jaraco / pip-run

pip-run - dynamic dependency loader for Python
MIT License
137 stars 19 forks source link

Unable to pip output from one pip-run to another pip-run #36

Closed jaraco closed 6 years ago

jaraco commented 6 years ago

Consider the use-case where you want to test the encoding/decoding of some string against two versions of a library. You could do two invocations of pip-run:

$ pip-run -q itsdangerous==0.24 -- -c "import itsdangerous; print(itsdangerous.Signer(b'secret-key').sign(b'my string').decode('ascii'))"
my string.wh6tMHxLgJqB6oY1uT73iMlyrOA
$ echo 'my string.wh6tMHxLgJqB6oY1uT73iMlyrOA' | pip-run -q itsdangerous==1.1 -- -c "import itsdangerous, sys; print(itsdangerous.Signer('secret-key').unsign(sys.stdin.read()))"
...

And that works fine, but anyone who has spent more than 30 seconds in Unix would expect to be able to take the output of the first command and pipe it into the second command to avoid having to emit and then re-enter the intermediate result. However, if you do this with pip-run, it fails with a BrokenPipeError:

~ $ pip-run -q itsdangerous==0.24 -- -c "import itsdangerous; print(itsdangerous.Signer(b'secret-key').sign(b'my string').decode('ascii'))" | pip-run -q itsdangerous==1.1 -- -c "import itsdangerous, sys; print(itsdangerous.Signer('secret-key').unsign(sys.stdin.read()))"
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/bin/pip-run", line 11, in <module>
    sys.exit(run())
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip_run/__init__.py", line 18, in run
    with deps.load(*deps.not_installed(pip_args)) as home:
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip_run/deps.py", line 74, in load
    with _patch_prefix():
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip_run/deps.py", line 89, in _patch_prefix
    with _save_file(cfg_fn):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip_run/deps.py", line 104, in _save_file
    raise NotImplementedError(tmpl.format(**locals()))
NotImplementedError: Unsupported with extant /Users/jaraco/.pydistutils.cfg
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe

This all would work except for the (undocumented) caveat that pip-run relies on ~/.pydistutils.cfg to inject certain functionality... and so two invocations of pip-run cannot run simultaneously for the same user.

Here is the code that invokes this behavior, which implicates #14 and pypa/pip#4106.

This issue only affects invocations where the pip install commands from pip-run overlap.

jaraco commented 6 years ago

pip-run 5.2 allows setting PIP_RUN_NO_PATCH_PREFIX to bypass this behavior for environments that are unaffected.

jaraco commented 6 years ago

Even better, pip-run 5.3 auto-detects the condition that will fail and applies the workaround there. This way, no environment variable is needed.