Commit 992aa3df authored by Jason R. Coombs's avatar Jason R. Coombs

Merge branch 'master' into fix_889_and_non-ascii_in_setup.cfg_take_2

parents 2c897b5b 9b777b75
comment: false
<!-- First time contributors: Take a moment to review https://setuptools.readthedocs.io/en/latest/developer-guide.html! -->
<!-- Remove sections if not applicable -->
## Summary of changes
<!-- Summary goes here -->
Closes <!-- issue number here -->
### Pull Request Checklist
- [ ] Changes have tests
- [ ] News fragment added in changelog.d. See [documentation](http://setuptools.readthedocs.io/en/latest/developer-guide.html#making-a-pull-request) for details
......@@ -2,6 +2,7 @@
bin
build
dist
docs/build
include
lib
distribute.egg-info
......@@ -9,9 +10,12 @@ setuptools.egg-info
.coverage
.eggs
.tox
.venv
*.egg
*.py[cod]
*.swp
*~
.hg*
.cache
.idea/
.pytest_cache/
pull_request_rules:
- name: auto-merge
conditions:
- base=master
- label=auto-merge
- status-success=continuous-integration/appveyor/pr
- status-success=continuous-integration/travis-ci/pr
- status-success=deploy/netlify
actions:
merge:
method: merge
python:
version: 3
requirements_file: docs/requirements.txt
pip_install: false
dist: trusty
sudo: false
language: python
jobs:
fast_finish: true
include:
- python: 2.6
- python: &latest_py2 2.7
- python: 3.3
- python: 3.4
- python: 3.5
- python: &latest_py3 3.6
- python: nightly
- &latest_py2
python: 2.7
- <<: *latest_py2
env: LANG=C
- python: pypy
env: DISABLE_COVERAGE=1 # Don't run coverage on pypy (too slow).
- python: pypy3
- python: *latest_py3
env: LANG=C
- python: *latest_py2
env: DISABLE_COVERAGE=1
- python: 3.4
- python: 3.5
- &default_py
python: 3.6
- &latest_py3
python: 3.7
dist: xenial
- <<: *latest_py3
env: LANG=C
- stage: deploy (to PyPI for tagged commits)
- python: 3.8-dev
dist: xenial
env: DISABLE_COVERAGE=1 # Ignore invalid coverage data.
- <<: *default_py
stage: deploy (to PyPI for tagged commits)
if: tag IS present
python: *latest_py3
install: skip
script: skip
before_deploy: python bootstrap.py
after_success: true
before_deploy:
- python bootstrap.py
- "! grep pyc setuptools.egg-info/SOURCES.txt"
deploy:
provider: pypi
on:
......@@ -38,13 +48,37 @@ jobs:
cache: pip
install:
# ensure we have recent pip/setuptools/wheel
- pip install --disable-pip-version-check --upgrade pip setuptools wheel
# need tox to get started
- pip install tox
- pip install --upgrade tox tox-venv
# Output the env, to verify behavior
- pip freeze --all
- env
# update egg_info based on setup.py in checkout
- python bootstrap.py
- "! grep pyc setuptools.egg-info/SOURCES.txt"
script:
- |
( # Run testsuite.
if [ -z "$DISABLE_COVERAGE" ]
then
tox -- --cov
else
tox
fi
)
script: tox
after_success:
- |
( # Upload coverage data.
if [ -z "$DISABLE_COVERAGE" ]
then
export TRAVIS_JOB_NAME="${TRAVIS_PYTHON_VERSION} (LANG=$LANG)" CODECOV_ENV=TRAVIS_JOB_NAME
tox -e coverage,codecov
fi
)
This diff is collapsed.
......@@ -2,7 +2,7 @@ recursive-include setuptools *.py *.exe *.xml
recursive-include tests *.py
recursive-include setuptools/tests *.html
recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html
recursive-include setuptools/_vendor *
recursive-include setuptools/_vendor *.py *.txt
recursive-include pkg_resources *.py *.txt
include *.py
include *.rst
......
......@@ -5,20 +5,24 @@
:target: https://setuptools.readthedocs.io
.. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20build%20%40%20Travis%20CI
:target: http://travis-ci.org/pypa/setuptools
:target: https://travis-ci.org/pypa/setuptools
.. image:: https://img.shields.io/appveyor/ci/jaraco/setuptools/master.svg?label=Windows%20build%20%40%20Appveyor
:target: https://ci.appveyor.com/project/jaraco/setuptools/branch/master
.. image:: https://img.shields.io/appveyor/ci/pypa/setuptools/master.svg?label=Windows%20build%20%40%20Appveyor
:target: https://ci.appveyor.com/project/pypa/setuptools/branch/master
.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg
:target: https://codecov.io/gh/pypa/setuptools
.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg
.. image:: https://tidelift.com/badges/github/pypa/setuptools
:target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme
See the `Installation Instructions
<https://packaging.python.org/installing/>`_ in the Python Packaging
User's Guide for instructions on installing, upgrading, and uninstalling
Setuptools.
The project is `maintained at GitHub <https://github.com/pypa/setuptools>`_.
Questions and comments should be directed to the `distutils-sig
mailing list <http://mail.python.org/pipermail/distutils-sig/>`_.
Bug reports and especially tested patches may be
......
clone_depth: 50
environment:
APPVEYOR: true
APPVEYOR: True
CODECOV_ENV: APPVEYOR_JOB_NAME
matrix:
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python27-x64"
- APPVEYOR_JOB_NAME: "python36-x64"
PYTHON: "C:\\Python36-x64"
- APPVEYOR_JOB_NAME: "python27-x64"
PYTHON: "C:\\Python27-x64"
install:
# symlink python from a directory with a space
......@@ -14,7 +19,18 @@ install:
build: off
cache:
- '%LOCALAPPDATA%\pip\Cache'
test_script:
- "python bootstrap.py"
- "python -m pip install tox"
- "tox"
- python --version
- python -m pip install --disable-pip-version-check --upgrade pip setuptools wheel
- pip install --upgrade tox tox-venv
- pip freeze --all
- python bootstrap.py
- tox -- --cov
after_test:
- tox -e coverage,codecov
version: '{build}'
``setuptools.package_index`` no longer relies on the deprecated ``urllib.parse.splituser`` per Python #27485.
Added tests for PackageIndex.download (for git URLs).
File inputs for the `license` field in `setup.cfg` files now explicitly raise an error.
In PEP 517 build_meta builder, ensure that sdists are built as gztar per the spec.
import sys
pytest_plugins = 'setuptools.tests.fixtures'
......@@ -6,3 +9,17 @@ def pytest_addoption(parser):
"--package_name", action="append", default=[],
help="list of package_name to pass to test functions",
)
collect_ignore = [
'tests/manual_test.py',
'setuptools/tests/mod_with_constant.py',
]
if sys.version_info < (3,):
collect_ignore.append('setuptools/lib2to3_ex.py')
if sys.version_info < (3, 6):
collect_ignore.append('pavement.py')
<h3>Download</h3>
<p>Current version: <b>{{ version }}</b></p>
<p>Get Setuptools from the <a href="https://pypi.python.org/pypi/setuptools"> Python Package Index</a>
<p>Get Setuptools from the <a href="https://pypi.org/project/setuptools/"> Python Package Index</a>
<h3>Questions? Suggestions? Contributions?</h3>
<p>Visit the <a href="https://github.com/pypa/setuptools">Setuptools 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-setuptools?utm_source=pypi-setuptools&utm_medium=readme">Tidelift Subscription</a>.
</p>
......@@ -34,7 +34,7 @@ import os
# 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', 'sphinx.ext.autosectionlabel']
extensions = ['jaraco.packaging.sphinx', 'rst.linker']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......@@ -45,6 +45,9 @@ 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.
exclude_patterns = ['requirements.txt']
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []
......
......@@ -57,40 +57,59 @@ Setuptools makes extensive use of hyperlinks to tickets in the changelog so
that system integrators and other users can get a quick summary, but then
jump to the in-depth discussion about any subject referenced.
-----------
Source Code
-----------
---------------------
Making a pull request
---------------------
When making a pull request, please include a short summary of the changes
and a reference to any issue tickets that the PR is intended to solve.
All PRs with code changes should include tests. All changes should include a
changelog entry.
``setuptools`` uses `towncrier <https://pypi.org/project/towncrier/>`_
for changelog management, so when making a PR, please add a news fragment in the
``changelog.d/`` folder. Changelog files are written in reStructuredText and
should be a 1 or 2 sentence description of the substantive changes in the PR.
They should be named ``<pr_number>.<category>.rst``, where the categories are:
- ``change``: Any backwards compatible code change
- ``breaking``: Any backwards-compatibility breaking change
- ``doc``: A change to the documentation
- ``misc``: Changes internal to the repo like CI, test and build changes
- ``deprecation``: For deprecations of an existing feature or behavior
A pull request may have more than one of these components, for example a code
change may introduce a new feature that deprecates an old feature, in which
case two fragments should be added. It is not necessary to make a separate
documentation fragment for documentation changes accompanying the relevant
code changes. See the following for an example news fragment:
.. code-block:: bash
$ cat changelog.d/1288.change.rst
Add support for maintainer in PKG-INFO
Grab the code at Github::
$ git checkout https://github.com/pypa/setuptools
If you want to contribute changes, we recommend you fork the repository on
Github, commit the changes to your repository, and then make a pull request
on Github. If you make some changes, don't forget to:
- add a note in CHANGES.rst
Please commit all changes in the 'master' branch against the latest available
commit or for bug-fixes, against an earlier commit or release in which the
bug occurred.
If you find yourself working on more than one issue at a time, Setuptools
generally prefers Git-style branches, so use Mercurial bookmarks or Git
branches or multiple forks to maintain separate efforts.
-------------------
Auto-Merge Requests
-------------------
The Continuous Integration tests that validate every release are run
from this repository.
To support running all code through CI, even lightweight contributions,
the project employs Mergify to auto-merge pull requests tagged as
auto-merge.
For posterity, the old `Bitbucket mirror
<https://bitbucket.org/pypa/setuptools>`_ is available.
Use ``hub pull-request -l auto-merge`` to create such a pull request
from the command line after pushing a new branch.
-------
Testing
-------
The primary tests are run using tox. To run the tests, first make
sure you have tox installed, then invoke it::
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::
$ tox
......@@ -109,10 +128,12 @@ Setuptools follows ``semver``.
Building Documentation
----------------------
Setuptools relies on the Sphinx system for building documentation.
To accommodate RTD, docs must be built from the docs/ directory.
Setuptools relies on the `Sphinx`_ system for building documentation.
The `published documentation`_ is hosted on Read the Docs.
To build the docs locally, use tox::
To build them, you need to have installed the requirements specified
in docs/requirements.txt. One way to do this is to use rwt:
$ tox -e docs
setuptools/docs$ python -m rwt -r requirements.txt -- -m sphinx . html
.. _Sphinx: http://www.sphinx-doc.org/en/master/
.. _published documentation: https://setuptools.readthedocs.io/en/latest/
This diff is collapsed.
: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.
......@@ -110,7 +110,7 @@ the need to create a directory just to store one file. This option is
other metadata. (In fact, setuptools itself never generates
``.egg-info`` files, either; the support for using files was added so
that the requirement could easily be satisfied by other tools, such
as the distutils in Python 2.5).
as distutils).
In addition to the ``PKG-INFO`` file, an egg's metadata directory may
also include files and directories representing various forms of
......
......@@ -40,7 +40,6 @@ Credits
re-invigorated the community on the project, encouraged renewed innovation,
and addressed many defects.
* Since the merge with Distribute, Jason R. Coombs is the
maintainer of setuptools. The project is maintained in coordination with
the Python Packaging Authority (PyPA) and the larger Python community.
* Jason R. Coombs performed the merge with Distribute, maintaining the
project for several years in coordination with the Python Packaging
Authority (PyPA).
......@@ -17,9 +17,9 @@ Documentation content:
:maxdepth: 2
setuptools
easy_install
pkg_resources
python3
development
roadmap
Deprecated: Easy Install <easy_install>
history
......@@ -620,8 +620,8 @@ Requirements Parsing
The "markers" in a requirement are used to specify when a requirement
should be installed -- the requirement will be installed if the marker
evaluates as true in the current environment. For example, specifying
``argparse;python_version<"2.7"`` will not install in an Python 2.7 or 3.3
environment, but will in a Python 2.6 environment.
``argparse;python_version<"3.0"`` will not install in an Python 3
environment, but will in a Python 2 environment.
``Requirement`` Methods and Attributes
--------------------------------------
......@@ -638,7 +638,7 @@ Requirements Parsing
sorted into ascending version order, and used to establish what ranges of
versions are acceptable. Adjacent redundant conditions are effectively
consolidated (e.g. ``">1, >2"`` produces the same results as ``">2"``, and
``"<2,<3"`` produces the same results as``"<2"``). ``"!="`` versions are
``"<2,<3"`` produces the same results as ``"<2"``). ``"!="`` versions are
excised from the ranges they fall within. The version being tested for
acceptability is then checked for membership in the resulting ranges.
......@@ -703,7 +703,7 @@ entry point group and look for entry points named "pre_process" and
To advertise an entry point, a project needs to use ``setuptools`` and provide
an ``entry_points`` argument to ``setup()`` in its setup script, so that the
entry points will be included in the distribution's metadata. For more
details, see the ``setuptools`` documentation. (XXX link here to setuptools)
details, see the [``setuptools`` documentation](https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins).
Each project distribution can advertise at most one entry point of a given
name within the same entry point group. For example, a distutils extension
......@@ -1087,6 +1087,7 @@ so that supporting custom importers or new distribution formats can be done
simply by creating an appropriate `IResourceProvider`_ implementation; see the
section below on `Supporting Custom Importers`_ for more details.
.. _ResourceManager API:
``ResourceManager`` API
=======================
......@@ -1658,19 +1659,7 @@ PEP 302 Utilities
-----------------
``get_importer(path_item)``
Retrieve a PEP 302 "importer" for the given path item (which need not
actually be on ``sys.path``). This routine simulates the PEP 302 protocol
for obtaining an "importer" object. It first checks for an importer for
the path item in ``sys.path_importer_cache``, and if not found it calls
each of the ``sys.path_hooks`` and caches the result if a good importer is
found. If no importer is found, this routine returns an ``ImpWrapper``
instance that wraps the builtin import machinery as a PEP 302-compliant
"importer" object. This ``ImpWrapper`` is *not* cached; instead a new
instance is returned each time.
(Note: When run under Python 2.5, this function is simply an alias for
``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper``
instances, it may return ``pkgutil.ImpImporter`` instances.)
A deprecated alias for ``pkgutil.get_importer()``
File/Path Utilities
......
......@@ -9,9 +9,9 @@ code.
Setuptools provides a facility to invoke 2to3 on the code as a part of the
build process, by setting the keyword parameter ``use_2to3`` to True, but
the Setuptools strongly recommends instead developing a unified codebase
using `six <https://pypi.python.org/pypi/six>`_,
`future <https://pypi.python.org/pypi/future>`_, or another compatibility
the Setuptools project strongly recommends instead developing a unified codebase
using `six <https://pypi.org/project/six/>`_,
`future <https://pypi.org/project/future/>`_, or another compatibility
library.
......
......@@ -7,20 +7,35 @@ 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 check that the CHANGES.rst reflects
the summary of changes since the last release.
Ideally, these changelog entries would have been added
along with the changes, but it's always good to check.
Think about it from the
perspective of a user not involved with the development--what would
that person want to know about what has changed--or from the
perspective of your future self wanting to know when a particular
change landed.
To cut a release, install and run ``bump2version {part}`` where ``part``
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. If tests pass,
the release will be uploaded to PyPI (from the Python 3.6 tests).
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/
Release Frequency
-----------------
......
sphinx
sphinx!=1.8.0
rst.linker>=1.9
jaraco.packaging>=3.2
......
......@@ -2,5 +2,6 @@
Roadmap
=======
Setuptools is primarily in maintenance mode. The project attempts to address
user issues, concerns, and feature requests in a timely fashion.
Setuptools maintains a series of `milestones
<https://github.com/pypa/setuptools/milestones>`_ to track
a roadmap of large-scale goals.
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
# Configuration for pull request documentation previews via Netlify
[build]
publish = "docs/build/html"
command = "pip install tox && tox -e docs"
import re
import sys
import subprocess
from paver.easy import task, path as Path
import pip
def remove_all(paths):
......@@ -11,22 +12,54 @@ def remove_all(paths):
@task
def update_vendored():
vendor = Path('pkg_resources/_vendor')
# pip uninstall doesn't support -t, so do it manually
remove_all(vendor.glob('packaging*'))
remove_all(vendor.glob('six*'))
remove_all(vendor.glob('pyparsing*'))
remove_all(vendor.glob('appdirs*'))
update_pkg_resources()
update_setuptools()
def rewrite_packaging(pkg_files, new_root):
"""
Rewrite imports in packaging to redirect to vendored copies.
"""
for file in pkg_files.glob('*.py'):
text = file.text()
text = re.sub(r' (pyparsing|six)', rf' {new_root}.\1', text)
file.write_text(text)
def clean(vendor):
"""
Remove all files out of the vendor directory except the meta
data (as pip uninstall doesn't support -t).
"""
remove_all(
path
for path in vendor.glob('*')
if path.basename() != 'vendored.txt'
)
def install(vendor):
clean(vendor)
install_args = [
sys.executable,
'-m', 'pip',
'install',
'-r', str(vendor / 'vendored.txt'),
'-t', str(vendor),
]
pip.main(install_args)
packaging = vendor / 'packaging'
for file in packaging.glob('*.py'):
text = file.text()
text = re.sub(r' (pyparsing|six)', r' pkg_resources.extern.\1', text)
file.write_text(text)
subprocess.check_call(install_args)
remove_all(vendor.glob('*.dist-info'))
remove_all(vendor.glob('*.egg-info'))
(vendor / '__init__.py').write_text('')
def update_pkg_resources():
vendor = Path('pkg_resources/_vendor')
install(vendor)
rewrite_packaging(vendor / 'packaging', 'pkg_resources.extern')
def update_setuptools():
vendor = Path('setuptools/_vendor')
install(vendor)
rewrite_packaging(vendor / 'packaging', 'setuptools.extern')
This diff is collapsed.
......@@ -13,7 +13,7 @@ See <http://github.com/ActiveState/appdirs> for details and usage.
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
__version_info__ = (1, 4, 0)
__version_info__ = (1, 4, 3)
__version__ = '.'.join(map(str, __version_info__))
......@@ -98,7 +98,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
"""Return full path to the user-shared data dir for this application.
r"""Return full path to the user-shared data dir for this application.
"appname" is the name of application.
If None, just the system directory is returned.
......@@ -117,7 +117,7 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
returned, or '/usr/local/share/<AppName>',
if XDG_DATA_DIRS is not set
Typical user data directories are:
Typical site data directories are:
Mac OS X: /Library/Application Support/<AppName>
Unix: /usr/local/share/<AppName> or /usr/share/<AppName>
Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
......@@ -184,13 +184,13 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
for a discussion of issues.
Typical user data directories are:
Typical user config directories are:
Mac OS X: same as user_data_dir
Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined
Win *: same as user_data_dir
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
That means, by deafult "~/.config/<AppName>".
That means, by default "~/.config/<AppName>".
"""
if system in ["win32", "darwin"]:
path = user_data_dir(appname, appauthor, None, roaming)
......@@ -204,7 +204,7 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
"""Return full path to the user-shared data dir for this application.
r"""Return full path to the user-shared data dir for this application.
"appname" is the name of application.
If None, just the system directory is returned.
......@@ -222,7 +222,7 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False)
returned. By default, the first item from XDG_CONFIG_DIRS is
returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
Typical user data directories are:
Typical site config directories are:
Mac OS X: same as site_data_dir
Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
$XDG_CONFIG_DIRS
......@@ -311,6 +311,48 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
return path
def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
r"""Return full path to the user-specific state dir for this application.
"appname" is the name of application.
If None, just the system directory is returned.
"appauthor" (only used on Windows) is the name of the
appauthor or distributing body for this application. Typically
it is the owning company name. This falls back to appname. You may
pass False to disable it.
"version" is an optional version path element to append to the
path. You might want to use this if you want multiple versions
of your app to be able to run independently. If used, this
would typically be "<major>.<minor>".
Only applied when appname is present.
"roaming" (boolean, default False) can be set True to use the Windows
roaming appdata directory. That means that for users on a Windows
network setup for roaming profiles, this user data will be
sync'd on login. See
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
for a discussion of issues.
Typical user state directories are:
Mac OS X: same as user_data_dir
Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined
Win *: same as user_data_dir
For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state>
to extend the XDG spec and support $XDG_STATE_HOME.
That means, by default "~/.local/state/<AppName>".
"""
if system in ["win32", "darwin"]:
path = user_data_dir(appname, appauthor, None, roaming)
else:
path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))
if appname:
path = os.path.join(path, appname)
if appname and version:
path = os.path.join(path, version)
return path
def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
r"""Return full path to the user-specific log dir for this application.
......@@ -329,7 +371,7 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
"Logs" to the base app data dir for Windows, and "log" to the
base cache dir for Unix. See discussion below.
Typical user cache directories are:
Typical user log directories are:
Mac OS X: ~/Library/Logs/<AppName>
Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined
Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
......@@ -364,8 +406,8 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
class AppDirs(object):
"""Convenience wrapper for getting application dirs."""
def __init__(self, appname, appauthor=None, version=None, roaming=False,
multipath=False):
def __init__(self, appname=None, appauthor=None, version=None,
roaming=False, multipath=False):
self.appname = appname
self.appauthor = appauthor
self.version = version
......@@ -397,6 +439,11 @@ class AppDirs(object):
return user_cache_dir(self.appname, self.appauthor,
version=self.version)
@property
def user_state_dir(self):
return user_state_dir(self.appname, self.appauthor,
version=self.version)
@property
def user_log_dir(self):
return user_log_dir(self.appname, self.appauthor,
......@@ -410,7 +457,10 @@ def _get_win_folder_from_registry(csidl_name):
registry for this guarantees us the correct answer for all CSIDL_*
names.
"""
import _winreg
if PY3:
import winreg as _winreg
else:
import _winreg
shell_folder_name = {
"CSIDL_APPDATA": "AppData",
......@@ -500,7 +550,7 @@ def _get_win_folder_with_jna(csidl_name):
if has_high_char:
buf = array.zeros('c', buf_size)
kernel = win32.Kernel32.INSTANCE
if kernal.GetShortPathName(dir, buf, buf_size):
if kernel.GetShortPathName(dir, buf, buf_size):
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
return dir
......@@ -527,9 +577,15 @@ if __name__ == "__main__":
appname = "MyApp"
appauthor = "MyCompany"
props = ("user_data_dir", "site_data_dir",
"user_config_dir", "site_config_dir",
"user_cache_dir", "user_log_dir")
props = ("user_data_dir",
"user_config_dir",
"user_cache_dir",
"user_state_dir",
"user_log_dir",
"site_data_dir",
"site_config_dir")
print("-- app dirs %s --" % __version__)
print("-- app dirs (with optional 'version')")
dirs = AppDirs(appname, appauthor, version="1.0")
......
This diff is collapsed.
packaging==16.8
pyparsing==2.1.10
pyparsing==2.2.1
six==1.10.0
appdirs==1.4.0
appdirs==1.4.3
......@@ -385,10 +385,10 @@ Environment Markers
>>> em("sys_platform=='win32'") == (sys.platform=='win32')
True
>>> em("python_version >= '2.6'")
>>> em("python_version >= '2.7'")
True
>>> em("python_version > '2.5'")
>>> em("python_version > '2.6'")
True
>>> im("implementation_name=='cpython'")
......
......@@ -48,7 +48,7 @@ class VendorImporter:
# on later Python versions to cause relative imports
# in the vendor package to resolve the same modules
# as those going through this importer.
if sys.version_info > (3, 3):
if prefix and sys.version_info > (3, 3):
del sys.modules[extant]
return mod
except ImportError:
......
......@@ -2,6 +2,8 @@ import os
import errno
import sys
from .extern import six
def _makedirs_31(path, exist_ok=False):
try:
......@@ -15,8 +17,7 @@ def _makedirs_31(path, exist_ok=False):
# and exists_ok considerations are disentangled.
# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663
needs_makedirs = (
sys.version_info < (3, 2, 5) or
(3, 3) <= sys.version_info < (3, 3, 6) or
six.PY2 or
(3, 4) <= sys.version_info < (3, 4, 1)
)
makedirs = _makedirs_31 if needs_makedirs else os.makedirs
......@@ -13,6 +13,7 @@ setuptools.setup(
)
""".lstrip()
class TestFindDistributions:
@pytest.fixture
......
......@@ -12,16 +12,19 @@ import stat
import distutils.dist
import distutils.command.install_egg_info
try:
from unittest import mock
except ImportError:
import mock
from pkg_resources.extern.six.moves import map
from pkg_resources.extern.six import text_type, string_types
import pytest
import pkg_resources
try:
unicode
except NameError:
unicode = str
__metaclass__ = type
def timestamp(dt):
......@@ -35,7 +38,7 @@ def timestamp(dt):
return time.mktime(dt.timetuple())
class EggRemover(unicode):
class EggRemover(text_type):
def __call__(self):
if self in sys.path:
sys.path.remove(self)
......@@ -43,7 +46,7 @@ class EggRemover(unicode):
os.remove(self)
class TestZipProvider(object):
class TestZipProvider:
finalizers = []
ref_time = datetime.datetime(2013, 5, 12, 13, 25, 0)
......@@ -62,10 +65,21 @@ class TestZipProvider(object):
zip_info.filename = 'data.dat'
zip_info.date_time = cls.ref_time.timetuple()
zip_egg.writestr(zip_info, 'hello, world!')
zip_info = zipfile.ZipInfo()
zip_info.filename = 'subdir/mod2.py'
zip_info.date_time = cls.ref_time.timetuple()
zip_egg.writestr(zip_info, 'x = 6\n')
zip_info = zipfile.ZipInfo()
zip_info.filename = 'subdir/data2.dat'
zip_info.date_time = cls.ref_time.timetuple()
zip_egg.writestr(zip_info, 'goodbye, world!')
zip_egg.close()
egg.close()
sys.path.append(egg.name)
subdir = os.path.join(egg.name, 'subdir')
sys.path.append(subdir)
cls.finalizers.append(EggRemover(subdir))
cls.finalizers.append(EggRemover(egg.name))
@classmethod
......@@ -73,6 +87,30 @@ class TestZipProvider(object):
for finalizer in cls.finalizers:
finalizer()
def test_resource_listdir(self):
import mod
zp = pkg_resources.ZipProvider(mod)
expected_root = ['data.dat', 'mod.py', 'subdir']
assert sorted(zp.resource_listdir('')) == expected_root
assert sorted(zp.resource_listdir('/')) == expected_root
expected_subdir = ['data2.dat', 'mod2.py']
assert sorted(zp.resource_listdir('subdir')) == expected_subdir
assert sorted(zp.resource_listdir('subdir/')) == expected_subdir
assert zp.resource_listdir('nonexistent') == []
assert zp.resource_listdir('nonexistent/') == []
import mod2
zp2 = pkg_resources.ZipProvider(mod2)
assert sorted(zp2.resource_listdir('')) == expected_subdir
assert sorted(zp2.resource_listdir('/')) == expected_subdir
assert zp2.resource_listdir('subdir') == []
assert zp2.resource_listdir('subdir/') == []
def test_resource_filename_rewrites_on_change(self):
"""
If a previous call to get_resource_filename has saved the file, but
......@@ -97,16 +135,42 @@ class TestZipProvider(object):
manager.cleanup_resources()
class TestResourceManager(object):
class TestResourceManager:
def test_get_cache_path(self):
mgr = pkg_resources.ResourceManager()
path = mgr.get_cache_path('foo')
type_ = str(type(path))
message = "Unexpected type from get_cache_path: " + type_
assert isinstance(path, (unicode, str)), message
assert isinstance(path, string_types), message
def test_get_cache_path_race(self, tmpdir):
# Patch to os.path.isdir to create a race condition
def patched_isdir(dirname, unpatched_isdir=pkg_resources.isdir):
patched_isdir.dirnames.append(dirname)
was_dir = unpatched_isdir(dirname)
if not was_dir:
os.makedirs(dirname)
return was_dir
patched_isdir.dirnames = []
# Get a cache path with a "race condition"
mgr = pkg_resources.ResourceManager()
mgr.set_extraction_path(str(tmpdir))
archive_name = os.sep.join(('foo', 'bar', 'baz'))
with mock.patch.object(pkg_resources, 'isdir', new=patched_isdir):
mgr.get_cache_path(archive_name)
# Because this test relies on the implementation details of this
# function, these assertions are a sentinel to ensure that the
# test suite will not fail silently if the implementation changes.
called_dirnames = patched_isdir.dirnames
assert len(called_dirnames) == 2
assert called_dirnames[0].split(os.sep)[-2:] == ['foo', 'bar']
assert called_dirnames[1].split(os.sep)[-1:] == ['foo']
class TestIndependence:
"""
Tests to ensure that pkg_resources runs independently from setuptools.
"""
......@@ -119,14 +183,16 @@ class TestIndependence:
lines = (
'import pkg_resources',
'import sys',
'assert "setuptools" not in sys.modules, '
'"setuptools was imported"',
(
'assert "setuptools" not in sys.modules, '
'"setuptools was imported"'
),
)
cmd = [sys.executable, '-c', '; '.join(lines)]
subprocess.check_call(cmd)
class TestDeepVersionLookupDistutils(object):
class TestDeepVersionLookupDistutils:
@pytest.fixture
def env(self, tmpdir):
"""
......@@ -170,3 +236,56 @@ class TestDeepVersionLookupDistutils(object):
req = pkg_resources.Requirement.parse('foo>=1.9')
dist = pkg_resources.WorkingSet([env.paths['lib']]).find(req)
assert dist.version == version
@pytest.mark.parametrize(
'unnormalized, normalized',
[
('foo', 'foo'),
('foo/', 'foo'),
('foo/bar', 'foo/bar'),
('foo/bar/', 'foo/bar'),
],
)
def test_normalize_path_trailing_sep(self, unnormalized, normalized):
"""Ensure the trailing slash is cleaned for path comparison.
See pypa/setuptools#1519.
"""
result_from_unnormalized = pkg_resources.normalize_path(unnormalized)
result_from_normalized = pkg_resources.normalize_path(normalized)
assert result_from_unnormalized == result_from_normalized
@pytest.mark.skipif(
os.path.normcase('A') != os.path.normcase('a'),
reason='Testing case-insensitive filesystems.',
)
@pytest.mark.parametrize(
'unnormalized, normalized',
[
('MiXeD/CasE', 'mixed/case'),
],
)
def test_normalize_path_normcase(self, unnormalized, normalized):
"""Ensure mixed case is normalized on case-insensitive filesystems.
"""
result_from_unnormalized = pkg_resources.normalize_path(unnormalized)
result_from_normalized = pkg_resources.normalize_path(normalized)
assert result_from_unnormalized == result_from_normalized
@pytest.mark.skipif(
os.path.sep != '\\',
reason='Testing systems using backslashes as path separators.',
)
@pytest.mark.parametrize(
'unnormalized, expected',
[
('forward/slash', 'forward\\slash'),
('forward/slash/', 'forward\\slash'),
('backward\\slash\\', 'backward\\slash'),
],
)
def test_normalize_path_backslash_sep(self, unnormalized, expected):
"""Ensure path seps are cleaned on backslash path sep systems.
"""
result = pkg_resources.normalize_path(unnormalized)
assert result.endswith(expected)
This diff is collapsed.
import inspect
import re
import textwrap
import functools
import pytest
......@@ -8,6 +9,8 @@ import pkg_resources
from .test_resources import Metadata
__metaclass__ = type
def strip_comments(s):
return '\n'.join(
......@@ -15,6 +18,7 @@ def strip_comments(s):
if l.strip() and not l.strip().startswith('#')
)
def parse_distributions(s):
'''
Parse a series of distribution specs of the form:
......@@ -31,10 +35,11 @@ def parse_distributions(s):
yield 2 distributions:
- project_name=foo, version=0.2
- project_name=bar, version=1.0, requires=['foo>=3.0', 'baz; extra=="feature"']
- project_name=bar, version=1.0,
requires=['foo>=3.0', 'baz; extra=="feature"']
'''
s = s.strip()
for spec in re.split('\n(?=[^\s])', s):
for spec in re.split(r'\n(?=[^\s])', s):
if not spec:
continue
fields = spec.split('\n', 1)
......@@ -42,7 +47,7 @@ def parse_distributions(s):
name, version = fields.pop(0).split('-')
if fields:
requires = textwrap.dedent(fields.pop(0))
metadata=Metadata(('requires.txt', requires))
metadata = Metadata(('requires.txt', requires))
else:
metadata = None
dist = pkg_resources.Distribution(project_name=name,
......@@ -51,7 +56,7 @@ def parse_distributions(s):
yield dist
class FakeInstaller(object):
class FakeInstaller:
def __init__(self, installable_dists):
self._installable_dists = installable_dists
......@@ -84,7 +89,7 @@ def parametrize_test_working_set_resolve(*test_list):
):
idlist.append(id_)
expected = strip_comments(expected.strip())
if re.match('\w+$', expected):
if re.match(r'\w+$', expected):
expected = getattr(pkg_resources, expected)
assert issubclass(expected, Exception)
else:
......@@ -467,7 +472,8 @@ def test_working_set_resolve(installed_dists, installable_dists, requirements,
replace_conflicting, resolved_dists_or_exception):
ws = pkg_resources.WorkingSet([])
list(map(ws.add, installed_dists))
resolve_call = lambda: ws.resolve(
resolve_call = functools.partial(
ws.resolve,
requirements, installer=FakeInstaller(installable_dists),
replace_conflicting=replace_conflicting,
)
......
[build-system]
requires = ["wheel"]
build-backend = "setuptools.build_meta"
[tool.towncrier]
package = "setuptools"
package_dir = "setuptools"
filename = "CHANGES.rst"
directory = "changelog.d"
title_format = "v{version}"
issue_format = "#{issue}"
template = "towncrier_template.rst"
underlines = ["-"]
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true
[[tool.towncrier.type]]
directory = "breaking"
name = "Breaking Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "change"
name = "Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "doc"
name = "Documentation changes"
showcontent = true
[[tool.towncrier.type]]
directory = "misc"
name = "Misc"
showcontent = true
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.
packaging==16.8
pyparsing==2.2.1
six==1.10.0
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
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.
File mode changed from 100755 to 100644
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