Commit 73068115 authored by Jason R. Coombs's avatar Jason R. Coombs

Merge branch 'master' into docs_ci

parents 8f1f09b7 52c394c1
[bumpversion]
current_version = 41.0.1
current_version = 46.4.0
commit = True
tag = True
[bumpversion:file:setup.cfg]
[flake8]
exclude=
.tox
setuptools/_vendor,
pkg_resources/_vendor
ignore =
# W503 violates spec https://github.com/PyCQA/pycodestyle/issues/513
W503
# W504 has issues https://github.com/OCA/maintainer-quality-tools/issues/545
W504
setuptools/site-patch.py F821
setuptools/py*compat.py F811
tidelift: pypi/setuptools
---
name: Setuptools warns about Python 2 incompatibility
about: Report the issue where setuptools 45 or later stops working on Python 2
title: Incompatible install in (summarize your environment)
labels: Python 2
assignees: ''
---
<!--
Please DO NOT SUBMIT this template without first investigating the issue and answering the questions below. This template is intended mainly for developers of systems and not for end users. If you are an end user experiencing the warning, please work with your system maintainers (starting with the project you're trying to use) to report the issue.
If you did not intend to use this template, but only meant to file a blank issue, just hit the back button and click "Open a blank issue".
It's by design that Setuptools 45 and later will stop working on Python 2. To ease the transition, Setuptools 45 was released to continue to have Python 2 compatibility, but emit a strenuous warning that it will stop working.
In most cases, using pip 9 or later to install Setuptools from PyPI or any index supporting the Requires-Python metadata will do the right thing and install Setuptools 44.x on Python 2.
If you've come to file an issue, it's probably because some process managed to bypass these protections.
Your first course of action should be to reason about how you managed to get an unsupported version of Setuptools on Python 2. Please complete the sections below and provide any other detail about your environment that will help us help you.
-->
## Prerequisites
<!-- These are the recommended workarounds for the issue. Please
try them first. -->
- [ ] Python 2 is required for this application.
- [ ] I maintain the software that installs Setuptools (if not, please contact that project).
- [ ] Setuptools installed with pip 9 or later.
- [ ] Pinning Setuptools to `setuptools<45` in the environment was unsuccessful.
## Environment Details
- Operating System and version:
- Python version:
- Python installed how:
- Virtualenv version (if using virtualenv): n/a
Command(s) used to install setuptools (and output):
```
```
Output of `pip --version` when installing setuptools:
```
```
## Other notes
name: >-
👷
Test suite
on:
push:
pull_request:
schedule:
- cron: 1 0 * * * # Run daily at 0:01 UTC
jobs:
tests:
name: >-
${{ matrix.python-version }}
/
${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
# max-parallel: 5
matrix:
python-version:
- 3.8
- pypy3
- 3.7
- 3.6
- 3.5
os:
- ubuntu-latest
- ubuntu-16.04
- macOS-latest
# - windows-2019
# - windows-2016
env:
NETWORK_REQUIRED: 1
TOX_PARALLEL_NO_SPINNER: 1
TOXENV: python
steps:
- uses: actions/checkout@master
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1.1.1
with:
python-version: ${{ matrix.python-version }}
- name: Log Python version
run: >-
python --version
- name: Log Python location
run: >-
which python
- name: Log Python env
run: >-
python -m sysconfig
- name: Pip cache
uses: actions/cache@v1
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('setup.cfg') }}
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-
- name: Upgrade pip/setuptools/wheel
run: >-
python
-m pip install
--disable-pip-version-check
--upgrade
pip setuptools wheel
- name: Install tox
run: >-
python -m pip install --upgrade tox tox-venv
- name: Log installed dists
run: >-
python -m pip freeze --all
- name: Adjust TOXENV for PyPy
if: startsWith(matrix.python-version, 'pypy')
run: >-
echo "::set-env name=TOXENV::${{ matrix.python-version }}"
- name: Log env vars
run: >-
env
- name: Verify that there's no cached Python modules in sources
if: >-
! startsWith(matrix.os, 'windows-')
run: >-
! grep pyc setuptools.egg-info/SOURCES.txt
- name: 'Initialize tox envs: ${{ matrix.env.TOXENV }}'
run: >-
python -m
tox
--parallel auto
--notest
--skip-missing-interpreters false
- name: Test with tox
run: >-
python -m
tox
--parallel auto
--
--cov
......@@ -19,3 +19,4 @@ setuptools.egg-info
.cache
.idea/
.pytest_cache/
.mypy_cache/
python:
version: 3
requirements_file: docs/requirements.txt
extra_requirements:
- docs
pip_install: false
requirements: docs/requirements.txt
......@@ -6,43 +6,26 @@ jobs:
include:
- &latest_py2
python: 2.7
env: TOXENV=py27
- <<: *latest_py2
env: LANG=C
- python: pypy2.7-6.0.0
env: LANG=C TOXENV=py27
- python: pypy3
env: DISABLE_COVERAGE=1 # Don't run coverage on pypy (too slow).
- python: pypy3.5-6.0.0
env: DISABLE_COVERAGE=1
- python: 3.4
- python: 3.5
- &default_py
python: 3.6
- python: 3.6
- python: 3.7
- &latest_py3
python: 3.7
python: 3.8
- <<: *latest_py3
env: LANG=C
- python: 3.8-dev
- <<: *latest_py3
env: TOXENV=docs DISABLE_COVERAGE=1
- <<: *default_py
stage: deploy (to PyPI for tagged commits)
if: tag IS present
install: skip
script: skip
after_success: true
before_deploy:
- python bootstrap.py
- "! grep pyc setuptools.egg-info/SOURCES.txt"
deploy:
provider: pypi
on:
tags: true
all_branches: true
user: jaraco
password:
secure: tfWrsQMH2bHrWjqnP+08IX1WlkbW94Q30f4d7lCyhWS1FIf/jBDx4jrEILNfMxQ1NCwuBRje5sihj1Ow0BFf0vVrkaeff2IdvnNDEGFduMejaEQJL3s3QrLfpiAvUbtqwyWaHfAdGfk48PovDKTx0ZTvXZKYGXZhxGCYSlG2CE6Y6RDvnEl6Tk8e+LqUohkcSOwxrRwUoyxSnUaavdGohXxDT8MJlfWOXgr2u+KsRrriZqp3l6Fdsnk4IGvy6pXpy42L1HYQyyVu9XyJilR2JTbC6eCp5f8p26093m1Qas49+t6vYb0VLqQe12dO+Jm3v4uztSS5pPQzS7PFyjEYd2Rdb6ijsdbsy1074S4q7G9Sz+T3RsPUwYEJ07lzez8cxP64dtj5j94RL8m35A1Fb1OE8hHN+4c1yLG1gudfXbem+fUhi2eqhJrzQo5vsvDv1xS5x5GIS5ZHgKHCsWcW1Tv+dsFkrhaup3uU6VkOuc9UN+7VPsGEY7NvquGpTm8O1CnGJRzuJg6nbYRGj8ORwDpI0KmrExx6akV92P72fMC/I5TCgbSQSZn370H3Jj40gz1SM30WAli9M+wFHFd4ddMVY65yxj0NLmrP+m1tvnWdKtNh/RHuoW92d9/UFtiA5IhMf1/3djfsjBq6S9NT1uaLkVkTttqrPYJ7hOql8+g=
distributions: release
skip_cleanup: true
skip_upload_docs: true
allow_failures:
# suppress failures due to pypa/setuptools#2000
- python: pypy3
- <<: *latest_py3
env: TOXENV=docs DISABLE_COVERAGE=1
cache: pip
......@@ -57,8 +40,6 @@ install:
- pip freeze --all
- env
# update egg_info based on setup.py in checkout
- python bootstrap.py
- "! grep pyc setuptools.egg-info/SOURCES.txt"
script:
......
v46.4.0
-------
* #1753: ``attr:`` now extracts variables through rudimentary examination of the AST,
thereby supporting modules with third-party imports. If examining the AST
fails to find the variable, ``attr:`` falls back to the old behavior of
importing the module. Works on Python 3 only.
v46.3.1
-------
No significant changes.
v46.3.0
-------
* #2089: Package index functionality no longer attempts to remove an md5 fragment from the index URL. This functionality, added for distribute #163 is no longer relevant.
* #2041: Preserve file modes during pkg files copying, but clear read only flag for target afterwards.
* #2105: Filter ``2to3`` deprecation warnings from ``TestDevelop.test_2to3_user_mode``.
v46.2.0
-------
* #2040: Deprecated the ``bdist_wininst`` command. Binary packages should be built as wheels instead.
* #2062: Change 'Mac OS X' to 'macOS' in code.
* #2075: Stop recognizing files ending with ``.dist-info`` as distribution metadata.
* #2086: Deprecate 'use_2to3' functionality. Packagers are encouraged to use single-source solutions or build tool chains to manage conversions outside of setuptools.
* #1698: Added documentation for ``build_meta`` (a bare minimum, not completed).
* #2082: Filter ``lib2to3`` ``PendingDeprecationWarning`` and ``DeprecationWarning`` in tests,
because ``lib2to3`` is `deprecated in Python 3.9 <https://bugs.python.org/issue40360>`_.
v46.1.3
-------
No significant changes.
v46.1.2
-------
* #1458: Added template for reporting Python 2 incompatibilities.
v46.1.1
-------
No significant changes.
v46.1.0
-------
* #308: Allow version number normalization to be bypassed by wrapping in a 'setuptools.sic()' call.
* #1424: Prevent keeping files mode for package_data build. It may break a build if user's package data has read only flag.
* #1431: In ``easy_install.check_site_dir``, ensure the installation directory exists.
* #1563: In ``pkg_resources`` prefer ``find_spec`` (PEP 451) to ``find_module``.
Incorporate changes from v44.1.0:
* #1704: Set sys.argv[0] in setup script run by build_meta.__legacy__
* #1959: Fix for Python 4: replace unsafe six.PY3 with six.PY2
* #1994: Fixed a bug in the "setuptools.finalize_distribution_options" hook that lead to ignoring the order attribute of entry points managed by this hook.
v44.1.0
-------
* #1704: Set sys.argv[0] in setup script run by build_meta.__legacy__
* #1959: Fix for Python 4: replace unsafe six.PY3 with six.PY2
* #1994: Fixed a bug in the "setuptools.finalize_distribution_options" hook that lead to ignoring the order attribute of entry points managed by this hook.
v46.0.0
-------
* #65: Once again as in 3.0, removed the Features feature.
* #1890: Fix vendored dependencies so importing ``setuptools.extern.some_module`` gives the same object as ``setuptools._vendor.some_module``. This makes Metadata picklable again.
* #1899: Test suite now fails on warnings.
* #2011: Fix broken link to distutils docs on package_data
* #1991: Include pkg_resources test data in sdist, so tests can be executed from it.
v45.3.0
-------
* #1557: Deprecated eggsecutable scripts and updated docs.
* #1904: Update msvc.py to use CPython 3.8.0 mechanism to find msvc 14+
v45.2.0
-------
* #1905: Fixed defect in _imp, introduced in 41.6.0 when the 'tests' directory is not present.
* #1941: Improve editable installs with PEP 518 build isolation:
* The ``--user`` option is now always available. A warning is issued if the user site directory is not available.
* The error shown when the install directory is not in ``PYTHONPATH`` has been turned into a warning.
* #1981: Setuptools now declares its ``tests`` and ``docs`` dependencies in metadata (extras).
* #1985: Add support for installing scripts in environments where bdist_wininst is missing (i.e. Python 3.9).
* #1968: Add flake8-2020 to check for misuse of sys.version or sys.version_info.
v45.1.0
-------
* #1458: Add minimum sunset date and preamble to Python 2 warning.
* #1704: Set sys.argv[0] in setup script run by build_meta.__legacy__
* #1974: Add Python 3 Only Trove Classifier and remove universal wheel declaration for more complete transition from Python 2.
v45.0.0
-------
* #1458: Drop support for Python 2. Setuptools now requires Python 3.5 or later. Install setuptools using pip >=9 or pin to Setuptools <45 to maintain 2.7 support.
* #1959: Fix for Python 4: replace unsafe six.PY3 with six.PY2
v44.0.0
-------
* #1908: Drop support for Python 3.4.
v43.0.0
-------
* #1634: Include ``pyproject.toml`` in source distribution by default. Projects relying on the previous behavior where ``pyproject.toml`` was excluded by default should stop relying on that behavior or add ``exclude pyproject.toml`` to their MANIFEST.in file.
* #1927: Setuptools once again declares 'setuptools' in the ``build-system.requires`` and adds PEP 517 build support by declaring itself as the ``build-backend``. It additionally specifies ``build-system.backend-path`` to rely on itself for those builders that support it.
v42.0.2
-------
* #1921: Fix support for easy_install's ``find-links`` option in ``setup.cfg``.
* #1922: Build dependencies (setup_requires and tests_require) now install transitive dependencies indicated by extras.
v42.0.1
-------
* #1918: Fix regression in handling wheels compatibility tags.
v42.0.0
-------
* #1830, #1909: Mark the easy_install script and setuptools command as deprecated, and use `pip <https://pip.pypa.io/en/stable/>`_ when available to fetch/build wheels for missing ``setup_requires``/``tests_require`` requirements, with the following differences in behavior:
* support for ``python_requires``
* better support for wheels (proper handling of priority with respect to PEP 425 tags)
* PEP 517/518 support
* eggs are not supported
* no support for the ``allow_hosts`` easy_install option (``index_url``/``find_links`` are still honored)
* pip environment variables are honored (and take precedence over easy_install options)
* #1898: Removed the "upload" and "register" commands in favor of `twine <https://pypi.org/p/twine>`_.
* #1767: Add support for the ``license_files`` option in ``setup.cfg`` to automatically
include multiple license files in a source distribution.
* #1829: Update handling of wheels compatibility tags:
* add support for manylinux2010
* fix use of removed 'm' ABI flag in Python 3.8 on Windows
* #1861: Fix empty namespace package installation from wheel.
* #1877: Setuptools now exposes a new entry point hook "setuptools.finalize_distribution_options", enabling plugins like `setuptools_scm <https://pypi.org/project/setuptools_scm>`_ to configure options on the distribution at finalization time.
v41.6.0
-------
* #479: Replace usage of deprecated ``imp`` module with local re-implementation in ``setuptools._imp``.
v41.5.1
-------
* #1891: Fix code for detecting Visual Studio's version on Windows under Python 2.
v41.5.0
-------
* #1811: Improve Visual C++ 14.X support, mainly for Visual Studio 2017 and 2019.
* #1814: Fix ``pkg_resources.Requirement`` hash/equality implementation: take PEP 508 direct URL into account.
* #1824: Fix tests when running under ``python3.10``.
* #1878: Formally deprecated the ``test`` command, with the recommendation that users migrate to ``tox``.
* #1860: Update documentation to mention the egg format is not supported by pip and dependency links support was dropped starting with pip 19.0.
* #1862: Drop ez_setup documentation: deprecated for some time (last updated in 2016), and still relying on easy_install (deprecated too).
* #1868: Drop most documentation references to (deprecated) EasyInstall.
* #1884: Added a trove classifier to document support for Python 3.8.
* #1886: Added Python 3.8 release to the Travis test matrix.
v41.4.0
-------
* #1847: In declarative config, now traps errors when invalid ``python_requires`` values are supplied.
v41.3.0
-------
* #1690: When storing extras, rely on OrderedSet to retain order of extras as indicated by the packager, which will also be deterministic on Python 2.7 (with PYTHONHASHSEED unset) and Python 3.6+.
* #1858: Fixed failing integration test triggered by 'long_description_content_type' in packaging.
v41.2.0
-------
* #479: Remove some usage of the deprecated ``imp`` module.
* #1565: Changed html_sidebars from string to list of string as per
https://www.sphinx-doc.org/en/master/changes.html#id58
v41.1.0
-------
* #1697: Moved most of the constants from setup.py to setup.cfg
* #1749: Fixed issue with the PEP 517 backend where building a source distribution would fail if any tarball existed in the destination directory.
* #1750: Fixed an issue with PEP 517 backend where wheel builds would fail if the destination directory did not already exist.
* #1756: Force metadata-version >= 1.2. when project urls are present.
* #1769: Improve ``package_data`` check: ensure the dictionary values are lists/tuples of strings.
* #1788: Changed compatibility fallback logic for ``html.unescape`` to avoid accessing ``HTMLParser.unescape`` when not necessary. ``HTMLParser.unescape`` is deprecated and will be removed in Python 3.9.
* #1790: Added the file path to the error message when a ``UnicodeDecodeError`` occurs while reading a metadata file.
* #1776: Use license classifiers rather than the license field.
v41.0.1
-------
......
......@@ -4,6 +4,7 @@ recursive-include setuptools/tests *.html
recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html
recursive-include setuptools/_vendor *.py *.txt
recursive-include pkg_resources *.py *.txt
recursive-include pkg_resources/tests/data *
include *.py
include *.rst
include MANIFEST.in
......
.. image:: https://img.shields.io/pypi/v/setuptools.svg
:target: https://pypi.org/project/setuptools
:target: `PyPI link`_
.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg
:target: https://setuptools.readthedocs.io
.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg
:target: `PyPI link`_
.. _PyPI link: https://pypi.org/project/setuptools
.. image:: https://dev.azure.com/jaraco/setuptools/_apis/build/status/pypa.setuptools?branchName=master
:target: https://dev.azure.com/jaraco/setuptools/_build/latest?definitionId=1&branchName=master
.. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20CI&logo=travis&logoColor=white
:target: https://travis-ci.org/pypa/setuptools
......@@ -10,14 +15,15 @@
.. image:: https://img.shields.io/appveyor/ci/pypa/setuptools/master.svg?label=Windows%20CI&logo=appveyor&logoColor=white
:target: https://ci.appveyor.com/project/pypa/setuptools/branch/master
.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg
:target: https://setuptools.readthedocs.io
.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white
:target: https://codecov.io/gh/pypa/setuptools
.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat
:target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme
.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg
See the `Installation Instructions
<https://packaging.python.org/installing/>`_ in the Python Packaging
User's Guide for instructions on installing, upgrading, and uninstalling
......@@ -34,8 +40,17 @@ To report a security vulnerability, please use the
Tidelift will coordinate the fix and disclosure.
For Enterprise
==============
Available as part of the Tidelift Subscription.
Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
`Learn more <https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=referral&utm_campaign=github>`_.
Code of Conduct
---------------
===============
Everyone interacting in the setuptools project's codebases, issue trackers,
chat rooms, and mailing lists is expected to follow the
......
......@@ -7,10 +7,19 @@ environment:
CODECOV_ENV: APPVEYOR_JOB_NAME
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
APPVEYOR_JOB_NAME: "python35-x64-vs2015"
PYTHON: "C:\\Python35-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
APPVEYOR_JOB_NAME: "python35-x64-vs2017"
PYTHON: "C:\\Python35-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
APPVEYOR_JOB_NAME: "python35-x64-vs2019"
PYTHON: "C:\\Python35-x64"
- APPVEYOR_JOB_NAME: "python36-x64"
PYTHON: "C:\\Python36-x64"
- APPVEYOR_JOB_NAME: "python27-x64"
PYTHON: "C:\\Python27-x64"
- APPVEYOR_JOB_NAME: "python37-x64"
PYTHON: "C:\\Python37-x64"
install:
# symlink python from a directory with a space
......@@ -28,7 +37,6 @@ test_script:
- python -m pip install --disable-pip-version-check --upgrade pip setuptools wheel
- pip install --upgrade tox tox-venv virtualenv
- pip freeze --all
- python bootstrap.py
- tox -- --cov
after_test:
......
# Create the project in Azure with:
# az devops project create --name $name --organization https://dev.azure.com/$org/ --visibility public
# then configure the pipelines (through web UI)
trigger:
branches:
include:
- '*'
tags:
include:
- '*'
pool:
vmImage: $(pool_vm_image)
variables:
- group: Azure secrets
- name: pool_vm_image
value: Ubuntu-18.04
stages:
- stage: Test
jobs:
- job: 'Test'
strategy:
matrix:
Bionic Python 3.6:
python.version: '3.6'
Bionic Python 3.8:
python.version: '3.8'
Windows:
python.version: '3.8'
pool_vm_image: vs2017-win2016
MacOS:
python.version: '3.8'
pool_vm_image: macos-10.15
maxParallel: 4
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
architecture: 'x64'
- script: python -m pip install tox
displayName: 'Install tox'
- script: |
tox -- --junit-xml=test-results.xml
displayName: 'run tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'
testRunTitle: 'Python $(python.version)'
condition: succeededOrFailed()
- stage: Publish
dependsOn: Test
jobs:
- job: 'Publish'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.8'
architecture: 'x64'
- script: python -m pip install tox
displayName: 'Install tox'
- script: |
tox -e release
env:
TWINE_PASSWORD: $(PyPI-token)
TIDELIFT_TOKEN: $(Tidelift-token)
displayName: 'publish to PyPI'
condition: contains(variables['Build.SourceBranch'], 'tags')
......@@ -25,6 +25,7 @@ minimal_egg_info = textwrap.dedent("""
entry_points = setuptools.dist:check_entry_points
[egg_info.writers]
PKG-INFO = setuptools.command.egg_info:write_pkg_info
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
entry_points.txt = setuptools.command.egg_info:write_entries
requires.txt = setuptools.command.egg_info:write_requirements
......@@ -35,10 +36,11 @@ def ensure_egg_info():
if os.path.exists('setuptools.egg-info'):
return
print("adding minimal entry_points")
build_egg_info()
add_minimal_info()
run_egg_info()
def build_egg_info():
def add_minimal_info():
"""
Build a minimal egg-info, enough to invoke egg_info
"""
......@@ -52,13 +54,6 @@ def run_egg_info():
cmd = [sys.executable, 'setup.py', 'egg_info']
print("Regenerating egg_info")
subprocess.check_call(cmd)
print("...and again.")
subprocess.check_call(cmd)
def main():
ensure_egg_info()
run_egg_info()
__name__ == '__main__' and main()
__name__ == '__main__' and ensure_egg_info()
Moved most of the constants from setup.py to setup.cfg
Document all supported keywords by migrating the ones from distutils.
Fixed issue with the PEP 517 backend where building a source distribution would fail if any tarball existed in the destination directory.
Fixed an issue with PEP 517 backend where wheel builds would fail if the destination directory did not already exist.
Forse metadata-version >= 1.2. when project urls are present.
Use license classifiers rather than the license field.
Changed compatibility fallback logic for ``html.unescape`` to avoid accessing ``HTMLParser.unescape`` when not necessary. ``HTMLParser.unescape`` is deprecated and will be removed in Python 3.9.
Added the file path to the error message when a ``UnicodeDecodeError`` occurs
while reading a metadata file.
......@@ -19,6 +19,7 @@ collect_ignore = [
if sys.version_info < (3,):
collect_ignore.append('setuptools/lib2to3_ex.py')
collect_ignore.append('setuptools/_imp.py')
if sys.version_info < (3, 6):
......
<h3 class="donation">For Enterprise</h3>
<p>
Professionally-supported {{ project }} is available with the
<a href="https://tidelift.com/subscription/pkg/pypi-{{ project }}?utm_source=pypi-{{ project }}&utm_medium=referral">Tidelift Subscription</a>.
</p>
<h3>Download</h3>
<p>Current version: <b>{{ version }}</b></p>
......@@ -6,10 +13,3 @@
<h3>Questions? Suggestions? Contributions?</h3>
<p>Visit the <a href="{{ package_url }}">Project page</a> </p>
<h3 class="donation">Professional support</h3>
<p>
Professionally-supported {{ project }} is available with the
<a href="https://tidelift.com/subscription/pkg/pypi-{{ project }}?utm_source=pypi-{{ project }}&utm_medium=readme">Tidelift Subscription</a>.
</p>
=======================================
Build System Support
=======================================
What is it?
-------------
Python packaging has come `a long way <https://www.bernat.tech/pep-517-518/>`_.
The traditional ``setuptools`` way of packgaging 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
overhaul. Because ``setup.py`` scripts allowed for arbitrary execution, it
proved difficult to provide a reliable user experience across environments
and history.
`PEP 517 <https://www.python.org/dev/peps/pep-0517/>`_ therefore came 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.
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'
(the default is ``setuptools``)
With this standard, switching between packaging tools becomes a lot easier. ``build_meta``
implements ``setuptools``' build system support.
How to use it?
--------------
Starting with a package that you want to distribute. You will need your source
scripts, a ``pyproject.toml`` file and a ``setup.cfg`` file::
~/meowpkg/
pyproject.toml
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
setuptools, the content would be::
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
Use ``setuptools``' `declarative config`_ to specify the package information::
[metadata]
name = meowpkg
version = 0.0.1
description = a package that meows
[options]
packages = find:
Now generate the distribution. Although the PyPA is still working to
`provide a recommended tool <https://github.com/pypa/packaging-problems/issues/219>`_
to build packages, the `pep517 package <https://pypi.org/project/pep517`_
provides this functionality. To build the package::
$ pip install -q pep517
$ mkdir dist
$ python -m pep517.build .
And now it's done! The ``.whl`` file and ``.tar.gz`` can then be distributed
and installed::
dist/
meowpkg-0.0.1.whl
meowpkg-0.0.1.tar.gz
$ pip install dist/meowpkg-0.0.1.whl
or::
$ pip install dist/meowpkg-0.0.1.tar.gz
# -*- coding: utf-8 -*-
#
# Setuptools documentation build configuration file, created by
# sphinx-quickstart on Fri Jul 17 14:22:37 2009.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
import subprocess
import sys
import os
......@@ -26,14 +6,12 @@ import os
# hack to run the bootstrap script so that jaraco.packaging.sphinx
# can invoke setup.py
'READTHEDOCS' in os.environ and subprocess.check_call(
[sys.executable, 'bootstrap.py'],
[sys.executable, '-m', 'bootstrap'],
cwd=os.path.join(os.path.dirname(__file__), os.path.pardir),
)
# -- General configuration -----------------------------------------------------
# -- General configuration --
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['jaraco.packaging.sphinx', 'rst.linker']
# Add any paths that contain templates here, relative to this directory.
......@@ -45,7 +23,8 @@ source_suffix = '.txt'
# The master toctree document.
master_doc = 'index'
# A list of glob-style patterns that should be excluded when looking for source files.
# A list of glob-style patterns that should be excluded
# when looking for source files.
exclude_patterns = ['requirements.txt']
# List of directories, relative to source directory, that shouldn't be searched
......@@ -55,7 +34,7 @@ exclude_trees = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output ---------------------------------------------------
# -- Options for HTML output --
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
......@@ -69,7 +48,10 @@ html_theme_path = ['_theme']
html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {'index': 'indexsidebar.html'}
html_sidebars = {
'index': [
'relations.html', 'sourcelink.html', 'indexsidebar.html',
'searchbox.html']}
# If false, no module index is generated.
html_use_modindex = False
......@@ -77,14 +59,15 @@ html_use_modindex = False
# If false, no index is generated.
html_use_index = False
# -- Options for LaTeX output --------------------------------------------------
# -- Options for LaTeX output --
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Setuptools.tex', 'Setuptools Documentation',
'The fellowship of the packaging', 'manual'),
]
# (source start file, target name, title, author,
# documentclass [howto/manual]).
latex_documents = [(
'index', 'Setuptools.tex', 'Setuptools Documentation',
'The fellowship of the packaging', 'manual',
)]
link_files = {
'../CHANGES.rst': dict(
......
......@@ -104,12 +104,8 @@ from the command line after pushing a new branch.
Testing
-------
The primary tests are run using tox. To run the tests, first create the metadata
needed to run the tests::
$ python bootstrap.py
Then make sure you have tox installed, and invoke it::
The primary tests are run using tox. Make sure you have tox installed,
and invoke it::
$ tox
......@@ -143,7 +139,7 @@ Vendored Dependencies
---------------------
Setuptools has some dependencies, but due to `bootstrapping issues
<https://github.com/pypa/setuptools/issues/980>`, those dependencies
<https://github.com/pypa/setuptools/issues/980>`_, those dependencies
cannot be declared as they won't be resolved soon enough to build
setuptools from source. Eventually, this limitation may be lifted as
PEP 517/518 reach ubiquitous adoption, but for now, Setuptools
......
......@@ -7,7 +7,7 @@ Authority (PyPA) and led by Jason R. Coombs.
This document describes the process by which Setuptools is developed.
This document assumes the reader has some passing familiarity with
*using* setuptools, the ``pkg_resources`` module, and EasyInstall. It
*using* setuptools, the ``pkg_resources`` module, and pip. It
does not attempt to explain basic concepts like inter-project
dependencies, nor does it contain detailed lexical syntax for most
file formats. Neither does it explain concepts like "namespace
......
......@@ -41,7 +41,7 @@ Please see the `setuptools PyPI page <https://pypi.org/project/setuptools/>`_
for download links and basic installation instructions for each of the
supported platforms.
You will need at least Python 3.4 or 2.7. An ``easy_install`` script will be
You will need at least Python 3.5 or 2.7. An ``easy_install`` script will be
installed in the normal location for Python scripts on your platform.
Note that the instructions on the setuptools PyPI page assume that you are
......@@ -317,8 +317,8 @@ Note that instead of changing your ``PATH`` to include the Python scripts
directory, you can also retarget the installation location for scripts so they
go on a directory that's already on the ``PATH``. For more information see
`Command-Line Options`_ and `Configuration Files`_. During installation,
pass command line options (such as ``--script-dir``) to
``ez_setup.py`` to control where ``easy_install.exe`` will be installed.
pass command line options (such as ``--script-dir``) to control where
scripts will be installed.
Windows Executable Launcher
......
:orphan:
``ez_setup`` distribution guide
===============================
Using ``setuptools``... Without bundling it!
---------------------------------------------
.. warning:: **ez_setup** is deprecated in favor of PIP with **PEP-518** support.
.. _ez_setup.py: https://bootstrap.pypa.io/ez_setup.py
.. _EasyInstall Installation Instructions: easy_install.html
.. _Custom Installation Locations: easy_install.html
Your users might not have ``setuptools`` installed on their machines, or even
if they do, it might not be the right version. Fixing this is easy; just
download `ez_setup.py`_, and put it in the same directory as your ``setup.py``
script. (Be sure to add it to your revision control system, too.) Then add
these two lines to the very top of your setup script, before the script imports
anything from setuptools:
.. code-block:: python
import ez_setup
ez_setup.use_setuptools()
That's it. The ``ez_setup`` module will automatically download a matching
version of ``setuptools`` from PyPI, if it isn't present on the target system.
Whenever you install an updated version of setuptools, you should also update
your projects' ``ez_setup.py`` files, so that a matching version gets installed
on the target machine(s).
(By the way, if you need to distribute a specific version of ``setuptools``,
you can specify the exact version and base download URL as parameters to the
``use_setuptools()`` function. See the function's docstring for details.)
What Your Users Should Know
---------------------------
In general, a setuptools-based project looks just like any distutils-based
project -- as long as your users have an internet connection and are installing
to ``site-packages``, that is. But for some users, these conditions don't
apply, and they may become frustrated if this is their first encounter with
a setuptools-based project. To keep these users happy, you should review the
following topics in your project's installation instructions, if they are
relevant to your project and your target audience isn't already familiar with
setuptools and ``easy_install``.
Network Access
If your project is using ``ez_setup``, you should inform users of the
need to either have network access, or to preinstall the correct version of
setuptools using the `EasyInstall installation instructions`_. Those
instructions also have tips for dealing with firewalls as well as how to
manually download and install setuptools.
Custom Installation Locations
You should inform your users that if they are installing your project to
somewhere other than the main ``site-packages`` directory, they should
first install setuptools using the instructions for `Custom Installation
Locations`_, before installing your project.
Your Project's Dependencies
If your project depends on other projects that may need to be downloaded
from PyPI or elsewhere, you should list them in your installation
instructions, or tell users how to find out what they are. While most
users will not need this information, any users who don't have unrestricted
internet access may have to find, download, and install the other projects
manually. (Note, however, that they must still install those projects
using ``easy_install``, or your project will not know they are installed,
and your setup script will try to download them again.)
If you want to be especially friendly to users with limited network access,
you may wish to build eggs for your project and its dependencies, making
them all available for download from your site, or at least create a page
with links to all of the needed eggs. In this way, users with limited
network access can manually download all the eggs to a single directory,
then use the ``-f`` option of ``easy_install`` to specify the directory
to find eggs in. Users who have full network access can just use ``-f``
with the URL of your download page, and ``easy_install`` will find all the
needed eggs using your links directly. This is also useful when your
target audience isn't able to compile packages (e.g. most Windows users)
and your package or some of its dependencies include C code.
Revision Control System Users and Co-Developers
Users and co-developers who are tracking your in-development code using
a revision control system should probably read this manual's sections
regarding such development. Alternately, you may wish to create a
quick-reference guide containing the tips from this manual that apply to
your particular situation. For example, if you recommend that people use
``setup.py develop`` when tracking your in-development code, you should let
them know that this needs to be run after every update or commit.
Similarly, if you remove modules or data files from your project, you
should remind them to run ``setup.py clean --all`` and delete any obsolete
``.pyc`` or ``.pyo``. (This tip applies to the distutils in general, not
just setuptools, but not everybody knows about them; be kind to your users
by spelling out your project's best practices rather than leaving them
guessing.)
Creating System Packages
Some users want to manage all Python packages using a single package
manager, and sometimes that package manager isn't ``easy_install``!
Setuptools currently supports ``bdist_rpm``, ``bdist_wininst``, and
``bdist_dumb`` formats for system packaging. If a user has a locally-
installed "bdist" packaging tool that internally uses the distutils
``install`` command, it should be able to work with ``setuptools``. Some
examples of "bdist" formats that this should work with include the
``bdist_nsi`` and ``bdist_msi`` formats for Windows.
However, packaging tools that build binary distributions by running
``setup.py install`` on the command line or as a subprocess will require
modification to work with setuptools. They should use the
``--single-version-externally-managed`` option to the ``install`` command,
combined with the standard ``--root`` or ``--record`` options.
See the `install command`_ documentation below for more details. The
``bdist_deb`` command is an example of a command that currently requires
this kind of patching to work with setuptools.
Please note that building system packages may require you to install
some system software, for example ``bdist_rpm`` requires the ``rpmbuild``
command to be installed.
If you or your users have a problem building a usable system package for
your project, please report the problem via the mailing list so that
either the "bdist" tool in question or setuptools can be modified to
resolve the issue.
Your users might not have ``setuptools`` installed on their machines, or even
if they do, it might not be the right version. Fixing this is easy; just
download `ez_setup.py`_, and put it in the same directory as your ``setup.py``
script. (Be sure to add it to your revision control system, too.) Then add
these two lines to the very top of your setup script, before the script imports
anything from setuptools:
.. code-block:: python
import ez_setup
ez_setup.use_setuptools()
That's it. The ``ez_setup`` module will automatically download a matching
version of ``setuptools`` from PyPI, if it isn't present on the target system.
Whenever you install an updated version of setuptools, you should also update
your projects' ``ez_setup.py`` files, so that a matching version gets installed
on the target machine(s).
(By the way, if you need to distribute a specific version of ``setuptools``,
you can specify the exact version and base download URL as parameters to the
``use_setuptools()`` function. See the function's docstring for details.)
.. _install command:
``install`` - Run ``easy_install`` or old-style installation
============================================================
The setuptools ``install`` command is basically a shortcut to run the
``easy_install`` command on the current project. However, for convenience
in creating "system packages" of setuptools-based projects, you can also
use this option:
``--single-version-externally-managed``
This boolean option tells the ``install`` command to perform an "old style"
installation, with the addition of an ``.egg-info`` directory so that the
installed project will still have its metadata available and operate
normally. If you use this option, you *must* also specify the ``--root``
or ``--record`` options (or both), because otherwise you will have no way
to identify and remove the installed files.
This option is automatically in effect when ``install`` is invoked by another
distutils command, so that commands like ``bdist_wininst`` and ``bdist_rpm``
will create system packages of eggs. It is also automatically in effect if
you specify the ``--root`` option.
``install_egg_info`` - Install an ``.egg-info`` directory in ``site-packages``
==============================================================================
Setuptools runs this command as part of ``install`` operations that use the
``--single-version-externally-managed`` options. You should not invoke it
directly; it is documented here for completeness and so that distutils
extensions such as system package builders can make use of it. This command
has only one option:
``--install-dir=DIR, -d DIR``
The parent directory where the ``.egg-info`` directory will be placed.
Defaults to the same as the ``--install-dir`` option specified for the
``install_lib`` command, which is usually the system ``site-packages``
directory.
This command assumes that the ``egg_info`` command has been given valid options
via the command line or ``setup.cfg``, as it will invoke the ``egg_info``
command and use its options to locate the project's source ``.egg-info``
directory.
......@@ -299,11 +299,8 @@ specified by the ``setup_requires`` parameter to the Distribution.
A list of dependency URLs, one per line, as specified using the
``dependency_links`` keyword to ``setup()``. These may be direct
download URLs, or the URLs of web pages containing direct download
links, and will be used by EasyInstall to find dependencies, as though
the user had manually provided them via the ``--find-links`` command
line option. Please see the setuptools manual and EasyInstall manual
for more information on specifying this option, and for information on
how EasyInstall processes ``--find-links`` URLs.
links. Please see the setuptools manual for more information on
specifying this option.
``depends.txt`` -- Obsolete, do not create!
......
......@@ -12,7 +12,7 @@ Credits
* The original design for the ``.egg`` format and the ``pkg_resources`` API was
co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first
version of ``pkg_resources``, and supplied the OS X operating system version
version of ``pkg_resources``, and supplied the macOS operating system version
compatibility algorithm.
* Ian Bicking implemented many early "creature comfort" features of
......
This diff is collapsed.
......@@ -245,8 +245,8 @@ abbreviation for ``pkg_resources.working_set.require()``:
interactive interpreter hacking than for production use. If you're creating
an actual library or application, it's strongly recommended that you create
a "setup.py" script using ``setuptools``, and declare all your requirements
there. That way, tools like EasyInstall can automatically detect what
requirements your package has, and deal with them accordingly.
there. That way, tools like pip can automatically detect what requirements
your package has, and deal with them accordingly.
Note that calling ``require('SomePackage')`` will not install
``SomePackage`` if it isn't already present. If you need to do this, you
......@@ -611,9 +611,9 @@ Requirements Parsing
or activation of both Report-O-Rama and any libraries it needs in order to
provide PDF support. For example, you could use::
easy_install.py Report-O-Rama[PDF]
pip install Report-O-Rama[PDF]
To install the necessary packages using the EasyInstall program, or call
To install the necessary packages using pip, or call
``pkg_resources.require('Report-O-Rama[PDF]')`` to add the necessary
distributions to sys.path at runtime.
......@@ -1621,7 +1621,7 @@ Platform Utilities
``get_build_platform()``
Return this platform's identifier string. For Windows, the return value
is ``"win32"``, and for Mac OS X it is a string of the form
is ``"win32"``, and for macOS it is a string of the form
``"macosx-10.4-ppc"``. All other platforms return the same uname-based
string that the ``distutils.util.get_platform()`` function returns.
This string is the minimum platform version required by distributions built
......@@ -1641,7 +1641,7 @@ Platform Utilities
considered a wildcard, and the platforms are therefore compatible.
Likewise, if the platform strings are equal, they're also considered
compatible, and ``True`` is returned. Currently, the only non-equal
platform strings that are considered compatible are Mac OS X platform
platform strings that are considered compatible are macOS platform
strings with the same hardware type (e.g. ``ppc``) and major version
(e.g. ``10``) with the `provided` platform's minor version being less than
or equal to the `required` platform's minor version.
......@@ -1674,7 +1674,7 @@ File/Path Utilities
the same filesystem location if they have equal ``normalized_path()``
values. Specifically, this is a shortcut for calling ``os.path.realpath``
and ``os.path.normcase`` on `path`. Unfortunately, on certain platforms
(notably Cygwin and Mac OS X) the ``normcase`` function does not accurately
(notably Cygwin and macOS) the ``normcase`` function does not accurately
reflect the platform's case-sensitivity, so there is always the possibility
of two apparently-different paths being equal on such platforms.
......@@ -1843,9 +1843,9 @@ History
because it isn't necessarily a filesystem path (and hasn't been for some
time now). The ``location`` of ``Distribution`` objects in the filesystem
should always be normalized using ``pkg_resources.normalize_path()``; all
of the setuptools and EasyInstall code that generates distributions from
the filesystem (including ``Distribution.from_filename()``) ensure this
invariant, but if you use a more generic API like ``Distribution()`` or
of the setuptools' code that generates distributions from the filesystem
(including ``Distribution.from_filename()``) ensure this invariant, but if
you use a more generic API like ``Distribution()`` or
``Distribution.from_location()`` you should take care that you don't
create a distribution with an un-normalized filesystem path.
......
......@@ -3,39 +3,13 @@ Release Process
===============
In order to allow for rapid, predictable releases, Setuptools uses a
mechanical technique for releases, enacted by Travis following a
successful build of a tagged release per
`PyPI deployment <https://docs.travis-ci.com/user/deployment/pypi>`_.
Prior to cutting a release, please use `towncrier`_ to update
``CHANGES.rst`` to summarize the changes since the last release.
To update the changelog:
1. Install towncrier via ``pip install towncrier`` if not already installed.
2. Preview the new ``CHANGES.rst`` entry by running
``towncrier --draft --version {new.version.number}`` (enter the desired
version number for the next release). If any changes are needed, make
them and generate a new preview until the output is acceptable. Run
``git add`` for any modified files.
3. Run ``towncrier --version {new.version.number}`` to stage the changelog
updates in git.
4. Verify that there are no remaining ``changelog.d/*.rst`` files. If a
file was named incorrectly, it may be ignored by towncrier.
5. Review the updated ``CHANGES.rst`` file. If any changes are needed,
make the edits and stage them via ``git add CHANGES.rst``.
Once the changelog edits are staged and ready to commit, cut a release by
installing and running ``bump2version --allow-dirty {part}`` where ``part``
is major, minor, or patch based on the scope of the changes in the
release. Then, push the commits to the master branch::
$ git push origin master
$ git push --tags
If tests pass, the release will be uploaded to PyPI (from the Python 3.6
tests).
.. _towncrier: https://pypi.org/project/towncrier/
mechanical technique for releases, enacted on tagged commits by
continuous integration.
To finalize a release, run ``tox -e finalize``, review, then push
the changes.
If tests pass, the release will be uploaded to PyPI.
Release Frequency
-----------------
......
sphinx!=1.8.0
rst.linker>=1.9
# keep these in sync with setup.cfg
sphinx
jaraco.packaging>=6.1
rst.linker>=1.9
pygments-github-lexers==0.0.5
setuptools>=34
This diff is collapsed.
......@@ -37,6 +37,7 @@
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
#include <process.h>
int child_pid=0;
......
# Configuration for pull request documentation previews via Netlify
# Netlify relies on there being a ./runtime.txt to indicate Python 3.
[build]
publish = "docs/build/html"
publish = "build/html"
command = "pip install tox && tox -e docs"
......@@ -55,7 +55,7 @@ except NameError:
FileExistsError = OSError
from pkg_resources.extern import six
from pkg_resources.extern.six.moves import urllib, map, filter
from pkg_resources.extern.six.moves import map, filter
# capture these to bypass sandboxing
from os import utime
......@@ -83,13 +83,14 @@ __import__('pkg_resources.extern.packaging.version')
__import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
__import__('pkg_resources.py2_warn')
__metaclass__ = type
if (3, 0) < sys.version_info < (3, 4):
raise RuntimeError("Python 3.4 or later is required")
if (3, 0) < sys.version_info < (3, 5):
raise RuntimeError("Python 3.5 or later is required")
if six.PY2:
# Those builtin exceptions are only defined in Python 3
......@@ -178,10 +179,10 @@ def get_supported_platform():
"""Return this platform's maximum compatible version.
distutils.util.get_platform() normally reports the minimum version
of Mac OS X that would be required to *use* extensions produced by
of macOS that would be required to *use* extensions produced by
distutils. But what we want when checking compatibility is to know the
version of Mac OS X that we are *running*. To allow usage of packages that
explicitly require a newer version of Mac OS X, we must also know the
version of macOS that we are *running*. To allow usage of packages that
explicitly require a newer version of macOS, we must also know the
current version of the OS.
If this condition occurs for any other platform with a version in its
......@@ -191,9 +192,9 @@ def get_supported_platform():
m = macosVersionString.match(plat)
if m is not None and sys.platform == "darwin":
try:
plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
except ValueError:
# not Mac OS X
# not macOS
pass
return plat
......@@ -333,7 +334,7 @@ class UnknownExtra(ResolutionError):
_provider_factories = {}
PY_MAJOR = sys.version[:3]
PY_MAJOR = '{}.{}'.format(*sys.version_info)
EGG_DIST = 3
BINARY_DIST = 2
SOURCE_DIST = 1
......@@ -364,7 +365,7 @@ def get_provider(moduleOrReq):
return _find_adapter(_provider_factories, loader)(module)
def _macosx_vers(_cache=[]):
def _macos_vers(_cache=[]):
if not _cache:
version = platform.mac_ver()[0]
# fallback for MacPorts
......@@ -380,7 +381,7 @@ def _macosx_vers(_cache=[]):
return _cache[0]
def _macosx_arch(machine):
def _macos_arch(machine):
return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
......@@ -388,18 +389,18 @@ def get_build_platform():
"""Return this platform's string for platform-specific distributions
XXX Currently this is the same as ``distutils.util.get_platform()``, but it
needs some hacks for Linux and Mac OS X.
needs some hacks for Linux and macOS.
"""
from sysconfig import get_platform
plat = get_platform()
if sys.platform == "darwin" and not plat.startswith('macosx-'):
try:
version = _macosx_vers()
version = _macos_vers()
machine = os.uname()[4].replace(" ", "_")
return "macosx-%d.%d-%s" % (
int(version[0]), int(version[1]),
_macosx_arch(machine),
_macos_arch(machine),
)
except ValueError:
# if someone is running a non-Mac darwin system, this will fall
......@@ -425,7 +426,7 @@ def compatible_platforms(provided, required):
# easy case
return True
# Mac OS X special cases
# macOS special cases
reqMac = macosVersionString.match(required)
if reqMac:
provMac = macosVersionString.match(provided)
......@@ -434,7 +435,7 @@ def compatible_platforms(provided, required):
if not provMac:
# this is backwards compatibility for packages built before
# setuptools 0.6. All packages built after this point will
# use the new macosx designation.
# use the new macOS designation.
provDarwin = darwinVersionString.match(provided)
if provDarwin:
dversion = int(provDarwin.group(1))
......@@ -442,7 +443,7 @@ def compatible_platforms(provided, required):
if dversion == 7 and macosversion >= "10.3" or \
dversion == 8 and macosversion >= "10.4":
return True
# egg isn't macosx or legacy darwin
# egg isn't macOS or legacy darwin
return False
# are they the same major version and machine type?
......@@ -1234,12 +1235,13 @@ class ResourceManager:
mode = os.stat(path).st_mode
if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
msg = (
"%s is writable by group/others and vulnerable to attack "
"when "
"used with get_resource_filename. Consider a more secure "
"Extraction path is writable by group/others "
"and vulnerable to attack when "
"used with get_resource_filename ({path}). "
"Consider a more secure "
"location (set with .set_extraction_path or the "
"PYTHON_EGG_CACHE environment variable)." % path
)
"PYTHON_EGG_CACHE environment variable)."
).format(**locals())
warnings.warn(msg, UserWarning)
def postprocess(self, tempname, filename):
......@@ -2067,11 +2069,14 @@ def find_on_path(importer, path_item, only=False):
def dist_factory(path_item, entry, only):
"""
Return a dist_factory for a path_item and entry
"""
"""Return a dist_factory for the given entry."""
lower = entry.lower()
is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info')))
is_egg_info = lower.endswith('.egg-info')
is_dist_info = (
lower.endswith('.dist-info') and
os.path.isdir(os.path.join(path_item, entry))
)
is_meta = is_egg_info or is_dist_info
return (
distributions_from_metadata
if is_meta else
......@@ -2195,10 +2200,14 @@ def _handle_ns(packageName, path_item):
if importer is None:
return None
# capture warnings due to #1111
with warnings.catch_warnings():
warnings.simplefilter("ignore")
loader = importer.find_module(packageName)
# use find_spec (PEP 451) and fall-back to find_module (PEP 302)
try:
loader = importer.find_spec(packageName).loader
except AttributeError:
# capture warnings due to #1111
with warnings.catch_warnings():
warnings.simplefilter("ignore")
loader = importer.find_module(packageName)
if loader is None:
return None
......@@ -2328,7 +2337,8 @@ register_namespace_handler(object, null_ns_handler)
def normalize_path(filename):
"""Normalize a file/dir name for comparison purposes"""
return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename))))
return os.path.normcase(os.path.realpath(os.path.normpath(
_cygwin_patch(filename))))
def _cygwin_patch(filename): # pragma: nocover
......@@ -2536,15 +2546,6 @@ class EntryPoint:
return maps
def _remove_md5_fragment(location):
if not location:
return ''
parsed = urllib.parse.urlparse(location)
if parsed[-1].startswith('md5='):
return urllib.parse.urlunparse(parsed[:-1] + ('',))
return location
def _version_from_file(lines):
"""
Given an iterable of lines from a Metadata file, return
......@@ -2601,7 +2602,7 @@ class Distribution:
self.parsed_version,
self.precedence,
self.key,
_remove_md5_fragment(self.location),
self.location,
self.py_version or '',
self.platform or '',
)
......@@ -3109,6 +3110,7 @@ class Requirement(packaging.requirements.Requirement):
self.extras = tuple(map(safe_extra, self.extras))
self.hashCmp = (
self.key,
self.url,
self.specifier,
frozenset(self.extras),
str(self.marker) if self.marker else None,
......@@ -3286,6 +3288,7 @@ def _initialize_master_working_set():
list(map(working_set.add_entry, sys.path))
globals().update(locals())
class PkgResourcesDeprecationWarning(Warning):
"""
Base class for warning about deprecations in ``pkg_resources``
......
......@@ -36,7 +36,7 @@ Distributions have various introspectable attributes::
>>> dist.version
'0.9'
>>> dist.py_version == sys.version[:3]
>>> dist.py_version == '{}.{}'.format(*sys.version_info)
True
>>> print(dist.platform)
......@@ -290,8 +290,8 @@ Platform Compatibility Rules
----------------------------
On the Mac, there are potential compatibility issues for modules compiled
on newer versions of Mac OS X than what the user is running. Additionally,
Mac OS X will soon have two platforms to contend with: Intel and PowerPC.
on newer versions of macOS than what the user is running. Additionally,
macOS will soon have two platforms to contend with: Intel and PowerPC.
Basic equality works as on other platforms::
......
......@@ -43,13 +43,6 @@ class VendorImporter:
__import__(extant)
mod = sys.modules[extant]
sys.modules[fullname] = mod
# mysterious hack:
# Remove the reference to the extant package/module
# on later Python versions to cause relative imports
# in the vendor package to resolve the same modules
# as those going through this importer.
if prefix and sys.version_info > (3, 3):
del sys.modules[extant]
return mod
except ImportError:
pass
......
import sys
import warnings
import textwrap
msg = textwrap.dedent("""
You are running Setuptools on Python 2, which is no longer
supported and
>>> SETUPTOOLS WILL STOP WORKING <<<
in a subsequent release (no sooner than 2020-04-20).
Please ensure you are installing
Setuptools using pip 9.x or later or pin to `setuptools<45`
in your environment.
If you have done those things and are still encountering
this message, please follow up at
https://bit.ly/setuptools-py2-warning.
""")
pre = "Setuptools will stop working on Python 2\n"
sys.version_info < (3,) and warnings.warn(pre + "*" * 60 + msg + "*" * 60)
import setuptools
setuptools.setup(
name="my-test-package",
version="1.0",
zip_safe=True,
)
Metadata-Version: 1.0
Name: my-test-package
Version: 1.0
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN
setup.cfg
setup.py
my_test_package.egg-info/PKG-INFO
my_test_package.egg-info/SOURCES.txt
my_test_package.egg-info/dependency_links.txt
my_test_package.egg-info/top_level.txt
my_test_package.egg-info/zip-safe
\ No newline at end of file
import subprocess
import sys
import py
import pytest
import pkg_resources
SETUP_TEMPLATE = """
import setuptools
setuptools.setup(
name="my-test-package",
version="1.0",
zip_safe=True,
)
""".lstrip()
TESTS_DATA_DIR = py.path.local(__file__).dirpath('data')
class TestFindDistributions:
......@@ -21,46 +13,22 @@ class TestFindDistributions:
target_dir = tmpdir.mkdir('target')
# place a .egg named directory in the target that is not an egg:
target_dir.mkdir('not.an.egg')
return str(target_dir)
@pytest.fixture
def project_dir(self, tmpdir):
project_dir = tmpdir.mkdir('my-test-package')
(project_dir / "setup.py").write(SETUP_TEMPLATE)
return str(project_dir)
return target_dir
def test_non_egg_dir_named_egg(self, target_dir):
dists = pkg_resources.find_distributions(target_dir)
dists = pkg_resources.find_distributions(str(target_dir))
assert not list(dists)
def test_standalone_egg_directory(self, project_dir, target_dir):
# install this distro as an unpacked egg:
args = [
sys.executable,
'-c', 'from setuptools.command.easy_install import main; main()',
'-mNx',
'-d', target_dir,
'--always-unzip',
project_dir,
]
subprocess.check_call(args)
dists = pkg_resources.find_distributions(target_dir)
def test_standalone_egg_directory(self, target_dir):
(TESTS_DATA_DIR / 'my-test-package_unpacked-egg').copy(target_dir)
dists = pkg_resources.find_distributions(str(target_dir))
assert [dist.project_name for dist in dists] == ['my-test-package']
dists = pkg_resources.find_distributions(target_dir, only=True)
dists = pkg_resources.find_distributions(str(target_dir), only=True)
assert not list(dists)
def test_zipped_egg(self, project_dir, target_dir):
# install this distro as an unpacked egg:
args = [
sys.executable,
'-c', 'from setuptools.command.easy_install import main; main()',
'-mNx',
'-d', target_dir,
'--zip-ok',
project_dir,
]
subprocess.check_call(args)
dists = pkg_resources.find_distributions(target_dir)
def test_zipped_egg(self, target_dir):
(TESTS_DATA_DIR / 'my-test-package_zipped-egg').copy(target_dir)
dists = pkg_resources.find_distributions(str(target_dir))
assert [dist.project_name for dist in dists] == ['my-test-package']
dists = pkg_resources.find_distributions(target_dir, only=True)
dists = pkg_resources.find_distributions(str(target_dir), only=True)
assert not list(dists)
......@@ -17,7 +17,9 @@ try:
except ImportError:
import mock
from pkg_resources import DistInfoDistribution, Distribution, EggInfoDistribution
from pkg_resources import (
DistInfoDistribution, Distribution, EggInfoDistribution,
)
from setuptools.extern import six
from pkg_resources.extern.six.moves import map
from pkg_resources.extern.six import text_type, string_types
......@@ -279,8 +281,8 @@ def make_distribution_no_version(tmpdir, basename):
('dist-info', 'METADATA', DistInfoDistribution),
],
)
def test_distribution_version_missing(tmpdir, suffix, expected_filename,
expected_dist_type):
def test_distribution_version_missing(
tmpdir, suffix, expected_filename, expected_dist_type):
"""
Test Distribution.version when the "Version" header is missing.
"""
......@@ -328,6 +330,14 @@ def test_distribution_version_missing_undetected_path():
assert msg == expected
@pytest.mark.parametrize('only', [False, True])
def test_dist_info_is_not_dir(tmp_path, only):
"""Test path containing a file with dist-info extension."""
dist_info = tmp_path / 'foobar.dist-info'
dist_info.touch()
assert not pkg_resources.dist_factory(str(tmp_path), str(dist_info), only)
class TestDeepVersionLookupDistutils:
@pytest.fixture
def env(self, tmpdir):
......
......@@ -15,7 +15,7 @@ import pkg_resources
from pkg_resources import (
parse_requirements, VersionConflict, parse_version,
Distribution, EntryPoint, Requirement, safe_version, safe_name,
WorkingSet, PkgResourcesDeprecationWarning)
WorkingSet)
# from Python 3.6 docs.
......@@ -116,7 +116,7 @@ class TestDistro:
self.checkFooPkg(d)
d = Distribution("/some/path")
assert d.py_version == sys.version[:3]
assert d.py_version == '{}.{}'.format(*sys.version_info)
assert d.platform is None
def testDistroParse(self):
......@@ -501,7 +501,6 @@ class TestEntryPoints:
ep.load(require=False)
class TestRequirements:
def testBasics(self):
r = Requirement.parse("Twisted>=1.2")
......@@ -520,6 +519,11 @@ class TestRequirements:
assert r1 == r2
assert str(r1) == str(r2)
assert str(r2) == "Twisted==1.2c1,>=1.2"
assert (
Requirement("Twisted")
!=
Requirement("Twisted @ https://localhost/twisted.zip")
)
def testBasicContains(self):
r = Requirement("Twisted>=1.2")
......@@ -546,11 +550,23 @@ class TestRequirements:
==
hash((
"twisted",
None,
packaging.specifiers.SpecifierSet(">=1.2"),
frozenset(["foo", "bar"]),
None
))
)
assert (
hash(Requirement.parse("Twisted @ https://localhost/twisted.zip"))
==
hash((
"twisted",
"https://localhost/twisted.zip",
packaging.specifiers.SpecifierSet(),
frozenset(),
None
))
)
def testVersionEquality(self):
r1 = Requirement.parse("foo==0.3a2")
......
......@@ -14,8 +14,8 @@ __metaclass__ = type
def strip_comments(s):
return '\n'.join(
l for l in s.split('\n')
if l.strip() and not l.strip().startswith('#')
line for line in s.split('\n')
if line.strip() and not line.strip().startswith('#')
)
......
[build-system]
requires = ["wheel"]
requires = [
# avoid self install on Python 2; ref #1996
"setuptools >= 40.8; python_version > '3'",
"wheel",
]
build-backend = "setuptools.build_meta"
backend-path = ["."]
[tool.towncrier]
package = "setuptools"
......
[pytest]
addopts=--doctest-modules --doctest-glob=pkg_resources/api_tests.txt -r sxX
norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern .*
flake8-ignore =
setuptools/site-patch.py F821
setuptools/py*compat.py F811
addopts=--doctest-modules --flake8 --doctest-glob=pkg_resources/api_tests.txt -r sxX
norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern pkg_resources/tests/data tools .* setuptools/_vendor pkg_resources/_vendor
doctest_optionflags=ELLIPSIS ALLOW_UNICODE
filterwarnings =
# Fail on warnings
error
# https://github.com/pypa/setuptools/issues/1823
ignore:bdist_wininst command is deprecated
# Suppress this error; unimportant for CI tests
ignore:Extraction path is writable by group/others:UserWarning
# Suppress Python 2 deprecation warning
ignore:Setuptools will stop working on Python 2:UserWarning
# Suppress weird RuntimeWarning.
ignore:Parent module 'setuptools' not found while handling absolute import:RuntimeWarning
# Suppress use of bytes for filenames on Windows until fixed #2016
ignore:The Windows bytes API has been deprecated:DeprecationWarning
# Suppress other Python 2 UnicodeWarnings
ignore:Unicode equal comparison failed to convert:UnicodeWarning
ignore:Unicode unequal comparison failed to convert:UnicodeWarning
# https://github.com/pypa/setuptools/issues/2025
ignore:direct construction of .*Item has been deprecated:DeprecationWarning
# https://github.com/pypa/setuptools/issues/2081
ignore:lib2to3 package is deprecated:PendingDeprecationWarning
ignore:lib2to3 package is deprecated:DeprecationWarning
......@@ -14,12 +14,9 @@ repository = https://upload.pypi.org/legacy/
[sdist]
formats = zip
[bdist_wheel]
universal = 1
[metadata]
name = setuptools
version = 41.0.1
version = 46.4.0
description = Easily download, build, install, upgrade, and uninstall Python packages
author = Python Packaging Authority
author_email = distutils-sig@python.org
......@@ -35,13 +32,12 @@ classifiers =
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Topic :: Software Development :: Libraries :: Python Modules
Topic :: System :: Archiving :: Packaging
Topic :: System :: Systems Administration
......@@ -49,7 +45,7 @@ classifiers =
[options]
zip_safe = True
python_requires = >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
python_requires = >=3.5
py_modules = easy_install
packages = find:
......@@ -59,5 +55,27 @@ exclude = *.tests
[options.extras_require]
ssl =
wincertstore==0.2; sys_platform=='win32'
certs =
certifi==2016.9.26
tests =
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.
docs =
# Keep these in sync with docs/requirements.txt
sphinx
jaraco.packaging>=6.1
rst.linker>=1.9
pygments-github-lexers==0.0.5
......@@ -44,7 +44,7 @@ def _gen_console_scripts():
if any(os.environ.get(var) not in (None, "", "0") for var in var_names):
return
tmpl = "easy_install-{shortver} = setuptools.command.easy_install:main"
yield tmpl.format(shortver=sys.version[:3])
yield tmpl.format(shortver='{}.{}'.format(*sys.version_info))
package_data = dict(
......@@ -89,6 +89,12 @@ setup_params = dict(
"%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals()
for cmd in read_commands()
],
"setuptools.finalize_distribution_options": [
"parent_finalize = setuptools.dist:_Distribution.finalize_options",
"keywords = setuptools.dist:Distribution._finalize_setup_keywords",
"2to3_doctests = "
"setuptools.dist:Distribution._finalize_2to3_doctests",
],
"distutils.setup_keywords": [
"eager_resources = setuptools.dist:assert_string_list",
"namespace_packages = setuptools.dist:check_nsp",
......
"""Extensions to the 'distutils' for large or complex distributions"""
import os
import sys
import functools
import distutils.core
import distutils.filelist
......@@ -17,7 +16,7 @@ from setuptools.extern.six.moves import filter, map
import setuptools.version
from setuptools.extension import Extension
from setuptools.dist import Distribution, Feature
from setuptools.dist import Distribution
from setuptools.depends import Require
from . import monkey
......@@ -25,13 +24,13 @@ __metaclass__ = type
__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
'setup', 'Distribution', 'Command', 'Extension', 'Require',
'SetuptoolsDeprecationWarning',
'find_packages'
]
if PY3:
__all__.append('find_namespace_packages')
__all__.append('find_namespace_packages')
__version__ = setuptools.version.__version__
......@@ -123,7 +122,7 @@ class PEP420PackageFinder(PackageFinder):
find_packages = PackageFinder.find
if PY3:
find_namespace_packages = PEP420PackageFinder.find
find_namespace_packages = PEP420PackageFinder.find
def _install_setup_requires(attrs):
......@@ -144,6 +143,7 @@ def setup(**attrs):
_install_setup_requires(attrs)
return distutils.core.setup(**attrs)
setup.__doc__ = distutils.core.setup.__doc__
......@@ -191,8 +191,8 @@ class Command(_Command):
ok = False
if not ok:
raise DistutilsOptionError(
"'%s' must be a list of strings (got %r)"
% (option, val))
"'%s' must be a list of strings (got %r)"
% (option, val))
def reinitialize_command(self, command, reinit_subcommands=0, **kw):
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
......@@ -224,5 +224,9 @@ def findall(dir=os.curdir):
return list(files)
class sic(str):
"""Treat this string as-is (https://en.wikipedia.org/wiki/Sic)"""
# Apply monkey patches
monkey.patch_all()
"""
Re-implementation of find_module and get_frozen_object
from the deprecated imp module.
"""
import os
import importlib.util
import importlib.machinery
from .py34compat import module_from_spec
PY_SOURCE = 1
PY_COMPILED = 2
C_EXTENSION = 3
C_BUILTIN = 6
PY_FROZEN = 7
def find_spec(module, paths):
finder = (
importlib.machinery.PathFinder().find_spec
if isinstance(paths, list) else
importlib.util.find_spec
)
return finder(module, paths)
def find_module(module, paths=None):
"""Just like 'imp.find_module()', but with package support"""
spec = find_spec(module, paths)
if spec is None:
raise ImportError("Can't find %s" % module)
if not spec.has_location and hasattr(spec, 'submodule_search_locations'):
spec = importlib.util.spec_from_loader('__init__.py', spec.loader)
kind = -1
file = None
static = isinstance(spec.loader, type)
if spec.origin == 'frozen' or static and issubclass(
spec.loader, importlib.machinery.FrozenImporter):
kind = PY_FROZEN
path = None # imp compabilty
suffix = mode = '' # imp compability
elif spec.origin == 'built-in' or static and issubclass(
spec.loader, importlib.machinery.BuiltinImporter):
kind = C_BUILTIN
path = None # imp compabilty
suffix = mode = '' # imp compability
elif spec.has_location:
path = spec.origin
suffix = os.path.splitext(path)[1]
mode = 'r' if suffix in importlib.machinery.SOURCE_SUFFIXES else 'rb'
if suffix in importlib.machinery.SOURCE_SUFFIXES:
kind = PY_SOURCE
elif suffix in importlib.machinery.BYTECODE_SUFFIXES:
kind = PY_COMPILED
elif suffix in importlib.machinery.EXTENSION_SUFFIXES:
kind = C_EXTENSION
if kind in {PY_SOURCE, PY_COMPILED}:
file = open(path, mode)
else:
path = None
suffix = mode = ''
return file, path, (suffix, mode, kind)
def get_frozen_object(module, paths=None):
spec = find_spec(module, paths)
if not spec:
raise ImportError("Can't find %s" % module)
return spec.loader.get_code(module)
def get_module(module, paths, info):
spec = find_spec(module, paths)
if not spec:
raise ImportError("Can't find %s" % module)
return module_from_spec(spec)
This diff is collapsed.
......@@ -4,18 +4,24 @@
from __future__ import absolute_import, division, print_function
__all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
]
__title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
__version__ = "16.8"
__version__ = "19.2"
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0"
__copyright__ = "Copyright 2014-2016 %s" % __author__
__copyright__ = "Copyright 2014-2019 %s" % __author__
......@@ -4,11 +4,23 @@
from __future__ import absolute_import, division, print_function
from .__about__ import (
__author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__
__author__,
__copyright__,
__email__,
__license__,
__summary__,
__title__,
__uri__,
__version__,
)
__all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
]
......@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3
# flake8: noqa
if PY3:
string_types = str,
string_types = (str,)
else:
string_types = basestring,
string_types = (basestring,)
def with_metaclass(meta, *bases):
......@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases):
class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
return type.__new__(metaclass, "temporary_class", (), {})
......@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function
class Infinity(object):
def __repr__(self):
return "Infinity"
......@@ -33,11 +32,11 @@ class Infinity(object):
def __neg__(self):
return NegativeInfinity
Infinity = Infinity()
class NegativeInfinity(object):
def __repr__(self):
return "-Infinity"
......@@ -65,4 +64,5 @@ class NegativeInfinity(object):
def __neg__(self):
return Infinity
NegativeInfinity = NegativeInfinity()
......@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier
__all__ = [
"InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
"Marker", "default_environment",
"InvalidMarker",
"UndefinedComparison",
"UndefinedEnvironmentName",
"Marker",
"default_environment",
]
......@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError):
class Node(object):
def __init__(self, value):
self.value = value
......@@ -57,62 +59,52 @@ class Node(object):
class Variable(Node):
def serialize(self):
return str(self)
class Value(Node):
def serialize(self):
return '"{0}"'.format(self)
class Op(Node):
def serialize(self):
return str(self)
VARIABLE = (
L("implementation_version") |
L("platform_python_implementation") |
L("implementation_name") |
L("python_full_version") |
L("platform_release") |
L("platform_version") |
L("platform_machine") |
L("platform_system") |
L("python_version") |
L("sys_platform") |
L("os_name") |
L("os.name") | # PEP-345
L("sys.platform") | # PEP-345
L("platform.version") | # PEP-345
L("platform.machine") | # PEP-345
L("platform.python_implementation") | # PEP-345
L("python_implementation") | # undocumented setuptools legacy
L("extra")
L("implementation_version")
| L("platform_python_implementation")
| L("implementation_name")
| L("python_full_version")
| L("platform_release")
| L("platform_version")
| L("platform_machine")
| L("platform_system")
| L("python_version")
| L("sys_platform")
| L("os_name")
| L("os.name")
| L("sys.platform") # PEP-345
| L("platform.version") # PEP-345
| L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345
| L("python_implementation") # PEP-345
| L("extra") # undocumented setuptools legacy
)
ALIASES = {
'os.name': 'os_name',
'sys.platform': 'sys_platform',
'platform.version': 'platform_version',
'platform.machine': 'platform_machine',
'platform.python_implementation': 'platform_python_implementation',
'python_implementation': 'platform_python_implementation'
"os.name": "os_name",
"sys.platform": "sys_platform",
"platform.version": "platform_version",
"platform.machine": "platform_machine",
"platform.python_implementation": "platform_python_implementation",
"python_implementation": "platform_python_implementation",
}
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = (
L("===") |
L("==") |
L(">=") |
L("<=") |
L("!=") |
L("~=") |
L(">") |
L("<")
L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
)
MARKER_OP = VERSION_CMP | L("not in") | L("in")
......@@ -152,8 +144,11 @@ def _format_marker(marker, first=True):
# where the single item is itself it's own list. In that case we want skip
# the rest of this function so that we don't get extraneous () on the
# outside.
if (isinstance(marker, list) and len(marker) == 1 and
isinstance(marker[0], (list, tuple))):
if (
isinstance(marker, list)
and len(marker) == 1
and isinstance(marker[0], (list, tuple))
):
return _format_marker(marker[0])
if isinstance(marker, list):
......@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
version = '{0.major}.{0.minor}.{0.micro}'.format(info)
version = "{0.major}.{0.minor}.{0.micro}".format(info)
kind = info.releaselevel
if kind != 'final':
if kind != "final":
version += kind[0] + str(info.serial)
return version
def default_environment():
if hasattr(sys, 'implementation'):
if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
else:
iver = '0'
implementation_name = ''
iver = "0"
implementation_name = ""
return {
"implementation_name": implementation_name,
......@@ -264,19 +259,19 @@ def default_environment():
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
"python_version": platform.python_version()[:3],
"python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
}
class Marker(object):
def __init__(self, marker):
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
marker, marker[e.loc:e.loc + 8])
marker, marker[e.loc : e.loc + 8]
)
raise InvalidMarker(err_str)
def __str__(self):
......
......@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name")
EXTRA = IDENTIFIER
URI = Regex(r'[^ ]+')("url")
URL = (AT + URI)
URI = Regex(r"[^ ]+")("url")
URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
......@@ -48,28 +48,31 @@ VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
joinString=",", adjacent=False)("_raw_spec")
VERSION_MANY = Combine(
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR.setParseAction(
lambda s, l, t: Marker(s[t._original_start:t._original_end])
lambda s, l, t: Marker(s[t._original_start : t._original_end])
)
MARKER_SEPERATOR = SEMICOLON
MARKER = MARKER_SEPERATOR + MARKER_EXPR
MARKER_SEPARATOR = SEMICOLON
MARKER = MARKER_SEPARATOR + MARKER_EXPR
VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
URL_AND_MARKER = URL + Optional(MARKER)
NAMED_REQUIREMENT = \
NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
# issue #104
REQUIREMENT.parseString("x[]")
class Requirement(object):
......@@ -90,15 +93,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
raise InvalidRequirement(
"Invalid requirement, parse error at \"{0!r}\"".format(
requirement_string[e.loc:e.loc + 8]))
'Parse error at "{0!r}": {1}'.format(
requirement_string[e.loc : e.loc + 8], e.msg
)
)
self.name = req.name
if req.url:
parsed_url = urlparse.urlparse(req.url)
if not (parsed_url.scheme and parsed_url.netloc) or (
not parsed_url.scheme and not parsed_url.netloc):
raise InvalidRequirement("Invalid URL given")
if parsed_url.scheme == "file":
if urlparse.urlunparse(parsed_url) != req.url:
raise InvalidRequirement("Invalid URL given")
elif not (parsed_url.scheme and parsed_url.netloc) or (
not parsed_url.scheme and not parsed_url.netloc
):
raise InvalidRequirement("Invalid URL: {0}".format(req.url))
self.url = req.url
else:
self.url = None
......@@ -117,6 +126,8 @@ class Requirement(object):
if self.url:
parts.append("@ {0}".format(self.url))
if self.marker:
parts.append(" ")
if self.marker:
parts.append("; {0}".format(self.marker))
......
......@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError):
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod
def __str__(self):
"""
......@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier):
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
self._spec = (
match.group("operator").strip(),
match.group("version").strip(),
)
self._spec = (match.group("operator").strip(), match.group("version").strip())
# Store whether or not this Specifier should accept prereleases
self._prereleases = prereleases
......@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier):
else ""
)
return "<{0}({1!r}{2})>".format(
self.__class__.__name__,
str(self),
pre,
)
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
def __str__(self):
return "{0}{1}".format(*self._spec)
......@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier):
# If our version is a prerelease, and we were not set to allow
# prereleases, then we'll store it for later incase nothing
# else matches this specifier.
if (parsed_version.is_prerelease and not
(prereleases or self.prereleases)):
if parsed_version.is_prerelease and not (
prereleases or self.prereleases
):
found_prereleases.append(version)
# Either this is not a prerelease, or we should have been
# accepting prereleases from the begining.
# accepting prereleases from the beginning.
else:
yielded = True
yield version
......@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier):
class LegacySpecifier(_IndividualSpecifier):
_regex_str = (
r"""
_regex_str = r"""
(?P<operator>(==|!=|<=|>=|<|>))
\s*
(?P<version>
......@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier):
# them, and a comma since it's a version separator.
)
"""
)
_regex = re.compile(
r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"==": "equal",
......@@ -269,13 +259,13 @@ def _require_version_compare(fn):
if not isinstance(prospective, Version):
return False
return fn(self, prospective, spec)
return wrapped
class Specifier(_IndividualSpecifier):
_regex_str = (
r"""
_regex_str = r"""
(?P<operator>(~=|==|!=|<=|>=|<|>|===))
(?P<version>
(?:
......@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier):
)
)
"""
)
_regex = re.compile(
r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"~=": "compatible",
......@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier):
prefix = ".".join(
list(
itertools.takewhile(
lambda x: (not x.startswith("post") and not
x.startswith("dev")),
lambda x: (not x.startswith("post") and not x.startswith("dev")),
_version_split(spec),
)
)[:-1]
......@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier):
# Add the prefix notation to the end of our string
prefix += ".*"
return (self._get_operator(">=")(prospective, spec) and
self._get_operator("==")(prospective, prefix))
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
prospective, prefix
)
@_require_version_compare
def _compare_equal(self, prospective, spec):
......@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier):
# Shorten the prospective version to be the same length as the spec
# so that we can determine if the specifier is a prefix of the
# prospective version or not.
prospective = prospective[:len(spec)]
prospective = prospective[: len(spec)]
# Pad out our two sides with zeros so that they both equal the same
# length.
......@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier):
return False
# Ensure that we do not allow a local version of the version mentioned
# in the specifier, which is techincally greater than, to match.
# in the specifier, which is technically greater than, to match.
if prospective.local is not None:
if Version(prospective.base_version) == Version(spec.base_version):
return False
......@@ -567,27 +555,17 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions
left_split.append(left[len(left_split[0]):])
right_split.append(right[len(right_split[0]):])
left_split.append(left[len(left_split[0]) :])
right_split.append(right[len(right_split[0]) :])
# Insert our padding
left_split.insert(
1,
["0"] * max(0, len(right_split[0]) - len(left_split[0])),
)
right_split.insert(
1,
["0"] * max(0, len(left_split[0]) - len(right_split[0])),
)
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
return (
list(itertools.chain(*left_split)),
list(itertools.chain(*right_split)),
)
return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers="", prereleases=None):
# Split on , to break each indidivual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
......@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier):
# given version is contained within all of them.
# Note: This use of all() here means that an empty set of specifiers
# will always return True, this is an explicit design decision.
return all(
s.contains(item, prereleases=prereleases)
for s in self._specs
)
return all(s.contains(item, prereleases=prereleases) for s in self._specs)
def filter(self, iterable, prereleases=None):
# Determine if we're forcing a prerelease or not, if we're not forcing
......
This diff is collapsed.
......@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function
import re
from .version import InvalidVersion, Version
_canonicalize_regex = re.compile(r"[-_.]+")
......@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name):
# This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower()
def canonicalize_version(version):
"""
This is very similar to Version.__str__, but has one subtle differences
with the way it handles the release segment.
"""
try:
version = Version(version)
except InvalidVersion:
# Legacy versions cannot be normalized
return version
parts = []
# Epoch
if version.epoch != 0:
parts.append("{0}!".format(version.epoch))
# Release segment
# NB: This strips trailing '.0's to normalize
parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
# Pre-release
if version.pre is not None:
parts.append("".join(str(x) for x in version.pre))
# Post-release
if version.post is not None:
parts.append(".post{0}".format(version.post))
# Development release
if version.dev is not None:
parts.append(".dev{0}".format(version.dev))
# Local version segment
if version.local is not None:
parts.append("+{0}".format(version.local))
return "".join(parts)
This diff is collapsed.
packaging==16.8
packaging==19.2
pyparsing==2.2.1
six==1.10.0
ordered-set==3.1.1
......@@ -25,7 +25,8 @@ def default_filter(src, dst):
return dst
def unpack_archive(filename, extract_dir, progress_filter=default_filter,
def unpack_archive(
filename, extract_dir, progress_filter=default_filter,
drivers=None):
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
......@@ -148,7 +149,8 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
# resolve any links and to extract the link targets as normal
# files
while member is not None and (member.islnk() or member.issym()):
while member is not None and (
member.islnk() or member.issym()):
linkpath = member.linkname
if member.issym():
base = posixpath.dirname(member.name)
......
This diff is collapsed.
......@@ -2,8 +2,7 @@ __all__ = [
'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib',
'dist_info',
'bdist_wininst', 'upload_docs', 'build_clib', 'dist_info',
]
from distutils.command.bdist import bdist
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -108,7 +108,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
return path_to_setup
def install_for_development(self):
if six.PY3 and getattr(self.distribution, 'use_2to3', False):
if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
# If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment