Skip to content

Uploading Wheels (pip)

bbartley edited this page Jul 7, 2019 · 56 revisions

Before generating and uploading wheels, read this information carefully

Versioning in PyPI is very strict. You need to follow a specific guideline when bumping the version number.

There is absolutely NO do-overs. Once you upload a version, that namespace is occupied forever. Therefore, we will follow post-release version scheme for minor bug fixes. When you wish to upload a new version without changes in version number, add .post<post-release-version-number> at the end. It is not at all unusual to upload several posts for a given release in this manner. Just increment the post number in the setup.py script.

pySBOL supports Microsoft Windows, Apple Mac OS X, and various Linux distros. Check each section for detailed instructions.

Windows

Mac OS X

Linux

Windows

Example building 32-bit Python 3.6 library on Windows with VS2017:

cmake -DSBOL_BUILD_PYTHON3=TRUE -G"Visual Studio 15 2017" -DSWIG_EXECUTABLE="/swigwin-3.0.12/swig.exe" -DPYTHON_LIBRARY="C:\Program Files (x86)\Python36-32\libs\python36.lib" -DSBOL_BUILD_SHARED=FALSE

Common mistakes are specifying a dynamically linked library (libpython.a) when static build (python36.lib) should be specified. Also make sure the build config is set to Release not Debug in Visual Studio's toolbar.

Example building 64-bit Python 3.6 library on Windows with VS2017. Note this requires specifying the 64-bit CMake generator and the SBOL_BUILD_64 tag:

cmake -DSBOL_BUILD_PYTHON3=TRUE -G"Visual Studio 15 2017 Win64" -DSWIG_EXECUTABLE="/swigwin-3.0.12/swig.exe" -DPYTHON_LIBRARY="C:\Program Files\Python36\libs\python36.lib" -DSBOL_BUILD_64=TRUE -DSBOL_BUILD_SHARED=FALSE

The 32-bit Python 2.7 library:

cmake -DSBOL_BUILD_PYTHON2=TRUE -G"Visual Studio 15 2017" -DSWIG_EXECUTABLE="/swigwin-3.0.12/swig.exe" -DPYTHON_LIBRARY="C:\Python27\libs\python27.lib"  -DSBOL_BUILD_SHARED=FALSE

The 64-bit Python 2.7 library:

PS C:\Users\Bryan Bartley\Dev\libSBOL> cmake -DSBOL_BUILD_PYTHON2=TRUE -G"Visual Studio 15 2017 Win64" -DSWIG_EXECUTABLE="/swigwin-3.0.12/swig.exe" -DPYTHON_LIBRARY="C:\Python27amd64\libs\python27.lib"  -DSBOL_BUILD_SHARED=FALSE -DSBOL_BUILD_64=TRUE

To generate wheels and upload it to PyPI, you need Python, twine, and PyPI account with the right authentication. Make sure that the version number in setup.py is correct. For different versions of Python, it is recommended to use miniconda distributions, as linking the command console with different Python executables can become messy.

To build a Python wheel run:

python setup.py bdist_wheel --python-tag=cp27 --plat-name=win_amd64

in command console. Above line generates a Python wheel for 64-bit Python 2.7. Change flags if you want to generate wheels for different Python versions (cp35, cp36, etc.) or different architecture (win32). Once finished, a wheel will be generated under dist folder within sub-folder (Win_64_2, etc.) with name such as:

pySBOL-2.3.0.post1-cp27-none-win_amd64.whl

Make sure to rename ABI tag 'none' to 'cp27m' (or 'cp35m', 'cp36m', etc.), e.g.:

pySBOL-2.3.0.post1-cp27-cp27m-win_amd64.whl

To upload the wheels to PyPI, run:

twine upload <file-location> -u <username> -p <password>

It is also possible to configure a .pypirc file so that you don't have to type in your username and password every time when you upload. See this page for more info.

Mac OS X

The process for building PyPI distributions on Mac parallels the process for Windows. The following command lines are useful:

python setup.py bdist_wheel --python-tag=cp27 --plat-name=macosx_10_11_x86_64
python3 setup.py bdist_wheel --python-tag=cp36 --plat-name=macosx_10_11_x86_64
python3 setup.py bdist_wheel --python-tag=cp35 --plat-name=macosx_10_11_x86_64

The wheel will be put in the dist directory. If one of the fields in the wheel directory is "none", change to cp27m (replace 27 with whatever Python version you used).

In order to build wheels for Python 3, it's necessary to configure some environment variables. For Python 3.6:

export PATH=/Library/Frameworks/Python.framework/Versions/3.6/bin:$PATH
export PYTHONPATH=/usr/local/lib/python3.6/site-packages:/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages:$PATH

For Python 3.5, I used my Anaconda interpreter:

export PYTHONPATH=$HOME/Users/bryan/anaconda/lib/python3.5/site-packages/:$PYTHONPATH
export PATH=$HOME/anaconda/bin:$PATH

To upload the package, switch back to a Python 2 interpreter and use twine : twine upload pySBOL2-2.1.0-cp27-cp27m-macosx_10_11_x86_64.whl

Linux

Because there are numerous different Linux distros out there, generating wheels can be quite strenuous. Thus, we utilize manylinux to generate a manylinux-compatible wheel that will work on most of the modern Linux distros. To generate pySBOL wheels for Linux using manylinux container, you will need Docker. That means technically you don't need a Linux machine!

In order for maximum compatibility, current manylinux container is based on ancient CentOS 5. This means we will have to do a lot of tinkering to make this work! Following the commend line below step-by-step will lead you to a functional pySBOL manylinux wheel. Before generating wheels, make sure that the version number in setup.py is correct.

Running manylinux container

After installing Docker, run following lines in your terminal/command console. You will end up in manylinux container.

docker pull quay.io/pypa/manylinux1_x86_64

This will take 64 bit version of container. We will only support 64-bit architecture in Linux because nobody use 32-bit Python in Linux in 2018.

docker run -it quay.io/pypa/manylinux1_x86_64 bash

Now you will be inside the container.

Installing dependencies

Following command will install some of the necessary dependencies.

yum install git libxslt-devel pcre-devel

Building CURL

You need to rebuild CURL with PIC support.

curl --tlsv1.2 -L https://github.com/curl/curl/releases/download/curl-7_57_0/curl-7.57.0.tar.bz2 > curl-7.57.0.tar.bz2

tar xvjf curl-7.57.0.tar.bz2

cd curl-7.57.0

./configure --prefix=/curl-7.57.0/install --with-pic

make

make install

Building jsonCpp

cd ..

curl --tlsv1.2 -L https://github.com/open-source-parsers/jsoncpp/archive/1.7.7.tar.gz > jsoncpp-1.7.7.tar.gz

tar -xzf jsoncpp-1.7.7.tar.gz

cd jsoncpp-1.7.7

cmake28 . -Bbuild -DCMAKE_CXX_FLAGS=-fPIC -DCMAKE_C_FLAGS=-fPIC

cd build

make

make install

Building Raptor

cd ../..

curl --tlsv1.2 -L http://download.librdf.org/source/raptor2-2.0.15.tar.gz > raptor2-2.0.15.tar.gz

tar -xzf raptor2-2.0.15.tar.gz

cd raptor2-2.0.15

./configure --prefix=/usr/local --with-curl-config=/curl-7.57.0/curl-config --with-pic

make

make install

Building SWIG

You also need to build SWIG because the version that comes with CentOS 5 is very old.

cd ../..

curl --tlsv1.2 -L https://downloads.sourceforge.net/swig/swig-3.0.12.tar.gz > swig-3.0.12.tar.gz

tar -xzf swig-3.0.12.tar.gz

cd swig-3.0.12

./configure --prefix=/swig-3.0.12/swig_install

make

make install

Building pySBOL

cd ..

git clone https://github.com/SynBioDex/libSBOL.git

cd libSBOL

git submodule update --init --recursive

Use different Python distributions to generate wheels for various Python versions.

  • Python 2.7

cmake28 . -Bbuild_27m -DCMAKE_INSTALL_PREFIX=/libSBOL/install_27m -DSBOL_BUILD_SHARED=FALSE -DSBOL_BUILD_PYTHON2=TRUE -DPYTHON_LIBRARY=/opt/python/cp27-cp27m/bin/python2.7 -DPYTHON_INCLUDE_DIR=/opt/python/cp27-cp27m/include/python2.7 -DSWIG_EXECUTABLE=/swig-3.0.12/swig_install/bin/swig -DCURL_LIBRARY=/curl-7.57.0/install/lib/libcurl.a -DCURL_INCLUDE_DIR=/curl-7.57.0/install/include -DCMAKE_CXX_FLAGS=-fPIC -DCMAKE_C_FLAGS=-fPIC

  • Python 2.7 wide unicode

cmake28 . -Bbuild_27mu -DCMAKE_INSTALL_PREFIX=/libSBOL/install_27mu -DSBOL_BUILD_SHARED=FALSE -DSBOL_BUILD_PYTHON2=TRUE -DPYTHON_LIBRARY=/opt/python/cp27-cp27mu/bin/python2.7 -DPYTHON_INCLUDE_DIR=/opt/python/cp27-cp27mu/include/python2.7 -DSWIG_EXECUTABLE=/swig-3.0.12/swig_install/bin/swig -DCURL_LIBRARY=/curl-7.57.0/install/lib/libcurl.a -DCURL_INCLUDE_DIR=/curl-7.57.0/install/include -DCMAKE_CXX_FLAGS=-fPIC -DCMAKE_C_FLAGS=-fPIC

  • Python 3.6

cmake28 . -Bbuild_36 -DCMAKE_INSTALL_PREFIX=/libSBOL/install_36m -DSBOL_BUILD_SHARED=FALSE -DSBOL_BUILD_PYTHON3=TRUE -DPYTHON_LIBRARY=/opt/python/cp36-cp36m/bin/python3.6 -DPYTHON_INCLUDE_DIR=/opt/python/cp36-cp36m/include/python3.6 -DSWIG_EXECUTABLE=/swig-3.0.12/swig_install/bin/swig -DCURL_LIBRARY=/curl-7.57.0/install/lib/libcurl.a -DCURL_INCLUDE_DIR=/curl-7.57.0/install/include -DCMAKE_CXX_FLAGS=-fPIC -DCMAKE_C_FLAGS=-fPIC

IMPORTANT: Under /opt/python/, you will find various directories dedicated to different Python distributions, e.g. cp27-cp27m, cp36-cp36m, etc. On top on that, you will also find mu variant of some distribution, e.g. cp27-cp27mu, etc. These are wide-unicode (ucs4) versions of Python. We will need to support both m and mu variants.

Now, run make under each build folder.

cd build_27m

make

make install

Building wheel

Use different Python to generate wheels for various Python versions.

cd ../install_27m/wrapper

Get setup.py script from pySBOL repository.

/opt/python/cp27-cp27m/bin/python2.7 setup.py bdist_wheel --python-tag=cp27

Use different Python to generate wheels for various Python versions. Make sure to change --python-tag=<cp27|cp36>.

cd dist

mv ./pySBOL-2.3.0.post11-cp27-none-any.whl ./pySBOL-2.3.0.post11-cp27-cp27m-manylinux1_x86_64.whl

Renaming the wheel is crucial.

IMPORTANT: Make sure to change ABI tag none to cp27mu, etc. when building wheels for mu distributions.

Checking and uploading wheel

Now, lets check whether our wheel is manylinux compatible. Run auditwheel on the wheel that was just generated.

auditwheel show ./pySBOL-2.3.0.post1-cp27-cp27m-manylinux1_x86_64.whl

The output will look like this:

pySBOL-2.3.0.post11-cp27-cp27m-manylinux1_x86_64.whl is consistent
with the following platform tag: "linux_x86_64".

The wheel references external versioned symbols in these system-
provided shared libraries: libgcc_s.so.1 with versions {'GCC_3.0'},
libm.so.6 with versions {'GLIBC_2.2.5'}, libc.so.6 with versions
{'GLIBC_2.3', 'GLIBC_2.2.5', 'GLIBC_2.4', 'GLIBC_2.3.4',
'GLIBC_2.3.2'}, libstdc++.so.6 with versions {'GLIBCXX_3.4',
'CXXABI_1.3.1', 'GLIBCXX_3.4.5', 'CXXABI_1.3'}

The following external shared libraries are required by the wheel:
{
    "libc.so.6": "/lib64/libc-2.5.so",
    "libdl.so.2": "/lib64/libdl-2.5.so",
    "libgcc_s.so.1": "/lib64/libgcc_s-4.1.2-20080825.so.1",
    "libm.so.6": "/lib64/libm-2.5.so",
    "libstdc++.so.6": "/usr/lib64/libstdc++.so.6.0.8",
    "libxml2.so.2": "/usr/lib64/libxml2.so.2.6.26",
    "libxslt.so.1": "/usr/lib64/libxslt.so.1.1.17",
    "libz.so.1": "/lib64/libz.so.1.2.3"
}

In order to achieve the tag platform tag "manylinux1_x86_64" the
following shared library dependencies will need to be eliminated:

libxml2.so.2, libxslt.so.1, libz.so.1

Let's remove the last set of dependencies by using

auditwheel repair ./pySBOL-2.3.0.post1-cp27-cp27m-manylinux1_x86_64.whl

There might be an error, but a new wheel will be generated under wheelhouse folder regardless. Checking this wheel by using auditwheel show, you will see:

pySBOL-2.3.0.post11-cp27-cp27m-manylinux1_x86_64.whl is consistent
with the following platform tag: "manylinux1_x86_64".

The wheel references external versioned symbols in these system-
provided shared libraries: libgcc_s.so.1 with versions {'GCC_3.0'},
libm.so.6 with versions {'GLIBC_2.2.5'}, libc.so.6 with versions
{'GLIBC_2.3.4', 'GLIBC_2.2.5', 'GLIBC_2.4', 'GLIBC_2.3.2',
'GLIBC_2.3'}, libstdc++.so.6 with versions {'CXXABI_1.3.1',
'GLIBCXX_3.4', 'GLIBCXX_3.4.5', 'CXXABI_1.3'}

The following external shared libraries are required by the wheel:
{
    "libc.so.6": "/lib64/libc-2.5.so",
    "libdl.so.2": "/lib64/libdl-2.5.so",
    "libgcc_s.so.1": "/lib64/libgcc_s-4.1.2-20080825.so.1",
    "libm.so.6": "/lib64/libm-2.5.so",
    "libstdc++.so.6": "/usr/lib64/libstdc++.so.6.0.8"
}

Make sure that the wheel is consistent with the platform tag and there are no other dependencies to be eliminated. The above output indicates that the wheel is ready to be deployed. However, it is always a good idea to test the wheels first.

Next, upload the wheel using twine. You will have to install twine first, through pip under a Python distribution, e.g. /opt/python/cp27-cp27m/bin/pip. After running /opt/python/cp27-cp27m/bin/pip install twine, you can do something like:

/opt/python/cp27-cp27m/bin/twine upload <file-location> -u <username> -p <password>

Repeat this through all Python versions we support (for both m and mu). Right now, we support Python 2.7 and 3.6, so you will need to repeat the steps from building Python libraries few times. Make sure that you are consistent with the Python version you are using.