summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2017-07-26 02:51:59 +0300
committerAlex Grönholm <alex.gronholm@nextday.fi>2017-07-26 03:20:11 +0300
commit88fff78c73e300592ecba4d9a0550d1dac761eb7 (patch)
tree2e056f5ed661cfd73e87b5779dccce8149cc3f46
parent0eea55fe5b9f6d690a3069b9e1e69f7764384e0b (diff)
downloadwheel-git-88fff78c73e300592ecba4d9a0550d1dac761eb7.tar.gz
Fixed errors reported by flake8
-rw-r--r--tox.ini6
-rw-r--r--wheel/__init__.py2
-rw-r--r--wheel/__main__.py4
-rw-r--r--wheel/archive.py8
-rw-r--r--wheel/bdist_wheel.py38
-rwxr-xr-xwheel/egg2wheel.py14
-rw-r--r--wheel/install.py51
-rw-r--r--wheel/metadata.py74
-rw-r--r--wheel/paths.py10
-rw-r--r--wheel/pep425tags.py25
-rw-r--r--wheel/pkginfo.py11
-rw-r--r--wheel/signatures/__init__.py54
-rw-r--r--wheel/signatures/djbec.py233
-rw-r--r--wheel/signatures/ed25519py.py20
-rw-r--r--wheel/signatures/keys.py36
-rw-r--r--wheel/test/__init__.py1
-rw-r--r--wheel/test/complex-dist/setup.py4
-rw-r--r--wheel/test/conftest.py12
-rw-r--r--wheel/test/extension.dist/setup.py8
-rw-r--r--wheel/test/headers.dist/setup.py2
-rw-r--r--wheel/test/simple.dist/setup.py2
-rw-r--r--wheel/test/test_basic.py37
-rw-r--r--wheel/test/test_install.py17
-rw-r--r--wheel/test/test_keys.py54
-rw-r--r--wheel/test/test_paths.py4
-rw-r--r--wheel/test/test_ranking.py15
-rw-r--r--wheel/test/test_signatures.py20
-rw-r--r--wheel/test/test_tagopt.py19
-rw-r--r--wheel/test/test_tool.py3
-rw-r--r--wheel/test/test_wheelfile.py43
-rw-r--r--wheel/tool/__init__.py41
-rw-r--r--wheel/util.py92
-rwxr-xr-xwheel/wininst2wheel.py29
33 files changed, 567 insertions, 422 deletions
diff --git a/tox.ini b/tox.ini
index 6866741..07c8947 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,9 +4,13 @@
# and then run "tox" from this directory.
[tox]
-envlist = py27, pypy, py33, py34, py35, py36
+envlist = py27, pypy, py33, py34, py35, py36, flake8
minversion = 2.5.0
+[travis]
+python =
+ 2.7: py27, flake8
+
[testenv]
commands = python -m pytest
extras =
diff --git a/wheel/__init__.py b/wheel/__init__.py
index 7b3d278..0857063 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.a0"
+__version__ = "0.30.0a0"
diff --git a/wheel/__main__.py b/wheel/__main__.py
index 889359c..8f0c4fe 100644
--- a/wheel/__main__.py
+++ b/wheel/__main__.py
@@ -4,7 +4,8 @@ Wheel command line tool (enable python -m wheel syntax)
import sys
-def main(): # needed for console script
+
+def main(): # needed for console script
if __package__ == '':
# To be able to run 'python wheel-0.9.whl/wheel':
import os.path
@@ -13,5 +14,6 @@ def main(): # needed for console script
import wheel.tool
sys.exit(wheel.tool.main())
+
if __name__ == "__main__":
sys.exit(main())
diff --git a/wheel/archive.py b/wheel/archive.py
index 403d45b..ce747c9 100644
--- a/wheel/archive.py
+++ b/wheel/archive.py
@@ -3,18 +3,16 @@ Archive tools for wheel.
"""
import os
-import time
-import logging
import os.path
+import time
import zipfile
-
from distutils import log
def archive_wheelfile(base_name, base_dir):
- '''Archive all files under `base_dir` in a whl file and name it like
+ """Archive all files under `base_dir` in a whl file and name it like
`base_name`.
- '''
+ """
olddir = os.path.abspath(os.curdir)
base_name = os.path.abspath(base_name)
try:
diff --git a/wheel/bdist_wheel.py b/wheel/bdist_wheel.py
index dfcc910..dd67a8a 100644
--- a/wheel/bdist_wheel.py
+++ b/wheel/bdist_wheel.py
@@ -13,19 +13,13 @@ import shutil
import json
import sys
import re
-
-import pkg_resources
-
-safe_name = pkg_resources.safe_name
-safe_version = pkg_resources.safe_version
-
-from shutil import rmtree
from email.generator import Generator
-
from distutils.core import Command
from distutils.sysconfig import get_python_version
-
from distutils import log as logger
+from shutil import rmtree
+
+import pkg_resources
from .pep425tags import get_abbr_impl, get_impl_ver, get_abi_tag, get_platform
from .util import native, open_for_csv
@@ -35,14 +29,21 @@ from .metadata import pkginfo_to_dict
from . import pep425tags, metadata
from . import __version__ as wheel_version
+
+safe_name = pkg_resources.safe_name
+safe_version = pkg_resources.safe_version
+
PY_LIMITED_API_PATTERN = r'cp3\d'
+
def safer_name(name):
return safe_name(name).replace('-', '_')
+
def safer_version(version):
return safe_version(version).replace('-', '_')
+
class bdist_wheel(Command):
description = 'create a wheel distribution'
@@ -147,7 +148,6 @@ class bdist_wheel(Command):
plat_name = 'linux_i686'
plat_name = plat_name.replace('-', '_').replace('.', '_')
-
if self.root_is_pure:
if self.universal:
impl = 'py2.py3'
@@ -300,7 +300,7 @@ class bdist_wheel(Command):
def license_file(self):
"""Return license filename from a license-file key in setup.cfg, or None."""
metadata = self.distribution.get_option_dict('metadata')
- if not 'license_file' in metadata:
+ if 'license_file' not in metadata:
return None
return metadata['license_file'][1]
@@ -329,7 +329,7 @@ class bdist_wheel(Command):
# our .ini parser folds - to _ in key names:
for key, title in (('provides_extra', 'Provides-Extra'),
('requires_dist', 'Requires-Dist')):
- if not key in metadata:
+ if key not in metadata:
continue
field = metadata[key]
for line in field[1].splitlines():
@@ -341,7 +341,9 @@ class bdist_wheel(Command):
def add_requirements(self, metadata_path):
"""Add additional requirements from setup.cfg to file metadata_path"""
additional = list(self.setupcfg_requirements())
- if not additional: return
+ if not additional:
+ return
+
pkg_info = read_pkg_info(metadata_path)
if 'Provides-Extra' in pkg_info or 'Requires-Dist' in pkg_info:
warnings.warn('setup.cfg requirements overwrite values from setup.py')
@@ -389,10 +391,9 @@ class bdist_wheel(Command):
# ignore common egg metadata that is useless to wheel
shutil.copytree(egginfo_path, distinfo_path,
- ignore=lambda x, y: set(('PKG-INFO',
- 'requires.txt',
- 'SOURCES.txt',
- 'not-zip-safe',)))
+ ignore=lambda x, y: {'PKG-INFO', 'requires.txt', 'SOURCES.txt',
+ 'not-zip-safe'}
+ )
# delete dependency_links if it is only whitespace
dependency_links_path = os.path.join(distinfo_path, 'dependency_links.txt')
@@ -419,7 +420,8 @@ class bdist_wheel(Command):
description_filename)
with open(description_path, "wb") as description_file:
description_file.write(description_text.encode('utf-8'))
- pymeta['extensions']['python.details']['document_names']['description'] = description_filename
+ pymeta['extensions']['python.details']['document_names']['description'] = \
+ description_filename
# XXX heuristically copy any LICENSE/LICENSE.txt?
license = self.license_file()
diff --git a/wheel/egg2wheel.py b/wheel/egg2wheel.py
index e8d3153..3799909 100755
--- a/wheel/egg2wheel.py
+++ b/wheel/egg2wheel.py
@@ -1,20 +1,22 @@
#!/usr/bin/env python
+import distutils.dist
import os.path
import re
+import shutil
import sys
import tempfile
import zipfile
-import wheel.bdist_wheel
-import shutil
-import distutils.dist
-from distutils.archive_util import make_archive
from argparse import ArgumentParser
+from distutils.archive_util import make_archive
from glob import iglob
+
+import wheel.bdist_wheel
from wheel.wininst2wheel import _bdist_wheel_tag
egg_info_re = re.compile(r'''(?P<name>.+?)-(?P<ver>.+?)
(-(?P<pyver>.+?))?(-(?P<arch>.+?))?.egg''', re.VERBOSE)
+
def egg2wheel(egg_path, dest_dir):
egg_info = egg_info_re.match(os.path.basename(egg_path)).groupdict()
dir = tempfile.mkdtemp(suffix="_e2w")
@@ -67,11 +69,12 @@ def egg2wheel(egg_path, dest_dir):
os.rename(filename, filename[:-3] + 'whl')
shutil.rmtree(dir)
+
def main():
parser = ArgumentParser()
parser.add_argument('eggs', nargs='*', help="Eggs to convert")
parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
- help="Directory to store wheels (default %(default)s)")
+ help="Directory to store wheels (default %(default)s)")
parser.add_argument('--verbose', '-v', action='store_true')
args = parser.parse_args()
for pat in args.eggs:
@@ -82,5 +85,6 @@ def main():
if args.verbose:
sys.stdout.write("OK\n")
+
if __name__ == "__main__":
main()
diff --git a/wheel/install.py b/wheel/install.py
index a422b0e..a4fd8aa 100644
--- a/wheel/install.py
+++ b/wheel/install.py
@@ -1,33 +1,32 @@
"""
-Operations on existing wheel files, including basic installation.
+Operations on existing wheel files, including basic installation.
"""
# XXX see patched pip to install
-import sys
-import warnings
+import csv
+import hashlib
import os.path
import re
-import zipfile
-import hashlib
-import csv
-
import shutil
+import sys
+import warnings
+import zipfile
-try:
- _big_number = sys.maxsize
-except NameError:
- _big_number = sys.maxint
-
+from . import signatures
from .decorator import reify
from .util import (urlsafe_b64encode, from_json, urlsafe_b64decode,
native, binary, HashingFile)
-from . import signatures
from .pkginfo import read_pkg_info_bytes
from .util import open_for_csv
from .pep425tags import get_supported
from .paths import get_install_paths
+try:
+ _big_number = sys.maxsize
+except NameError:
+ _big_number = sys.maxint
+
# The next major version after this version of the 'wheel' tool:
VERSION_TOO_HIGH = (1, 0)
@@ -39,6 +38,7 @@ WHEEL_INFO_RE = re.compile(
\.whl|\.dist-info)$""",
re.VERBOSE).match
+
def parse_version(version):
"""Use parse_version from pkg_resources or distutils as available."""
global parse_version
@@ -48,6 +48,7 @@ def parse_version(version):
from distutils.version import LooseVersion as parse_version
return parse_version(version)
+
class BadWheelFile(ValueError):
pass
@@ -55,7 +56,7 @@ class BadWheelFile(ValueError):
class WheelFile(object):
"""Parse wheel-specific attributes from a wheel (.whl) file and offer
basic installation and verification support.
-
+
WheelFile can be used to simply parse a wheel filename by avoiding the
methods that require the actual file contents."""
@@ -201,11 +202,11 @@ class WheelFile(object):
raise TypeError("{0}.context != {1}.context".format(self, other))
sc = self.rank
oc = other.rank
- if sc != None and oc != None and sc != oc:
+ if sc is not None and oc is not None and sc != oc:
# Smaller compatibility ranks are "better" than larger ones,
# so we have to reverse the sense of the comparison here!
return sc > oc
- elif sc == None and oc != None:
+ elif sc is None and oc is not None:
return False
return self.filename < other.filename
@@ -247,10 +248,10 @@ class WheelFile(object):
"""
Consult distutils to get the install paths for our dist. A dict with
('purelib', 'platlib', 'headers', 'scripts', 'data').
-
+
We use the name from our filename as the dist name, which means headers
could be installed in the wrong place if the filesystem-escaped name
- is different than the Name. Who cares?
+ is different than the Name. Who cares?
"""
name = self.parsed_filename.group('name')
return get_install_paths(name)
@@ -323,7 +324,9 @@ class WheelFile(object):
k = info.filename
key, target, filename, dest = v
if os.path.exists(dest):
- raise ValueError("Wheel file {0} would overwrite {1}. Use force if this is intended".format(k, dest))
+ raise ValueError(
+ "Wheel file {0} would overwrite {1}. Use force if this is intended".format(
+ k, dest))
# Get the name of our executable, for use when replacing script
# wrapper hashbang lines.
@@ -367,9 +370,9 @@ class WheelFile(object):
writer.writerow((self.record_name, '', ''))
def verify(self, zipfile=None):
- """Configure the VerifyingZipFile `zipfile` by verifying its signature
+ """Configure the VerifyingZipFile `zipfile` by verifying its signature
and setting expected hashes for every hash in RECORD.
- Caller must complete the verification process by completely reading
+ Caller must complete the verification process by completely reading
every file in the archive (e.g. with extractall)."""
sig = None
if zipfile is None:
@@ -413,7 +416,7 @@ class WheelFile(object):
class VerifyingZipFile(zipfile.ZipFile):
"""ZipFile that can assert that each of its extracted contents matches
- an expected sha256 hash. Note that each file must be completly read in
+ an expected sha256 hash. Note that each file must be completly read in
order for its hash to be checked."""
def __init__(self, file, mode="r",
@@ -440,8 +443,8 @@ class VerifyingZipFile(zipfile.ZipFile):
name = name_or_info.filename
else:
name = name_or_info
- if (name in self._expected_hashes
- and self._expected_hashes[name] != None):
+
+ if name in self._expected_hashes and self._expected_hashes[name] is not None:
expected_hash = self._expected_hashes[name]
try:
_update_crc_orig = ef._update_crc
diff --git a/wheel/metadata.py b/wheel/metadata.py
index 2b123f9..a779188 100644
--- a/wheel/metadata.py
+++ b/wheel/metadata.py
@@ -2,35 +2,33 @@
Tools for converting old- to new-style metadata.
"""
-from collections import namedtuple
-from .pkginfo import read_pkg_info
-from .util import OrderedDefaultDict
-from collections import OrderedDict
-
-import re
+import email.parser
import os.path
+import re
import textwrap
+from collections import namedtuple, OrderedDict
+
import pkg_resources
-import email.parser
from . import __version__ as wheel_version
+from .pkginfo import read_pkg_info
+from .util import OrderedDefaultDict
METADATA_VERSION = "2.0"
-PLURAL_FIELDS = { "classifier" : "classifiers",
- "provides_dist" : "provides",
- "provides_extra" : "extras" }
+PLURAL_FIELDS = {"classifier": "classifiers",
+ "provides_dist": "provides",
+ "provides_extra": "extras"}
SKIP_FIELDS = set()
-CONTACT_FIELDS = (({"email":"author_email", "name": "author"},
- "author"),
- ({"email":"maintainer_email", "name": "maintainer"},
- "maintainer"))
+CONTACT_FIELDS = (({"email": "author_email", "name": "author"},
+ "author"),
+ ({"email": "maintainer_email", "name": "maintainer"},
+ "maintainer"))
# commonly filled out as "UNKNOWN" by distutils:
-UNKNOWN_FIELDS = set(("author", "author_email", "platform", "home_page",
- "license"))
+UNKNOWN_FIELDS = {"author", "author_email", "platform", "home_page", "license"}
# Wheel itself is probably the only program that uses non-extras markers
# in METADATA/PKG-INFO. Support its syntax with the extra at the end only.
@@ -39,13 +37,14 @@ KEYWORDS_RE = re.compile("[\0-,]+")
MayRequiresKey = namedtuple('MayRequiresKey', ('condition', 'extra'))
+
def unique(iterable):
"""
Yield unique values in iterable, preserving order.
"""
seen = set()
for value in iterable:
- if not value in seen:
+ if value not in seen:
seen.add(value)
yield value
@@ -72,6 +71,7 @@ def handle_requires(metadata, pkg_info, key):
if may_requires:
metadata['run_requires'] = []
+
def sort_key(item):
# Both condition and extra could be None, which can't be compared
# against strings in Python 3.
@@ -79,6 +79,7 @@ def handle_requires(metadata, pkg_info, key):
if key.condition is None:
return ''
return key.condition
+
for key, value in sorted(may_requires.items(), key=sort_key):
may_requirement = OrderedDict((('requires', value),))
if key.extra:
@@ -87,7 +88,7 @@ def handle_requires(metadata, pkg_info, key):
may_requirement['environment'] = key.condition
metadata['run_requires'].append(may_requirement)
- if not 'extras' in metadata:
+ if 'extras' not in metadata:
metadata['extras'] = []
metadata['extras'].extend([key.extra for key in may_requires.keys() if key.extra])
@@ -103,7 +104,8 @@ def pkginfo_to_dict(path, distribution=None):
distribution: optional distutils Distribution()
"""
- metadata = OrderedDefaultDict(lambda: OrderedDefaultDict(lambda: OrderedDefaultDict(OrderedDict)))
+ metadata = OrderedDefaultDict(
+ lambda: OrderedDefaultDict(lambda: OrderedDefaultDict(OrderedDict)))
metadata["generator"] = "bdist_wheel (" + wheel_version + ")"
try:
unicode
@@ -148,12 +150,12 @@ def pkginfo_to_dict(path, distribution=None):
handle_requires(metadata, pkg_info, key)
elif low_key == 'provides_extra':
- if not 'extras' in metadata:
+ if 'extras' not in metadata:
metadata['extras'] = []
metadata['extras'].extend(pkg_info.get_all(key))
elif low_key == 'home_page':
- metadata['extensions']['python.details']['project_urls'] = {'Home':pkg_info[key]}
+ metadata['extensions']['python.details']['project_urls'] = {'Home': pkg_info[key]}
elif low_key == 'keywords':
metadata['keywords'] = KEYWORDS_RE.split(pkg_info[key])
@@ -173,7 +175,7 @@ def pkginfo_to_dict(path, distribution=None):
requirements = getattr(distribution, attr)
if isinstance(requirements, list):
new_requirements = sorted(convert_requirements(requirements))
- metadata[requires] = [{'requires':new_requirements}]
+ metadata[requires] = [{'requires': new_requirements}]
except AttributeError:
pass
@@ -215,6 +217,7 @@ def pkginfo_to_dict(path, distribution=None):
return metadata
+
def requires_to_requires_dist(requirement):
"""Compose the version predicates for requirement in PEP 345 fashion."""
requires_dist = []
@@ -224,6 +227,7 @@ def requires_to_requires_dist(requirement):
return ''
return " (%s)" % ','.join(requires_dist)
+
def convert_requirements(requirements):
"""Yield Requires-Dist: strings for parsed requirements strings."""
for req in requirements:
@@ -234,6 +238,7 @@ 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')
@@ -257,6 +262,7 @@ def generate_requirements(extras_require):
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
@@ -290,8 +296,8 @@ def pkginfo_unicode(pkg_info, field):
return str(text)
for item in pkg_info.raw_items():
if item[0].lower() == field:
- text = item[1].encode('ascii', 'surrogateescape')\
- .decode('utf-8')
+ text = item[1].encode('ascii', 'surrogateescape') \
+ .decode('utf-8')
break
return text
@@ -311,20 +317,22 @@ def dedent_description(pkg_info):
description_lines = description.splitlines()
description_dedent = '\n'.join(
- # if the first line of long_description is blank,
- # the first line here will be indented.
- (description_lines[0].lstrip(),
- textwrap.dedent('\n'.join(description_lines[1:])),
- '\n'))
+ # if the first line of long_description is blank,
+ # the first line here will be indented.
+ (description_lines[0].lstrip(),
+ textwrap.dedent('\n'.join(description_lines[1:])),
+ '\n'))
if surrogates:
- description_dedent = description_dedent\
- .encode("utf8")\
- .decode("ascii", "surrogateescape")
+ description_dedent = description_dedent \
+ .encode("utf8") \
+ .decode("ascii", "surrogateescape")
return description_dedent
if __name__ == "__main__":
- import sys, pprint
+ import sys
+ import pprint
+
pprint.pprint(pkginfo_to_dict(sys.argv[1]))
diff --git a/wheel/paths.py b/wheel/paths.py
index fe3dfd6..afb3cae 100644
--- a/wheel/paths.py
+++ b/wheel/paths.py
@@ -4,22 +4,24 @@ Installation paths.
Map the .data/ subdirectory names to install paths.
"""
+import distutils.command.install as install
+import distutils.dist as dist
import os.path
import sys
-import distutils.dist as dist
-import distutils.command.install as install
+
def get_install_command(name):
# late binding due to potential monkeypatching
- d = dist.Distribution({'name':name})
+ d = dist.Distribution({'name': name})
i = install.install(d)
i.finalize_options()
return i
+
def get_install_paths(name):
"""
Return the (distutils) install paths for the named dist.
-
+
A dict with ('purelib', 'platlib', 'headers', 'scripts', 'data') keys.
"""
paths = {}
diff --git a/wheel/pep425tags.py b/wheel/pep425tags.py
index a7bd4a9..47b959e 100644
--- a/wheel/pep425tags.py
+++ b/wheel/pep425tags.py
@@ -1,10 +1,9 @@
"""Generate and work with PEP 425 Compatibility Tags."""
+import distutils.util
import sys
-import warnings
-
import sysconfig
-import distutils.util
+import warnings
def get_config_var(var):
@@ -107,11 +106,11 @@ def get_supported(versions=None, supplied_platform=None):
"""Return a list of supported tags for each version specified in
`versions`.
- :param versions: a list of string versions, of the form ["33", "32"],
+ :param versions: a list of string versions, of the form ["33", "32"],
or None. The first version will be assumed to support our ABI.
"""
supported = []
-
+
# Versions must be given with respect to the preference
if versions is None:
versions = []
@@ -120,15 +119,15 @@ def get_supported(versions=None, supplied_platform=None):
# Support all previous minor Python versions.
for minor in range(version_info[-1], -1, -1):
versions.append(''.join(map(str, major + (minor,))))
-
+
impl = get_abbr_impl()
-
+
abis = []
abi = get_abi_tag()
if abi:
abis[0:0] = [abi]
-
+
abi3s = set()
import imp
for suffix in imp.get_suffixes():
@@ -143,7 +142,7 @@ def get_supported(versions=None, supplied_platform=None):
if supplied_platform:
platforms.append(supplied_platform)
platforms.append(get_platform())
-
+
# Current version, current API (built specifically for our Python):
for abi in abis:
for arch in platforms:
@@ -162,10 +161,10 @@ def get_supported(versions=None, supplied_platform=None):
for i, version in enumerate(versions):
supported.append(('%s%s' % (impl, version), 'none', 'any'))
if i == 0:
- # Tagged specifically as being cross-version compatible
+ # Tagged specifically as being cross-version compatible
# (with just the major version specified)
- supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
-
+ supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
+
# Major Python version + platform; e.g. binaries not using the Python API
supported.append(('py%s' % (versions[0][0]), 'none', arch))
@@ -174,5 +173,5 @@ def get_supported(versions=None, supplied_platform=None):
supported.append(('py%s' % (version,), 'none', 'any'))
if i == 0:
supported.append(('py%s' % (version[0]), 'none', 'any'))
-
+
return supported
diff --git a/wheel/pkginfo.py b/wheel/pkginfo.py
index 8a4aca3..e153db0 100644
--- a/wheel/pkginfo.py
+++ b/wheel/pkginfo.py
@@ -11,7 +11,7 @@ except NameError:
if not _PY3:
from email.generator import Generator
-
+
def read_pkg_info_bytes(bytestr):
return Parser().parsestr(bytestr)
@@ -22,18 +22,18 @@ if not _PY3:
def write_pkg_info(path, message):
with open(path, 'w') as metadata:
- Generator(metadata, maxheaderlen=0).flatten(message)
-
+ Generator(metadata, maxheaderlen=0).flatten(message)
else:
from email.generator import BytesGenerator
+
def read_pkg_info_bytes(bytestr):
headers = bytestr.decode(encoding="ascii", errors="surrogateescape")
message = Parser().parsestr(headers)
return message
def read_pkg_info(path):
- with open(path, "r",
- encoding="ascii",
+ with open(path, "r",
+ encoding="ascii",
errors="surrogateescape") as headers:
message = Parser().parse(headers)
return message
@@ -41,4 +41,3 @@ else:
def write_pkg_info(path, message):
with open(path, "wb") as out:
BytesGenerator(out, maxheaderlen=0).flatten(message)
-
diff --git a/wheel/signatures/__init__.py b/wheel/signatures/__init__.py
index 3f21b50..e7a5331 100644
--- a/wheel/signatures/__init__.py
+++ b/wheel/signatures/__init__.py
@@ -2,63 +2,67 @@
Create and verify jws-js format Ed25519 signatures.
"""
-__all__ = [ 'sign', 'verify' ]
-
import json
from ..util import urlsafe_b64decode, urlsafe_b64encode, native, binary
+__all__ = ['sign', 'verify']
+
ed25519ll = None
ALG = "Ed25519"
+
def get_ed25519ll():
"""Lazy import-and-test of ed25519 module"""
global ed25519ll
-
+
if not ed25519ll:
try:
- import ed25519ll # fast (thousands / s)
- except (ImportError, OSError): # pragma nocover
- from . import ed25519py as ed25519ll # pure Python (hundreds / s)
+ import ed25519ll # fast (thousands / s)
+ except (ImportError, OSError): # pragma nocover
+ from . import ed25519py as ed25519ll # pure Python (hundreds / s)
test()
-
+
return ed25519ll
+
def sign(payload, keypair):
- """Return a JWS-JS format signature given a JSON-serializable payload and
+ """Return a JWS-JS format signature given a JSON-serializable payload and
an Ed25519 keypair."""
get_ed25519ll()
#
header = {
"alg": ALG,
"jwk": {
- "kty": ALG, # alg -> kty in jwk-08.
+ "kty": ALG, # alg -> kty in jwk-08.
"vk": native(urlsafe_b64encode(keypair.vk))
}
}
-
+
encoded_header = urlsafe_b64encode(binary(json.dumps(header, sort_keys=True)))
encoded_payload = urlsafe_b64encode(binary(json.dumps(payload, sort_keys=True)))
secured_input = b".".join((encoded_header, encoded_payload))
sig_msg = ed25519ll.crypto_sign(secured_input, keypair.sk)
signature = sig_msg[:ed25519ll.SIGNATUREBYTES]
encoded_signature = urlsafe_b64encode(signature)
-
- return {"recipients":
- [{"header":native(encoded_header),
- "signature":native(encoded_signature)}],
+
+ return {"recipients":
+ [{"header": native(encoded_header),
+ "signature": native(encoded_signature)}],
"payload": native(encoded_payload)}
+
def assertTrue(condition, message=""):
if not condition:
raise ValueError(message)
-
+
+
def verify(jwsjs):
"""Return (decoded headers, payload) if all signatures in jwsjs are
consistent, else raise ValueError.
-
+
Caller must decide whether the keys are actually trusted."""
- get_ed25519ll()
+ get_ed25519ll()
# XXX forbid duplicate keys in JSON input using object_pairs_hook (2.7+)
recipients = jwsjs["recipients"]
encoded_payload = binary(jwsjs["payload"])
@@ -68,12 +72,12 @@ def verify(jwsjs):
h = binary(recipient["header"])
s = binary(recipient["signature"])
header = json.loads(native(urlsafe_b64decode(h)))
- assertTrue(header["alg"] == ALG,
- "Unexpected algorithm {0}".format(header["alg"]))
- if "alg" in header["jwk"] and not "kty" in header["jwk"]:
- header["jwk"]["kty"] = header["jwk"]["alg"] # b/w for JWK < -08
- assertTrue(header["jwk"]["kty"] == ALG, # true for Ed25519
- "Unexpected key type {0}".format(header["jwk"]["kty"]))
+ assertTrue(header["alg"] == ALG,
+ "Unexpected algorithm {0}".format(header["alg"]))
+ if "alg" in header["jwk"] and "kty" not in header["jwk"]:
+ header["jwk"]["kty"] = header["jwk"]["alg"] # b/w for JWK < -08
+ assertTrue(header["jwk"]["kty"] == ALG, # true for Ed25519
+ "Unexpected key type {0}".format(header["jwk"]["kty"]))
vk = urlsafe_b64decode(binary(header["jwk"]["vk"]))
secured_input = b".".join((h, encoded_payload))
sig = urlsafe_b64decode(s)
@@ -91,6 +95,7 @@ def verify(jwsjs):
return headers, payload
+
def test():
kp = ed25519ll.crypto_sign_keypair()
payload = {'test': 'onstartup'}
@@ -101,6 +106,5 @@ def test():
verify(jwsjs)
except ValueError:
pass
- else: # pragma no cover
+ else: # pragma no cover
raise RuntimeError("No error from bad wheel.signatures payload.")
-
diff --git a/wheel/signatures/djbec.py b/wheel/signatures/djbec.py
index 56efe44..87f72d4 100644
--- a/wheel/signatures/djbec.py
+++ b/wheel/signatures/djbec.py
@@ -6,61 +6,80 @@
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
# Specifically add-2008-hwcd-4 and dbl-2008-hwcd
-try: # pragma nocover
+import hashlib
+import random
+
+try: # pragma nocover
unicode
PY3 = False
+
def asbytes(b):
"""Convert array of integers to byte string"""
return ''.join(chr(x) for x in b)
+
def joinbytes(b):
"""Convert array of bytes to byte string"""
return ''.join(b)
+
def bit(h, i):
"""Return i'th bit of bytestring h"""
- return (ord(h[i//8]) >> (i%8)) & 1
-
-except NameError: # pragma nocover
+ return (ord(h[i // 8]) >> (i % 8)) & 1
+except NameError: # pragma nocover
PY3 = True
asbytes = bytes
joinbytes = bytes
- def bit(h, i):
- return (h[i//8] >> (i%8)) & 1
-import hashlib
+ def bit(h, i):
+ return (h[i // 8] >> (i % 8)) & 1
b = 256
-q = 2**255 - 19
-l = 2**252 + 27742317777372353535851937790883648493
+q = 2 ** 255 - 19
+l = 2 ** 252 + 27742317777372353535851937790883648493
+
def H(m):
return hashlib.sha512(m).digest()
+
def expmod(b, e, m):
- if e == 0: return 1
+ if e == 0:
+ return 1
+
t = expmod(b, e // 2, m) ** 2 % m
- if e & 1: t = (t * b) % m
+ if e & 1:
+ t = (t * b) % m
+
return t
+
# Can probably get some extra speedup here by replacing this with
# an extended-euclidean, but performance seems OK without that
def inv(x):
- return expmod(x, q-2, q)
+ return expmod(x, q - 2, q)
+
d = -121665 * inv(121666)
-I = expmod(2,(q-1)//4,q)
+I = expmod(2, (q - 1) // 4, q)
+
def xrecover(y):
- xx = (y*y-1) * inv(d*y*y+1)
- x = expmod(xx,(q+3)//8,q)
- if (x*x - xx) % q != 0: x = (x*I) % q
- if x % 2 != 0: x = q-x
+ xx = (y * y - 1) * inv(d * y * y + 1)
+ x = expmod(xx, (q + 3) // 8, q)
+ if (x * x - xx) % q != 0:
+ x = (x * I) % q
+
+ if x % 2 != 0:
+ x = q - x
+
return x
+
By = 4 * inv(5)
Bx = xrecover(By)
-B = [Bx % q,By % q]
+B = [Bx % q, By % q]
+
-#def edwards(P,Q):
+# def edwards(P,Q):
# x1 = P[0]
# y1 = P[1]
# x2 = Q[0]
@@ -69,7 +88,7 @@ B = [Bx % q,By % q]
# y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
# return (x3 % q,y3 % q)
-#def scalarmult(P,e):
+# def scalarmult(P,e):
# if e == 0: return [0,1]
# Q = scalarmult(P,e/2)
# Q = edwards(Q,Q)
@@ -82,113 +101,137 @@ B = [Bx % q,By % q]
def xpt_add(pt1, pt2):
(X1, Y1, Z1, T1) = pt1
(X2, Y2, Z2, T2) = pt2
- A = ((Y1-X1)*(Y2+X2)) % q
- B = ((Y1+X1)*(Y2-X2)) % q
- C = (Z1*2*T2) % q
- D = (T1*2*Z2) % q
- E = (D+C) % q
- F = (B-A) % q
- G = (B+A) % q
- H = (D-C) % q
- X3 = (E*F) % q
- Y3 = (G*H) % q
- Z3 = (F*G) % q
- T3 = (E*H) % q
+ A = ((Y1 - X1) * (Y2 + X2)) % q
+ B = ((Y1 + X1) * (Y2 - X2)) % q
+ C = (Z1 * 2 * T2) % q
+ D = (T1 * 2 * Z2) % q
+ E = (D + C) % q
+ F = (B - A) % q
+ G = (B + A) % q
+ H = (D - C) % q
+ X3 = (E * F) % q
+ Y3 = (G * H) % q
+ Z3 = (F * G) % q
+ T3 = (E * H) % q
return (X3, Y3, Z3, T3)
-def xpt_double (pt):
+
+def xpt_double(pt):
(X1, Y1, Z1, _) = pt
- A = (X1*X1)
- B = (Y1*Y1)
- C = (2*Z1*Z1)
+ A = (X1 * X1)
+ B = (Y1 * Y1)
+ C = (2 * Z1 * Z1)
D = (-A) % q
- J = (X1+Y1) % q
- E = (J*J-A-B) % q
- G = (D+B) % q
- F = (G-C) % q
- H = (D-B) % q
- X3 = (E*F) % q
- Y3 = (G*H) % q
- Z3 = (F*G) % q
- T3 = (E*H) % q
- return (X3, Y3, Z3, T3)
-
-def pt_xform (pt):
+ J = (X1 + Y1) % q
+ E = (J * J - A - B) % q
+ G = (D + B) % q
+ F = (G - C) % q
+ H = (D - B) % q
+ X3 = (E * F) % q
+ Y3 = (G * H) % q
+ Z3 = (F * G) % q
+ T3 = (E * H) % q
+ return X3, Y3, Z3, T3
+
+
+def pt_xform(pt):
(x, y) = pt
- return (x, y, 1, (x*y)%q)
+ return x, y, 1, (x * y) % q
+
-def pt_unxform (pt):
+def pt_unxform(pt):
(x, y, z, _) = pt
- return ((x*inv(z))%q, (y*inv(z))%q)
+ return (x * inv(z)) % q, (y * inv(z)) % q
+
+
+def xpt_mult(pt, n):
+ if n == 0:
+ return pt_xform((0, 1))
+
+ _ = xpt_double(xpt_mult(pt, n >> 1))
+ return xpt_add(_, pt) if n & 1 else _
-def xpt_mult (pt, n):
- if n==0: return pt_xform((0,1))
- _ = xpt_double(xpt_mult(pt, n>>1))
- return xpt_add(_, pt) if n&1 else _
def scalarmult(pt, e):
return pt_unxform(xpt_mult(pt_xform(pt), e))
+
def encodeint(y):
bits = [(y >> i) & 1 for i in range(b)]
e = [(sum([bits[i * 8 + j] << j for j in range(8)]))
- for i in range(b//8)]
+ for i in range(b // 8)]
return asbytes(e)
+
def encodepoint(P):
x = P[0]
y = P[1]
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
e = [(sum([bits[i * 8 + j] << j for j in range(8)]))
- for i in range(b//8)]
+ for i in range(b // 8)]
return asbytes(e)
-
+
+
def publickey(sk):
h = H(sk)
- a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
- A = scalarmult(B,a)
+ a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
+ A = scalarmult(B, a)
return encodepoint(A)
+
def Hint(m):
h = H(m)
- return sum(2**i * bit(h,i) for i in range(2*b))
+ return sum(2 ** i * bit(h, i) for i in range(2 * b))
+
-def signature(m,sk,pk):
+def signature(m, sk, pk):
h = H(sk)
- a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
- inter = joinbytes([h[i] for i in range(b//8,b//4)])
+ a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
+ inter = joinbytes([h[i] for i in range(b // 8, b // 4)])
r = Hint(inter + m)
- R = scalarmult(B,r)
+ R = scalarmult(B, r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
+
def isoncurve(P):
x = P[0]
y = P[1]
- return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
+ return (-x * x + y * y - 1 - d * x * x * y * y) % q == 0
+
def decodeint(s):
- return sum(2**i * bit(s,i) for i in range(0,b))
+ return sum(2 ** i * bit(s, i) for i in range(0, b))
+
def decodepoint(s):
- y = sum(2**i * bit(s,i) for i in range(0,b-1))
+ y = sum(2 ** i * bit(s, i) for i in range(0, b - 1))
x = xrecover(y)
- if x & 1 != bit(s,b-1): x = q-x
- P = [x,y]
- if not isoncurve(P): raise Exception("decoding point that is not on curve")
+ if x & 1 != bit(s, b - 1):
+ x = q - x
+
+ P = [x, y]
+ if not isoncurve(P):
+ raise Exception("decoding point that is not on curve")
+
return P
+
def checkvalid(s, m, pk):
- if len(s) != b//4: raise Exception("signature length is wrong")
- if len(pk) != b//8: raise Exception("public-key length is wrong")
- R = decodepoint(s[0:b//8])
+ if len(s) != b // 4:
+ raise Exception("signature length is wrong")
+ if len(pk) != b // 8:
+ raise Exception("public-key length is wrong")
+
+ R = decodepoint(s[0:b // 8])
A = decodepoint(pk)
- S = decodeint(s[b//8:b//4])
+ S = decodeint(s[b // 8:b // 4])
h = Hint(encodepoint(R) + pk + m)
- v1 = scalarmult(B,S)
-# v2 = edwards(R,scalarmult(A,h))
+ v1 = scalarmult(B, S)
+ # v2 = edwards(R,scalarmult(A,h))
v2 = pt_unxform(xpt_add(pt_xform(R), pt_xform(scalarmult(A, h))))
- return v1==v2
+ return v1 == v2
+
##########################################################
#
@@ -199,7 +242,8 @@ def checkvalid(s, m, pk):
P = q
A = 486662
-#def expmod(b, e, m):
+
+# def expmod(b, e, m):
# if e == 0: return 1
# t = expmod(b, e / 2, m) ** 2 % m
# if e & 1: t = (t * b) % m
@@ -207,64 +251,73 @@ A = 486662
# def inv(x): return expmod(x, P - 2, P)
+
def add(n, m, d):
(xn, zn) = n
- (xm, zm) = m
+ (xm, zm) = m
(xd, zd) = d
x = 4 * (xm * xn - zm * zn) ** 2 * zd
z = 4 * (xm * zn - zm * xn) ** 2 * xd
return (x % P, z % P)
+
def double(n):
(xn, zn) = n
x = (xn ** 2 - zn ** 2) ** 2
z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2)
return (x % P, z % P)
+
def curve25519(n, base=9):
- one = (base,1)
+ one = (base, 1)
two = double(one)
+
# f(m) evaluates to a tuple
# containing the mth multiple and the
# (m+1)th multiple of base.
def f(m):
- if m == 1: return (one, two)
+ if m == 1:
+ return (one, two)
+
(pm, pm1) = f(m // 2)
- if (m & 1):
+ if m & 1:
return (add(pm, pm1, one), double(pm1))
+
return (double(pm), add(pm, pm1, one))
- ((x,z), _) = f(n)
+
+ ((x, z), _) = f(n)
return (x * inv(z)) % P
-import random
def genkey(n=0):
- n = n or random.randint(0,P)
+ n = n or random.randint(0, P)
n &= ~7
n &= ~(128 << 8 * 31)
n |= 64 << 8 * 31
return n
-#def str2int(s):
+
+# def str2int(s):
# return int(hexlify(s), 16)
# # return sum(ord(s[i]) << (8 * i) for i in range(32))
#
-#def int2str(n):
+# def int2str(n):
# return unhexlify("%x" % n)
# # return ''.join([chr((n >> (8 * i)) & 255) for i in range(32)])
#################################################
+
def dsa_test():
import os
- msg = str(random.randint(q,q+q)).encode('utf-8')
+ msg = str(random.randint(q, q + q)).encode('utf-8')
sk = os.urandom(32)
pk = publickey(sk)
sig = signature(msg, sk, pk)
return checkvalid(sig, msg, pk)
+
def dh_test():
sk1 = genkey()
sk2 = genkey()
return curve25519(sk1, curve25519(sk2)) == curve25519(sk2, curve25519(sk1))
-
diff --git a/wheel/signatures/ed25519py.py b/wheel/signatures/ed25519py.py
index 55eba2e..0c4ab8f 100644
--- a/wheel/signatures/ed25519py.py
+++ b/wheel/signatures/ed25519py.py
@@ -1,22 +1,21 @@
-# -*- coding: utf-8 -*-
-
-import warnings
import os
-
+import warnings
from collections import namedtuple
+
from . import djbec
__all__ = ['crypto_sign', 'crypto_sign_open', 'crypto_sign_keypair', 'Keypair',
'PUBLICKEYBYTES', 'SECRETKEYBYTES', 'SIGNATUREBYTES']
-PUBLICKEYBYTES=32
-SECRETKEYBYTES=64
-SIGNATUREBYTES=64
+PUBLICKEYBYTES = 32
+SECRETKEYBYTES = 64
+SIGNATUREBYTES = 64
+
+Keypair = namedtuple('Keypair', ('vk', 'sk')) # verifying key, secret key
-Keypair = namedtuple('Keypair', ('vk', 'sk')) # verifying key, secret key
def crypto_sign_keypair(seed=None):
- """Return (verifying, secret) key from a given seed, or os.urandom(32)"""
+ """Return (verifying, secret) key from a given seed, or os.urandom(32)"""
if seed is None:
seed = os.urandom(PUBLICKEYBYTES)
else:
@@ -47,6 +46,5 @@ def crypto_sign_open(signed, vk):
raise ValueError("Bad verifying key length %d" % len(vk))
rc = djbec.checkvalid(signed[:SIGNATUREBYTES], signed[SIGNATUREBYTES:], vk)
if not rc:
- raise ValueError("rc != True", rc)
+ raise ValueError("rc != True", rc)
return signed[SIGNATUREBYTES:]
-
diff --git a/wheel/signatures/keys.py b/wheel/signatures/keys.py
index 57d7feb..eb5d4ac 100644
--- a/wheel/signatures/keys.py
+++ b/wheel/signatures/keys.py
@@ -1,7 +1,7 @@
"""Store and retrieve wheel signing / verifying keys.
-Given a scope (a package name, + meaning "all packages", or - meaning
-"no packages"), return a list of verifying keys that are trusted for that
+Given a scope (a package name, + meaning "all packages", or - meaning
+"no packages"), return a list of verifying keys that are trusted for that
scope.
Given a package name, return a list of (scope, key) suggested keys to sign
@@ -33,15 +33,17 @@ wheel export key
import json
import os.path
+
from ..util import native, load_config_paths, save_config_path
+
class WheelKeys(object):
SCHEMA = 1
CONFIG_NAME = 'wheel.json'
-
+
def __init__(self):
- self.data = {'signers':[], 'verifiers':[]}
-
+ self.data = {'signers': [], 'verifiers': []}
+
def load(self):
# XXX JSON is not a great database
for path in load_config_paths('wheel'):
@@ -50,7 +52,7 @@ class WheelKeys(object):
with open(conf, 'r') as infile:
self.data = json.load(infile)
for x in ('signers', 'verifiers'):
- if not x in self.data:
+ if x not in self.data:
self.data[x] = []
if 'schema' not in self.data:
self.data['schema'] = self.SCHEMA
@@ -62,38 +64,38 @@ class WheelKeys(object):
return self
def save(self):
- # Try not to call this a very long time after load()
+ # Try not to call this a very long time after load()
path = save_config_path('wheel')
conf = os.path.join(native(path), self.CONFIG_NAME)
with open(conf, 'w+') as out:
json.dump(self.data, out, indent=2)
return self
-
+
def trust(self, scope, vk):
"""Start trusting a particular key for given scope."""
- self.data['verifiers'].append({'scope':scope, 'vk':vk})
+ self.data['verifiers'].append({'scope': scope, 'vk': vk})
return self
-
+
def untrust(self, scope, vk):
"""Stop trusting a particular key for given scope."""
- self.data['verifiers'].remove({'scope':scope, 'vk':vk})
+ self.data['verifiers'].remove({'scope': scope, 'vk': vk})
return self
-
+
def trusted(self, scope=None):
"""Return list of [(scope, trusted key), ...] for given scope."""
- trust = [(x['scope'], x['vk']) for x in self.data['verifiers'] if x['scope'] in (scope, '+')]
+ trust = [(x['scope'], x['vk']) for x in self.data['verifiers']
+ if x['scope'] in (scope, '+')]
trust.sort(key=lambda x: x[0])
trust.reverse()
return trust
-
+
def signers(self, scope):
"""Return list of signing key(s)."""
sign = [(x['scope'], x['vk']) for x in self.data['signers'] if x['scope'] in (scope, '+')]
sign.sort(key=lambda x: x[0])
sign.reverse()
return sign
-
+
def add_signer(self, scope, vk):
"""Remember verifying key vk as being valid for signing in scope."""
- self.data['signers'].append({'scope':scope, 'vk':vk})
-
+ self.data['signers'].append({'scope': scope, 'vk': vk})
diff --git a/wheel/test/__init__.py b/wheel/test/__init__.py
index 4287ca8..e69de29 100644
--- a/wheel/test/__init__.py
+++ b/wheel/test/__init__.py
@@ -1 +0,0 @@
-# \ No newline at end of file
diff --git a/wheel/test/complex-dist/setup.py b/wheel/test/complex-dist/setup.py
index 615d5dc..0b3b76a 100644
--- a/wheel/test/complex-dist/setup.py
+++ b/wheel/test/complex-dist/setup.py
@@ -2,6 +2,7 @@ from setuptools import setup
try:
unicode
+
def u8(s):
return s.decode('unicode-escape')
except NameError:
@@ -18,7 +19,7 @@ setup(name='complex-dist',
packages=['complexdist'],
setup_requires=["wheel", "setuptools"],
install_requires=["quux", "splort"],
- extras_require={'simple':['simple.dist']},
+ extras_require={'simple': ['simple.dist']},
tests_require=["foo", "bar>=10.0.0"],
entry_points={
'console_scripts': [
@@ -27,4 +28,3 @@ setup(name='complex-dist',
],
},
)
-
diff --git a/wheel/test/conftest.py b/wheel/test/conftest.py
index ad87cb3..8d5b073 100644
--- a/wheel/test/conftest.py
+++ b/wheel/test/conftest.py
@@ -12,7 +12,7 @@ import pytest
def error_on_ResourceWarning():
"""This fixture captures ResourceWarning's and reports an "error"
describing the file handles left open.
-
+
This is shown regardless of how successful the test was, if a test fails
and leaves files open then those files will be reported. Ideally, even
those files should be closed properly after a test failure or exception.
@@ -35,11 +35,11 @@ def error_on_ResourceWarning():
# Python 3, PyPy3
with warnings.catch_warnings(record=True) as caught:
- warnings.resetwarnings() # clear all filters
- warnings.simplefilter('ignore') # ignore all
- warnings.simplefilter('always', ResourceWarning) # add filter
- yield # run tests in this context
- gc.collect() # run garbage collection (for pypy3)
+ warnings.resetwarnings() # clear all filters
+ warnings.simplefilter('ignore') # ignore all
+ warnings.simplefilter('always', ResourceWarning) # add filter
+ yield # run tests in this context
+ gc.collect() # run garbage collection (for pypy3)
if not caught:
return
pytest.fail('The following file descriptors were not closed properly:\n' +
diff --git a/wheel/test/extension.dist/setup.py b/wheel/test/extension.dist/setup.py
index 7a66845..9e78469 100644
--- a/wheel/test/extension.dist/setup.py
+++ b/wheel/test/extension.dist/setup.py
@@ -2,6 +2,7 @@ from setuptools import setup, Extension
try:
unicode
+
def u8(s):
return s.decode('unicode-escape').encode('utf-8')
except NameError:
@@ -12,9 +13,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)
+ Extension(name='extension',
+ sources=['extension.c'],
+ py_limited_api=True)
],
)
-
diff --git a/wheel/test/headers.dist/setup.py b/wheel/test/headers.dist/setup.py
index 2704f01..8e5273f 100644
--- a/wheel/test/headers.dist/setup.py
+++ b/wheel/test/headers.dist/setup.py
@@ -2,6 +2,7 @@ from setuptools import setup
try:
unicode
+
def u8(s):
return s.decode('unicode-escape').encode('utf-8')
except NameError:
@@ -13,4 +14,3 @@ setup(name='headers.dist',
description=u8('A distribution with headers'),
headers=['header.h']
)
-
diff --git a/wheel/test/simple.dist/setup.py b/wheel/test/simple.dist/setup.py
index 50c909f..ef90683 100644
--- a/wheel/test/simple.dist/setup.py
+++ b/wheel/test/simple.dist/setup.py
@@ -2,6 +2,7 @@ from setuptools import setup
try:
unicode
+
def u8(s):
return s.decode('unicode-escape').encode('utf-8')
except NameError:
@@ -14,4 +15,3 @@ setup(name='simple.dist',
packages=['simpledist'],
extras_require={'voting': ['beaglevote']},
)
-
diff --git a/wheel/test/test_basic.py b/wheel/test/test_basic.py
index 6bd46b1..e36c05a 100644
--- a/wheel/test/test_basic.py
+++ b/wheel/test/test_basic.py
@@ -2,23 +2,23 @@
Basic wheel tests.
"""
-import os
-import pkg_resources
import json
+import os
import sys
+from shutil import rmtree
+from zipfile import ZipFile
+import pkg_resources
from pkg_resources import resource_filename
-import wheel.util
import wheel.tool
-
+import wheel.util
from wheel import egg2wheel
from wheel.install import WheelFile
-from zipfile import ZipFile
-from shutil import rmtree
test_distributions = ("complex-dist", "simple.dist", "headers.dist")
+
def teardown_module():
"""Delete eggs/wheels created by tests."""
base = pkg_resources.resource_filename('wheel.test', '')
@@ -29,10 +29,12 @@ def teardown_module():
except OSError:
pass
+
def setup_module():
build_wheel()
build_egg()
+
def build_wheel():
"""Build wheels from test distributions."""
for dist in test_distributions:
@@ -45,6 +47,7 @@ def build_wheel():
finally:
os.chdir(pwd)
+
def build_egg():
"""Build eggs from test distributions."""
for dist in test_distributions:
@@ -57,10 +60,12 @@ def build_egg():
finally:
os.chdir(pwd)
+
def test_findable():
"""Make sure pkg_resources can find us."""
assert pkg_resources.working_set.by_key['wheel'].version
+
def test_egg_re():
"""Make sure egg_info_re matches."""
egg_names_path = pkg_resources.resource_filename('wheel', 'eggnames.txt')
@@ -71,17 +76,19 @@ def test_egg_re():
continue
assert egg2wheel.egg_info_re.match(line), line
+
def test_compatibility_tags():
"""Test compatibilty tags are working."""
wf = WheelFile("package-1.0.0-cp32.cp33-noabi-noarch.whl")
assert (list(wf.compatibility_tags) ==
- [('cp32', 'noabi', 'noarch'), ('cp33', 'noabi', 'noarch')])
- assert (wf.arity == 2)
+ [('cp32', 'noabi', 'noarch'), ('cp33', 'noabi', 'noarch')])
+ assert wf.arity == 2
wf2 = WheelFile("package-1.0.0-1st-cp33-noabi-noarch.whl")
wf2_info = wf2.parsed_filename.groupdict()
assert wf2_info['build'] == '1st', wf2_info
+
def test_convert_egg():
base = pkg_resources.resource_filename('wheel.test', '')
for dist in test_distributions:
@@ -89,6 +96,7 @@ def test_convert_egg():
eggs = [e for e in os.listdir(distdir) if e.endswith('.egg')]
wheel.tool.convert(eggs, distdir, verbose=False)
+
def test_unpack():
"""
Make sure 'wheel unpack' works.
@@ -100,6 +108,7 @@ def test_unpack():
for wheelfile in (w for w in os.listdir(distdir) if w.endswith('.whl')):
wheel.tool.unpack(os.path.join(distdir, wheelfile), distdir)
+
def test_no_scripts():
"""Make sure entry point scripts are not generated."""
dist = "complex-dist"
@@ -109,7 +118,8 @@ def test_no_scripts():
if filename.endswith('.whl'):
whl = ZipFile(os.path.join(dirname, filename))
for entry in whl.infolist():
- assert not '.data/scripts/' in entry.filename
+ assert '.data/scripts/' not in entry.filename
+
def test_pydist():
"""Make sure pydist.json exists and validates against our schema."""
@@ -137,6 +147,7 @@ def test_pydist():
valid += 1
assert valid > 0, "No metadata.json found"
+
def test_util():
"""Test functions in util.py."""
for i in range(10):
@@ -168,9 +179,11 @@ def test_pick_best():
('cp27', 'noabi', 'linux_i686'), ('py27', 'noabi', 'noarch')]
for supp in (supported, supported2, supported3):
- context = lambda: list(supp)
- for wheel in cand_wheels:
- wheel.context = context
+ def context():
+ return list(supp)
+
+ for wheel_ in cand_wheels:
+ wheel_.context = context
best = max(cand_wheels)
assert list(best.tags)[0] == supp[0]
diff --git a/wheel/test/test_install.py b/wheel/test/test_install.py
index ddcddf5..46ea02e 100644
--- a/wheel/test/test_install.py
+++ b/wheel/test/test_install.py
@@ -12,23 +12,27 @@
# The root is PLATLIB
# So, some in PLATLIB, and one in each of DATA, HEADERS and SCRIPTS.
-import wheel.tool
+import os
+import shutil
+from tempfile import mkdtemp
+
import wheel.pep425tags
+import wheel.tool
from wheel.install import WheelFile
-from tempfile import mkdtemp
-import shutil
-import os
THISDIR = os.path.dirname(__file__)
TESTWHEEL = os.path.join(THISDIR, 'test-1.0-py2.py3-none-win32.whl')
+
def check(*path):
return os.path.exists(os.path.join(*path))
+
def test_install():
- tempdir = mkdtemp()
def get_supported():
return list(wheel.pep425tags.get_supported()) + [('py3', 'none', 'win32')]
+
+ tempdir = mkdtemp()
whl = WheelFile(TESTWHEEL, context=get_supported)
assert whl.supports_current_python(get_supported)
try:
@@ -48,8 +52,7 @@ def test_install():
finally:
shutil.rmtree(tempdir)
+
def test_install_tool():
"""Slightly improve coverage of wheel.install"""
wheel.tool.install([TESTWHEEL], force=True, dry_run=True)
-
- \ No newline at end of file
diff --git a/wheel/test/test_keys.py b/wheel/test/test_keys.py
index f96166b..9a74e29 100644
--- a/wheel/test/test_keys.py
+++ b/wheel/test/test_keys.py
@@ -9,76 +9,78 @@ wheel_json = """
{
"verifiers": [
{
- "scope": "+",
+ "scope": "+",
"vk": "bp-bjK2fFgtA-8DhKKAAPm9-eAZcX_u03oBv2RlKOBc"
- },
+ },
{
- "scope": "+",
+ "scope": "+",
"vk": "KAHZBfyqFW3OcFDbLSG4nPCjXxUPy72phP9I4Rn9MAo"
},
{
- "scope": "+",
+ "scope": "+",
"vk": "tmAYCrSfj8gtJ10v3VkvW7jOndKmQIYE12hgnFu3cvk"
- }
- ],
+ }
+ ],
"signers": [
{
- "scope": "+",
+ "scope": "+",
"vk": "tmAYCrSfj8gtJ10v3VkvW7jOndKmQIYE12hgnFu3cvk"
- },
+ },
{
- "scope": "+",
+ "scope": "+",
"vk": "KAHZBfyqFW3OcFDbLSG4nPCjXxUPy72phP9I4Rn9MAo"
}
- ],
+ ],
"schema": 1
}
"""
+
class TestWheelKeys(unittest.TestCase):
def setUp(self):
- self.config = tempfile.NamedTemporaryFile(suffix='.json')
- self.config.close()
-
- self.config_path, self.config_filename = os.path.split(self.config.name)
def load(*args):
return [self.config_path]
+
def save(*args):
return self.config_path
+
+ self.config = tempfile.NamedTemporaryFile(suffix='.json')
+ self.config.close()
+ self.config_path, self.config_filename = os.path.split(self.config.name)
keys.load_config_paths = load
keys.save_config_path = save
self.wk = keys.WheelKeys()
self.wk.CONFIG_NAME = self.config_filename
-
+
def tearDown(self):
os.unlink(self.config.name)
-
+
def test_load_save(self):
self.wk.data = json.loads(wheel_json)
-
+
self.wk.add_signer('+', '67890')
self.wk.add_signer('scope', 'abcdefg')
-
+
self.wk.trust('epocs', 'gfedcba')
self.wk.trust('+', '12345')
-
+
self.wk.save()
-
+
del self.wk.data
self.wk.load()
-
+
signers = self.wk.signers('scope')
self.assertTrue(signers[0] == ('scope', 'abcdefg'), self.wk.data['signers'])
self.assertTrue(signers[1][0] == '+', self.wk.data['signers'])
-
+
trusted = self.wk.trusted('epocs')
self.assertTrue(trusted[0] == ('epocs', 'gfedcba'))
self.assertTrue(trusted[1][0] == '+')
-
+
self.wk.untrust('epocs', 'gfedcba')
trusted = self.wk.trusted('epocs')
self.assertTrue(('epocs', 'gfedcba') not in trusted)
-
+
def test_load_save_incomplete(self):
self.wk.data = json.loads(wheel_json)
del self.wk.data['signers']
@@ -90,9 +92,7 @@ class TestWheelKeys(unittest.TestCase):
pass
else:
raise Exception("Expected ValueError")
-
+
del self.wk.data['schema']
self.wk.save()
self.wk.load()
-
-
diff --git a/wheel/test/test_paths.py b/wheel/test/test_paths.py
index a23d506..7aed099 100644
--- a/wheel/test/test_paths.py
+++ b/wheel/test/test_paths.py
@@ -1,6 +1,8 @@
-import wheel.paths
from distutils.command.install import SCHEME_KEYS
+import wheel.paths
+
+
def test_path():
d = wheel.paths.get_install_paths('wheel')
assert len(d) == len(SCHEME_KEYS)
diff --git a/wheel/test/test_ranking.py b/wheel/test/test_ranking.py
index 1632a13..64423f5 100644
--- a/wheel/test/test_ranking.py
+++ b/wheel/test/test_ranking.py
@@ -4,11 +4,13 @@ from wheel.pep425tags import get_supported
from wheel.install import WheelFile
WHEELPAT = "%(name)s-%(ver)s-%(pyver)s-%(abi)s-%(arch)s.whl"
+
+
def make_wheel(name, ver, pyver, abi, arch):
- name = WHEELPAT % dict(name=name, ver=ver, pyver=pyver, abi=abi,
- arch=arch)
+ name = WHEELPAT % dict(name=name, ver=ver, pyver=pyver, abi=abi, arch=arch)
return WheelFile(name)
+
# This relies on the fact that generate_supported will always return the
# exact pyver, abi, and architecture for its first (best) match.
sup = get_supported()
@@ -30,14 +32,15 @@ COMBINATIONS = (
# This will not be compatible for Python x.0. Beware when we hit Python
# 4.0, and don't test with 3.0!!!
('foo', '2.1', majver + '1', 'none', 'any'),
- ('foo', '2.1', pyver , 'none', 'any'),
- ('foo', '2.1', pyver , abi, arch),
+ ('foo', '2.1', pyver, 'none', 'any'),
+ ('foo', '2.1', pyver, abi, arch),
)
-WHEELS = [ make_wheel(*args) for args in COMBINATIONS ]
+WHEELS = [make_wheel(*args) for args in COMBINATIONS]
+
class TestRanking(unittest.TestCase):
def test_comparison(self):
for i in range(len(WHEELS)-1):
for j in range(i):
- self.assertTrue(WHEELS[j]<WHEELS[i])
+ self.assertTrue(WHEELS[j] < WHEELS[i])
diff --git a/wheel/test/test_signatures.py b/wheel/test/test_signatures.py
index 0af19a7..aa0eb23 100644
--- a/wheel/test/test_signatures.py
+++ b/wheel/test/test_signatures.py
@@ -2,46 +2,48 @@ from wheel import signatures
from wheel.signatures import djbec, ed25519py
from wheel.util import binary
+
def test_getlib():
signatures.get_ed25519ll()
+
def test_djbec():
- djbec.dsa_test()
+ djbec.dsa_test()
djbec.dh_test()
-
+
+
def test_ed25519py():
kp0 = ed25519py.crypto_sign_keypair(binary(' '*32))
kp = ed25519py.crypto_sign_keypair()
-
+
signed = ed25519py.crypto_sign(binary('test'), kp.sk)
-
+
ed25519py.crypto_sign_open(signed, kp.vk)
-
+
try:
ed25519py.crypto_sign_open(signed, kp0.vk)
except ValueError:
pass
else:
raise Exception("Expected ValueError")
-
+
try:
ed25519py.crypto_sign_keypair(binary(' '*33))
except ValueError:
pass
else:
raise Exception("Expected ValueError")
-
+
try:
ed25519py.crypto_sign(binary(''), binary(' ')*31)
except ValueError:
pass
else:
raise Exception("Expected ValueError")
-
+
try:
ed25519py.crypto_sign_open(binary(''), binary(' ')*31)
except ValueError:
pass
else:
raise Exception("Expected ValueError")
- \ No newline at end of file
diff --git a/wheel/test/test_tagopt.py b/wheel/test/test_tagopt.py
index b0d083e..03a5f0c 100644
--- a/wheel/test/test_tagopt.py
+++ b/wheel/test/test_tagopt.py
@@ -24,11 +24,13 @@ setup(
EXT_MODULES = "ext_modules=[Extension('_test', sources=['test.c'])],"
+
@pytest.fixture
def temp_pkg(request, ext=False):
- tempdir = tempfile.mkdtemp()
def fin():
shutil.rmtree(tempdir)
+
+ tempdir = tempfile.mkdtemp()
request.addfinalizer(fin)
temppath = py.path.local(tempdir)
temppath.join('test.py').write('print("Hello, world")')
@@ -40,13 +42,14 @@ def temp_pkg(request, ext=False):
temppath.join('setup.py').write(setup_py)
return temppath
+
@pytest.fixture
def temp_ext_pkg(request):
return temp_pkg(request, ext=True)
+
def test_default_tag(temp_pkg):
- subprocess.check_call([sys.executable, 'setup.py', 'bdist_wheel'],
- cwd=str(temp_pkg))
+ subprocess.check_call([sys.executable, 'setup.py', 'bdist_wheel'], cwd=str(temp_pkg))
dist_dir = temp_pkg.join('dist')
assert dist_dir.check(dir=1)
wheels = dist_dir.listdir()
@@ -54,6 +57,7 @@ def test_default_tag(temp_pkg):
assert wheels[0].basename == 'Test-1.0-py%s-none-any.whl' % (sys.version[0],)
assert wheels[0].ext == '.whl'
+
def test_explicit_tag(temp_pkg):
subprocess.check_call(
[sys.executable, 'setup.py', 'bdist_wheel', '--python-tag=py32'],
@@ -65,6 +69,7 @@ def test_explicit_tag(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py32-')
assert wheels[0].ext == '.whl'
+
def test_universal_tag(temp_pkg):
subprocess.check_call(
[sys.executable, 'setup.py', 'bdist_wheel', '--universal'],
@@ -76,6 +81,7 @@ def test_universal_tag(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py2.py3-')
assert wheels[0].ext == '.whl'
+
def test_universal_beats_explicit_tag(temp_pkg):
subprocess.check_call(
[sys.executable, 'setup.py', 'bdist_wheel', '--universal', '--python-tag=py32'],
@@ -87,6 +93,7 @@ def test_universal_beats_explicit_tag(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py2.py3-')
assert wheels[0].ext == '.whl'
+
def test_universal_in_setup_cfg(temp_pkg):
temp_pkg.join('setup.cfg').write('[bdist_wheel]\nuniversal=1')
subprocess.check_call(
@@ -99,6 +106,7 @@ def test_universal_in_setup_cfg(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py2.py3-')
assert wheels[0].ext == '.whl'
+
def test_pythontag_in_setup_cfg(temp_pkg):
temp_pkg.join('setup.cfg').write('[bdist_wheel]\npython_tag=py32')
subprocess.check_call(
@@ -111,6 +119,7 @@ def test_pythontag_in_setup_cfg(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py32-')
assert wheels[0].ext == '.whl'
+
def test_legacy_wheel_section_in_setup_cfg(temp_pkg):
temp_pkg.join('setup.cfg').write('[wheel]\nuniversal=1')
subprocess.check_call(
@@ -123,6 +132,7 @@ def test_legacy_wheel_section_in_setup_cfg(temp_pkg):
assert wheels[0].basename.startswith('Test-1.0-py2.py3-')
assert wheels[0].ext == '.whl'
+
def test_plat_name_purepy(temp_pkg):
subprocess.check_call(
[sys.executable, 'setup.py', 'bdist_wheel', '--plat-name=testplat.pure'],
@@ -134,6 +144,7 @@ def test_plat_name_purepy(temp_pkg):
assert wheels[0].basename.endswith('-testplat_pure.whl')
assert wheels[0].ext == '.whl'
+
def test_plat_name_ext(temp_ext_pkg):
try:
subprocess.check_call(
@@ -148,6 +159,7 @@ def test_plat_name_ext(temp_ext_pkg):
assert wheels[0].basename.endswith('-testplat_arch.whl')
assert wheels[0].ext == '.whl'
+
def test_plat_name_purepy_in_setupcfg(temp_pkg):
temp_pkg.join('setup.cfg').write('[bdist_wheel]\nplat_name=testplat.pure')
subprocess.check_call(
@@ -160,6 +172,7 @@ def test_plat_name_purepy_in_setupcfg(temp_pkg):
assert wheels[0].basename.endswith('-testplat_pure.whl')
assert wheels[0].ext == '.whl'
+
def test_plat_name_ext_in_setupcfg(temp_ext_pkg):
temp_ext_pkg.join('setup.cfg').write('[bdist_wheel]\nplat_name=testplat.arch')
try:
diff --git a/wheel/test/test_tool.py b/wheel/test/test_tool.py
index 1f3b11b..f37c836 100644
--- a/wheel/test/test_tool.py
+++ b/wheel/test/test_tool.py
@@ -1,5 +1,6 @@
from wheel import tool
+
def test_keygen():
def get_keyring():
WheelKeys, keyring = tool.get_keyring()
@@ -13,8 +14,10 @@ def test_keygen():
def get_keyring(cls):
class keyringTest2:
pw = None
+
def set_password(self, a, b, c):
self.pw = c
+
def get_password(self, a, b):
return self.pw
diff --git a/wheel/test/test_wheelfile.py b/wheel/test/test_wheelfile.py
index 181668f..1d559a3 100644
--- a/wheel/test/test_wheelfile.py
+++ b/wheel/test/test_wheelfile.py
@@ -1,17 +1,21 @@
+import codecs
+import hashlib
import os
-import wheel.install
+import shutil
+import tempfile
+import zipfile
+from contextlib import contextmanager
+
+import pytest
+
import wheel.archive
-import hashlib
+import wheel.install
+
try:
from StringIO import StringIO
except ImportError:
from io import BytesIO as StringIO
-import codecs
-import zipfile
-import pytest
-import shutil
-import tempfile
-from contextlib import contextmanager
+
@contextmanager
def environ(key, value):
@@ -25,6 +29,7 @@ def environ(key, value):
else:
os.environ[key] = old_value
+
@contextmanager
def temporary_directory():
# tempfile.TemporaryDirectory doesn't exist in Python 2.
@@ -34,6 +39,7 @@ def temporary_directory():
finally:
shutil.rmtree(tempdir)
+
@contextmanager
def readable_zipfile(path):
# zipfile.ZipFile() isn't a context manager under Python 2.
@@ -47,14 +53,14 @@ def readable_zipfile(path):
def test_verifying_zipfile():
if not hasattr(zipfile.ZipExtFile, '_update_crc'):
pytest.skip('No ZIP verification. Missing ZipExtFile._update_crc.')
-
+
sio = StringIO()
zf = zipfile.ZipFile(sio, 'w')
zf.writestr("one", b"first file")
zf.writestr("two", b"second file")
zf.writestr("three", b"third file")
zf.close()
-
+
# In default mode, VerifyingZipFile checks the hash of any read file
# mentioned with set_expected_hash(). Files not mentioned with
# set_expected_hash() are not checked.
@@ -69,7 +75,7 @@ def test_verifying_zipfile():
pass
else:
raise Exception("expected exception 'BadWheelFile()'")
-
+
# In strict mode, VerifyingZipFile requires every read file to be
# mentioned with set_expected_hash().
vzf.strict = True
@@ -79,31 +85,33 @@ def test_verifying_zipfile():
pass
else:
raise Exception("expected exception 'BadWheelFile()'")
-
+
vzf.set_expected_hash("two", None)
vzf.open("two").read()
-
+
+
def test_pop_zipfile():
sio = StringIO()
zf = wheel.install.VerifyingZipFile(sio, 'w')
zf.writestr("one", b"first file")
zf.writestr("two", b"second file")
zf.close()
-
+
try:
zf.pop()
except RuntimeError:
- pass # already closed
+ pass # already closed
else:
raise Exception("expected RuntimeError")
-
+
zf = wheel.install.VerifyingZipFile(sio, 'a')
zf.pop()
zf.close()
-
+
zf = wheel.install.VerifyingZipFile(sio, 'r')
assert len(zf.infolist()) == 1
+
def test_zipfile_timestamp():
# An environment variable can be used to influence the timestamp on
# TarInfo objects inside the zip. See issue #143. TemporaryDirectory is
@@ -122,6 +130,7 @@ def test_zipfile_timestamp():
for info in zf.infolist():
assert info.date_time[:3] == (1980, 1, 1)
+
def test_zipfile_attributes():
# With the change from ZipFile.write() to .writestr(), we need to manually
# set member attributes.
diff --git a/wheel/tool/__init__.py b/wheel/tool/__init__.py
index 4c0187b..a55752d 100644
--- a/wheel/tool/__init__.py
+++ b/wheel/tool/__init__.py
@@ -2,27 +2,29 @@
Wheel command-line utility.
"""
-import os
+import argparse
import hashlib
-import sys
import json
-
+import os
+import sys
from glob import iglob
+
from .. import signatures
-from ..util import (urlsafe_b64decode, urlsafe_b64encode, native, binary,
- matches_requirement)
from ..install import WheelFile, VerifyingZipFile
from ..paths import get_install_command
+from ..util import urlsafe_b64decode, urlsafe_b64encode, native, binary, matches_requirement
+
def require_pkgresources(name):
try:
- import pkg_resources
+ import pkg_resources # noqa: F401
except ImportError:
raise RuntimeError("'{0}' needs pkg_resources (part of setuptools).".format(name))
-import argparse
-class WheelError(Exception): pass
+class WheelError(Exception):
+ pass
+
# For testability
def get_keyring():
@@ -31,9 +33,12 @@ def get_keyring():
import keyring
assert keyring.get_keyring().priority
except (ImportError, AssertionError):
- raise WheelError("Install wheel[signatures] (requires keyring, keyrings.alt, pyxdg) for signatures.")
+ raise WheelError(
+ "Install wheel[signatures] (requires keyring, keyrings.alt, pyxdg) for signatures.")
+
return keys.WheelKeys, keyring
+
def keygen(get_keyring=get_keyring):
"""Generate a public/private key pair."""
WheelKeys, keyring = get_keyring()
@@ -59,6 +64,7 @@ def keygen(get_keyring=get_keyring):
wk.trust('+', vk)
wk.save()
+
def sign(wheelfile, replace=False, get_keyring=get_keyring):
"""Sign a wheel"""
WheelKeys, keyring = get_keyring()
@@ -78,17 +84,17 @@ def sign(wheelfile, replace=False, get_keyring=get_keyring):
keypair = ed25519ll.Keypair(urlsafe_b64decode(binary(vk)),
urlsafe_b64decode(binary(sk)))
-
record_name = wf.distinfo_name + '/RECORD'
sig_name = wf.distinfo_name + '/RECORD.jws'
if sig_name in wf.zipfile.namelist():
raise WheelError("Wheel is already signed.")
record_data = wf.zipfile.read(record_name)
- payload = {"hash":"sha256=" + native(urlsafe_b64encode(hashlib.sha256(record_data).digest()))}
+ payload = {"hash": "sha256=" + native(urlsafe_b64encode(hashlib.sha256(record_data).digest()))}
sig = signatures.sign(payload, keypair)
wf.zipfile.writestr(sig_name, json.dumps(sig, sort_keys=True))
wf.zipfile.close()
+
def unsign(wheelfile):
"""
Remove RECORD.jws from a wheel by truncating the zip file.
@@ -104,6 +110,7 @@ def unsign(wheelfile):
vzf.pop()
vzf.close()
+
def verify(wheelfile):
"""Verify a wheel.
@@ -119,6 +126,7 @@ def verify(wheelfile):
sys.stdout.write(json.dumps(verified, indent=2))
sys.stdout.write('\n')
+
def unpack(wheelfile, dest='.'):
"""Unpack a wheel.
@@ -135,6 +143,7 @@ def unpack(wheelfile, dest='.'):
wf.zipfile.extractall(destination)
wf.zipfile.close()
+
def install(requirements, requirements_file=None,
wheel_dirs=None, force=False, list_files=False,
dry_run=False):
@@ -155,7 +164,7 @@ def install(requirements, requirements_file=None,
if wheelpath:
wheel_dirs = wheelpath.split(os.pathsep)
else:
- wheel_dirs = [ os.path.curdir ]
+ wheel_dirs = [os.path.curdir]
# Get a list of all valid wheels in wheel_dirs
all_wheels = []
@@ -220,6 +229,7 @@ def install(requirements, requirements_file=None,
wf.install(force=force)
wf.zipfile.close()
+
def install_scripts(distributions):
"""
Regenerate the entry_points console_scripts for the named distribution.
@@ -234,10 +244,11 @@ def install_scripts(distributions):
pkg_resources_dist = pkg_resources.get_distribution(dist)
install = get_install_command(dist)
command = easy_install.easy_install(install.distribution)
- command.args = ['wheel'] # dummy argument
+ command.args = ['wheel'] # dummy argument
command.finalize_options()
command.install_egg_scripts(pkg_resources_dist)
+
def convert(installers, dest_dir, verbose):
require_pkgresources('wheel convert')
@@ -258,6 +269,7 @@ def convert(installers, dest_dir, verbose):
if verbose:
sys.stdout.write("OK\n")
+
def parser():
p = argparse.ArgumentParser()
s = p.add_subparsers(help="commands")
@@ -327,7 +339,7 @@ def parser():
convert_parser = s.add_parser('convert', help='Convert egg or wininst to wheel')
convert_parser.add_argument('installers', nargs='*', help='Installers to convert')
convert_parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
- help="Directory to store wheels (default %(default)s)")
+ help="Directory to store wheels (default %(default)s)")
convert_parser.add_argument('--verbose', '-v', action='store_true')
convert_parser.set_defaults(func=convert_f)
@@ -344,6 +356,7 @@ def parser():
return p
+
def main():
p = parser()
args = p.parse_args()
diff --git a/wheel/util.py b/wheel/util.py
index 20f386f..1878fb2 100644
--- a/wheel/util.py
+++ b/wheel/util.py
@@ -1,15 +1,32 @@
"""Utility functions."""
-import sys
-import os
import base64
-import json
import hashlib
+import json
+import os
+import sys
from collections import OrderedDict
__all__ = ['urlsafe_b64encode', 'urlsafe_b64decode', 'utf8',
'to_json', 'from_json', 'matches_requirement']
+
+# For encoding ascii back and forth between bytestrings, as is repeatedly
+# necessary in JSON-based crypto under Python 3
+if sys.version_info[0] < 3:
+ text_type = unicode # noqa: F821
+
+ def native(s):
+ return s
+else:
+ text_type = str
+
+ def native(s):
+ if isinstance(s, bytes):
+ return s.decode('ascii')
+ return s
+
+
def urlsafe_b64encode(data):
"""urlsafe_b64encode without padding"""
return base64.urlsafe_b64encode(data).rstrip(binary('='))
@@ -22,57 +39,38 @@ def urlsafe_b64decode(data):
def to_json(o):
- '''Convert given data to JSON.'''
+ """Convert given data to JSON."""
return json.dumps(o, sort_keys=True)
def from_json(j):
- '''Decode a JSON payload.'''
+ """Decode a JSON payload."""
return json.loads(j)
+
def open_for_csv(name, mode):
if sys.version_info[0] < 3:
nl = {}
bin = 'b'
else:
- nl = { 'newline': '' }
+ nl = {'newline': ''}
bin = ''
+
return open(name, mode + bin, **nl)
-try:
- unicode
-
- def utf8(data):
- '''Utf-8 encode data.'''
- if isinstance(data, unicode):
- return data.encode('utf-8')
- return data
-except NameError:
- def utf8(data):
- '''Utf-8 encode data.'''
- if isinstance(data, str):
- return data.encode('utf-8')
- return data
-
-
-try:
- # For encoding ascii back and forth between bytestrings, as is repeatedly
- # necessary in JSON-based crypto under Python 3
- unicode
- def native(s):
- return s
- def binary(s):
- if isinstance(s, unicode):
- return s.encode('ascii')
- return s
-except NameError:
- def native(s):
- if isinstance(s, bytes):
- return s.decode('ascii')
- return s
- def binary(s):
- if isinstance(s, str):
- return s.encode('ascii')
+
+def utf8(data):
+ """Utf-8 encode data."""
+ if isinstance(data, text_type):
+ return data.encode('utf-8')
+ return data
+
+
+def binary(s):
+ if isinstance(s, text_type):
+ return s.encode('ascii')
+ return s
+
class HashingFile(object):
def __init__(self, fd, hashtype='sha256'):
@@ -80,18 +78,22 @@ class HashingFile(object):
self.hashtype = hashtype
self.hash = hashlib.new(hashtype)
self.length = 0
+
def write(self, data):
self.hash.update(data)
self.length += len(data)
self.fd.write(data)
+
def close(self):
self.fd.close()
+
def digest(self):
if self.hashtype == 'md5':
return self.hash.hexdigest()
digest = self.hash.digest()
return self.hashtype + '=' + native(urlsafe_b64encode(digest))
+
class OrderedDefaultDict(OrderedDict):
def __init__(self, *args, **kwargs):
if not args:
@@ -103,18 +105,19 @@ class OrderedDefaultDict(OrderedDict):
args = args[1:]
super(OrderedDefaultDict, self).__init__(*args, **kwargs)
- def __missing__ (self, key):
+ def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
self[key] = default = self.default_factory()
return default
+
if sys.platform == 'win32':
import ctypes.wintypes
# CSIDL_APPDATA for reference - not used here for compatibility with
# dirspec, which uses LOCAL_APPDATA and COMMON_APPDATA in that order
- csidl = dict(CSIDL_APPDATA=26, CSIDL_LOCAL_APPDATA=28,
- CSIDL_COMMON_APPDATA=35)
+ csidl = dict(CSIDL_APPDATA=26, CSIDL_LOCAL_APPDATA=28, CSIDL_COMMON_APPDATA=35)
+
def get_path(name):
SHGFP_TYPE_CURRENT = 0
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
@@ -127,6 +130,7 @@ if sys.platform == 'win32':
if not os.path.isdir(path):
os.makedirs(path)
return path
+
def load_config_paths(*resource):
ids = ["CSIDL_LOCAL_APPDATA", "CSIDL_COMMON_APPDATA"]
for id in ids:
@@ -138,10 +142,12 @@ else:
def save_config_path(*resource):
import xdg.BaseDirectory
return xdg.BaseDirectory.save_config_path(*resource)
+
def load_config_paths(*resource):
import xdg.BaseDirectory
return xdg.BaseDirectory.load_config_paths(*resource)
+
def matches_requirement(req, wheels):
"""List of wheels matching a requirement.
diff --git a/wheel/wininst2wheel.py b/wheel/wininst2wheel.py
index 15f0cdf..b8a3469 100755
--- a/wheel/wininst2wheel.py
+++ b/wheel/wininst2wheel.py
@@ -1,23 +1,24 @@
#!/usr/bin/env python
+import distutils.dist
import os.path
import re
import sys
import tempfile
import zipfile
-import wheel.bdist_wheel
-import distutils.dist
-from distutils.archive_util import make_archive
-from shutil import rmtree
-from wheel.archive import archive_wheelfile
from argparse import ArgumentParser
from glob import iglob
+from shutil import rmtree
+
+import wheel.bdist_wheel
+from wheel.archive import archive_wheelfile
egg_info_re = re.compile(r'''(^|/)(?P<name>[^/]+?)-(?P<ver>.+?)
(-(?P<pyver>.+?))?(-(?P<arch>.+?))?.egg-info(/|$)''', re.VERBOSE)
+
def parse_info(wininfo_name, egginfo_name):
"""Extract metadata from filenames.
-
+
Extracts the 4 metadataitems needed (name, version, pyversion, arch) from
the installer filename and the name of the egg-info directory embedded in
the zipfile (if any).
@@ -52,15 +53,14 @@ def parse_info(wininfo_name, egginfo_name):
if egginfo_name:
egginfo = egg_info_re.search(egginfo_name)
if not egginfo:
- raise ValueError("Egg info filename %s is not valid" %
- (egginfo_name,))
+ raise ValueError("Egg info filename %s is not valid" % (egginfo_name,))
# Parse the wininst filename
# 1. Distribution name (up to the first '-')
w_name, sep, rest = wininfo_name.partition('-')
if not sep:
- raise ValueError("Installer filename %s is not valid" %
- (wininfo_name,))
+ raise ValueError("Installer filename %s is not valid" % (wininfo_name,))
+
# Strip '.exe'
rest = rest[:-4]
# 2. Python version (from the last '-', must start with 'py')
@@ -78,8 +78,7 @@ def parse_info(wininfo_name, egginfo_name):
# 3. Version and architecture
w_ver, sep, w_arch = rest.rpartition('.')
if not sep:
- raise ValueError("Installer filename %s is not valid" %
- (wininfo_name,))
+ raise ValueError("Installer filename %s is not valid" % (wininfo_name,))
if egginfo:
w_name = egginfo.group('name')
@@ -87,6 +86,7 @@ def parse_info(wininfo_name, egginfo_name):
return dict(name=w_name, ver=w_ver, arch=w_arch, pyver=w_pyver)
+
def bdist_wininst2wheel(path, dest_dir=os.path.curdir):
bdw = zipfile.ZipFile(path)
@@ -176,7 +176,7 @@ def bdist_wininst2wheel(path, dest_dir=os.path.curdir):
bw.egg2dist(os.path.join(dir, egginfo_name), dist_info_dir)
bw.write_wheelfile(dist_info_dir, generator='wininst2wheel')
bw.write_record(dir, dist_info_dir)
-
+
archive_wheelfile(os.path.join(dest_dir, wheel_name), dir)
rmtree(dir)
@@ -201,7 +201,7 @@ def main():
parser = ArgumentParser()
parser.add_argument('installers', nargs='*', help="Installers to convert")
parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
- help="Directory to store wheels (default %(default)s)")
+ help="Directory to store wheels (default %(default)s)")
parser.add_argument('--verbose', '-v', action='store_true')
args = parser.parse_args()
for pat in args.installers:
@@ -212,5 +212,6 @@ def main():
if args.verbose:
sys.stdout.write("OK\n")
+
if __name__ == "__main__":
main()