Skip to content

Instantly share code, notes, and snippets.

@EliahKagan
Last active September 7, 2023 15:32
Show Gist options
  • Save EliahKagan/eb0c0d34b0b5e911f52cd044f8fac320 to your computer and use it in GitHub Desktop.
Save EliahKagan/eb0c0d34b0b5e911f52cd044f8fac320 to your computer and use it in GitHub Desktop.
git.util.cwd and contextlib.chdir reentrancy
BSD Zero Clause License
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
(.venv) ek@Glub:~/repos-wsl/GitPython (main *+%=)$ ./try-cwd.py
Separate objects - contextlib.chdir:
/tmp/a
/tmp/b
/tmp/a
/tmp/b
/tmp/a
Separate objects - git.util.cwd:
/tmp/a
/tmp/b
/tmp/a
/tmp/b
/tmp/a
Shared object - contextlib.chdir:
/tmp/a
/tmp/b
/tmp/a
/tmp/b
/tmp/a
Shared object - git.util.cwd:
/tmp/a
/tmp/b
Traceback (most recent call last):
File "/home/ek/repos-wsl/GitPython/./try-cwd.py", line 67, in <module>
main()
File "/home/ek/repos-wsl/GitPython/./try-cwd.py", line 63, in main
demo_shared("git.util.cwd", _git_util_cwd) # contextlib.py AttributeError.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ek/repos-wsl/GitPython/./try-cwd.py", line 50, in demo_shared
with used_twice:
File "/usr/lib/python3.11/contextlib.py", line 135, in __enter__
del self.args, self.kwds, self.func
^^^^^^^^^
AttributeError: '_GeneratorContextManager' object has no attribute 'args'
#!/usr/bin/env python
# SPDX-License-Identifier: 0BSD
"""
Experiments for what forms of reentrancy git.util.cwd supports.
This requires Python 3.11 or later, because contextlib.chdir is also examined
for comparison. It also in effect requires a Unix-like system, because it
creates and uses the hard-coded directories /tmp/a and /tmp/b for simplicity.
"""
import contextlib
from contextlib import AbstractContextManager
import os
from typing import Any, Callable
from git.types import PathLike
# Import cwd this way instead of accessing it as git.util.cwd, because the
# "from git.index import *" in git/__init__.py sets git.util to git.index.util:
from git.util import cwd as _git_util_cwd
CwdObject = AbstractContextManager[None] | AbstractContextManager[PathLike]
"""Type shared by return values of cwd in git.util and of contextlib.chdir."""
CwdFactory = Callable[[PathLike], CwdObject]
"""Type shared by cwd in git.util and contextlib.chdir."""
def demo_separate(label: str, cwd: CwdFactory) -> None:
"""Attempt to enter separate context manager objects for the same dir."""
print(f"\nSeparate objects - {label}:")
with cwd("/tmp/a"):
print(os.getcwd())
with cwd("/tmp/b"):
print(os.getcwd())
with cwd("/tmp/a"):
print(os.getcwd())
print(os.getcwd())
print(os.getcwd())
def demo_shared(label: str, cwd: CwdFactory) -> None:
"""Attempt to reenter the same returned context manager object."""
print(f"\nShared object - {label}:")
used_twice = cwd("/tmp/a")
with used_twice:
print(os.getcwd())
with cwd("/tmp/b"):
print(os.getcwd())
with used_twice:
print(os.getcwd())
print(os.getcwd())
print(os.getcwd())
def main() -> None:
"""Create directories in /tmp, and run both experiments/demonstrations."""
os.makedirs("/tmp/a", exist_ok=True)
os.makedirs("/tmp/b", exist_ok=True)
demo_separate("contextlib.chdir", contextlib.chdir) # OK.
demo_separate("git.util.cwd", _git_util_cwd) # OK.
demo_shared("contextlib.chdir", contextlib.chdir) # OK.
demo_shared("git.util.cwd", _git_util_cwd) # contextlib.py AttributeError.
if __name__ == "__main__":
main()
#!/bin/sh
mypy --python-version=3.11 --follow-imports=silent try-cwd.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment