#!/usr/bin/env python import glob import os import os.path import sys if sys.version_info < (3, 5, 0): sys.stderr.write("ERROR: You need Python 3.5 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', 'sitepkgs.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'), ) 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') force_multifile = os.getenv('MYPYC_MULTI_FILE', '') == '1' ext_modules = mypycify( mypyc_targets + ['--config-file=mypy_bootstrap.ini'], opt_level=opt_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.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', '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}, scripts=['scripts/mypyc'], entry_points={'console_scripts': ['mypy=mypy.__main__:console_entry', 'stubgen=mypy.stubgen:main', 'stubtest=mypy.stubtest:main', 'dmypy=mypy.dmypy.client:console_entry', ]}, classifiers=classifiers, cmdclass=cmdclass, # When changing this, also update mypy-requirements.txt. install_requires=["typed_ast >= 1.4.0, < 1.5.0; python_version<'3.8'", 'typing_extensions>=3.7.4', 'mypy_extensions >= 0.4.3, < 0.5.0', 'toml', ], # Same here. extras_require={'dmypy': 'psutil >= 4.0', 'python2': 'typed_ast >= 1.4.0, < 1.5.0'}, python_requires=">=3.5", include_package_data=True, project_urls={ 'News': 'http://mypy-lang.org/news.html', }, )