Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
v38.2.2
-------

* #1214: fix handling of namespace packages when installing
from a wheel.

v38.2.1
-------

Expand Down
2 changes: 1 addition & 1 deletion setuptools/command/easy_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ def install_wheel(self, wheel_path, tmpdir):
try:
self.execute(
wheel.install_as_egg,
(destination,),
(os.path.dirname(destination),),
("Installing %s to %s") % (
os.path.basename(wheel_path),
os.path.dirname(destination)
Expand Down
40 changes: 33 additions & 7 deletions setuptools/tests/test_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import pytest

from pkg_resources import Distribution, PathMetadata, PY_MAJOR
from pkg_resources import PY_MAJOR
from setuptools.wheel import Wheel

from .contexts import tempdir
Expand Down Expand Up @@ -116,19 +116,14 @@ def prefix(path_depth):
def _check_wheel_install(filename, install_dir, install_tree,
project_name, version, requires_txt):
w = Wheel(filename)
egg_path = os.path.join(install_dir, w.egg_name())
w.install_as_egg(egg_path)
dist = w.install_as_egg(install_dir)
if install_tree is not None:
install_tree = install_tree.format(
py_version=PY_MAJOR,
platform=get_platform(),
shlib_ext=get_config_var('EXT_SUFFIX') or get_config_var('SO')
)
assert install_tree == tree(install_dir)
metadata = PathMetadata(egg_path, os.path.join(egg_path, 'EGG-INFO'))
dist = Distribution.from_filename(egg_path, metadata=metadata)
assert dist.project_name == project_name
assert dist.version == version
if requires_txt is None:
assert not dist.has_metadata('requires.txt')
else:
Expand Down Expand Up @@ -412,6 +407,37 @@ def __repr__(self):
),
),

dict(
id='namespace_package',
file_defs={
'foo': {
'bar': {
'__init__.py': ''
},
},
},
setup_kwargs=dict(
namespace_packages=['foo'],
packages=['foo.bar'],
),
install_tree=DALS(
'''
foo-1.0-py{py_version}-nspkg.pth
foo-1.0-py{py_version}.egg/
|-- foo-1.0-py{py_version}-nspkg.pth
|-- EGG-INFO/
| |-- DESCRIPTION.rst
| |-- PKG-INFO
| |-- RECORD
| |-- WHEEL
| |-- metadata.json
| |-- namespace_packages.txt
| |-- top_level.txt
|-- foo/
| |-- bar/
| | |-- __init__.py
'''),
),
)

@pytest.mark.parametrize(
Expand Down
29 changes: 28 additions & 1 deletion setuptools/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from setuptools import Distribution as SetuptoolsDistribution
from setuptools import pep425tags
from setuptools.command.egg_info import write_requirements
from setuptools.namespaces import Installer


WHEEL_NAME = re.compile(
Expand All @@ -21,6 +22,22 @@
re.VERBOSE).match


class NamespacesInstaller(Installer):

def __init__(self, destination, namespace_packages):
self.outputs = []
self.dry_run = False
self.target = destination
self.distribution = SetuptoolsDistribution()
self.distribution.namespace_packages = namespace_packages

def _get_root(self):
return "os.path.join(%s, %r)" % (
Installer._get_root(self),
os.path.basename(self.target),
)


class Wheel(object):

def __init__(self, filename):
Expand Down Expand Up @@ -48,8 +65,9 @@ def egg_name(self):
platform=(None if self.platform == 'any' else get_platform()),
).egg_name() + '.egg'

def install_as_egg(self, destination_eggdir):
def install_as_egg(self, destination_dir):
'''Install wheel as an egg directory.'''
destination_eggdir = os.path.join(destination_dir, self.egg_name())
with zipfile.ZipFile(self.filename) as zf:
dist_basename = '%s-%s' % (self.project_name, self.version)
dist_info = '%s.dist-info' % dist_basename
Expand Down Expand Up @@ -124,3 +142,12 @@ def raw_req(req):
os.rmdir(subdir)
if os.path.exists(dist_data):
os.rmdir(dist_data)
dist = Distribution.from_location(
destination_eggdir, egg_info,
metadata=PathMetadata(destination_eggdir, egg_info)
)
if dist.has_metadata('namespace_packages.txt'):
namespace_packages = dist.get_metadata('namespace_packages.txt').split()
installer = NamespacesInstaller(destination_eggdir, namespace_packages)
installer.install_namespaces()
return dist