Supporting Windows using Appveyor¶
This section covers how to use the free Appveyor continuous integration service to provide Windows support for your project. This includes testing the code on Windows, and building Windows-targeted binaries for projects that use C extensions.
Many projects are developed on Unix by default, and providing Windows support can be a challenge, because setting up a suitable Windows test environment is non-trivial, and may require buying software licenses.
The Appveyor service is a continuous integration service, much like the better-known Travis service that is commonly used for testing by projects hosted on Github. However, unlike Travis, the build workers on Appveyor are Windows hosts and have the necessary compilers installed to build Python extensions.
Windows users typically do not have access to a C compiler, and therefore are
reliant on projects that use C extensions distributing binary wheels on PyPI in
order for the distribution to be installable via
pip install <dist>. By
using Appveyor as a build service (even if not using it for testing) it is
possible for projects without a dedicated Windows environment to provide
In order to use Appveyor to build Windows wheels for your project, you must have an account on the service. Instructions on setting up an account are given in the Appveyor documentation. The free tier of account is perfectly adequate for open source projects.
Once you have set up your Appveyor account and added your project, Appveyor will automatically build your project each time a commit occurs. This behaviour will be familiar to users of Travis.
In order to define how Appveyor should build your project, you need to add an
appveyor.yml file to your project. The full details of what can be included
in the file are covered in the Appveyor documentation. This guide will provide
the details necessary to set up wheel builds.
Appveyor includes by default all of the compiler toolchains needed to build extensions for Python. For Python 2.7, 3.5+ and 32-bit versions of 3.3 and 3.4, the tools work out of the box. But for 64-bit versions of Python 3.3 and 3.4, there is a small amount of additional configuration needed to let distutils know where to find the 64-bit compilers. (From 3.5 onwards, the version of Visual Studio used includes 64-bit compilers with no additional setup).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
environment: matrix: # For Python versions available on Appveyor, see # http://www.appveyor.com/docs/installed-software#python # The list here is complete (excluding Python 2.6, which # isn't covered by this document) at the time of writing. - PYTHON: "C:\\Python27" - PYTHON: "C:\\Python33" - PYTHON: "C:\\Python34" - PYTHON: "C:\\Python35" - PYTHON: "C:\\Python27-x64" - PYTHON: "C:\\Python33-x64" DISTUTILS_USE_SDK: "1" - PYTHON: "C:\\Python34-x64" DISTUTILS_USE_SDK: "1" - PYTHON: "C:\\Python35-x64" install: # We need wheel installed to build wheels - "%PYTHON%\\python.exe -m pip install wheel" build: off test_script: # Put your test command here. # If you don't need to build C extensions on 64-bit Python 3.3 or 3.4, # you can remove "build.cmd" from the front of the command, as it's # only needed to support those cases. # Note that you must use the environment variable %PYTHON% to refer to # the interpreter you're using - Appveyor does not do anything special # to put the Python version you want to use on PATH. - "build.cmd %PYTHON%\\python.exe setup.py test" after_test: # This step builds your wheels. # Again, you only need build.cmd if you're building C extensions for # 64-bit Python 3.3/3.4. And you need to use %PYTHON% to get the correct # interpreter - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel" artifacts: # bdist_wheel puts your built wheel in the dist directory - path: dist\* #on_success: # You can use this step to upload your artifacts to a public website. # See Appveyor's documentation for more details. Or you can simply # access your wheels from the Appveyor "artifacts" tab for your build.
This file can be downloaded from here.
appveyor.yml file must be located in the root directory of your
project. It is in
YAML format, and consists of a number of sections.
environment section is the key to defining the Python versions for
which your wheels will be created. Appveyor comes with Python 2.6, 2.7, 3.3,
3.4 and 3.5 installed, in both 32-bit and 64-bit builds. The example file
builds for all of these environments except Python 2.6. Installing for Python
2.6 is more complex, as it does not come with pip included. We don’t support
2.6 in this document (as Windows users still using Python 2 are generally able
to move to Python 2.7 without too much difficulty).
install section uses pip to install any additional software that the
project may require. The only requirement for building wheels is the
project, but projects may wish to customise this code in certain circumstances
(for example, to install additional build packages such as
Cython, or test
tools such as
build section simply switches off builds - there is no build step needed
for Python, unlike languages like
The main sections that will need to be tailored to your project are
test_script section is where you will run your project’s tests. The
supplied file runs your test suite using
setup.py test. If you are only
interested in building wheels, and not in running your tests on Windows, you
can replace this section with a dummy command such as
echo Skipped Tests.
You may wish to use another test tool, such as
py.test. Or you
may wish to use a test driver like
tox - however if you are using
there are some additional configuration changes you will need to consider,
which are described below.
after_test runs once your tests have completed, and so is where the
wheels should be built. Assuming your project uses the recommended tools
setuptools) then the
setup.py bdist_wheel command
will build your wheels.
Note that wheels will only be built if your tests succeed. If you expect your tests to fail on Windows, you can skip them as described above.
appveyor.yml file relies on a single support script, which sets up the
environment to use the SDK compiler for 64-bit builds on Python 3.3 and 3.4.
For projects which do not need a compiler, or which don’t support 3.3 or 3.4 on
64-bit Windows, only the
appveyor.yml file is needed.
is a Windows batch script that runs a single command in an environment with the
appropriate compiler for the selected Python version. All you need to do is to
set the single environment variable
DISTUTILS_USE_SDK to a value of
and the script does the rest. It sets up the SDK needed for 64-bit builds of
Python 3.3 or 3.4, so don’t set the environment variable for any other builds.
You can simply download the batch file and include it in your project unchanged.
When your build completes, the built wheels will be available from the Appveyor control panel for your project. They can be found by going to the build status page for each build in turn. At the top of the build output there is a series of links, one of which is “Artifacts”. That page will include a list of links to the wheels for that Python version / architecture. You can download those wheels and upload them to PyPI as part of your release process.
Many projects use the Tox tool to run their tests. It ensures that tests are run in an isolated environment using the exact files that will be distributed by the project.
In order to use
tox on Appveyor there are a couple of additional considerations
(in actual fact, these issues are not specific to Appveyor, and may well affect
other CI systems).
toxonly passes a chosen subset of environment variables to the test processes. Because
distutilsuses environment variables to control the compiler, this “test isolation” feature will cause the tests to use the wrong compiler by default.
toxto pass the necessary environment variables to the subprocess, you need to set the
passenvto list the additional environment variables to be passed to the subprocess. For the SDK compilers, you need
passenvoption can be set in your
tox.ini, or if you prefer to avoid adding Windows-specific settings to your general project files, it can be set by setting the
TOX_TESTENV_PASSENVenvironment variable. The supplied
build.cmdscript does this by default whenever
When used interactively,
toxallows you to run your tests against multiple environments (often, this means multiple Python versions). This feature is not as useful in a CI environment like Travis or Appveyor, where all tests are run in isolated environments for each configuration. As a result, projects often supply an argument
toxto specify which environment to use (there are default environments for most versions of Python).
However, this does not work well with a Windows CI system like Appveyor, where there are (for example) two installations of Python 3.4 (32-bit and 64-bit) available, but only one
In order to run tests using
tox, therefore, projects should probably use the default
tox, which uses the Python interpreter that was used to run
tox. This will ensure that when Appveyor runs the tests, they will be run with the configured interpreter.
In order to support running under the
pyenvironment, it is possible that projects with complex
toxconfigurations might need to modify their
tox.inifile. Doing so is, however, outside the scope of this document.
It is possible to request Appveyor to automatically upload wheels. There is a
deployment step available in
appveyor.yml that can be used to (for
example) copy the built artifacts to a FTP site, or an Amazon S3 instance.
Documentation on how to do this is included in the Appveyor guides.
Alternatively, it would be possible to add a
twine upload step to the
build. The supplied
appveyor.yml does not do this, as it is not clear that
uploading new wheels after every commit is desirable (although some projects
may wish to do this).
The supplied scripts will successfully build any distribution that does not rely on 3rd party external libraries for the build.
It is possible to add steps to the
appveyor.yml configuration (typically
in the “install” section) to download and/or build external libraries needed by
the distribution. And if needed, it is possible to add extra configuration for
the build to supply the location of these libraries to the compiler. However,
this level of configuration is beyond the scope of this document.
For reference, the SDK setup support script is listed here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
@echo off :: To build extensions for 64 bit Python 3, we need to configure environment :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 4 :: :: More details at: :: https://github.com/cython/cython/wiki/CythonExtensionsOnWindows IF "%DISTUTILS_USE_SDK%"=="1" ( ECHO Configuring environment to build with MSVC on a 64bit architecture ECHO Using Windows SDK 7.1 "C:\Program Files\Microsoft SDKs\Windows\v7.1\Setup\WindowsSdkVer.exe" -q -version:v7.1 CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release SET MSSdk=1 REM Need the following to allow tox to see the SDK compiler SET TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB ) ELSE ( ECHO Using default MSVC build environment ) CALL %*