Commit 67aefd1b authored by Jason R. Coombs's avatar Jason R. Coombs

Merge branch 'develop-nspkg-always' into issue250-module_from_spec

parents acd94990 3dd506f0
...@@ -9,10 +9,11 @@ from setuptools.extern import six ...@@ -9,10 +9,11 @@ from setuptools.extern import six
from pkg_resources import Distribution, PathMetadata, normalize_path from pkg_resources import Distribution, PathMetadata, normalize_path
from setuptools.command.easy_install import easy_install from setuptools.command.easy_install import easy_install
from setuptools import namespaces
import setuptools import setuptools
class develop(easy_install): class develop(namespaces.DevelopInstaller, easy_install):
"""Set up package for development""" """Set up package for development"""
description = "install package in 'development mode'" description = "install package in 'development mode'"
...@@ -30,6 +31,7 @@ class develop(easy_install): ...@@ -30,6 +31,7 @@ class develop(easy_install):
if self.uninstall: if self.uninstall:
self.multi_version = True self.multi_version = True
self.uninstall_link() self.uninstall_link()
self.uninstall_namespaces()
else: else:
self.install_for_development() self.install_for_development()
self.warn_deprecated_options() self.warn_deprecated_options()
...@@ -123,6 +125,8 @@ class develop(easy_install): ...@@ -123,6 +125,8 @@ class develop(easy_install):
self.easy_install(setuptools.bootstrap_install_from) self.easy_install(setuptools.bootstrap_install_from)
setuptools.bootstrap_install_from = None setuptools.bootstrap_install_from = None
self.install_namespaces()
# create an .egg-link in the installation dir, pointing to our egg # create an .egg-link in the installation dir, pointing to our egg
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
if not self.dry_run: if not self.dry_run:
......
...@@ -31,21 +31,27 @@ class Installer: ...@@ -31,21 +31,27 @@ class Installer:
with open(filename, 'wt') as f: with open(filename, 'wt') as f:
f.writelines(lines) f.writelines(lines)
def uninstall_namespaces(self):
filename, ext = os.path.splitext(self._get_target())
filename += self.nspkg_ext
if not os.path.exists(filename):
return
log.info("Removing %s", filename)
os.remove(filename)
def _get_target(self): def _get_target(self):
return self.target return self.target
_nspkg_tmpl = ( _nspkg_tmpl = (
"import sys, types, os, importlib.util, importlib.machinery", "import sys, types, os, importlib.util, importlib.machinery",
"pep420 = (3, 3) < sys.version_info < (3, 5)",
"has_mfs = sys.version_info > (3, 5)", "has_mfs = sys.version_info > (3, 5)",
"p = os.path.join(%(root)s, *%(pth)r)", "p = os.path.join(%(root)s, *%(pth)r)",
"ie = os.path.exists(os.path.join(p,'__init__.py'))", "m = has_mfs and "
"m = not ie and not pep420 and has_mfs and "
"sys.modules.setdefault(%(pkg)r, " "sys.modules.setdefault(%(pkg)r, "
"importlib.util.module_from_spec(" "importlib.util.module_from_spec("
"importlib.machinery.PathFinder.find_spec(%(pkg)r, " "importlib.machinery.PathFinder.find_spec(%(pkg)r, "
"[os.path.dirname(p)])))", "[os.path.dirname(p)])))",
"m = not ie and not pep420 and not has_mfs and " "m = not has_mfs and "
"sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))", "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
"mp = (m or []) and m.__dict__.setdefault('__path__',[])", "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
"(p not in mp) and mp.append(p)", "(p not in mp) and mp.append(p)",
......
"""develop tests """develop tests
""" """
from __future__ import absolute_import, unicode_literals
import os import os
import site import site
import sys import sys
import io import io
import subprocess
from setuptools.extern import six from setuptools.extern import six
...@@ -12,6 +16,7 @@ import pytest ...@@ -12,6 +16,7 @@ import pytest
from setuptools.command.develop import develop from setuptools.command.develop import develop
from setuptools.dist import Distribution from setuptools.dist import Distribution
from . import contexts from . import contexts
from . import namespaces
SETUP_PY = """\ SETUP_PY = """\
from setuptools import setup from setuptools import setup
...@@ -114,3 +119,47 @@ class TestDevelop: ...@@ -114,3 +119,47 @@ class TestDevelop:
cmd.install_dir = tmpdir cmd.install_dir = tmpdir
cmd.run() cmd.run()
# assert '0.0' not in foocmd_text # assert '0.0' not in foocmd_text
class TestNamespaces:
@staticmethod
def install_develop(src_dir, target):
develop_cmd = [
sys.executable,
'setup.py',
'develop',
'--install-dir', str(target),
]
env = dict(PYTHONPATH=str(target))
with src_dir.as_cwd():
subprocess.check_call(develop_cmd, env=env)
def test_namespace_package_importable(self, tmpdir):
"""
Installing two packages sharing the same namespace, one installed
naturally using pip or `--single-version-externally-managed`
and the other installed using `develop` should leave the namespace
in tact and both packages reachable by import.
"""
pkg_A = namespaces.build_namespace_package(tmpdir, 'myns.pkgA')
pkg_B = namespaces.build_namespace_package(tmpdir, 'myns.pkgB')
target = tmpdir / 'packages'
# use pip to install to the target directory
install_cmd = [
'pip',
'install',
str(pkg_A),
'-t', str(target),
]
subprocess.check_call(install_cmd)
self.install_develop(pkg_B, target)
namespaces.make_site_dir(target)
try_import = [
sys.executable,
'-c', 'import myns.pkgA; import myns.pkgB',
]
env = dict(PYTHONPATH=str(target))
subprocess.check_call(try_import, env=env)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment