diff --git a/.gitignore b/.gitignore index 2b7d5ec615c7..f107d8ec887f 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,4 @@ setup.cfg .coverage .coverage.* cover/ +__conda_version__.txt diff --git a/.travis.yml b/.travis.yml index b749e95781ac..717c6c181187 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ matrix: - python: "nightly" before_install: - - source tools/travis_tools.sh + - source ci/travis/travis_tools.sh # Install into our own pristine virtualenv - virtualenv --python=python venv - source venv/bin/activate @@ -90,7 +90,7 @@ install: fc-cache -f -v else # Use the special local version of freetype for testing - cp .travis/setup.cfg . + cp ci/travis/setup.cfg . fi; - pip install -e . @@ -130,10 +130,10 @@ after_success: if [[ $TRAVIS_PULL_REQUEST == false && $TRAVIS_REPO_SLUG == 'matplotlib/matplotlib' && $BUILD_DOCS == true && $TRAVIS_BRANCH == 'master' ]]; then cd $TRAVIS_BUILD_DIR echo "Uploading documentation" - openssl aes-256-cbc -K $encrypted_cc802e084cd0_key -iv $encrypted_cc802e084cd0_iv -in .travis/matplotlibDeployKey.enc -out .travis/matplotlibDeployKey -d + openssl aes-256-cbc -K $encrypted_cc802e084cd0_key -iv $encrypted_cc802e084cd0_iv -in ci/travis/matplotlibDeployKey.enc -out ci/travis/matplotlibDeployKey -d eval `ssh-agent -s` - chmod 600 .travis/matplotlibDeployKey - ssh-add .travis/matplotlibDeployKey + chmod 600 ci/travis/matplotlibDeployKey + ssh-add ci/travis/matplotlibDeployKey cd .. git clone git@github.com:matplotlib/devdocs.git cd devdocs @@ -154,12 +154,12 @@ after_success: [[ $TRAVIS_REPO_SLUG == 'matplotlib/matplotlib' ]] && \ [[ $TRAVIS_BRANCH == 'master' ]]; then cd $TRAVIS_BUILD_DIR - python .travis/travis_after_all.py + python ci/travis/travis_after_all.py export $(cat .to_export_back) if [ "$BUILD_LEADER" = "YES" ]; then if [ "$BUILD_AGGREGATE_STATUS" = "others_succeeded" ]; then echo "All Succeeded! Triggering OSX build..." - ./.travis/build_children.sh + ./ci/travis/build_children.sh else echo "Some Failed; no OSX build" fi diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000000..202e26cb4d22 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,104 @@ +# With infos from +# http://tjelvarolsson.com/blog/how-to-continuously-test-your-python-code-on-windows-using-appveyor/ +# https://packaging.python.org/en/latest/appveyor/ +# https://github.com/rmcgibbo/python-appveyor-conda-example + +# Backslashes in quotes need to be escaped: \ -> "\\" + +environment: + + global: + # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the + # /E:ON and /V:ON options are not enabled in the batch script intepreter + # See: http://stackoverflow.com/a/13751649/163740 + CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci\\appveyor\\run_with_env.cmd" + + matrix: + - PYTHON: "C:\\Python34_64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + CONDA_PY: "34" + CONDA_NPY: "110" + + - PYTHON: "C:\\Python35_64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + CONDA_PY: "35" + CONDA_NPY: "110" + + - PYTHON: "C:\\Python27_64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + CONDA_PY: "27" + CONDA_NPY: "18" + + - PYTHON: "C:\\Python27_32" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + CONDA_PY: "27" + CONDA_NPY: "18" + +# We always use a 64-bit machine, but can build x86 distributions +# with the PYTHON_ARCH variable (which is used by CMD_IN_ENV). +platform: + - x64 + +# all our python builds have to happen in tests_script... +build: false + +init: + - "ECHO %PYTHON_VERSION% %PYTHON%" + +install: + - powershell .\ci\appveyor\install.ps1 + - SET PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% + - cmd: conda config --set show_channel_urls yes + # for msinttypes + - cmd: conda config --add channels conda-forge + # this is now the downloaded conda... + - conda info -a + # same things as in tools/conda_recipe + - cmd: conda create -y -q -n test-environment python=%PYTHON_VERSION% pip setuptools numpy python-dateutil freetype=2.5 msinttypes tk pyparsing pytz tornado libpng zlib pyqt cycler nose mock + - activate test-environment + # This is needed for the installer to find the dlls... + - set LIBRARY_LIB=%CONDA_DEFAULT_ENV%\Library\lib + - cmd: 'mkdir lib || cmd /c "exit /b 0"' + - copy %LIBRARY_LIB%\zlibstatic.lib lib\z.lib + - copy %LIBRARY_LIB%\libpng_static.lib lib\png.lib + - set MPLBASEDIRLIST=%CONDA_DEFAULT_ENV%\Library\;. + # Show the installed packages + versions + - conda list + +test_script: + # Now build the thing.. + - '%CMD_IN_ENV% python setup.py develop' + # tests + # for now, just let them pass to get the after_test parts... + - python tests.py || cmd /c "exit /b 0" + +after_test: + # After the tests were a success, build packages (wheels and conda) + + # There is a bug in wheels which prevents building wheels when the package uses namespaces + - cmd: '%CMD_IN_ENV% python setup.py bdist_wheel' + # Note also that our setup.py script, which is called by conda-build, writes + # a __conda_version__.txt file, so the version number on the binary package + # is set dynamically. This unfortunately mean that conda build --output + # doesn't really work. + - cmd: '%CMD_IN_ENV% conda config --get channels' + # we can't build conda packages on 27 due to missing functools32, which is a recent + # additional dependency for matplotlib + - cmd: if [%CONDA_PY%] NEQ [27] %CMD_IN_ENV% conda build .\ci\conda_recipe + # Move the conda package into the dist directory, to register it + # as an "artifact" for Appveyor. + - cmd: 'copy /Y %PYTHON%\conda-bld\win-32\*.bz2 dist || cmd /c "exit /b 0"' + - cmd: 'copy /Y %PYTHON%\conda-bld\win-64\*.bz2 dist || cmd /c "exit /b 0"' + - cmd: dir .\dist\ + +artifacts: + - path: dist\* + name: packages + + - path: result_images\* + name: test result images + type: zip diff --git a/ci/appveyor/install.ps1 b/ci/appveyor/install.ps1 new file mode 100644 index 000000000000..c964973c6769 --- /dev/null +++ b/ci/appveyor/install.ps1 @@ -0,0 +1,96 @@ +# Sample script to install Miniconda under Windows +# Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner, Robert McGibbon +# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ + +$MINICONDA_URL = "http://repo.continuum.io/miniconda/" + + +function DownloadMiniconda ($python_version, $platform_suffix) { + $webclient = New-Object System.Net.WebClient + if ($python_version -match "3.4") { + $filename = "Miniconda3-latest-Windows-" + $platform_suffix + ".exe" + } else { + $filename = "Miniconda-latest-Windows-" + $platform_suffix + ".exe" + } + $url = $MINICONDA_URL + $filename + + $basedir = $pwd.Path + "\" + $filepath = $basedir + $filename + if (Test-Path $filename) { + Write-Host "Reusing" $filepath + return $filepath + } + + # Download and retry up to 3 times in case of network transient errors. + Write-Host "Downloading" $filename "from" $url + $retry_attempts = 2 + for($i=0; $i -lt $retry_attempts; $i++){ + try { + $webclient.DownloadFile($url, $filepath) + break + } + Catch [Exception]{ + Start-Sleep 1 + } + } + if (Test-Path $filepath) { + Write-Host "File saved at" $filepath + } else { + # Retry once to get the error message if any at the last try + $webclient.DownloadFile($url, $filepath) + } + return $filepath +} + + +function InstallMiniconda ($python_version, $architecture, $python_home) { + Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home + if (Test-Path $python_home) { + Write-Host $python_home "already exists, skipping." + return $false + } + if ($architecture -match "32") { + $platform_suffix = "x86" + } else { + $platform_suffix = "x86_64" + } + + $filepath = DownloadMiniconda $python_version $platform_suffix + Write-Host "Installing" $filepath "to" $python_home + $install_log = $python_home + ".log" + $args = "/S /D=$python_home" + Write-Host $filepath $args + Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru + if (Test-Path $python_home) { + Write-Host "Python $python_version ($architecture) installation complete" + } else { + Write-Host "Failed to install Python in $python_home" + Get-Content -Path $install_log + Exit 1 + } +} + + +function InstallCondaPackages ($python_home, $spec) { + $conda_path = $python_home + "\Scripts\conda.exe" + $args = "install --yes " + $spec + Write-Host ("conda " + $args) + Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru +} + +function UpdateConda ($python_home) { + $conda_path = $python_home + "\Scripts\conda.exe" + Write-Host "Updating conda..." + $args = "update --yes conda" + Write-Host $conda_path $args + Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru +} + + +function main () { + InstallMiniconda $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON + UpdateConda $env:PYTHON + InstallCondaPackages $env:PYTHON "conda-build jinja2 anaconda-client" +} + +main diff --git a/ci/appveyor/run_with_env.cmd b/ci/appveyor/run_with_env.cmd new file mode 100644 index 000000000000..848f4608c862 --- /dev/null +++ b/ci/appveyor/run_with_env.cmd @@ -0,0 +1,95 @@ +:: EXPECTED ENV VARS: PYTHON_ARCH (either x86 or x64) +:: CONDA_PY (either 27, 33, 35 etc. - only major version is extracted) +:: +:: +:: 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 (SDK v7.1) +:: +:: To build extensions for 64 bit Python 2, we need to configure environment +:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: +:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) +:: +:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific +:: environment configurations. +:: +:: Note: this script needs to be run with the /E:ON and /V:ON flags for the +:: cmd interpreter, at least for (SDK v7.0) +:: +:: More details at: +:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows +:: http://stackoverflow.com/a/13751649/163740 +:: +:: Author: Phil Elson +:: Original Author: Olivier Grisel (https://github.com/ogrisel/python-appveyor-demo) +:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ +:: +:: Notes about batch files for Python people: +:: +:: Quotes in values are literally part of the values: +:: SET FOO="bar" +:: FOO is now five characters long: " b a r " +:: If you don't want quotes, don't include them on the right-hand side. +:: +:: The CALL lines at the end of this file look redundant, but if you move them +:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y +:: case, I don't know why. +:: originally from https://github.com/pelson/Obvious-CI/blob/master/scripts/obvci_appveyor_python_build_env.cmd +@ECHO OFF + +SET COMMAND_TO_RUN=%* +SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows + +:: Extract the major and minor versions, and allow for the minor version to be +:: more than 9. This requires the version number to have two dots in it. +SET MAJOR_PYTHON_VERSION=%CONDA_PY:~0,1% + +IF "%CONDA_PY:~2,1%" == "" ( + :: CONDA_PY style, such as 27, 34 etc. + SET MINOR_PYTHON_VERSION=%CONDA_PY:~1,1% +) ELSE ( + IF "%CONDA_PY:~3,1%" == "." ( + SET MINOR_PYTHON_VERSION=%CONDA_PY:~2,1% + ) ELSE ( + SET MINOR_PYTHON_VERSION=%CONDA_PY:~2,2% + ) +) + +:: Based on the Python version, determine what SDK version to use, and whether +:: to set the SDK for 64-bit. +IF %MAJOR_PYTHON_VERSION% == 2 ( + SET WINDOWS_SDK_VERSION="v7.0" + SET SET_SDK_64=Y +) ELSE ( + IF %MAJOR_PYTHON_VERSION% == 3 ( + SET WINDOWS_SDK_VERSION="v7.1" + IF %MINOR_PYTHON_VERSION% LEQ 4 ( + SET SET_SDK_64=Y + ) ELSE ( + SET SET_SDK_64=N + ) + ) ELSE ( + ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" + EXIT /B 1 + ) +) + +IF "%PYTHON_ARCH%"=="64" ( + IF %SET_SDK_64% == Y ( + ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture + SET DISTUTILS_USE_SDK=1 + SET MSSdk=1 + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT /B 1 + ) ELSE ( + ECHO Using default MSVC build environment for 64 bit architecture + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT /B 1 + ) +) ELSE ( + ECHO Using default MSVC build environment for 32 bit architecture + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT /B 1 +) diff --git a/ci/conda_recipe/README.md b/ci/conda_recipe/README.md new file mode 100644 index 000000000000..7819c9f0c766 --- /dev/null +++ b/ci/conda_recipe/README.md @@ -0,0 +1,3 @@ +# conda package + +Up to now, this is mainly used to build a test conda package on windows on appveyor. \ No newline at end of file diff --git a/ci/conda_recipe/bld.bat b/ci/conda_recipe/bld.bat new file mode 100644 index 000000000000..fb7909de3362 --- /dev/null +++ b/ci/conda_recipe/bld.bat @@ -0,0 +1,19 @@ +mkdir lib +copy %LIBRARY_LIB%\zlibstatic.lib lib\z.lib +if errorlevel 1 exit 1 +copy %LIBRARY_LIB%\libpng_static.lib lib\png.lib +if errorlevel 1 exit 1 + +set MPLBASEDIRLIST=%LIBRARY_PREFIX%;. + +:: debug... +set + +copy setup.cfg.template setup.cfg +if errorlevel 1 exit 1 + +python setup.py install +if errorlevel 1 exit 1 + +rd /s /q %SP_DIR%\dateutil +rd /s /q %SP_DIR%\numpy diff --git a/ci/conda_recipe/build.sh b/ci/conda_recipe/build.sh new file mode 100644 index 000000000000..c9ff280da808 --- /dev/null +++ b/ci/conda_recipe/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ `uname` == Linux ]; then + pushd $PREFIX/lib + ln -s libtcl8.5.so libtcl.so + ln -s libtk8.5.so libtk.so + popd +fi + +if [ `uname` == Darwin ]; then + sed s:'#ifdef WITH_NEXT_FRAMEWORK':'#if 1':g -i src/_macosx.m +fi + +cp setup.cfg.template setup.cfg || exit 1 + +sed s:/usr/local:$PREFIX:g -i setupext.py + +$PYTHON setup.py install + +rm -rf $SP_DIR/PySide +rm -rf $SP_DIR/__pycache__ +rm -rf $PREFIX/bin/nose* + diff --git a/ci/conda_recipe/cfg_notests.patch b/ci/conda_recipe/cfg_notests.patch new file mode 100644 index 000000000000..e47f9d1619d3 --- /dev/null +++ b/ci/conda_recipe/cfg_notests.patch @@ -0,0 +1,13 @@ +diff --git setup.cfg.template setup.cfg.template +index 09fd92f..2085832 100644 +--- setup.cfg.template ++++ setup.cfg.template +@@ -18,7 +18,7 @@ + # optional. They are all installed by default, but they may be turned + # off here. + # +-#tests = True ++tests = False + #sample_data = True + #toolkits = True + # Tests for the toolkits are only automatically installed \ No newline at end of file diff --git a/ci/conda_recipe/cfg_qt4agg.patch b/ci/conda_recipe/cfg_qt4agg.patch new file mode 100644 index 000000000000..2403b9149fd5 --- /dev/null +++ b/ci/conda_recipe/cfg_qt4agg.patch @@ -0,0 +1,11 @@ +diff --git setup.cfg.template setup.cfg.template +index 8af8b6d..4e4f9d2 100644 +--- setup.cfg.template ++++ setup.cfg.template +@@ -78,5 +78,5 @@ + # if you have disabled the relevent extension modules. Agg will be used + # by default. + # +-#backend = Agg ++backend = Qt4Agg + # diff --git a/ci/conda_recipe/condaversion.patch b/ci/conda_recipe/condaversion.patch new file mode 100644 index 000000000000..c0883d491bca --- /dev/null +++ b/ci/conda_recipe/condaversion.patch @@ -0,0 +1,14 @@ +diff --git setup.py setup.py +index 8af8b6d..4e4f9d2 100644 +--- setup.py ++++ setup.py +@@ -57,6 +57,9 @@ + import versioneer + __version__ = versioneer.get_version() + ++# For conda builds... ++with open("__conda_version__.txt", "w") as f: ++ f.write(__version__) + + # These are the packages in the order we want to display them. This + # list may contain strings to create section headers for the display. diff --git a/ci/conda_recipe/meta.yaml b/ci/conda_recipe/meta.yaml new file mode 100644 index 000000000000..16101f30131e --- /dev/null +++ b/ci/conda_recipe/meta.yaml @@ -0,0 +1,61 @@ +# stolen from https://github.com/conda/conda-recipes/tree/master/matplotlib +# selectors [py27] and comments need to be `# [selector] comment` not `[sel] # comment` + +package: + name: matplotlib-test + version: 1.5.0.9 + +source: + path: ../../ + + patches: + # don't run nosetest + - cfg_notests.patch + # nake Qt4Agg the default backend + - cfg_qt4agg.patch [not osx] + - rctmp_pyside.patch [not osx] + # tk work on OSX + - osx-tk.patch [osx] + # dynamic version from git + - condaversion.patch + +requirements: + build: + - python + - setuptools + - numpy + - python-dateutil + - freetype >=2.5,<2.6 + - pyparsing + - pytz + - py2cairo [linux and py2k] + - tornado + - libpng + - zlib [win] + - msinttypes # this package is from the conda-forge channel! + - pyqt [not osx] + - cycler + - tk + #- functools32 [py27] # this is currently not available + + run: + - python + - numpy + - python-dateutil + - freetype [unix] + - pytz + - pyparsing + - py2cairo [linux and py2k] + - libpng [unix] + - pyqt [not osx] + - cycler + - tk + +test: + requires: + - nose + - mock + +about: + home: http://matplotlib.sourceforge.net/ + license: PSF-based (http://matplotlib.sourceforge.net/users/license.html) diff --git a/ci/conda_recipe/osx-tk.patch b/ci/conda_recipe/osx-tk.patch new file mode 100644 index 000000000000..e950b3284829 --- /dev/null +++ b/ci/conda_recipe/osx-tk.patch @@ -0,0 +1,60 @@ +diff --git setupext.py setupext.py +index 9219c88..e3a9653 100644 +--- setupext.py ++++ setupext.py +@@ -1334,52 +1334,11 @@ class BackendTkAgg(OptionalBackendPackage): + ext.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) + + elif sys.platform == 'darwin': +- # this config section lifted directly from Imaging - thanks to +- # the effbot! +- +- # First test for a MacOSX/darwin framework install + from os.path import join, exists +- framework_dirs = [ +- join(os.getenv('HOME'), '/Library/Frameworks'), +- '/Library/Frameworks', +- '/System/Library/Frameworks/', +- ] +- +- # Find the directory that contains the Tcl.framework and +- # Tk.framework bundles. +- tk_framework_found = 0 +- for F in framework_dirs: +- # both Tcl.framework and Tk.framework should be present +- for fw in 'Tcl', 'Tk': +- if not exists(join(F, fw + '.framework')): +- break +- else: +- # ok, F is now directory with both frameworks. Continure +- # building +- tk_framework_found = 1 +- break +- if tk_framework_found: +- # For 8.4a2, we must add -I options that point inside +- # the Tcl and Tk frameworks. In later release we +- # should hopefully be able to pass the -F option to +- # gcc, which specifies a framework lookup path. +- +- tk_include_dirs = [ +- join(F, fw + '.framework', H) +- for fw in ('Tcl', 'Tk') +- for H in ('Headers', 'Versions/Current/PrivateHeaders') +- ] +- +- # For 8.4a2, the X11 headers are not included. Rather +- # than include a complicated search, this is a +- # hard-coded path. It could bail out if X11 libs are +- # not found... + +- # tk_include_dirs.append('/usr/X11R6/include') +- frameworks = ['-framework', 'Tcl', '-framework', 'Tk'] +- ext.include_dirs.extend(tk_include_dirs) +- ext.extra_link_args.extend(frameworks) +- ext.extra_compile_args.extend(frameworks) ++ ext.include_dirs.append(join(sys.prefix, 'include')) ++ ext.libraries.extend(['tk8.5', 'tcl8.5']) ++ ext.library_dirs.append(join(sys.prefix, 'lib')) + + # you're still here? ok we'll try it this way... + else: diff --git a/ci/conda_recipe/rctmp_pyside.patch b/ci/conda_recipe/rctmp_pyside.patch new file mode 100644 index 000000000000..15e97de64541 --- /dev/null +++ b/ci/conda_recipe/rctmp_pyside.patch @@ -0,0 +1,19 @@ +diff --git matplotlibrc.template matplotlibrc.template +index fdbbf26..6902fe9 100644 +--- matplotlibrc.template ++++ matplotlibrc.template +@@ -35,12 +35,12 @@ + # You can also deploy your own backend outside of matplotlib by + # referring to the module name (which must be in the PYTHONPATH) as + # 'module://my_backend'. +-backend : %(backend)s ++backend : Qt4Agg + + # If you are using the Qt4Agg backend, you can choose here + # to use the PyQt4 bindings or the newer PySide bindings to + # the underlying Qt4 toolkit. +-#backend.qt4 : PyQt4 # PyQt4 | PySide ++backend.qt4 : PyQt4 # PyQt4 | PySide + + # Note that this can be overridden by the environment variable + # QT_API used by Enthought Tool Suite (ETS); valid values are diff --git a/ci/conda_recipe/run_test.py b/ci/conda_recipe/run_test.py new file mode 100644 index 000000000000..37c11af85bf9 --- /dev/null +++ b/ci/conda_recipe/run_test.py @@ -0,0 +1,27 @@ +import os +import sys + +import matplotlib +import matplotlib.pyplot +import matplotlib._cntr +import matplotlib._delaunay +import matplotlib._image +import matplotlib._path +import matplotlib._png +import matplotlib._tri +import matplotlib.backends._backend_agg +import matplotlib.ft2font +import matplotlib.ttconv +import matplotlib.backends._tkagg + +import pylab +import mpl_toolkits + +if int(os.getenv('GUI_TEST', 0)): + assert matplotlib.rcParams['backend.qt4'] == 'PyQt4' + + import matplotlib.pyplot as plt + plt.ioff() + plt.title('If this window displays, success: CLOSE TO CONTINUE TESTS') + plt.plot([1,2,5,9]) + plt.show() diff --git a/.travis/build_children.sh b/ci/travis/build_children.sh old mode 100755 new mode 100644 similarity index 100% rename from .travis/build_children.sh rename to ci/travis/build_children.sh diff --git a/.travis/matplotlibDeployKey.enc b/ci/travis/matplotlibDeployKey.enc similarity index 100% rename from .travis/matplotlibDeployKey.enc rename to ci/travis/matplotlibDeployKey.enc diff --git a/.travis/setup.cfg b/ci/travis/setup.cfg similarity index 100% rename from .travis/setup.cfg rename to ci/travis/setup.cfg diff --git a/.travis/travis_after_all.py b/ci/travis/travis_after_all.py similarity index 100% rename from .travis/travis_after_all.py rename to ci/travis/travis_after_all.py diff --git a/tools/travis_tools.sh b/ci/travis/travis_tools.sh similarity index 100% rename from tools/travis_tools.sh rename to ci/travis/travis_tools.sh diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 0e9c106498b9..d0655a2f787c 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -38,7 +38,7 @@ from matplotlib.cbook import iterable, is_string_like from matplotlib.compat import subprocess from matplotlib import verbose -from matplotlib import rcParams +from matplotlib import rcParams, rcParamsDefault # Process creation flag for subprocess to prevent it raising a terminal # window. See for example: @@ -267,6 +267,8 @@ def isAvailable(cls): Check to see if a MovieWriter subclass is actually available by running the commandline tool. ''' + if not cls.bin_path(): + return False try: p = subprocess.Popen(cls.bin_path(), shell=False, @@ -551,6 +553,27 @@ def delay(self): def output_args(self): return [self.outfile] + @classmethod + def _init_from_registry(cls): + if sys.platform != 'win32' or rcParams[cls.exec_key] != 'convert': + return + from matplotlib.externals.six.moves import winreg + for flag in (0, winreg.KEY_WOW64_32KEY, winreg.KEY_WOW64_64KEY): + try: + hkey = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, + 'Software\\Imagemagick\\Current', + 0, winreg.KEY_QUERY_VALUE | flag) + binpath = winreg.QueryValueEx(hkey, 'BinPath')[0] + winreg.CloseKey(hkey) + binpath += '\\convert.exe' + break + except Exception: + binpath = '' + rcParams[cls.exec_key] = rcParamsDefault[cls.exec_key] = binpath + + +ImageMagickBase._init_from_registry() + @writers.register('imagemagick') class ImageMagickWriter(MovieWriter, ImageMagickBase): diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index a02b094d2bfd..bb87bebeb999 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -29,9 +29,17 @@ def test_font_priority(): def test_json_serialization(): - with tempfile.NamedTemporaryFile() as temp: - json_dump(fontManager, temp.name) - copy = json_load(temp.name) + # on windows, we can't open a file twice, so save the name and unlink + # manually... + try: + name = None + with tempfile.NamedTemporaryFile(delete=False) as temp: + name = temp.name + json_dump(fontManager, name) + copy = json_load(name) + finally: + if name and os.path.exists(name): + os.remove(name) with warnings.catch_warnings(): warnings.filterwarnings('ignore', 'findfont: Font family.*not found') for prop in ({'family': 'STIXGeneral'}, diff --git a/patched_bdist_wheel.py b/patched_bdist_wheel.py new file mode 100644 index 000000000000..63fc3ec22d16 --- /dev/null +++ b/patched_bdist_wheel.py @@ -0,0 +1,103 @@ +""" +Workaround until https://bitbucket.org/pypa/wheel/issues/91/cannot-create-a-file-when-that-file +is fixed... + +Only one small patch in the os.name == nt case: +- basedir_observed = os.path.join(self.data_dir, '..') ++ basedir_observed = os.path.join(self.data_dir, '..', '.') +""" + +from wheel.bdist_wheel import bdist_wheel +from distutils.sysconfig import get_python_version +from distutils import log as logger +from wheel.archive import archive_wheelfile +import subprocess +import os +from shutil import rmtree + +class patched_bdist_wheel(bdist_wheel): + + def run(self): + build_scripts = self.reinitialize_command('build_scripts') + build_scripts.executable = 'python' + + if not self.skip_build: + self.run_command('build') + + install = self.reinitialize_command('install', + reinit_subcommands=True) + install.root = self.bdist_dir + install.compile = False + install.skip_build = self.skip_build + install.warn_dir = False + + # A wheel without setuptools scripts is more cross-platform. + # Use the (undocumented) `no_ep` option to setuptools' + # install_scripts command to avoid creating entry point scripts. + install_scripts = self.reinitialize_command('install_scripts') + install_scripts.no_ep = True + + # Use a custom scheme for the archive, because we have to decide + # at installation time which scheme to use. + for key in ('headers', 'scripts', 'data', 'purelib', 'platlib'): + setattr(install, + 'install_' + key, + os.path.join(self.data_dir, key)) + + basedir_observed = '' + + if os.name == 'nt': + # win32 barfs if any of these are ''; could be '.'? + # (distutils.command.install:change_roots bug) + # PATCHED... + basedir_observed = os.path.join(self.data_dir, '..', '.') + self.install_libbase = self.install_lib = basedir_observed + + setattr(install, + 'install_purelib' if self.root_is_pure else 'install_platlib', + basedir_observed) + + logger.info("installing to %s", self.bdist_dir) + + self.run_command('install') + + archive_basename = self.get_archive_basename() + + pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) + if not self.relative: + archive_root = self.bdist_dir + else: + archive_root = os.path.join( + self.bdist_dir, + self._ensure_relative(install.install_base)) + + self.set_undefined_options( + 'install_egg_info', ('target', 'egginfo_dir')) + self.distinfo_dir = os.path.join(self.bdist_dir, + '%s.dist-info' % self.wheel_dist_name) + self.egg2dist(self.egginfo_dir, + self.distinfo_dir) + + self.write_wheelfile(self.distinfo_dir) + + self.write_record(self.bdist_dir, self.distinfo_dir) + + # Make the archive + if not os.path.exists(self.dist_dir): + os.makedirs(self.dist_dir) + wheel_name = archive_wheelfile(pseudoinstall_root, archive_root) + + # Sign the archive + if 'WHEEL_TOOL' in os.environ: + subprocess.call([os.environ['WHEEL_TOOL'], 'sign', wheel_name]) + + # Add to 'Distribution.dist_files' so that the "upload" command works + getattr(self.distribution, 'dist_files', []).append( + ('bdist_wheel', get_python_version(), wheel_name)) + + if not self.keep_temp: + if self.dry_run: + logger.info('removing %s', self.bdist_dir) + else: + rmtree(self.bdist_dir) + diff --git a/setup.py b/setup.py index 3e1393e8a6d3..e262db3fbb3a 100644 --- a/setup.py +++ b/setup.py @@ -253,6 +253,18 @@ def run(self): cmdclass['test'] = NoseTestCommand cmdclass['build_ext'] = BuildExtraLibraries +# patch bdist_wheel for a bug on windows +# https://bitbucket.org/pypa/wheel/issues/91/cannot-create-a-file-when-that-file +if os.name == 'nt': + try: + from wheel.bdist_wheel import bdist_wheel + except ImportError: + # No wheel installed, so we also can't run that command... + pass + else: + # patched_bdist_wheel has a run() method, which works on windows + from patched_bdist_wheel import patched_bdist_wheel + cmdclass['bdist_wheel'] = patched_bdist_wheel # One doesn't normally see `if __name__ == '__main__'` blocks in a setup.py, # however, this is needed on Windows to avoid creating infinite subprocesses diff --git a/setupext.py b/setupext.py index 01d482ce58fb..b3438fa8cf1c 100755 --- a/setupext.py +++ b/setupext.py @@ -126,9 +126,18 @@ def get_base_dirs(): """ if options['basedirlist']: return options['basedirlist'] - + + if os.environ.get('MPLBASEDIRLIST'): + return os.environ.get('MPLBASEDIRLIST').split(os.pathsep) + + win_bases = ['win32_static', ] + # on conda windows, we also add the \Library of the local interperter, + # as conda installs libs/includes there + if os.getenv('CONDA_DEFAULT_ENV'): + win_bases.append(os.path.join(os.getenv('CONDA_DEFAULT_ENV'), "Library")) + basedir_map = { - 'win32': ['win32_static', ], + 'win32': win_bases, 'darwin': ['/usr/local/', '/usr', '/usr/X11', '/opt/X11', '/opt/local'], 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local', ], @@ -143,8 +152,11 @@ def get_include_dirs(): Returns a list of standard include directories on this platform. """ include_dirs = [os.path.join(d, 'include') for d in get_base_dirs()] - include_dirs.extend( - os.environ.get('CPLUS_INCLUDE_PATH', '').split(os.pathsep)) + if sys.platform != 'win32': + # gcc includes this dir automatically, so also look for headers in + # these dirs + include_dirs.extend( + os.environ.get('CPLUS_INCLUDE_PATH', '').split(os.pathsep)) return include_dirs @@ -906,7 +918,10 @@ def check(self): return "Using local version for testing" if sys.platform == 'win32': - check_include_file(get_include_dirs(), 'ft2build.h', 'freetype') + try: + check_include_file(get_include_dirs(), 'ft2build.h', 'freetype') + except CheckFailed: + check_include_file(get_include_dirs(), 'freetype2\\ft2build.h', 'freetype') return 'Using unknown version found on system.' status, output = getstatusoutput("freetype-config --ftversion") @@ -1579,14 +1594,22 @@ def hardcoded_tcl_config(self): def add_flags(self, ext): if sys.platform == 'win32': - major, minor1, minor2, s, tmp = sys.version_info - if sys.version_info[0:2] < (3, 4): - ext.include_dirs.extend(['win32_static/include/tcl85']) + if os.getenv('CONDA_DEFAULT_ENV'): + # We are in conda and conda builds against tcl85 for all versions + # includes are directly in the conda\library\include dir and + # libs in DLL or lib + ext.include_dirs.extend(['include']) ext.libraries.extend(['tk85', 'tcl85']) + ext.library_dirs.extend(['dlls']) # or lib? else: - ext.include_dirs.extend(['win32_static/include/tcl86']) - ext.libraries.extend(['tk86t', 'tcl86t']) - ext.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) + major, minor1, minor2, s, tmp = sys.version_info + if sys.version_info[0:2] < (3, 4): + ext.include_dirs.extend(['win32_static/include/tcl85']) + ext.libraries.extend(['tk85', 'tcl85']) + else: + ext.include_dirs.extend(['win32_static/include/tcl86']) + ext.libraries.extend(['tk86t', 'tcl86t']) + ext.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) elif sys.platform == 'darwin': # this config section lifted directly from Imaging - thanks to