Skip to content

Commit

Permalink
fix pypa#97 introduce find_packages_ns() for also finding PEP420 name…
Browse files Browse the repository at this point in the history
…space packages
  • Loading branch information
silkentrance committed Jul 4, 2018
1 parent 244ff32 commit 4fef13b
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
v39.2.0
-------

* #97: PEP 420: introduce find_packages_ns()
* #1359: Support using "file:" to load a PEP 440-compliant package version from
a text file.
* #1360: Fixed issue with a mismatch between the name of the package and the
Expand Down
18 changes: 18 additions & 0 deletions docs/setuptools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ Feature Highlights:
* Create extensible applications and frameworks that automatically discover
extensions, using simple "entry points" declared in a project's setup script.

* Full support for PEP 420 via ``find_packages_ns()``, which is also backwards
compatible to the existing ``find_packages()`` for Python >= 3.3.

.. contents:: **Table of Contents**

.. _ez_setup.py: `bootstrap module`_
Expand Down Expand Up @@ -107,6 +110,21 @@ As you can see, it doesn't take much to use setuptools in a project.
Run that script in your project folder, alongside the Python packages
you have developed.

For Python 3.3+, and whenever you are using PEP 420 compliant implicit
namespace packages, you can use ``find_packages_ns()`` instead.
But keep in mind that if you do, you might have to either define a few
exclusions or reorganize your codebase a little bit so that the new function
does not find for example your test fixtures and treat them as implicit
namespace packages. And here is a minimal setup script using
``find_packages_ns()``::

from setuptools import setup, find_packages_ns as find_packages
setup(
name="HelloWorld",
version="0.1",
packages=find_packages(),
)

Invoke that script to produce eggs, upload to
PyPI, and automatically include all packages in the directory where the
setup.py lives. See the `Command Reference`_ section below to see what
Expand Down
9 changes: 8 additions & 1 deletion setuptools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Extensions to the 'distutils' for large or complex distributions"""

import os
import sys
import functools
import distutils.core
import distutils.filelist
from distutils.util import convert_path
from fnmatch import fnmatchcase

from setuptools.extern.six import PY3
from setuptools.extern.six.moves import filter, map

import setuptools.version
Expand All @@ -17,11 +19,15 @@

__metaclass__ = type


__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
'find_packages',
'find_packages'
]

if PY3:
__all__.append('find_packages_ns')

__version__ = setuptools.version.__version__

bootstrap_install_from = None
Expand Down Expand Up @@ -110,6 +116,7 @@ def _looks_like_package(path):


find_packages = PackageFinder.find
find_packages_ns = PEP420PackageFinder.find


def _install_setup_requires(attrs):
Expand Down
26 changes: 16 additions & 10 deletions setuptools/tests/test_find_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

import pytest

import setuptools
from setuptools.extern.six import PY3
from setuptools import find_packages

find_420_packages = setuptools.PEP420PackageFinder.find
py3_only = pytest.mark.xfail(not PY3, reason="Test runs on Python 3 only")
if PY3:
from setuptools import find_packages_ns

# modeled after CPython's test.support.can_symlink


def can_symlink():
TESTFN = tempfile.mktemp()
symlink_path = TESTFN + "can_symlink"
Expand Down Expand Up @@ -153,30 +154,35 @@ def test_symlinked_packages_are_included(self):
def _assert_packages(self, actual, expected):
assert set(actual) == set(expected)

@py3_only
def test_pep420_ns_package(self):
packages = find_420_packages(
packages = find_packages_ns(
self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'])
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])

@py3_only
def test_pep420_ns_package_no_includes(self):
packages = find_420_packages(
packages = find_packages_ns(
self.dist_dir, exclude=['pkg.subpkg.assets'])
self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])

@py3_only
def test_pep420_ns_package_no_includes_or_excludes(self):
packages = find_420_packages(self.dist_dir)
expected = [
'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
packages = find_packages_ns(self.dist_dir)
expected = ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
self._assert_packages(packages, expected)

@py3_only
def test_regular_package_with_nested_pep420_ns_packages(self):
self._touch('__init__.py', self.pkg_dir)
packages = find_420_packages(
packages = find_packages_ns(
self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'])
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])

@py3_only
def test_pep420_ns_package_no_non_package_dirs(self):
shutil.rmtree(self.docs_dir)
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
packages = find_420_packages(self.dist_dir)
packages = find_packages_ns(self.dist_dir)
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])

0 comments on commit 4fef13b

Please sign in to comment.