Reputation: 7743
I'm looking for a general recipe to use a URL for a function that expects a filename. I've puzzled one out, but it's a little complex and easy to get wrong.
In this case, my function is read_file
from geopandas
, but it would be the same problem in any case.
import tempfile, requests
import geopandas as gpd
def as_file(url):
tfile = tempfile.NamedTemporaryFile()
tfile.write(requests.get(url).content)
return tfile
URL = 'https://raw.githubusercontent.com/bowmanmc/ohiorepresents/master/data/congressional.min.json'
tf = as_file(URL)
gpd.read_file(tf.name)
That works, and doesn't look too awful, but I had to experiment a bunch to find it, because slight variants raise OSError: no such file or directory
, due to the lifespan of tempfiles; yet I also don't want to clutter the filesystem with permanent files.
This fails:
def as_file(url):
tfile = tempfile.NamedTemporaryFile()
tfile.write(requests.get(url).content)
return tfile.name
gpd.read_file(as_file(URL))
and even this:
def as_file(url):
tfile = tempfile.NamedTemporaryFile()
tfile.write(requests.get(url).content)
return tfile
gpd.read_file(as_file(URL).name)
Is there a more obvious, memorable, or bulletproof way?
Upvotes: 5
Views: 1314
Reputation: 24133
You can use a context manager to manage the lifetime of the temporary file:
from contextlib import contextmanager
@contextmanager
def as_file(url):
with tempfile.NamedTemporaryFile() as tfile:
tfile.write(requests.get(url).content)
tfile.flush()
yield tfile.name
Note: The with NamedTemporaryFile() as tfile
will only work with Python 3. Otherwise you'll have to make sure it cleans up properly yourself for Python 2.
Usage:
with as_file(URL) as filename:
gpd.read_file(filename)
Upvotes: 6