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
[distutils.setup_keywords] [egg_info.writers]
packages = setuptools.dist:check_packages entry_points.txt = setuptools.command.egg_info:write_entries
entry_points = setuptools.dist:check_entry_points dependency_links.txt = setuptools.command.egg_info:overwrite_arg
test_suite = setuptools.dist:check_test_suite eager_resources.txt = setuptools.command.egg_info:overwrite_arg
include_package_data = setuptools.dist:assert_bool top_level.txt = setuptools.command.egg_info:write_toplevel_names
exclude_package_data = setuptools.dist:check_package_data namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
convert_2to3_doctests = setuptools.dist:assert_string_list depends.txt = setuptools.command.egg_info:warn_depends_obsolete
extras_require = setuptools.dist:check_extras requires.txt = setuptools.command.egg_info:write_requirements
install_requires = setuptools.dist:check_requirements PKG-INFO = setuptools.command.egg_info:write_pkg_info
use_2to3_fixers = setuptools.dist:assert_string_list
zip_safe = setuptools.dist:assert_bool [setuptools.file_finders]
namespace_packages = setuptools.dist:check_nsp svn_cvs = setuptools.command.sdist:_default_revctrl
test_loader = setuptools.dist:check_importable
use_2to3 = setuptools.dist:assert_bool [console_scripts]
eager_resources = setuptools.dist:assert_string_list easy_install-3.4 = setuptools.command.easy_install:main
dependency_links = setuptools.dist:assert_string_list easy_install = setuptools.command.easy_install:main
tests_require = setuptools.dist:check_requirements
package_data = setuptools.dist:check_package_data [distutils.setup_keywords]
use_2to3_exclude_fixers = setuptools.dist:assert_string_list use_2to3_fixers = setuptools.dist:assert_string_list
dependency_links = setuptools.dist:assert_string_list
[setuptools.file_finders] packages = setuptools.dist:check_packages
svn_cvs = setuptools.command.sdist:_default_revctrl use_2to3_exclude_fixers = setuptools.dist:assert_string_list
convert_2to3_doctests = setuptools.dist:assert_string_list
[distutils.commands] use_2to3 = setuptools.dist:assert_bool
setopt = setuptools.command.setopt:setopt exclude_package_data = setuptools.dist:check_package_data
easy_install = setuptools.command.easy_install:easy_install entry_points = setuptools.dist:check_entry_points
bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst test_loader = setuptools.dist:check_importable
register = setuptools.command.register:register namespace_packages = setuptools.dist:check_nsp
test = setuptools.command.test:test zip_safe = setuptools.dist:assert_bool
install_scripts = setuptools.command.install_scripts:install_scripts extras_require = setuptools.dist:check_extras
install = setuptools.command.install:install eager_resources = setuptools.dist:assert_string_list
alias = setuptools.command.alias:alias tests_require = setuptools.dist:check_requirements
bdist_egg = setuptools.command.bdist_egg:bdist_egg package_data = setuptools.dist:check_package_data
build_py = setuptools.command.build_py:build_py test_suite = setuptools.dist:check_test_suite
install_lib = setuptools.command.install_lib:install_lib include_package_data = setuptools.dist:assert_bool
rotate = setuptools.command.rotate:rotate install_requires = setuptools.dist:check_requirements
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
egg_info = setuptools.command.egg_info:egg_info [distutils.commands]
develop = setuptools.command.develop:develop upload_docs = setuptools.command.upload_docs:upload_docs
install_egg_info = setuptools.command.install_egg_info:install_egg_info egg_info = setuptools.command.egg_info:egg_info
build_ext = setuptools.command.build_ext:build_ext install_scripts = setuptools.command.install_scripts:install_scripts
sdist = setuptools.command.sdist:sdist saveopts = setuptools.command.saveopts:saveopts
saveopts = setuptools.command.saveopts:saveopts bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
upload_docs = setuptools.command.upload_docs:upload_docs rotate = setuptools.command.rotate:rotate
install = setuptools.command.install:install
[egg_info.writers] bdist_egg = setuptools.command.bdist_egg:bdist_egg
namespace_packages.txt = setuptools.command.egg_info:overwrite_arg test = setuptools.command.test:test
eager_resources.txt = setuptools.command.egg_info:overwrite_arg install_egg_info = setuptools.command.install_egg_info:install_egg_info
entry_points.txt = setuptools.command.egg_info:write_entries install_lib = setuptools.command.install_lib:install_lib
PKG-INFO = setuptools.command.egg_info:write_pkg_info sdist = setuptools.command.sdist:sdist
depends.txt = setuptools.command.egg_info:warn_depends_obsolete register = setuptools.command.register:register
dependency_links.txt = setuptools.command.egg_info:overwrite_arg develop = setuptools.command.develop:develop
top_level.txt = setuptools.command.egg_info:write_toplevel_names build_py = setuptools.command.build_py:build_py
requires.txt = setuptools.command.egg_info:write_requirements setopt = setuptools.command.setopt:setopt
build_ext = setuptools.command.build_ext:build_ext
[console_scripts] alias = setuptools.command.alias:alias
easy_install = setuptools.command.easy_install:main easy_install = setuptools.command.easy_install:easy_install
easy_install-3.4 = setuptools.command.easy_install:main bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
[ssl:sys_platform=='win32']
wincertstore==0.2
[certs] [certs]
certifi==1.0.1 certifi==1.0.1
\ No newline at end of file
[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