Skip to content

Commit

Permalink
Convert to generic platform wheel. See #71
Browse files Browse the repository at this point in the history
Update CI configuration to only build one wheel for each Python
version.
  • Loading branch information
jcfr committed May 26, 2019
1 parent bcd451e commit 27b9903
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 102 deletions.
48 changes: 0 additions & 48 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,30 +44,14 @@ references:
jobs:

# x64
manylinux-x64_cp27-cp27m:
<<: *x64_build_job
manylinux-x64_cp27-cp27mu:
<<: *x64_build_job
manylinux-x64_cp34-cp34m:
<<: *x64_build_job
manylinux-x64_cp35-cp35m:
<<: *x64_build_job
manylinux-x64_cp36-cp36m:
<<: *x64_build_job
manylinux-x64_cp37-cp37m_upload-sdist:
<<: *x64_build_job

# x86
# manylinux-x86_cp27-cp27m:
# <<: *x86_build_job
# manylinux-x86_cp27-cp27mu:
# <<: *x86_build_job
# manylinux-x86_cp34-cp34m:
# <<: *x86_build_job
# manylinux-x86_cp35-cp35m:
# <<: *x86_build_job
# manylinux-x86_cp36-cp36m:
# <<: *x86_build_job
# manylinux-x86_cp37-cp37m:
# <<: *x86_build_job

Expand Down Expand Up @@ -103,66 +87,34 @@ workflows:
build-test-deploy:
jobs:
# x64
- manylinux-x64_cp27-cp27m:
<<: *no_filters
- manylinux-x64_cp27-cp27mu:
<<: *no_filters
- manylinux-x64_cp34-cp34m:
<<: *no_filters
- manylinux-x64_cp35-cp35m:
<<: *no_filters
- manylinux-x64_cp36-cp36m:
<<: *no_filters
- manylinux-x64_cp37-cp37m_upload-sdist:
<<: *no_filters
# x86
# - manylinux-x86_cp27-cp27m:
# <<: *no_filters
# - manylinux-x86_cp27-cp27mu:
# <<: *no_filters
# - manylinux-x86_cp34-cp34m:
# <<: *no_filters
# - manylinux-x86_cp35-cp35m:
# <<: *no_filters
# - manylinux-x86_cp36-cp36m:
# <<: *no_filters
# - manylinux-x86_cp37-cp37m:
# <<: *no_filters

- deploy-master:
requires:
# x64
- manylinux-x64_cp27-cp27m
- manylinux-x64_cp27-cp27mu
- manylinux-x64_cp34-cp34m
- manylinux-x64_cp35-cp35m
- manylinux-x64_cp36-cp36m
- manylinux-x64_cp37-cp37m_upload-sdist
# x86
# - manylinux-x86_cp27-cp27m
# - manylinux-x86_cp27-cp27mu
# - manylinux-x86_cp34-cp34m
# - manylinux-x86_cp35-cp35m
# - manylinux-x86_cp36-cp36m
# - manylinux-x86_cp37-cp37m
filters:
branches:
only: master
- deploy-release:
requires:
# x64
- manylinux-x64_cp27-cp27m
- manylinux-x64_cp27-cp27mu
- manylinux-x64_cp34-cp34m
- manylinux-x64_cp35-cp35m
- manylinux-x64_cp36-cp36m
- manylinux-x64_cp37-cp37m_upload-sdist
# x86
# - manylinux-x86_cp27-cp27m
# - manylinux-x86_cp27-cp27mu
# - manylinux-x86_cp34-cp34m
# - manylinux-x86_cp35-cp35m
# - manylinux-x86_cp36-cp36m
# - manylinux-x86_cp37-cp37m
filters:
tags:
Expand Down
18 changes: 0 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@ matrix:
env:
- PYTHON_VERSION=3.7.2

- os: osx
language: generic
env:
- PYTHON_VERSION=3.6.8

- os: osx
language: generic
env:
- PYTHON_VERSION=3.5.6

- os: osx
language: generic
env:
- PYTHON_VERSION=3.4.9

- os: osx
language: generic
env:
Expand All @@ -36,9 +21,6 @@ matrix:
cache:
directories:
- $HOME/.pyenv/versions/3.7.2
- $HOME/.pyenv/versions/3.6.8
- $HOME/.pyenv/versions/3.5.6
- $HOME/.pyenv/versions/3.4.9
- $HOME/.pyenv/versions/2.7.15
- $HOME/downloads

Expand Down
36 changes: 0 additions & 36 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,6 @@ environment:
PYTHON_ARCH: "64"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
PYTHON_DIR: "C:\\Python34"
PYTHON_VERSION: "3.4.x"
PYTHON_ARCH: "32"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
PYTHON_DIR: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x"
PYTHON_ARCH: "64"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
PYTHON_DIR: "C:\\Python35"
PYTHON_VERSION: "3.5.x"
PYTHON_ARCH: "32"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
PYTHON_DIR: "C:\\Python35-x64"
PYTHON_VERSION: "3.5.x"
PYTHON_ARCH: "64"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
PYTHON_DIR: "C:\\Python36"
PYTHON_VERSION: "3.6.x"
PYTHON_ARCH: "32"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
PYTHON_DIR: "C:\\Python36-x64"
PYTHON_VERSION: "3.6.x"
PYTHON_ARCH: "64"
BLOCK: "0"

- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
PYTHON_DIR: "C:\\Python37"
PYTHON_VERSION: "3.7.x"
Expand Down
8 changes: 8 additions & 0 deletions scikit-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ build:
test:
commands:
# Convert to generic platform wheel
- python: |
import glob, sys
sys.path.insert(0, "./scripts")
from convert_to_generic_platform_wheel import convert_to_generic_platform_wheel
wheels = glob.glob("dist/*.whl")
for wheel in wheels:
convert_to_generic_platform_wheel(wheel, remove_original=True)
- python setup.py test

after_test:
Expand Down
171 changes: 171 additions & 0 deletions scripts/convert_to_generic_platform_wheel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@

import argparse
import logging
import os
import sys

from itertools import product
from os.path import (abspath, basename, dirname, isfile, join as pjoin, splitext)

from auditwheel.tools import unique_by_index
from auditwheel.wheeltools import _dist_info_dir, InWheelCtx
from wheel.pkginfo import read_pkg_info, write_pkg_info
from wheel.install import WHEEL_INFO_RE

logger = logging.getLogger(splitext(basename(__file__))[0])


def _to_generic_pyver(pyver_tags):
"""Convert from CPython implementation to generic python version tags
Convert each CPython version tag to the equivalent generic tag.
For example::
cp35 -> py3
cp27 -> py2
See https://www.python.org/dev/peps/pep-0425/#python-tag
"""
return ['py%s' % tag[2] if tag.startswith('cp') else tag for tag in pyver_tags]


def _convert_to_generic_platform_wheel(wheel_ctx):
"""Switch to generic python tags and remove ABI tags from a wheel
Convert implementation specific python tags to their generic equivalent and
remove all ABI tags from wheel_ctx's filename and ``WHEEL`` file.
Parameters
----------
wheel_ctx : InWheelCtx
An open wheel context
"""

abi_tags = ['none']

info_fname = pjoin(_dist_info_dir(wheel_ctx.path), 'WHEEL')
info = read_pkg_info(info_fname)

# Check what tags we have
if wheel_ctx.out_wheel is not None:
out_dir = dirname(wheel_ctx.out_wheel)
wheel_fname = basename(wheel_ctx.out_wheel)
else:
out_dir = '.'
wheel_fname = basename(wheel_ctx.in_wheel)

# Update wheel filename
parsed_fname = WHEEL_INFO_RE(wheel_fname)
fparts = parsed_fname.groupdict()
original_platform_tags = fparts['plat'].split('.')

original_abi_tags = fparts['abi'].split('.')
logger.debug('Previous ABI tags: %s', ', '.join(original_abi_tags))
if abi_tags != original_abi_tags:
logger.debug('New ABI tags ....: %s', ', '.join(abi_tags))
fparts['abi'] = '.'.join(abi_tags)
else:
logger.debug('No ABI tags change needed.')

original_pyver_tags = fparts['pyver'].split('.')
logger.debug('Previous pyver tags: %s', ', '.join(original_pyver_tags))
pyver_tags = _to_generic_pyver(original_pyver_tags)
if pyver_tags != original_pyver_tags:
logger.debug('New pyver tags ....: %s', ', '.join(pyver_tags))
fparts['pyver'] = '.'.join(pyver_tags)
else:
logger.debug('No pyver change needed.')

_, ext = splitext(wheel_fname)
fparts['ext'] = ext
out_wheel_fname = "{namever}-{pyver}-{abi}-{plat}{ext}".format(**fparts)

logger.info('Previous filename: %s', wheel_fname)
if out_wheel_fname != wheel_fname:
logger.info('New filename ....: %s', out_wheel_fname)
else:
logger.info('No filename change needed.')

out_wheel = pjoin(out_dir, out_wheel_fname)

# Update wheel tags
in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
logger.info('Previous WHEEL info tags: %s', ', '.join(in_info_tags))

# Python version, C-API version combinations
pyc_apis = []
for tag in in_info_tags:
py_ver = '.'.join(_to_generic_pyver(tag.split('-')[0].split('.')))
abi = 'none'
pyc_apis.append('-'.join([py_ver, abi]))
# unique Python version, C-API version combinations
pyc_apis = unique_by_index(pyc_apis)

# Set tags for each Python version, C-API combination
updated_tags = ['-'.join(tup) for tup in product(pyc_apis, original_platform_tags)]

if updated_tags != in_info_tags:
del info['Tag']
for tag in updated_tags:
info.add_header('Tag', tag)

logger.info('New WHEEL info tags ....: %s', ', '.join(info.get_all('Tag')))
write_pkg_info(info_fname, info)
else:
logger.info('No WHEEL info change needed.')
return out_wheel


def convert_to_generic_platform_wheel(wheel_path, out_dir='./dist/', remove_original=False, verbose=0):
logging.disable(logging.NOTSET)
if verbose >= 1:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)

wheel_fname = basename(wheel_path)
out_dir = abspath(out_dir)

with InWheelCtx(wheel_path) as ctx:
ctx.out_wheel = pjoin(out_dir, wheel_fname)
ctx.out_wheel = _convert_to_generic_platform_wheel(ctx)

if remove_original:
logger.info('Removed original wheel %s' % wheel_path)
os.remove(wheel_path)


def main():
p = argparse.ArgumentParser(description='Convert wheel to be independent of python implementation and ABI')
p.set_defaults(prog=basename(sys.argv[0]))
p.add_argument("-v",
"--verbose",
action='count',
dest='verbose',
default=0,
help='Give more output. Option is additive')

p.add_argument('WHEEL_FILE', help='Path to wheel file.')
p.add_argument('-w',
'--wheel-dir',
dest='WHEEL_DIR',
type=abspath,
help='Directory to store updated wheels (default: "dist/")',
default='dist/')
p.add_argument("-r",
"--remove-original",
dest='remove_original',
action='store_true',
help='Remove original wheel')

args = p.parse_args()

if not isfile(args.WHEEL_FILE):
p.error('cannot access %s. No such file' % args.WHEEL_FILE)

convert_to_generic_platform_wheel(args.WHEEL_FILE, args.WHEEL_DIR, args.remove_original, args.verbose)


if __name__ == '__main__':
main()

0 comments on commit 27b9903

Please sign in to comment.