MNT: Run PTH flake test in prep for supporting pathlib (io.ascii)#16954
MNT: Run PTH flake test in prep for supporting pathlib (io.ascii)#16954taldcroft merged 1 commit intoastropy:mainfrom
Conversation
|
Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.
|
|
👋 Thank you for your draft pull request! Do you know that you can use |
e4b63bd to
3412167
Compare
3412167 to
48210e4
Compare
astropy/io/ascii/ui.py
Outdated
| output.write(outstr) | ||
| output.write(os.linesep) | ||
| output.close() | ||
| if not output: |
There was a problem hiding this comment.
But there is already this check above:
if output is None:
output = sys.stdoutThere was a problem hiding this comment.
This check is different: it also invalidates the empty string '' because Path('') means "the current work directory", and this scenario (passing output='' and expecting a FileNotFoundError) is actually exercised in a test.
There was a problem hiding this comment.
What was the old behavior for output=''? Does this need a change log?
There was a problem hiding this comment.
Au contraire, this is being strictly backward compatible: open('') raises the same exception.
There was a problem hiding this comment.
I am seeing this error message:
>>> open("", "w")
FileNotFoundError: [Errno 2] No such file or directory: ''
There was a problem hiding this comment.
I'm going to revert this and simply refactor with a context manager as suggested in https://github.com/astropy/astropy/pull/16954/files#r1748045678
taldcroft
left a comment
There was a problem hiding this comment.
Looks OK but with requested changes. Overall in the Path migration I think you should mostly avoid doing a blind replacement of open(...) with Path().read/write_text().
There is nothing wrong with open() and the two cases here show that open() is often preferable because it is a streaming interface.
astropy/io/ascii/qdp.py
Outdated
| elif isinstance(qdp_file, (str, os.PathLike)): | ||
| lines = [line.strip() for line in Path(qdp_file).read_text().splitlines()] |
There was a problem hiding this comment.
This new code ends up making two additional copies of the entire file in memory, one the full read_text() output and second the splitlines() output. In general splitlines() is not a drop-in replacement for iterating over open() since splitlines() removes the line endings. In this case it doesn't matter but best to keep this Path refactoring as close to the original code as possible.
So basically the only change here should be isinstance(qdp_file, (str, os.PathLike)):.
There was a problem hiding this comment.
In this case it doesn't matter but best to keep this Path refactoring as close to the original code as possible.
100% agreed. Any behavioral difference with the original code that I don't advertise myself in a comment is a mistake from me, so thank you for your attention to details !
astropy/io/ascii/ui.py
Outdated
| output.write(outstr) | ||
| output.write(os.linesep) | ||
| output.close() | ||
| if not output: |
There was a problem hiding this comment.
I am seeing this error message:
>>> open("", "w")
FileNotFoundError: [Errno 2] No such file or directory: ''
astropy/io/ascii/ui.py
Outdated
| if isinstance(output, (str, bytes, os.PathLike)): | ||
| output = os.path.expanduser(output) | ||
| if isinstance(output, (str, bytes, os.PathLike)) and output: | ||
| output = Path(output).expanduser() |
There was a problem hiding this comment.
I would prefer to revert the changes In this function and stick with the original os.path.expanduser(). In this case using Path is introducing new complexity to the logic because of the Path("") => cwd() behavior. So maybe add a #noqa ....
astropy/io/ascii/ui.py
Outdated
| # Path("") gives the current working directory | ||
| raise FileNotFoundError("No such file or directory") | ||
| Path(output).write_text( | ||
| outstr + os.linesep, |
There was a problem hiding this comment.
This creates an unnecessary temporary string outstr + os.linesep.
| output = open(output, "w", newline="") | ||
| output.write(outstr) | ||
| output.write(os.linesep) | ||
| output.close() |
There was a problem hiding this comment.
This should just be changed to an open(...) context manager.
| @@ -379,7 +380,7 @@ def read(self, table): | |||
| with suppress(TypeError): | |||
| # For strings only | |||
| if os.linesep not in table + "": | |||
There was a problem hiding this comment.
@taldcroft just out of pure curiosity, what is the purpose of the + "" here?
There was a problem hiding this comment.
I assume this is to trigger a TypeError if table isn't a string ?
There was a problem hiding this comment.
Exactly what @neutrinoceros said. This is a very old idiom to check for string-like (somewhat like a protocol, asking if it supports appending a str) instead of an explicit str type check.
What's the best way to check for string-like? Or does isinstance(table, str) cover all realistic use cases?
There was a problem hiding this comment.
isinstance is definitely more idiomatic here; I can't think of any type other than str that accepts another str in __add__
There was a problem hiding this comment.
From BaseReader.read in core.py below, which uses the same construct, the only other input cases are file-like or list of strings (the table lines), so they should all be covered.
@taldcroft I agree. I'll open a PR to propose ignoring that specific rule ( |
48210e4 to
f897605
Compare
|
I think I've now addressed all comments from @taldcroft, let me know if there's anything I missed ! |
astropy/io/ascii/ui.py
Outdated
| with open(output, "w", newline="") as output: | ||
| output.write(outstr) | ||
| output.write(os.linesep) | ||
| output.close() |
There was a problem hiding this comment.
The .close() is not needed with the context manager.
There was a problem hiding this comment.
Thanks for catching this. Fixed.
f897605 to
e04f9b3
Compare
Description
Ref #16924
This is in the continuation of #16060