CQ-editor icon indicating copy to clipboard operation
CQ-editor copied to clipboard

Possible fix for 'PosixPath' object does not support the context manager protocol

Open jdegenstein opened this issue 10 months ago • 3 comments

per user report on python 3.13

thanks also to @snoyer

see also: https://bugs.python.org/issue39682

This is untested so far as I haven't been able to reproduce the bug myself yet.

jdegenstein avatar Jan 30 '25 03:01 jdegenstein

Looks like this is the right bug but not the right fix.

Key points from the Discord discussion:

  • with path: was deprecated and is now gone because it was clever but it was not smart https://bugs.python.org/issue39682
  • with path: would change the current directory and the replacement is contextlib.chdir https://github.com/mwouts/jupytext/pull/1251/files#diff-e52e4ddd58b7ef887ab03c04116e676f6280b824ab7469d5d3080e5cba4f2128L50
  • contextlib.chdir is not available for python < 3.11 but could be backported if needed https://github.com/python/cpython/blob/a4722449caccc42ad644611d02fbdb5005f601eb/Lib/contextlib.py#L802-L814

snoyer avatar Jan 30 '25 04:01 snoyer

@snoyer So would we check to see if contextlib has chdir, and monkey-patch the updated chdir (that would probably live in our codebase) in if it does not? Or is there a more elegant way of doing it?

jmwright avatar Feb 01 '25 03:02 jmwright

@jmwright

So would we check to see if contextlib has chdir, and monkey-patch the updated chdir (that would probably live in our codebase) in if it does not? Or is there a more elegant way of doing it?

Defining chdir if the import fail would be a bit cleaner than monkey-patching IMO, but it would still be branching based on the Python version.

try:
    from contextlib import chdir
except ImportError:
    def chdir(path): 
        # ...

It looks like chdir would be pretty simple when implemented with @contextmanager so maybe you can just use a custom impl unconditionally and not bother with the builtin one at all?

import os
from contextlib import contextmanager
from pathlib import Path


@contextmanager
def chdir(path: str | Path):
    old_path = os.getcwd()
    os.chdir(path)
    yield
    os.chdir(old_path)


with chdir("/tmp"):
    assert os.getcwd() == "/tmp"
    with chdir("/opt"):
        assert os.getcwd() == "/opt"
    assert os.getcwd() == "/tmp"

snoyer avatar Feb 01 '25 05:02 snoyer