Skip to content

Commit a918470

Browse files
authored
Merge pull request #1379 from chrysle/update-namespace-packaging-guide
Improve namespace packaging guide
2 parents a9e56ee + 1217bf7 commit a918470

File tree

2 files changed

+105
-56
lines changed

2 files changed

+105
-56
lines changed

source/discussions/src-layout-vs-flat-layout.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _src-layout-vs-flat-layout:
2+
13
=========================
24
src layout vs flat layout
35
=========================

source/guides/packaging-namespace-packages.rst

Lines changed: 103 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ have the following package structure:
1919
__init__.py
2020
...
2121
module_b.py
22-
setup.py
22+
pyproject.toml
2323
2424
And you use this package in your code like so::
2525

@@ -31,17 +31,19 @@ Then you can break these sub-packages into two separate distributions:
3131
.. code-block:: text
3232
3333
mynamespace-subpackage-a/
34-
setup.py
35-
mynamespace/
36-
subpackage_a/
37-
__init__.py
34+
pyproject.toml
35+
src/
36+
mynamespace/
37+
subpackage_a/
38+
__init__.py
3839
3940
mynamespace-subpackage-b/
40-
setup.py
41-
mynamespace/
42-
subpackage_b/
43-
__init__.py
44-
module_b.py
41+
pyproject.toml
42+
src/
43+
mynamespace/
44+
subpackage_b/
45+
__init__.py
46+
module_b.py
4547
4648
Each sub-package can now be separately installed, used, and versioned.
4749

@@ -57,52 +59,72 @@ import object short).
5759
Creating a namespace package
5860
============================
5961

60-
There are currently three different approaches to creating namespace packages:
62+
There are currently two different approaches to creating namespace packages,
63+
from which the latter is discouraged:
6164

6265
#. Use `native namespace packages`_. This type of namespace package is defined
6366
in :pep:`420` and is available in Python 3.3 and later. This is recommended if
6467
packages in your namespace only ever need to support Python 3 and
6568
installation via ``pip``.
66-
#. Use `pkgutil-style namespace packages`_. This is recommended for new
67-
packages that need to support Python 2 and 3 and installation via both
68-
``pip`` and ``python setup.py install``.
69-
#. Use `pkg_resources-style namespace packages`_. This method is recommended if
70-
you need compatibility with packages already using this method or if your
71-
package needs to be zip-safe.
72-
73-
.. warning:: While native namespace packages and pkgutil-style namespace
74-
packages are largely compatible, pkg_resources-style namespace packages
75-
are not compatible with the other methods. It's inadvisable to use
76-
different methods in different distributions that provide packages to the
77-
same namespace.
69+
#. Use `legacy namespace packages`_. This comprises `pkgutil-style namespace packages`_
70+
and `pkg_resources-style namespace packages`_.
7871

7972
Native namespace packages
8073
-------------------------
8174

8275
Python 3.3 added **implicit** namespace packages from :pep:`420`. All that is
8376
required to create a native namespace package is that you just omit
8477
:file:`__init__.py` from the namespace package directory. An example file
85-
structure:
78+
structure (following :ref:`src-layout <setuptools:src-layout>`):
8679

8780
.. code-block:: text
8881
89-
setup.py
90-
mynamespace/
91-
# No __init__.py here.
92-
subpackage_a/
93-
# Sub-packages have __init__.py.
94-
__init__.py
95-
module.py
82+
mynamespace-subpackage-a/
83+
pyproject.toml # AND/OR setup.py, setup.cfg
84+
src/
85+
mynamespace/ # namespace package
86+
# No __init__.py here.
87+
subpackage_a/
88+
# Regular import packages have an __init__.py.
89+
__init__.py
90+
module.py
9691
9792
It is extremely important that every distribution that uses the namespace
9893
package omits the :file:`__init__.py` or uses a pkgutil-style
9994
:file:`__init__.py`. If any distribution does not, it will cause the namespace
10095
logic to fail and the other sub-packages will not be importable.
10196

102-
Because ``mynamespace`` doesn't contain an :file:`__init__.py`,
103-
:func:`setuptools.find_packages` won't find the sub-package. You must
104-
use :func:`setuptools.find_namespace_packages` instead or explicitly
105-
list all packages in your :file:`setup.py`. For example:
97+
The ``src-layout`` directory structure allows automatic discovery of packages
98+
by most :term:`build backends <Build Backend>`. See :ref:`src-layout-vs-flat-layout`
99+
for more information. If however you want to manage exclusions or inclusions of packages
100+
yourself, this is possible to be configured in the top-level :file:`pyproject.toml`:
101+
102+
.. code-block:: toml
103+
104+
[build-system]
105+
...
106+
107+
[tool.setuptools.packages.find]
108+
where = ["src/"]
109+
include = ["mynamespace.subpackage_a"]
110+
111+
[project]
112+
name = "mynamespace-subpackage-a"
113+
...
114+
115+
The same can be accomplished with a :file:`setup.cfg`:
116+
117+
.. code-block:: ini
118+
119+
[options]
120+
package_dir =
121+
=src
122+
packages = find_namespace:
123+
124+
[options.packages.find]
125+
where = src
126+
127+
Or :file:`setup.py`:
106128

107129
.. code-block:: python
108130
@@ -111,9 +133,13 @@ list all packages in your :file:`setup.py`. For example:
111133
setup(
112134
name='mynamespace-subpackage-a',
113135
...
114-
packages=find_namespace_packages(include=['mynamespace.*'])
136+
packages=find_namespace_packages(where='src/', include=['mynamespace.subpackage_a']),
137+
package_dir={'': 'src'},
115138
)
116139
140+
:ref:`setuptools` will search the directory structure for implicit namespace
141+
packages by default.
142+
117143
A complete working example of two native namespace packages can be found in
118144
the `native namespace package example project`_.
119145

@@ -125,8 +151,25 @@ the `native namespace package example project`_.
125151
only support Python 3 and pkgutil-style namespace packages in the
126152
distributions that need to support Python 2 and 3.
127153

154+
155+
Legacy namespace packages
156+
-------------------------
157+
158+
These two methods, that were used to create namespace packages prior to :pep:`420`,
159+
are now considered to be obsolete and should not be used unless you need compatibility
160+
with packages already using this method. Also, :doc:`pkg_resources <setuptools:pkg_resources>`
161+
has been deprecated.
162+
163+
To migrate an existing package, all packages sharing the namespace must be migrated simultaneously.
164+
165+
.. warning:: While native namespace packages and pkgutil-style namespace
166+
packages are largely compatible, pkg_resources-style namespace packages
167+
are not compatible with the other methods. It's inadvisable to use
168+
different methods in different distributions that provide packages to the
169+
same namespace.
170+
128171
pkgutil-style namespace packages
129-
--------------------------------
172+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
130173

131174
Python 2.3 introduced the :doc:`pkgutil <python:library/pkgutil>` module and the
132175
:py:func:`python:pkgutil.extend_path` function. This can be used to declare namespace
@@ -138,22 +181,24 @@ To create a pkgutil-style namespace package, you need to provide an
138181

139182
.. code-block:: text
140183
141-
setup.py
142-
mynamespace/
143-
__init__.py # Namespace package __init__.py
144-
subpackage_a/
145-
__init__.py # Sub-package __init__.py
146-
module.py
184+
mynamespace-subpackage-a/
185+
src/
186+
pyproject.toml # AND/OR setup.cfg, setup.py
187+
mynamespace/
188+
__init__.py # Namespace package __init__.py
189+
subpackage_a/
190+
__init__.py # Regular package __init__.py
191+
module.py
147192
148193
The :file:`__init__.py` file for the namespace package needs to contain
149-
**only** the following:
194+
the following:
150195

151196
.. code-block:: python
152197
153198
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
154199
155-
**Every** distribution that uses the namespace package must include an
156-
identical :file:`__init__.py`. If any distribution does not, it will cause the
200+
**Every** distribution that uses the namespace package must include such
201+
an :file:`__init__.py`. If any distribution does not, it will cause the
157202
namespace logic to fail and the other sub-packages will not be importable. Any
158203
additional code in :file:`__init__.py` will be inaccessible.
159204

@@ -167,7 +212,7 @@ in the `pkgutil namespace example project`_.
167212

168213

169214
pkg_resources-style namespace packages
170-
--------------------------------------
215+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
171216

172217
:doc:`Setuptools <setuptools:index>` provides the `pkg_resources.declare_namespace`_ function and
173218
the ``namespace_packages`` argument to :func:`~setuptools.setup`. Together
@@ -183,22 +228,24 @@ To create a pkg_resources-style namespace package, you need to provide an
183228

184229
.. code-block:: text
185230
186-
setup.py
187-
mynamespace/
188-
__init__.py # Namespace package __init__.py
189-
subpackage_a/
190-
__init__.py # Sub-package __init__.py
191-
module.py
231+
mynamespace-subpackage-a/
232+
src/
233+
pyproject.toml # AND/OR setup.cfg, setup.py
234+
mynamespace/
235+
__init__.py # Namespace package __init__.py
236+
subpackage_a/
237+
__init__.py # Regular package __init__.py
238+
module.py
192239
193240
The :file:`__init__.py` file for the namespace package needs to contain
194-
**only** the following:
241+
the following:
195242

196243
.. code-block:: python
197244
198245
__import__('pkg_resources').declare_namespace(__name__)
199246
200-
**Every** distribution that uses the namespace package must include an
201-
identical :file:`__init__.py`. If any distribution does not, it will cause the
247+
**Every** distribution that uses the namespace package must include such an
248+
:file:`__init__.py`. If any distribution does not, it will cause the
202249
namespace logic to fail and the other sub-packages will not be importable. Any
203250
additional code in :file:`__init__.py` will be inaccessible.
204251

0 commit comments

Comments
 (0)