pypa / setuptools

Official project repository for the Setuptools build system
https://pypi.org/project/setuptools/
MIT License
2.34k stars 1.14k forks source link

Emergent build failure: MinimalDistribution has no attribute entry_points #4333

Closed jaraco closed 2 weeks ago

jaraco commented 2 weeks ago

As recently as four days ago, tests were passing. A day later, one test (test_license_is_a_string), started failing. Today, the package fails to build/install at all. All of these jobs are on the same commit (0156e248e).

jaraco commented 2 weeks ago

On my local machine, I'm able to build from scratch, but a few of the tests fail with the same MinimalDistribution has no attribute entry_points error. I suspect a release of tox or virtualenv may be implicated.

jaraco commented 2 weeks ago

If I run the tests on a local Linux docker image, I see the same failures I observe on my local mac, but not the build errors I see in CI. So I'm going to focus on fixing those errors and then worry about CI subsequently if it's continuing to fail.

jaraco commented 2 weeks ago

The first failure I encounter occurs during test setup when an sdist is produced.

``` setuptools main @ tox -- -p no:cov -p no:xdist -p no:perf -p no:checkdocs -x .pkg: _optional_hooks> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta .pkg: get_requires_for_build_editable> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta .pkg: build_editable> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta py: install_package> python -I -m pip install --force-reinstall --no-deps /Users/jaraco/code/pypa/setuptools/.tox/.tmp/package/3/setuptools-69.5.1.post20240429-0.editable-py3-none-any.whl py: commands[0]> pytest -p no:cov -p no:xdist -p no:perf -p no:checkdocs -x ============================================================== test session starts =============================================================== platform darwin -- Python 3.12.3, pytest-8.2.0, pluggy-1.5.0 cachedir: .tox/py/.pytest_cache rootdir: /Users/jaraco/code/pypa/setuptools configfile: pytest.ini plugins: ruff-0.3.1, typeguard-4.2.1, mypy-0.10.3, home-0.5.1, enabler-3.1.1, timeout-2.3.1, xdist-3.6.1 collected 1631 items conftest.py .... [ 0%] docs/conf.py ... [ 0%] exercises.py ... [ 0%] pkg_resources/__init__.py ...... [ 0%] pkg_resources/api_tests.txt . [ 1%] pkg_resources/tests/__init__.py ... [ 1%] pkg_resources/tests/test_find_distributions.py ....... [ 1%] pkg_resources/tests/test_markers.py .... [ 1%] pkg_resources/tests/test_pkg_resources.py ....................ssss [ 3%] pkg_resources/tests/test_resources.py ..................................................................................... [ 8%] pkg_resources/tests/test_working_set.py ....................................... [ 10%] setup.py ... [ 11%] setuptools/__init__.py ... [ 11%] setuptools/_core_metadata.py ... [ 11%] setuptools/_entry_points.py .... [ 11%] setuptools/_imp.py ... [ 11%] setuptools/_importlib.py ... [ 12%] setuptools/_itertools.py .... [ 12%] setuptools/_normalization.py .......... [ 12%] setuptools/_path.py .... [ 13%] setuptools/_reqs.py ... [ 13%] setuptools/archive_util.py ... [ 13%] setuptools/build_meta.py ........ [ 14%] setuptools/command/__init__.py ... [ 14%] setuptools/command/_requirestxt.py ... [ 14%] setuptools/command/alias.py ... [ 14%] setuptools/command/bdist_egg.py ... [ 14%] setuptools/command/bdist_rpm.py ... [ 15%] setuptools/command/build.py ... [ 15%] setuptools/command/build_clib.py ... [ 15%] setuptools/command/build_ext.py ... [ 15%] setuptools/command/build_py.py ... [ 15%] setuptools/command/develop.py .... [ 16%] setuptools/command/dist_info.py ... [ 16%] setuptools/command/easy_install.py ... [ 16%] setuptools/command/editable_wheel.py ...... [ 16%] setuptools/command/egg_info.py ... [ 16%] setuptools/command/install.py ... [ 17%] setuptools/command/install_egg_info.py ... [ 17%] setuptools/command/install_lib.py .... [ 17%] setuptools/command/install_scripts.py ... [ 17%] setuptools/command/register.py ... [ 17%] setuptools/command/rotate.py ... [ 18%] setuptools/command/saveopts.py ... [ 18%] setuptools/command/sdist.py ... [ 18%] setuptools/command/setopt.py ... [ 18%] setuptools/command/test.py ... [ 18%] setuptools/command/upload.py ... [ 19%] setuptools/command/upload_docs.py ... [ 19%] setuptools/compat/__init__.py ... [ 19%] setuptools/compat/py310.py ... [ 19%] setuptools/compat/py311.py ... [ 19%] setuptools/compat/py39.py ... [ 19%] setuptools/config/__init__.py ... [ 20%] setuptools/config/_apply_pyprojecttoml.py ..... [ 20%] setuptools/config/expand.py .... [ 20%] setuptools/config/pyprojecttoml.py ... [ 20%] setuptools/config/setupcfg.py ... [ 21%] setuptools/dep_util.py ... [ 21%] setuptools/depends.py ... [ 21%] setuptools/discovery.py ...... [ 21%] setuptools/dist.py .... [ 22%] setuptools/errors.py ... [ 22%] setuptools/extension.py ... [ 22%] setuptools/glob.py ... [ 22%] setuptools/installer.py ... [ 22%] setuptools/launch.py ... [ 22%] setuptools/logging.py ... [ 23%] setuptools/monkey.py ... [ 23%] setuptools/msvc.py ... [ 23%] setuptools/namespaces.py .... [ 23%] setuptools/package_index.py ..... [ 24%] setuptools/sandbox.py .... [ 24%] setuptools/tests/__init__.py ... [ 24%] setuptools/tests/config/__init__.py ... [ 24%] setuptools/tests/config/downloads/__init__.py ... [ 24%] setuptools/tests/config/downloads/preload.py ... [ 25%] setuptools/tests/config/test_apply_pyprojecttoml.py .............................x...............E ===================================================================== ERRORS ===================================================================== _____________________________________________ ERROR at setup of TestMeta.test_example_file_in_sdist ______________________________________________ tmp_path_factory = TempPathFactory(_given_basetemp=None, _trace=, _basetemp=PosixPath.../folders/f2/2plv6q2n7l932m2x004jlw340000gn/T/pytest-of-jaraco/pytest-24'), _retention_count=3, _retention_policy='all') request = > @pytest.fixture(scope="session") def setuptools_sdist(tmp_path_factory, request): prebuilt = os.getenv("PRE_BUILT_SETUPTOOLS_SDIST") if prebuilt and os.path.exists(prebuilt): # pragma: no cover return Path(prebuilt).resolve() > sdist, _ = _build_distributions(tmp_path_factory, request) setuptools/tests/fixtures.py:104: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tmp_path_factory = TempPathFactory(_given_basetemp=None, _trace=, _basetemp=PosixPath.../folders/f2/2plv6q2n7l932m2x004jlw340000gn/T/pytest-of-jaraco/pytest-24'), _retention_count=3, _retention_policy='all') request = > def _build_distributions(tmp_path_factory, request): with contexts.session_locked_tmp_dir( request, tmp_path_factory, "dist_build" ) as tmp: # pragma: no cover sdist = next(tmp.glob("*.tar.gz"), None) wheel = next(tmp.glob("*.whl"), None) if sdist and wheel: return (sdist, wheel) # Sanity check: should not create recursive setuptools/build/lib/build/lib/... > assert not Path(request.config.rootdir, "build/lib/build").exists() E AssertionError: assert not True E + where True = () E + where = PosixPath('/Users/jaraco/code/pypa/setuptools/build/lib/build').exists E + where PosixPath('/Users/jaraco/code/pypa/setuptools/build/lib/build') = Path(local('/Users/jaraco/code/pypa/setuptools'), 'build/lib/build') E + where local('/Users/jaraco/code/pypa/setuptools') = <_pytest.config.Config object at 0x104a81be0>.rootdir E + where <_pytest.config.Config object at 0x104a81be0> = >.config setuptools/tests/fixtures.py:81: AssertionError =================================================================== XFAILURES ==================================================================== ... ====================================================================== mypy ====================================================================== Success: no issues found in 143 source files ============================================================ short test summary info ============================================================= SKIPPED [1] pkg_resources/tests/test_pkg_resources.py:400: Testing case-insensitive filesystems. SKIPPED [3] pkg_resources/tests/test_pkg_resources.py:416: Testing systems using backslashes as path separators. XFAIL setuptools/tests/config/test_apply_pyprojecttoml.py::test_utf8_maintainer_in_metadata[international-email] - CPython's `email.headerregistry.Address` only supports RFC 5322, as of Nov 10, 2022 and latest Python 3.11.0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! =============================================== 448 passed, 4 skipped, 1 xfailed, 1 error in 3.71s =============================================== py: exit 1 (4.35 seconds) /Users/jaraco/code/pypa/setuptools> pytest -p no:cov -p no:xdist -p no:perf -p no:checkdocs -x pid=58962 py: FAIL code 1 (5.58=setup[1.23]+cmd[4.35] seconds) evaluation failed :( (5.65 seconds) ```
jaraco commented 2 weeks ago

If I clean the directory then home in on just that test, I see the error emitted in CI:

``` setuptools main @ tox -- -p no:cov -p no:xdist -p no:perf -p no:checkdocs -k test_example_file_in_sdist .pkg: _optional_hooks> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta .pkg: get_requires_for_build_editable> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta .pkg: install_requires_for_build_editable> python -I -m pip install wheel .pkg: build_editable> python '/Users/jaraco/Library/Application Support/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py' True setuptools.build_meta py: install_package_deps> python -I -m pip install 'build[virtualenv]>=1.0.3' 'filelock>=3.4.0' importlib-metadata 'ini2toml[lite]>=0.14' 'jaraco.develop>=7.21; python_version >= "3.9" and sys_platform != "cygwin"' 'jaraco.envs>=2.2' 'jaraco.path>=3.2.0' mypy==1.9 'packaging>=23.2' 'pip>=19.1' 'pytest!=8.1.1,>=6' 'pytest-checkdocs>=2.4' 'pytest-cov; platform_python_implementation != "PyPy"' 'pytest-enabler>=2.2' 'pytest-home>=0.5' pytest-mypy 'pytest-perf; sys_platform != "cygwin"' 'pytest-ruff>=0.2.1; sys_platform != "cygwin"' pytest-timeout 'pytest-xdist>=3' tomli 'tomli-w>=1.0.0' 'virtualenv>=13.0.0' wheel py: install_package> python -I -m pip install --force-reinstall --no-deps /Users/jaraco/code/pypa/setuptools/.tox/.tmp/package/1/setuptools-69.5.1.post20240429-0.editable-py3-none-any.whl py: commands[0]> pytest -p no:cov -p no:xdist -p no:perf -p no:checkdocs -k test_example_file_in_sdist ============================================================== test session starts =============================================================== platform darwin -- Python 3.12.3, pytest-8.2.0, pluggy-1.5.0 cachedir: .tox/py/.pytest_cache rootdir: /Users/jaraco/code/pypa/setuptools configfile: pytest.ini plugins: ruff-0.3.1, typeguard-4.2.1, mypy-0.10.3, home-0.5.1, enabler-3.1.1, timeout-2.3.1, xdist-3.6.1 collected 1631 items / 1630 deselected / 1 selected setuptools/tests/config/test_apply_pyprojecttoml.py E [100%] ===================================================================== ERRORS ===================================================================== _____________________________________________ ERROR at setup of TestMeta.test_example_file_in_sdist ______________________________________________ tmp_path_factory = TempPathFactory(_given_basetemp=None, _trace=, _basetemp=PosixPath.../folders/f2/2plv6q2n7l932m2x004jlw340000gn/T/pytest-of-jaraco/pytest-26'), _retention_count=3, _retention_policy='all') request = > @pytest.fixture(scope="session") def setuptools_sdist(tmp_path_factory, request): prebuilt = os.getenv("PRE_BUILT_SETUPTOOLS_SDIST") if prebuilt and os.path.exists(prebuilt): # pragma: no cover return Path(prebuilt).resolve() > sdist, _ = _build_distributions(tmp_path_factory, request) setuptools/tests/fixtures.py:104: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ setuptools/tests/fixtures.py:83: in _build_distributions subprocess.check_output([ /opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/subprocess.py:466: in check_output return run(*popenargs, stdout=PIPE, timeout=timeout, check=True, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ input = None, capture_output = False, timeout = None, check = True popenargs = (['/Users/jaraco/code/pypa/setuptools/.tox/py/bin/python', '-m', 'build', '--outdir', '/private/var/folders/f2/2plv6q2n7l932m2x004jlw340000gn/T/pytest-of-jaraco/pytest-26/dist_build', '/Users/jaraco/code/pypa/setuptools'],) kwargs = {'stdout': -1}, process = stdout = b'* Creating isolated environment: venv+pip...\n* Getting build dependencies for sdist...\n\nERROR Backend subprocess exited when trying to invoke get_requires_for_build_sdist\n' stderr = None, retcode = 1 def run(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs): """Run command with arguments and return a CompletedProcess instance. The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them, or pass capture_output=True to capture both. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute, and output & stderr attributes if those streams were captured. If timeout is given, and the process takes too long, a TimeoutExpired exception will be raised. There is an optional argument "input", allowing you to pass bytes or a string to the subprocess's stdin. If you use this argument you may not also use the Popen constructor's "stdin" argument, as it will be used internally. By default, all communication is in bytes, and therefore any "input" should be bytes, and the stdout and stderr will be bytes. If in text mode, any "input" should be a string, and stdout and stderr will be strings decoded according to locale encoding, or by "encoding" if set. Text mode is triggered by setting any of text, encoding, errors or universal_newlines. The other arguments are the same as for the Popen constructor. """ if input is not None: if kwargs.get('stdin') is not None: raise ValueError('stdin and input arguments may not both be used.') kwargs['stdin'] = PIPE if capture_output: if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None: raise ValueError('stdout and stderr arguments may not be used ' 'with capture_output.') kwargs['stdout'] = PIPE kwargs['stderr'] = PIPE with Popen(*popenargs, **kwargs) as process: try: stdout, stderr = process.communicate(input, timeout=timeout) except TimeoutExpired as exc: process.kill() if _mswindows: # Windows accumulates the output in a single blocking # read() call run on child threads, with the timeout # being done in a join() on those threads. communicate() # _after_ kill() is required to collect that and add it # to the exception. exc.stdout, exc.stderr = process.communicate() else: # POSIX _communicate already populated the output so # far into the TimeoutExpired exception. process.wait() raise except: # Including KeyboardInterrupt, communicate handled that. process.kill() # We don't call process.wait() as .__exit__ does that for us. raise retcode = process.poll() if check and retcode: > raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) E subprocess.CalledProcessError: Command '['/Users/jaraco/code/pypa/setuptools/.tox/py/bin/python', '-m', 'build', '--outdir', '/private/var/folders/f2/2plv6q2n7l932m2x004jlw340000gn/T/pytest-of-jaraco/pytest-26/dist_build', '/Users/jaraco/code/pypa/setuptools']' returned non-zero exit status 1. /opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/subprocess.py:571: CalledProcessError ------------------------------------------------------------- Captured stderr setup -------------------------------------------------------------- Traceback (most recent call last): File "/Users/jaraco/code/pypa/setuptools/setuptools/config/setupcfg.py", line 285, in __setitem__ current_value = getattr(target_obj, option_name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'MinimalDistribution' object has no attribute 'entry_points' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/Users/jaraco/code/pypa/setuptools/.tox/py/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 373, in main() File "/Users/jaraco/code/pypa/setuptools/.tox/py/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 357, in main json_out["return_val"] = hook(**hook_input["kwargs"]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/jaraco/code/pypa/setuptools/.tox/py/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 308, in get_requires_for_build_sdist return hook(config_settings) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/jaraco/code/pypa/setuptools/setuptools/build_meta.py", line 328, in get_requires_for_build_sdist return self._get_build_requires(config_settings, requirements=[]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/jaraco/code/pypa/setuptools/setuptools/build_meta.py", line 295, in _get_build_requires self.run_setup() File "/Users/jaraco/code/pypa/setuptools/setuptools/build_meta.py", line 311, in run_setup exec(code, locals()) File "", line 93, in File "/Users/jaraco/code/pypa/setuptools/setuptools/__init__.py", line 103, in setup _install_setup_requires(attrs) File "/Users/jaraco/code/pypa/setuptools/setuptools/__init__.py", line 74, in _install_setup_requires dist.parse_config_files(ignore_option_errors=True) File "/Users/jaraco/code/pypa/setuptools/setuptools/dist.py", line 627, in parse_config_files setupcfg.parse_configuration( File "/Users/jaraco/code/pypa/setuptools/setuptools/config/setupcfg.py", line 178, in parse_configuration options.parse() File "/Users/jaraco/code/pypa/setuptools/setuptools/config/setupcfg.py", line 501, in parse section_parser_method(section_options) File "/Users/jaraco/code/pypa/setuptools/setuptools/config/setupcfg.py", line 714, in parse_section_entry_points self['entry_points'] = parsed ~~~~^^^^^^^^^^^^^^^^ File "/Users/jaraco/code/pypa/setuptools/setuptools/config/setupcfg.py", line 287, in __setitem__ raise KeyError(option_name) from e KeyError: 'entry_points' ======================================================= 1630 deselected, 1 error in 0.76s ======================================================== py: exit 1 (1.38 seconds) /Users/jaraco/code/pypa/setuptools> pytest -p no:cov -p no:xdist -p no:perf -p no:checkdocs -k test_example_file_in_sdist pid=59297 py: FAIL code 1 (20.40=setup[19.03]+cmd[1.38] seconds) evaluation failed :( (20.44 seconds) ```
jaraco commented 2 weeks ago

I see pyproject-hooks was released 12 hours ago, so may be pertinent.

jaraco commented 2 weeks ago

Downgrading to pyproject-hooks!=1.1 works around the failure.

jaraco commented 2 weeks ago

Well, that change fixed things for me locally, but doesn't fix the issue in CI. I wonder what's different about the CI build.

jaraco commented 2 weeks ago

Aah. Setuptools uses a pre-built wheel and sdist and that invocation of pipx doesn't honor the pin. That also explains why CI was seeing the issue earlier, because that invocation of build encounters the issue prior to setting up the test environment.

jaraco commented 2 weeks ago

The remaining failure is one that was exhibited a few days ago. I'll file a separate issue about that.

jaraco commented 2 weeks ago

This issue is still affecting docs builds.

jaraco commented 2 weeks ago

I was unable to replicate the docs build failures with tox -e docs, so I'm attempting a fix by pushing to main.

jaraco commented 2 weeks ago

The build completed, so that workaround was adequate.