Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
from mypy.indirection import TypeIndirectionVisitor
from mypy.errors import Errors, CompileError, report_internal_error
from mypy.util import DecodeError, decode_python_encoding, is_sub_path
from mypy.report import Reports
if MYPY:
from mypy.report import Reports # Avoid unconditional slow import
from mypy import moduleinfo
from mypy.fixup import fixup_module
from mypy.modulefinder import BuildSource, compute_search_paths, FindModuleCache, SearchPaths
Expand All @@ -50,7 +51,6 @@
from mypy.version import __version__
from mypy.plugin import Plugin, ChainedPlugin, plugin_types
from mypy.plugins.default import DefaultPlugin
from mypy.server.deps import get_dependencies
from mypy.fscache import FileSystemCache
from mypy.metastore import MetadataStore, FilesystemMetadataStore, SqliteMetadataStore
from mypy.typestate import TypeState, reset_global_state
Expand Down Expand Up @@ -182,7 +182,12 @@ def _build(sources: List[BuildSource],

search_paths = compute_search_paths(sources, options, data_dir, alt_lib_path)

reports = Reports(data_dir, options.report_dirs)
reports = None
if options.report_dirs:
# Import lazily to avoid slowing down startup.
from mypy.report import Reports # noqa
reports = Reports(data_dir, options.report_dirs)

source_set = BuildSourceSet(sources)
errors = Errors(options.show_error_context, options.show_column_numbers)
plugin, snapshot = load_plugins(options, errors)
Expand Down Expand Up @@ -214,8 +219,9 @@ def _build(sources: List[BuildSource],
(time.time() - manager.start_time,
len(manager.modules),
manager.errors.num_messages()))
# Finish the HTML or XML reports even if CompileError was raised.
reports.finish()
if reports is not None:
# Finish the HTML or XML reports even if CompileError was raised.
reports.finish()


def default_data_dir() -> str:
Expand Down Expand Up @@ -473,7 +479,7 @@ def __init__(self, data_dir: str,
search_paths: SearchPaths,
ignore_prefix: str,
source_set: BuildSourceSet,
reports: Reports,
reports: Optional['Reports'],
options: Options,
version_id: str,
plugin: Plugin,
Expand Down Expand Up @@ -504,10 +510,11 @@ def __init__(self, data_dir: str,
self.stale_modules = set() # type: Set[str]
self.rechecked_modules = set() # type: Set[str]
self.flush_errors = flush_errors
has_reporters = reports is not None and reports.reporters
self.cache_enabled = (options.incremental
and (not options.fine_grained_incremental
or options.use_fine_grained_cache)
and not reports.reporters)
and not has_reporters)
self.fscache = fscache
self.find_module_cache = FindModuleCache(self.search_paths, self.fscache, self.options)
if options.sqlite_cache:
Expand Down Expand Up @@ -679,7 +686,7 @@ def report_file(self,
file: MypyFile,
type_map: Dict[Expression, Type],
options: Options) -> None:
if self.source_set.is_source(file):
if self.reports is not None and self.source_set.is_source(file):
self.reports.file(file, type_map, options)

def stats_summary(self) -> Mapping[str, object]:
Expand Down Expand Up @@ -1845,6 +1852,7 @@ def compute_fine_grained_deps(self) -> None:
# TODO: Not a reliable test, as we could have a package named typeshed.
# TODO: Consider relaxing this -- maybe allow some typeshed changes to be tracked.
return
from mypy.server.deps import get_dependencies # Lazy import to speed up startup
self.fine_grained_deps = get_dependencies(target=self.tree,
type_map=self.type_map(),
python_version=self.options.python_version,
Expand Down
14 changes: 14 additions & 0 deletions mypy/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@
SHARED_CONFIG_FILES = ('setup.cfg',) # type: Final
USER_CONFIG_FILES = ('~/.mypy.ini',) # type: Final
CONFIG_FILES = (CONFIG_FILE,) + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final

# This must include all reporters defined in mypy.report. This is defined here
# to make reporter names available without importing mypy.report -- this speeds
# up startup.
REPORTER_NAMES = ['linecount',
'any-exprs',
'linecoverage',
'memory-xml',
'cobertura-xml',
'xml',
'xslt-html',
'xslt-txt',
'html',
'txt'] # type: Final
5 changes: 2 additions & 3 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from mypy.fscache import FileSystemCache
from mypy.errors import CompileError
from mypy.options import Options, BuildType, PER_MODULE_OPTIONS
from mypy.report import reporter_classes

from mypy.version import __version__

Expand Down Expand Up @@ -606,7 +605,7 @@ def add_invertible_flag(flag: str,
report_group = parser.add_argument_group(
title='Report generation',
description='Generate a report in the specified format.')
for report_type in sorted(reporter_classes):
for report_type in sorted(defaults.REPORTER_NAMES):
report_group.add_argument('--%s-report' % report_type.replace('_', '-'),
metavar='DIR',
dest='special-opts:%s_report' % report_type)
Expand Down Expand Up @@ -968,7 +967,7 @@ def parse_section(prefix: str, template: Options,
if dv is None:
if key.endswith('_report'):
report_type = key[:-7].replace('_', '-')
if report_type in reporter_classes:
if report_type in defaults.REPORTER_NAMES:
report_dirs[report_type] = section[key]
else:
print("%s: Unrecognized report type: %s" % (prefix, key),
Expand Down
5 changes: 5 additions & 0 deletions mypy/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from mypy.traverser import TraverserVisitor
from mypy.types import Type, TypeOfAny
from mypy.version import __version__
from mypy.defaults import REPORTER_NAMES

MYPY = False
if MYPY:
Expand Down Expand Up @@ -749,3 +750,7 @@ def on_finish(self) -> None:

alias_reporter('xslt-html', 'html')
alias_reporter('xslt-txt', 'txt')

# Reporter class names are defined twice to speed up mypy startup, as this
# module is slow to import. Ensure that the two definitions match.
assert set(reporter_classes) == set(REPORTER_NAMES)
5 changes: 2 additions & 3 deletions mypy/util.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"""Utility functions with no non-trivial dependencies."""
import inspect
import os
import pathlib
import re
import subprocess
import sys
from xml.sax.saxutils import escape
from typing import TypeVar, List, Tuple, Optional, Dict, Sequence

MYPY = False
Expand Down Expand Up @@ -143,7 +141,7 @@ def try_find_python2_interpreter() -> Optional[str]:


def write_junit_xml(dt: float, serious: bool, messages: List[str], path: str) -> None:
"""XXX"""
from xml.sax.saxutils import escape
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, I thought I had already made this change.

if not messages and not serious:
xml = PASS_TEMPLATE.format(time=dt)
elif not serious:
Expand Down Expand Up @@ -205,6 +203,7 @@ def correct_relative_import(cur_mod_id: str,


def get_class_descriptors(cls: 'Type[object]') -> Sequence[str]:
import inspect # Lazy import for minor startup speed win
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What were you timing? I think get_class_descriptors is unfortunately actually on the path for a lot of stuff, even not the daemon, so I suspect this won't speed up real workloads? Though I'm not sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have been timing mypy --help for this. I timed other changes by type checking a small program. Since this is a very small change I think it's okay to keep it even if it doesn't help in any realistic scenarios.

# Maintain a cache of type -> attributes defined by descriptors in the class
# (that is, attributes from __slots__ and C extension classes)
if cls not in fields_cache:
Expand Down