Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
setuptools
Commits
0551421f
Commit
0551421f
authored
Jan 27, 2019
by
Jason R. Coombs
Committed by
GitHub
Jan 27, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into license-fix-357
parents
28872fc9
78fd7302
Changes
63
Hide whitespace changes
Inline
Side-by-side
Showing
63 changed files
with
1935 additions
and
573 deletions
+1935
-573
.mergify.yml
.mergify.yml
+11
-0
.travis.yml
.travis.yml
+4
-1
CHANGES.rst
CHANGES.rst
+48
-0
MANIFEST.in
MANIFEST.in
+1
-1
README.rst
README.rst
+0
-4
docs/_templates/indexsidebar.html
docs/_templates/indexsidebar.html
+8
-1
docs/developer-guide.txt
docs/developer-guide.txt
+14
-3
docs/ez_setup.txt
docs/ez_setup.txt
+195
-0
docs/index.txt
docs/index.txt
+1
-1
docs/python3.txt
docs/python3.txt
+1
-1
docs/requirements.txt
docs/requirements.txt
+1
-1
docs/roadmap.txt
docs/roadmap.txt
+3
-8
docs/setuptools.txt
docs/setuptools.txt
+120
-193
pkg_resources/__init__.py
pkg_resources/__init__.py
+13
-2
pkg_resources/tests/test_pkg_resources.py
pkg_resources/tests/test_pkg_resources.py
+53
-0
pkg_resources/tests/test_resources.py
pkg_resources/tests/test_resources.py
+10
-1
pyproject.toml
pyproject.toml
+1
-0
setup.cfg
setup.cfg
+1
-1
setup.py
setup.py
+2
-1
setuptools/__init__.py
setuptools/__init__.py
+38
-1
setuptools/_deprecation_warning.py
setuptools/_deprecation_warning.py
+7
-0
setuptools/build_meta.py
setuptools/build_meta.py
+14
-13
setuptools/command/develop.py
setuptools/command/develop.py
+14
-11
setuptools/command/easy_install.py
setuptools/command/easy_install.py
+11
-4
setuptools/command/egg_info.py
setuptools/command/egg_info.py
+12
-2
setuptools/command/upload.py
setuptools/command/upload.py
+144
-1
setuptools/config.py
setuptools/config.py
+71
-23
setuptools/dist.py
setuptools/dist.py
+231
-37
setuptools/monkey.py
setuptools/monkey.py
+6
-6
setuptools/package_index.py
setuptools/package_index.py
+10
-6
setuptools/pep425tags.py
setuptools/pep425tags.py
+1
-1
setuptools/py36compat.py
setuptools/py36compat.py
+0
-82
setuptools/ssl_support.py
setuptools/ssl_support.py
+1
-1
setuptools/tests/files.py
setuptools/tests/files.py
+6
-3
setuptools/tests/server.py
setuptools/tests/server.py
+8
-6
setuptools/tests/test_build_clib.py
setuptools/tests/test_build_clib.py
+4
-5
setuptools/tests/test_build_meta.py
setuptools/tests/test_build_meta.py
+64
-8
setuptools/tests/test_config.py
setuptools/tests/test_config.py
+120
-8
setuptools/tests/test_depends.py
setuptools/tests/test_depends.py
+9
-9
setuptools/tests/test_dist.py
setuptools/tests/test_dist.py
+121
-1
setuptools/tests/test_easy_install.py
setuptools/tests/test_easy_install.py
+19
-1
setuptools/tests/test_egg_info.py
setuptools/tests/test_egg_info.py
+99
-4
setuptools/tests/test_find_packages.py
setuptools/tests/test_find_packages.py
+6
-5
setuptools/tests/test_install_scripts.py
setuptools/tests/test_install_scripts.py
+4
-2
setuptools/tests/test_integration.py
setuptools/tests/test_integration.py
+14
-9
setuptools/tests/test_manifest.py
setuptools/tests/test_manifest.py
+67
-67
setuptools/tests/test_msvc.py
setuptools/tests/test_msvc.py
+3
-2
setuptools/tests/test_namespaces.py
setuptools/tests/test_namespaces.py
+1
-2
setuptools/tests/test_packageindex.py
setuptools/tests/test_packageindex.py
+69
-5
setuptools/tests/test_pep425tags.py
setuptools/tests/test_pep425tags.py
+3
-1
setuptools/tests/test_sandbox.py
setuptools/tests/test_sandbox.py
+2
-1
setuptools/tests/test_sdist.py
setuptools/tests/test_sdist.py
+44
-4
setuptools/tests/test_setuptools.py
setuptools/tests/test_setuptools.py
+6
-3
setuptools/tests/test_test.py
setuptools/tests/test_test.py
+0
-5
setuptools/tests/test_upload.py
setuptools/tests/test_upload.py
+170
-0
setuptools/tests/test_virtualenv.py
setuptools/tests/test_virtualenv.py
+11
-3
setuptools/tests/test_wheel.py
setuptools/tests/test_wheel.py
+2
-0
setuptools/tests/test_windows_wrappers.py
setuptools/tests/test_windows_wrappers.py
+10
-3
setuptools/unicode_utils.py
setuptools/unicode_utils.py
+13
-0
setuptools/wheel.py
setuptools/wheel.py
+7
-6
tests/manual_test.py
tests/manual_test.py
+1
-1
tests/requirements.txt
tests/requirements.txt
+4
-1
tox.ini
tox.ini
+1
-1
No files found.
.mergify.yml
0 → 100644
View file @
0551421f
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
.travis.yml
View file @
0551421f
...
...
@@ -30,7 +30,9 @@ jobs:
install
:
skip
script
:
skip
after_success
:
true
before_deploy
:
python bootstrap.py
before_deploy
:
-
python bootstrap.py
-
"
!
grep
pyc
setuptools.egg-info/SOURCES.txt"
deploy
:
provider
:
pypi
on
:
...
...
@@ -58,6 +60,7 @@ install:
# update egg_info based on setup.py in checkout
-
python bootstrap.py
-
"
!
grep
pyc
setuptools.egg-info/SOURCES.txt"
script
:
-
|
...
...
CHANGES.rst
View file @
0551421f
v40
.7.0
-------
*
#
1551
:
File
inputs
for
the
`
license
`
field
in
`
setup
.
cfg
`
files
now
explicitly
raise
an
error
.
*
#
1180
:
Add
support
for
non
-
ASCII
in
setup
.
cfg
(#
1062
).
Add
support
for
native
strings
on
some
parameters
(#
1136
).
*
#
1499
:
``
setuptools
.
package_index
``
no
longer
relies
on
the
deprecated
``
urllib
.
parse
.
splituser
``
per
Python
#
27485.
*
#
1544
:
Added
tests
for
PackageIndex
.
download
(
for
git
URLs
).
*
#
1625
:
In
PEP
517
build_meta
builder
,
ensure
that
sdists
are
built
as
gztar
per
the
spec
.
v40
.6.3
-------
*
#
1594
:
PEP
517
backend
no
longer
declares
setuptools
as
a
dependency
as
it
can
be
assumed
.
v40
.6.2
-------
*
#
1592
:
Fix
invalid
dependency
on
external
six
module
(
instead
of
vendored
version
).
v40
.6.1
-------
*
#
1590
:
Fixed
regression
where
packages
without
``
author
``
or
``
author_email
``
fields
generated
malformed
package
metadata
.
v40
.6.0
-------
*
#
1541
:
Officially
deprecated
the
``
requires
``
parameter
in
``
setup
()``.
*
#
1519
:
In
``
pkg_resources
.
normalize_path
``,
additional
path
normalization
is
now
performed
to
ensure
path
values
to
a
directory
is
always
the
same
,
preventing
false
positives
when
checking
scripts
have
a
consistent
prefix
to
set
up
on
Windows
.
*
#
1545
:
Changed
the
warning
class
of
all
deprecation
warnings
;
deprecation
warning
classes
are
no
longer
derived
from
``
DeprecationWarning
``
and
are
thus
visible
by
default
.
*
#
1554
:
``
build_meta
.
build_sdist
``
now
includes
``
setup
.
py
``
in
source
distributions
by
default
.
*
#
1576
:
Started
monkey
-
patching
``
get_metadata_version
``
and
``
read_pkg_file
``
onto
``
distutils
.
DistributionMetadata
``
to
retain
the
correct
version
on
the
``
PKG
-
INFO
``
file
in
the
(
deprecated
)
``
upload
``
command
.
*
#
1533
:
Restricted
the
``
recursive
-
include
setuptools
/
_vendor
``
to
contain
only
.
py
and
.
txt
files
.
*
#
1395
:
Changed
Pyrex
references
to
Cython
in
the
documentation
.
*
#
1456
:
Documented
that
the
``
rpmbuild
``
packages
is
required
for
the
``
bdist_rpm
``
command
.
*
#
1537
:
Documented
how
to
use
``
setup
.
cfg
``
for
``
src
/
layouts
``
*
#
1539
:
Added
minimum
version
column
in
``
setup
.
cfg
``
metadata
table
.
*
#
1552
:
Fixed
a
minor
typo
in
the
python
2
/
3
compatibility
documentation
.
*
#
1553
:
Updated
installation
instructions
to
point
to
``
pip
install
``
instead
of
``
ez_setup
.
py
``.
*
#
1560
:
Updated
``
setuptools
``
distribution
documentation
to
remove
some
outdated
information
.
*
#
1564
:
Documented
``
setup
.
cfg
``
minimum
version
for
version
and
project_urls
.
*
#
1572
:
Added
the
``
concurrent
.
futures
``
backport
``
futures
``
to
the
Python
2.7
test
suite
requirements
.
v40
.5.0
-------
...
...
MANIFEST.in
View file @
0551421f
...
...
@@ -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
...
...
README.rst
View file @
0551421f
...
...
@@ -23,10 +23,6 @@ See the `Installation Instructions
User's Guide for instructions on installing, upgrading, and uninstalling
Setuptools.
The project is `maintained at GitHub <https://github.com/pypa/setuptools>`_
by the `Setuptools Developers
<https://github.com/orgs/pypa/teams/setuptools-developers>`_.
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
...
...
docs/_templates/indexsidebar.html
View file @
0551421f
...
...
@@ -5,4 +5,11 @@
<h3>
Questions? Suggestions? Contributions?
</h3>
<p>
Visit the
<a
href=
"https://github.com/pypa/setuptools"
>
Setuptools project page
</a>
</p>
<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>
docs/developer-guide.txt
View file @
0551421f
...
...
@@ -67,8 +67,8 @@ 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 managment, so when making a PR, please add a news fragment in the
``changelog.d/`` folder. Changelog files are written in
Restructured
Text and
for changelog manag
e
ment, so when making a PR, please add a news fragment in the
``changelog.d/`` folder. Changelog files are written in
reStructured
Text 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:
...
...
@@ -76,7 +76,7 @@ They should be named ``<pr_number>.<category>.rst``, where the categories are:
- ``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 o
f
behavior
- ``deprecation``: For deprecations of an existing feature o
r
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
...
...
@@ -89,6 +89,17 @@ code changes. See the following for an example news fragment:
$ cat changelog.d/1288.change.rst
Add support for maintainer in PKG-INFO
-------------------
Auto-Merge Requests
-------------------
To support running all code through CI, even lightweight contributions,
the project employs Mergify to auto-merge pull requests tagged as
auto-merge.
Use ``hub pull-request -l auto-merge`` to create such a pull request
from the command line after pushing a new branch.
-------
Testing
-------
...
...
docs/ez_setup.txt
0 → 100644
View file @
0551421f
: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.
docs/index.txt
View file @
0551421f
...
...
@@ -17,9 +17,9 @@ Documentation content:
:maxdepth: 2
setuptools
easy_install
pkg_resources
python3
development
roadmap
Deprecated: Easy Install <easy_install>
history
docs/python3.txt
View file @
0551421f
...
...
@@ -9,7 +9,7 @@ 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
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.
...
...
docs/requirements.txt
View file @
0551421f
sphinx!=1.8.0
rst.linker>=1.9
jaraco.packaging>=
3.2
jaraco.packaging>=
6.1
setuptools>=34
docs/roadmap.txt
View file @
0551421f
...
...
@@ -2,11 +2,6 @@
Roadmap
=======
Setuptools has the following large-scale goals on the roadmap:
- Mature declarative config to supersede imperative config in
all supported use-cases and harmonize with pyproject.toml
syntax.
- Deprecate and remove setup_requires and easy_install in
favor of PEP 518 build requirements and pip install.
- Adopt the Distutils package and stop monkeypatching stdlib.
Setuptools maintains a series of `milestones
<https://github.com/pypa/setuptools/milestones>`_ to track
a roadmap of large-scale goals.
docs/setuptools.txt
View file @
0551421f
...
...
@@ -41,9 +41,9 @@ Feature Highlights:
files for any number of "main" functions in your project. (Note: this is not
a py2exe replacement; the .exe files rely on the local Python installation.)
* Transparent
Pyrex
support, so that your setup.py can list ``.pyx`` files and
still work even when the end-user doesn't have
Pyrex
installed (as long as
you include the
Pyrex
-generated C in your source distribution)
* Transparent
Cython
support, so that your setup.py can list ``.pyx`` files and
still work even when the end-user doesn't have
Cython
installed (as long as
you include the
Cython
-generated C in your source distribution)
* Command aliases - create project-specific, per-user, or site-wide shortcut
names for commonly used commands and options
...
...
@@ -73,23 +73,17 @@ Developer's Guide
Installing ``setuptools``
=========================
Please follow the `EasyInstall Installation Instructions`_ to install the
current stable version of setuptools. In particular, be sure to read the
section on `Custom Installation Locations`_ if you are installing anywhere
other than Python's ``site-packages`` directory.
.. _EasyInstall Installation Instructions: easy_install.html
.. _
EasyInstall Installation Instructions: easy_install.html#installation-instructions
.. _
Custom Installation Locations: easy_install.html
.. _
Custom Installation Locations: easy_install.html#custom-installation-locations
.. _
Installing Packages: https://packaging.python.org/tutorials/installing-packages/
If you want the current in-development version of setuptools, you should first
install a stable version, and then run::
To install the latest version of setuptools, use::
ez_setup.py setuptools==dev
This will download and install the latest development (i.e. unstable) version
of setuptools from the Python Subversion sandbox.
pip install -U setuptools
Refer to `Installing Packages`_ guide for more information.
Basic Use
=========
...
...
@@ -1229,121 +1223,53 @@ the quoted part.
Distributing a ``setuptools``-based project
===========================================
Using ``setuptools``... Without bundling it!
---------------------------------------------
Detailed instructions to distribute a setuptools project can be found at
`Packaging project tutorials`_.
..
warning:: **ez_setup** is deprecated in favor of PIP with **PEP-518** support.
..
_Packaging project tutorials: https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives
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:
Before you begin, make sure you have the latest versions of setuptools and wheel::
.. code-block:: python
python3 -m pip install --user --upgrade setuptools wheel
import ez_setup
ez_setup.use_setuptools()
To build a setuptools project, run this command from the same directory where
setup.py is located::
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).
python3 setup.py sdist bdist_wheel
(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.)
This will generate distribution archives in the `dist` directory.
Before you upload the generated archives make sure you're registered on
https://test.pypi.org/account/register/. You will also need to verify your email
to be able to upload any packages.
You should install twine to be able to upload packages::
What Your Users Should Know
---------------------------
python3 -m pip install --user --upgrade setuptools wheel
Now, to upload these archives, run::
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
To install your newly uploaded package ``example_pkg``, you can use pip::
python3 -m pip install --index-url https://test.pypi.org/simple/ example_pkg
If you have issues at any point, please refer to `Packaging project tutorials`_
for clarification.
Distributing legacy ``setuptools`` projects using ez_setup.py
-------------------------------------------------------------
.. warning:: **ez_setup** is deprecated in favor of PIP with **PEP-518** support.
Distributing packages using the legacy ``ez_setup.py`` and ``easy_install`` is
deprecated in favor of PIP. Please consider migrating to using pip and twine based
distribution.
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.
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.
However, if you still have any ``ez_setup`` based packages, documentation for
ez_setup based distributions can be found at `ez_setup distribution guide`_.
.. _ez_setup distribution guide: ez_setup.html
Setting the ``zip_safe`` flag
-----------------------------
...
...
@@ -1651,29 +1577,43 @@ See the sections below on the `egg_info`_ and `alias`_ commands for more ideas.
Distributing Extensions compiled with
Pyrex
-------------------------------------------
Distributing Extensions compiled with
Cython
-------------------------------------------
-
``setuptools`` includes transparent support for building Pyrex extensions, as
long as you define your extensions using ``setuptools.Extension``, *not*
``distutils.Extension``. You must also not import anything from Pyrex in
your setup script.
``setuptools`` will detect at build time whether Cython is installed or not.
If Cython is not found ``setuptools`` will ignore pyx files.
To ensure Cython is available, include Cython in the build-requires section
of your pyproject.toml::
[build-system]
requires=[..., 'cython']
Built with pip 10 or later, that declaration is sufficient to include Cython
in the build. For broader compatibility, declare the dependency in your
setup-requires of setup.cfg::
[options]
setup_requires =
...
cython
As long as Cython is present in the build environment, ``setuptools`` includes
transparent support for building Cython extensions, as
long as extensions are defined using ``setuptools.Extension``.
If you follow these rules, you can safely list ``.pyx`` files as the source
of your ``Extension`` objects in the setup script. ``setuptools`` will detect
at build time whether Pyrex is installed or not. If it is, then ``setuptools``
will use it. If not, then ``setuptools`` will silently change the
``Extension`` objects to refer to the ``.c`` counterparts of the ``.pyx``
files, so that the normal distutils C compilation process will occur.
of your ``Extension`` objects in the setup script. If it is, then ``setuptools``
will use it.
Of course, for this to work, your source distributions must include the C
code generated by
Pyrex
, as well as your original ``.pyx`` files. This means
code generated by
Cython
, as well as your original ``.pyx`` files. This means
that you will probably want to include current ``.c`` files in your revision
control system, rebuilding them whenever you check changes in for the ``.pyx``
source files. This will ensure that people tracking your project in a revision
control system will be able to build it even if they don't have
Pyrex
control system will be able to build it even if they don't have
Cython
installed, and that your source releases will be similarly usable with or
without
Pyrex
.
without
Cython
.
-----------------
...
...
@@ -2046,52 +1986,6 @@ specified in ``setup.cfg``::
(Notice that ``egg_info`` must always appear on the command line *before* any
commands that you want the version changes to apply to.)
.. _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.
.. _rotate:
``rotate`` - Delete outdated distribution files
...
...
@@ -2400,6 +2294,35 @@ Metadata and options are set in the config sections of the same name.
* Unknown keys are ignored.
Using a ``src/`` layout
=======================
One commonly used package configuration has all the module source code in a
subdirectory (often called the ``src/`` layout), like this::
├── src
│ └── mypackage
│ ├── __init__.py
│ └── mod1.py
├── setup.py
└── setup.cfg
You can set up your ``setup.cfg`` to automatically find all your packages in
the subdirectory like this:
.. code-block:: ini
# This example contains just the necessary options for a src-layout, set up
# the rest of the file as described above.
[options]
package_dir=
=src
packages=find:
[options.packages.find]
where=src
Specifying values
=================
...
...
@@ -2434,42 +2357,45 @@ Metadata
The aliases given below are supported for compatibility reasons,
but their use is not advised.
============================== ================= =====
Key Aliases Type
============================== ================= =====
============================== ================= =====
============ =============== =====
Key Aliases Type
Minimum Version Notes
============================== ================= =====
============ =============== =====
name str
version attr:, file:, str
version attr:, file:, str
39.2.0 (1)
url home-page str
download_url download-url str
project_urls dict
project_urls dict
38.3.0
author str
author_email author-email str
maintainer str
maintainer_email maintainer-email str
classifiers classifier file:, list-comma
license
file:,
str
license str
license_file str
description summary file:, str
long_description long-description file:, str
long_description_content_type str
long_description_content_type str
38.6.0
keywords list-comma
platforms platform list-comma
provides list-comma
requires list-comma
obsoletes list-comma
============================== ================= =====
============================== ================= =====
============ =============== =====
.. note::
A version loaded using the ``file:`` directive must comply with PEP 440.
It is easy to accidentally put something other than a valid version
string in such a file, so validation is stricter in this case.
Notes:
1. The `version` file attribute has only been supported since 39.2.0.
Options
-------
======================= =====
Key Type
======================= =====
======================= =====
============================== =============== =====
Key Type
Minimum Version Notes
======================= =====
============================== =============== =====
zip_safe bool
setup_requires list-semi
install_requires list-semi
...
...
@@ -2491,7 +2417,8 @@ package_data section
exclude_package_data section
namespace_packages list-comma
py_modules list-comma
======================= =====
data_files dict 40.6.0
======================= =================================== =============== =====
.. note::
...
...
@@ -2500,7 +2427,7 @@ py_modules list-comma
accepts the same keys as the `setuptools.find_packages` and the
`setuptools.find_namespace_packages` function:
``where``, ``include``, and ``exclude``.
**find_namespace directive** - The ``find_namespace:`` directive is supported since Python >=3.3.
...
...
pkg_resources/__init__.py
View file @
0551421f
...
...
@@ -238,6 +238,9 @@ __all__ = [
'register_finder'
,
'register_namespace_handler'
,
'register_loader_type'
,
'fixup_namespace_packages'
,
'get_importer'
,
# Warnings
'PkgResourcesDeprecationWarning'
,
# Deprecated/backward compatibility only
'run_main'
,
'AvailableDistributions'
,
]
...
...
@@ -2228,7 +2231,7 @@ 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(
_cygwin_patch(filename
)))
return os.path.normcase(os.path.realpath(
os.path.normpath(_cygwin_patch(filename)
)))
def _cygwin_patch(filename): # pragma: nocover
...
...
@@ -2335,7 +2338,7 @@ class EntryPoint:
warnings.warn(
"
Parameters
to
load
are
deprecated
.
Call
.
resolve
and
"
"
.
require
separately
.
",
DeprecationWarning,
PkgResources
DeprecationWarning,
stacklevel=2,
)
if require:
...
...
@@ -3158,3 +3161,11 @@ def _initialize_master_working_set():
# match order
list(map(working_set.add_entry, sys.path))
globals().update(locals())
class PkgResourcesDeprecationWarning(Warning):
"""
Base class for warning about deprecations in ``pkg_resources``
This class is not derived from ``DeprecationWarning``, and as such is
visible by default.
"""
pkg_resources/tests/test_pkg_resources.py
View file @
0551421f
...
...
@@ -236,3 +236,56 @@ class TestDeepVersionLookupDistutils:
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
)
pkg_resources/tests/test_resources.py
View file @
0551421f
...
...
@@ -15,7 +15,7 @@ import pkg_resources
from
pkg_resources
import
(
parse_requirements
,
VersionConflict
,
parse_version
,
Distribution
,
EntryPoint
,
Requirement
,
safe_version
,
safe_name
,
WorkingSet
)
WorkingSet
,
PkgResourcesDeprecationWarning
)
# from Python 3.6 docs.
...
...
@@ -492,6 +492,15 @@ class TestEntryPoints:
with
pytest
.
raises
(
ValueError
):
EntryPoint
.
parse_map
(
self
.
submap_str
)
def
testDeprecationWarnings
(
self
):
ep
=
EntryPoint
(
"foo"
,
"pkg_resources.tests.test_resources"
,
[
"TestEntryPoints"
],
[
"x"
]
)
with
pytest
.
warns
(
pkg_resources
.
PkgResourcesDeprecationWarning
):
ep
.
load
(
require
=
False
)
class
TestRequirements
:
def
testBasics
(
self
):
...
...
pyproject.toml
View file @
0551421f
[build-system]
requires
=
["wheel"]
build-backend
=
"setuptools.build_meta"
[tool.towncrier]
package
=
"setuptools"
...
...
setup.cfg
View file @
0551421f
[bumpversion]
current_version = 40.
5
.0
current_version = 40.
7
.0
commit = True
tag = True
...
...
setup.py
View file @
0551421f
...
...
@@ -89,7 +89,7 @@ def pypi_link(pkg_filename):
setup_params
=
dict
(
name
=
"setuptools"
,
version
=
"40.
5
.0"
,
version
=
"40.
7
.0"
,
description
=
(
"Easily download, build, install, upgrade, and uninstall "
"Python packages"
...
...
@@ -164,6 +164,7 @@ setup_params = dict(
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Topic :: Software Development :: Libraries :: Python Modules
Topic :: System :: Archiving :: Packaging
Topic :: System :: Systems Administration
...
...
setuptools/__init__.py
View file @
0551421f
...
...
@@ -5,10 +5,14 @@ import sys
import
functools
import
distutils.core
import
distutils.filelist
import
re
from
distutils.errors
import
DistutilsOptionError
from
distutils.util
import
convert_path
from
fnmatch
import
fnmatchcase
from
setuptools.extern.six
import
PY3
from
._deprecation_warning
import
SetuptoolsDeprecationWarning
from
setuptools.extern.six
import
PY3
,
string_types
from
setuptools.extern.six.moves
import
filter
,
map
import
setuptools.version
...
...
@@ -22,6 +26,7 @@ __metaclass__ = type
__all__
=
[
'setup'
,
'Distribution'
,
'Feature'
,
'Command'
,
'Extension'
,
'Require'
,
'SetuptoolsDeprecationWarning'
,
'find_packages'
]
...
...
@@ -158,6 +163,37 @@ class Command(_Command):
_Command
.
__init__
(
self
,
dist
)
vars
(
self
).
update
(
kw
)
def
_ensure_stringlike
(
self
,
option
,
what
,
default
=
None
):
val
=
getattr
(
self
,
option
)
if
val
is
None
:
setattr
(
self
,
option
,
default
)
return
default
elif
not
isinstance
(
val
,
string_types
):
raise
DistutilsOptionError
(
"'%s' must be a %s (got `%s`)"
%
(
option
,
what
,
val
))
return
val
def
ensure_string_list
(
self
,
option
):
r"""Ensure that 'option' is a list of strings. If 'option' is
currently a string, we split it either on /,\
s*/ o
r /\
s+/, so
"foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
["foo", "bar", "baz"].
"""
val
=
getattr
(
self
,
option
)
if
val
is
None
:
return
elif
isinstance
(
val
,
string_types
):
setattr
(
self
,
option
,
re
.
split
(
r',\
s*|
\s+'
,
val
))
else
:
if
isinstance
(
val
,
list
):
ok
=
all
(
isinstance
(
v
,
string_types
)
for
v
in
val
)
else
:
ok
=
False
if
not
ok
:
raise
DistutilsOptionError
(
"'%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
)
vars
(
cmd
).
update
(
kw
)
...
...
@@ -188,4 +224,5 @@ def findall(dir=os.curdir):
return
list
(
files
)
# Apply monkey patches
monkey
.
patch_all
()
setuptools/_deprecation_warning.py
0 → 100644
View file @
0551421f
class
SetuptoolsDeprecationWarning
(
Warning
):
"""
Base class for warning deprecations in ``setuptools``
This class is not derived from ``DeprecationWarning``, and as such is
visible by default.
"""
setuptools/build_meta.py
View file @
0551421f
...
...
@@ -112,12 +112,12 @@ def _get_immediate_subdirectories(a_dir):
def
get_requires_for_build_wheel
(
config_settings
=
None
):
config_settings
=
_fix_config
(
config_settings
)
return
_get_build_requires
(
config_settings
,
requirements
=
[
'
setuptools'
,
'
wheel'
])
return
_get_build_requires
(
config_settings
,
requirements
=
[
'wheel'
])
def
get_requires_for_build_sdist
(
config_settings
=
None
):
config_settings
=
_fix_config
(
config_settings
)
return
_get_build_requires
(
config_settings
,
requirements
=
[
'setuptools'
])
return
_get_build_requires
(
config_settings
,
requirements
=
[])
def
prepare_metadata_for_build_wheel
(
metadata_directory
,
config_settings
=
None
):
...
...
@@ -149,6 +149,15 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
return
dist_infos
[
0
]
def
_file_with_extension
(
directory
,
extension
):
matching
=
(
f
for
f
in
os
.
listdir
(
directory
)
if
f
.
endswith
(
extension
)
)
file
,
=
matching
return
file
def
build_wheel
(
wheel_directory
,
config_settings
=
None
,
metadata_directory
=
None
):
config_settings
=
_fix_config
(
config_settings
)
...
...
@@ -160,23 +169,15 @@ def build_wheel(wheel_directory, config_settings=None,
shutil
.
rmtree
(
wheel_directory
)
shutil
.
copytree
(
'dist'
,
wheel_directory
)
wheels
=
[
f
for
f
in
os
.
listdir
(
wheel_directory
)
if
f
.
endswith
(
'.whl'
)]
assert
len
(
wheels
)
==
1
return
wheels
[
0
]
return
_file_with_extension
(
wheel_directory
,
'.whl'
)
def
build_sdist
(
sdist_directory
,
config_settings
=
None
):
config_settings
=
_fix_config
(
config_settings
)
sdist_directory
=
os
.
path
.
abspath
(
sdist_directory
)
sys
.
argv
=
sys
.
argv
[:
1
]
+
[
'sdist'
]
+
\
sys
.
argv
=
sys
.
argv
[:
1
]
+
[
'sdist'
,
'--formats'
,
'gztar'
]
+
\
config_settings
[
"--global-option"
]
+
\
[
"--dist-dir"
,
sdist_directory
]
_run_setup
()
sdists
=
[
f
for
f
in
os
.
listdir
(
sdist_directory
)
if
f
.
endswith
(
'.tar.gz'
)]
assert
len
(
sdists
)
==
1
return
sdists
[
0
]
return
_file_with_extension
(
sdist_directory
,
'.tar.gz'
)
setuptools/command/develop.py
View file @
0551421f
...
...
@@ -7,7 +7,7 @@ import io
from
setuptools.extern
import
six
from
pkg_resources
import
Distribution
,
PathMetadata
,
normalize_path
import
pkg_resources
from
setuptools.command.easy_install
import
easy_install
from
setuptools
import
namespaces
import
setuptools
...
...
@@ -65,9 +65,9 @@ class develop(namespaces.DevelopInstaller, easy_install):
if
self
.
egg_path
is
None
:
self
.
egg_path
=
os
.
path
.
abspath
(
ei
.
egg_base
)
target
=
normalize_path
(
self
.
egg_base
)
egg_path
=
normalize_path
(
os
.
path
.
join
(
self
.
install_dir
,
self
.
egg_path
))
target
=
pkg_resources
.
normalize_path
(
self
.
egg_base
)
egg_path
=
pkg_resources
.
normalize_path
(
os
.
path
.
join
(
self
.
install_dir
,
self
.
egg_path
))
if
egg_path
!=
target
:
raise
DistutilsOptionError
(
"--egg-path must be a relative path from the install"
...
...
@@ -75,9 +75,9 @@ class develop(namespaces.DevelopInstaller, easy_install):
)
# Make a distribution for the package's source
self
.
dist
=
Distribution
(
self
.
dist
=
pkg_resources
.
Distribution
(
target
,
PathMetadata
(
target
,
os
.
path
.
abspath
(
ei
.
egg_info
)),
pkg_resources
.
PathMetadata
(
target
,
os
.
path
.
abspath
(
ei
.
egg_info
)),
project_name
=
ei
.
egg_name
)
...
...
@@ -97,13 +97,14 @@ class develop(namespaces.DevelopInstaller, easy_install):
path_to_setup
=
egg_base
.
replace
(
os
.
sep
,
'/'
).
rstrip
(
'/'
)
if
path_to_setup
!=
os
.
curdir
:
path_to_setup
=
'../'
*
(
path_to_setup
.
count
(
'/'
)
+
1
)
resolved
=
normalize_path
(
resolved
=
pkg_resources
.
normalize_path
(
os
.
path
.
join
(
install_dir
,
egg_path
,
path_to_setup
)
)
if
resolved
!=
normalize_path
(
os
.
curdir
):
if
resolved
!=
pkg_resources
.
normalize_path
(
os
.
curdir
):
raise
DistutilsOptionError
(
"Can't get a consistent path to setup script from"
" installation directory"
,
resolved
,
normalize_path
(
os
.
curdir
))
" installation directory"
,
resolved
,
pkg_resources
.
normalize_path
(
os
.
curdir
))
return
path_to_setup
def
install_for_development
(
self
):
...
...
@@ -114,7 +115,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
self
.
reinitialize_command
(
'build_py'
,
inplace
=
0
)
self
.
run_command
(
'build_py'
)
bpy_cmd
=
self
.
get_finalized_command
(
"build_py"
)
build_path
=
normalize_path
(
bpy_cmd
.
build_lib
)
build_path
=
pkg_resources
.
normalize_path
(
bpy_cmd
.
build_lib
)
# Build extensions
self
.
reinitialize_command
(
'egg_info'
,
egg_base
=
build_path
)
...
...
@@ -128,7 +129,8 @@ class develop(namespaces.DevelopInstaller, easy_install):
self
.
egg_path
=
build_path
self
.
dist
.
location
=
build_path
# XXX
self
.
dist
.
_provider
=
PathMetadata
(
build_path
,
ei_cmd
.
egg_info
)
self
.
dist
.
_provider
=
pkg_resources
.
PathMetadata
(
build_path
,
ei_cmd
.
egg_info
)
else
:
# Without 2to3 inplace works fine:
self
.
run_command
(
'egg_info'
)
...
...
@@ -200,6 +202,7 @@ class VersionlessRequirement:
name as the 'requirement' so that scripts will work across
multiple versions.
>>> from pkg_resources import Distribution
>>> dist = Distribution(project_name='foo', version='1.0')
>>> str(dist.as_requirement())
'foo==1.0'
...
...
setuptools/command/easy_install.py
View file @
0551421f
...
...
@@ -40,8 +40,11 @@ import subprocess
import
shlex
import
io
from
sysconfig
import
get_config_vars
,
get_path
from
setuptools
import
SetuptoolsDeprecationWarning
from
setuptools.extern
import
six
from
setuptools.extern.six.moves
import
configparser
,
map
...
...
@@ -2077,7 +2080,7 @@ class ScriptWriter:
@
classmethod
def
get_script_args
(
cls
,
dist
,
executable
=
None
,
wininst
=
False
):
# for backward compatibility
warnings
.
warn
(
"Use get_args"
,
DeprecationWarning
)
warnings
.
warn
(
"Use get_args"
,
EasyInstall
DeprecationWarning
)
writer
=
(
WindowsScriptWriter
if
wininst
else
ScriptWriter
).
best
()
header
=
cls
.
get_script_header
(
""
,
executable
,
wininst
)
return
writer
.
get_args
(
dist
,
header
)
...
...
@@ -2085,7 +2088,7 @@ class ScriptWriter:
@
classmethod
def
get_script_header
(
cls
,
script_text
,
executable
=
None
,
wininst
=
False
):
# for backward compatibility
warnings
.
warn
(
"Use get_header"
,
DeprecationWarning
,
stacklevel
=
2
)
warnings
.
warn
(
"Use get_header"
,
EasyInstall
DeprecationWarning
,
stacklevel
=
2
)
if
wininst
:
executable
=
"python.exe"
return
cls
.
get_header
(
script_text
,
executable
)
...
...
@@ -2120,7 +2123,7 @@ class ScriptWriter:
@
classmethod
def
get_writer
(
cls
,
force_windows
):
# for backward compatibility
warnings
.
warn
(
"Use best"
,
DeprecationWarning
)
warnings
.
warn
(
"Use best"
,
EasyInstall
DeprecationWarning
)
return
WindowsScriptWriter
.
best
()
if
force_windows
else
cls
.
best
()
@
classmethod
...
...
@@ -2152,7 +2155,7 @@ class WindowsScriptWriter(ScriptWriter):
@
classmethod
def
get_writer
(
cls
):
# for backward compatibility
warnings
.
warn
(
"Use best"
,
DeprecationWarning
)
warnings
.
warn
(
"Use best"
,
EasyInstall
DeprecationWarning
)
return
cls
.
best
()
@
classmethod
...
...
@@ -2333,3 +2336,7 @@ def _patch_usage():
yield
finally
:
distutils
.
core
.
gen_usage
=
saved
class
EasyInstallDeprecationWarning
(
SetuptoolsDeprecationWarning
):
"""Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
setuptools/command/egg_info.py
View file @
0551421f
...
...
@@ -31,7 +31,7 @@ import setuptools.unicode_utils as unicode_utils
from
setuptools.glob
import
glob
from
setuptools.extern
import
packaging
from
setuptools
import
SetuptoolsDeprecationWarning
def
translate_pattern
(
glob
):
"""
...
...
@@ -576,6 +576,12 @@ class manifest_maker(sdist):
self
.
filelist
.
extend
(
rcfiles
)
elif
os
.
path
.
exists
(
self
.
manifest
):
self
.
read_manifest
()
if
os
.
path
.
exists
(
"setup.py"
):
# setup.py should be included by default, even if it's not
# the script called to create the sdist
self
.
filelist
.
append
(
"setup.py"
)
ei_cmd
=
self
.
get_finalized_command
(
'egg_info'
)
self
.
filelist
.
graft
(
ei_cmd
.
egg_info
)
...
...
@@ -697,7 +703,7 @@ def get_pkg_info_revision():
Get a -r### off of PKG-INFO Version in case this is an sdist of
a subversion revision.
"""
warnings
.
warn
(
"get_pkg_info_revision is deprecated."
,
DeprecationWarning
)
warnings
.
warn
(
"get_pkg_info_revision is deprecated."
,
EggInfo
DeprecationWarning
)
if
os
.
path
.
exists
(
'PKG-INFO'
):
with
io
.
open
(
'PKG-INFO'
)
as
f
:
for
line
in
f
:
...
...
@@ -705,3 +711,7 @@ def get_pkg_info_revision():
if
match
:
return
int
(
match
.
group
(
1
))
return
0
class
EggInfoDeprecationWarning
(
SetuptoolsDeprecationWarning
):
"""Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning."""
setuptools/command/upload.py
View file @
0551421f
import
io
import
os
import
hashlib
import
getpass
from
base64
import
standard_b64encode
from
distutils
import
log
from
distutils.command
import
upload
as
orig
from
distutils.spawn
import
spawn
from
distutils.errors
import
DistutilsError
from
setuptools.extern.six.moves.urllib.request
import
urlopen
,
Request
from
setuptools.extern.six.moves.urllib.error
import
HTTPError
from
setuptools.extern.six.moves.urllib.parse
import
urlparse
class
upload
(
orig
.
upload
):
...
...
@@ -8,7 +21,6 @@ class upload(orig.upload):
Override default upload behavior to obtain password
in a variety of different ways.
"""
def
run
(
self
):
try
:
orig
.
upload
.
run
(
self
)
...
...
@@ -33,6 +45,137 @@ class upload(orig.upload):
self
.
_prompt_for_password
()
)
def
upload_file
(
self
,
command
,
pyversion
,
filename
):
# Makes sure the repository URL is compliant
schema
,
netloc
,
url
,
params
,
query
,
fragments
=
\
urlparse
(
self
.
repository
)
if
params
or
query
or
fragments
:
raise
AssertionError
(
"Incompatible url %s"
%
self
.
repository
)
if
schema
not
in
(
'http'
,
'https'
):
raise
AssertionError
(
"unsupported schema "
+
schema
)
# Sign if requested
if
self
.
sign
:
gpg_args
=
[
"gpg"
,
"--detach-sign"
,
"-a"
,
filename
]
if
self
.
identity
:
gpg_args
[
2
:
2
]
=
[
"--local-user"
,
self
.
identity
]
spawn
(
gpg_args
,
dry_run
=
self
.
dry_run
)
# Fill in the data - send all the meta-data in case we need to
# register a new release
with
open
(
filename
,
'rb'
)
as
f
:
content
=
f
.
read
()
meta
=
self
.
distribution
.
metadata
data
=
{
# action
':action'
:
'file_upload'
,
'protocol_version'
:
'1'
,
# identify release
'name'
:
meta
.
get_name
(),
'version'
:
meta
.
get_version
(),
# file content
'content'
:
(
os
.
path
.
basename
(
filename
),
content
),
'filetype'
:
command
,
'pyversion'
:
pyversion
,
'md5_digest'
:
hashlib
.
md5
(
content
).
hexdigest
(),
# additional meta-data
'metadata_version'
:
str
(
meta
.
get_metadata_version
()),
'summary'
:
meta
.
get_description
(),
'home_page'
:
meta
.
get_url
(),
'author'
:
meta
.
get_contact
(),
'author_email'
:
meta
.
get_contact_email
(),
'license'
:
meta
.
get_licence
(),
'description'
:
meta
.
get_long_description
(),
'keywords'
:
meta
.
get_keywords
(),
'platform'
:
meta
.
get_platforms
(),
'classifiers'
:
meta
.
get_classifiers
(),
'download_url'
:
meta
.
get_download_url
(),
# PEP 314
'provides'
:
meta
.
get_provides
(),
'requires'
:
meta
.
get_requires
(),
'obsoletes'
:
meta
.
get_obsoletes
(),
}
data
[
'comment'
]
=
''
if
self
.
sign
:
data
[
'gpg_signature'
]
=
(
os
.
path
.
basename
(
filename
)
+
".asc"
,
open
(
filename
+
".asc"
,
"rb"
).
read
())
# set up the authentication
user_pass
=
(
self
.
username
+
":"
+
self
.
password
).
encode
(
'ascii'
)
# The exact encoding of the authentication string is debated.
# Anyway PyPI only accepts ascii for both username or password.
auth
=
"Basic "
+
standard_b64encode
(
user_pass
).
decode
(
'ascii'
)
# Build up the MIME payload for the POST data
boundary
=
'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary
=
b'
\
r
\
n
--'
+
boundary
.
encode
(
'ascii'
)
end_boundary
=
sep_boundary
+
b'--
\
r
\
n
'
body
=
io
.
BytesIO
()
for
key
,
value
in
data
.
items
():
title
=
'
\
r
\
n
Content-Disposition: form-data; name="%s"'
%
key
# handle multiple entries for the same name
if
not
isinstance
(
value
,
list
):
value
=
[
value
]
for
value
in
value
:
if
type
(
value
)
is
tuple
:
title
+=
'; filename="%s"'
%
value
[
0
]
value
=
value
[
1
]
else
:
value
=
str
(
value
).
encode
(
'utf-8'
)
body
.
write
(
sep_boundary
)
body
.
write
(
title
.
encode
(
'utf-8'
))
body
.
write
(
b"
\
r
\
n
\
r
\
n
"
)
body
.
write
(
value
)
body
.
write
(
end_boundary
)
body
=
body
.
getvalue
()
msg
=
"Submitting %s to %s"
%
(
filename
,
self
.
repository
)
self
.
announce
(
msg
,
log
.
INFO
)
# build the Request
headers
=
{
'Content-type'
:
'multipart/form-data; boundary=%s'
%
boundary
,
'Content-length'
:
str
(
len
(
body
)),
'Authorization'
:
auth
,
}
request
=
Request
(
self
.
repository
,
data
=
body
,
headers
=
headers
)
# send the data
try
:
result
=
urlopen
(
request
)
status
=
result
.
getcode
()
reason
=
result
.
msg
except
HTTPError
as
e
:
status
=
e
.
code
reason
=
e
.
msg
except
OSError
as
e
:
self
.
announce
(
str
(
e
),
log
.
ERROR
)
raise
if
status
==
200
:
self
.
announce
(
'Server response (%s): %s'
%
(
status
,
reason
),
log
.
INFO
)
if
self
.
show_response
:
text
=
getattr
(
self
,
'_read_pypi_response'
,
lambda
x
:
None
)(
result
)
if
text
is
not
None
:
msg
=
'
\
n
'
.
join
((
'-'
*
75
,
text
,
'-'
*
75
))
self
.
announce
(
msg
,
log
.
INFO
)
else
:
msg
=
'Upload failed (%s): %s'
%
(
status
,
reason
)
self
.
announce
(
msg
,
log
.
ERROR
)
raise
DistutilsError
(
msg
)
def
_load_password_from_keyring
(
self
):
"""
Attempt to load password from keyring. Suppress Exceptions.
...
...
setuptools/config.py
View file @
0551421f
...
...
@@ -2,8 +2,12 @@ from __future__ import absolute_import, unicode_literals
import
io
import
os
import
sys
import
warnings
import
functools
from
collections
import
defaultdict
from
functools
import
partial
from
functools
import
wraps
from
importlib
import
import_module
from
distutils.errors
import
DistutilsOptionError
,
DistutilsFileError
...
...
@@ -61,6 +65,18 @@ def read_configuration(
return
configuration_to_dict
(
handlers
)
def
_get_option
(
target_obj
,
key
):
"""
Given a target object and option key, get that option from
the target object, either through a get_{key} method or
from an attribute directly.
"""
getter_name
=
'get_{key}'
.
format
(
**
locals
())
by_attribute
=
functools
.
partial
(
getattr
,
target_obj
,
key
)
getter
=
getattr
(
target_obj
,
getter_name
,
by_attribute
)
return
getter
()
def
configuration_to_dict
(
handlers
):
"""Returns configuration data gathered by given handlers as a dict.
...
...
@@ -72,20 +88,9 @@ def configuration_to_dict(handlers):
config_dict
=
defaultdict
(
dict
)
for
handler
in
handlers
:
obj_alias
=
handler
.
section_prefix
target_obj
=
handler
.
target_obj
for
option
in
handler
.
set_options
:
getter
=
getattr
(
target_obj
,
'get_%s'
%
option
,
None
)
if
getter
is
None
:
value
=
getattr
(
target_obj
,
option
)
else
:
value
=
getter
()
config_dict
[
obj_alias
][
option
]
=
value
value
=
_get_option
(
handler
.
target_obj
,
option
)
config_dict
[
handler
.
section_prefix
][
option
]
=
value
return
config_dict
...
...
@@ -110,7 +115,8 @@ def parse_configuration(
options
.
parse
()
meta
=
ConfigMetadataHandler
(
distribution
.
metadata
,
command_options
,
ignore_option_errors
,
distribution
.
package_dir
)
distribution
.
metadata
,
command_options
,
ignore_option_errors
,
distribution
.
package_dir
)
meta
.
parse
()
return
meta
,
options
...
...
@@ -240,6 +246,26 @@ class ConfigHandler:
value
=
value
.
lower
()
return
value
in
(
'1'
,
'true'
,
'yes'
)
@
classmethod
def
_exclude_files_parser
(
cls
,
key
):
"""Returns a parser function to make sure field inputs
are not files.
Parses a value after getting the key so error messages are
more informative.
:param key:
:rtype: callable
"""
def
parser
(
value
):
exclude_directive
=
'file:'
if
value
.
startswith
(
exclude_directive
):
raise
ValueError
(
'Only strings are accepted for the {0} field, '
'files are not accepted'
.
format
(
key
))
return
value
return
parser
@
classmethod
def
_parse_file
(
cls
,
value
):
"""Represents value as a string, allowing including text
...
...
@@ -249,7 +275,6 @@ class ConfigHandler:
directory with setup.py.
Examples:
file: LICENSE
file: README.rst, CHANGELOG.md, src/file.txt
:param str value:
...
...
@@ -388,7 +413,7 @@ class ConfigHandler:
section_parser_method
=
getattr
(
self
,
# Dots in section names are tran
ls
ated into dunderscores.
# Dots in section names are tran
sl
ated into dunderscores.
(
'parse_section%s'
%
method_postfix
).
replace
(
'.'
,
'__'
),
None
)
...
...
@@ -399,6 +424,20 @@ class ConfigHandler:
section_parser_method
(
section_options
)
def
_deprecated_config_handler
(
self
,
func
,
msg
,
warning_class
):
""" this function will wrap around parameters that are deprecated
:param msg: deprecation message
:param warning_class: class of warning exception to be raised
:param func: function to be wrapped around
"""
@
wraps
(
func
)
def
config_handler
(
*
args
,
**
kwargs
):
warnings
.
warn
(
msg
,
warning_class
)
return
func
(
*
args
,
**
kwargs
)
return
config_handler
class
ConfigMetadataHandler
(
ConfigHandler
):
...
...
@@ -429,15 +468,20 @@ class ConfigMetadataHandler(ConfigHandler):
parse_list
=
self
.
_parse_list
parse_file
=
self
.
_parse_file
parse_dict
=
self
.
_parse_dict
exclude_files_parser
=
self
.
_exclude_files_parser
return
{
'platforms'
:
parse_list
,
'keywords'
:
parse_list
,
'provides'
:
parse_list
,
'requires'
:
parse_list
,
'requires'
:
self
.
_deprecated_config_handler
(
parse_list
,
"The requires parameter is deprecated, please use "
"install_requires for runtime dependencies."
,
DeprecationWarning
),
'obsoletes'
:
parse_list
,
'classifiers'
:
self
.
_get_parser_compound
(
parse_file
,
parse_list
),
'license'
:
parse_file
,
'license'
:
exclude_files_parser
(
'license'
)
,
'description'
:
parse_file
,
'long_description'
:
parse_file
,
'version'
:
self
.
_parse_version
,
...
...
@@ -458,9 +502,12 @@ class ConfigMetadataHandler(ConfigHandler):
# Be strict about versions loaded from file because it's easy to
# accidentally include newlines and other unintended content
if
isinstance
(
parse
(
version
),
LegacyVersion
):
raise
DistutilsOptionError
(
'Version loaded from %s does not comply with PEP 440: %s'
%
(
value
,
version
))
tmpl
=
(
'Version loaded from {value} does not '
'comply with PEP 440: {version}'
)
raise
DistutilsOptionError
(
tmpl
.
format
(
**
locals
()))
return
version
version
=
self
.
_parse_attr
(
value
,
self
.
package_dir
)
...
...
@@ -518,12 +565,13 @@ class ConfigOptionsHandler(ConfigHandler):
find_directives
=
[
'find:'
,
'find_namespace:'
]
trimmed_value
=
value
.
strip
()
if
not
trimmed_value
in
find_directives
:
if
trimmed_value
not
in
find_directives
:
return
self
.
_parse_list
(
value
)
findns
=
trimmed_value
==
find_directives
[
1
]
if
findns
and
not
PY3
:
raise
DistutilsOptionError
(
'find_namespace: directive is unsupported on Python < 3.3'
)
raise
DistutilsOptionError
(
'find_namespace: directive is unsupported on Python < 3.3'
)
# Read function arguments from a dedicated section.
find_kwargs
=
self
.
parse_section_packages__find
(
...
...
setuptools/dist.py
View file @
0551421f
# -*- coding: utf-8 -*-
__all__
=
[
'Distribution'
]
import
io
import
sys
import
re
import
os
import
warnings
...
...
@@ -9,8 +11,15 @@ import distutils.log
import
distutils.core
import
distutils.cmd
import
distutils.dist
from
distutils.errors
import
DistutilsOptionError
from
distutils.util
import
strtobool
from
distutils.debug
import
DEBUG
from
distutils.fancy_getopt
import
translate_longopt
import
itertools
from
collections
import
defaultdict
from
email
import
message_from_file
from
distutils.errors
import
(
DistutilsOptionError
,
DistutilsPlatformError
,
DistutilsSetupError
,
)
...
...
@@ -21,51 +30,121 @@ from setuptools.extern import six
from
setuptools.extern
import
packaging
from
setuptools.extern.six.moves
import
map
,
filter
,
filterfalse
from
.
import
SetuptoolsDeprecationWarning
from
setuptools.depends
import
Require
from
setuptools
import
windows_support
from
setuptools.monkey
import
get_unpatched
from
setuptools.config
import
parse_configuration
from
.unicode_utils
import
detect_encoding
import
pkg_resources
from
.py36compat
import
Distribution_parse_config_files
__import__
(
'setuptools.extern.packaging.specifiers'
)
__import__
(
'setuptools.extern.packaging.version'
)
def
_get_unpatched
(
cls
):
warnings
.
warn
(
"Do not call this function"
,
DeprecationWarning
)
warnings
.
warn
(
"Do not call this function"
,
D
istD
eprecationWarning
)
return
get_unpatched
(
cls
)
def
get_metadata_version
(
dist_md
):
if
dist_md
.
long_description_content_type
or
dist_md
.
provides_extras
:
return
StrictVersion
(
'2.1'
)
elif
(
dist_md
.
maintainer
is
not
None
or
dist_md
.
maintainer_email
is
not
None
or
getattr
(
dist_md
,
'python_requires'
,
None
)
is
not
None
):
return
StrictVersion
(
'1.2'
)
elif
(
dist_md
.
provides
or
dist_md
.
requires
or
dist_md
.
obsoletes
or
dist_md
.
classifiers
or
dist_md
.
download_url
):
return
StrictVersion
(
'1.1'
)
def
get_metadata_version
(
self
):
mv
=
getattr
(
self
,
'metadata_version'
,
None
)
return
StrictVersion
(
'1.0'
)
if
mv
is
None
:
if
self
.
long_description_content_type
or
self
.
provides_extras
:
mv
=
StrictVersion
(
'2.1'
)
elif
(
self
.
maintainer
is
not
None
or
self
.
maintainer_email
is
not
None
or
getattr
(
self
,
'python_requires'
,
None
)
is
not
None
):
mv
=
StrictVersion
(
'1.2'
)
elif
(
self
.
provides
or
self
.
requires
or
self
.
obsoletes
or
self
.
classifiers
or
self
.
download_url
):
mv
=
StrictVersion
(
'1.1'
)
else
:
mv
=
StrictVersion
(
'1.0'
)
self
.
metadata_version
=
mv
return
mv
def
read_pkg_file
(
self
,
file
):
"""Reads the metadata values from a file object."""
msg
=
message_from_file
(
file
)
def
_read_field
(
name
):
value
=
msg
[
name
]
if
value
==
'UNKNOWN'
:
return
None
return
value
def
_read_list
(
name
):
values
=
msg
.
get_all
(
name
,
None
)
if
values
==
[]:
return
None
return
values
self
.
metadata_version
=
StrictVersion
(
msg
[
'metadata-version'
])
self
.
name
=
_read_field
(
'name'
)
self
.
version
=
_read_field
(
'version'
)
self
.
description
=
_read_field
(
'summary'
)
# we are filling author only.
self
.
author
=
_read_field
(
'author'
)
self
.
maintainer
=
None
self
.
author_email
=
_read_field
(
'author-email'
)
self
.
maintainer_email
=
None
self
.
url
=
_read_field
(
'home-page'
)
self
.
license
=
_read_field
(
'license'
)
if
'download-url'
in
msg
:
self
.
download_url
=
_read_field
(
'download-url'
)
else
:
self
.
download_url
=
None
self
.
long_description
=
_read_field
(
'description'
)
self
.
description
=
_read_field
(
'summary'
)
if
'keywords'
in
msg
:
self
.
keywords
=
_read_field
(
'keywords'
).
split
(
','
)
self
.
platforms
=
_read_list
(
'platform'
)
self
.
classifiers
=
_read_list
(
'classifier'
)
# PEP 314 - these fields only exist in 1.1
if
self
.
metadata_version
==
StrictVersion
(
'1.1'
):
self
.
requires
=
_read_list
(
'requires'
)
self
.
provides
=
_read_list
(
'provides'
)
self
.
obsoletes
=
_read_list
(
'obsoletes'
)
else
:
self
.
requires
=
None
self
.
provides
=
None
self
.
obsoletes
=
None
# Based on Python 3.5 version
def
write_pkg_file
(
self
,
file
):
"""Write the PKG-INFO format data to a file object.
"""
version
=
get_metadata_version
(
self
)
version
=
self
.
get_metadata_version
()
if
six
.
PY2
:
def
write_field
(
key
,
value
):
file
.
write
(
"%s: %s
\
n
"
%
(
key
,
self
.
_encode_field
(
value
)))
else
:
def
write_field
(
key
,
value
):
file
.
write
(
"%s: %s
\
n
"
%
(
key
,
value
))
file
.
write
(
'Metadata-Version: %s
\
n
'
%
version
)
file
.
write
(
'Name: %s
\
n
'
%
self
.
get_name
())
file
.
write
(
'Version: %s
\
n
'
%
self
.
get_version
())
file
.
write
(
'Summary: %s
\
n
'
%
self
.
get_description
())
file
.
write
(
'Home-page: %s
\
n
'
%
self
.
get_url
())
write_field
(
'Metadata-Version'
,
str
(
version
)
)
write_field
(
'Name'
,
self
.
get_name
())
write_field
(
'Version'
,
self
.
get_version
())
write_field
(
'Summary'
,
self
.
get_description
())
write_field
(
'Home-page'
,
self
.
get_url
())
if
version
<
StrictVersion
(
'1.2'
):
file
.
write
(
'Author: %s
\
n
'
%
self
.
get_contact
())
file
.
write
(
'Author-email: %s
\
n
'
%
self
.
get_contact_email
())
write_field
(
'Author'
,
self
.
get_contact
())
write_field
(
'Author-email'
,
self
.
get_contact_email
())
else
:
optional_fields
=
(
(
'Author'
,
'author'
),
...
...
@@ -76,28 +155,26 @@ def write_pkg_file(self, file):
for
field
,
attr
in
optional_fields
:
attr_val
=
getattr
(
self
,
attr
)
if
six
.
PY2
:
attr_val
=
self
.
_encode_field
(
attr_val
)
if
attr_val
is
not
None
:
file
.
write
(
'%s: %s
\
n
'
%
(
field
,
attr_val
)
)
write_field
(
field
,
attr_val
)
file
.
write
(
'License: %s
\
n
'
%
self
.
get_license
())
write_field
(
'License'
,
self
.
get_license
())
if
self
.
download_url
:
file
.
write
(
'Download-URL: %s
\
n
'
%
self
.
download_url
)
write_field
(
'Download-URL'
,
self
.
download_url
)
for
project_url
in
self
.
project_urls
.
items
():
file
.
write
(
'Project-URL: %s, %s
\
n
'
%
project_url
)
write_field
(
'Project-URL'
,
'%s, %s
'
%
project_url
)
long_desc
=
rfc822_escape
(
self
.
get_long_description
())
file
.
write
(
'Description: %s
\
n
'
%
long_desc
)
write_field
(
'Description'
,
long_desc
)
keywords
=
','
.
join
(
self
.
get_keywords
())
if
keywords
:
file
.
write
(
'Keywords: %s
\
n
'
%
keywords
)
write_field
(
'Keywords'
,
keywords
)
if
version
>=
StrictVersion
(
'1.2'
):
for
platform
in
self
.
get_platforms
():
file
.
write
(
'Platform: %s
\
n
'
%
platform
)
write_field
(
'Platform'
,
platform
)
else
:
self
.
_write_list
(
file
,
'Platform'
,
self
.
get_platforms
())
...
...
@@ -110,17 +187,17 @@ def write_pkg_file(self, file):
# Setuptools specific for PEP 345
if
hasattr
(
self
,
'python_requires'
):
file
.
write
(
'Requires-Python: %s
\
n
'
%
self
.
python_requires
)
write_field
(
'Requires-Python'
,
self
.
python_requires
)
# PEP 566
if
self
.
long_description_content_type
:
file
.
write
(
'Description-Content-Type
: %s
\
n
'
%
write_field
(
'Description-Content-Type
'
,
self
.
long_description_content_type
)
if
self
.
provides_extras
:
for
extra
in
self
.
provides_extras
:
file
.
write
(
'Provides-Extra: %s
\
n
'
%
extra
)
write_field
(
'Provides-Extra'
,
extra
)
sequence
=
tuple
,
list
...
...
@@ -260,7 +337,7 @@ def check_packages(dist, attr, value):
_Distribution = get_unpatched(distutils.core.Distribution)
class Distribution(
Distribution_parse_config_files,
_Distribution):
class Distribution(_Distribution):
"""Distribution with support for features, tests, and package data
This is an enhanced version of '
distutils
.
dist
.
Distribution
' that
...
...
@@ -484,12 +561,125 @@ class Distribution(Distribution_parse_config_files, _Distribution):
req
.
marker
=
None
return
req
def
_parse_config_files
(
self
,
filenames
=
None
):
"""
Adapted from distutils.dist.Distribution.parse_config_files,
this method provides the same functionality in subtly-improved
ways.
"""
from
setuptools.extern.six.moves.configparser
import
ConfigParser
# Ignore install directory options if we have a venv
if
six
.
PY3
and
sys
.
prefix
!=
sys
.
base_prefix
:
ignore_options
=
[
'install-base'
,
'install-platbase'
,
'install-lib'
,
'install-platlib'
,
'install-purelib'
,
'install-headers'
,
'install-scripts'
,
'install-data'
,
'prefix'
,
'exec-prefix'
,
'home'
,
'user'
,
'root'
]
else
:
ignore_options
=
[]
ignore_options
=
frozenset
(
ignore_options
)
if
filenames
is
None
:
filenames
=
self
.
find_config_files
()
if
DEBUG
:
self
.
announce
(
"Distribution.parse_config_files():"
)
parser
=
ConfigParser
()
for
filename
in
filenames
:
with
io
.
open
(
filename
,
'rb'
)
as
fp
:
encoding
=
detect_encoding
(
fp
)
if
DEBUG
:
self
.
announce
(
" reading %s [%s]"
%
(
filename
,
encoding
or
'locale'
)
)
reader
=
io
.
TextIOWrapper
(
fp
,
encoding
=
encoding
)
(
parser
.
read_file
if
six
.
PY3
else
parser
.
readfp
)(
reader
)
for
section
in
parser
.
sections
():
options
=
parser
.
options
(
section
)
opt_dict
=
self
.
get_option_dict
(
section
)
for
opt
in
options
:
if
opt
!=
'__name__'
and
opt
not
in
ignore_options
:
val
=
parser
.
get
(
section
,
opt
)
opt
=
opt
.
replace
(
'-'
,
'_'
)
opt_dict
[
opt
]
=
(
filename
,
val
)
# Make the ConfigParser forget everything (so we retain
# the original filenames that options come from)
parser
.
__init__
()
# If there was a "global" section in the config file, use it
# to set Distribution options.
if
'global'
in
self
.
command_options
:
for
(
opt
,
(
src
,
val
))
in
self
.
command_options
[
'global'
].
items
():
alias
=
self
.
negative_opt
.
get
(
opt
)
try
:
if
alias
:
setattr
(
self
,
alias
,
not
strtobool
(
val
))
elif
opt
in
(
'verbose'
,
'dry_run'
):
# ugh!
setattr
(
self
,
opt
,
strtobool
(
val
))
else
:
setattr
(
self
,
opt
,
val
)
except
ValueError
as
msg
:
raise
DistutilsOptionError
(
msg
)
def
_set_command_options
(
self
,
command_obj
,
option_dict
=
None
):
"""
Set the options for 'command_obj' from 'option_dict'. Basically
this means copying elements of a dictionary ('option_dict') to
attributes of an instance ('command').
'command_obj' must be a Command instance. If 'option_dict' is not
supplied, uses the standard option dictionary for this command
(from 'self.command_options').
(Adopted from distutils.dist.Distribution._set_command_options)
"""
command_name
=
command_obj
.
get_command_name
()
if
option_dict
is
None
:
option_dict
=
self
.
get_option_dict
(
command_name
)
if
DEBUG
:
self
.
announce
(
" setting options for '%s' command:"
%
command_name
)
for
(
option
,
(
source
,
value
))
in
option_dict
.
items
():
if
DEBUG
:
self
.
announce
(
" %s = %s (from %s)"
%
(
option
,
value
,
source
))
try
:
bool_opts
=
[
translate_longopt
(
o
)
for
o
in
command_obj
.
boolean_options
]
except
AttributeError
:
bool_opts
=
[]
try
:
neg_opt
=
command_obj
.
negative_opt
except
AttributeError
:
neg_opt
=
{}
try
:
is_string
=
isinstance
(
value
,
six
.
string_types
)
if
option
in
neg_opt
and
is_string
:
setattr
(
command_obj
,
neg_opt
[
option
],
not
strtobool
(
value
))
elif
option
in
bool_opts
and
is_string
:
setattr
(
command_obj
,
option
,
strtobool
(
value
))
elif
hasattr
(
command_obj
,
option
):
setattr
(
command_obj
,
option
,
value
)
else
:
raise
DistutilsOptionError
(
"error in %s: command '%s' has no such option '%s'"
%
(
source
,
command_name
,
option
))
except
ValueError
as
msg
:
raise
DistutilsOptionError
(
msg
)
def
parse_config_files
(
self
,
filenames
=
None
,
ignore_option_errors
=
False
):
"""Parses configuration files from various levels
and loads configuration.
"""
_Distribution
.
parse_config_files
(
self
,
filenames
=
filenames
)
self
.
_parse_config_files
(
filenames
=
filenames
)
parse_configuration
(
self
,
self
.
command_options
,
ignore_option_errors
=
ignore_option_errors
)
...
...
@@ -980,7 +1170,7 @@ class Feature:
"Features are deprecated and will be removed in a future "
"version. See https://github.com/pypa/setuptools/issues/65."
)
warnings
.
warn
(
msg
,
DeprecationWarning
,
stacklevel
=
3
)
warnings
.
warn
(
msg
,
D
istD
eprecationWarning
,
stacklevel
=
3
)
def
__init__
(
self
,
description
,
standard
=
False
,
available
=
True
,
...
...
@@ -1069,3 +1259,7 @@ class Feature:
" doesn't contain any packages or modules under %s"
%
(
self
.
description
,
item
,
item
)
)
class
DistDeprecationWarning
(
SetuptoolsDeprecationWarning
):
"""Class for warning about deprecations in dist in setuptools. Not ignored by default, unlike DeprecationWarning."""
setuptools/monkey.py
View file @
0551421f
...
...
@@ -84,7 +84,7 @@ def patch_all():
warehouse
=
'https://upload.pypi.org/legacy/'
distutils
.
config
.
PyPIRCCommand
.
DEFAULT_REPOSITORY
=
warehouse
_patch_distribution_metadata
_write_pkg_file
()
_patch_distribution_metadata
()
# Install Distribution throughout the distutils
for
module
in
distutils
.
dist
,
distutils
.
core
,
distutils
.
cmd
:
...
...
@@ -101,11 +101,11 @@ def patch_all():
patch_for_msvc_specialized_compiler
()
def
_patch_distribution_metadata
_write_pkg_file
():
"""Patch write_pkg_file
to also write Requires-Python/Requires-External
"""
distutils
.
dist
.
DistributionMetadata
.
write_pkg_file
=
(
setuptools
.
dist
.
write_pkg_file
)
def
_patch_distribution_metadata
():
"""Patch write_pkg_file
and read_pkg_file for higher metadata standards
"""
for
attr
in
(
'write_pkg_file'
,
'read_pkg_file'
,
'get_metadata_version'
):
new_val
=
getattr
(
setuptools
.
dist
,
attr
)
setattr
(
distutils
.
dist
.
DistributionMetadata
,
attr
,
new_val
)
def
patch_func
(
replacement
,
target_mod
,
func_name
):
...
...
setuptools/package_index.py
View file @
0551421f
...
...
@@ -850,13 +850,16 @@ class PackageIndex(Environment):
def _download_svn(self, url, filename):
warnings.warn("SVN download support is deprecated", UserWarning)
def splituser(host):
user, delim, host = host.rpartition('@')
return user, host
url = url.split('#', 1)[0] # remove any fragment for svn's sake
creds = ''
if url.lower().startswith('svn:') and '@' in url:
scheme, netloc, path, p, q, f = urllib.parse.urlparse(url)
if not netloc and path.startswith('//') and '/' in path[2:]:
netloc, path = path[2:].split('/', 1)
auth, host =
urllib.parse.
splituser(netloc)
auth, host = splituser(netloc)
if auth:
if ':' in auth:
user, pw = auth.split(':', 1)
...
...
@@ -1047,15 +1050,16 @@ class PyPIConfig(configparser.RawConfigParser):
def open_with_auth(url, opener=urllib.request.urlopen):
"""
Open
a
urllib2
request
,
handling
HTTP
authentication
"""
scheme, netloc, path, params, query, frag = urllib.parse.urlparse(url)
parsed = urllib.parse.urlparse(url)
scheme, netloc, path, params, query, frag = parsed
# Double scheme does not raise on Mac OS X as revealed by a
# failing test. We would expect "nonnumeric port". Refs #20.
if netloc.endswith(':'):
raise http_client.InvalidURL("nonnumeric port: ''")
if scheme in ('http', 'https'):
auth
, host = urllib.parse.splituser(netloc
)
if scheme in ('http', 'https')
and parsed.username
:
auth
= ':'.join((parsed.username, parsed.password)
)
else:
auth = None
...
...
@@ -1068,7 +1072,7 @@ def open_with_auth(url, opener=urllib.request.urlopen):
if auth:
auth = "Basic " + _encode_auth(auth)
parts = scheme,
host
, path, params, query, frag
parts = scheme,
parsed.hostname
, path, params, query, frag
new_url = urllib.parse.urlunparse(parts)
request = urllib.request.Request(new_url)
request.add_header("Authorization", auth)
...
...
@@ -1082,7 +1086,7 @@ def open_with_auth(url, opener=urllib.request.urlopen):
# Put authentication info back into request URL if same host,
# so that links found on the page will work
s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url)
if s2 == scheme and h2 ==
host
:
if s2 == scheme and h2 ==
parsed.hostname
:
parts = s2, netloc, path2, param2, query2, frag2
fp.url = urllib.parse.urlunparse(parts)
...
...
setuptools/pep425tags.py
View file @
0551421f
...
...
@@ -161,7 +161,7 @@ def is_manylinux1_compatible():
def
get_darwin_arches
(
major
,
minor
,
machine
):
"""Return a list of supported arches (including group arches) for
the given major, minor and machine architecture of a
n
macOS machine.
the given major, minor and machine architecture of a macOS machine.
"""
arches
=
[]
...
...
setuptools/py36compat.py
deleted
100644 → 0
View file @
28872fc9
import
sys
from
distutils.errors
import
DistutilsOptionError
from
distutils.util
import
strtobool
from
distutils.debug
import
DEBUG
class
Distribution_parse_config_files
:
"""
Mix-in providing forward-compatibility for functionality to be
included by default on Python 3.7.
Do not edit the code in this class except to update functionality
as implemented in distutils.
"""
def
parse_config_files
(
self
,
filenames
=
None
):
from
configparser
import
ConfigParser
# Ignore install directory options if we have a venv
if
sys
.
prefix
!=
sys
.
base_prefix
:
ignore_options
=
[
'install-base'
,
'install-platbase'
,
'install-lib'
,
'install-platlib'
,
'install-purelib'
,
'install-headers'
,
'install-scripts'
,
'install-data'
,
'prefix'
,
'exec-prefix'
,
'home'
,
'user'
,
'root'
]
else
:
ignore_options
=
[]
ignore_options
=
frozenset
(
ignore_options
)
if
filenames
is
None
:
filenames
=
self
.
find_config_files
()
if
DEBUG
:
self
.
announce
(
"Distribution.parse_config_files():"
)
parser
=
ConfigParser
(
interpolation
=
None
)
for
filename
in
filenames
:
if
DEBUG
:
self
.
announce
(
" reading %s"
%
filename
)
parser
.
read
(
filename
)
for
section
in
parser
.
sections
():
options
=
parser
.
options
(
section
)
opt_dict
=
self
.
get_option_dict
(
section
)
for
opt
in
options
:
if
opt
!=
'__name__'
and
opt
not
in
ignore_options
:
val
=
parser
.
get
(
section
,
opt
)
opt
=
opt
.
replace
(
'-'
,
'_'
)
opt_dict
[
opt
]
=
(
filename
,
val
)
# Make the ConfigParser forget everything (so we retain
# the original filenames that options come from)
parser
.
__init__
()
# If there was a "global" section in the config file, use it
# to set Distribution options.
if
'global'
in
self
.
command_options
:
for
(
opt
,
(
src
,
val
))
in
self
.
command_options
[
'global'
].
items
():
alias
=
self
.
negative_opt
.
get
(
opt
)
try
:
if
alias
:
setattr
(
self
,
alias
,
not
strtobool
(
val
))
elif
opt
in
(
'verbose'
,
'dry_run'
):
# ugh!
setattr
(
self
,
opt
,
strtobool
(
val
))
else
:
setattr
(
self
,
opt
,
val
)
except
ValueError
as
msg
:
raise
DistutilsOptionError
(
msg
)
if
sys
.
version_info
<
(
3
,):
# Python 2 behavior is sufficient
class
Distribution_parse_config_files
:
pass
if
False
:
# When updated behavior is available upstream,
# disable override here.
class
Distribution_parse_config_files
:
pass
setuptools/ssl_support.py
View file @
0551421f
...
...
@@ -59,7 +59,7 @@ if not match_hostname:
def
_dnsname_match
(
dn
,
hostname
,
max_wildcards
=
1
):
"""Matching according to RFC 6125, section 6.4.3
http://tools.ietf.org/html/rfc6125#section-6.4.3
http
s
://tools.ietf.org/html/rfc6125#section-6.4.3
"""
pats
=
[]
if
not
dn
:
...
...
setuptools/tests/files.py
View file @
0551421f
...
...
@@ -6,10 +6,13 @@ import pkg_resources.py31compat
def
build_files
(
file_defs
,
prefix
=
""
):
"""
Build a set of files/directories, as described by the file_defs dictionary.
Build a set of files/directories, as described by the
file_defs dictionary.
Each key/value pair in the dictionary is interpreted as a filename/contents
pair. If the contents value is a dictionary, a directory is created, and the
Each key/value pair in the dictionary is interpreted as
a filename/contents
pair. If the contents value is a dictionary, a directory
is created, and the
dictionary interpreted as the files within it, recursively.
For example:
...
...
setuptools/tests/server.py
View file @
0551421f
...
...
@@ -19,10 +19,11 @@ class IndexServer(BaseHTTPServer.HTTPServer):
s.stop()
"""
def
__init__
(
self
,
server_address
=
(
''
,
0
),
def
__init__
(
self
,
server_address
=
(
''
,
0
),
RequestHandlerClass
=
SimpleHTTPServer
.
SimpleHTTPRequestHandler
):
BaseHTTPServer
.
HTTPServer
.
__init__
(
self
,
server_address
,
RequestHandlerClass
)
BaseHTTPServer
.
HTTPServer
.
__init__
(
self
,
server_address
,
RequestHandlerClass
)
self
.
_run
=
True
def
start
(
self
):
...
...
@@ -56,10 +57,11 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread):
A simple HTTP Server that records the requests made to it.
"""
def
__init__
(
self
,
server_address
=
(
''
,
0
),
def
__init__
(
self
,
server_address
=
(
''
,
0
),
RequestHandlerClass
=
RequestRecorder
):
BaseHTTPServer
.
HTTPServer
.
__init__
(
self
,
server_address
,
RequestHandlerClass
)
BaseHTTPServer
.
HTTPServer
.
__init__
(
self
,
server_address
,
RequestHandlerClass
)
threading
.
Thread
.
__init__
(
self
)
self
.
setDaemon
(
True
)
self
.
requests
=
[]
...
...
setuptools/tests/test_build_clib.py
View file @
0551421f
import
pytest
import
os
import
shutil
import
mock
from
distutils.errors
import
DistutilsSetupError
...
...
@@ -40,13 +38,14 @@ class TestBuildCLib:
# with that out of the way, let's see if the crude dependency
# system works
cmd
.
compiler
=
mock
.
MagicMock
(
spec
=
cmd
.
compiler
)
mock_newer
.
return_value
=
([],[])
mock_newer
.
return_value
=
([],
[])
obj_deps
=
{
''
:
(
'global.h'
,),
'example.c'
:
(
'example.h'
,)}
libs
=
[(
'example'
,
{
'sources'
:
[
'example.c'
]
,
'obj_deps'
:
obj_deps
})]
libs
=
[(
'example'
,
{
'sources'
:
[
'example.c'
]
,
'obj_deps'
:
obj_deps
})]
cmd
.
build_libraries
(
libs
)
assert
[[
'example.c'
,
'global.h'
,
'example.h'
]]
in
mock_newer
.
call_args
[
0
]
assert
[[
'example.c'
,
'global.h'
,
'example.h'
]]
in
\
mock_newer
.
call_args
[
0
]
assert
not
cmd
.
compiler
.
compile
.
called
assert
cmd
.
compiler
.
create_static_lib
.
call_count
==
1
...
...
setuptools/tests/test_build_meta.py
View file @
0551421f
...
...
@@ -2,16 +2,20 @@ from __future__ import unicode_literals
import
os
import
shutil
import
tarfile
import
pytest
from
setuptools.build_meta
import
build_sdist
from
.files
import
build_files
from
.textwrap
import
DALS
from
.
import
py2_only
__metaclass__
=
type
futures
=
pytest
.
importorskip
(
'concurrent.futures'
)
importlib
=
pytest
.
importorskip
(
'importlib'
)
# Backports on Python 2.7
import
importlib
from
concurrent
import
futures
class
BuildBackendBase
:
...
...
@@ -108,13 +112,13 @@ def build_backend(tmpdir, request):
def
test_get_requires_for_build_wheel
(
build_backend
):
actual
=
build_backend
.
get_requires_for_build_wheel
()
expected
=
[
'six'
,
'
setuptools'
,
'
wheel'
]
expected
=
[
'six'
,
'wheel'
]
assert
sorted
(
actual
)
==
sorted
(
expected
)
def
test_get_requires_for_build_sdist
(
build_backend
):
actual
=
build_backend
.
get_requires_for_build_sdist
()
expected
=
[
'six'
,
'setuptools'
]
expected
=
[
'six'
]
assert
sorted
(
actual
)
==
sorted
(
expected
)
...
...
@@ -143,7 +147,7 @@ def test_prepare_metadata_for_build_wheel(build_backend):
assert
os
.
path
.
isfile
(
os
.
path
.
join
(
dist_dir
,
dist_info
,
'METADATA'
))
@
py
test
.
mark
.
skipif
(
'sys.version_info > (3,)'
)
@
py
2_only
def
test_prepare_metadata_for_build_wheel_with_str
(
build_backend
):
dist_dir
=
os
.
path
.
abspath
(
str
(
'pip-dist-info'
))
os
.
makedirs
(
dist_dir
)
...
...
@@ -168,15 +172,67 @@ def test_build_sdist_version_change(build_backend):
sdist_name
=
build_backend
.
build_sdist
(
sdist_into_directory
)
assert
os
.
path
.
isfile
(
os
.
path
.
join
(
sdist_into_directory
,
sdist_name
))
# if the setup.py changes subsequent call of the build meta should still succeed, given the
# if the setup.py changes subsequent call of the build meta
# should still succeed, given the
# sdist_directory the frontend specifies is empty
with
open
(
os
.
path
.
abspath
(
"setup.py"
),
'rt'
)
as
file_handler
:
content
=
file_handler
.
read
()
with
open
(
os
.
path
.
abspath
(
"setup.py"
),
'wt'
)
as
file_handler
:
file_handler
.
write
(
content
.
replace
(
"version='0.0.0'"
,
"version='0.0.1'"
))
file_handler
.
write
(
content
.
replace
(
"version='0.0.0'"
,
"version='0.0.1'"
))
shutil
.
rmtree
(
sdist_into_directory
)
os
.
makedirs
(
sdist_into_directory
)
sdist_name
=
build_backend
.
build_sdist
(
"out_sdist"
)
assert
os
.
path
.
isfile
(
os
.
path
.
join
(
os
.
path
.
abspath
(
"out_sdist"
),
sdist_name
))
assert
os
.
path
.
isfile
(
os
.
path
.
join
(
os
.
path
.
abspath
(
"out_sdist"
),
sdist_name
))
def
test_build_sdist_setup_py_exists
(
tmpdir_cwd
):
# If build_sdist is called from a script other than setup.py,
# ensure setup.py is include
build_files
(
defns
[
0
])
targz_path
=
build_sdist
(
"temp"
)
with
tarfile
.
open
(
os
.
path
.
join
(
"temp"
,
targz_path
))
as
tar
:
assert
any
(
'setup.py'
in
name
for
name
in
tar
.
getnames
())
def
test_build_sdist_setup_py_manifest_excluded
(
tmpdir_cwd
):
# Ensure that MANIFEST.in can exclude setup.py
files
=
{
'setup.py'
:
DALS
(
"""
__import__('setuptools').setup(
name='foo',
version='0.0.0',
py_modules=['hello']
)"""
),
'hello.py'
:
''
,
'MANIFEST.in'
:
DALS
(
"""
exclude setup.py
"""
)
}
build_files
(
files
)
targz_path
=
build_sdist
(
"temp"
)
with
tarfile
.
open
(
os
.
path
.
join
(
"temp"
,
targz_path
))
as
tar
:
assert
not
any
(
'setup.py'
in
name
for
name
in
tar
.
getnames
())
def
test_build_sdist_builds_targz_even_if_zip_indicated
(
tmpdir_cwd
):
files
=
{
'setup.py'
:
DALS
(
"""
__import__('setuptools').setup(
name='foo',
version='0.0.0',
py_modules=['hello']
)"""
),
'hello.py'
:
''
,
'setup.cfg'
:
DALS
(
"""
[sdist]
formats=zip
"""
)
}
build_files
(
files
)
build_sdist
(
"temp"
)
setuptools/tests/test_config.py
View file @
0551421f
# -*- coding: UTF-8 -*-
from
__future__
import
unicode_literals
import
contextlib
import
pytest
from
distutils.errors
import
DistutilsOptionError
,
DistutilsFileError
from
mock
import
patch
from
setuptools.dist
import
Distribution
,
_Distribution
from
setuptools.config
import
ConfigHandler
,
read_configuration
from
setuptools.extern.six.moves.configparser
import
InterpolationMissingOptionError
from
setuptools.tests
import
is_ascii
from
.
import
py2_only
,
py3_only
from
.textwrap
import
DALS
class
ErrConfigHandler
(
ConfigHandler
):
"""Erroneous handler. Fails to implement required methods."""
...
...
@@ -16,12 +24,12 @@ def make_package_dir(name, base_dir, ns=False):
dir_package
=
dir_package
.
mkdir
(
dir_name
)
init_file
=
None
if
not
ns
:
init_file
=
dir_package
.
join
(
'__init__.py'
)
init_file
.
write
(
''
)
init_file
=
dir_package
.
join
(
'__init__.py'
)
init_file
.
write
(
''
)
return
dir_package
,
init_file
def
fake_env
(
tmpdir
,
setup_cfg
,
setup_py
=
None
,
package_path
=
'fake_package'
):
def
fake_env
(
tmpdir
,
setup_cfg
,
setup_py
=
None
,
encoding
=
'ascii'
,
package_path
=
'fake_package'
):
if
setup_py
is
None
:
setup_py
=
(
...
...
@@ -31,7 +39,7 @@ def fake_env(tmpdir, setup_cfg, setup_py=None, package_path='fake_package'):
tmpdir
.
join
(
'setup.py'
).
write
(
setup_py
)
config
=
tmpdir
.
join
(
'setup.cfg'
)
config
.
write
(
setup_cfg
)
config
.
write
(
setup_cfg
.
encode
(
encoding
),
mode
=
'wb'
)
package_dir
,
init_file
=
make_package_dir
(
package_path
,
tmpdir
)
...
...
@@ -146,6 +154,24 @@ class TestMetadata:
assert
metadata
.
download_url
==
'http://test.test.com/test/'
assert
metadata
.
maintainer_email
==
'test@test.com'
def
test_license_cfg
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
DALS
(
"""
[metadata]
name=foo
version=0.0.1
license=Apache 2.0
"""
)
)
with
get_dist
(
tmpdir
)
as
dist
:
metadata
=
dist
.
metadata
assert
metadata
.
name
==
"foo"
assert
metadata
.
version
==
"0.0.1"
assert
metadata
.
license
==
"Apache 2.0"
def
test_file_mixed
(
self
,
tmpdir
):
fake_env
(
...
...
@@ -288,7 +314,7 @@ class TestMetadata:
tmpdir
.
join
(
'fake_package'
,
'version.txt'
).
write
(
'1.2.3
\
n
4.5.6
\
n
'
)
with
pytest
.
raises
(
DistutilsOptionError
):
with
get_dist
(
tmpdir
)
as
dist
:
_
=
dist
.
metadata
.
version
dist
.
metadata
.
version
def
test_version_with_package_dir_simple
(
self
,
tmpdir
):
...
...
@@ -391,6 +417,89 @@ class TestMetadata:
with
get_dist
(
tmpdir
)
as
dist
:
assert
set
(
dist
.
metadata
.
classifiers
)
==
expected
def
test_deprecated_config_handlers
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'[metadata]
\
n
'
'version = 10.1.1
\
n
'
'description = Some description
\
n
'
'requires = some, requirement
\
n
'
)
with
pytest
.
deprecated_call
():
with
get_dist
(
tmpdir
)
as
dist
:
metadata
=
dist
.
metadata
assert
metadata
.
version
==
'10.1.1'
assert
metadata
.
description
==
'Some description'
assert
metadata
.
requires
==
[
'some'
,
'requirement'
]
def
test_interpolation
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'[metadata]
\
n
'
'description = %(message)s
\
n
'
)
with
pytest
.
raises
(
InterpolationMissingOptionError
):
with
get_dist
(
tmpdir
):
pass
skip_if_not_ascii
=
pytest
.
mark
.
skipif
(
not
is_ascii
,
reason
=
'Test not supported with this locale'
)
@
skip_if_not_ascii
def
test_non_ascii_1
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'[metadata]
\
n
'
'description = éàïôñ
\
n
'
,
encoding
=
'utf-8'
)
with
pytest
.
raises
(
UnicodeDecodeError
):
with
get_dist
(
tmpdir
):
pass
def
test_non_ascii_2
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'# -*- coding: invalid
\
n
'
)
with
pytest
.
raises
(
LookupError
):
with
get_dist
(
tmpdir
):
pass
def
test_non_ascii_3
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'
\
n
'
'# -*- coding: invalid
\
n
'
)
with
get_dist
(
tmpdir
):
pass
@
skip_if_not_ascii
def
test_non_ascii_4
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'# -*- coding: utf-8
\
n
'
'[metadata]
\
n
'
'description = éàïôñ
\
n
'
,
encoding
=
'utf-8'
)
with
get_dist
(
tmpdir
)
as
dist
:
assert
dist
.
metadata
.
description
==
'éàïôñ'
@
skip_if_not_ascii
def
test_non_ascii_5
(
self
,
tmpdir
):
fake_env
(
tmpdir
,
'# vim: set fileencoding=iso-8859-15 :
\
n
'
'[metadata]
\
n
'
'description = éàïôñ
\
n
'
,
encoding
=
'iso-8859-15'
)
with
get_dist
(
tmpdir
)
as
dist
:
assert
dist
.
metadata
.
description
==
'éàïôñ'
class
TestOptions
:
...
...
@@ -414,7 +523,7 @@ class TestOptions:
'tests_require = mock==0.7.2; pytest
\
n
'
'setup_requires = docutils>=0.3; spack ==1.1, ==1.3; there
\
n
'
'dependency_links = http://some.com/here/1, '
'http://some.com/there/2
\
n
'
'http://some.com/there/2
\
n
'
'python_requires = >=1.0, !=2.8
\
n
'
'py_modules = module1, module2
\
n
'
)
...
...
@@ -622,7 +731,7 @@ class TestOptions:
dir_sub_two
,
_
=
make_package_dir
(
'sub_two'
,
dir_package
,
ns
=
True
)
with
get_dist
(
tmpdir
)
as
dist
:
assert
set
(
dist
.
packages
)
==
{
assert
set
(
dist
.
packages
)
==
{
'fake_package'
,
'fake_package.sub_two'
,
'fake_package.sub_one'
}
...
...
@@ -674,7 +783,7 @@ class TestOptions:
tmpdir
,
'[options.entry_points]
\
n
'
'group1 = point1 = pack.module:func, '
'.point2 = pack.module2:func_rest [rest]
\
n
'
'.point2 = pack.module2:func_rest [rest]
\
n
'
'group2 = point3 = pack.module:func2
\
n
'
)
...
...
@@ -720,7 +829,10 @@ class TestOptions:
]
assert
sorted
(
dist
.
data_files
)
==
sorted
(
expected
)
saved_dist_init
=
_Distribution
.
__init__
class
TestExternalSetters
:
# During creation of the setuptools Distribution() object, we call
# the init of the parent distutils Distribution object via
...
...
setuptools/tests/test_depends.py
View file @
0551421f
...
...
@@ -5,12 +5,12 @@ from setuptools import depends
class
TestGetModuleConstant
:
def
test_basic
(
self
):
"""
Invoke get_module_constant on a module in
the test package.
"""
mod_name
=
'setuptools.tests.mod_with_constant'
val
=
depends
.
get_module_constant
(
mod_name
,
'value'
)
assert
val
==
'three, sir!'
assert
'setuptools.tests.mod_with_constant'
not
in
sys
.
modules
def
test_basic
(
self
):
"""
Invoke get_module_constant on a module in
the test package.
"""
mod_name
=
'setuptools.tests.mod_with_constant'
val
=
depends
.
get_module_constant
(
mod_name
,
'value'
)
assert
val
==
'three, sir!'
assert
'setuptools.tests.mod_with_constant'
not
in
sys
.
modules
setuptools/tests/test_dist.py
View file @
0551421f
...
...
@@ -3,10 +3,11 @@
from
__future__
import
unicode_literals
import
io
from
setuptools.dist
import
DistDeprecationWarning
,
_get_unpatched
from
setuptools
import
Distribution
from
setuptools.extern.six.moves.urllib.request
import
pathname2url
from
setuptools.extern.six.moves.urllib_parse
import
urljoin
from
setuptools.extern
import
six
from
.textwrap
import
DALS
from
.test_easy_install
import
make_nspkg_sdist
...
...
@@ -56,6 +57,125 @@ def test_dist_fetch_build_egg(tmpdir):
assert
[
dist
.
key
for
dist
in
resolved_dists
if
dist
]
==
reqs
def
test_dist__get_unpatched_deprecated
():
pytest
.
warns
(
DistDeprecationWarning
,
_get_unpatched
,
[
""
])
def
__read_test_cases
():
# Metadata version 1.0
base_attrs
=
{
"name"
:
"package"
,
"version"
:
"0.0.1"
,
"author"
:
"Foo Bar"
,
"author_email"
:
"foo@bar.net"
,
"long_description"
:
"Long
\
n
description"
,
"description"
:
"Short description"
,
"keywords"
:
[
"one"
,
"two"
]
}
def
merge_dicts
(
d1
,
d2
):
d1
=
d1
.
copy
()
d1
.
update
(
d2
)
return
d1
test_cases
=
[
(
'Metadata version 1.0'
,
base_attrs
.
copy
()),
(
'Metadata version 1.1: Provides'
,
merge_dicts
(
base_attrs
,
{
'provides'
:
[
'package'
]
})),
(
'Metadata version 1.1: Obsoletes'
,
merge_dicts
(
base_attrs
,
{
'obsoletes'
:
[
'foo'
]
})),
(
'Metadata version 1.1: Classifiers'
,
merge_dicts
(
base_attrs
,
{
'classifiers'
:
[
'Programming Language :: Python :: 3'
,
'Programming Language :: Python :: 3.7'
,
'License :: OSI Approved :: MIT License'
,
]})),
(
'Metadata version 1.1: Download URL'
,
merge_dicts
(
base_attrs
,
{
'download_url'
:
'https://example.com'
})),
(
'Metadata Version 1.2: Requires-Python'
,
merge_dicts
(
base_attrs
,
{
'python_requires'
:
'>=3.7'
})),
pytest
.
param
(
'Metadata Version 1.2: Project-Url'
,
merge_dicts
(
base_attrs
,
{
'project_urls'
:
{
'Foo'
:
'https://example.bar'
}
}),
marks
=
pytest
.
mark
.
xfail
(
reason
=
"Issue #1578: project_urls not read"
)),
(
'Metadata Version 2.1: Long Description Content Type'
,
merge_dicts
(
base_attrs
,
{
'long_description_content_type'
:
'text/x-rst; charset=UTF-8'
})),
pytest
.
param
(
'Metadata Version 2.1: Provides Extra'
,
merge_dicts
(
base_attrs
,
{
'provides_extras'
:
[
'foo'
,
'bar'
]
}),
marks
=
pytest
.
mark
.
xfail
(
reason
=
"provides_extras not read"
)),
(
'Missing author, missing author e-mail'
,
{
'name'
:
'foo'
,
'version'
:
'1.0.0'
}),
(
'Missing author'
,
{
'name'
:
'foo'
,
'version'
:
'1.0.0'
,
'author_email'
:
'snorri@sturluson.name'
}),
(
'Missing author e-mail'
,
{
'name'
:
'foo'
,
'version'
:
'1.0.0'
,
'author'
:
'Snorri Sturluson'
}),
(
'Missing author'
,
{
'name'
:
'foo'
,
'version'
:
'1.0.0'
,
'author'
:
'Snorri Sturluson'
}),
]
return
test_cases
@
pytest
.
mark
.
parametrize
(
'name,attrs'
,
__read_test_cases
())
def
test_read_metadata
(
name
,
attrs
):
dist
=
Distribution
(
attrs
)
metadata_out
=
dist
.
metadata
dist_class
=
metadata_out
.
__class__
# Write to PKG_INFO and then load into a new metadata object
if
six
.
PY2
:
PKG_INFO
=
io
.
BytesIO
()
else
:
PKG_INFO
=
io
.
StringIO
()
metadata_out
.
write_pkg_file
(
PKG_INFO
)
PKG_INFO
.
seek
(
0
)
metadata_in
=
dist_class
()
metadata_in
.
read_pkg_file
(
PKG_INFO
)
tested_attrs
=
[
(
'name'
,
dist_class
.
get_name
),
(
'version'
,
dist_class
.
get_version
),
(
'author'
,
dist_class
.
get_contact
),
(
'author_email'
,
dist_class
.
get_contact_email
),
(
'metadata_version'
,
dist_class
.
get_metadata_version
),
(
'provides'
,
dist_class
.
get_provides
),
(
'description'
,
dist_class
.
get_description
),
(
'download_url'
,
dist_class
.
get_download_url
),
(
'keywords'
,
dist_class
.
get_keywords
),
(
'platforms'
,
dist_class
.
get_platforms
),
(
'obsoletes'
,
dist_class
.
get_obsoletes
),
(
'requires'
,
dist_class
.
get_requires
),
(
'classifiers'
,
dist_class
.
get_classifiers
),
(
'project_urls'
,
lambda
s
:
getattr
(
s
,
'project_urls'
,
{})),
(
'provides_extras'
,
lambda
s
:
getattr
(
s
,
'provides_extras'
,
set
())),
]
for
attr
,
getter
in
tested_attrs
:
assert
getter
(
metadata_in
)
==
getter
(
metadata_out
)
def
__maintainer_test_cases
():
attrs
=
{
"name"
:
"package"
,
"version"
:
"1.0"
,
...
...
setuptools/tests/test_easy_install.py
View file @
0551421f
...
...
@@ -15,7 +15,9 @@ import distutils.errors
import
io
import
zipfile
import
mock
from
setuptools.command.easy_install
import
(
EasyInstallDeprecationWarning
,
ScriptWriter
,
WindowsScriptWriter
,
)
import
time
from
setuptools.extern
import
six
from
setuptools.extern.six.moves
import
urllib
...
...
@@ -287,6 +289,22 @@ class TestEasyInstallTest:
cmd
.
easy_install
(
sdist_script
)
assert
(
target
/
'mypkg_script'
).
exists
()
def
test_dist_get_script_args_deprecated
(
self
):
with
pytest
.
warns
(
EasyInstallDeprecationWarning
):
ScriptWriter
.
get_script_args
(
None
,
None
)
def
test_dist_get_script_header_deprecated
(
self
):
with
pytest
.
warns
(
EasyInstallDeprecationWarning
):
ScriptWriter
.
get_script_header
(
""
)
def
test_dist_get_writer_deprecated
(
self
):
with
pytest
.
warns
(
EasyInstallDeprecationWarning
):
ScriptWriter
.
get_writer
(
None
)
def
test_dist_WindowsScriptWriter_get_writer_deprecated
(
self
):
with
pytest
.
warns
(
EasyInstallDeprecationWarning
):
WindowsScriptWriter
.
get_writer
()
@
pytest
.
mark
.
filterwarnings
(
'ignore:Unbuilt egg'
)
class
TestPTHFileWriter
:
...
...
setuptools/tests/test_egg_info.py
View file @
0551421f
import
datetime
import
sys
import
ast
import
os
...
...
@@ -7,7 +6,9 @@ import re
import
stat
import
time
from
setuptools.command.egg_info
import
egg_info
,
manifest_maker
from
setuptools.command.egg_info
import
(
egg_info
,
manifest_maker
,
EggInfoDeprecationWarning
,
get_pkg_info_revision
,
)
from
setuptools.dist
import
Distribution
from
setuptools.extern.six.moves
import
map
...
...
@@ -148,6 +149,37 @@ class TestEggInfo:
]
assert
sorted
(
actual
)
==
expected
def
test_license_is_a_string
(
self
,
tmpdir_cwd
,
env
):
setup_config
=
DALS
(
"""
[metadata]
name=foo
version=0.0.1
license=file:MIT
"""
)
setup_script
=
DALS
(
"""
from setuptools import setup
setup()
"""
)
build_files
({
'setup.py'
:
setup_script
,
'setup.cfg'
:
setup_config
})
# This command should fail with a ValueError, but because it's
# currently configured to use a subprocess, the actual traceback
# object is lost and we need to parse it from stderr
with
pytest
.
raises
(
AssertionError
)
as
exc
:
self
.
_run_egg_info_command
(
tmpdir_cwd
,
env
)
# Hopefully this is not too fragile: the only argument to the
# assertion error should be a traceback, ending with:
# ValueError: ....
#
# assert not 1
tb
=
exc
.
value
.
args
[
0
].
split
(
'
\
n
'
)
assert
tb
[
-
3
].
lstrip
().
startswith
(
'ValueError'
)
def
test_rebuilt
(
self
,
tmpdir_cwd
,
env
):
"""Ensure timestamps are updated when the command is re-run."""
self
.
_create_project
()
...
...
@@ -618,6 +650,20 @@ class TestEggInfo:
for
msg
in
fixtures
:
assert
manifest_maker
.
_should_suppress_warning
(
msg
)
def
test_egg_info_includes_setup_py
(
self
,
tmpdir_cwd
):
self
.
_create_project
()
dist
=
Distribution
({
"name"
:
"foo"
,
"version"
:
"0.0.1"
})
dist
.
script_name
=
"non_setup.py"
egg_info_instance
=
egg_info
(
dist
)
egg_info_instance
.
finalize_options
()
egg_info_instance
.
run
()
assert
'setup.py'
in
egg_info_instance
.
filelist
.
files
with
open
(
egg_info_instance
.
egg_info
+
"/SOURCES.txt"
)
as
f
:
sources
=
f
.
read
().
split
(
'
\
n
'
)
assert
'setup.py'
in
sources
def
_run_egg_info_command
(
self
,
tmpdir_cwd
,
env
,
cmd
=
None
,
output
=
None
):
environ
=
os
.
environ
.
copy
().
update
(
HOME
=
env
.
paths
[
'home'
],
...
...
@@ -632,8 +678,8 @@ class TestEggInfo:
data_stream
=
1
,
env
=
environ
,
)
if
code
:
raise
AssertionError
(
data
)
assert
not
code
,
data
if
output
:
assert
output
in
data
...
...
@@ -652,3 +698,52 @@ class TestEggInfo:
with
open
(
os
.
path
.
join
(
egg_info_dir
,
'PKG-INFO'
))
as
pkginfo_file
:
pkg_info_lines
=
pkginfo_file
.
read
().
split
(
'
\
n
'
)
assert
'Version: 0.0.0.dev0'
in
pkg_info_lines
def
test_get_pkg_info_revision_deprecated
(
self
):
pytest
.
warns
(
EggInfoDeprecationWarning
,
get_pkg_info_revision
)
EGG_INFO_TESTS
=
(
# Check for issue #1136: invalid string type when
# reading declarative `setup.cfg` under Python 2.
{
'setup.py'
:
DALS
(
"""
from setuptools import setup
setup(
name="foo",
)
"""
),
'setup.cfg'
:
DALS
(
"""
[options]
package_dir =
= src
"""
),
'src'
:
{},
},
# Check Unicode can be used in `setup.py` under Python 2.
{
'setup.py'
:
DALS
(
"""
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from setuptools import setup, find_packages
setup(
name="foo",
package_dir={'': 'src'},
)
"""
),
'src'
:
{},
}
)
@
pytest
.
mark
.
parametrize
(
'package_files'
,
EGG_INFO_TESTS
)
def
test_egg_info
(
self
,
tmpdir_cwd
,
env
,
package_files
):
"""
"""
build_files
(
package_files
)
code
,
data
=
environment
.
run_setup_py
(
cmd
=
[
'egg_info'
],
data_stream
=
1
,
)
assert
not
code
,
data
setuptools/tests/test_find_packages.py
View file @
0551421f
...
...
@@ -12,10 +12,10 @@ from . import py3_only
from
setuptools.extern.six
import
PY3
from
setuptools
import
find_packages
if
PY3
:
from
setuptools
import
find_namespace_packages
from
setuptools
import
find_namespace_packages
# modeled after CPython's test.support.can_symlink
# modeled after CPython's test.support.can_symlink
def
can_symlink
():
TESTFN
=
tempfile
.
mktemp
()
symlink_path
=
TESTFN
+
"can_symlink"
...
...
@@ -164,12 +164,14 @@ class TestFindPackages:
def
test_pep420_ns_package_no_includes
(
self
):
packages
=
find_namespace_packages
(
self
.
dist_dir
,
exclude
=
[
'pkg.subpkg.assets'
])
self
.
_assert_packages
(
packages
,
[
'docs'
,
'pkg'
,
'pkg.nspkg'
,
'pkg.subpkg'
])
self
.
_assert_packages
(
packages
,
[
'docs'
,
'pkg'
,
'pkg.nspkg'
,
'pkg.subpkg'
])
@
py3_only
def
test_pep420_ns_package_no_includes_or_excludes
(
self
):
packages
=
find_namespace_packages
(
self
.
dist_dir
)
expected
=
[
'docs'
,
'pkg'
,
'pkg.nspkg'
,
'pkg.subpkg'
,
'pkg.subpkg.assets'
]
expected
=
[
'docs'
,
'pkg'
,
'pkg.nspkg'
,
'pkg.subpkg'
,
'pkg.subpkg.assets'
]
self
.
_assert_packages
(
packages
,
expected
)
@
py3_only
...
...
@@ -185,4 +187,3 @@ class TestFindPackages:
shutil
.
rmtree
(
os
.
path
.
join
(
self
.
dist_dir
,
'pkg/subpkg/assets'
))
packages
=
find_namespace_packages
(
self
.
dist_dir
)
self
.
_assert_packages
(
packages
,
[
'pkg'
,
'pkg.nspkg'
,
'pkg.subpkg'
])
setuptools/tests/test_install_scripts.py
View file @
0551421f
...
...
@@ -64,7 +64,8 @@ class TestInstallScripts:
@
pytest
.
mark
.
skipif
(
sys
.
platform
==
'win32'
,
reason
=
'non-Windows only'
)
def
test_executable_with_spaces_escaping_unix
(
self
,
tmpdir
):
"""
Ensure that shebang on Unix is not quoted, even when a value with spaces
Ensure that shebang on Unix is not quoted, even when
a value with spaces
is specified using --executable.
"""
expected
=
'#!%s
\
n
'
%
self
.
unix_spaces_exe
...
...
@@ -77,7 +78,8 @@ class TestInstallScripts:
@
pytest
.
mark
.
skipif
(
sys
.
platform
!=
'win32'
,
reason
=
'Windows only'
)
def
test_executable_arg_escaping_win32
(
self
,
tmpdir
):
"""
Ensure that shebang on Windows is quoted when getting a path with spaces
Ensure that shebang on Windows is quoted when
getting a path with spaces
from --executable, that is itself properly quoted.
"""
expected
=
'#!"%s"
\
n
'
%
self
.
win32_exe
...
...
setuptools/tests/test_integration.py
View file @
0551421f
...
...
@@ -6,6 +6,11 @@ Try to install a few packages.
import
glob
import
os
import
sys
import
re
import
subprocess
import
functools
import
tarfile
import
zipfile
from
setuptools.extern.six.moves
import
urllib
import
pytest
...
...
@@ -114,15 +119,12 @@ def test_pyuri(install_context):
assert
os
.
path
.
exists
(
os
.
path
.
join
(
pyuri
.
location
,
'pyuri'
,
'uri.regex'
))
import
re
import
subprocess
import
functools
import
tarfile
,
zipfile
build_deps
=
[
'appdirs'
,
'packaging'
,
'pyparsing'
,
'six'
]
build_deps
=
[
'appdirs'
,
'packaging'
,
'pyparsing'
,
'six'
]
@
pytest
.
mark
.
parametrize
(
"build_dep"
,
build_deps
)
@
pytest
.
mark
.
skipif
(
sys
.
version_info
<
(
3
,
6
),
reason
=
'run only on late versions'
)
@
pytest
.
mark
.
skipif
(
sys
.
version_info
<
(
3
,
6
),
reason
=
'run only on late versions'
)
def
test_build_deps_on_distutils
(
request
,
tmpdir_factory
,
build_dep
):
"""
All setuptools build dependencies must build without
...
...
@@ -149,13 +151,16 @@ def install(pkg_dir, install_dir):
breaker
.
write
(
'raise ImportError()'
)
cmd
=
[
sys
.
executable
,
'setup.py'
,
'install'
,
'--prefix'
,
install_dir
]
env
=
dict
(
os
.
environ
,
PYTHONPATH
=
pkg_dir
)
output
=
subprocess
.
check_output
(
cmd
,
cwd
=
pkg_dir
,
env
=
env
,
stderr
=
subprocess
.
STDOUT
)
output
=
subprocess
.
check_output
(
cmd
,
cwd
=
pkg_dir
,
env
=
env
,
stderr
=
subprocess
.
STDOUT
)
return
output
.
decode
(
'utf-8'
)
def
download_and_extract
(
request
,
req
,
target
):
cmd
=
[
sys
.
executable
,
'-m'
,
'pip'
,
'download'
,
'--no-deps'
,
'--no-binary'
,
':all:'
,
req
]
cmd
=
[
sys
.
executable
,
'-m'
,
'pip'
,
'download'
,
'--no-deps'
,
'--no-binary'
,
':all:'
,
req
,
]
output
=
subprocess
.
check_output
(
cmd
,
encoding
=
'utf-8'
)
filename
=
re
.
search
(
'Saved (.*)'
,
output
).
group
(
1
)
request
.
addfinalizer
(
functools
.
partial
(
os
.
remove
,
filename
))
...
...
setuptools/tests/test_manifest.py
View file @
0551421f
...
...
@@ -20,8 +20,6 @@ import pytest
__metaclass__
=
type
py3_only
=
pytest
.
mark
.
xfail
(
six
.
PY2
,
reason
=
"Test runs on Python 3 only"
)
def
make_local_path
(
s
):
"""Converts '/' in a string to os.sep"""
...
...
@@ -75,7 +73,9 @@ translate_specs = [
# Glob matching
(
'*.txt'
,
[
'foo.txt'
,
'bar.txt'
],
[
'foo/foo.txt'
]),
(
'dir/*.txt'
,
[
'dir/foo.txt'
,
'dir/bar.txt'
,
'dir/.txt'
],
[
'notdir/foo.txt'
]),
(
'dir/*.txt'
,
[
'dir/foo.txt'
,
'dir/bar.txt'
,
'dir/.txt'
],
[
'notdir/foo.txt'
]),
(
'*/*.py'
,
[
'bin/start.py'
],
[]),
(
'docs/page-?.txt'
,
[
'docs/page-9.txt'
],
[
'docs/page-10.txt'
]),
...
...
@@ -244,77 +244,77 @@ class TestManifestTest(TempDirTestCase):
def
test_exclude
(
self
):
"""Include everything in app/ except the text files"""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"""
include app/*
exclude app/*.txt
"""
)
files
=
default_files
|
set
([
l
(
'app/c.rst'
)])
files
=
default_files
|
set
([
m
l
(
'app/c.rst'
)])
assert
files
==
self
.
get_files
()
def
test_include_multiple
(
self
):
"""Include with multiple patterns."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"include app/*.txt app/static/*"
)
files
=
default_files
|
set
([
l
(
'app/a.txt'
),
l
(
'app/b.txt'
),
l
(
'app/static/app.js'
),
l
(
'app/static/app.js.map'
),
l
(
'app/static/app.css'
),
l
(
'app/static/app.css.map'
)])
ml
(
'app/a.txt'
),
m
l
(
'app/b.txt'
),
ml
(
'app/static/app.js'
),
m
l
(
'app/static/app.js.map'
),
ml
(
'app/static/app.css'
),
m
l
(
'app/static/app.css.map'
)])
assert
files
==
self
.
get_files
()
def
test_graft
(
self
):
"""Include the whole app/static/ directory."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"graft app/static"
)
files
=
default_files
|
set
([
l
(
'app/static/app.js'
),
l
(
'app/static/app.js.map'
),
l
(
'app/static/app.css'
),
l
(
'app/static/app.css.map'
)])
ml
(
'app/static/app.js'
),
m
l
(
'app/static/app.js.map'
),
ml
(
'app/static/app.css'
),
m
l
(
'app/static/app.css.map'
)])
assert
files
==
self
.
get_files
()
def
test_graft_glob_syntax
(
self
):
"""Include the whole app/static/ directory."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"graft */static"
)
files
=
default_files
|
set
([
l
(
'app/static/app.js'
),
l
(
'app/static/app.js.map'
),
l
(
'app/static/app.css'
),
l
(
'app/static/app.css.map'
)])
ml
(
'app/static/app.js'
),
m
l
(
'app/static/app.js.map'
),
ml
(
'app/static/app.css'
),
m
l
(
'app/static/app.css.map'
)])
assert
files
==
self
.
get_files
()
def
test_graft_global_exclude
(
self
):
"""Exclude all *.map files in the project."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"""
graft app/static
global-exclude *.map
"""
)
files
=
default_files
|
set
([
l
(
'app/static/app.js'
),
l
(
'app/static/app.css'
)])
ml
(
'app/static/app.js'
),
m
l
(
'app/static/app.css'
)])
assert
files
==
self
.
get_files
()
def
test_global_include
(
self
):
"""Include all *.rst, *.js, and *.css files in the whole tree."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"""
global-include *.rst *.js *.css
"""
)
files
=
default_files
|
set
([
'.hidden.rst'
,
'testing.rst'
,
l
(
'app/c.rst'
),
l
(
'app/static/app.js'
),
l
(
'app/static/app.css'
)])
'.hidden.rst'
,
'testing.rst'
,
m
l
(
'app/c.rst'
),
ml
(
'app/static/app.js'
),
m
l
(
'app/static/app.css'
)])
assert
files
==
self
.
get_files
()
def
test_graft_prune
(
self
):
"""Include all files in app/, except for the whole app/static/ dir."""
l
=
make_local_path
m
l
=
make_local_path
self
.
make_manifest
(
"""
graft app
prune app/static
"""
)
files
=
default_files
|
set
([
l
(
'app/a.txt'
),
l
(
'app/b.txt'
),
l
(
'app/c.rst'
)])
ml
(
'app/a.txt'
),
ml
(
'app/b.txt'
),
m
l
(
'app/c.rst'
)])
assert
files
==
self
.
get_files
()
...
...
@@ -370,7 +370,7 @@ class TestFileListTest(TempDirTestCase):
def
test_process_template_line
(
self
):
# testing all MANIFEST.in template patterns
file_list
=
FileList
()
l
=
make_local_path
m
l
=
make_local_path
# simulated file list
self
.
make_files
([
...
...
@@ -378,16 +378,16 @@ class TestFileListTest(TempDirTestCase):
'buildout.cfg'
,
# filelist does not filter out VCS directories,
# it's sdist that does
l
(
'.hg/last-message.txt'
),
l
(
'global/one.txt'
),
l
(
'global/two.txt'
),
l
(
'global/files.x'
),
l
(
'global/here.tmp'
),
l
(
'f/o/f.oo'
),
l
(
'dir/graft-one'
),
l
(
'dir/dir2/graft2'
),
l
(
'dir3/ok'
),
l
(
'dir3/sub/ok.txt'
),
m
l
(
'.hg/last-message.txt'
),
m
l
(
'global/one.txt'
),
m
l
(
'global/two.txt'
),
m
l
(
'global/files.x'
),
m
l
(
'global/here.tmp'
),
m
l
(
'f/o/f.oo'
),
m
l
(
'dir/graft-one'
),
m
l
(
'dir/dir2/graft2'
),
m
l
(
'dir3/ok'
),
m
l
(
'dir3/sub/ok.txt'
),
])
MANIFEST_IN
=
DALS
(
"""
\
...
...
@@ -414,12 +414,12 @@ class TestFileListTest(TempDirTestCase):
'buildout.cfg'
,
'four.txt'
,
'ok'
,
l
(
'.hg/last-message.txt'
),
l
(
'dir/graft-one'
),
l
(
'dir/dir2/graft2'
),
l
(
'f/o/f.oo'
),
l
(
'global/one.txt'
),
l
(
'global/two.txt'
),
m
l
(
'.hg/last-message.txt'
),
m
l
(
'dir/graft-one'
),
m
l
(
'dir/dir2/graft2'
),
m
l
(
'f/o/f.oo'
),
m
l
(
'global/one.txt'
),
m
l
(
'global/two.txt'
),
]
file_list
.
sort
()
...
...
@@ -476,10 +476,10 @@ class TestFileListTest(TempDirTestCase):
assert
False
,
"Should have thrown an error"
def
test_include
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# include
file_list
=
FileList
()
self
.
make_files
([
'a.py'
,
'b.txt'
,
l
(
'd/c.py'
)])
self
.
make_files
([
'a.py'
,
'b.txt'
,
m
l
(
'd/c.py'
)])
file_list
.
process_template_line
(
'include *.py'
)
file_list
.
sort
()
...
...
@@ -492,42 +492,42 @@ class TestFileListTest(TempDirTestCase):
self
.
assertWarnings
()
def
test_exclude
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# exclude
file_list
=
FileList
()
file_list
.
files
=
[
'a.py'
,
'b.txt'
,
l
(
'd/c.py'
)]
file_list
.
files
=
[
'a.py'
,
'b.txt'
,
m
l
(
'd/c.py'
)]
file_list
.
process_template_line
(
'exclude *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'b.txt'
,
l
(
'd/c.py'
)]
assert
file_list
.
files
==
[
'b.txt'
,
m
l
(
'd/c.py'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'exclude *.rb'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'b.txt'
,
l
(
'd/c.py'
)]
assert
file_list
.
files
==
[
'b.txt'
,
m
l
(
'd/c.py'
)]
self
.
assertWarnings
()
def
test_global_include
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# global-include
file_list
=
FileList
()
self
.
make_files
([
'a.py'
,
'b.txt'
,
l
(
'd/c.py'
)])
self
.
make_files
([
'a.py'
,
'b.txt'
,
m
l
(
'd/c.py'
)])
file_list
.
process_template_line
(
'global-include *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'd/c.py'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'd/c.py'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'global-include *.rb'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'd/c.py'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'd/c.py'
)]
self
.
assertWarnings
()
def
test_global_exclude
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# global-exclude
file_list
=
FileList
()
file_list
.
files
=
[
'a.py'
,
'b.txt'
,
l
(
'd/c.py'
)]
file_list
.
files
=
[
'a.py'
,
'b.txt'
,
m
l
(
'd/c.py'
)]
file_list
.
process_template_line
(
'global-exclude *.py'
)
file_list
.
sort
()
...
...
@@ -540,65 +540,65 @@ class TestFileListTest(TempDirTestCase):
self
.
assertWarnings
()
def
test_recursive_include
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# recursive-include
file_list
=
FileList
()
self
.
make_files
([
'a.py'
,
l
(
'd/b.py'
),
l
(
'd/c.txt'
),
l
(
'd/d/e.py'
)])
self
.
make_files
([
'a.py'
,
ml
(
'd/b.py'
),
ml
(
'd/c.txt'
),
m
l
(
'd/d/e.py'
)])
file_list
.
process_template_line
(
'recursive-include d *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
l
(
'd/b.py'
),
l
(
'd/d/e.py'
)]
assert
file_list
.
files
==
[
ml
(
'd/b.py'
),
m
l
(
'd/d/e.py'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'recursive-include e *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
l
(
'd/b.py'
),
l
(
'd/d/e.py'
)]
assert
file_list
.
files
==
[
ml
(
'd/b.py'
),
m
l
(
'd/d/e.py'
)]
self
.
assertWarnings
()
def
test_recursive_exclude
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# recursive-exclude
file_list
=
FileList
()
file_list
.
files
=
[
'a.py'
,
l
(
'd/b.py'
),
l
(
'd/c.txt'
),
l
(
'd/d/e.py'
)]
file_list
.
files
=
[
'a.py'
,
ml
(
'd/b.py'
),
ml
(
'd/c.txt'
),
m
l
(
'd/d/e.py'
)]
file_list
.
process_template_line
(
'recursive-exclude d *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'd/c.txt'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'd/c.txt'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'recursive-exclude e *.py'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'd/c.txt'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'd/c.txt'
)]
self
.
assertWarnings
()
def
test_graft
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# graft
file_list
=
FileList
()
self
.
make_files
([
'a.py'
,
l
(
'd/b.py'
),
l
(
'd/d/e.py'
),
l
(
'f/f.py'
)])
self
.
make_files
([
'a.py'
,
ml
(
'd/b.py'
),
ml
(
'd/d/e.py'
),
m
l
(
'f/f.py'
)])
file_list
.
process_template_line
(
'graft d'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
l
(
'd/b.py'
),
l
(
'd/d/e.py'
)]
assert
file_list
.
files
==
[
ml
(
'd/b.py'
),
m
l
(
'd/d/e.py'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'graft e'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
l
(
'd/b.py'
),
l
(
'd/d/e.py'
)]
assert
file_list
.
files
==
[
ml
(
'd/b.py'
),
m
l
(
'd/d/e.py'
)]
self
.
assertWarnings
()
def
test_prune
(
self
):
l
=
make_local_path
m
l
=
make_local_path
# prune
file_list
=
FileList
()
file_list
.
files
=
[
'a.py'
,
l
(
'd/b.py'
),
l
(
'd/d/e.py'
),
l
(
'f/f.py'
)]
file_list
.
files
=
[
'a.py'
,
ml
(
'd/b.py'
),
ml
(
'd/d/e.py'
),
m
l
(
'f/f.py'
)]
file_list
.
process_template_line
(
'prune d'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'f/f.py'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'f/f.py'
)]
self
.
assertNoWarnings
()
file_list
.
process_template_line
(
'prune e'
)
file_list
.
sort
()
assert
file_list
.
files
==
[
'a.py'
,
l
(
'f/f.py'
)]
assert
file_list
.
files
==
[
'a.py'
,
m
l
(
'f/f.py'
)]
self
.
assertWarnings
()
setuptools/tests/test_msvc.py
View file @
0551421f
...
...
@@ -49,7 +49,8 @@ def mock_reg(hkcu=None, hklm=None):
for
k
in
hive
if
k
.
startswith
(
key
.
lower
())
)
return
mock
.
patch
.
multiple
(
distutils
.
msvc9compiler
.
Reg
,
return
mock
.
patch
.
multiple
(
distutils
.
msvc9compiler
.
Reg
,
read_keys
=
read_keys
,
read_values
=
read_values
)
...
...
@@ -61,7 +62,7 @@ class TestModulePatch:
"""
key_32
=
r'software\
mic
rosoft\
de
vdiv\vcforpython\
9.
0\
i
nstalldir'
key_64
=
r'software\
wow
6432node\
mic
rosoft\
de
vdiv\vcforpython\
9.
0\
i
nstalldir'
key_64
=
key_32
.
replace
(
r'\
mic
rosoft'
,
r'\
wow
6432node\
mic
rosoft'
)
def
test_patched
(
self
):
"Test the module is actually patched"
...
...
setuptools/tests/test_namespaces.py
View file @
0551421f
from
__future__
import
absolute_import
,
unicode_literals
import
os
import
sys
import
subprocess
...
...
@@ -12,7 +11,7 @@ from setuptools.command import test
class
TestNamespaces
:
@
pytest
.
mark
.
xfail
(
@
pytest
.
mark
.
skipif
(
sys
.
version_info
<
(
3
,
5
),
reason
=
"Requires importlib.util.module_from_spec"
,
)
...
...
setuptools/tests/test_packageindex.py
View file @
0551421f
...
...
@@ -6,6 +6,8 @@ import distutils.errors
from
setuptools.extern
import
six
from
setuptools.extern.six.moves
import
urllib
,
http_client
import
mock
import
pytest
import
pkg_resources
import
setuptools.package_index
...
...
@@ -42,7 +44,10 @@ class TestPackageIndex:
hosts
=
(
'www.example.com'
,)
)
url
=
'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk'
url
=
(
'url:%20https://svn.plone.org/svn'
'/collective/inquant.contentmirror.plone/trunk'
)
try
:
v
=
index
.
open_url
(
url
)
except
Exception
as
v
:
...
...
@@ -61,9 +66,9 @@ class TestPackageIndex:
index
.
opener
=
_urlopen
url
=
'http://example.com'
try
:
v
=
index
.
open_url
(
url
)
except
Exception
as
v
:
assert
'line'
in
str
(
v
)
index
.
open_url
(
url
)
except
Exception
as
exc
:
assert
'line'
in
str
(
exc
)
else
:
raise
AssertionError
(
'Should have raise here!'
)
...
...
@@ -81,7 +86,11 @@ class TestPackageIndex:
index
.
open_url
(
url
)
except
distutils
.
errors
.
DistutilsError
as
error
:
msg
=
six
.
text_type
(
error
)
assert
'nonnumeric port'
in
msg
or
'getaddrinfo failed'
in
msg
or
'Name or service not known'
in
msg
assert
(
'nonnumeric port'
in
msg
or
'getaddrinfo failed'
in
msg
or
'Name or service not known'
in
msg
)
return
raise
RuntimeError
(
"Did not raise"
)
...
...
@@ -223,6 +232,61 @@ class TestPackageIndex:
assert
dists
[
0
].
version
==
''
assert
dists
[
1
].
version
==
vc
def
test_download_git_with_rev
(
self
,
tmpdir
):
url
=
'git+https://github.example/group/project@master#egg=foo'
index
=
setuptools
.
package_index
.
PackageIndex
()
with
mock
.
patch
(
"os.system"
)
as
os_system_mock
:
result
=
index
.
download
(
url
,
str
(
tmpdir
))
os_system_mock
.
assert_called
()
expected_dir
=
str
(
tmpdir
/
'project@master'
)
expected
=
(
'git clone --quiet '
'https://github.example/group/project {expected_dir}'
).
format
(
**
locals
())
first_call_args
=
os_system_mock
.
call_args_list
[
0
][
0
]
assert
first_call_args
==
(
expected
,)
tmpl
=
'(cd {expected_dir} && git checkout --quiet master)'
expected
=
tmpl
.
format
(
**
locals
())
assert
os_system_mock
.
call_args_list
[
1
][
0
]
==
(
expected
,)
assert
result
==
expected_dir
def
test_download_git_no_rev
(
self
,
tmpdir
):
url
=
'git+https://github.example/group/project#egg=foo'
index
=
setuptools
.
package_index
.
PackageIndex
()
with
mock
.
patch
(
"os.system"
)
as
os_system_mock
:
result
=
index
.
download
(
url
,
str
(
tmpdir
))
os_system_mock
.
assert_called
()
expected_dir
=
str
(
tmpdir
/
'project'
)
expected
=
(
'git clone --quiet '
'https://github.example/group/project {expected_dir}'
).
format
(
**
locals
())
os_system_mock
.
assert_called_once_with
(
expected
)
def
test_download_svn
(
self
,
tmpdir
):
url
=
'svn+https://svn.example/project#egg=foo'
index
=
setuptools
.
package_index
.
PackageIndex
()
with
pytest
.
warns
(
UserWarning
):
with
mock
.
patch
(
"os.system"
)
as
os_system_mock
:
result
=
index
.
download
(
url
,
str
(
tmpdir
))
os_system_mock
.
assert_called
()
expected_dir
=
str
(
tmpdir
/
'project'
)
expected
=
(
'svn checkout -q '
'svn+https://svn.example/project {expected_dir}'
).
format
(
**
locals
())
os_system_mock
.
assert_called_once_with
(
expected
)
class
TestContentCheckers
:
def
test_md5
(
self
):
...
...
setuptools/tests/test_pep425tags.py
View file @
0551421f
...
...
@@ -32,7 +32,9 @@ class TestPEP425Tags:
if
sys
.
version_info
<
(
3
,
3
):
config_vars
.
update
({
'Py_UNICODE_SIZE'
:
2
})
mock_gcf
=
self
.
mock_get_config_var
(
**
config_vars
)
with
patch
(
'setuptools.pep425tags.sysconfig.get_config_var'
,
mock_gcf
):
with
patch
(
'setuptools.pep425tags.sysconfig.get_config_var'
,
mock_gcf
):
abi_tag
=
pep425tags
.
get_abi_tag
()
assert
abi_tag
==
base
+
flags
...
...
setuptools/tests/test_sandbox.py
View file @
0551421f
...
...
@@ -26,7 +26,8 @@ class TestSandbox:
"""
It should be possible to execute a setup.py with a Byte Order Mark
"""
target
=
pkg_resources
.
resource_filename
(
__name__
,
target
=
pkg_resources
.
resource_filename
(
__name__
,
'script-with-bom.py'
)
namespace
=
types
.
ModuleType
(
'namespace'
)
setuptools
.
sandbox
.
_execfile
(
target
,
vars
(
namespace
))
...
...
setuptools/tests/test_sdist.py
View file @
0551421f
...
...
@@ -20,8 +20,8 @@ from setuptools.command.egg_info import manifest_maker
from
setuptools.dist
import
Distribution
from
setuptools.tests
import
fail_on_ascii
from
.text
import
Filenames
from
.
import
py3_only
py3_only
=
pytest
.
mark
.
xfail
(
six
.
PY2
,
reason
=
"Test runs on Python 3 only"
)
SETUP_ATTRS
=
{
'name'
:
'sdist_test'
,
...
...
@@ -92,9 +92,8 @@ fail_on_latin1_encoded_filenames = pytest.mark.xfail(
class
TestSdistTest
:
def
setup_method
(
self
,
method
):
self
.
temp_dir
=
tempfile
.
mkdtemp
()
f
=
open
(
os
.
path
.
join
(
self
.
temp_dir
,
'setup.py'
),
'w'
)
f
.
write
(
SETUP_PY
)
f
.
close
()
with
open
(
os
.
path
.
join
(
self
.
temp_dir
,
'setup.py'
),
'w'
)
as
f
:
f
.
write
(
SETUP_PY
)
# Set up the rest of the test package
test_pkg
=
os
.
path
.
join
(
self
.
temp_dir
,
'sdist_test'
)
...
...
@@ -135,6 +134,47 @@ class TestSdistTest:
assert
os
.
path
.
join
(
'sdist_test'
,
'c.rst'
)
not
in
manifest
assert
os
.
path
.
join
(
'd'
,
'e.dat'
)
in
manifest
def
test_setup_py_exists
(
self
):
dist
=
Distribution
(
SETUP_ATTRS
)
dist
.
script_name
=
'foo.py'
cmd
=
sdist
(
dist
)
cmd
.
ensure_finalized
()
with
quiet
():
cmd
.
run
()
manifest
=
cmd
.
filelist
.
files
assert
'setup.py'
in
manifest
def
test_setup_py_missing
(
self
):
dist
=
Distribution
(
SETUP_ATTRS
)
dist
.
script_name
=
'foo.py'
cmd
=
sdist
(
dist
)
cmd
.
ensure_finalized
()
if
os
.
path
.
exists
(
"setup.py"
):
os
.
remove
(
"setup.py"
)
with
quiet
():
cmd
.
run
()
manifest
=
cmd
.
filelist
.
files
assert
'setup.py'
not
in
manifest
def
test_setup_py_excluded
(
self
):
with
open
(
"MANIFEST.in"
,
"w"
)
as
manifest_file
:
manifest_file
.
write
(
"exclude setup.py"
)
dist
=
Distribution
(
SETUP_ATTRS
)
dist
.
script_name
=
'foo.py'
cmd
=
sdist
(
dist
)
cmd
.
ensure_finalized
()
with
quiet
():
cmd
.
run
()
manifest
=
cmd
.
filelist
.
files
assert
'setup.py'
not
in
manifest
def
test_defaults_case_sensitivity
(
self
):
"""
Make sure default files (README.*, etc.) are added in a case-sensitive
...
...
setuptools/tests/test_setuptools.py
View file @
0551421f
...
...
@@ -77,7 +77,8 @@ class TestDepends:
from
json
import
__version__
assert
dep
.
get_module_constant
(
'json'
,
'__version__'
)
==
__version__
assert
dep
.
get_module_constant
(
'sys'
,
'version'
)
==
sys
.
version
assert
dep
.
get_module_constant
(
'setuptools.tests.test_setuptools'
,
'__doc__'
)
==
__doc__
assert
dep
.
get_module_constant
(
'setuptools.tests.test_setuptools'
,
'__doc__'
)
==
__doc__
@
needs_bytecode
def
testRequire
(
self
):
...
...
@@ -216,7 +217,8 @@ class TestFeatures:
self
.
req
=
Require
(
'Distutils'
,
'1.0.3'
,
'distutils'
)
self
.
dist
=
makeSetup
(
features
=
{
'foo'
:
Feature
(
"foo"
,
standard
=
True
,
require_features
=
[
'baz'
,
self
.
req
]),
'foo'
:
Feature
(
"foo"
,
standard
=
True
,
require_features
=
[
'baz'
,
self
.
req
]),
'bar'
:
Feature
(
"bar"
,
standard
=
True
,
packages
=
[
'pkg.bar'
],
py_modules
=
[
'bar_et'
],
remove
=
[
'bar.ext'
],
),
...
...
@@ -252,7 +254,8 @@ class TestFeatures:
(
'with-dwim'
,
None
,
'include DWIM'
)
in
dist
.
feature_options
)
assert
(
(
'without-dwim'
,
None
,
'exclude DWIM (default)'
)
in
dist
.
feature_options
(
'without-dwim'
,
None
,
'exclude DWIM (default)'
)
in
dist
.
feature_options
)
assert
(
(
'with-bar'
,
None
,
'include bar (default)'
)
in
dist
.
feature_options
...
...
setuptools/tests/test_test.py
View file @
0551421f
...
...
@@ -4,7 +4,6 @@ from __future__ import unicode_literals
from
distutils
import
log
import
os
import
sys
import
pytest
...
...
@@ -93,10 +92,6 @@ def test_test(capfd):
assert
out
==
'Foo
\
n
'
@
pytest
.
mark
.
xfail
(
sys
.
version_info
<
(
2
,
7
),
reason
=
"No discover support for unittest on Python 2.6"
,
)
@
pytest
.
mark
.
usefixtures
(
'tmpdir_cwd'
,
'quiet_log'
)
def
test_tests_are_run_once
(
capfd
):
params
=
dict
(
...
...
setuptools/tests/test_upload.py
View file @
0551421f
import
mock
import
os
import
re
from
distutils
import
log
from
distutils.errors
import
DistutilsError
import
pytest
from
setuptools.command.upload
import
upload
from
setuptools.dist
import
Distribution
from
setuptools.extern
import
six
def
_parse_upload_body
(
body
):
boundary
=
u'
\
r
\
n
----------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
entries
=
[]
name_re
=
re
.
compile
(
u'^Content-Disposition: form-data; name="([^
\
"
]+)"'
)
for
entry
in
body
.
split
(
boundary
):
pair
=
entry
.
split
(
u'
\
r
\
n
\
r
\
n
'
)
if
not
len
(
pair
)
==
2
:
continue
key
,
value
=
map
(
six
.
text_type
.
strip
,
pair
)
m
=
name_re
.
match
(
key
)
if
m
is
not
None
:
key
=
m
.
group
(
1
)
entries
.
append
((
key
,
value
))
return
entries
@
pytest
.
fixture
def
patched_upload
(
tmpdir
):
class
Fix
:
def
__init__
(
self
,
cmd
,
urlopen
):
self
.
cmd
=
cmd
self
.
urlopen
=
urlopen
def
__iter__
(
self
):
return
iter
((
self
.
cmd
,
self
.
urlopen
))
def
get_uploaded_metadata
(
self
):
request
=
self
.
urlopen
.
call_args_list
[
0
][
0
][
0
]
body
=
request
.
data
.
decode
(
'utf-8'
)
entries
=
dict
(
_parse_upload_body
(
body
))
return
entries
class
ResponseMock
(
mock
.
Mock
):
def
getheader
(
self
,
name
,
default
=
None
):
"""Mocked getheader method for response object"""
return
{
'content-type'
:
'text/plain; charset=utf-8'
,
}.
get
(
name
.
lower
(),
default
)
with
mock
.
patch
(
'setuptools.command.upload.urlopen'
)
as
urlopen
:
urlopen
.
return_value
=
ResponseMock
()
urlopen
.
return_value
.
getcode
.
return_value
=
200
urlopen
.
return_value
.
read
.
return_value
=
b''
content
=
os
.
path
.
join
(
str
(
tmpdir
),
"content_data"
)
with
open
(
content
,
'w'
)
as
f
:
f
.
write
(
"Some content"
)
dist
=
Distribution
()
dist
.
dist_files
=
[(
'sdist'
,
'3.7.0'
,
content
)]
cmd
=
upload
(
dist
)
cmd
.
announce
=
mock
.
Mock
()
cmd
.
username
=
'user'
cmd
.
password
=
'hunter2'
yield
Fix
(
cmd
,
urlopen
)
class
TestUploadTest
:
def
test_upload_metadata
(
self
,
patched_upload
):
cmd
,
patch
=
patched_upload
# Set the metadata version to 2.1
cmd
.
distribution
.
metadata
.
metadata_version
=
'2.1'
# Run the command
cmd
.
ensure_finalized
()
cmd
.
run
()
# Make sure we did the upload
patch
.
assert_called_once
()
# Make sure the metadata version is correct in the headers
entries
=
patched_upload
.
get_uploaded_metadata
()
assert
entries
[
'metadata_version'
]
==
'2.1'
def
test_warns_deprecation
(
self
):
dist
=
Distribution
()
dist
.
dist_files
=
[(
mock
.
Mock
(),
mock
.
Mock
(),
mock
.
Mock
())]
...
...
@@ -41,3 +128,86 @@ class TestUploadTest:
"upload instead (https://pypi.org/p/twine/)"
,
log
.
WARN
)
@
pytest
.
mark
.
parametrize
(
'url'
,
[
'https://example.com/a;parameter'
,
# Has parameters
'https://example.com/a?query'
,
# Has query
'https://example.com/a#fragment'
,
# Has fragment
'ftp://example.com'
,
# Invalid scheme
])
def
test_upload_file_invalid_url
(
self
,
url
,
patched_upload
):
patched_upload
.
urlopen
.
side_effect
=
Exception
(
"Should not be reached"
)
cmd
=
patched_upload
.
cmd
cmd
.
repository
=
url
cmd
.
ensure_finalized
()
with
pytest
.
raises
(
AssertionError
):
cmd
.
run
()
def
test_upload_file_http_error
(
self
,
patched_upload
):
patched_upload
.
urlopen
.
side_effect
=
six
.
moves
.
urllib
.
error
.
HTTPError
(
'https://example.com'
,
404
,
'File not found'
,
None
,
None
)
cmd
=
patched_upload
.
cmd
cmd
.
ensure_finalized
()
with
pytest
.
raises
(
DistutilsError
):
cmd
.
run
()
cmd
.
announce
.
assert_any_call
(
'Upload failed (404): File not found'
,
log
.
ERROR
)
def
test_upload_file_os_error
(
self
,
patched_upload
):
patched_upload
.
urlopen
.
side_effect
=
OSError
(
"Invalid"
)
cmd
=
patched_upload
.
cmd
cmd
.
ensure_finalized
()
with
pytest
.
raises
(
OSError
):
cmd
.
run
()
cmd
.
announce
.
assert_any_call
(
'Invalid'
,
log
.
ERROR
)
@
mock
.
patch
(
'setuptools.command.upload.spawn'
)
def
test_upload_file_gpg
(
self
,
spawn
,
patched_upload
):
cmd
,
urlopen
=
patched_upload
cmd
.
sign
=
True
cmd
.
identity
=
"Alice"
cmd
.
dry_run
=
True
content_fname
=
cmd
.
distribution
.
dist_files
[
0
][
2
]
signed_file
=
content_fname
+
'.asc'
with
open
(
signed_file
,
'wb'
)
as
f
:
f
.
write
(
"signed-data"
.
encode
(
'utf-8'
))
cmd
.
ensure_finalized
()
cmd
.
run
()
# Make sure that GPG was called
spawn
.
assert_called_once_with
([
"gpg"
,
"--detach-sign"
,
"--local-user"
,
"Alice"
,
"-a"
,
content_fname
],
dry_run
=
True
)
# Read the 'signed' data that was transmitted
entries
=
patched_upload
.
get_uploaded_metadata
()
assert
entries
[
'gpg_signature'
]
==
'signed-data'
def
test_show_response_no_error
(
self
,
patched_upload
):
# This test is just that show_response doesn't throw an error
# It is not really important what the printed response looks like
# in a deprecated command, but we don't want to introduce new
# errors when importing this function from distutils
patched_upload
.
cmd
.
show_response
=
True
patched_upload
.
cmd
.
ensure_finalized
()
patched_upload
.
cmd
.
run
()
setuptools/tests/test_virtualenv.py
View file @
0551421f
...
...
@@ -57,9 +57,6 @@ def test_pip_upgrade_from_source(virtualenv):
Check pip can upgrade setuptools from source.
"""
dist_dir
=
virtualenv
.
workspace
if
sys
.
version_info
<
(
2
,
7
):
# Python 2.6 support was dropped in wheel 0.30.0.
virtualenv
.
run
(
'pip install -U "wheel<0.30.0"'
)
# Generate source distribution / wheel.
virtualenv
.
run
(
' && '
.
join
((
'cd {source}'
,
...
...
@@ -137,3 +134,14 @@ def test_test_command_install_requirements(bare_virtualenv, tmpdir):
'python setup.py test -s test'
,
)).
format
(
tmpdir
=
tmpdir
))
assert
tmpdir
.
join
(
'success'
).
check
()
def
test_no_missing_dependencies
(
bare_virtualenv
):
"""
Quick and dirty test to ensure all external dependencies are vendored.
"""
for
command
in
(
'upload'
,):
# sorted(distutils.command.__all__):
bare_virtualenv
.
run
(
' && '
.
join
((
'cd {source}'
,
'python setup.py {command} -h'
,
)).
format
(
command
=
command
,
source
=
SOURCE_DIR
))
setuptools/tests/test_wheel.py
View file @
0551421f
...
...
@@ -63,6 +63,7 @@ WHEEL_INFO_TESTS = (
}),
)
@
pytest
.
mark
.
parametrize
(
(
'filename'
,
'info'
),
WHEEL_INFO_TESTS
,
ids
=
[
t
[
0
]
for
t
in
WHEEL_INFO_TESTS
]
...
...
@@ -487,6 +488,7 @@ WHEEL_INSTALL_TESTS = (
)
@
pytest
.
mark
.
parametrize
(
'params'
,
WHEEL_INSTALL_TESTS
,
ids
=
list
(
params
[
'id'
]
for
params
in
WHEEL_INSTALL_TESTS
),
...
...
setuptools/tests/test_windows_wrappers.py
View file @
0551421f
...
...
@@ -97,7 +97,8 @@ class TestCLI(WrapperTester):
'arg 4
\
\
'
,
'arg5 a
\
\
\
\
b'
,
]
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
)
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
)
stdout
,
stderr
=
proc
.
communicate
(
'hello
\
n
world
\
n
'
.
encode
(
'ascii'
))
actual
=
stdout
.
decode
(
'ascii'
).
replace
(
'
\
r
\
n
'
,
'
\
n
'
)
expected
=
textwrap
.
dedent
(
r"""
...
...
@@ -134,7 +135,11 @@ class TestCLI(WrapperTester):
with
(
tmpdir
/
'foo-script.py'
).
open
(
'w'
)
as
f
:
f
.
write
(
self
.
prep_script
(
tmpl
))
cmd
=
[
str
(
tmpdir
/
'foo.exe'
)]
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
stdout
,
stderr
=
proc
.
communicate
()
actual
=
stdout
.
decode
(
'ascii'
).
replace
(
'
\
r
\
n
'
,
'
\
n
'
)
expected
=
textwrap
.
dedent
(
r"""
...
...
@@ -172,7 +177,9 @@ class TestGUI(WrapperTester):
str
(
tmpdir
/
'test_output.txt'
),
'Test Argument'
,
]
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
proc
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stdin
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
stdout
,
stderr
=
proc
.
communicate
()
assert
not
stdout
assert
not
stderr
...
...
setuptools/unicode_utils.py
View file @
0551421f
import
unicodedata
import
sys
import
re
from
setuptools.extern
import
six
...
...
@@ -42,3 +43,15 @@ def try_encode(string, enc):
return
string
.
encode
(
enc
)
except
UnicodeEncodeError
:
return
None
CODING_RE
=
re
.
compile
(
br'^[ \t\f]*#.*?coding[:=][ \t]*([-\
w.]+)
')
def detect_encoding(fp):
first_line = fp.readline()
fp.seek(0)
m = CODING_RE.match(first_line)
if m is None:
return None
return m.group(1).decode('
ascii
')
setuptools/wheel.py
View file @
0551421f
...
...
@@ -8,10 +8,11 @@ import posixpath
import
re
import
zipfile
from
pkg_resources
import
Distribution
,
PathMetadata
,
parse_version
import
pkg_resources
import
setuptools
from
pkg_resources
import
parse_version
from
setuptools.extern.packaging.utils
import
canonicalize_name
from
setuptools.extern.six
import
PY3
from
setuptools
import
Distribution
as
SetuptoolsDistribution
from
setuptools
import
pep425tags
from
setuptools.command.egg_info
import
write_requirements
...
...
@@ -79,7 +80,7 @@ class Wheel:
return next((True for t in self.tags() if t in supported_tags), False)
def egg_name(self):
return Distribution(
return
pkg_resources.
Distribution(
project_name=self.project_name, version=self.version,
platform=(None if self.platform == 'any' else get_platform()),
).egg_name() + '.egg'
...
...
@@ -130,9 +131,9 @@ class Wheel:
zf.extractall(destination_eggdir)
# Convert metadata.
dist_info = os.path.join(destination_eggdir, dist_info)
dist = Distribution.from_location(
dist =
pkg_resources.
Distribution.from_location(
destination_eggdir, dist_info,
metadata=PathMetadata(destination_eggdir, dist_info),
metadata=
pkg_resources.
PathMetadata(destination_eggdir, dist_info),
)
# Note: Evaluate and strip markers now,
...
...
@@ -155,7 +156,7 @@ class Wheel:
os.path.join(egg_info, 'METADATA'),
os.path.join(egg_info, 'PKG-INFO'),
)
setup_dist =
Setuptools
Distribution(
setup_dist =
setuptools.
Distribution(
attrs=dict(
install_requires=install_requires,
extras_require=extras_require,
...
...
tests/manual_test.py
View file @
0551421f
...
...
@@ -8,7 +8,7 @@ import subprocess
from
distutils.command.install
import
INSTALL_SCHEMES
from
string
import
Template
from
six.moves
import
urllib
from
s
etuptools.extern.s
ix.moves
import
urllib
def
_system_call
(
*
args
):
...
...
tests/requirements.txt
View file @
0551421f
...
...
@@ -3,8 +3,11 @@ pytest-flake8; python_version!="3.4"
pytest-flake8<=1.0.0; python_version=="3.4"
virtualenv>=13.0.0
pytest-virtualenv>=1.2.7
pytest>=3.0.2
# pytest pinned to <4 due to #1638
pytest>=3.7,<4
wheel
coverage>=4.5.1
pytest-cov>=2.5.1
paver; python_version>="3.6"
futures; python_version=="2.7"
pip==18.1 # Temporary workaround for #1644.
tox.ini
View file @
0551421f
...
...
@@ -12,7 +12,7 @@ deps=-rtests/requirements.txt
# Changed from default (`python -m pip ...`)
# to prevent the current working directory
# from being added to `sys.path`.
install_command
=
{envbindir}/pip
install {opts} {packages}
install_command
=
python -c 'import sys; sys.path.remove(""); from pkg_resources import load_entry_point; load_entry_point("pip", "console_scripts", "pip")()'
install {opts} {packages}
# Same as above.
list_dependencies_command
=
{envbindir}/pip freeze
setenv
=
COVERAGE_FILE={toxworkdir}/.coverage.{envname}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment