New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Path objects in io packages #4606
Changes from 4 commits
b8b3c12
419a960
056a1a9
5d78141
7296933
c7b5d20
0451edf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ | |
from .util import (isreadable, iswritable, isfile, fileobj_open, fileobj_name, | ||
fileobj_closed, fileobj_mode, _array_from_file, | ||
_array_to_file, _write_string) | ||
from ...extern.six import b, string_types | ||
from ...extern.six import b, string_types, PY3 | ||
from ...utils.data import download_file, _is_url | ||
from ...utils.decorators import classproperty | ||
from ...utils.exceptions import AstropyUserWarning | ||
|
@@ -74,6 +74,13 @@ | |
PKZIP_MAGIC = b('\x50\x4b\x03\x04') | ||
BZIP2_MAGIC = b('\x42\x5a') | ||
|
||
try: | ||
from pathlib import Path | ||
except: | ||
HAS_PATHLIB = False | ||
else: | ||
HAS_PATHLIB = True | ||
|
||
class _File(object): | ||
""" | ||
Represents a FITS file on disk (or in some other file-like object). | ||
|
@@ -97,6 +104,9 @@ def __init__(self, fileobj=None, mode=None, memmap=None, clobber=False, | |
return | ||
else: | ||
self.simulateonly = False | ||
# If fileobj is of type pathlib.Path | ||
if PY3 and HAS_PATHLIB and isinstance(fileobj, Path): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need to check |
||
fileobj = str(fileobj) | ||
|
||
# Holds mmap instance for files that use mmap | ||
self._mmap = None | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,13 @@ | |
from ....utils.data import get_pkg_data_filename, get_pkg_data_filenames | ||
from ....tests.helper import pytest, raises, catch_warnings | ||
|
||
try: | ||
import pathlib | ||
except ImportError: | ||
HAS_PATHLIB = False | ||
else: | ||
HAS_PATHLIB = True | ||
|
||
# Determine the kind of float formatting in this build of Python | ||
if hasattr(sys, 'float_repr_style'): | ||
legacy_float_repr = (sys.float_repr_style == 'legacy') | ||
|
@@ -820,6 +827,45 @@ def test_validate(): | |
assert truth == output | ||
|
||
|
||
@pytest.mark.skipif('not HAS_PATHLIB') | ||
def test_validate_path_object(): | ||
""" | ||
Validating when source is passed as path object. (#4412) | ||
Creating different method from ``test_validate`` so that it could be | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can just add an argument to
Then you can still have a separate |
||
skipped if ``pathlib`` isnt available without affecting ``test_validate`` | ||
""" | ||
output = io.StringIO() | ||
fpath = pathlib.Path(get_pkg_data_filename('data/regression.xml')) | ||
|
||
with catch_warnings(): | ||
result = validate(fpath, | ||
output, xmllint=False) | ||
|
||
assert result == False | ||
|
||
output.seek(0) | ||
output = output.readlines() | ||
|
||
with io.open( | ||
get_pkg_data_filename('data/validation.txt'), | ||
'rt', encoding='utf-8') as fd: | ||
truth = fd.readlines() | ||
|
||
truth = truth[1:] | ||
output = output[1:-1] | ||
|
||
for line in difflib.unified_diff(truth, output): | ||
if six.PY3: | ||
sys.stdout.write( | ||
line.replace('\\n', '\n')) | ||
else: | ||
sys.stdout.write( | ||
line.encode('unicode_escape'). | ||
replace('\\n', '\n')) | ||
|
||
assert truth == output | ||
|
||
|
||
def test_gzip_filehandles(tmpdir): | ||
votable = parse( | ||
get_pkg_data_filename('data/regression.xml'), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,7 +106,7 @@ def _is_inside(path, parent_path): | |
def get_readable_fileobj(name_or_obj, encoding=None, cache=False, | ||
show_progress=True, remote_timeout=None): | ||
""" | ||
Given a filename or a readable file-like object, return a context | ||
Given a filename, pathlib.Path object or a readable file-like object, return a context | ||
manager that yields a readable file-like object. | ||
|
||
This supports passing filenames, URLs, and readable file-like objects, | ||
|
@@ -167,6 +167,14 @@ def get_readable_fileobj(name_or_obj, encoding=None, cache=False, | |
# passed in. In that case it is not the responsibility of this | ||
# function to close it: doing so could result in a "double close" | ||
# and an "invalid file descriptor" exception. | ||
PATH_TYPES = six.string_types | ||
try: | ||
from pathlib import Path | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to follow the same idiom from testing and define Note: you should change my original implementation in |
||
except: | ||
pass | ||
else: | ||
PATH_TYPES += (Path,) | ||
|
||
close_fds = [] | ||
delete_fds = [] | ||
|
||
|
@@ -175,7 +183,11 @@ def get_readable_fileobj(name_or_obj, encoding=None, cache=False, | |
remote_timeout = conf.remote_timeout | ||
|
||
# Get a file object to the content | ||
if isinstance(name_or_obj, six.string_types): | ||
if isinstance(name_or_obj, PATH_TYPES): | ||
# name_or_obj could be a Path object in Python 3 | ||
if six.PY3: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice that this code becomes easier to understand:
This avoids one level of contextual knowledge that only Python 3 has pathlib. So then the comment would be more like |
||
name_or_obj = str(name_or_obj) | ||
|
||
is_url = _is_url(name_or_obj) | ||
if is_url: | ||
name_or_obj = download_file( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this
import pathlib
for consistency with usage in the other modules.