summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Dufresne <jon.dufresne@gmail.com>2017-07-07 17:24:24 -0700
committerJon Dufresne <jon.dufresne@gmail.com>2017-07-07 17:24:24 -0700
commit5eb85d0e1f9064a645c490cfdde9bb246af986b2 (patch)
tree518dd60e1d71cdc1af8d51cb04b364f68629093c
parent63ad63cc2122069ae6ff8f28cfbfd87953c91ae0 (diff)
parent5076a511f1444b3520ca37ed22aa692f6fd49305 (diff)
downloadwheel-5eb85d0e1f9064a645c490cfdde9bb246af986b2.tar.gz
Merge
-rw-r--r--CHANGES.txt10
-rw-r--r--docs/index.rst18
-rw-r--r--setup.py14
-rw-r--r--wheel/__init__.py2
-rw-r--r--wheel/bdist_wheel.py25
-rw-r--r--wheel/metadata.py37
-rw-r--r--wheel/pep425tags.py11
-rw-r--r--wheel/test/extension.dist/extension.c2
-rw-r--r--wheel/test/extension.dist/setup.cfg2
-rw-r--r--wheel/test/extension.dist/setup.py20
10 files changed, 112 insertions, 29 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 1024db1..dfbb12b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,11 @@
-UNRELEASED
-==========
+0.30.0
+======
+- Add py-limited-api {cp32|cp33|cp34|...} flag to produce cpNN.abi3.{arch}
+ tags on CPython 3.
+- Improve Python, abi tagging for `wheel convert`. Thanks Ales Erjavec.
+- Much improved use of context managers for file handling. Thanks Kyle
+ Stewart.
+- Convert absolute imports to relative. Thanks Ashish Bhate.
- Remove support for Python 2.6.
0.29.0
diff --git a/docs/index.rst b/docs/index.rst
index 5b1b157..f1dbce6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -111,9 +111,21 @@ used to specify the Python version tag to use more precisely::
equates to the tag "py2.py3".
--python-tag XXX Specifies the precise python version tag to use for
a pure-python wheel.
-
-Neither of these two flags have any effect when used on a project that includes
-C extension code.
+ --py-limited-api {cp32|cp33|cp34|...}
+ Specifies Python Py_LIMITED_API compatibility with
+ the version of CPython passed and later versions.
+ The wheel will be tagged cpNN.abi3.{arch} on CPython 3.
+ This flag does not affect Python 2 builds or alternate
+ Python implementations.
+
+ To conform to the limited API, all your C
+ extensions must use only functions from the limited
+ API, pass Extension(py_limited_api=True) and e.g.
+ #define Py_LIMITED_API=0x03020000 depending on
+ the exact minimun Python you wish to support.
+
+The --universal and --python-tag flags have no effect when used on a
+project that includes C extension code.
The default for a pure Python project (if no explicit flags are given) is "pyN"
where N is the major version of the Python interpreter used to build the wheel.
diff --git a/setup.py b/setup.py
index 2d77f51..e187cba 100644
--- a/setup.py
+++ b/setup.py
@@ -55,10 +55,12 @@ setup(name='wheel',
],
include_package_data=True,
zip_safe=False,
- entry_points = """\
-[console_scripts]
-wheel = wheel.tool:main
-
-[distutils.commands]
-bdist_wheel = wheel.bdist_wheel:bdist_wheel"""
+ entry_points = {
+ 'console_scripts': [
+ 'wheel=wheel.tool:main'
+ ],
+ 'distutils.commands': [
+ 'bdist_wheel=wheel.bdist_wheel:bdist_wheel'
+ ]
+ }
)
diff --git a/wheel/__init__.py b/wheel/__init__.py
index 1dbfedc..7b3d278 100644
--- a/wheel/__init__.py
+++ b/wheel/__init__.py
@@ -1,2 +1,2 @@
# __variables__ with double-quoted values will be available in setup.py:
-__version__ = "0.30.0.dev0"
+__version__ = "0.30.0.a0"
diff --git a/wheel/bdist_wheel.py b/wheel/bdist_wheel.py
index f45270a..dfcc910 100644
--- a/wheel/bdist_wheel.py
+++ b/wheel/bdist_wheel.py
@@ -12,6 +12,7 @@ import warnings
import shutil
import json
import sys
+import re
import pkg_resources
@@ -34,6 +35,8 @@ from .metadata import pkginfo_to_dict
from . import pep425tags, metadata
from . import __version__ as wheel_version
+PY_LIMITED_API_PATTERN = r'cp3\d'
+
def safer_name(name):
return safe_name(name).replace('-', '_')
@@ -71,6 +74,9 @@ class bdist_wheel(Command):
('python-tag=', None,
"Python implementation compatibility tag"
" (default: py%s)" % get_impl_ver()[0]),
+ ('py-limited-api=', None,
+ "Python tag (cp32|cp33|cpNN) for abi3 wheel tag"
+ " (default: false)"),
]
boolean_options = ['keep-temp', 'skip-build', 'relative', 'universal']
@@ -92,6 +98,7 @@ class bdist_wheel(Command):
self.group = None
self.universal = False
self.python_tag = 'py' + get_impl_ver()[0]
+ self.py_limited_api = False
self.plat_name_supplied = False
def finalize_options(self):
@@ -110,6 +117,9 @@ class bdist_wheel(Command):
self.root_is_pure = not (self.distribution.has_ext_modules()
or self.distribution.has_c_libraries())
+ if self.py_limited_api and not re.match(PY_LIMITED_API_PATTERN, self.py_limited_api):
+ raise ValueError("py-limited-api must match '%s'" % PY_LIMITED_API_PATTERN)
+
# Support legacy [wheel] section for setting universal
wheel = self.distribution.get_option_dict('wheel')
if 'universal' in wheel:
@@ -147,13 +157,20 @@ class bdist_wheel(Command):
else:
impl_name = get_abbr_impl()
impl_ver = get_impl_ver()
- # PEP 3149
- abi_tag = str(get_abi_tag()).lower()
- tag = (impl_name + impl_ver, abi_tag, plat_name)
+ impl = impl_name + impl_ver
+ # We don't work on CPython 3.1, 3.0.
+ if self.py_limited_api and (impl_name + impl_ver).startswith('cp3'):
+ impl = self.py_limited_api
+ abi_tag = 'abi3'
+ else:
+ abi_tag = str(get_abi_tag()).lower()
+ tag = (impl, abi_tag, plat_name)
supported_tags = pep425tags.get_supported(
supplied_platform=plat_name if self.plat_name_supplied else None)
# XXX switch to this alternate implementation for non-pure:
- assert tag == supported_tags[0], "%s != %s" % (tag, supported_tags[0])
+ if not self.py_limited_api:
+ assert tag == supported_tags[0], "%s != %s" % (tag, supported_tags[0])
+ assert tag in supported_tags, "would build wheel with unsupported tag %s" % tag
return tag
def get_archive_basename(self):
diff --git a/wheel/metadata.py b/wheel/metadata.py
index e68d621..2b123f9 100644
--- a/wheel/metadata.py
+++ b/wheel/metadata.py
@@ -234,6 +234,29 @@ def convert_requirements(requirements):
extras = "[%s]" % extras
yield (parsed_requirement.project_name + extras + spec)
+def generate_requirements(extras_require):
+ """
+ Convert requirements from a setup()-style dictionary to ('Requires-Dist', 'requirement')
+ and ('Provides-Extra', 'extra') tuples.
+
+ extras_require is a dictionary of {extra: [requirements]} as passed to setup(),
+ using the empty extra {'': [requirements]} to hold install_requires.
+ """
+ for extra, depends in extras_require.items():
+ condition = ''
+ if extra and ':' in extra: # setuptools extra:condition syntax
+ extra, condition = extra.split(':', 1)
+ extra = pkg_resources.safe_extra(extra)
+ if extra:
+ yield ('Provides-Extra', extra)
+ if condition:
+ condition += " and "
+ condition += "extra == '%s'" % extra
+ if condition:
+ condition = '; ' + condition
+ for new_req in convert_requirements(depends):
+ yield ('Requires-Dist', new_req + condition)
+
def pkginfo_to_metadata(egg_info_path, pkginfo_path):
"""
Convert .egg-info directory with PKG-INFO to the Metadata 1.3 aka
@@ -247,18 +270,8 @@ def pkginfo_to_metadata(egg_info_path, pkginfo_path):
requires = requires_file.read()
for extra, reqs in sorted(pkg_resources.split_sections(requires),
key=lambda x: x[0] or ''):
- condition = ''
- if extra and ':' in extra: # setuptools extra:condition syntax
- extra, condition = extra.split(':', 1)
- if extra:
- pkg_info['Provides-Extra'] = extra
- if condition:
- condition += " and "
- condition += 'extra == %s' % repr(extra)
- if condition:
- condition = '; ' + condition
- for new_req in sorted(convert_requirements(reqs)):
- pkg_info['Requires-Dist'] = new_req + condition
+ for item in generate_requirements({extra: reqs}):
+ pkg_info[item[0]] = item[1]
description = pkg_info['Description']
if description:
diff --git a/wheel/pep425tags.py b/wheel/pep425tags.py
index 704afaa..a7bd4a9 100644
--- a/wheel/pep425tags.py
+++ b/wheel/pep425tags.py
@@ -148,7 +148,16 @@ def get_supported(versions=None, supplied_platform=None):
for abi in abis:
for arch in platforms:
supported.append(('%s%s' % (impl, versions[0]), abi, arch))
-
+
+ # abi3 modules compatible with older version of Python
+ for version in versions[1:]:
+ # abi3 was introduced in Python 3.2
+ if version in ('31', '30'):
+ break
+ for abi in abi3s: # empty set if not Python 3
+ for arch in platforms:
+ supported.append(("%s%s" % (impl, version), abi, arch))
+
# No abi / arch, but requires our implementation:
for i, version in enumerate(versions):
supported.append(('%s%s' % (impl, version), 'none', 'any'))
diff --git a/wheel/test/extension.dist/extension.c b/wheel/test/extension.dist/extension.c
new file mode 100644
index 0000000..a37c3fa
--- /dev/null
+++ b/wheel/test/extension.dist/extension.c
@@ -0,0 +1,2 @@
+#define Py_LIMITED_API 0x03020000
+#include <Python.h>
diff --git a/wheel/test/extension.dist/setup.cfg b/wheel/test/extension.dist/setup.cfg
new file mode 100644
index 0000000..9f6ff39
--- /dev/null
+++ b/wheel/test/extension.dist/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+py_limited_api=cp32
diff --git a/wheel/test/extension.dist/setup.py b/wheel/test/extension.dist/setup.py
new file mode 100644
index 0000000..7a66845
--- /dev/null
+++ b/wheel/test/extension.dist/setup.py
@@ -0,0 +1,20 @@
+from setuptools import setup, Extension
+
+try:
+ unicode
+ def u8(s):
+ return s.decode('unicode-escape').encode('utf-8')
+except NameError:
+ def u8(s):
+ return s.encode('utf-8')
+
+setup(name='extension.dist',
+ version='0.1',
+ description=u8('A testing distribution \N{SNOWMAN}'),
+ ext_modules=[
+ Extension(name='extension',
+ sources=['extension.c'],
+ py_limited_api=True)
+ ],
+ )
+