diff options
| -rw-r--r-- | .travis.yml | 2 | ||||
| -rw-r--r-- | CHANGES.rst | 16 | ||||
| -rw-r--r-- | bootstrap.py | 16 | ||||
| -rw-r--r-- | docs/conf.py | 2 | ||||
| -rw-r--r-- | docs/pkg_resources.txt | 10 | ||||
| -rw-r--r-- | docs/requirements.txt | 1 | ||||
| -rw-r--r-- | docs/setuptools.txt | 17 | ||||
| -rw-r--r-- | pkg_resources/__init__.py | 6 | ||||
| -rwxr-xr-x | setup.cfg | 2 | ||||
| -rwxr-xr-x | setup.py | 2 | ||||
| -rw-r--r-- | setuptools/config.py | 11 | ||||
| -rwxr-xr-x | setuptools/namespaces.py | 2 | ||||
| -rwxr-xr-x | setuptools/package_index.py | 2 | ||||
| -rw-r--r-- | setuptools/py27compat.py | 1 | ||||
| -rw-r--r-- | setuptools/tests/test_config.py | 13 | ||||
| -rw-r--r-- | setuptools/tests/test_packageindex.py | 42 |
16 files changed, 103 insertions, 42 deletions
diff --git a/.travis.yml b/.travis.yml index 7affc0a6..adb2f948 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ deploy: on: tags: true all_branches: true - python: 3.5 + python: 3.6 condition: $LC_ALL != "C" user: jaraco password: diff --git a/CHANGES.rst b/CHANGES.rst index efe4488e..0e47fe06 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,22 @@ v34.3.0 * #941: In the upload command, if the username is blank, default to ``getpass.getuser()``. +v34.2.0 +------- + +* #966: Add support for reading dist-info metadata and + thus locating Distributions from zip files. + +* #968: Allow '+' and '!' in egg fragments + so that it can take package names that contain + PEP 440 conforming version specifiers. + +v34.1.1 +------- + +* #953: More aggressively employ the compatibility issue + originally added in #706. + v34.1.0 ------- diff --git a/bootstrap.py b/bootstrap.py index f7644f12..ee3b53c8 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -17,7 +17,6 @@ import sys import textwrap import subprocess -import pip minimal_egg_info = textwrap.dedent(""" [distutils.commands] @@ -75,7 +74,7 @@ def gen_deps(): @contextlib.contextmanager def install_deps(): "Just in time make the deps available" - gen_deps() + import pip tmpdir = tempfile.mkdtemp() args = [ 'install', @@ -90,7 +89,16 @@ def install_deps(): shutil.rmtree(tmpdir) -if __name__ == '__main__': +def main(): ensure_egg_info() - with install_deps(): + gen_deps() + try: + # first assume dependencies are present run_egg_info() + except Exception: + # but if that fails, try again with dependencies just in time + with install_deps(): + run_egg_info() + + +__name__ == '__main__' and main() diff --git a/docs/conf.py b/docs/conf.py index c1854ed8..fe684271 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,7 +29,7 @@ import setup as setup_script # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['rst.linker'] +extensions = ['rst.linker', 'sphinx.ext.autosectionlabel'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/pkg_resources.txt b/docs/pkg_resources.txt index e8412b33..487320ce 100644 --- a/docs/pkg_resources.txt +++ b/docs/pkg_resources.txt @@ -143,10 +143,10 @@ namespace package for Zope Corporation packages, and the ``peak`` namespace package for the Python Enterprise Application Kit. To create a namespace package, you list it in the ``namespace_packages`` -argument to ``setup()``, in your project's ``setup.py``. (See the `setuptools -documentation on namespace packages`_ for more information on this.) Also, -you must add a ``declare_namespace()`` call in the package's ``__init__.py`` -file(s): +argument to ``setup()``, in your project's ``setup.py``. (See the +:ref:`setuptools documentation on namespace packages <Namespace Packages>` for +more information on this.) Also, you must add a ``declare_namespace()`` call +in the package's ``__init__.py`` file(s): ``declare_namespace(name)`` Declare that the dotted package name `name` is a "namespace package" whose @@ -175,8 +175,6 @@ filesystem and zip importers, you can extend its support to other "importers" compatible with PEP 302 using the ``register_namespace_handler()`` function. See the section below on `Supporting Custom Importers`_ for details. -.. _setuptools documentation on namespace packages: http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages - ``WorkingSet`` Objects ====================== diff --git a/docs/requirements.txt b/docs/requirements.txt index 0871ed76..4be41887 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,2 @@ rst.linker>=1.6.1 +sphinx>=1.4 diff --git a/docs/setuptools.txt b/docs/setuptools.txt index 2a494fca..f0da6e1d 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -940,14 +940,13 @@ Typically, existing programs manipulate a package's ``__file__`` attribute in order to find the location of data files. However, this manipulation isn't compatible with PEP 302-based import hooks, including importing from zip files and Python Eggs. It is strongly recommended that, if you are using data files, -you should use the `Resource Management API`_ of ``pkg_resources`` to access +you should use the :ref:`ResourceManager API` of ``pkg_resources`` to access them. The ``pkg_resources`` module is distributed as part of setuptools, so if you're using setuptools to distribute your package, there is no reason not to use its resource management API. See also `Accessing Package Resources`_ for a quick example of converting code that uses ``__file__`` to use ``pkg_resources`` instead. -.. _Resource Management API: http://peak.telecommunity.com/DevCenter/PkgResources#resourcemanager-api .. _Accessing Package Resources: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources @@ -959,8 +958,8 @@ location (e.g. ``/usr/share``). This feature intended to be used for things like documentation, example configuration files, and the like. ``setuptools`` does not install these data files in a separate location, however. They are bundled inside the egg file or directory, alongside the Python modules and -packages. The data files can also be accessed using the `Resource Management -API`_, by specifying a ``Requirement`` instead of a package name:: +packages. The data files can also be accessed using the :ref:`ResourceManager +API`, by specifying a ``Requirement`` instead of a package name:: from pkg_resources import Requirement, resource_filename filename = resource_filename(Requirement.parse("MyProject"),"sample.conf") @@ -2303,10 +2302,10 @@ boilerplate code in some cases. long_description = file: README.rst keywords = one, two license = BSD 3-Clause License - - [metadata.classifiers] - Framework :: Django - Programming Language :: Python :: 3.5 + classifiers = + Framework :: Django + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 [options] zip_safe = False @@ -2399,7 +2398,7 @@ author str author_email author-email str maintainer str maintainer_email maintainer-email str -classifiers classifier file:, section, list-comma +classifiers classifier file:, list-comma license file:, str description summary file:, str long_description long-description file:, str diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index e33de0e7..220a7ccc 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1956,6 +1956,12 @@ def find_eggs_in_zip(importer, path_item, only=False): subpath = os.path.join(path_item, subitem) for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath): yield dist + elif subitem.lower().endswith('.dist-info'): + subpath = os.path.join(path_item, subitem) + submeta = EggMetadata(zipimport.zipimporter(subpath)) + submeta.egg_info = subpath + yield Distribution.from_location(path_item, subitem, submeta) + register_finder(zipimport.zipimporter, find_eggs_in_zip) @@ -1,5 +1,5 @@ [bumpversion] -current_version = 34.1.0 +current_version = 34.2.0 commit = True tag = True @@ -88,7 +88,7 @@ def pypi_link(pkg_filename): setup_params = dict( name="setuptools", - version="34.1.0", + version="34.2.0", description="Easily download, build, install, upgrade, and uninstall " "Python packages", author="Python Packaging Authority", diff --git a/setuptools/config.py b/setuptools/config.py index 19b39629..39a01f88 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -412,17 +412,6 @@ class ConfigMetadataHandler(ConfigHandler): 'version': self._parse_version, } - def parse_section_classifiers(self, section_options): - """Parses configuration file section. - - :param dict section_options: - """ - classifiers = [] - for begin, (_, rest) in section_options.items(): - classifiers.append('%s :%s' % (begin.title(), rest)) - - self['classifiers'] = classifiers - def _parse_version(self, value): """Parses `version` option value. diff --git a/setuptools/namespaces.py b/setuptools/namespaces.py index 556b5dd2..7c24a566 100755 --- a/setuptools/namespaces.py +++ b/setuptools/namespaces.py @@ -52,7 +52,7 @@ class Installer: "importlib.util.module_from_spec(" "importlib.machinery.PathFinder.find_spec(%(pkg)r, " "[os.path.dirname(p)])))", - "m = m or not has_mfs and " + "m = m or " "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))", "mp = (m or []) and m.__dict__.setdefault('__path__',[])", "(p not in mp) and mp.append(p)", diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 42361058..3544dd54 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -30,7 +30,7 @@ from fnmatch import translate from setuptools.py26compat import strip_fragment from setuptools.py27compat import get_all_headers -EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') +EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$') HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) # this is here to fix emacs' cruddy broken syntax highlighting PYPI_MD5 = re.compile( diff --git a/setuptools/py27compat.py b/setuptools/py27compat.py index a71a936e..f0a80a8e 100644 --- a/setuptools/py27compat.py +++ b/setuptools/py27compat.py @@ -21,7 +21,6 @@ if sys.version_info < (3,): linux_py2_ascii = ( platform.system() == 'Linux' and - sys.getfilesystemencoding() == 'ascii' and sys.version_info < (3,) ) diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index fa8d523b..799fb165 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -257,6 +257,7 @@ class TestMetadata: def test_classifiers(self, tmpdir): expected = set([ 'Framework :: Django', + 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', ]) @@ -269,19 +270,21 @@ class TestMetadata: tmpdir.join('classifiers').write( 'Framework :: Django\n' + 'Programming Language :: Python :: 3\n' 'Programming Language :: Python :: 3.5\n' ) with get_dist(tmpdir) as dist: assert set(dist.metadata.classifiers) == expected - # From section. + # From list notation config.write( - '[metadata.classifiers]\n' - 'Framework :: Django\n' - 'Programming Language :: Python :: 3.5\n' + '[metadata]\n' + 'classifiers =\n' + ' Framework :: Django\n' + ' Programming Language :: Python :: 3\n' + ' Programming Language :: Python :: 3.5\n' ) - with get_dist(tmpdir) as dist: assert set(dist.metadata.classifiers) == expected diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py index d68867c2..1a66394f 100644 --- a/setuptools/tests/test_packageindex.py +++ b/setuptools/tests/test_packageindex.py @@ -181,6 +181,48 @@ class TestPackageIndex: res = setuptools.package_index.local_open(url) assert 'content' in res.read() + def test_egg_fragment(self): + """ + EGG fragments must comply to PEP 440 + """ + epoch = [ + '', + '1!', + ] + releases = [ + '0', + '0.0', + '0.0.0', + ] + pre = [ + 'a0', + 'b0', + 'rc0', + ] + post = [ + '.post0' + ] + dev = [ + '.dev0', + ] + local = [ + ('', ''), + ('+ubuntu.0', '+ubuntu.0'), + ('+ubuntu-0', '+ubuntu.0'), + ('+ubuntu_0', '+ubuntu.0'), + ] + versions = [ + [''.join([e, r, p, l]) for l in ll] + for e in epoch + for r in releases + for p in sum([pre, post, dev], ['']) + for ll in local] + for v, vc in versions: + dists = list(setuptools.package_index.distros_for_url( + 'http://example.com/example.zip#egg=example-' + v)) + assert dists[0].version == '' + assert dists[1].version == vc + class TestContentCheckers: def test_md5(self): |
