pyflyby 1.9.11__tar.gz → 1.9.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyflyby might be problematic. Click here for more details.
- {pyflyby-1.9.11/lib/python/pyflyby.egg-info → pyflyby-1.9.12}/PKG-INFO +1 -1
- {pyflyby-1.9.11/lib/python → pyflyby-1.9.12/bin}/pyflyby/_py.py +77 -0
- {pyflyby-1.9.11/lib/python → pyflyby-1.9.12/bin}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.11/bin → pyflyby-1.9.12/lib/python}/pyflyby/_py.py +77 -0
- {pyflyby-1.9.11/bin → pyflyby-1.9.12/lib/python}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.11 → pyflyby-1.9.12/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_py.py +61 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/.pyflyby +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/LICENSE.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/MANIFEST.in +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/README.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/autoipython +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/autopython +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/collect-exports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/collect-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/create-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/find-import +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/prune-broken-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_autoimp.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_dynimp.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_file.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_format.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_log.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_parse.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_saveframe.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_saveframe_reader.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/_util.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/pyflyby-diff +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/reformat-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/replace-star-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/saveframe +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/tidy-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/bin/transform-imports +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/LICENSE.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/Makefile +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/TODO.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/__init__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/api.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/comms.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/dbg.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/file.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/flags.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/format.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/idents.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/importclns.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/importdb.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/interactive.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/log.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/modules.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/parse.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/py.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/api/util.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/cli.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/py.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/conf.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/index.rst +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/make.bat +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/doc/testing.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_autoimp.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_dynimp.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_file.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_parse.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_saveframe.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_saveframe_reader.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/_util.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby.egg-info/requires.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/pyproject.toml +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/setup.cfg +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/setup.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/__init__.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_autoimp.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_cmdline.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_docxref.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_file.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_flags.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_format.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_idents.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_importclns.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_importdb.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_imports2s.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_importstmt.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_interactive.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_livepatch.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_modules.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_parse.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_saveframe.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_saveframe_reader.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/test_util.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/tests_sorts.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tests/xrefs.py +0 -0
- {pyflyby-1.9.11 → pyflyby-1.9.12}/tox.ini +0 -0
|
@@ -281,7 +281,9 @@ Examples
|
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
from functools import total_ordering
|
|
284
|
+
from pathlib import Path
|
|
284
285
|
from typing import Any
|
|
286
|
+
import warnings
|
|
285
287
|
|
|
286
288
|
from pyflyby._util import cmp
|
|
287
289
|
from shlex import quote as shquote
|
|
@@ -1410,9 +1412,84 @@ def print_result(result, output_mode):
|
|
|
1410
1412
|
raise AssertionError("unexpected output_mode=%r" % (output_mode,))
|
|
1411
1413
|
|
|
1412
1414
|
|
|
1415
|
+
def _get_path_links(p: Path):
|
|
1416
|
+
"""Gets path links including all symlinks.
|
|
1417
|
+
|
|
1418
|
+
Adapted from `IPython.core.interactiveshell.InteractiveShell.get_path_links`.
|
|
1419
|
+
"""
|
|
1420
|
+
paths = [p]
|
|
1421
|
+
while p.is_symlink():
|
|
1422
|
+
new_path = Path(os.readlink(p))
|
|
1423
|
+
if not new_path.is_absolute():
|
|
1424
|
+
new_path = p.parent / new_path
|
|
1425
|
+
p = new_path
|
|
1426
|
+
paths.append(p)
|
|
1427
|
+
return paths
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
def _init_virtualenv():
|
|
1431
|
+
"""Add the current virtualenv to sys.path so the user can import modules from it.
|
|
1432
|
+
|
|
1433
|
+
A warning will appear suggesting the user installs IPython in the
|
|
1434
|
+
virtualenv, but for many cases, it probably works well enough.
|
|
1435
|
+
|
|
1436
|
+
Adapted `IPython.core.interactiveshell.InteractiveShell.init_virtualenv`.
|
|
1437
|
+
"""
|
|
1438
|
+
if 'VIRTUAL_ENV' not in os.environ:
|
|
1439
|
+
# Not in a virtualenv
|
|
1440
|
+
return
|
|
1441
|
+
elif os.environ["VIRTUAL_ENV"] == "":
|
|
1442
|
+
warnings.warn("Virtual env path set to '', please check if this is intended.")
|
|
1443
|
+
return
|
|
1444
|
+
|
|
1445
|
+
p = Path(sys.executable)
|
|
1446
|
+
p_venv = Path(os.environ["VIRTUAL_ENV"]).resolve()
|
|
1447
|
+
|
|
1448
|
+
# fallback venv detection:
|
|
1449
|
+
# stdlib venv may symlink sys.executable, so we can't use realpath.
|
|
1450
|
+
# but others can symlink *to* the venv Python, so we can't just use sys.executable.
|
|
1451
|
+
# So we just check every item in the symlink tree (generally <= 3)
|
|
1452
|
+
paths = _get_path_links(p)
|
|
1453
|
+
|
|
1454
|
+
# In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
|
|
1455
|
+
if len(p_venv.parts) > 2 and p_venv.parts[1] == "cygdrive":
|
|
1456
|
+
drive_name = p_venv.parts[2]
|
|
1457
|
+
p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
|
|
1458
|
+
|
|
1459
|
+
if any(p_venv == p.parents[1].resolve() for p in paths):
|
|
1460
|
+
# Our exe is inside or has access to the virtualenv, don't need to do anything.
|
|
1461
|
+
return
|
|
1462
|
+
|
|
1463
|
+
if sys.platform == "win32":
|
|
1464
|
+
virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
|
|
1465
|
+
else:
|
|
1466
|
+
virtual_env_path = Path(
|
|
1467
|
+
os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
|
|
1468
|
+
)
|
|
1469
|
+
p_ver = sys.version_info[:2]
|
|
1470
|
+
|
|
1471
|
+
# Predict version from py[thon]-x.x in the $VIRTUAL_ENV
|
|
1472
|
+
re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
|
|
1473
|
+
if re_m:
|
|
1474
|
+
predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
|
|
1475
|
+
if predicted_path.exists():
|
|
1476
|
+
p_ver = re_m.groups()
|
|
1477
|
+
|
|
1478
|
+
virtual_env = str(virtual_env_path).format(*p_ver)
|
|
1479
|
+
|
|
1480
|
+
warnings.warn(
|
|
1481
|
+
"Attempting to work in a virtualenv. If you encounter problems, "
|
|
1482
|
+
"please install pyflyby inside the virtualenv."
|
|
1483
|
+
)
|
|
1484
|
+
import site
|
|
1485
|
+
sys.path.insert(0, virtual_env)
|
|
1486
|
+
site.addsitedir(virtual_env)
|
|
1487
|
+
|
|
1488
|
+
|
|
1413
1489
|
class _Namespace(object):
|
|
1414
1490
|
|
|
1415
1491
|
def __init__(self):
|
|
1492
|
+
_init_virtualenv()
|
|
1416
1493
|
self.globals = {"__name__": "__main__",
|
|
1417
1494
|
"__builtin__": builtins,
|
|
1418
1495
|
"__builtins__": builtins}
|
|
@@ -281,7 +281,9 @@ Examples
|
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
from functools import total_ordering
|
|
284
|
+
from pathlib import Path
|
|
284
285
|
from typing import Any
|
|
286
|
+
import warnings
|
|
285
287
|
|
|
286
288
|
from pyflyby._util import cmp
|
|
287
289
|
from shlex import quote as shquote
|
|
@@ -1410,9 +1412,84 @@ def print_result(result, output_mode):
|
|
|
1410
1412
|
raise AssertionError("unexpected output_mode=%r" % (output_mode,))
|
|
1411
1413
|
|
|
1412
1414
|
|
|
1415
|
+
def _get_path_links(p: Path):
|
|
1416
|
+
"""Gets path links including all symlinks.
|
|
1417
|
+
|
|
1418
|
+
Adapted from `IPython.core.interactiveshell.InteractiveShell.get_path_links`.
|
|
1419
|
+
"""
|
|
1420
|
+
paths = [p]
|
|
1421
|
+
while p.is_symlink():
|
|
1422
|
+
new_path = Path(os.readlink(p))
|
|
1423
|
+
if not new_path.is_absolute():
|
|
1424
|
+
new_path = p.parent / new_path
|
|
1425
|
+
p = new_path
|
|
1426
|
+
paths.append(p)
|
|
1427
|
+
return paths
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
def _init_virtualenv():
|
|
1431
|
+
"""Add the current virtualenv to sys.path so the user can import modules from it.
|
|
1432
|
+
|
|
1433
|
+
A warning will appear suggesting the user installs IPython in the
|
|
1434
|
+
virtualenv, but for many cases, it probably works well enough.
|
|
1435
|
+
|
|
1436
|
+
Adapted `IPython.core.interactiveshell.InteractiveShell.init_virtualenv`.
|
|
1437
|
+
"""
|
|
1438
|
+
if 'VIRTUAL_ENV' not in os.environ:
|
|
1439
|
+
# Not in a virtualenv
|
|
1440
|
+
return
|
|
1441
|
+
elif os.environ["VIRTUAL_ENV"] == "":
|
|
1442
|
+
warnings.warn("Virtual env path set to '', please check if this is intended.")
|
|
1443
|
+
return
|
|
1444
|
+
|
|
1445
|
+
p = Path(sys.executable)
|
|
1446
|
+
p_venv = Path(os.environ["VIRTUAL_ENV"]).resolve()
|
|
1447
|
+
|
|
1448
|
+
# fallback venv detection:
|
|
1449
|
+
# stdlib venv may symlink sys.executable, so we can't use realpath.
|
|
1450
|
+
# but others can symlink *to* the venv Python, so we can't just use sys.executable.
|
|
1451
|
+
# So we just check every item in the symlink tree (generally <= 3)
|
|
1452
|
+
paths = _get_path_links(p)
|
|
1453
|
+
|
|
1454
|
+
# In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
|
|
1455
|
+
if len(p_venv.parts) > 2 and p_venv.parts[1] == "cygdrive":
|
|
1456
|
+
drive_name = p_venv.parts[2]
|
|
1457
|
+
p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
|
|
1458
|
+
|
|
1459
|
+
if any(p_venv == p.parents[1].resolve() for p in paths):
|
|
1460
|
+
# Our exe is inside or has access to the virtualenv, don't need to do anything.
|
|
1461
|
+
return
|
|
1462
|
+
|
|
1463
|
+
if sys.platform == "win32":
|
|
1464
|
+
virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
|
|
1465
|
+
else:
|
|
1466
|
+
virtual_env_path = Path(
|
|
1467
|
+
os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
|
|
1468
|
+
)
|
|
1469
|
+
p_ver = sys.version_info[:2]
|
|
1470
|
+
|
|
1471
|
+
# Predict version from py[thon]-x.x in the $VIRTUAL_ENV
|
|
1472
|
+
re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
|
|
1473
|
+
if re_m:
|
|
1474
|
+
predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
|
|
1475
|
+
if predicted_path.exists():
|
|
1476
|
+
p_ver = re_m.groups()
|
|
1477
|
+
|
|
1478
|
+
virtual_env = str(virtual_env_path).format(*p_ver)
|
|
1479
|
+
|
|
1480
|
+
warnings.warn(
|
|
1481
|
+
"Attempting to work in a virtualenv. If you encounter problems, "
|
|
1482
|
+
"please install pyflyby inside the virtualenv."
|
|
1483
|
+
)
|
|
1484
|
+
import site
|
|
1485
|
+
sys.path.insert(0, virtual_env)
|
|
1486
|
+
site.addsitedir(virtual_env)
|
|
1487
|
+
|
|
1488
|
+
|
|
1413
1489
|
class _Namespace(object):
|
|
1414
1490
|
|
|
1415
1491
|
def __init__(self):
|
|
1492
|
+
_init_virtualenv()
|
|
1416
1493
|
self.globals = {"__name__": "__main__",
|
|
1417
1494
|
"__builtin__": builtins,
|
|
1418
1495
|
"__builtins__": builtins}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
import ast
|
|
8
9
|
import os
|
|
9
10
|
import pytest
|
|
10
11
|
from shutil import rmtree
|
|
@@ -13,6 +14,7 @@ import sys
|
|
|
13
14
|
import tempfile
|
|
14
15
|
from tempfile import NamedTemporaryFile, mkdtemp
|
|
15
16
|
from textwrap import dedent
|
|
17
|
+
import venv
|
|
16
18
|
|
|
17
19
|
from pyflyby._file import Filename
|
|
18
20
|
from pyflyby._util import cached_attribute
|
|
@@ -2734,6 +2736,65 @@ def test_apply_not_a_function():
|
|
|
2734
2736
|
assert "NotAFunctionError: ('Not a function', 75650517)" in result
|
|
2735
2737
|
|
|
2736
2738
|
|
|
2739
|
+
def test_virtualenv_recognized(tmpdir, monkeypatch):
|
|
2740
|
+
"""Verify that virtualenv sys.path is set correctly, and that warnings are emitted."""
|
|
2741
|
+
if os.environ.get("VIRTUAL_ENV") is not None:
|
|
2742
|
+
old_path = os.environ["PATH"].split(os.pathsep)
|
|
2743
|
+
new_path = os.pathsep.join(old_path[1:])
|
|
2744
|
+
|
|
2745
|
+
monkeypatch.delenv("VIRTUAL_ENV")
|
|
2746
|
+
monkeypatch.setenv("PATH", new_path)
|
|
2747
|
+
|
|
2748
|
+
no_venv_stdout = py('print(sys.path)')
|
|
2749
|
+
no_venv_sys_path = ast.literal_eval(no_venv_stdout.split('\n')[-1])
|
|
2750
|
+
|
|
2751
|
+
env_dir = os.path.join(tmpdir, "venv")
|
|
2752
|
+
env_bin = os.path.join(env_dir, "Scripts" if os.name == "nt" else "bin")
|
|
2753
|
+
venv.create(env_dir)
|
|
2754
|
+
|
|
2755
|
+
# Simulate activation
|
|
2756
|
+
monkeypatch.setenv("VIRTUAL_ENV", env_dir)
|
|
2757
|
+
monkeypatch.setenv("PATH", env_bin + os.pathsep + os.environ["PATH"])
|
|
2758
|
+
|
|
2759
|
+
venv_stdout = py('print(sys.path)')
|
|
2760
|
+
venv_sys_path = ast.literal_eval(venv_stdout.split('\n')[-1])
|
|
2761
|
+
|
|
2762
|
+
# Check that the appropriate warning is in place when using the venv,
|
|
2763
|
+
# and missing if not.
|
|
2764
|
+
warning = (
|
|
2765
|
+
"UserWarning: Attempting to work in a virtualenv. "
|
|
2766
|
+
"If you encounter problems, please install pyflyby inside the virtualenv."
|
|
2767
|
+
)
|
|
2768
|
+
assert warning not in no_venv_stdout
|
|
2769
|
+
assert warning in venv_stdout
|
|
2770
|
+
|
|
2771
|
+
# Check that sys.path printed from the subprocess contains the same
|
|
2772
|
+
# paths as what we have in the test process
|
|
2773
|
+
for path in sys.path:
|
|
2774
|
+
|
|
2775
|
+
# If a path is missing from one, it must be missing from the other
|
|
2776
|
+
# (because both are called in subprocesses, which means that e.g.
|
|
2777
|
+
# the pyenv bin path won't be included in the subprocess call but
|
|
2778
|
+
# will be in the pytest call that runs this test)
|
|
2779
|
+
if path not in no_venv_stdout:
|
|
2780
|
+
assert path not in venv_stdout
|
|
2781
|
+
else:
|
|
2782
|
+
assert path in venv_stdout
|
|
2783
|
+
assert path in no_venv_stdout
|
|
2784
|
+
|
|
2785
|
+
# Check that sys.path of the non-virtualenv appears
|
|
2786
|
+
# in the sys.path of the virtualenv
|
|
2787
|
+
#
|
|
2788
|
+
# Get the last line (which contains the printed sys.path); convert
|
|
2789
|
+
# back into a list
|
|
2790
|
+
assert all(path in venv_sys_path for path in no_venv_sys_path)
|
|
2791
|
+
|
|
2792
|
+
# Check that the virtualenv directory appears in the sys.path of
|
|
2793
|
+
# the virtualenv, but not in the sys.path of the non-virtualenv
|
|
2794
|
+
assert not any(env_dir in path for path in no_venv_sys_path)
|
|
2795
|
+
assert any(env_dir in path for path in venv_sys_path)
|
|
2796
|
+
|
|
2797
|
+
|
|
2737
2798
|
# TODO: test timeit, time
|
|
2738
2799
|
# TODO: test --attach
|
|
2739
2800
|
# TODO: test postmortem debugging
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|