Skip to content

Commit

Permalink
Support invoking mypy from setuptools
Browse files Browse the repository at this point in the history
By default, this will typecheck all of the package modules.
We still need to figure out how to handle third-party modules.
Passing in `--mypy-args="--use-python-path"` will also include
any dependent modules, but nearly all of them fail to typecheck.

This will fix python#992
  • Loading branch information
Roy Williams committed Nov 24, 2015
1 parent ea1bcfe commit 848654a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
4 changes: 4 additions & 0 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def default_data_dir(bin_dir: str) -> str:
# TODO fix this logic
if not bin_dir:
# Default to directory containing this file's parent.
grandparent_dir = os.path.dirname(os.path.dirname(__file__))
# Running from within an egg, likely from setuptools.
if grandparent_dir.endswith('.egg'):
return os.path.join(grandparent_dir, 'lib', 'mypy')
return os.path.dirname(os.path.dirname(__file__))
base = os.path.basename(bin_dir)
dir = os.path.dirname(bin_dir)
Expand Down
42 changes: 42 additions & 0 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import os
import os.path
import shlex
import shutil
import subprocess
import sys
import tempfile

import setuptools as setuptools # type: ignore

import typing
from typing import Dict, List, Tuple

Expand All @@ -31,6 +34,45 @@ def __init__(self) -> None:
self.dirty_stubs = False


class MyPyCommand(setuptools.Command):
"""The :class:`MyPyCommand` class is used by setuptools to perform
type checks on registered modules.
"""

description = "Validate PEP 0484 Types with mypy"
user_options = [
('mypy-args=', None, 'Arguments to pass through to mypy')
] # type: List[tuple]

def initialize_options(self):
self.mypy_args = ''

def finalize_options(self):
pass

def run(self):
try:
mypy_options = []
for package in set(self.distribution.packages):
mypy_options.append('--package')
mypy_options.append(package)
mypy_options.extend(shlex.split(self.mypy_args))
sources, options = process_options(mypy_options)
# If the user has requested to use the python_path during analysis,
# fetch all required eggs (This will also add them to sys.path).
# This will ensure mypy behaves as if the package were installed
# globally without having to globally install it to modify
# PYTHONPATH
if options.python_path and self.distribution.install_requires:
self.distribution.fetch_build_eggs(
self.distribution.install_requires)
type_check_only(sources, None, options)
except CompileError as e:
for m in e.messages:
sys.stderr.write(m + '\n')
sys.exit(1)


def main(script_path: str) -> None:
"""Main entry point to the type checker.
Expand Down
10 changes: 9 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os.path
import sys

from distutils.core import setup
from setuptools import setup
from mypy.version import __version__
from mypy import git

Expand Down Expand Up @@ -69,6 +69,13 @@ def find_data_files(base, globs):
'Topic :: Software Development',
]

entry_points = {
'distutils.commands': [
'mypy = mypy.main:MyPyCommand'
]
}


setup(name='mypy-lang',
version=version,
description=description,
Expand All @@ -84,4 +91,5 @@ def find_data_files(base, globs):
scripts=['scripts/mypy'],
data_files=data_files,
classifiers=classifiers,
entry_points=entry_points,
)

0 comments on commit 848654a

Please sign in to comment.