For this experiment, I put these files in the root of the cloned GitPython
repository.
The interesting files are:
try-cwd.py
, the script.transcript.txt
, which shows output.
This gist is licensed under 0BSD, a public-domain equivalent license.
For this experiment, I put these files in the root of the cloned GitPython
repository.
The interesting files are:
try-cwd.py
, the script.transcript.txt
, which shows output.This gist is licensed under 0BSD, a public-domain equivalent license.
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 |