Repository navigation
Add io.fits test showing that reading from URL works... - #6378
Conversation
|
Hi there @drdavella 👋 - thanks for the pull request! I'm just a friendly 🤖 that checks for issues related to the changelog and making sure that this pull request is milestoned and labelled correctly. This is mainly intended for the maintainers, so if you are not a maintainer you can ignore this, and a maintainer will let you know if any action is required on your part 😃. Everything looks good from my point of view! 👍 |
|
@astrofrog , I set "no change log required" but |
|
@pllim - |
|
Would you be against to backport this to 2.0.x? |
|
Thanks for the explanation, @bsipocz . No, I am not against backporting if you don't mind the work. Feel free to re-milestone. 😃 |
|
@pllim - Doing a clean backport is super easy especially so close to the first release. If I run into non-trivial issues with the backport, then can always just remilesone it out of the bugfix milestone. So feel free to mark the doc/test and obviously bug fixes whenever applicable. |
|
This seems to work because you are using the In [1]: import urllib.request
...: from astropy.io import fits
In [2]: obj = urllib.request.urlopen("http://data.muse-vlt.eu/HDFS/v1.0/EmiLines_HDFS_v1p0.fits")
In [3]: fits.open(obj)
---------------------------------------------------------------------------
UnsupportedOperation Traceback (most recent call last)
<ipython-input-3-e81a7a49e374> in <module>()
----> 1 fits.open(obj)
~/dev/astropy/astropy/io/fits/hdu/hdulist.py in fitsopen(name, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)
156
157 return HDUList.fromfile(name, mode, memmap, save_backup, cache,
--> 158 lazy_load_hdus, **kwargs)
159
160
~/dev/astropy/astropy/io/fits/hdu/hdulist.py in fromfile(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)
409 return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,
410 save_backup=save_backup, cache=cache,
--> 411 lazy_load_hdus=lazy_load_hdus, **kwargs)
412
413 @classmethod
~/dev/astropy/astropy/io/fits/hdu/hdulist.py in _readfrom(cls, fileobj, data, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)
994 if not isinstance(fileobj, _File):
995 # instantiate a FITS file object (ffo)
--> 996 fileobj = _File(fileobj, mode=mode, memmap=memmap, cache=cache)
997 # The pyfits mode is determined by the _File initializer if the
998 # supplied mode was None
~/dev/astropy/astropy/utils/decorators.py in wrapper(*args, **kwargs)
505 # one with the name of the new argument to the function
506 kwargs[new_name[i]] = value
--> 507 return function(*args, **kwargs)
508
509 return wrapper
~/dev/astropy/astropy/io/fits/file.py in __init__(self, fileobj, mode, memmap, overwrite, cache)
177 self.size = 0
178 else:
--> 179 pos = self._file.tell()
180 self._file.seek(0, 2)
181 self.size = self._file.tell()
UnsupportedOperation: seek |
|
@saimn, you're right. Is the URL that you provided one that would be reasonable to use in a unit test? |
|
@MSeifert04 - I checked quickly as I'm trying to catch up with opened issues and PRs, but it looks like the issue is not closed. The current PR should also a test with a remote FITS file. |
|
@drdavella - If you look at the Astropy tests, there is a mechanism for this kind of tests: with the |
|
Also iirc, the |
|
It seems like |
|
@drdavella - I suggest just use a url directly within a |
|
Is it necessary to add a specific file to https://astropy.stsci.edu/data for this test, or can I just use one that already exists there? |
|
it's great if you could reuse one from there, but can add another if it's necessary. |
|
@saimn I think the method using In addition, I squashed everything a bit to make things look a little cleaner. |
|
Thanks @drdavella , I changed the milestone to 3.0 hence we don't need to bother too much with Python 2 (we just need to keep the code compatible until Python 2 compatibility is removed). Can you move the changelog entry to 3.0 ? For Request objects, I would vote for removing this as I don't see how it can be useful, but it's up to you ;-) |
| if mode in ('ostream', 'append', 'update'): | ||
| raise ValueError( | ||
| "Mode {} not supported for HTTPResponse".format(mode)) | ||
| from io import BytesIO |
There was a problem hiding this comment.
nitpick: move the import at the top
There was a problem hiding this comment.
The reason It's not at the top is because you can avoid the import in the failure case. I'm not sure it matters much either way.
There was a problem hiding this comment.
It's from the stdlib and surely already imported (it's the module that provides open ;-)).
There was a problem hiding this comment.
Sorry, do you mean to the top of that elif or to the top of the file?
There was a problem hiding this comment.
The top of the file, all imports should be global unless there is a good reason (circular imports, optional dependencies).
| ^^^^^^^^^^^^^^^ | ||
|
|
||
| - Properly handle opening of FITS files from URL Requests and HTTPResponses | ||
| from remote URLs. [#6378] |
There was a problem hiding this comment.
Requests and HTTPResponses with the plural form may be confusing. If we care only about Python 3, you could use instead the complete name (http.client.HTTPResponse) or just mention it as the output of urlopen ?
This addresses issue [astropy#4185] and tests opening FITS files from URLs corresponding to local and remote files using urlopen.
|
@saimn okay I think I've addressed all the feedback:
|
| _array_to_file, _write_string) | ||
| from ...extern.six import b, string_types | ||
| from ...extern.six.moves import http_client | ||
| from ...extern.six import b, string_types, moves |
|
ping @MSeifert04, if you want to have another look ? |
| if mode in ('ostream', 'append', 'update'): | ||
| raise ValueError( | ||
| "Mode {} not supported for HTTPResponse".format(mode)) | ||
| fileobj = io.BytesIO(fileobj.read()) |
There was a problem hiding this comment.
Not really a good idea because once read subsequent reads will return an empty string. I wouldn't expect open to "clear" the Response object.
There was a problem hiding this comment.
If you pass a Response object, I think you have to expect that it will be used to read the data. Otherwise there are other ways, passing the url or saving the data to disk.
There was a problem hiding this comment.
FWIW the original solution using download_files actually avoided this problem, even if it was at the cost of redundant resources being used. However, I think I agree with @saimn that the current behavior is reasonable given the use case.
|
I'm not sure if we actually should support open "response" objects. We already support reading from urls. Wouldn't it make sense to just error out in case a response is passed in with a helpful message (pass in the url instead)? |
|
The question is to know if there is a real usecase for this. For HTTP responses, it is logical to support it because it is a file-like object, which is already supported by |
|
@saimn and @MSeifert04, it's easy enough for me to add back if you want. On the one hand, I agree with @saimn that there's probably not a real use case for this. On the other hand, I agree with @MSeifert04 that it's not that hard to support requests and it makes things seem more 'complete'. At this point I don't have strong feelings about it so I'll just wait for someone else to tell me what to do 😅. |
|
@saimn But #6378 (comment) shows that while it's somewhat file-like it's not exactly file-like. So it would be "okay" not to support it. I'm not sure either. It probably won't hurt to support HTTP responses but I'm a bit hesitant because it seems like we're trying to fix a non-existing problem. |
Yes, for
I'm confused by this, do you mean for responses, requests, or both ? For responses, as show above, it's almost file-like and I think it makes sense to support this. But for requests I'm also advocating that it's a non-existing problem. |
|
I'm not sure what you mean by "requests". Personally I feel that passing an url to As I see it there is only one use-case to pass in responses: When the online material requires authentication, because that way you can't just pass in the url to I'm not totally against supporting |
|
@MSeifert04 - i mean To clarify:
|
Couldn't this argument also apply to results from |
Ah, I thought that issue was just about the "misleading" error. Not about supporting it (although it was mentioned that it would be easy).
But I don't feel strong about that so if you actually want to support it I won't mind. 😄 |
|
Again, I realize I'm a biased source, but it's easy to support and it's consistent with the way that regular file objects are already supported, so I think it makes sense to add support for objects from But I'm new here, so I'll leave the final decision to someone else 🤐 |
|
@MSeifert04 - With the full quote it suggests that it could be supported:
Also the issue was triggered by https://stackoverflow.com/questions/32643206/how-do-i-open-a-fits-file-from-a-url-in-astropy where someone tries to do exactly this. So, I think everybody agree that we spent already too much time discussing this 😉. It's not a major feature but can be useful for specific cases. Let's merge and move forward (is it a special day where everybody reports FITS issues ? 😮 ). |
|
And thanks @drdavella ! |
This addresses issue #4165 and adds a test to
io.fitsshowing that opening a FITS file from a URL already appears to work as expected.It seems like this one probably doesn't need a change log entry?
EDIT: Fix #4165