Virtualenv: نصوص مثبتة مع shebang خاطئ تحت عملية فرعية

تم إنشاؤها على ٢٠ يناير ٢٠١٦  ·  27تعليقات  ·  مصدر: pypa/virtualenv

في Python 3.5.1 ولكن ليس في 2.7.10 ، عندما استدعي النقطة من خلال عملية فرعية في Virtualenv ، يتم إنشاء البرامج النصية باستخدام shebang الخطأ وبالتالي تفشل في التشغيل:

$ cat > invoke.py
import sys
import subprocess

subprocess.Popen(sys.argv[1:]).wait()
$ rm -Rf env
$ python -m virtualenv --version
14.0.0
$ python --version
Python 3.5.1
$ python -m virtualenv env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.5'
New python executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
Also creating executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python
Installing setuptools, pip, wheel...done.
$ python invoke.py env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Collecting py>=1.4.29 (from pytest)
  Using cached py-1.4.31-py2.py3-none-any.whl
Installing collected packages: py, pytest
Successfully installed py-1.4.31 pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Library/Frameworks/Python.framework/Versions/3.5/bin/python3

قد يتوقع المرء أن يحتوي نص اختبار py.test على shebang بداخله كلمة "env".

استخدام pyvenv بدلاً من ذلك لا يخضع لهذه المشكلة. تعمل إزالة متغير البيئة __PYVENV_LAUNCHER__ قبل بدء العملية الفرعية على حل المشكلة ، كما ورد هنا . لوحظت المشكلة مع 13.1.2 و 14.0.0.

هل هذا السلوك متوقع؟ إذا كان الأمر كذلك ، فهل إزالة متغير البيئة هو الشيء المناسب الذي يجب أن تقوم به العملية الأب للتغلب على المشكلة؟

التعليق الأكثر فائدة

لقد عضت للتو من هذا الخطأ الدقيق. إنه خطأ شديد في رأيي ، ويرجع ذلك في الغالب إلى أنه مربك للغاية ويصعب اكتشافه عند حدوثه.

ال 27 كومينتر

هل

$ env/bin/pip uninstall pytest
$ env/bin/pip install pytest
$ head -n 1 env/bin/py.test

تعطي نفس النتائج أو نتائج مختلفة؟

ونفس السؤال مع

$ env/bin/python -m pip install pytest

؟

من المحتمل حدوث تراجع بطريقة ما على https://github.com/pypa/virtualenv/issues/322 / https://github.com/pypa/virtualenv/pull/541

في هذه الحالة ، هل يمكنك اختبار ما إذا كان

subprocess.Popen(sys.argv[1:], env={}).wait()

يساعد ام لا؟

حسنًا ، كان هناك رمز في pip / distlib ربما للتعامل مع هذا ، ولكن تم التعليق عليه قبل عام-

https://github.com/pypa/pip/blob/7cea748d0fb2e8980c2676304607426585550b41/pip/_vendor/distlib/util.py#L157 -L165

تعطي نفس النتائج أو نتائج مختلفة؟

في كلتا الحالتين ، يؤدي استدعاء النقطة مباشرة إلى وجود shebang مناسب:

$ env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): py>=1.4.29 in ./env/lib/python3.5/site-packages (from pytest)
Installing collected packages: pytest
Successfully installed pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
$ env/bin/pip uninstall -y pytest
Uninstalling pytest-2.8.5:
  Successfully uninstalled pytest-2.8.5
$ env/bin/python -m pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): py>=1.4.29 in ./env/lib/python3.5/site-packages (from pytest)
Installing collected packages: pytest
Successfully installed pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python

أيضًا ، الاستدعاء ببيئة فارغة يعمل:

$ cat invoke.py 
import sys
import os
import subprocess

env = dict(os.environ)
env.pop('__PYVENV_LAUNCHER__')
env = {}

subprocess.Popen(sys.argv[1:], env=env).wait()
$ python -m virtualenv env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.5'
New python executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
Also creating executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python
Installing setuptools, pip, wheel...done.
$ python invoke.py env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Collecting py>=1.4.29 (from pytest)
  Using cached py-1.4.31-py2.py3-none-any.whl
Installing collected packages: py, pytest
Successfully installed py-1.4.31 pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python3

وفقًا للالتزام ، تم التعليق على هذا الحل مع تضمين distlib 0.2.0 الذي تم إصداره في النقطة 6.0.

أن الالتزام المراجع PIP 2031 .

أيضًا ، لقد قمت بتثبيت Python من أداة تثبيت python.org Mac ، وليس من خلال البيرة المنزلية أو طرق أخرى.

تمت إزالة الكود من distlib في هذا الالتزام ، والذي يوفر القليل

أعتقد أنه سيكون "متوقعًا" نظرًا لأن $ python الأولي الخاص بك يقوم بتعيين __VENV_LAUNCHER__ وبعد ذلك يخدع البرامج النصية / الملفات التنفيذية الأخرى. لسوء الحظ ، ليس لدي OS X لتصحيح كيفية استمرار عملية "الخداع" بالضبط.

يمكن أيضًا أن تكون مماثلة / نفس المشكلة كما تم الإبلاغ عنها في # 620

jaraco ، قد يكون من المفيد تعديل pip في virtualenv لإلغاء التعليق على خطوط distlib المذكورة ومعرفة ما إذا كان هذا يبدو أنه يعمل على إصلاح سلوك النقطة في التقاط الثعبان الخاطئ للكتابة

لقد تتبعت رمز الكشف عن venv إلى هذا الالتزام ، والذي للأسف لا يوضح أصول الفكرة.

لقد وجدت هذا التفسير .

كان ميلي مشابهًا لما اقترحه رونالد هنا .

vsajip هل يمكن أن تقدم أي نصيحة؟

بعض الأفكار:

  • __PYVENV_LAUNCHER__ لأنه بالنسبة للإصدارات السابقة من Python (<3.3 ، وفقًا لرونالد) ولكن ليس للإصدارات الأحدث ، احتاج Python site.py على نظام التشغيل OS X للتمييز بين موقع قاذفات الروتين من ملفات الإطار التنفيذية. وفقًا لهذا التعليق من قبل Ned Deily ، يشير الآن sys.executable إلى قاذفة كعب الروتين ، ولهذا السبب توقف distlib عن استخدام __PYVENV_LAUNCHER__ . الاستخدام الوحيد الآن هو في site.py - إذا كان متاحًا ، في OS X ، يتم استخدامه لتحديد موقع الملف pyvenv.cfg .
  • قد يكون من المفيد التحقق لمعرفة ما يحدث في Python 3.4 ، لمعرفة ما إذا كان هناك نوع من الانحدار ، أو ما إذا كانت جميع Python> = 3.3 لها نفس السلوك.
  • أظن أن شيئًا ما ، في مكان ما ، يقوم بمكالمة os.path.realpath() عندما لا يكون كذلك. لا يبدو أنه يفعل ذلك distlib . إذا كان (حسب تعليق Ned) sys.executable و env var متماثلان دائمًا ، فلا يجب أن يكون الأمر مهمًا ؛ ولكن إذا حدث شيء ما realpath على sys.executable وقام بتنفيذ Python من خلال النتيجة ، فسيؤدي ذلك إلى shebang غير متوقع (لأن sys.executable سيكون مسارًا غير مرجعي).

عرض بسيط (آخر) للمشكلة ، والذي أعاد Homebrew اكتشافه في https://github.com/Homebrew/homebrew-core/pull/8129 :

$ virtualenv -p python3 test
$ test/bin/python3 -c 'import sys; print(sys.executable)'
/Users/tim/test/bin/python3

$ /usr/local/bin/python3 -c 'import subprocess; subprocess.call(["/Users/tim/test/bin/python3", "-c", "import sys; print(sys.executable)"])'
/usr/local/bin/python3

$ /usr/local/bin/python3 -c 'import subprocess, os; del os.environ["__PYVENV_LAUNCHER__"]; subprocess.call(["/Users/tim/test/bin/python3", "-c", "import sys; print(sys.executable)"])'
/Users/tim/test/bin/python3

لقد عضت للتو من هذا الخطأ الدقيق. إنه خطأ شديد في رأيي ، ويرجع ذلك في الغالب إلى أنه مربك للغاية ويصعب اكتشافه عند حدوثه.

لقد أصبت بما أعتقد أنه مظهر أكثر خطورة لهذه القضية.

لقد بدأت في استخدام xonsh كصدفة يومية.

ولكن عندما أحاول استخدام virtualenv تحت xonsh ، فإنه غير قابل للاستخدام:

~ $ cd ~/draft
draft $ virtualenv --version
16.0.0
draft $ virtualenv .env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/jaraco/draft/.env/bin/python3
Also creating executable in /Users/jaraco/draft/.env/bin/python
Installing setuptools, pip, wheel...done.
draft $ .env/bin/pip install paver
Collecting paver
  Using cached https://files.pythonhosted.org/packages/98/1e/37ba8a75bd77ea56a75ef5ae66fe657b79205bbc36556c9456cd641782a4/Paver-1.3.4-py2.py3-none-any.whl
Collecting six (from paver)
  Using cached https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
Installing collected packages: six, paver
Successfully installed paver-1.3.4 six-1.11.0
  The script paver is installed in '/Users/jaraco/draft/.env/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
draft $ .env/bin/paver --help
Traceback (most recent call last):
  File ".env/bin/paver", line 7, in <module>
    from paver.tasks import main
ModuleNotFoundError: No module named 'paver'
draft $ head -n 1 .env/bin/paver
#!/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

يبدو أن جميع البرامج النصية المثبتة تحصل على بادئة النظام وليس بادئة virtualenv.

ربما ينبع هذا من حقيقة أن xonsh يعمل تحت Python 3.7 (بادئة النظام) وكذلك هذا في env:

draft $ env | grep LAUNCHER
__PYVENV_LAUNCHER__=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

إذا قمت بدلاً من ذلك بتشغيل zsh وقمت بتشغيل نفس الأوامر أو إذا قمت أولاً باستدعاء del $__PYVENV_LAUNCHER__ ، فسيتم تشغيل الرصف كما هو متوقع ويشير خط shebang إلى virtualenv.

هل يجب على xonsh مسح متغير البيئة هذا عند بدء تشغيله؟

يوجد إصلاح خطأ محتمل على https://github.com/python/cpython/pull/9516

تم وضع علامة على هذه المشكلة تلقائيًا على أنها قديمة نظرًا لعدم وجود نشاط حديث لها. سيتم إغلاقه إذا لم يحدث أي نشاط آخر. فقط أضف تعليقًا إذا كنت تريد إبقائه مفتوحًا. شكرا لمساهماتكم.

ما زلت أرى نفس السلوك على Mojave مع Python 3.7.6 (مثبت عبر Homebrew).

هل يمكنك التحقق من فرع إعادة الكتابة؟

gaborbernat محاولة إنشاء فرع rewrite (fbdd782257d8eace7f5440a2b665f2ddb72e9db6) تعطيني خطأ في الإنشاء من python3 setup.py build .

...src/virtualenv/__init__.py", line 3, in <module>
    from .version import __version__
ModuleNotFoundError: No module named 'virtualenv.version'

التي لا تبدو ذات صلة بهذه القضية.

تعطيني محاولة إنشاء فرع إعادة الكتابة (fbdd782) خطأ في الإنشاء من بناء python3 setup.py.

يجب عليك استخدام النقطة لإجراء الإنشاء - pip wheel . - حيث يستخدم فرع إعادة الكتابة pyproject.toml لتعريف عملية الإنشاء.

الخطأ الذي تحصل عليه هو طريقة setuptools للقول إنني لا أدعم الطريقة القياسية الجديدة لبناء مكتبات بايثون (PEP-517/518). إنه خطأ في setuptools في أحسن الأحوال ، ولكن كما أشار pfmoore ، يجب عليك استخدام النقطة لبناء عجلة ، أو حتى أفضل لتوجيهها إلى مجلد virtualenv لتثبيتها (ستقوم تلقائيًا ببناء عجلة وتثبيتها دفعة واحدة).

حالة اختبار:

#!/bin/bash
rm -rf venv-test
virtualenv --python python3 venv-test
python3 -c 'import subprocess; subprocess.check_call(["./venv-test/bin/pip3", "install", "markdown"])'
shebang=$(head -1 venv-test/bin/markdown_py)
expected_shebang="#!$(pwd)/venv-test/bin/python"
if [ "$shebang" == "$expected_shebang" ]; then
    echo "PASSED"
else
    echo "FAILED: \"$shebang\" != \"$expected_shebang\""
    exit 1
fi

فشل هذا في إطار python3 + virtualenv 16.7.9 ، ويمر تحت python3 + virtualenv-16.7.10.dev11 + gfbdd782 (على سبيل المثال ، الفرع rewrite ).

ثابت في إعادة الكتابة على النحو الوارد أعلاه.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات