From: JinWang An Date: Mon, 27 Mar 2023 08:02:44 +0000 (+0900) Subject: Imported Upstream version 60.6.0 X-Git-Tag: upstream/60.6.0^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a134f2da5986c51c9f4212ac4da53ba2c741b26b;p=platform%2Fupstream%2Fpython-setuptools.git Imported Upstream version 60.6.0 --- diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6534cde..baf5b08 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 60.5.4 +current_version = 60.6.0 commit = True tag = True diff --git a/.codecov.yml b/.codecov.yml index 7510dfc..51b248b 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,4 +2,5 @@ comment: false coverage: status: project: - threshold: 0.5% + default: + threshold: 0.5% diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 73911ec..672acd1 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -115,15 +115,4 @@ body: validations: required: true - -- type: checkboxes - attributes: - label: Code of Conduct - description: | - Read the [PSF Code of Conduct][CoC] first. - - [CoC]: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md - options: - - label: I agree to follow the PSF Code of Conduct - required: true ... diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index dde102c..ebc2d33 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,3 @@ -# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser -blank_issues_enabled: false # default: true contact_links: - name: 🤔 Have questions or need support? url: https://github.com/pypa/setuptools/discussions @@ -9,7 +7,6 @@ contact_links: about: | Please ask typical Q&A here: general ideas for Python packaging, questions about structuring projects and so on -- name: >- - 💬 IRC: #pypa @ Freenode - url: https://webchat.freenode.net/#pypa +- name: 💬 Discord (chat) + url: https://discord.com/invite/pypa about: Chat with devs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ae4a26..821cf88 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,6 @@ jobs: ${{ matrix.python }} test_cygwin: - if: ${{ false }} # failing #3016 strategy: matrix: distutils: @@ -53,13 +52,24 @@ jobs: SETUPTOOLS_USE_DISTUTILS: ${{ matrix.distutils }} steps: - uses: actions/checkout@v2 - - name: Install Cygwin with Python and tox + - name: Install Cygwin with Python + uses: cygwin/cygwin-install-action@v1 + with: + platform: x86_64 + packages: >- + git, + gcc-core, + python38, + python38-devel, + python38-pip + - name: Install tox + shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} run: | - choco install git gcc-core python38-devel python38-pip --source cygwin - C:\\tools\\cygwin\\bin\\bash -l -x -c 'python3.8 -m pip install tox' + python3.8 -m pip install tox - name: Run tests + shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} run: | - C:\\tools\\cygwin\\bin\\bash -l -x -c 'cd $(cygpath -u "$GITHUB_WORKSPACE") && tox -- --cov-report xml' + tox -- --cov-report xml integration-test: strategy: diff --git a/CHANGES.rst b/CHANGES.rst index e9f8a70..a77f539 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,24 @@ +v60.6.0 +------- + + +Changes +^^^^^^^ +* #3043: Merge with pypa/distutils@bb018f1ac3 including consolidated behavior in sysconfig.get_platform (pypa/distutils#104). +* #3057: Don't include optional ``Home-page`` in metadata if no ``url`` is specified. -- by :user:`cdce8p` +* #3062: Merge with pypa/distutils@b53a824ec3 including improved support for lib directories on non-x64 Windows builds. + +Misc +^^^^ +* #3054: Used Py3 syntax ``super().__init__()`` -- by :user:`imba-tjd` + + v60.5.4 ------- Misc ^^^^ -* #NNN: * #3009: Remove filtering of distutils warnings. * #3031: Suppress distutils replacement when building or testing CPython. diff --git a/README.rst b/README.rst index 7ea2b70..fe2e749 100644 --- a/README.rst +++ b/README.rst @@ -40,8 +40,8 @@ See the `Installation Instructions User's Guide for instructions on installing, upgrading, and uninstalling Setuptools. -Questions and comments should be directed to the `distutils-sig -mailing list `_. +Questions and comments should be directed to `GitHub Discussions +`_. Bug reports and especially tested patches may be submitted directly to the `bug tracker `_. @@ -51,7 +51,7 @@ Code of Conduct =============== Everyone interacting in the setuptools project's codebases, issue trackers, -chat rooms, and mailing lists is expected to follow the +chat rooms, and fora is expected to follow the `PSF Code of Conduct `_. diff --git a/changelog.d/2897.docs.rst b/changelog.d/2897.docs.rst new file mode 100644 index 0000000..763a39b --- /dev/null +++ b/changelog.d/2897.docs.rst @@ -0,0 +1,4 @@ +Added documentation about wrapping ``setuptools.build_meta`` in a in-tree +custom backend. This is a :pep:`517`-compliant way of dynamically specifying +build dependencies (e.g. when platform, OS and other markers are not enough) +-- by :user:`abravalheri`. diff --git a/changelog.d/3034.docs.rst b/changelog.d/3034.docs.rst new file mode 100644 index 0000000..6106e0f --- /dev/null +++ b/changelog.d/3034.docs.rst @@ -0,0 +1,4 @@ +Replaced occurrences of the defunct distutils-sig mailing list with pointers +to GitHub Discussions. +-- by :user:`ashemedai` + diff --git a/changelog.d/3056.docs.rst b/changelog.d/3056.docs.rst new file mode 100644 index 0000000..c3de4e9 --- /dev/null +++ b/changelog.d/3056.docs.rst @@ -0,0 +1,2 @@ +The documentation has stopped suggesting to add ``wheel`` to +:pep:`517` requirements -- by :user:`webknjaz` diff --git a/docs/build_meta.rst b/docs/build_meta.rst index 27df70a..1337bdd 100644 --- a/docs/build_meta.rst +++ b/docs/build_meta.rst @@ -9,29 +9,29 @@ Python packaging has come `a long way `_ The traditional ``setuptools`` way of packaging Python modules uses a ``setup()`` function within the ``setup.py`` script. Commands such as -``python setup.py bdist`` or ``python setup.py bdist_wheel`` generate a -distribution bundle and ``python setup.py install`` installs the distribution. -This interface makes it difficult to choose other packaging tools without an +``python setup.py bdist`` or ``python setup.py bdist_wheel`` generate a +distribution bundle and ``python setup.py install`` installs the distribution. +This interface makes it difficult to choose other packaging tools without an overhaul. Because ``setup.py`` scripts allowed for arbitrary execution, it proved difficult to provide a reliable user experience across environments and history. `PEP 517 `_ therefore came to -rescue and specified a new standard to +rescue and specified a new standard to package and distribute Python modules. Under PEP 517: a ``pyproject.toml`` file is used to specify what program to use - for generating distribution. + for generating distribution. - Then, two functions provided by the program, ``build_wheel(directory: str)`` - and ``build_sdist(directory: str)`` create the distribution bundle at the - specified ``directory``. The program is free to use its own configuration - script or extend the ``.toml`` file. + Then, two functions provided by the program, ``build_wheel(directory: str)`` + and ``build_sdist(directory: str)`` create the distribution bundle at the + specified ``directory``. The program is free to use its own configuration + script or extend the ``.toml`` file. Lastly, ``pip install *.whl`` or ``pip install *.tar.gz`` does the actual installation. If ``*.whl`` is available, ``pip`` will go ahead and copy the files into ``site-packages`` directory. If not, ``pip`` will look at - ``pyproject.toml`` and decide what program to use to 'build from source' + ``pyproject.toml`` and decide what program to use to 'build from source' (the default is ``setuptools``) With this standard, switching between packaging tools becomes a lot easier. ``build_meta`` @@ -48,17 +48,18 @@ scripts, a ``pyproject.toml`` file and a ``setup.cfg`` file:: setup.cfg meowpkg/__init__.py -The pyproject.toml file is required to specify the build system (i.e. what is -being used to package your scripts and install from source). To use it with +The pyproject.toml file is required to specify the build system (i.e. what is +being used to package your scripts and install from source). To use it with setuptools, the content would be:: [build-system] - requires = ["setuptools", "wheel"] + requires = ["setuptools"] build-backend = "setuptools.build_meta" The ``setuptools`` package implements the ``build_sdist`` command and the ``wheel`` package implements the ``build_wheel`` -command; both are required to be compliant with PEP 517. +command; the latter is a dependency of the former +exposed via :pep:`517` hooks. Use ``setuptools``' :ref:`declarative config ` to specify the package information:: @@ -67,7 +68,7 @@ specify the package information:: name = meowpkg version = 0.0.1 description = a package that meows - + [options] packages = find: @@ -77,7 +78,7 @@ Now generate the distribution. To build the package, use $ pip install -q build $ python -m build -And now it's done! The ``.whl`` file and ``.tar.gz`` can then be distributed +And now it's done! The ``.whl`` file and ``.tar.gz`` can then be distributed and installed:: dist/ @@ -89,3 +90,85 @@ and installed:: or:: $ pip install dist/meowpkg-0.0.1.tar.gz + +Dynamic build dependencies and other ``build_meta`` tweaks +---------------------------------------------------------- + +With the changes introduced by :pep:`517` and :pep:`518`, the +``setup_requires`` configuration field was made deprecated in ``setup.cfg`` and +``setup.py``, in favour of directly listing build dependencies in the +``requires`` field of the ``build-system`` table of ``pyproject.toml``. +This approach has a series of advantages and gives package managers and +installers the ability to inspect in advance the build requirements and +perform a series of optimisations. + +However some package authors might still need to dynamically inspect the final +users machine before deciding these requirements. One way of doing that, as +specified by :pep:`517`, is to "tweak" ``setuptools.build_meta`` by using a +:pep:`in-tree backend <517#in-tree-build-backends>`. + +.. tip:: Before implementing a *in-tree* backend, have a look on + :pep:`PEP 508 <508#environment-markers>`. Most of the times, dependencies + with **environment markers** are enough to differentiate operating systems + and platforms. + +If you add the following configuration to your ``pyprojec.toml``: + + +.. code-block:: toml + + [build-system] + requires = ["setuptools", "wheel"] + build-backend = "backend" + backend-path = ["_custom_build"] + + +then you should be able to implement a thin wrapper around ``build_meta`` in +the ``_custom_build/backend.py`` file, as shown in the following example: + +.. code-block:: python + + from setuptools import build_meta as _orig + + prepare_metadata_for_build_wheel = _orig.prepare_metadata_for_build_wheel + build_wheel = _orig.build_wheel + build_sdist = _orig.build_sdist + + + def get_requires_for_build_wheel(self, config_settings=None): + return _orig.get_requires_for_build_wheel(config_settings) + [...] + + + def get_requires_for_build_sdist(self, config_settings=None): + return _orig.get_requires_for_build_sdist(config_settings) + [...] + + +Note that you can override any of the functions specified in :pep:`PEP 517 +<517#build-backend-interface>`, not only the ones responsible for gathering +requirements. + +.. important:: Make sure your backend script is included in the :doc:`source + distribution `, otherwise the build will fail. + This can be done by using a SCM_/VCS_ plugin (like :pypi:`setuptools-scm` + and :pypi:`setuptools-svn`), or by correctly setting up :ref:`MANIFEST.in + `. + + If this is the first time you are using a customised backend, please have a + look on the generated ``.tar.gz`` and ``.whl``. + On POSIX systems that can be done with ``tar -tf dist/*.tar.gz`` + and ``unzip -l dist/*.whl``. + On Windows systems you can rename the ``.whl`` to ``.zip`` to be able to + inspect it on the file explorer, and use the same ``tar`` command in a + command prompt (alternativelly there are GUI programs like `7-zip`_ that + handle ``.tar.gz``). + + In general the backend script should be present in the ``.tar.gz`` (so the + project can be build from the source) but not in the ``.whl`` (otherwise the + backend script would end up being distributed alongside your package). + See ":doc:`/userguide/package_discovery`" for more details about package + files. + + +.. _SCM: https://en.wikipedia.org/wiki/Software_configuration_management +.. _VCS: https://en.wikipedia.org/wiki/Version_control +.. _7-zip: https://www.7-zip.org diff --git a/docs/conf.py b/docs/conf.py index 1fb2771..bfd45a6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -96,6 +96,7 @@ github_url = 'https://github.com' github_sponsors_url = f'{github_url}/sponsors' extlinks = { 'user': (f'{github_sponsors_url}/%s', '@'), # noqa: WPS323 + 'pypi': ('https://pypi.org/project/%s', '%s'), } extensions += ['sphinx.ext.extlinks'] diff --git a/docs/deprecated/distutils-legacy.rst b/docs/deprecated/distutils-legacy.rst index 94104fe..148dc25 100644 --- a/docs/deprecated/distutils-legacy.rst +++ b/docs/deprecated/distutils-legacy.rst @@ -5,7 +5,7 @@ Setuptools and the PyPA have a `stated goal `_, or on IRC (Freenode) at -#pypa. +User support and discussions are done through +`GitHub Discussions `_, +or the issue tracker (for specific issues). -Discussions about development happen on the distutils-sig mailing list or on -`Gitter `_. +Discussions about development happen on GitHub Discussions or +the ``setuptools`` channel on `PyPA Discord `_. ----------------- Authoring Tickets @@ -125,12 +125,9 @@ cannot declare dependencies other than through ``setuptools/_vendor/vendored.txt`` and ``pkg_resources/_vendor/vendored.txt``. -All the dependencies specified in these files are "vendorized" using Paver_, a -simple Python-based project scripting and task running tool. +All the dependencies specified in these files are "vendorized" using a +simple Python script ``tools/vendor.py``. -To refresh the dependencies, you can run the following command (defined in -``pavement.py``):: +To refresh the dependencies, run the following command:: - $ paver update_vendored - -.. _Paver: https://pythonhosted.org/Paver/ + $ tox -e vendor diff --git a/docs/setuptools.rst b/docs/setuptools.rst index c5a89ad..d0fb9a9 100644 --- a/docs/setuptools.rst +++ b/docs/setuptools.rst @@ -201,13 +201,13 @@ As a consequence, the resulting dictionary will include no such options. -Mailing List and Bug Tracker -============================ +Forum and Bug Tracker +===================== -Please use the `distutils-sig mailing list`_ for questions and discussion about +Please use `GitHub Discussions`_ for questions and discussion about setuptools, and the `setuptools bug tracker`_ ONLY for issues you have -confirmed via the list are actual bugs, and which you have reduced to a minimal +confirmed via the forum are actual bugs, and which you have reduced to a minimal set of steps to reproduce. -.. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ +.. _GitHub Discussions: https://github.com/pypa/setuptools/discussions .. _setuptools bug tracker: https://github.com/pypa/setuptools/ diff --git a/docs/userguide/declarative_config.rst b/docs/userguide/declarative_config.rst index d1c25df..6f41d92 100644 --- a/docs/userguide/declarative_config.rst +++ b/docs/userguide/declarative_config.rst @@ -222,10 +222,10 @@ data_files section 40.6.0 [# .. [#opt-1] In the ``package_data`` section, a key named with a single asterisk (``*``) refers to all packages, in lieu of the empty string used in ``setup.py``. - + .. [#opt-2] In the ``extras_require`` section, values are parsed as ``list-semi``. This implies that in order to include markers, they **must** be *dangling*: - + .. code-block:: ini [options.extras_require] diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst index 9c29dbd..ea2fc55 100644 --- a/docs/userguide/dependency_management.rst +++ b/docs/userguide/dependency_management.rst @@ -28,7 +28,7 @@ other two types of dependency keyword, this one is specified in your .. code-block:: ini [build-system] - requires = ["setuptools", "wheel"] + requires = ["setuptools"] #... .. note:: diff --git a/docs/userguide/distribution.rst b/docs/userguide/distribution.rst index 2872dac..db0f1a5 100644 --- a/docs/userguide/distribution.rst +++ b/docs/userguide/distribution.rst @@ -162,7 +162,7 @@ Specifying Your Project's Version --------------------------------- Setuptools can work well with most versioning schemes. Over the years, -setuptools has tried to closely follow the +setuptools has tried to closely follow the `PEP 440 `_ scheme, but it also supports legacy versions. There are, however, a few special things to watch out for, in order to ensure that setuptools and diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst index 4c62c6d..203d620 100644 --- a/docs/userguide/quickstart.rst +++ b/docs/userguide/quickstart.rst @@ -32,7 +32,7 @@ package your project: .. code-block:: toml [build-system] - requires = ["setuptools", "wheel"] + requires = ["setuptools"] build-backend = "setuptools.build_meta" Then, you will need a ``setup.cfg`` or ``setup.py`` to specify your package @@ -96,7 +96,7 @@ to specify to properly package your project. Automatic package discovery =========================== For simple projects, it's usually easy enough to manually add packages to -the ``packages`` keyword in ``setup.cfg``. However, for very large projects, +the ``packages`` keyword in ``setup.cfg``. However, for very large projects, it can be a big burden to keep the package list updated. ``setuptools`` therefore provides two convenient tools to ease the burden: :literal:`find:\ ` and :literal:`find_namespace:\ `. To use it in your project: @@ -189,9 +189,9 @@ Development mode .. tip:: - Prior to :ref:`pip v21.1 `, a ``setup.py`` script was - required to be compatible with development mode. With late - versions of pip, any project may be installed in this mode. + Prior to :ref:`pip v21.1 `, a ``setup.py`` script was + required to be compatible with development mode. With late + versions of pip, any project may be installed in this mode. ``setuptools`` allows you to install a package without copying any files to your interpreter directory (e.g. the ``site-packages`` directory). diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 9cc6b0a..93db52d 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1581,7 +1581,7 @@ class EggProvider(NullProvider): """Provider based on a virtual filesystem""" def __init__(self, module): - NullProvider.__init__(self, module) + super().__init__(module) self._setup_prefix() def _setup_prefix(self): @@ -1701,7 +1701,7 @@ class ZipProvider(EggProvider): _zip_manifests = MemoizedZipManifests() def __init__(self, module): - EggProvider.__init__(self, module) + super().__init__(module) self.zip_pre = self.loader.archive + os.sep def _zipinfo_name(self, fspath): @@ -2404,7 +2404,20 @@ def _nonblank(str): @functools.singledispatch def yield_lines(iterable): - """Yield valid lines of a string or iterable""" + r""" + Yield valid lines of a string or iterable. + + >>> list(yield_lines('')) + [] + >>> list(yield_lines(['foo', 'bar'])) + ['foo', 'bar'] + >>> list(yield_lines('foo\nbar')) + ['foo', 'bar'] + >>> list(yield_lines('\nfoo\n#bar\nbaz #comment')) + ['foo', 'baz #comment'] + >>> list(yield_lines(['foo\nbar', 'baz', 'bing\n\n\n'])) + ['foo', 'bar', 'baz', 'bing'] + """ return itertools.chain.from_iterable(map(yield_lines, iterable)) @@ -3079,26 +3092,61 @@ def issue_warning(*args, **kw): warnings.warn(stacklevel=level + 1, *args, **kw) -def parse_requirements(strs): - """Yield ``Requirement`` objects for each specification in `strs` +def drop_comment(line): + """ + Drop comments. - `strs` must be a string, or a (possibly-nested) iterable thereof. + >>> drop_comment('foo # bar') + 'foo' + + A hash without a space may be in a URL. + + >>> drop_comment('http://example.com/foo#bar') + 'http://example.com/foo#bar' """ - # create a steppable iterator, so we can handle \-continuations - lines = iter(yield_lines(strs)) + return line.partition(' #')[0] + + +def join_continuation(lines): + r""" + Join lines continued by a trailing backslash. - for line in lines: - # Drop comments -- a hash without a space may be in a URL. - if ' #' in line: - line = line[:line.find(' #')] - # If there is a line continuation, drop it, and append the next line. - if line.endswith('\\'): - line = line[:-2].strip() + >>> list(join_continuation(['foo \\', 'bar', 'baz'])) + ['foobar', 'baz'] + >>> list(join_continuation(['foo \\', 'bar', 'baz'])) + ['foobar', 'baz'] + >>> list(join_continuation(['foo \\', 'bar \\', 'baz'])) + ['foobarbaz'] + + Not sure why, but... + The character preceeding the backslash is also elided. + + >>> list(join_continuation(['goo\\', 'dly'])) + ['godly'] + + A terrible idea, but... + If no line is available to continue, suppress the lines. + + >>> list(join_continuation(['foo', 'bar\\', 'baz\\'])) + ['foo'] + """ + lines = iter(lines) + for item in lines: + while item.endswith('\\'): try: - line += next(lines) + item = item[:-2].strip() + next(lines) except StopIteration: return - yield Requirement(line) + yield item + + +def parse_requirements(strs): + """ + Yield ``Requirement`` objects for each specification in `strs`. + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + return map(Requirement, join_continuation(map(drop_comment, yield_lines(strs)))) class RequirementParseError(packaging.requirements.InvalidRequirement): diff --git a/setup.cfg b/setup.cfg index b83d376..957c7ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = setuptools -version = 60.5.4 +version = 60.6.0 author = Python Packaging Authority author_email = distutils-sig@python.org description = Easily download, build, install, upgrade, and uninstall Python packages @@ -65,6 +65,7 @@ testing = jaraco.path>=3.2.0 build[virtualenv] filelock>=3.4.0 + pip_run>=8.8 testing-integration = pytest diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 43d1c96..06991b6 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -132,7 +132,7 @@ def _install_setup_requires(attrs): def __init__(self, attrs): _incl = 'dependency_links', 'setup_requires' filtered = {k: attrs[k] for k in set(_incl) & set(attrs)} - distutils.core.Distribution.__init__(self, filtered) + super().__init__(filtered) def finalize_options(self): """ @@ -171,7 +171,7 @@ class Command(_Command): Construct the command for dist, updating vars(self) with any keyword parameters. """ - _Command.__init__(self, dist) + super().__init__(dist) vars(self).update(kw) def _ensure_stringlike(self, option, what, default=None): diff --git a/setuptools/_distutils/_msvccompiler.py b/setuptools/_distutils/_msvccompiler.py index c41ea9a..f2f801c 100644 --- a/setuptools/_distutils/_msvccompiler.py +++ b/setuptools/_distutils/_msvccompiler.py @@ -203,7 +203,7 @@ class MSVCCompiler(CCompiler) : def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + super().__init__(verbose, dry_run, force) # target platform (.plat_name is consistent with 'bdist') self.plat_name = None self.initialized = False diff --git a/setuptools/_distutils/bcppcompiler.py b/setuptools/_distutils/bcppcompiler.py index 071fea5..2eb6d2e 100644 --- a/setuptools/_distutils/bcppcompiler.py +++ b/setuptools/_distutils/bcppcompiler.py @@ -55,7 +55,7 @@ class BCPPCompiler(CCompiler) : dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + super().__init__(verbose, dry_run, force) # These executables are assumed to all be in the path. # Borland doesn't seem to use any special registry settings to diff --git a/setuptools/_distutils/command/bdist_msi.py b/setuptools/_distutils/command/bdist_msi.py index 0863a18..1525953 100644 --- a/setuptools/_distutils/command/bdist_msi.py +++ b/setuptools/_distutils/command/bdist_msi.py @@ -27,7 +27,7 @@ class PyDialog(Dialog): def __init__(self, *args, **kw): """Dialog(database, name, x, y, w, h, attributes, title, first, default, cancel, bitmap=true)""" - Dialog.__init__(self, *args) + super().__init__(*args) ruler = self.h - 36 bmwidth = 152*ruler/328 #if kw.get("bitmap", True): diff --git a/setuptools/_distutils/command/check.py b/setuptools/_distutils/command/check.py index ada2500..525540b 100644 --- a/setuptools/_distutils/command/check.py +++ b/setuptools/_distutils/command/check.py @@ -17,7 +17,7 @@ try: def __init__(self, source, report_level, halt_level, stream=None, debug=0, encoding='ascii', error_handler='replace'): self.messages = [] - Reporter.__init__(self, source, report_level, halt_level, stream, + super().__init__(source, report_level, halt_level, stream, debug, encoding, error_handler) def system_message(self, level, message, *children, **kwargs): diff --git a/setuptools/_distutils/command/install.py b/setuptools/_distutils/command/install.py index 0587ccd..41c17d8 100644 --- a/setuptools/_distutils/command/install.py +++ b/setuptools/_distutils/command/install.py @@ -68,8 +68,8 @@ if HAS_USER_SITE: INSTALL_SCHEMES['nt_user'] = { 'purelib': '{usersite}', 'platlib': '{usersite}', - 'headers': '{userbase}/{implementation}{py_version_nodot}/Include/{dist_name}', - 'scripts': '{userbase}/{implementation}{py_version_nodot}/Scripts', + 'headers': '{userbase}/{implementation}{py_version_nodot_plat}/Include/{dist_name}', + 'scripts': '{userbase}/{implementation}{py_version_nodot_plat}/Scripts', 'data' : '{userbase}', } @@ -412,12 +412,18 @@ class install(Command): 'implementation': _get_implementation(), } + # vars for compatibility on older Pythons + compat_vars = dict( + # Python 3.9 and earlier + py_version_nodot_plat=getattr(sys, 'winver', '').replace('.', ''), + ) + if HAS_USER_SITE: local_vars['userbase'] = self.install_userbase local_vars['usersite'] = self.install_usersite self.config_vars = _collections.DictStack( - [sysconfig.get_config_vars(), local_vars]) + [compat_vars, sysconfig.get_config_vars(), local_vars]) self.expand_basedirs() diff --git a/setuptools/_distutils/cygwinccompiler.py b/setuptools/_distutils/cygwinccompiler.py index fd082f6..c5c86d8 100644 --- a/setuptools/_distutils/cygwinccompiler.py +++ b/setuptools/_distutils/cygwinccompiler.py @@ -108,7 +108,7 @@ class CygwinCCompiler(UnixCCompiler): def __init__(self, verbose=0, dry_run=0, force=0): - UnixCCompiler.__init__(self, verbose, dry_run, force) + super().__init__(verbose, dry_run, force) status, details = check_config_h() self.debug_print("Python's GCC status: %s (details: %s)" % @@ -268,7 +268,7 @@ class Mingw32CCompiler(CygwinCCompiler): def __init__(self, verbose=0, dry_run=0, force=0): - CygwinCCompiler.__init__ (self, verbose, dry_run, force) + super().__init__ (verbose, dry_run, force) shared_option = "-shared" diff --git a/setuptools/_distutils/msvc9compiler.py b/setuptools/_distutils/msvc9compiler.py index 14d1377..6b62738 100644 --- a/setuptools/_distutils/msvc9compiler.py +++ b/setuptools/_distutils/msvc9compiler.py @@ -324,7 +324,7 @@ class MSVCCompiler(CCompiler) : exe_extension = '.exe' def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + super().__init__(verbose, dry_run, force) self.__version = VERSION self.__root = r"Software\Microsoft\VisualStudio" # self.__macros = MACROS diff --git a/setuptools/_distutils/msvccompiler.py b/setuptools/_distutils/msvccompiler.py index 2d447b8..e1367b8 100644 --- a/setuptools/_distutils/msvccompiler.py +++ b/setuptools/_distutils/msvccompiler.py @@ -228,7 +228,7 @@ class MSVCCompiler(CCompiler) : exe_extension = '.exe' def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + super().__init__(verbose, dry_run, force) self.__version = get_build_version() self.__arch = get_build_architecture() if self.__arch == "Intel": diff --git a/setuptools/_distutils/spawn.py b/setuptools/_distutils/spawn.py index 6e1c89f..b2d10e3 100644 --- a/setuptools/_distutils/spawn.py +++ b/setuptools/_distutils/spawn.py @@ -10,7 +10,7 @@ import sys import os import subprocess -from distutils.errors import DistutilsPlatformError, DistutilsExecError +from distutils.errors import DistutilsExecError from distutils.debug import DEBUG from distutils import log diff --git a/setuptools/_distutils/tests/test_config.py b/setuptools/_distutils/tests/test_config.py index 8ab70ef..27bd9d4 100644 --- a/setuptools/_distutils/tests/test_config.py +++ b/setuptools/_distutils/tests/test_config.py @@ -66,7 +66,7 @@ class BasePyPIRCCommandTestCase(support.TempdirManager, class command(PyPIRCCommand): def __init__(self, dist): - PyPIRCCommand.__init__(self, dist) + super().__init__(dist) def initialize_options(self): pass finalize_options = initialize_options diff --git a/setuptools/_distutils/tests/test_install.py b/setuptools/_distutils/tests/test_install.py index 75770b0..5dbc06b 100644 --- a/setuptools/_distutils/tests/test_install.py +++ b/setuptools/_distutils/tests/test_install.py @@ -81,7 +81,9 @@ class InstallTestCase(support.TempdirManager, install_module.USER_SITE = self.user_site def _expanduser(path): - return self.tmpdir + if path.startswith('~'): + return os.path.normpath(self.tmpdir + path[1:]) + return path self.old_expand = os.path.expanduser os.path.expanduser = _expanduser @@ -122,6 +124,17 @@ class InstallTestCase(support.TempdirManager, self.assertIn('userbase', cmd.config_vars) self.assertIn('usersite', cmd.config_vars) + actual_headers = os.path.relpath(cmd.install_headers, self.user_base) + if os.name == 'nt': + site_path = os.path.relpath( + os.path.dirname(self.old_user_site), self.old_user_base) + include = os.path.join(site_path, 'Include') + else: + include = sysconfig.get_python_inc(0, '') + expect_headers = os.path.join(include, 'xx') + + self.assertEqual(os.path.normcase(actual_headers), os.path.normcase(expect_headers)) + def test_handle_extra_path(self): dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'}) cmd = install(dist) diff --git a/setuptools/_distutils/tests/test_util.py b/setuptools/_distutils/tests/test_util.py index 12469e3..2738388 100644 --- a/setuptools/_distutils/tests/test_util.py +++ b/setuptools/_distutils/tests/test_util.py @@ -2,6 +2,7 @@ import os import sys import unittest +import sysconfig as stdlib_sysconfig from copy import copy from test.support import run_unittest from unittest import mock @@ -10,12 +11,10 @@ from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError from distutils.util import (get_platform, convert_path, change_root, check_environ, split_quoted, strtobool, rfc822_escape, byte_compile, - grok_environment_error) + grok_environment_error, get_host_platform) from distutils import util # used to patch _environ_checked -from distutils.sysconfig import get_config_vars from distutils import sysconfig from distutils.tests import support -import _osx_support class UtilTestCase(support.EnvironGuard, unittest.TestCase): @@ -63,110 +62,26 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase): def _get_uname(self): return self._uname - def test_get_platform(self): - - # windows XP, 32bits - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Intel)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win32') - - # windows XP, amd64 - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Amd64)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win-amd64') - - # macbook - os.name = 'posix' - sys.version = ('2.5 (r25:51918, Sep 19 2006, 08:49:13) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]') - sys.platform = 'darwin' - self._set_uname(('Darwin', 'macziade', '8.11.1', - ('Darwin Kernel Version 8.11.1: ' - 'Wed Oct 10 18:23:28 PDT 2007; ' - 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - - get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' - '-fwrapv -O3 -Wall -Wstrict-prototypes') - - cursize = sys.maxsize - sys.maxsize = (2 ** 31)-1 - try: - self.assertEqual(get_platform(), 'macosx-10.3-i386') - finally: - sys.maxsize = cursize - - # macbook with fat binaries (fat, universal or fat64) - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' - get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat') - - _osx_support._remove_original_values(get_config_vars()) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' - self.assertEqual(get_platform(), 'macosx-10.4-fat') - + def test_get_host_platform(self): + with unittest.mock.patch('os.name', 'nt'): + with unittest.mock.patch('sys.version', '... [... (ARM64)]'): + self.assertEqual(get_host_platform(), 'win-arm64') + with unittest.mock.patch('sys.version', '... [... (ARM)]'): + self.assertEqual(get_host_platform(), 'win-arm32') - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + with unittest.mock.patch('sys.version_info', (3, 9, 0, 'final', 0)): + self.assertEqual(get_host_platform(), stdlib_sysconfig.get_platform()) - self.assertEqual(get_platform(), 'macosx-10.4-intel') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-fat3') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-universal') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat64') - - for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3'%(arch,)) - - self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) - - - # linux debian sarge - os.name = 'posix' - sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' - '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]') - sys.platform = 'linux2' - self._set_uname(('Linux', 'aglae', '2.6.21.1dedibox-r7', - '#1 Mon Apr 30 17:25:38 CEST 2007', 'i686')) - - self.assertEqual(get_platform(), 'linux-i686') - - # XXX more platforms to tests here + def test_get_platform(self): + with unittest.mock.patch('os.name', 'nt'): + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x86'}): + self.assertEqual(get_platform(), 'win32') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x64'}): + self.assertEqual(get_platform(), 'win-amd64') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm'}): + self.assertEqual(get_platform(), 'win-arm32') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm64'}): + self.assertEqual(get_platform(), 'win-arm64') def test_convert_path(self): # linux/mac diff --git a/setuptools/_distutils/util.py b/setuptools/_distutils/util.py index ac6d446..6d506d7 100644 --- a/setuptools/_distutils/util.py +++ b/setuptools/_distutils/util.py @@ -9,6 +9,7 @@ import re import importlib.util import string import sys +import sysconfig from distutils.errors import DistutilsPlatformError from distutils.dep_util import newer from distutils.spawn import spawn @@ -20,82 +21,29 @@ from .py35compat import _optim_args_from_interpreter_flags def get_host_platform(): """Return a string that identifies the current platform. This is used mainly to distinguish platform-specific build directories and platform-specific built - distributions. Typically includes the OS name and version and the - architecture (as supplied by 'os.uname()'), although the exact information - included depends on the OS; eg. on Linux, the kernel version isn't - particularly important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - + distributions. """ - if os.name == 'nt': - if 'amd64' in sys.version.lower(): - return 'win-amd64' - if '(arm)' in sys.version.lower(): - return 'win-arm32' - if '(arm64)' in sys.version.lower(): - return 'win-arm64' - return sys.platform - - # Set for cross builds explicitly - if "_PYTHON_HOST_PLATFORM" in os.environ: - return os.environ["_PYTHON_HOST_PLATFORM"] - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - - (osname, host, release, version, machine) = os.uname() - - # Convert the OS name to lowercase, remove '/' characters, and translate - # spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # We can't use "platform.architecture()[0]" because a - # bootstrap problem. We use a dict to get an error - # if some suspicious happens. - bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} - machine += ".%s" % bitness[sys.maxsize] - # fall through to standard osname-release-machine representation - elif osname[:3] == "aix": - from .py38compat import aix_platform - return aix_platform(osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile (r'[\d.]+', re.ASCII) - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - import _osx_support, distutils.sysconfig - osname, release, machine = _osx_support.get_platform_osx( - distutils.sysconfig.get_config_vars(), - osname, release, machine) - - return "%s-%s-%s" % (osname, release, machine) + + # We initially exposed platforms as defined in Python 3.9 + # even with older Python versions when distutils was split out. + # Now that we delegate to stdlib sysconfig we need to restore this + # in case anyone has started to depend on it. + + if sys.version_info < (3, 8): + if os.name == 'nt': + if '(arm)' in sys.version.lower(): + return 'win-arm32' + if '(arm64)' in sys.version.lower(): + return 'win-arm64' + + if sys.version_info < (3, 9): + if os.name == "posix" and hasattr(os, 'uname'): + osname, host, release, version, machine = os.uname() + if osname[:3] == "aix": + from .py38compat import aix_platform + return aix_platform(osname, version, release) + + return sysconfig.get_platform() def get_platform(): if os.name == 'nt': diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 514719d..e25090b 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -260,6 +260,12 @@ class easy_install(Command): 'implementation': install._get_implementation(), }) + # pypa/distutils#113 Python 3.9 compat + self.config_vars.setdefault( + 'py_version_nodot_plat', + getattr(sys, 'windir', '').replace('.', ''), + ) + if site.ENABLE_USER_SITE: self.config_vars['userbase'] = self.install_userbase self.config_vars['usersite'] = self.install_usersite @@ -1577,7 +1583,7 @@ class PthDistributions(Environment): self.sitedirs = list(map(normalize_path, sitedirs)) self.basedir = normalize_path(os.path.dirname(self.filename)) self._load() - Environment.__init__(self, [], None, None) + super().__init__([], None, None) for path in yield_lines(self.paths): list(map(self.add, find_distributions(path, True))) diff --git a/setuptools/dist.py b/setuptools/dist.py index 37a10d1..f4a56b0 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -113,13 +113,9 @@ def read_pkg_file(self, file): self.author_email = _read_field_from_msg(msg, 'author-email') self.maintainer_email = None self.url = _read_field_from_msg(msg, 'home-page') + self.download_url = _read_field_from_msg(msg, 'download-url') self.license = _read_field_unescaped_from_msg(msg, 'license') - if 'download-url' in msg: - self.download_url = _read_field_from_msg(msg, 'download-url') - else: - self.download_url = None - self.long_description = _read_field_unescaped_from_msg(msg, 'description') if ( self.long_description is None and @@ -171,9 +167,10 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME write_field('Name', self.get_name()) write_field('Version', self.get_version()) write_field('Summary', single_line(self.get_description())) - write_field('Home-page', self.get_url()) optional_fields = ( + ('Home-page', 'url'), + ('Download-URL', 'download_url'), ('Author', 'author'), ('Author-email', 'author_email'), ('Maintainer', 'maintainer'), @@ -187,8 +184,6 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME license = rfc822_escape(self.get_license()) write_field('License', license) - if self.download_url: - write_field('Download-URL', self.download_url) for project_url in self.project_urls.items(): write_field('Project-URL', '%s, %s' % project_url) @@ -472,6 +467,19 @@ class Distribution(_Distribution): ) self._finalize_requires() + def _validate_metadata(self): + required = {"name"} + provided = { + key + for key in vars(self.metadata) + if getattr(self.metadata, key, None) is not None + } + missing = required - provided + + if missing: + msg = f"Required package metadata is missing: {missing}" + raise DistutilsSetupError(msg) + def _set_metadata_defaults(self, attrs): """ Fill-in missing metadata fields not supported by distutils. diff --git a/setuptools/extension.py b/setuptools/extension.py index 1820722..f696c9c 100644 --- a/setuptools/extension.py +++ b/setuptools/extension.py @@ -34,7 +34,7 @@ class Extension(_Extension): # The *args is needed for compatibility as calls may use positional # arguments. py_limited_api may be set only via keyword. self.py_limited_api = kw.pop("py_limited_api", False) - _Extension.__init__(self, name, sources, *args, **kw) + super().__init__(name, sources, *args, **kw) def _convert_pyx_sources_to_lang(self): """ diff --git a/setuptools/logging.py b/setuptools/logging.py index dbead6e..15b5761 100644 --- a/setuptools/logging.py +++ b/setuptools/logging.py @@ -24,6 +24,12 @@ def configure(): format="{message}", style='{', handlers=handlers, level=logging.DEBUG) monkey.patch_func(set_threshold, distutils.log, 'set_threshold') + # For some reason `distutils.log` module is getting cached in `distutils.dist` + # and then loaded again when patched, + # implying: id(distutils.log) != id(distutils.dist.log). + # Make sure the same module object is used everywhere: + distutils.dist.log = distutils.log + def set_threshold(level): logging.root.setLevel(level*10) diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 270e7f3..051e523 100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -285,7 +285,7 @@ class PackageIndex(Environment): self, index_url="https://pypi.org/simple/", hosts=('*',), ca_bundle=None, verify_ssl=True, *args, **kw ): - Environment.__init__(self, *args, **kw) + super().__init__(*args, **kw) self.index_url = index_url + "/" [:not index_url.endswith('/')] self.scanned_urls = {} self.fetched_urls = {} @@ -1002,7 +1002,7 @@ class PyPIConfig(configparser.RawConfigParser): Load from ~/.pypirc """ defaults = dict.fromkeys(['username', 'password', 'repository'], '') - configparser.RawConfigParser.__init__(self, defaults) + super().__init__(defaults) rc = os.path.join(os.path.expanduser('~'), '.pypirc') if os.path.exists(rc): diff --git a/setuptools/tests/requirements.txt b/setuptools/tests/requirements.txt deleted file mode 100644 index b2d84a9..0000000 --- a/setuptools/tests/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -mock -pytest-flake8 -flake8-2020; python_version>="3.6" -virtualenv>=13.0.0 -pytest-virtualenv>=1.2.7 -pytest>=3.7 -wheel -coverage>=4.5.1 -pytest-cov>=2.5.1 -paver; python_version>="3.6" -futures; python_version=="2.7" -pip>=19.1 # For proper file:// URLs support. -jaraco.envs -sphinx diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py index fb5b90b..67f788c 100644 --- a/setuptools/tests/test_bdist_egg.py +++ b/setuptools/tests/test_bdist_egg.py @@ -13,7 +13,7 @@ from . import contexts SETUP_PY = """\ from setuptools import setup -setup(name='foo', py_modules=['hi']) +setup(py_modules=['hi']) """ @@ -52,7 +52,6 @@ class Test: dist = Distribution(dict( script_name='setup.py', script_args=['bdist_egg', '--exclude-source-files'], - name='foo', py_modules=['hi'], )) with contexts.quiet(): diff --git a/setuptools/tests/test_build_py.py b/setuptools/tests/test_build_py.py index 78a31ac..19c8b78 100644 --- a/setuptools/tests/test_build_py.py +++ b/setuptools/tests/test_build_py.py @@ -18,7 +18,6 @@ def test_directories_in_package_data_glob(tmpdir_cwd): script_name='setup.py', script_args=['build_py'], packages=[''], - name='foo', package_data={'': ['path/*']}, )) os.makedirs('path/subpath') @@ -40,7 +39,6 @@ def test_read_only(tmpdir_cwd): script_args=['build_py'], packages=['pkg'], package_data={'pkg': ['data.dat']}, - name='pkg', )) os.makedirs('pkg') open('pkg/__init__.py', 'w').close() @@ -70,7 +68,6 @@ def test_executable_data(tmpdir_cwd): script_args=['build_py'], packages=['pkg'], package_data={'pkg': ['run-me']}, - name='pkg', )) os.makedirs('pkg') open('pkg/__init__.py', 'w').close() diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py index 1aeb7ff..c52072a 100644 --- a/setuptools/tests/test_develop.py +++ b/setuptools/tests/test_develop.py @@ -6,11 +6,11 @@ import sys import subprocess import platform import pathlib -import textwrap from setuptools.command import test import pytest +import pip_run.launch from setuptools.command.develop import develop from setuptools.dist import Distribution @@ -166,21 +166,6 @@ class TestNamespaces: with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(pkg_resources_imp) - @staticmethod - def install_workaround(site_packages): - site_packages.mkdir(parents=True) - sc = site_packages / 'sitecustomize.py' - sc.write_text( - textwrap.dedent( - """ - import site - import pathlib - here = pathlib.Path(__file__).parent - site.addsitedir(str(here)) - """ - ).lstrip() - ) - @pytest.mark.xfail( platform.python_implementation() == 'PyPy', reason="Workaround fails on PyPy (why?)", @@ -190,7 +175,6 @@ class TestNamespaces: Editable install to a prefix should be discoverable. """ prefix = tmp_path / 'prefix' - prefix.mkdir() # figure out where pip will likely install the package site_packages = prefix / next( @@ -198,9 +182,10 @@ class TestNamespaces: for path in sys.path if 'site-packages' in path and path.startswith(sys.prefix) ) + site_packages.mkdir(parents=True) - # install the workaround - self.install_workaround(site_packages) + # install workaround + pip_run.launch.inject_sitecustomize(str(site_packages)) env = dict(os.environ, PYTHONPATH=str(site_packages)) cmd = [ diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py index c4279f0..4980f2c 100644 --- a/setuptools/tests/test_dist.py +++ b/setuptools/tests/test_dist.py @@ -374,3 +374,8 @@ def test_check_specifier(): ) def test_rfc822_unescape(content, result): assert (result or content) == rfc822_unescape(rfc822_escape(content)) + + +def test_metadata_name(): + with pytest.raises(DistutilsSetupError, match='missing.*name'): + Distribution()._validate_metadata() diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 83ce7f4..5831b26 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -64,7 +64,7 @@ class FakeDist: SETUP_PY = DALS(""" from setuptools import setup - setup(name='foo') + setup() """) diff --git a/setuptools/tests/test_logging.py b/setuptools/tests/test_logging.py new file mode 100644 index 0000000..a5ddd56 --- /dev/null +++ b/setuptools/tests/test_logging.py @@ -0,0 +1,36 @@ +import logging + +import pytest + + +setup_py = """\ +from setuptools import setup + +setup( + name="test_logging", + version="0.0" +) +""" + + +@pytest.mark.parametrize( + "flag, expected_level", [("--dry-run", "INFO"), ("--verbose", "DEBUG")] +) +def test_verbosity_level(tmp_path, monkeypatch, flag, expected_level): + """Make sure the correct verbosity level is set (issue #3038)""" + import setuptools # noqa: Import setuptools to monkeypatch distutils + import distutils # <- load distutils after all the patches take place + + logger = logging.Logger(__name__) + monkeypatch.setattr(logging, "root", logger) + unset_log_level = logger.getEffectiveLevel() + assert logging.getLevelName(unset_log_level) == "NOTSET" + + setup_script = tmp_path / "setup.py" + setup_script.write_text(setup_py) + dist = distutils.core.run_setup(setup_script, stop_after="init") + dist.script_args = [flag, "sdist"] + dist.parse_command_line() # <- where the log level is set + log_level = logger.getEffectiveLevel() + log_level_name = logging.getLevelName(log_level) + assert log_level_name == expected_level diff --git a/setuptools/tests/test_sphinx_upload_docs.py b/setuptools/tests/test_sphinx_upload_docs.py index cc5b829..f24077f 100644 --- a/setuptools/tests/test_sphinx_upload_docs.py +++ b/setuptools/tests/test_sphinx_upload_docs.py @@ -25,7 +25,6 @@ def sphinx_doc_sample_project(tmpdir_cwd): class TestSphinxUploadDocs: def test_sphinx_doc(self): params = dict( - name='foo', packages=['test'], ) dist = Distribution(params) diff --git a/setuptools/tests/test_test.py b/setuptools/tests/test_test.py index 8b8d9e6..530474d 100644 --- a/setuptools/tests/test_test.py +++ b/setuptools/tests/test_test.py @@ -10,7 +10,6 @@ from .textwrap import DALS @pytest.mark.usefixtures('tmpdir_cwd') def test_tests_are_run_once(capfd): params = dict( - name='foo', packages=['dummy'], ) files = { diff --git a/setuptools/tests/test_upload_docs.py b/setuptools/tests/test_upload_docs.py index 55978aa..68977a5 100644 --- a/setuptools/tests/test_upload_docs.py +++ b/setuptools/tests/test_upload_docs.py @@ -18,7 +18,7 @@ def sample_project(tmpdir_cwd): 'setup.py': DALS(""" from setuptools import setup - setup(name='foo') + setup() """), 'build': { 'index.html': 'Hello world.',