Skip to content
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

Improve error message when providing UPath instances to open() #124

Open
ap-- opened this issue Jul 31, 2023 · 0 comments
Open

Improve error message when providing UPath instances to open() #124

ap-- opened this issue Jul 31, 2023 · 0 comments
Labels
compatibility 🤝 Compatibility with stdlib pathlib

Comments

@ap--
Copy link
Collaborator

ap-- commented Jul 31, 2023

Currently opening a UPath via open fails with a FileNotFoundError because the URI returned via __fspath__() is just interpreted as a string path.

>>> import upath
>>> pth = upath.UPath("memory:///abc.txt")
>>> pth.write_text("hello world")
11
>>> with open(pth, "rt") as f:
...     print(f.read())
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'memory:/abc.txt'

There's two possible ways of improving this error:

  1. We raise an exception in non-local UPath subclasses in __fspath__.
  2. Or we could keep the basic functionality that fspath returns a string and raise an exception if we detect that the result was used in open
    import os
    
    import sys
    from textwrap import dedent
    from typing import Self
    
    
    class _upath_str(str):
        """helper str subclass for better error messages
    
        This helper class allows us to catch when a user tries
        to provide a UPath instance of a non-local filesystem
        to Python's `open()` function.
        """
        def __str__(self) -> Self:
            return self
    
    
    def _upath_audit_hook(name: str, args: tuple) -> None:
        """audit hook matching the `open` event
    
        Raises a better error message if we detect that a
        user tries to use UPath instances with `open()`.
        """
        if name == "open" and isinstance(args[0], _upath_str):
            msg = dedent(
                f"""\
                builtins.open does not support non-local UPath instances.
                  Use the pathlib interface instead:
                    >>> pth = UPath({args[0]!r})
                    >>> with pth.open() as f:
                    >>>    ...
                """
            )
            raise OSError(msg)
    
    
    sys.addaudithook(_upath_audit_hook)
    
    
    class A:
        def __fspath__(self):
            return _upath_str("abc")
    
        def __str__(self):
            return _upath_str("abc")
    
    a = A()
    b = _upath_str("b")
    print(type(b))
    c = str(a)
    print(type(c))
    print(type(str(c)))
    
    os.fspath(a)
    
    with open(a) as f:
        pass

(1) would be preferable, but (2) might be useful, since there's some code out there that uses __fspath__ to convert os.PathLike to strings.

Need to do a survey of code on github, and if we choose (1) there needs to be a deprecation period.

@ap-- ap-- added the compatibility 🤝 Compatibility with stdlib pathlib label Aug 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compatibility 🤝 Compatibility with stdlib pathlib
Projects
None yet
Development

No branches or pull requests

1 participant