-
Notifications
You must be signed in to change notification settings - Fork 227
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
Fix Exception Handling in _get_yaml_data_and_path(...) #392
Conversation
e.errno
is None
I can dig a little deeper to find the root cause, because the docs do not mention that try:
yaml_path = Path(inp).expanduser().resolve(strict=True)
# if no FileNotFoundError exception happens, get file contents
yaml_str = open_file_read(yaml_path).read()
except (FileNotFoundError, OSError) as e:
# if inp is a long YAML string, Pathlib will raise OSError: [errno.ENAMETOOLONG]
# (in Windows, it seems OSError [errno.EINVAL] might be raised in some cases)
# when trying to expand and resolve it as a path.
# Catch this error, but raise any others
from errno import EINVAL, ENAMETOOLONG
if type(e) is OSError and e.errno not in (EINVAL, ENAMETOOLONG):
raise e
# file does not exist; assume inp is a YAML string
yaml_str = inp
yaml_path = None The exception asks for both, FileNotFoundError and OSError. Since one is a subclass of the other, PS : I am taking a peek at jaraco/path as possible drop-in replacement, although still proposinc this PR only as a Bugfix! |
@RedshiftVelocities, I noticed that a similar issue has been found by @kvid in #318 (review) a year ago. Could you please check this again? It seems that behavior changes with different Python versions. The referred one uses |
@martinrieder wrote:
I can confirm that I still get Update: Tested again at a different PC with Python 3.9.13 with the current branch of PR #365 (without this PR merged in) with the valid a-80k.yml as input: WireViz 0.4.1-dev
Input file: _test\a-80k.yml
Output file: _test\a-80k.[html|png|svg|tsv]
Traceback (most recent call last):
File "C:\Repos\WireViz\src\wireviz\wv_cli.py", line 153, in <module>
wireviz()
File "C:\Repos\WireViz\.venv\lib\site-packages\click\core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "C:\Repos\WireViz\.venv\lib\site-packages\click\core.py", line 1078, in main
rv = self.invoke(ctx)
File "C:\Repos\WireViz\.venv\lib\site-packages\click\core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\Repos\WireViz\.venv\lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "C:\Repos\WireViz\src\wireviz\wv_cli.py", line 141, in wireviz
wv.parse(
File "C:\Repos\WireViz\src\wireviz\..\wireviz\wireviz.py", line 90, in parse
yaml_data, yaml_file = _get_yaml_data_and_path(inp)
File "C:\Repos\WireViz\src\wireviz\..\wireviz\wireviz.py", line 409, in _get_yaml_data_and_path
yaml_path = Path(inp).expanduser().resolve(strict=True)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\pathlib.py", line 1215, in resolve
s = self._flavour.resolve(self, strict=strict)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\pathlib.py", line 210, in resolve
return self._ext_to_normal(_getfinalpathname(s))
ValueError: _getfinalpathname: path too long for Windows |
@kvid what does errno evaluate to in that case? Which version of Pathlib are you running? BTW: I do not consider running a huge YAML file to be that unusual. If a library of connectors is contained in the templates section, file size can increase quickly. |
An
I agree to that, but my 80000 character test input was only a single long string, and that is a bit unusual. However, I just now added my 80000 character as one of the attributes of a connector in a valid WireViz YAML file, and the same ValueError was raised, so you are probably right it also can happen with a huge template section. I suggest you include except (FileNotFoundError, OSError, ValueError) as e: |
Additionally, the if clause needs to be adapted, so that the exception is also raised. My proposal to add some "band-aid" the fix:
What do you think about treating all multi-line strings as YAML? Besides bugfixing, would printing an error message if it is neither an existing file nor valid YAML provide a more user-friendly behavior instead of simply raising an exception? |
No, the
As I wrote a year ago in point 4 of #318 (review) that you referred to above, this is exactly what is already implemented in #251. Catching more exceptions here is just a quick band-aid to avoid most errors until the more thorough fix in #251.
No expected exceptions to catch after the #251 changes, so they are all raised normally.
No special catching of these exceptions are needed.
I agree, and #251 is the first to be merged after releasing the collections of quick-fixes.
See #207 |
Okay then I will keep things simple and it shall look like this: try:
yaml_path = Path(inp).expanduser().resolve(strict=True)
# if no FileNotFoundError exception happens, get file contents
yaml_str = open_file_read(yaml_path).read()
except (FileNotFoundError, OSError, ValueError) as e: # adding ValueError per #318
# if inp is a long YAML string, Pathlib will raise OSError: [errno.ENAMETOOLONG]
# (in Windows, it seems OSError [errno.EINVAL] might be raised in some cases)
# when trying to expand and resolve it as a path.
# Catch this error, but raise any others
from errno import EINVAL, ENAMETOOLONG
if type(e) is OSError and e.errno not in (EINVAL, ENAMETOOLONG, None): # adding None fixes #391
raise e
# file does not exist; assume inp is a YAML string
yaml_str = inp
yaml_path = None |
@formatc1702 seems to prefer not referring to issues or PRs in the source code - see #264 (comment) Referring to them in the body of commit messages is OK and often useful, though. I therefore suggest removing the two trailing comments including issue references. Instead I suggest expanding the comment block to explain the latest additions like this: # if inp is a long YAML string, Pathlib will raise OSError: [errno.ENAMETOOLONG]
# (in Windows, it seems ValueError or OSError [errno.EINVAL or None]
# also might be raised in some cases - depending on the Python version)
# when trying to expand and resolve it as a path.
# Catch these errors, but raise any others |
Thanks. I will update the PR accordingly. I discovered an additional OS-specific bug with |
@martinrieder wrote:
If the fix is similar to what is already discussed (catching an extra Please use the imperative mood in your commit subject lines as recommended in the contribution guidelines and I think the PR title should follow the same recommendation as for commit subject lines, because a squash commit will normally use the PR title as subject line. |
e.errno
is None
e.errno
is None
in Exception Handling
e.errno
is None
in Exception Handlinge.errno
is None
to Exception Handling of _get_yaml_data_and_path(...)
I'm sorry for being unclear. When I wrote "update the PR title and description to cover all sub-issues", I didn't mean all details should be in the title. Please read all the commit recommendations at the page I linked to above. The subject line should be a short summary, preferably limited to 50 characters and never more than 72. Use the body for details. |
e.errno
is None
to Exception Handling of _get_yaml_data_and_path(...)
Thanks for digging into these more obscure issues despite my limited availability. It seems like a very minor code change with multiple positive effects, good job :) I assume it's ready for merge but have requested review just to be sure. |
Sorry, I did not get to commit the discussed changes over the weekend. I am doing that now and will keep you updated. |
@martinrieder wrote:
Didn't you include a fix for this? I can't see any more code additions than what we discussed before you mentioned this last issue. Or does the fix involve huge code changes that is clearly out of scope for this PR? |
No, I am working on another machine today and had some trouble trying reproduce the issue here. I even reinstalled Python and noticed that the installer asked me to remove MAX_PATH limit. The following link might give a hint on the issue you found in #318, which indicates that it is also depending on System configuration: When a file name starts with
|
@kvid as you can see from the output above, the exception is raised in Regarding this other issue, I was able to trace it back to the argument handling of the Click library, which passes @click.argument("file", nargs=-1) Calling |
At Linux it's normal to evaluate a path with a leading If I understand your description correctly, it seems to work as designed. You get an exception because there is no user named Note also that if the leading |
@kvid thanks for explaining. It is of course unlikely for users to choose file names like this. Many Windows apps, especially MS Office create these as temporary files. They would typically not carry a I would still like to criticize the fact that file names are evaluated in two different parts of the code. This could be the source of many more bugs like the one I discovered. Once there is the chance to do more than just bugfixing, this should be reworked. Anyways, I am not planning to add more commits to this PR. I tested it locally (on Windows) and if the automated tests are also passing (on Linux) then it should be okay to merge this. |
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.
build_examples.py
runs without errors, and produces the expected results (diffs on version numbers and image absoulute paths are normal).- My
a-80k.yml
from Fix Exception Handling in _get_yaml_data_and_path(...) #392 (comment) is processed without errors, and produces the expected result. - I'm not able to verify the fix for Help with OS Error #391 because I'm not able to reproduce the reported error with
YMLFILE.txt
from Help with OS Error #391 (I've tried with Python 3.9.13 and 3.12.4 because 3.12.3 is no longer available from Microsoft Store). I get no errors both before and after changes in this PR. - I suggest a simple squash and merge with a summary of the two resolved issues in the resulting commit body.
Clarify the changes in wireviz#392 Co-authored-by: kvid <kvid@users.noreply.github.com>
In Windows might OSError(errno = None) be raised instead of the already catched exceptions in some cases (depending on the Python version) Fixes #391
In Windows might ValueError be raised instead of the already catched exceptions in some cases (depending on the Python version) Fixes point 2 of #318 (review)
Clarify all exceptions catched, including changes in #392 Co-authored-by: kvid <kvid@users.noreply.github.com>
Add ValueError and OSError where
e.errno
isNone
to Exception Handling of_get_yaml_data_and_path()
This PR is amending fixes for the following issues based on #250 and #318.
describing 80000 character YAML input raising
ValueError
describing
OSError: _getfinalpathname: path too long for Windows
master
contains #250 from d7d7854: Consolidate wireviz.parse() to handle Path, str and Dict as inputWireViz/src/wireviz/wireviz.py
Line 415 in 954c4f5
release/v0.4.1-rc
contains #318 at 6f9007f: Use portable OS error codes so program doesn't crashWireViz/src/wireviz/wireviz.py
Line 419 in ba84c54
Due to the following #246 (comment), this is a bugfix only, waiting to be resolved by #251.
References
Fix Exception Handling in _get_yaml_data_and_path(...) #392
Handle OSError [errno.EINVAL] that might be raised in Windows #346
os.path
withPathlib
#190Replace
os.path
withpathlib.Path
#246wireviz.parse()
#250Large scale refactoring #251