8000 Various improvements to stubgen by JukkaL · Pull Request #7921 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Various improvements to stubgen #7921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
aa0673f
Stubgen: Remove misplaced type comments before parsing
JukkaL Apr 11, 2019
ae33876
stubgen: Don't fail if docstring cannot be tokenized
JukkaL Apr 11, 2019
80108d3
stubgen: Handle None value for __file__
JukkaL Apr 12, 2019
37a1ab9
stubgen: Fix None-related crash
JukkaL Apr 12, 2019
020b11f
stubgen: Attempt to fix namespace packages
JukkaL Apr 12, 2019
e1de866
stubgen: Add --verbose and --quiet flags
JukkaL Apr 12, 2019
4473075
stubgen: Use __init__.pyi for C modules when needed
JukkaL Apr 12, 2019
3a0986d
stubgen: If we can't import a module, give more information
JukkaL Apr 12, 2019
049a2a4
stubgen: Work around crash
JukkaL Apr 12, 2019
bbf6268
stubgen: Don't fail if a class has a cyclic MRO
JukkaL Apr 12, 2019
a3ebf3c
stubgen: Log runtime imports in verbose mode
JukkaL Apr 12, 2019
a3a35fe
stubgen: More verbose output
JukkaL Apr 12, 2019
e287301
stubgen: Skip certain special cased packages
JukkaL Apr 12, 2019
819a77d
stubgen: Filter out additional things that look like type comments
JukkaL Apr 12, 2019
02d4184
stubgen: Survive inconsistent MROs
JukkaL Apr 12, 2019
67142d6
stubgen: Remove message when there are only C modules
JukkaL Apr 12, 2019
bc3ca08
Fix rebase issue
JukkaL Nov 4, 2019
b1814d9
Fix after rebase
JukkaL Nov 4, 2019
6f4a1fe
Add missing stuff
JukkaL Nov 4, 2019
25e3258
Fix signatures generated by stubgen for various dunder C methods
JukkaL Apr 10, 2019
c9d2987
Add missing line
JukkaL Nov 4, 2019
8777b5f
Ignore unreachable code in stubgen to avoid crashes
JukkaL Apr 9, 2019
5ccd902
Fix C dunder method inference tests
JukkaL Nov 4, 2019
09f1b13
Preserve @abstractproperty in stubgen
JukkaL Apr 10, 2019
a9721ed
Stubgen: Avoid name clashes between typing.Any and class Any etc.
JukkaL Apr 10, 2019
6cefdc4
Stubgen: special case certain names to be exported
JukkaL Apr 10, 2019
95ab57c
Fix None errors
JukkaL Nov 4, 2019
156fe17
Add some docstrings and comments to stubgen tests
JukkaL Apr 10, 2019
9b802e3
Stubgen: Generate exports for imported names that aren't referenced
JukkaL Apr 10, 2019
d7b2942
Stubgen: allow special casing internal definitions to be exported
JukkaL Apr 10, 2019
b739314
Stubgen: translate imports from vendored six to use real six
JukkaL Apr 10, 2019
add4a64
Stubgen: Remove generated header
JukkaL Apr 10, 2019
8da487d
Add unit tests for skipping blacklisted and test modules
JukkaL May 10, 2019
376513d
Add docstring
JukkaL Nov 4, 2019
41a1f22
Add test case for vendored package
JukkaL Nov 4, 2019
b6db629
Fix lint
JukkaL Nov 11, 2019
c6aca1b
Update test case
JukkaL Nov 11, 2019
3309f74
Always filter out tests
JukkaL Nov 4, 2019
575cecd
Simplify redundant note
JukkaL Nov 4, 2019
bde23a1
Skip conftest modules (used for pytest tests)
JukkaL Nov 4, 2019
b4554e6
Fix crash
JukkaL Nov 5, 2019
c84677b
Filter out more kinds of bad function type comments
JukkaL Nov 5, 2019
be7414e
Recognize more modules as test modules
JukkaL Nov 5, 2019
07e1955
Revert changes to imports
JukkaL Nov 11, 2019
e6bac88
Try to fix Windows
JukkaL Nov 11, 2019
548bb10
Attempt to fix compiled
JukkaL Nov 11, 2019
f876154
Fix lint
JukkaL Nov 11, 2019
56d1a73
Try to fix Python 3.5
JukkaL Nov 11, 2019
58ae038
Respond to feedback
JukkaL Nov 14, 2019
2989121
Merge branch 'master' into stubgen-fixes-batch
JukkaL Nov 14, 2019
073832e
Fix stuff
JukkaL Nov 14, 2019
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
Prev Previous commit
Next Next commit
stubgen: Add --verbose and --quiet flags
  • Loading branch information
JukkaL committed Nov 11, 2019
commit e1de86673011fb23df88c06ea091e7f554f9b47b
69 changes: 51 additions & 18 deletions mypy/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
from mypy.stubutil import (
write_header, default_py2_interpreter, CantImport, generate_guarded,
walk_packages, find_module_path_and_all_py2, find_module_path_and_all_py3,
report_missing, fail_missing, remove_misplaced_type_comments
report_missing, fail_missing, remove_misplaced_type_comments, common_dir_prefix
)
from mypy.stubdoc imp 8000 ort parse_all_signatures, find_unique_signatures, Sig
from mypy.options import Options as MypyOptions
Expand All @@ -96,10 +96,21 @@ class Options:

This class is mutable to simplify testing.
"""
def __init__(self, pyversion: Tuple[int, int], no_import: bool, doc_dir: str,
search_path: List[str], interpreter: str, parse_only: bool, ignore_errors: bool,
include_private: bool, output_dir: str, modules: List[str], packages: List[str],
files: List[str]) -> None:
def __init__(self,
pyversion: Tuple[int, int],
no_import: bool,
doc_dir: str,
search_path: List[str],
interpreter: str,
parse_only: bool,
ignore_errors: bool,
include_private: bool,
output_dir: str,
modules: List[str],
packages: List[str],
files: List[str],
verbose: bool,
quiet: bool) -> None:
# See parse_options for descriptions of the flags.
self.pyversion = pyversion
self.no_import = no_import
Expand All @@ -114,6 +125,8 @@ def __init__(self, pyversion: Tuple[int, int], no_import: bool, doc_dir: str,
self.modules = modules
self.packages = packages
self.files = files
self.verbose = verbose
self.quiet = quiet


class StubSource(BuildSource):
Expand Down Expand Up @@ -904,7 +917,9 @@ def collect_build_targets(options: Options, mypy_opts: MypyOptions) -> Tuple[Lis
py_modules, c_modules = find_module_paths_using_imports(options.modules,
options.packages,
options.interpreter,
options.pyversion)
options.pyversion,
options.verbose,
options.quiet)
else:
# Use mypy native source collection for files and directories.
try:
Expand All @@ -917,10 +932,12 @@ def collect_build_targets(options: Options, mypy_opts: MypyOptions) -> Tuple[Lis
return py_modules, c_modules


def find_module_paths_using_imports(modules: List[str], packages: List[str],
def find_module_paths_using_imports(modules: List[str],
packages: List[str],
interpreter: str,
pyversion: Tuple[int, int],
quiet: bool = True) -> Tuple[List[StubSource],
verbose: bool,
quiet: bool) -> Tuple[List[StubSource],
List[StubSource]]:
"""Find path and runtime value of __all__ (if possible) for modules and packages.

Expand All @@ -936,9 +953,10 @@ def find_module_paths_using_imports(modules: List[str], packages: List[str],
else:
result = find_module_path_and_all_py3(mod)
except CantImport as e:
if not quiet:
if verbose:
traceback.print_exc()
report_missing(mod, e.message)
if not quiet:
report_missing(mod, e.message)
continue
if not result:
c_modules.append(StubSource(mod))
Expand Down Expand Up @@ -1074,9 +1092,7 @@ def collect_docs_signatures(doc_dir: str) -> Tuple[Dict[str, str], Dict[str, str
return sigs, class_sigs


def generate_stubs(options: Options,
# additional args for testing
quiet: bool = False, add_header: bool = True) -> None:
def generate_stubs(options: Options) -> None:
"""Main entry point for the program."""
mypy_opts = mypy_options(options)
py_modules, c_modules = collect_build_targets(options, mypy_opts)
Expand All @@ -1088,6 +1104,7 @@ def generate_stubs(options: Options,

# Use parsed sources to generate stubs for Python modules.
generate_asts_for_modules(py_modules, options.parse_only, mypy_opts)
files = []
for mod in py_modules:
assert mod.path is not None, "Not found module was not skipped"
target = mod.module.replace('.', '/')
Expand All @@ -1096,7 +1113,8 @@ def generate_stubs(options: Options,
else:
target += '.pyi'
target = os.path.join(options.output_dir, target)
with generate_guarded(mod.module, target, options.ignore_errors, quiet):
files.append(target)
with generate_guarded(mod.module, target, options.ignore_errors, options.verbose):
generate_stub_from_ast(mod, target,
options.parse_only, options.pyversion,
options.include_private, add_header)
Expand All @@ -1105,9 +1123,16 @@ def generate_stubs(options: Options,
for mod in c_modules:
target = mod.module.replace('.', '/') + '.pyi'
target = os.path.join(options.output_dir, target)
with generate_guarded(mod.module, target, options.ignore_errors, quiet):
generate_stub_for_c_module(mod.module, target, sigs=sigs, class_sigs=class_sigs,
add_header=add_header)
files.append(target)
with generate_guarded(mod.module, target, options.ignore_errors, options.verbose):
generate_stub_for_c_module(mod.module, target, sigs=sigs, class_sigs=class_sigs, add_header=add_header)
num_modules = len(py_modules) + len(c_modules)
if not options.quiet and num_modules > 0:
print('Processed %d modules' % num_modules)
if len(files) == 1:
print('Generated %s' % files[0])
else:
print('Generated files under %s' % common_dir_prefix(files) + os.sep)


HEADER = """%(prog)s [-h] [--py2] [more options, see -h]
Expand Down Expand Up @@ -1140,6 +1165,10 @@ def parse_options(args: List[str]) -> Options:
parser.add_argument('--include-private', action='store_true',
help="generate stubs for objects and members considered private "
"(single leading underscore and no trailing underscores)")
parser.add_argument('-v', '--verbose', action='store_true',
help="show more verbose messages")
parser.add_argument('-q', '--quiet', action='store_true',
help="show fewer messages")
parser.add_argument('--doc-dir', metavar='PATH', default='',
help="use .rst documentation in PATH (this may result in "
"better stubs in some cases; consider setting this to "
Expand Down Expand Up @@ -1168,6 +1197,8 @@ def parse_options(args: List[str]) -> Options:
ns.interpreter = sys.executable if pyversion[0] == 3 else default_py2_interpreter()
if ns.modules + ns.packages and ns.files:
parser.error("May only specify one of: modules/packages or files.")
if ns.quiet and ns.verbose:
parser.error('Cannot specify both quiet and verbose messages')

# Create the output folder if it doesn't already exist.
if not os.path.exists(ns.output_dir):
Expand All @@ -1184,7 +1215,9 @@ def parse_options(args: List[str]) -> Options:
output_dir=ns.output_dir,
modules=ns.modules,
packages=ns.packages,
files=ns.files)
files=ns.files,
verbose=ns.verbose,
quiet=ns.quiet)


def main() -> None:
Expand Down
19 changes: 17 additions & 2 deletions mypy/stubutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ def find_module_path_and_all_py3(module: str) -> Optional[Tuple[str, Optional[Li

@contextmanager
def generate_guarded(mod: str, target: str,
ignore_errors: bool = True, quiet: bool = False) -> Iterator[None]:
ignore_errors: bool = True, verbose: bool = False) -> Iterator[None]:
"""Ignore or report errors during stub generation.

Optionally report success.
"""
if verbose:
print('Processing %s' % mod)
try:
yield
except Exception as e:
Expand All @@ -157,7 +159,7 @@ def generate_guarded(mod: str, target: str,
# --ignore-errors was passed
print("Stub generation failed for", mod, file=sys.stderr)
else:
if not quiet:
if verbose:
print('Created %s' % target)


Expand Down Expand Up @@ -191,3 +193,16 @@ def remove_misplaced_type_comments(source: AnyStr) -> AnyStr:
return text.encode('latin1')
else:
return text


def common_dir_prefix(paths: List[str]) -> str:
if not paths:
return '.'
cur = os.path.dirname(paths[0])
for path in paths[1:]:
while True:
path = os.path.dirname(path)
if (cur + '/').startswith(path + '/'):
cur = path
break
return cur or '.'
23 changes: 20 additions & 3 deletions mypy/test/teststubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
generate_stubs, parse_options, Options, collect_build_targets,
mypy_options
)
from mypy.stubutil import walk_packages, remove_misplaced_type_comments
from mypy.stubutil import walk_packages, remove_misplaced_type_comments, common_dir_prefix
from mypy.stubgenc import generate_c_type_stub, infer_method_sig, generate_c_function_stub
from mypy.stubdoc import (
parse_signature, parse_all_signatures, build_signature, find_unique_signatures,
Expand Down Expand Up @@ -400,6 +400,20 @@ def h():

assert_equal(remove_misplaced_type_comments(original), dest)

def test_common_dir_prefix(self) -> None:
assert common_dir_prefix([]) == '.'
assert common_dir_prefix(['x.pyi']) == '.'
assert common_dir_prefix(['./x.pyi']) == '.'
assert common_dir_prefix(['foo/bar/x.pyi']) == 'foo/bar'
assert common_dir_prefix(['foo/bar/x.pyi',
'foo/bar/y.pyi']) == 'foo/bar'
assert common_dir_prefix(['foo/bar/x.pyi', 'foo/y.pyi']) == 'foo'
assert common_dir_prefix(['foo/x.pyi', 'foo/bar/y.pyi']) == 'foo'
assert common_dir_prefix(['foo/bar/zar/x.pyi', 'foo/y.pyi']) == 'foo'
assert common_dir_prefix(['foo/x.pyi', 'foo/bar/zar/y.pyi']) == 'foo'
assert common_dir_prefix(['foo/bar/zar/x.pyi', 'foo/bar/y.pyi']) == 'foo/bar'
assert common_dir_prefix(['foo/bar/x.pyi', 'foo/bar/zar/y.pyi']) == 'foo/bar'


class StubgenPythonSuite(DataSuite):
required_out_section = True
Expand Down Expand Up @@ -429,7 +443,7 @@ def run_case_inner(self, testcase: DataDrivenTestCase) -> None:
options.no_import = True
if not testcase.name.endswith('_semanal'):
options.parse_only = True
generate_stubs(options, quiet=True, add_header=False)
generate_stubs(options, add_header=False)
a = [] # type: List[str]
self.add_file(os.path.join(out_dir, 'main.pyi'), a)
except CompileError as e:
Expand All @@ -449,7 +463,10 @@ def parse_flags(self, program_text: str, extra: List[str]) -> Options:
flag_list = flags.group(1).split()
else:
flag_list = []
return parse_options(flag_list + extra)
options = parse_options(flag_list + extra)
if '--verbose' not in flag_list:
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it makes sense to add a test for this flag?

options.quiet = True
return options

def add_file(self, path: str, result: List[str]) -> None:
with open(path, encoding='utf8') as file:
Expand Down
0