Commit 80fc5b6d authored by Wyatt Lee Baldwin's avatar Wyatt Lee Baldwin

Add support for PEP 420 namespace packages to find_packages()

On Python 3.3+, `find_packages()` now considers any subdirectory of the
start directory that's not a regular package (i.e., that doesn't have an
`__init__.py`) to be a namespace package.

The other way this supports PEP 420 is by making sure `__pycache__`
directories are never added to the list of packages.

Fixes issue #97
parent c74177b8
...@@ -2,6 +2,15 @@ ...@@ -2,6 +2,15 @@
CHANGES CHANGES
======= =======
---
4.0
---
* Issue #97: ``find_packages()`` now supports PEP 420 namespace packages. It
does so by considering all subdirectories of the start directory that
aren't regular packages to be PEP 420 namespace packages (on Python 3.3+
only).
--- ---
3.3 3.3
--- ---
......
[setuptools.installation] [setuptools.installation]
eggsecutable = setuptools.command.easy_install:bootstrap eggsecutable = setuptools.command.easy_install:bootstrap
[egg_info.writers]
entry_points.txt = setuptools.command.egg_info:write_entries
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
eager_resources.txt = setuptools.command.egg_info:overwrite_arg
top_level.txt = setuptools.command.egg_info:write_toplevel_names
namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
depends.txt = setuptools.command.egg_info:warn_depends_obsolete
requires.txt = setuptools.command.egg_info:write_requirements
PKG-INFO = setuptools.command.egg_info:write_pkg_info
[setuptools.file_finders]
svn_cvs = setuptools.command.sdist:_default_revctrl
[console_scripts]
easy_install-3.4 = setuptools.command.easy_install:main
easy_install = setuptools.command.easy_install:main
[distutils.setup_keywords] [distutils.setup_keywords]
use_2to3_fixers = setuptools.dist:assert_string_list
dependency_links = setuptools.dist:assert_string_list
packages = setuptools.dist:check_packages packages = setuptools.dist:check_packages
entry_points = setuptools.dist:check_entry_points use_2to3_exclude_fixers = setuptools.dist:assert_string_list
test_suite = setuptools.dist:check_test_suite
include_package_data = setuptools.dist:assert_bool
exclude_package_data = setuptools.dist:check_package_data
convert_2to3_doctests = setuptools.dist:assert_string_list convert_2to3_doctests = setuptools.dist:assert_string_list
extras_require = setuptools.dist:check_extras
install_requires = setuptools.dist:check_requirements
use_2to3_fixers = setuptools.dist:assert_string_list
zip_safe = setuptools.dist:assert_bool
namespace_packages = setuptools.dist:check_nsp
test_loader = setuptools.dist:check_importable
use_2to3 = setuptools.dist:assert_bool use_2to3 = setuptools.dist:assert_bool
exclude_package_data = setuptools.dist:check_package_data
entry_points = setuptools.dist:check_entry_points
test_loader = setuptools.dist:check_importable
namespace_packages = setuptools.dist:check_nsp
zip_safe = setuptools.dist:assert_bool
extras_require = setuptools.dist:check_extras
eager_resources = setuptools.dist:assert_string_list eager_resources = setuptools.dist:assert_string_list
dependency_links = setuptools.dist:assert_string_list
tests_require = setuptools.dist:check_requirements tests_require = setuptools.dist:check_requirements
package_data = setuptools.dist:check_package_data package_data = setuptools.dist:check_package_data
use_2to3_exclude_fixers = setuptools.dist:assert_string_list test_suite = setuptools.dist:check_test_suite
include_package_data = setuptools.dist:assert_bool
[setuptools.file_finders] install_requires = setuptools.dist:check_requirements
svn_cvs = setuptools.command.sdist:_default_revctrl
[distutils.commands] [distutils.commands]
setopt = setuptools.command.setopt:setopt upload_docs = setuptools.command.upload_docs:upload_docs
easy_install = setuptools.command.easy_install:easy_install egg_info = setuptools.command.egg_info:egg_info
bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
register = setuptools.command.register:register
test = setuptools.command.test:test
install_scripts = setuptools.command.install_scripts:install_scripts install_scripts = setuptools.command.install_scripts:install_scripts
saveopts = setuptools.command.saveopts:saveopts
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
rotate = setuptools.command.rotate:rotate
install = setuptools.command.install:install install = setuptools.command.install:install
alias = setuptools.command.alias:alias
bdist_egg = setuptools.command.bdist_egg:bdist_egg bdist_egg = setuptools.command.bdist_egg:bdist_egg
build_py = setuptools.command.build_py:build_py test = setuptools.command.test:test
install_egg_info = setuptools.command.install_egg_info:install_egg_info
install_lib = setuptools.command.install_lib:install_lib install_lib = setuptools.command.install_lib:install_lib
rotate = setuptools.command.rotate:rotate sdist = setuptools.command.sdist:sdist
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm register = setuptools.command.register:register
egg_info = setuptools.command.egg_info:egg_info
develop = setuptools.command.develop:develop develop = setuptools.command.develop:develop
install_egg_info = setuptools.command.install_egg_info:install_egg_info build_py = setuptools.command.build_py:build_py
setopt = setuptools.command.setopt:setopt
build_ext = setuptools.command.build_ext:build_ext build_ext = setuptools.command.build_ext:build_ext
sdist = setuptools.command.sdist:sdist alias = setuptools.command.alias:alias
saveopts = setuptools.command.saveopts:saveopts easy_install = setuptools.command.easy_install:easy_install
upload_docs = setuptools.command.upload_docs:upload_docs bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
[egg_info.writers]
namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
eager_resources.txt = setuptools.command.egg_info:overwrite_arg
entry_points.txt = setuptools.command.egg_info:write_entries
PKG-INFO = setuptools.command.egg_info:write_pkg_info
depends.txt = setuptools.command.egg_info:warn_depends_obsolete
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
top_level.txt = setuptools.command.egg_info:write_toplevel_names
requires.txt = setuptools.command.egg_info:write_requirements
[console_scripts]
easy_install = setuptools.command.easy_install:main
easy_install-3.4 = setuptools.command.easy_install:main
[ssl:sys_platform=='win32']
wincertstore==0.2
[certs] [certs]
certifi==1.0.1 certifi==1.0.1
[ssl:sys_platform=='win32']
wincertstore==0.2
\ No newline at end of file
...@@ -56,7 +56,10 @@ def find_packages(where='.', exclude=(), include=()): ...@@ -56,7 +56,10 @@ def find_packages(where='.', exclude=(), include=()):
looks_like_package = ( looks_like_package = (
'.' not in name '.' not in name
and os.path.isdir(fn) and os.path.isdir(fn)
and os.path.isfile(os.path.join(fn, '__init__.py')) and (
os.path.isfile(os.path.join(fn, '__init__.py'))
or sys.version_info[:2] >= (3, 3) # PEP 420
)
) )
if looks_like_package: if looks_like_package:
pkg_name = prefix + name pkg_name = prefix + name
......
"""Tests for setuptools.find_packages().""" """Tests for setuptools.find_packages()."""
import os import os
import shutil import shutil
import sys
import tempfile import tempfile
import unittest import unittest
from setuptools import find_packages from setuptools import find_packages
PEP420 = sys.version_info[:2] >= (3, 3)
class TestFindPackages(unittest.TestCase): class TestFindPackages(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -58,6 +62,7 @@ class TestFindPackages(unittest.TestCase): ...@@ -58,6 +62,7 @@ class TestFindPackages(unittest.TestCase):
fp.close() fp.close()
return path return path
@unittest.skipIf(PEP420, 'Not a PEP 420 env')
def test_regular_package(self): def test_regular_package(self):
self._touch('__init__.py', self.pkg_dir) self._touch('__init__.py', self.pkg_dir)
packages = find_packages(self.dist_dir) packages = find_packages(self.dist_dir)
...@@ -80,3 +85,36 @@ class TestFindPackages(unittest.TestCase): ...@@ -80,3 +85,36 @@ class TestFindPackages(unittest.TestCase):
self._touch('file.dat', data_dir) self._touch('file.dat', data_dir)
packages = find_packages(self.dist_dir) packages = find_packages(self.dist_dir)
self.assertTrue('pkg.some.data' not in packages) self.assertTrue('pkg.some.data' not in packages)
@unittest.skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package(self):
packages = find_packages(
self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'])
self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
@unittest.skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package_no_includes(self):
packages = find_packages(
self.dist_dir, exclude=['pkg.subpkg.assets'])
self.assertEqual(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
@unittest.skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package_no_includes_or_excludes(self):
packages = find_packages(self.dist_dir)
expected = [
'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
self.assertEqual(packages, expected)
@unittest.skipIf(not PEP420, 'PEP 420 only')
def test_regular_package_with_nested_pep420_ns_packages(self):
self._touch('__init__.py', self.pkg_dir)
packages = find_packages(
self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'])
self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
@unittest.skipIf(not PEP420, 'PEP 420 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_packages(self.dist_dir)
self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
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