Skip to content

Commit 2ffb9b8

Browse files
committed
More documentation of download / upload procedure
1 parent 61db547 commit 2ffb9b8

File tree

4 files changed

+111
-49
lines changed

4 files changed

+111
-49
lines changed

README.rst

+12-48
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ The wheel-building repository:
2525
(Manylinux1_). ``delocate`` and ``auditwheel`` copy the required dynamic
2626
libraries into the wheel and relinks the extension modules against the
2727
copied libraries;
28-
* uploads the built wheels to http://wheels.scipy.org (a Rackspace container
29-
kindly donated by Rackspace to scikit-learn).
28+
* uploads the built wheels to http://anaconda.org/nipy/nipy
3029

3130
The resulting wheels are therefore self-contained and do not need any external
3231
dynamic libraries apart from those provided as standard by OSX / Linux as
3332
defined by the manylinux1 standard.
3433

3534
The ``.travis.yml`` file in this repository has a line containing the API key
36-
for the Rackspace container encrypted with an RSA key that is unique to the
37-
repository - see http://docs.travis-ci.com/user/encryption-keys. This
35+
for the Anaconda.org organization encrypted with an RSA key that is unique to
36+
the repository - see http://docs.travis-ci.com/user/encryption-keys. This
3837
encrypted key gives the travis build permission to upload to the Rackspace
3938
directory pointed to by http://wheels.scipy.org.
4039

@@ -70,67 +69,32 @@ hash.
7069
Uploading the built wheels to pypi
7170
==================================
7271

73-
Be careful, http://wheels.scipy.org points to a container on a distributed
74-
content delivery network. It can take up to 15 minutes for the new wheel file
75-
to get updated into the container at http://wheels.scipy.org.
76-
77-
The same contents appear at
78-
https://3f23b170c54c2533c070-1c8a9b3114517dc5fe17b7c3f8c63a43.ssl.cf2.rackcdn.com;
79-
you might prefer this address because it is https.
80-
8172
When the wheels are updated, you can download them to your machine manually,
82-
and then upload them manually to pypi, or by using twine_. You can also use a
83-
script for doing this, housed at :
84-
https://github.com/MacPython/terryfy/blob/master/wheel-uploader
73+
and then upload them manually to pypi, or by using twine_.
8574

86-
For the ``wheel-uploader`` script, you'll need twine and `beautiful soup 4
87-
<bs4>`_.
75+
To download, use something like::
8876

89-
You will typically have a directory on your machine where you store wheels,
90-
called a `wheelhouse`. The typical call for `wheel-uploader` would then
91-
be something like::
77+
python tools/download-wheels.py 0.5.0 --staging-url=https://anaconda.org/nipy/nipy --prefix=nipy -w wheelhouse
9278

93-
VERSION=0.4.0
94-
CDN_URL=https://3f23b170c54c2533c070-1c8a9b3114517dc5fe17b7c3f8c63a43.ssl.cf2.rackcdn.com
95-
wheel-uploader -r warehouse -u $CDN_URL -s -v -w ~/wheelhouse -t macosx nipy $VERSION
96-
wheel-uploader -r warehouse -u $CDN_URL -s -v -w ~/wheelhouse -t manylinux1 nipy $VERSION
97-
wheel-uploader -r warehouse -u $CDN_URL -s -v -w ~/wheelhouse -t win nipy $VERSION
79+
where `0.5.0` is the release version.
9880

99-
where:
81+
You may want to add the `sdist` to the `wheelhouse`.
10082

101-
* ``-r warehouse`` uses the upcoming Warehouse PyPI server (it is more
102-
reliable than the current PyPI service for uploads);
103-
* ``-u`` gives the URL from which to fetch the wheels, here the https address,
104-
for some extra security;
105-
* ``-s`` causes twine to sign the wheels with your GPG key;
106-
* ``-v`` means give verbose messages;
107-
* ``-w ~/wheelhouse`` means download the wheels from to the local directory
108-
``~/wheelhouse``.
83+
Then::
10984

110-
``nipy`` is the root name of the wheel(s) to download / upload, and ``0.4.0``
111-
is the version to download / upload.
85+
twine upload --sign wheelhouse/*
11286

113-
In order to use the Warehouse PyPI server, you will need something like this
114-
in your ``~/.pypirc`` file::
87+
In order to use Twine, you will need something like this in your ``~/.pypirc``
88+
file::
11589

11690
[distutils]
11791
index-servers =
11892
pypi
119-
warehouse
12093

12194
[pypi]
12295
username:your_user_name
12396
password:your_password
12497

125-
[warehouse]
126-
repository: https://upload.pypi.io/legacy/
127-
username: your_user_name
128-
password: your_password
129-
130-
So, in this case, ``wheel-uploader`` will download all wheels starting with
131-
``nipy-0.4.0-`` from http://wheels.scipy.org to ``~/wheelhouse``, then upload
132-
them to PyPI.
133-
13498
Of course, you will need permissions to upload to PyPI, for this to work.
13599

136100
.. _manylinux1: https://www.python.org/dev/peps/pep-0513

tools/download-wheels.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Download wheels from Anaconda staging area.
4+
"""
5+
6+
import os
7+
import re
8+
import shutil
9+
import argparse
10+
11+
import urllib3
12+
from bs4 import BeautifulSoup
13+
14+
__version__ = '0.2'
15+
16+
17+
def get_wheel_names(version, staging_url, prefix):
18+
""" Get wheel names from Anaconda HTML directory.
19+
20+
This looks in the Anaconda multibuild-wheels-staging page and
21+
parses the HTML to get all the wheel names for a release version.
22+
23+
Parameters
24+
----------
25+
version : str
26+
The release version. For instance, "1.5.0".
27+
staging_url : str
28+
URL at which to find packages
29+
prefix : str
30+
Prefix for wheels to download.
31+
"""
32+
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED')
33+
tmpl = re.compile(rf"^.*{prefix}-{version}-.*\.whl$")
34+
index_url = f"{staging_url}/files"
35+
index_html = http.request('GET', index_url)
36+
soup = BeautifulSoup(index_html.data, 'html.parser')
37+
return soup.findAll(text=tmpl)
38+
39+
40+
def download_wheels(version, wheelhouse, staging_url, prefix):
41+
"""Download release wheels.
42+
43+
The release wheels for the given package version are downloaded
44+
into the given directory.
45+
46+
Parameters
47+
----------
48+
version : str
49+
The release version. For instance, "1.5.0".
50+
wheelhouse : str
51+
Directory in which to download the wheels.
52+
staging_url : str
53+
URL at which to find packages
54+
prefix : str
55+
Prefix for wheels to download.
56+
"""
57+
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED')
58+
wheel_names = get_wheel_names(version, staging_url, prefix)
59+
60+
for i, wheel_name in enumerate(wheel_names):
61+
wheel_url = f"{staging_url}/{version}/download/{wheel_name}"
62+
wheel_path = os.path.join(wheelhouse, wheel_name)
63+
with open(wheel_path, 'wb') as f:
64+
with http.request('GET', wheel_url, preload_content=False,) as r:
65+
print(f"{i + 1:<4}{wheel_name}")
66+
shutil.copyfileobj(r, f)
67+
print(f"\nTotal files downloaded: {len(wheel_names)}")
68+
69+
70+
if __name__ == '__main__':
71+
parser = argparse.ArgumentParser()
72+
parser.add_argument(
73+
"version",
74+
help="Package version to download.")
75+
parser.add_argument(
76+
"--staging-url",
77+
default='https://anaconda.org/multibuild-wheels-staging/scipy',
78+
help="URL at which to find packages")
79+
parser.add_argument(
80+
"--prefix",
81+
default='scipy',
82+
help="Prefix for wheels (e.g 'scipy'")
83+
parser.add_argument(
84+
"-w", "--wheelhouse",
85+
default=os.path.join(os.getcwd(), "release", "installers"),
86+
help="Directory in which to store downloaded wheels\n"
87+
"[defaults to <cwd>/release/installers]")
88+
89+
args = parser.parse_args()
90+
91+
wheelhouse = os.path.expanduser(args.wheelhouse)
92+
if not os.path.isdir(wheelhouse):
93+
raise RuntimeError(
94+
f"{wheelhouse} wheelhouse directory is not present."
95+
" Perhaps you need to use the '-w' flag to specify one.")
96+
97+
download_wheels(args.version, wheelhouse, args.staging_url, args.prefix)

wheelhouse/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*

0 commit comments

Comments
 (0)