[bumpversion]
-current_version = 65.0.0
+current_version = 65.0.1
commit = True
tag = True
+v65.0.1
+-------
+
+
+Documentation changes
+^^^^^^^^^^^^^^^^^^^^^
+* #3529: Added clarification to :doc:`/userguide/quickstart` about support
+ to ``setup.py``.
+
+Misc
+^^^^
+* #3526: Fix backward compatibility of editable installs and custom ``build_ext``
+ commands inheriting directly from ``distutils``.
+* #3528: Fixed ``buid_meta.prepare_metadata_for_build_wheel`` when
+ given ``metadata_directory`` is ``"."``.
+
+
v65.0.0
-------
subpackages, and APIs for managing Python's current "working set" of active
packages.
-Use of ``pkg_resources`` is discouraged in favor of
-`importlib.resources <https://docs.python.org/3/library/importlib.html#module-importlib.resources>`_,
-`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_,
-and their backports (:pypi:`importlib_resources`,
-:pypi:`importlib_metadata`).
-Please consider using those libraries instead of pkg_resources.
+.. attention::
+ Use of ``pkg_resources`` is discouraged in favor of
+ `importlib.resources <https://docs.python.org/3/library/importlib.html#module-importlib.resources>`_,
+ `importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_,
+ and their backports (:pypi:`importlib_resources`,
+ :pypi:`importlib_metadata`).
+ Please consider using those libraries instead of pkg_resources.
--------
In addition to specifying a build system, you also will need to add
some package information such as metadata, contents, dependencies, etc.
This can be done in the same ``pyproject.toml`` [#beta]_ file,
-or in a separated one: ``setup.cfg`` or ``setup.py`` (please note however
-that configuring new projects via ``setup.py`` is discouraged [#setup.py]_).
+or in a separated one: ``setup.cfg`` or ``setup.py`` [#setup.py]_.
The following example demonstrates a minimum configuration
(which assumes the project depends on :pypi:`requests` and
could have a diagram for that (explaining for example that "wheels" are
built from "sdists" not the source tree).
+.. _setuppy_discouraged:
+.. admonition:: Info: Using ``setup.py``
+ :class: seealso
+
+ Setuptools offers first class support for ``setup.py`` files as a configuration
+ mechanism.
+
+ It is important to remember, however, that running this file as a
+ script (e.g. ``python setup.py sdist``) is strongly **discouraged**, and
+ that the majority of the command line interfaces are (or will be) **deprecated**
+ (e.g. ``python setup.py install``, ``python setup.py bdist_wininst``, ...).
+
+ We also recommend users to expose as much as possible configuration in a
+ more *declarative* way via the :doc:`pyproject.toml <pyproject_config>` or
+ :doc:`setup.cfg <declarative_config>`, and keep the ``setup.py`` minimal
+ with only the dynamic parts (or even omit it completely if applicable).
+
+ See `Why you shouldn't invoke setup.py directly`_ for more background.
+
+.. _Why you shouldn't invoke setup.py directly: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html
+
Overview
========
.. rubric:: Notes
.. [#setup.py]
- The ``setup.py`` file should be used only when custom scripting during the
- build is necessary.
+ New projects are advised to avoid ``setup.py`` configurations (beyond the minimal stub)
+ when custom scripting during the build is not necessary.
Examples are kept in this document to help people interested in maintaining or
contributing to existing packages that use ``setup.py``.
Note that you can still keep most of configuration declarative in
:doc:`setup.cfg <declarative_config>` or :doc:`pyproject.toml
<pyproject_config>` and use ``setup.py`` only for the parts not
supported in those files (e.g. C extensions).
+ See :ref:`note <setuppy_discouraged>`.
.. [#beta]
Support for adding build configuration options via the ``[tool.setuptools]``
[metadata]
name = setuptools
-version = 65.0.0
+version = 65.0.1
author = Python Packaging Authority
author_email = distutils-sig@python.org
description = Easily download, build, install, upgrade, and uninstall Python packages
import setuptools
import distutils
+from . import errors
from ._path import same_path
from ._reqs import parse_strings
from ._deprecation_warning import SetuptoolsDeprecationWarning
Returns the basename of the info directory, e.g. `proj-0.0.0.dist-info`.
"""
- candidates = list(Path(metadata_directory).glob(f"**/*{suffix}/"))
- assert len(candidates) == 1, f"Exactly one {suffix} should have been produced"
- info_dir = candidates[0]
-
+ info_dir = self._find_info_directory(metadata_directory, suffix)
if not same_path(info_dir.parent, metadata_directory):
shutil.move(str(info_dir), metadata_directory)
# PEP 517 allow other files and dirs to exist in metadata_directory
-
return info_dir.name
+ def _find_info_directory(self, metadata_directory: str, suffix: str) -> Path:
+ for parent, dirs, _ in os.walk(metadata_directory):
+ candidates = [f for f in dirs if f.endswith(suffix)]
+
+ if len(candidates) != 0 or len(dirs) != 1:
+ assert len(candidates) == 1, f"Multiple {suffix} directories found"
+ return Path(parent, candidates[0])
+
+ msg = f"No {suffix} directory found in {metadata_directory}"
+ raise errors.InternalError(msg)
+
def prepare_metadata_for_build_wheel(self, metadata_directory,
config_settings=None):
sys.argv = [
cmd = dist.get_command_obj(cmd_name)
if hasattr(cmd, "editable_mode"):
cmd.editable_mode = True
+ elif hasattr(cmd, "inplace"):
+ cmd.inplace = True # backward compatibility with distutils
def _collect_build_outputs(self) -> Tuple[List[str], Dict[str, str]]:
files: List[str] = []
assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA'))
+ def test_prepare_metadata_inplace(self, build_backend):
+ """
+ Some users might pass metadata_directory pre-populated with `.tox` or `.venv`.
+ See issue #3523.
+ """
+ for pre_existing in [
+ ".tox/python/lib/python3.10/site-packages/attrs-22.1.0.dist-info",
+ ".tox/python/lib/python3.10/site-packages/autocommand-2.2.1.dist-info",
+ ".nox/python/lib/python3.10/site-packages/build-0.8.0.dist-info",
+ ".venv/python3.10/site-packages/click-8.1.3.dist-info",
+ "venv/python3.10/site-packages/distlib-0.3.5.dist-info",
+ "env/python3.10/site-packages/docutils-0.19.dist-info",
+ ]:
+ os.makedirs(pre_existing, exist_ok=True)
+ dist_info = build_backend.prepare_metadata_for_build_wheel(".")
+ assert os.path.isfile(os.path.join(dist_info, 'METADATA'))
+
def test_build_sdist_explicit_dist(self, build_backend):
# explicitly specifying the dist folder should work
# the folder sdist_directory and the ``--dist-dir`` can be the same
import platform
from copy import deepcopy
from importlib import import_module
+from importlib.machinery import EXTENSION_SUFFIXES
from pathlib import Path
from textwrap import dedent
from unittest.mock import Mock
editable_wheel,
)
from setuptools.dist import Distribution
+from setuptools.extension import Extension
@pytest.fixture(params=["strict", "lenient"])
cmd = editable_wheel(dist)
cmd.ensure_finalized()
cmd.run()
- wheel_file = str(next(Path().glob('dist/*')))
+ wheel_file = str(next(Path().glob('dist/*.whl')))
assert "editable" in wheel_file
- assert wheel_file.endswith(".whl")
+
+
+class TestCustomBuildExt:
+ def install_custom_build_ext_distutils(self, dist):
+ from distutils.command.build_ext import build_ext as build_ext_cls
+
+ class MyBuildExt(build_ext_cls):
+ pass
+
+ dist.cmdclass["build_ext"] = MyBuildExt
+
+ @pytest.mark.skipif(
+ sys.platform != "linux", reason="compilers may fail without correct setup"
+ )
+ def test_distutils_leave_inplace_files(self, tmpdir_cwd):
+ jaraco.path.build({"module.c": ""})
+ attrs = {
+ "ext_modules": [Extension("module", ["module.c"])],
+ }
+ dist = Distribution(attrs)
+ dist.script_name = "setup.py"
+ dist.set_defaults()
+ self.install_custom_build_ext_distutils(dist)
+ cmd = editable_wheel(dist)
+ cmd.ensure_finalized()
+ cmd.run()
+ wheel_file = str(next(Path().glob('dist/*.whl')))
+ assert "editable" in wheel_file
+ files = [p for p in Path().glob("module.*") if p.suffix != ".c"]
+ assert len(files) == 1
+ name = files[0].name
+ assert any(name.endswith(ext) for ext in EXTENSION_SUFFIXES)
def install_project(name, venv, tmp_path, files, *opts):