blob: c2e46675a26b0c14349bc8f970cf6d9c0449b807 [file] [log] [blame]
#!/usr/bin/env python
import glob
import os
import os.path
import sys
if sys.version_info < (3, 6, 0):
sys.stderr.write("ERROR: You need Python 3.6 or later to use mypy.\n")
exit(1)
# we'll import stuff from the source tree, let's ensure is on the sys path
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
# This requires setuptools when building; setuptools is not needed
# when installing from a wheel file (though it is still needed for
# alternative forms of installing, as suggested by README.md).
from setuptools import setup, find_packages
from setuptools.command.build_py import build_py
from mypy.version import __version__ as version
description = 'Optional static typing for Python'
long_description = '''
Mypy -- Optional Static Typing for Python
=========================================
Add type annotations to your Python programs, and use mypy to type
check them. Mypy is essentially a Python linter on steroids, and it
can catch many programming errors by analyzing your program, without
actually having to run it. Mypy has a powerful type system with
features such as type inference, gradual typing, generics and union
types.
'''.lstrip()
def find_package_data(base, globs, root='mypy'):
"""Find all interesting data files, for setup(package_data=)
Arguments:
root: The directory to search in.
globs: A list of glob patterns to accept files.
"""
rv_dirs = [root for root, dirs, files in os.walk(base)]
rv = []
for rv_dir in rv_dirs:
files = []
for pat in globs:
files += glob.glob(os.path.join(rv_dir, pat))
if not files:
continue
rv.extend([os.path.relpath(f, root) for f in files])
return rv
class CustomPythonBuild(build_py):
def pin_version(self):
path = os.path.join(self.build_lib, 'mypy')
self.mkpath(path)
with open(os.path.join(path, 'version.py'), 'w') as stream:
stream.write('__version__ = "{}"\n'.format(version))
def run(self):
self.execute(self.pin_version, ())
build_py.run(self)
cmdclass = {'build_py': CustomPythonBuild}
package_data = ['py.typed']
package_data += find_package_data(os.path.join('mypy', 'typeshed'), ['*.py', '*.pyi'])
package_data += [os.path.join('mypy', 'typeshed', 'stdlib', 'VERSIONS')]
package_data += find_package_data(os.path.join('mypy', 'xml'), ['*.xsd', '*.xslt', '*.css'])
USE_MYPYC = False
# To compile with mypyc, a mypyc checkout must be present on the PYTHONPATH
if len(sys.argv) > 1 and sys.argv[1] == '--use-mypyc':
sys.argv.pop(1)
USE_MYPYC = True
if os.getenv('MYPY_USE_MYPYC', None) == '1':
USE_MYPYC = True
if USE_MYPYC:
MYPYC_BLACKLIST = tuple(os.path.join('mypy', x) for x in (
# Need to be runnable as scripts
'__main__.py',
'pyinfo.py',
os.path.join('dmypy', '__main__.py'),
# Uses __getattr__/__setattr__
'split_namespace.py',
# Lies to mypy about code reachability
'bogus_type.py',
# We don't populate __file__ properly at the top level or something?
# Also I think there would be problems with how we generate version.py.
'version.py',
# Skip these to reduce the size of the build
'stubtest.py',
'stubgenc.py',
'stubdoc.py',
'stubutil.py',
)) + (
# Don't want to grab this accidentally
os.path.join('mypyc', 'lib-rt', 'setup.py'),
# Uses __file__ at top level https://github.com/mypyc/mypyc/issues/700
os.path.join('mypyc', '__main__.py'),
)
everything = (
[os.path.join('mypy', x) for x in find_package_data('mypy', ['*.py'])] +
[os.path.join('mypyc', x) for x in find_package_data('mypyc', ['*.py'], root='mypyc')])
# Start with all the .py files
all_real_pys = [x for x in everything
if not x.startswith(os.path.join('mypy', 'typeshed') + os.sep)]
# Strip out anything in our blacklist
mypyc_targets = [x for x in all_real_pys if x not in MYPYC_BLACKLIST]
# Strip out any test code
mypyc_targets = [x for x in mypyc_targets
if not x.startswith((os.path.join('mypy', 'test') + os.sep,
os.path.join('mypyc', 'test') + os.sep,
os.path.join('mypyc', 'doc') + os.sep,
os.path.join('mypyc', 'test-data') + os.sep,
))]
# ... and add back in the one test module we need
mypyc_targets.append(os.path.join('mypy', 'test', 'visitors.py'))
# The targets come out of file system apis in an unspecified
# order. Sort them so that the mypyc output is deterministic.
mypyc_targets.sort()
use_other_mypyc = os.getenv('ALTERNATE_MYPYC_PATH', None)
if use_other_mypyc:
# This bit is super unfortunate: we want to use a different
# mypy/mypyc version, but we've already imported parts, so we
# remove the modules that we've imported already, which will
# let the right versions be imported by mypyc.
del sys.modules['mypy']
del sys.modules['mypy.version']
del sys.modules['mypy.git']
sys.path.insert(0, use_other_mypyc)
from mypyc.build import mypycify
opt_level = os.getenv('MYPYC_OPT_LEVEL', '3')
debug_level = os.getenv('MYPYC_DEBUG_LEVEL', '1')
force_multifile = os.getenv('MYPYC_MULTI_FILE', '') == '1'
ext_modules = mypycify(
mypyc_targets + ['--config-file=mypy_bootstrap.ini'],
opt_level=opt_level,
debug_level=debug_level,
# Use multi-file compilation mode on windows because without it
# our Appveyor builds run out of memory sometimes.
multi_file=sys.platform == 'win32' or force_multifile,
)
else:
ext_modules = []
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Topic :: Software Development',
]
setup(name='mypy',
version=version,
description=description,
long_description=long_description,
author='Jukka Lehtosalo',
author_email='jukka.lehtosalo@iki.fi',
url='http://www.mypy-lang.org/',
license='MIT License',
py_modules=[],
ext_modules=ext_modules,
packages=find_packages(),
package_data={'mypy': package_data},
entry_points={'console_scripts': ['mypy=mypy.__main__:console_entry',
'stubgen=mypy.stubgen:main',
'stubtest=mypy.stubtest:main',
'dmypy=mypy.dmypy.client:console_entry',
'mypyc=mypyc.__main__:main',
]},
classifiers=classifiers,
cmdclass=cmdclass,
# When changing this, also update mypy-requirements.txt.
install_requires=["typed_ast >= 1.4.0, < 2; python_version<'3.8'",
'typing_extensions>=3.10',
'mypy_extensions >= 0.4.3',
"tomli>=1.1.0; python_version<'3.11'",
],
# Same here.
extras_require={
'dmypy': 'psutil >= 4.0',
'python2': 'typed_ast >= 1.4.0, < 2',
'reports': 'lxml'
},
python_requires=">=3.6",
include_package_data=True,
project_urls={
'News': 'http://mypy-lang.org/news.html',
'Documentation': 'https://mypy.readthedocs.io/en/stable/introduction.html',
'Repository': 'https://github.com/python/mypy',
},
)