Skip to content

Commit

Permalink
Backport PR ipython#12548: Introduce pathlib on init_virtualenv.
Browse files Browse the repository at this point in the history
  • Loading branch information
Carreau authored and meeseeksmachine committed Sep 21, 2021
1 parent bf0ef17 commit 7d3594c
Showing 1 changed file with 24 additions and 23 deletions.
47 changes: 24 additions & 23 deletions IPython/core/interactiveshell.py
Expand Up @@ -28,6 +28,7 @@
import warnings
from io import open as io_open

from pathlib import Path
from pickleshare import PickleShareDB

from traitlets.config.configurable import SingletonConfigurable
Expand Down Expand Up @@ -892,7 +893,7 @@ def init_displayhook(self):
self.display_trap = DisplayTrap(hook=self.displayhook)

def init_virtualenv(self):
"""Add a virtualenv to sys.path so the user can import modules from it.
"""Add the current virtualenv to sys.path so the user can import modules from it.
This isn't perfect: it doesn't use the Python interpreter with which the
virtualenv was built, and it ignores the --no-site-packages option. A
warning will appear suggesting the user installs IPython in the
Expand All @@ -905,42 +906,42 @@ def init_virtualenv(self):
if 'VIRTUAL_ENV' not in os.environ:
# Not in a virtualenv
return

p = os.path.normcase(sys.executable)
p_venv = os.path.normcase(os.environ['VIRTUAL_ENV'])

# executable path should end like /bin/python or \\scripts\\python.exe
p_exe_up2 = os.path.dirname(os.path.dirname(p))
if p_exe_up2 and os.path.exists(p_venv) and os.path.samefile(p_exe_up2, p_venv):
# Our exe is inside the virtualenv, don't need to do anything.
elif os.environ["VIRTUAL_ENV"] == "":
warn("Virtual env path set to '', please check if this is intended.")
return

p = Path(sys.executable)
p_venv = Path(os.environ["VIRTUAL_ENV"])

# fallback venv detection:
# stdlib venv may symlink sys.executable, so we can't use realpath.
# but others can symlink *to* the venv Python, so we can't just use sys.executable.
# So we just check every item in the symlink tree (generally <= 3)
paths = [p]
while os.path.islink(p):
p = os.path.normcase(os.path.join(os.path.dirname(p), os.readlink(p)))
paths.append(p)
while p.is_symlink():
p = Path(os.readlink(p))
paths.append(p.resolve())

# In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
if p_venv.startswith('\\cygdrive'):
p_venv = p_venv[11:]
elif len(p_venv) >= 2 and p_venv[1] == ':':
p_venv = p_venv[2:]
if str(p_venv).startswith("\\cygdrive"):
p_venv = Path(str(p_venv)[11:])
elif len(str(p_venv)) >= 2 and str(p_venv)[1] == ":":
p_venv = Path(str(p_venv)[2:])

if any(p_venv in p for p in paths):
# Running properly in the virtualenv, don't need to do anything
if any(os.fspath(p_venv) in os.fspath(p) for p in paths):
# Our exe is inside or has access to the virtualenv, don't need to do anything.
return

warn("Attempting to work in a virtualenv. If you encounter problems, please "
"install IPython inside the virtualenv.")
if sys.platform == "win32":
virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath(
"Lib", "site-packages"
)
else:
virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
'python%d.%d' % sys.version_info[:2], 'site-packages')
virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath(
"lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages"
)

import site
sys.path.insert(0, virtual_env)
Expand Down

0 comments on commit 7d3594c

Please sign in to comment.