Skip to content

Commit d54fdbe

Browse files
authored
Merge branch 'main' into boolean-has_metadata-&-metadata_isdir
2 parents 56bd481 + b39639a commit d54fdbe

34 files changed

+253
-112
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# syntax: glob
2+
# See https://blog.jaraco.com/skeleton/#ignoring-artifacts before modifying.
23
bin
34
build
45
dist
@@ -17,6 +18,5 @@ setuptools.egg-info
1718
*~
1819
.hg*
1920
.cache
20-
.idea/
2121
.pytest_cache/
2222
.mypy_cache/

docs/conf.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,23 @@
161161
# Ref: https://stackoverflow.com/a/30624034/595220
162162
nitpick_ignore = [
163163
('c:func', 'SHGetSpecialFolderPath'), # ref to MS docs
164+
('envvar', 'DIST_EXTRA_CONFIG'), # undocumented
164165
('envvar', 'DISTUTILS_DEBUG'), # undocumented
165166
('envvar', 'HOME'), # undocumented
166167
('envvar', 'PLAT'), # undocumented
167-
('envvar', 'DIST_EXTRA_CONFIG'), # undocumented
168168
('py:attr', 'CCompiler.language_map'), # undocumented
169169
('py:attr', 'CCompiler.language_order'), # undocumented
170-
('py:class', 'distutils.dist.Distribution'), # undocumented
171-
('py:class', 'distutils.extension.Extension'), # undocumented
172170
('py:class', 'BorlandCCompiler'), # undocumented
173171
('py:class', 'CCompiler'), # undocumented
174172
('py:class', 'CygwinCCompiler'), # undocumented
173+
('py:class', 'distutils.dist.Distribution'), # undocumented
175174
('py:class', 'distutils.dist.DistributionMetadata'), # undocumented
175+
('py:class', 'distutils.extension.Extension'), # undocumented
176176
('py:class', 'FileList'), # undocumented
177177
('py:class', 'IShellLink'), # ref to MS docs
178178
('py:class', 'MSVCCompiler'), # undocumented
179179
('py:class', 'OptionDummy'), # undocumented
180+
('py:class', 'setuptools.dist.Distribution'), # undocumented
180181
('py:class', 'UnixCCompiler'), # undocumented
181182
('py:exc', 'CompileError'), # undocumented
182183
('py:exc', 'DistutilsExecError'), # undocumented
@@ -186,8 +187,7 @@
186187
('py:exc', 'PreprocessError'), # undocumented
187188
('py:exc', 'setuptools.errors.PlatformError'), # sphinx cannot find it
188189
('py:func', 'distutils.CCompiler.new_compiler'), # undocumented
189-
# undocumented:
190-
('py:func', 'distutils.dist.DistributionMetadata.read_pkg_file'),
190+
('py:func', 'distutils.dist.DistributionMetadata.read_pkg_file'), # undocumented
191191
('py:func', 'distutils.file_util._copy_file_contents'), # undocumented
192192
('py:func', 'distutils.log.debug'), # undocumented
193193
('py:func', 'distutils.spawn.find_executable'), # undocumented

docs/userguide/datafiles.rst

+62-38
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@ by including the data files **inside the package directory**.
1010

1111
Setuptools focuses on this most common type of data files and offers three ways
1212
of specifying which files should be included in your packages, as described in
13-
the following sections.
13+
the following section.
14+
15+
16+
Configuration Options
17+
=====================
18+
19+
20+
.. _include-package-data:
1421

1522
include_package_data
16-
====================
23+
--------------------
1724

18-
First, you can simply use the ``include_package_data`` keyword.
25+
First, you can use the ``include_package_data`` keyword.
1926
For example, if the package tree looks like this::
2027

2128
project_root_directory
@@ -92,8 +99,10 @@ your package, provided:
9299
(where ``include_package_data=False`` by default), which was not changed
93100
to ensure backwards compatibility with existing projects.
94101

102+
.. _package-data:
103+
95104
package_data
96-
============
105+
------------
97106

98107
By default, ``include_package_data`` considers **all** non ``.py`` files found inside
99108
the package directory (``src/mypkg`` in this case) as data files, and includes those that
@@ -260,8 +269,10 @@ we specify that ``data1.rst`` from ``mypkg1`` alone should be captured as well.
260269
Please check :ref:`section subdirectories <subdir-data-files>` below.
261270

262271

272+
.. _exclude-package-data:
273+
263274
exclude_package_data
264-
====================
275+
--------------------
265276

266277
Sometimes, the ``include_package_data`` or ``package_data`` options alone
267278
aren't sufficient to precisely define what files you want included. For example,
@@ -327,6 +338,38 @@ even if they were listed in ``package_data`` or were included as a result of usi
327338
``include_package_data``.
328339

329340

341+
Summary
342+
-------
343+
344+
In summary, the three options allow you to:
345+
346+
``include_package_data``
347+
Accept all data files and directories matched by
348+
:ref:`MANIFEST.in <Using MANIFEST.in>` or added by
349+
a :ref:`plugin <Adding Support for Revision Control Systems>`.
350+
351+
``package_data``
352+
Specify additional patterns to match files that may or may
353+
not be matched by :ref:`MANIFEST.in <Using MANIFEST.in>`
354+
or added by a :ref:`plugin <Adding Support for Revision Control Systems>`.
355+
356+
``exclude_package_data``
357+
Specify patterns for data files and directories that should *not* be
358+
included when a package is installed, even if they would otherwise have
359+
been included due to the use of the preceding options.
360+
361+
.. note::
362+
Due to the way the build process works, a data file that you
363+
include in your project and then stop including may be "orphaned" in your
364+
project's build directories, requiring you to manually deleting them.
365+
This may also be important for your users and contributors
366+
if they track intermediate revisions of your project using Subversion; be sure
367+
to let them know when you make changes that remove files from inclusion so they
368+
can also manually delete them.
369+
370+
See also troubleshooting information in :ref:`Caching and Troubleshooting`.
371+
372+
330373
.. _subdir-data-files:
331374

332375
Subdirectory for Data Files
@@ -350,8 +393,13 @@ Here, the ``.rst`` files are placed under a ``data`` subdirectory inside ``mypkg
350393
while the ``.txt`` files are directly under ``mypkg``.
351394

352395
In this case, the recommended approach is to treat ``data`` as a namespace package
353-
(refer :pep:`420`). With ``package_data``,
354-
the configuration might look like this:
396+
(refer :pep:`420`). This way, you can rely on the same methods described above,
397+
using either :ref:`package-data` or :ref:`include-package-data`.
398+
For the sake of completeness, we include below configuration examples
399+
for the subdirectory structure, but please refer to the detailed
400+
information in the previous sections of this document.
401+
402+
With :ref:`package-data`, the configuration might look like this:
355403

356404
.. tab:: pyproject.toml
357405

@@ -407,8 +455,9 @@ which enables the ``data`` directory to be identified, and then, we separately s
407455
files for the root package ``mypkg``, and the namespace package ``data`` under the package
408456
``mypkg``.
409457

410-
With ``include_package_data`` the configuration is simpler: you simply need to enable
411-
scanning of namespace packages in the ``src`` directory and the rest is handled by Setuptools.
458+
Alternatively, you can also rely on :ref:`include-package-data`.
459+
Note that this is the default behaviour in ``pyproject.toml``, but you need to
460+
manually enable scanning of namespace packages in ``setup.cfg`` or ``setup.py``:
412461

413462
.. tab:: pyproject.toml
414463

@@ -422,7 +471,7 @@ scanning of namespace packages in the ``src`` directory and the rest is handled
422471
423472
[tool.setuptools.packages.find]
424473
# scanning for namespace packages is true by default in pyproject.toml, so
425-
# you need NOT include the following line.
474+
# you need NOT include this configuration.
426475
namespaces = true
427476
where = ["src"]
428477
@@ -451,34 +500,9 @@ scanning of namespace packages in the ``src`` directory and the rest is handled
451500
include_package_data=True,
452501
)
453502
454-
Summary
455-
=======
456-
457-
In summary, the three options allow you to:
458-
459-
``include_package_data``
460-
Accept all data files and directories matched by
461-
:ref:`MANIFEST.in <Using MANIFEST.in>` or added by
462-
a :ref:`plugin <Adding Support for Revision Control Systems>`.
463-
464-
``package_data``
465-
Specify additional patterns to match files that may or may
466-
not be matched by :ref:`MANIFEST.in <Using MANIFEST.in>`
467-
or added by a :ref:`plugin <Adding Support for Revision Control Systems>`.
468-
469-
``exclude_package_data``
470-
Specify patterns for data files and directories that should *not* be
471-
included when a package is installed, even if they would otherwise have
472-
been included due to the use of the preceding options.
473-
474-
.. note::
475-
Due to the way the build process works, a data file that you
476-
include in your project and then stop including may be "orphaned" in your
477-
project's build directories, requiring you to manually deleting them.
478-
This may also be important for your users and contributors
479-
if they track intermediate revisions of your project using Subversion; be sure
480-
to let them know when you make changes that remove files from inclusion so they
481-
can also manually delete them.
503+
To avoid common mistakes with :ref:`include-package-data`,
504+
please ensure :ref:`MANIFEST.in <Using MANIFEST.in>` is properly set
505+
or use a revision control system plugin (see :doc:`/userguide/miscellaneous`).
482506

483507

484508
.. _Accessing Data Files at Runtime:

docs/userguide/dependency_management.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Build system requirement
1919

2020
After organizing all the scripts and files and getting ready for packaging,
2121
there needs to be a way to specify what programs and libraries are actually needed
22-
do the packaging (in our case, ``setuptools`` of course).
22+
to do the packaging (in our case, ``setuptools`` of course).
2323
This needs to be specified in your ``pyproject.toml`` file
2424
(if you have forgot what this is, go to :doc:`/userguide/quickstart` or :doc:`/build_meta`):
2525

docs/userguide/miscellaneous.rst

+18
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ binary extensions during the build process, or included in the final
168168

169169
See :doc:`/userguide/datafiles` for more information.
170170

171+
172+
.. _Caching and Troubleshooting:
173+
174+
Caching and Troubleshooting
175+
===========================
176+
177+
Setuptools automatically creates a few directories to host build artefacts and
178+
cache files, such as ``build``, ``dist``, ``*.egg-info``. While cache is
179+
useful to speed up incremental builds, in some edge cases it might become
180+
stale. If you feel that caching is causing problems to your build, specially
181+
after changes in configuration or in the directory/file structure., consider
182+
removing ``build``, ``dist``, ``*.egg-info`` [#PKG-INFO]_ before rebuilding or
183+
reinstalling your project.
184+
171185
----
172186

173187
.. [#build-process]
@@ -183,5 +197,9 @@ binary extensions during the build process, or included in the final
183197
:term:`Virtual Environment`.
184198
Therefore it only contains items that are required during runtime.
185199
200+
.. [#PKG-INFO]
201+
When working from an extracted sdist (e.g. for patching), you might also consider removing
202+
the ``PKG-INFO`` file to force its recreation.
203+
186204
.. _git: https://git-scm.com
187205
.. _mercurial: https://www.mercurial-scm.org

mypy.ini

+40-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11
[mypy]
2-
ignore_missing_imports = True
3-
# required to support namespace packages
4-
# https://github.com/python/mypy/issues/14057
2+
# CI should test for all versions, local development gets hints for oldest supported
3+
python_version = 3.8
4+
strict = False
5+
warn_unused_ignores = True
6+
# required to support namespace packages: https://github.com/python/mypy/issues/14057
57
explicit_package_bases = True
8+
exclude = (?x)(
9+
^build/
10+
| ^.tox/
11+
| ^pkg_resources/tests/data/my-test-package-source/setup.py$ # Duplicate module name
12+
| ^.+?/(_vendor|extern)/ # Vendored
13+
| ^setuptools/_distutils/ # Vendored
14+
| ^setuptools/config/_validate_pyproject/ # Auto-generated
15+
)
16+
disable_error_code =
17+
# TODO: Test environment is not yet properly configured to install all imported packages
18+
# import-not-found, # This can be left commented out for local runs until we enforce running mypy in the CI
19+
# TODO: Not all dependencies are typed. Namely: distutils._modified, wheel.wheelfile, and jaraco.*
20+
import-untyped,
21+
# Ignoring attr-defined because setuptools wraps a lot of distutils classes, adding new attributes,
22+
# w/o updating all the attributes and return types from the base classes for type-checkers to understand
23+
# Especially with setuptools.dist.command vs distutils.dist.command vs setuptools._distutils.dist.command
24+
# *.extern modules that actually live in *._vendor will also cause attr-defined issues on import
25+
attr-defined,
26+
27+
# Avoid raising issues when importing from "extern" modules, as those are added to path dynamically.
28+
# https://github.com/pypa/setuptools/pull/3979#discussion_r1367968993
29+
[mypy-pkg_resources.extern.*,setuptools.extern.*]
30+
ignore_missing_imports = True
31+
32+
[mypy-pkg_resources.tests.*,setuptools.tests.*]
33+
disable_error_code =
34+
# Tests include creating dynamic modules that won't exists statically before the test is run.
35+
# Let's ignore all "import-not-found", as if an import really wasn't found, then the test would fail.
36+
import-not-found,
37+
# mmany untyped "jaraco" modules
38+
import-untyped,
39+
40+
# Mypy issue, this vendored module is already excluded!
41+
[mypy-setuptools._vendor.packaging._manylinux]
42+
disable_error_code = import-not-found

newsfragments/4244.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Return an empty `list` by default in ``pkg_resources.ResourceManager.cleanup_resources`` -- by :user:`Avasam`

pkg_resources/__init__.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import time
2828
import re
2929
import types
30-
from typing import Protocol
30+
from typing import List, Protocol
3131
import zipfile
3232
import zipimport
3333
import warnings
@@ -1339,7 +1339,7 @@ def set_extraction_path(self, path):
13391339

13401340
self.extraction_path = path
13411341

1342-
def cleanup_resources(self, force=False):
1342+
def cleanup_resources(self, force=False) -> List[str]:
13431343
"""
13441344
Delete all extracted resource files and directories, returning a list
13451345
of the file and directory names that could not be successfully removed.
@@ -1351,6 +1351,7 @@ def cleanup_resources(self, force=False):
13511351
directory used for extractions.
13521352
"""
13531353
# XXX
1354+
return []
13541355

13551356

13561357
def get_default_cache():
@@ -3207,7 +3208,9 @@ def _find_adapter(registry, ob):
32073208
for t in types:
32083209
if t in registry:
32093210
return registry[t]
3210-
return None
3211+
# _find_adapter would previously return None, and immediatly be called.
3212+
# So we're raising a TypeError to keep backward compatibility if anyone depended on that behaviour.
3213+
raise TypeError(f"Could not find adapter for {registry} and {ob}")
32113214

32123215

32133216
def ensure_directory(path):

pkg_resources/tests/test_pkg_resources.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import stat
1010
import distutils.dist
1111
import distutils.command.install_egg_info
12+
from typing import List
1213

1314
from unittest import mock
1415

@@ -32,7 +33,7 @@ def __call__(self):
3233

3334

3435
class TestZipProvider:
35-
finalizers = []
36+
finalizers: List[EggRemover] = []
3637

3738
ref_time = datetime.datetime(2013, 5, 12, 13, 25, 0)
3839
"A reference time for a file modification"

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,6 @@ def _restore_install_lib(self):
8888

8989
if __name__ == '__main__':
9090
# allow setup.py to run from another directory
91-
here and os.chdir(here)
91+
# TODO: Use a proper conditonal statement here
92+
here and os.chdir(here) # type: ignore[func-returns-value]
9293
dist = setuptools.setup(**setup_params)

setuptools/__init__.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import functools
44
import os
55
import re
6+
from typing import TYPE_CHECKING
67

78
import _distutils_hack.override # noqa: F401
89
import distutils.core
@@ -105,8 +106,11 @@ def setup(**attrs):
105106

106107
setup.__doc__ = distutils.core.setup.__doc__
107108

108-
109-
_Command = monkey.get_unpatched(distutils.core.Command)
109+
if TYPE_CHECKING:
110+
# Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962
111+
_Command = distutils.core.Command
112+
else:
113+
_Command = monkey.get_unpatched(distutils.core.Command)
110114

111115

112116
class Command(_Command):
@@ -165,8 +169,9 @@ class Command(_Command):
165169
"""
166170

167171
command_consumes_arguments = False
172+
distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution
168173

169-
def __init__(self, dist, **kw):
174+
def __init__(self, dist: Distribution, **kw):
170175
"""
171176
Construct the command for dist, updating
172177
vars(self) with any keyword parameters.

0 commit comments

Comments
 (0)