Blame setup.py

Packit 7a8e5e
#!/usr/bin/env python
Packit 7a8e5e
"""NumPy: array processing for numbers, strings, records, and objects.
Packit 7a8e5e
Packit 7a8e5e
NumPy is a general-purpose array-processing package designed to
Packit 7a8e5e
efficiently manipulate large multi-dimensional arrays of arbitrary
Packit 7a8e5e
records without sacrificing too much speed for small multi-dimensional
Packit 7a8e5e
arrays.  NumPy is built on the Numeric code base and adds features
Packit 7a8e5e
introduced by numarray as well as an extended C-API and the ability to
Packit 7a8e5e
create arrays of arbitrary type which also makes NumPy suitable for
Packit 7a8e5e
interfacing with general-purpose data-base applications.
Packit 7a8e5e
Packit 7a8e5e
There are also basic facilities for discrete fourier transform,
Packit 7a8e5e
basic linear algebra and random number generation.
Packit 7a8e5e
Packit 7a8e5e
All numpy wheels distributed from pypi are BSD licensed.
Packit 7a8e5e
Packit 7a8e5e
Windows wheels are linked against the ATLAS BLAS / LAPACK library, restricted
Packit 7a8e5e
to SSE2 instructions, so may not give optimal linear algebra performance for
Packit 7a8e5e
your machine. See http://docs.scipy.org/doc/numpy/user/install.html for
Packit 7a8e5e
alternatives.
Packit 7a8e5e
Packit 7a8e5e
"""
Packit 7a8e5e
from __future__ import division, print_function
Packit 7a8e5e
Packit 7a8e5e
DOCLINES = (__doc__ or '').split("\n")
Packit 7a8e5e
Packit 7a8e5e
import os
Packit 7a8e5e
import sys
Packit 7a8e5e
import subprocess
Packit 7a8e5e
import textwrap
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 4):
Packit 7a8e5e
    raise RuntimeError("Python version 2.7 or >= 3.4 required.")
Packit 7a8e5e
Packit 7a8e5e
if sys.version_info[0] >= 3:
Packit 7a8e5e
    import builtins
Packit 7a8e5e
else:
Packit 7a8e5e
    import __builtin__ as builtins
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
CLASSIFIERS = """\
Packit 7a8e5e
Development Status :: 5 - Production/Stable
Packit 7a8e5e
Intended Audience :: Science/Research
Packit 7a8e5e
Intended Audience :: Developers
Packit 7a8e5e
License :: OSI Approved
Packit 7a8e5e
Programming Language :: C
Packit 7a8e5e
Programming Language :: Python
Packit 7a8e5e
Programming Language :: Python :: 2
Packit 7a8e5e
Programming Language :: Python :: 2.7
Packit 7a8e5e
Programming Language :: Python :: 3
Packit 7a8e5e
Programming Language :: Python :: 3.4
Packit 7a8e5e
Programming Language :: Python :: 3.5
Packit 7a8e5e
Programming Language :: Python :: 3.6
Packit 7a8e5e
Programming Language :: Python :: Implementation :: CPython
Packit 7a8e5e
Topic :: Software Development
Packit 7a8e5e
Topic :: Scientific/Engineering
Packit 7a8e5e
Operating System :: Microsoft :: Windows
Packit 7a8e5e
Operating System :: POSIX
Packit 7a8e5e
Operating System :: Unix
Packit 7a8e5e
Operating System :: MacOS
Packit 7a8e5e
"""
Packit 7a8e5e
Packit 7a8e5e
MAJOR               = 1
Packit 7a8e5e
MINOR               = 14
Packit 7a8e5e
MICRO               = 3
Packit 7a8e5e
ISRELEASED          = True
Packit 7a8e5e
VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
# Return the git revision as a string
Packit 7a8e5e
def git_version():
Packit 7a8e5e
    def _minimal_ext_cmd(cmd):
Packit 7a8e5e
        # construct minimal environment
Packit 7a8e5e
        env = {}
Packit 7a8e5e
        for k in ['SYSTEMROOT', 'PATH', 'HOME']:
Packit 7a8e5e
            v = os.environ.get(k)
Packit 7a8e5e
            if v is not None:
Packit 7a8e5e
                env[k] = v
Packit 7a8e5e
        # LANGUAGE is used on win32
Packit 7a8e5e
        env['LANGUAGE'] = 'C'
Packit 7a8e5e
        env['LANG'] = 'C'
Packit 7a8e5e
        env['LC_ALL'] = 'C'
Packit 7a8e5e
        out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
Packit 7a8e5e
        return out
Packit 7a8e5e
Packit 7a8e5e
    try:
Packit 7a8e5e
        out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
Packit 7a8e5e
        GIT_REVISION = out.strip().decode('ascii')
Packit 7a8e5e
    except OSError:
Packit 7a8e5e
        GIT_REVISION = "Unknown"
Packit 7a8e5e
Packit 7a8e5e
    return GIT_REVISION
Packit 7a8e5e
Packit 7a8e5e
# BEFORE importing setuptools, remove MANIFEST. Otherwise it may not be
Packit 7a8e5e
# properly updated when the contents of directories change (true for distutils,
Packit 7a8e5e
# not sure about setuptools).
Packit 7a8e5e
if os.path.exists('MANIFEST'):
Packit 7a8e5e
    os.remove('MANIFEST')
Packit 7a8e5e
Packit 7a8e5e
# This is a bit hackish: we are setting a global variable so that the main
Packit 7a8e5e
# numpy __init__ can detect if it is being loaded by the setup routine, to
Packit 7a8e5e
# avoid attempting to load components that aren't built yet.  While ugly, it's
Packit 7a8e5e
# a lot more robust than what was previously being used.
Packit 7a8e5e
builtins.__NUMPY_SETUP__ = True
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def get_version_info():
Packit 7a8e5e
    # Adding the git rev number needs to be done inside write_version_py(),
Packit 7a8e5e
    # otherwise the import of numpy.version messes up the build under Python 3.
Packit 7a8e5e
    FULLVERSION = VERSION
Packit 7a8e5e
    if os.path.exists('.git'):
Packit 7a8e5e
        GIT_REVISION = git_version()
Packit 7a8e5e
    elif os.path.exists('numpy/version.py'):
Packit 7a8e5e
        # must be a source distribution, use existing version file
Packit 7a8e5e
        try:
Packit 7a8e5e
            from numpy.version import git_revision as GIT_REVISION
Packit 7a8e5e
        except ImportError:
Packit 7a8e5e
            raise ImportError("Unable to import git_revision. Try removing " \
Packit 7a8e5e
                              "numpy/version.py and the build directory " \
Packit 7a8e5e
                              "before building.")
Packit 7a8e5e
    else:
Packit 7a8e5e
        GIT_REVISION = "Unknown"
Packit 7a8e5e
Packit 7a8e5e
    if not ISRELEASED:
Packit 7a8e5e
        FULLVERSION += '.dev0+' + GIT_REVISION[:7]
Packit 7a8e5e
Packit 7a8e5e
    return FULLVERSION, GIT_REVISION
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def write_version_py(filename='numpy/version.py'):
Packit 7a8e5e
    cnt = """
Packit 7a8e5e
# THIS FILE IS GENERATED FROM NUMPY SETUP.PY
Packit 7a8e5e
#
Packit 7a8e5e
# To compare versions robustly, use `numpy.lib.NumpyVersion`
Packit 7a8e5e
short_version = '%(version)s'
Packit 7a8e5e
version = '%(version)s'
Packit 7a8e5e
full_version = '%(full_version)s'
Packit 7a8e5e
git_revision = '%(git_revision)s'
Packit 7a8e5e
release = %(isrelease)s
Packit 7a8e5e
Packit 7a8e5e
if not release:
Packit 7a8e5e
    version = full_version
Packit 7a8e5e
"""
Packit 7a8e5e
    FULLVERSION, GIT_REVISION = get_version_info()
Packit 7a8e5e
Packit 7a8e5e
    a = open(filename, 'w')
Packit 7a8e5e
    try:
Packit 7a8e5e
        a.write(cnt % {'version': VERSION,
Packit 7a8e5e
                       'full_version': FULLVERSION,
Packit 7a8e5e
                       'git_revision': GIT_REVISION,
Packit 7a8e5e
                       'isrelease': str(ISRELEASED)})
Packit 7a8e5e
    finally:
Packit 7a8e5e
        a.close()
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def configuration(parent_package='',top_path=None):
Packit 7a8e5e
    from numpy.distutils.misc_util import Configuration
Packit 7a8e5e
Packit 7a8e5e
    config = Configuration(None, parent_package, top_path)
Packit 7a8e5e
    config.set_options(ignore_setup_xxx_py=True,
Packit 7a8e5e
                       assume_default_configuration=True,
Packit 7a8e5e
                       delegate_options_to_subpackages=True,
Packit 7a8e5e
                       quiet=True)
Packit 7a8e5e
Packit 7a8e5e
    config.add_subpackage('numpy')
Packit 7a8e5e
    config.add_data_files(('numpy', 'LICENSE.txt'))
Packit 7a8e5e
Packit 7a8e5e
    config.get_version('numpy/version.py') # sets config.version
Packit 7a8e5e
Packit 7a8e5e
    return config
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def check_submodules():
Packit 7a8e5e
    """ verify that the submodules are checked out and clean
Packit 7a8e5e
        use `git submodule update --init`; on failure
Packit 7a8e5e
    """
Packit 7a8e5e
    if not os.path.exists('.git'):
Packit 7a8e5e
        return
Packit 7a8e5e
    with open('.gitmodules') as f:
Packit 7a8e5e
        for l in f:
Packit 7a8e5e
            if 'path' in l:
Packit 7a8e5e
                p = l.split('=')[-1].strip()
Packit 7a8e5e
                if not os.path.exists(p):
Packit 7a8e5e
                    raise ValueError('Submodule %s missing' % p)
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
    proc = subprocess.Popen(['git', 'submodule', 'status'],
Packit 7a8e5e
                            stdout=subprocess.PIPE)
Packit 7a8e5e
    status, _ = proc.communicate()
Packit 7a8e5e
    status = status.decode("ascii", "replace")
Packit 7a8e5e
    for line in status.splitlines():
Packit 7a8e5e
        if line.startswith('-') or line.startswith('+'):
Packit 7a8e5e
            raise ValueError('Submodule not clean: %s' % line)
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
from distutils.command.sdist import sdist
Packit 7a8e5e
class sdist_checked(sdist):
Packit 7a8e5e
    """ check submodules on sdist to prevent incomplete tarballs """
Packit 7a8e5e
    def run(self):
Packit 7a8e5e
        check_submodules()
Packit 7a8e5e
        sdist.run(self)
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def generate_cython():
Packit 7a8e5e
    cwd = os.path.abspath(os.path.dirname(__file__))
Packit 7a8e5e
    print("Cythonizing sources")
Packit 7a8e5e
    p = subprocess.call([sys.executable,
Packit 7a8e5e
                          os.path.join(cwd, 'tools', 'cythonize.py'),
Packit 7a8e5e
                          'numpy/random'],
Packit 7a8e5e
                         cwd=cwd)
Packit 7a8e5e
    if p != 0:
Packit 7a8e5e
        raise RuntimeError("Running cythonize failed!")
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def parse_setuppy_commands():
Packit 7a8e5e
    """Check the commands and respond appropriately.  Disable broken commands.
Packit 7a8e5e
Packit 7a8e5e
    Return a boolean value for whether or not to run the build or not (avoid
Packit 7a8e5e
    parsing Cython and template files if False).
Packit 7a8e5e
    """
Packit 7a8e5e
    if len(sys.argv) < 2:
Packit 7a8e5e
        # User forgot to give an argument probably, let setuptools handle that.
Packit 7a8e5e
        return True
Packit 7a8e5e
Packit 7a8e5e
    info_commands = ['--help-commands', '--name', '--version', '-V',
Packit 7a8e5e
                     '--fullname', '--author', '--author-email',
Packit 7a8e5e
                     '--maintainer', '--maintainer-email', '--contact',
Packit 7a8e5e
                     '--contact-email', '--url', '--license', '--description',
Packit 7a8e5e
                     '--long-description', '--platforms', '--classifiers',
Packit 7a8e5e
                     '--keywords', '--provides', '--requires', '--obsoletes']
Packit 7a8e5e
    # Add commands that do more than print info, but also don't need Cython and
Packit 7a8e5e
    # template parsing.
Packit 7a8e5e
    info_commands.extend(['egg_info', 'install_egg_info', 'rotate'])
Packit 7a8e5e
Packit 7a8e5e
    for command in info_commands:
Packit 7a8e5e
        if command in sys.argv[1:]:
Packit 7a8e5e
            return False
Packit 7a8e5e
Packit 7a8e5e
    # Note that 'alias', 'saveopts' and 'setopt' commands also seem to work
Packit 7a8e5e
    # fine as they are, but are usually used together with one of the commands
Packit 7a8e5e
    # below and not standalone.  Hence they're not added to good_commands.
Packit 7a8e5e
    good_commands = ('develop', 'sdist', 'build', 'build_ext', 'build_py',
Packit 7a8e5e
                     'build_clib', 'build_scripts', 'bdist_wheel', 'bdist_rpm',
Packit 7a8e5e
                     'bdist_wininst', 'bdist_msi', 'bdist_mpkg')
Packit 7a8e5e
Packit 7a8e5e
    for command in good_commands:
Packit 7a8e5e
        if command in sys.argv[1:]:
Packit 7a8e5e
            return True
Packit 7a8e5e
Packit 7a8e5e
    # The following commands are supported, but we need to show more
Packit 7a8e5e
    # useful messages to the user
Packit 7a8e5e
    if 'install' in sys.argv[1:]:
Packit 7a8e5e
        print(textwrap.dedent("""
Packit 7a8e5e
            Note: if you need reliable uninstall behavior, then install
Packit 7a8e5e
            with pip instead of using `setup.py install`:
Packit 7a8e5e
Packit 7a8e5e
              - `pip install .`       (from a git repo or downloaded source
Packit 7a8e5e
                                       release)
Packit 7a8e5e
              - `pip install numpy`   (last NumPy release on PyPi)
Packit 7a8e5e
Packit 7a8e5e
            """))
Packit 7a8e5e
        return True
Packit 7a8e5e
Packit 7a8e5e
    if '--help' in sys.argv[1:] or '-h' in sys.argv[1]:
Packit 7a8e5e
        print(textwrap.dedent("""
Packit 7a8e5e
            NumPy-specific help
Packit 7a8e5e
            -------------------
Packit 7a8e5e
Packit 7a8e5e
            To install NumPy from here with reliable uninstall, we recommend
Packit 7a8e5e
            that you use `pip install .`. To install the latest NumPy release
Packit 7a8e5e
            from PyPi, use `pip install numpy`.
Packit 7a8e5e
Packit 7a8e5e
            For help with build/installation issues, please ask on the
Packit 7a8e5e
            numpy-discussion mailing list.  If you are sure that you have run
Packit 7a8e5e
            into a bug, please report it at https://github.com/numpy/numpy/issues.
Packit 7a8e5e
Packit 7a8e5e
            Setuptools commands help
Packit 7a8e5e
            ------------------------
Packit 7a8e5e
            """))
Packit 7a8e5e
        return False
Packit 7a8e5e
Packit 7a8e5e
    # The following commands aren't supported.  They can only be executed when
Packit 7a8e5e
    # the user explicitly adds a --force command-line argument.
Packit 7a8e5e
    bad_commands = dict(
Packit 7a8e5e
        test="""
Packit 7a8e5e
            `setup.py test` is not supported.  Use one of the following
Packit 7a8e5e
            instead:
Packit 7a8e5e
Packit 7a8e5e
              - `python runtests.py`              (to build and test)
Packit 7a8e5e
              - `python runtests.py --no-build`   (to test installed numpy)
Packit 7a8e5e
              - `>>> numpy.test()`           (run tests for installed numpy
Packit 7a8e5e
                                              from within an interpreter)
Packit 7a8e5e
            """,
Packit 7a8e5e
        upload="""
Packit 7a8e5e
            `setup.py upload` is not supported, because it's insecure.
Packit 7a8e5e
            Instead, build what you want to upload and upload those files
Packit 7a8e5e
            with `twine upload -s <filenames>` instead.
Packit 7a8e5e
            """,
Packit 7a8e5e
        upload_docs="`setup.py upload_docs` is not supported",
Packit 7a8e5e
        easy_install="`setup.py easy_install` is not supported",
Packit 7a8e5e
        clean="""
Packit 7a8e5e
            `setup.py clean` is not supported, use one of the following instead:
Packit 7a8e5e
Packit 7a8e5e
              - `git clean -xdf` (cleans all files)
Packit 7a8e5e
              - `git clean -Xdf` (cleans all versioned files, doesn't touch
Packit 7a8e5e
                                  files that aren't checked into the git repo)
Packit 7a8e5e
            """,
Packit 7a8e5e
        check="`setup.py check` is not supported",
Packit 7a8e5e
        register="`setup.py register` is not supported",
Packit 7a8e5e
        bdist_dumb="`setup.py bdist_dumb` is not supported",
Packit 7a8e5e
        bdist="`setup.py bdist` is not supported",
Packit 7a8e5e
        build_sphinx="""
Packit 7a8e5e
            `setup.py build_sphinx` is not supported, use the
Packit 7a8e5e
            Makefile under doc/""",
Packit 7a8e5e
        flake8="`setup.py flake8` is not supported, use flake8 standalone",
Packit 7a8e5e
        )
Packit 7a8e5e
    bad_commands['nosetests'] = bad_commands['test']
Packit 7a8e5e
    for command in ('upload_docs', 'easy_install', 'bdist', 'bdist_dumb',
Packit 7a8e5e
                     'register', 'check', 'install_data', 'install_headers',
Packit 7a8e5e
                     'install_lib', 'install_scripts', ):
Packit 7a8e5e
        bad_commands[command] = "`setup.py %s` is not supported" % command
Packit 7a8e5e
Packit 7a8e5e
    for command in bad_commands.keys():
Packit 7a8e5e
        if command in sys.argv[1:]:
Packit 7a8e5e
            print(textwrap.dedent(bad_commands[command]) +
Packit 7a8e5e
                  "\nAdd `--force` to your command to use it anyway if you "
Packit 7a8e5e
                  "must (unsupported).\n")
Packit 7a8e5e
            sys.exit(1)
Packit 7a8e5e
Packit 7a8e5e
    # If we got here, we didn't detect what setup.py command was given
Packit 7a8e5e
    import warnings
Packit 7a8e5e
    warnings.warn("Unrecognized setuptools command, proceeding with "
Packit 7a8e5e
                  "generating Cython sources and expanding templates", stacklevel=2)
Packit 7a8e5e
    return True
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
def setup_package():
Packit 7a8e5e
    src_path = os.path.dirname(os.path.abspath(sys.argv[0]))
Packit 7a8e5e
    old_path = os.getcwd()
Packit 7a8e5e
    os.chdir(src_path)
Packit 7a8e5e
    sys.path.insert(0, src_path)
Packit 7a8e5e
Packit 7a8e5e
    # Rewrite the version file everytime
Packit 7a8e5e
    write_version_py()
Packit 7a8e5e
Packit 7a8e5e
    metadata = dict(
Packit 7a8e5e
        name = 'numpy',
Packit 7a8e5e
        maintainer = "NumPy Developers",
Packit 7a8e5e
        maintainer_email = "numpy-discussion@python.org",
Packit 7a8e5e
        description = DOCLINES[0],
Packit 7a8e5e
        long_description = "\n".join(DOCLINES[2:]),
Packit 7a8e5e
        url = "http://www.numpy.org",
Packit 7a8e5e
        author = "Travis E. Oliphant et al.",
Packit 7a8e5e
        download_url = "https://pypi.python.org/pypi/numpy",
Packit 7a8e5e
        license = 'BSD',
Packit 7a8e5e
        classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f],
Packit 7a8e5e
        platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
Packit 7a8e5e
        test_suite='nose.collector',
Packit 7a8e5e
        cmdclass={"sdist": sdist_checked},
Packit 7a8e5e
        python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
Packit 7a8e5e
    )
Packit 7a8e5e
Packit 7a8e5e
    if "--force" in sys.argv:
Packit 7a8e5e
        run_build = True
Packit 7a8e5e
        sys.argv.remove('--force')
Packit 7a8e5e
    else:
Packit 7a8e5e
        # Raise errors for unsupported commands, improve help output, etc.
Packit 7a8e5e
        run_build = parse_setuppy_commands()
Packit 7a8e5e
Packit 7a8e5e
    from setuptools import setup
Packit 7a8e5e
    if run_build:
Packit 7a8e5e
        from numpy.distutils.core import setup
Packit 7a8e5e
        cwd = os.path.abspath(os.path.dirname(__file__))
Packit 7a8e5e
        if not os.path.exists(os.path.join(cwd, 'PKG-INFO')):
Packit 7a8e5e
            # Generate Cython sources, unless building from source release
Packit 7a8e5e
            generate_cython()
Packit 7a8e5e
Packit 7a8e5e
        metadata['configuration'] = configuration
Packit 7a8e5e
    else:
Packit 7a8e5e
        # Version number is added to metadata inside configuration() if build
Packit 7a8e5e
        # is run.
Packit 7a8e5e
        metadata['version'] = get_version_info()[0]
Packit 7a8e5e
Packit 7a8e5e
    try:
Packit 7a8e5e
        setup(**metadata)
Packit 7a8e5e
    finally:
Packit 7a8e5e
        del sys.path[0]
Packit 7a8e5e
        os.chdir(old_path)
Packit 7a8e5e
    return
Packit 7a8e5e
Packit 7a8e5e
Packit 7a8e5e
if __name__ == '__main__':
Packit 7a8e5e
    setup_package()
Packit 7a8e5e
    # This may avoid problems where numpy is installed via ``*_requires`` by
Packit 7a8e5e
    # setuptools, the global namespace isn't reset properly, and then numpy is
Packit 7a8e5e
    # imported later (which will then fail to load numpy extension modules).
Packit 7a8e5e
    # See gh-7956 for details
Packit 7a8e5e
    del builtins.__NUMPY_SETUP__