Skip to content
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

Improve CLI, refactor and document stubgen #6256

Merged
merged 35 commits into from
Jan 30, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f3ec824
Add source mode and fix semanal
ilevkivskyi Jan 20, 2019
478dc42
Start the big overhaul
ilevkivskyi Jan 20, 2019
c4d9e77
Move doc related stuff to a separate module
Jan 21, 2019
09726fb
Some more cleanup
Jan 21, 2019
e465bea
Complete the main rewriting
Jan 21, 2019
9b92d37
Some more refactoring (also to simplify testing)
Jan 22, 2019
b767e3f
Add some docs
Jan 23, 2019
e65d60a
Fix existing tests
Jan 23, 2019
4c2e0e9
Merge remote-tracking branch 'upstream/master' into unify-stubgen
Jan 23, 2019
b959d42
Copy semanal changes to new semanal
Jan 23, 2019
b41b494
Some progress with tests
Jan 24, 2019
f204858
Another idea for testing
Jan 24, 2019
8c71965
Even better testing; add first semanal test
Jan 24, 2019
4011d06
Fix lint and self-check
Jan 24, 2019
f3d935f
One more test
Jan 25, 2019
6fadc15
Remove irrelevamt TODOs, add few more tests
Jan 25, 2019
cc8e108
Merge remote-tracking branch 'upstream/master' into unify-stubgen
ilevkivskyi Jan 25, 2019
3cf24da
Re-organize tests, and add few more
ilevkivskyi Jan 25, 2019
000082e
Fix self-check
ilevkivskyi Jan 25, 2019
3782291
Finish sentence in module doctring
ilevkivskyi Jan 25, 2019
01872fd
Fix tempdirs in tests
ilevkivskyi Jan 25, 2019
ac2a1cf
Fix windows
ilevkivskyi Jan 25, 2019
38f424f
One more Windows fix
Jan 25, 2019
1f41f91
A temporary change to debug Windows: DO NOT MERGE
Jan 25, 2019
ac7317d
Try reordering clean-up
Jan 25, 2019
d51d4f8
Docstring and comment fixes
Jan 25, 2019
b4ac2b4
Include private aliases only with flag
Jan 25, 2019
0549d3e
Add type argument for bare Final
Jan 25, 2019
bb00dad
Address CR
Jan 28, 2019
5544c11
Add support for abstract classes; add typeshed to paths
Jan 29, 2019
b6e366a
Sully's rst fixes
Jan 29, 2019
ded5482
Never return None from abstract methods
Jan 29, 2019
ccceb30
Merge remote-tracking branch 'upstream/master' into unify-stubgen
Jan 29, 2019
be4e8eb
The rest of the merge
Jan 29, 2019
84c1926
Fix lint
Jan 29, 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
42 changes: 33 additions & 9 deletions mypy/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
from collections import defaultdict

from typing import (
Any, List, Dict, Tuple, Iterable, Mapping, Optional, NamedTuple, Set, cast
Any, List, Dict, Tuple, Iterable, Mapping, Optional, Set, cast
)

import mypy.build
Expand All @@ -62,13 +62,13 @@
import mypy.traverser
import mypy.util
from mypy import defaults
from mypy.modulefinder import FindModuleCache, SearchPaths, BuildSource
from mypy.modulefinder import FindModuleCache, SearchPaths, BuildSource, default_lib_path
from mypy.nodes import (
Expression, IntExpr, UnaryExpr, StrExpr, BytesExpr, NameExpr, FloatExpr, MemberExpr,
TupleExpr, ListExpr, ComparisonExpr, CallExpr, IndexExpr, EllipsisExpr,
ClassDef, MypyFile, Decorator, AssignmentStmt, TypeInfo,
IfStmt, ReturnStmt, ImportAll, ImportFrom, Import, FuncDef, FuncBase, TempNode,
ARG_POS, ARG_STAR, ARG_STAR2, ARG_NAMED, ARG_NAMED_OPT, NamedTupleExpr
ARG_POS, ARG_STAR, ARG_STAR2, ARG_NAMED, ARG_NAMED_OPT
)
from mypy.stubgenc import generate_stub_for_c_module
from mypy.stubutil import (
Expand Down Expand Up @@ -210,8 +210,6 @@ def visit_name_expr(self, node: NameExpr) -> str:
return node.name

def visit_member_expr(self, o: MemberExpr) -> str:
if not self.stubgen.analyzed:
return super().visit_member_expr(o)
node = o # type: Expression
trailer = ''
while isinstance(node, MemberExpr):
Expand Down Expand Up @@ -429,6 +427,10 @@ def visit_func_def(self, o: FuncDef) -> None:
retname = None
if isinstance(o.unanalyzed_type, CallableType):
retname = self.print_annotation(o.unanalyzed_type.ret_type)
elif isinstance(o, FuncDef) and o.is_abstract:
# Always assume abstract methods return Any unless explicitly annotated.
retname = 'Any'
self.add_typing_import("Any")
elif o.name() == '__init__' or not has_return_statement(o):
retname = 'None'
retfield = ''
Expand All @@ -452,9 +454,20 @@ def visit_decorator(self, o: Decorator) -> None:
'asyncio.coroutines',
'types'):
self.add_coroutine_decorator(o.func, decorator.name, decorator.name)
elif (self.import_tracker.module_for.get(decorator.name) == 'abc' and
(decorator.name == 'abstractmethod' or
self.import_tracker.reverse_alias.get(decorator.name) == 'abstractmethod')):
self.add('%s@%s\n' % (self._indent, decorator.name))
self.import_tracker.require_name(decorator.name)
elif isinstance(decorator, MemberExpr):
if decorator.name == 'setter' and isinstance(decorator.expr, NameExpr):
self.add('%s@%s.setter\n' % (self._indent, decorator.expr.name))
elif (isinstance(decorator.expr, NameExpr) and
(decorator.expr.name == 'abc' or
self.import_tracker.reverse_alias.get('abc')) and
decorator.name == 'abstractmethod'):
self.import_tracker.require_name(decorator.expr.name)
self.add('%s@%s.%s\n' % (self._indent, decorator.expr.name, decorator.name))
elif decorator.name == 'coroutine':
if (isinstance(decorator.expr, MemberExpr) and
decorator.expr.name == 'coroutines' and
Expand Down Expand Up @@ -484,9 +497,17 @@ def visit_class_def(self, o: ClassDef) -> None:
self.record_name(o.name)
base_types = self.get_base_types(o)
if base_types:
self.add('(%s)' % ', '.join(base_types))
for base in base_types:
self.import_tracker.require_name(base)
if isinstance(o.metaclass, (NameExpr, MemberExpr)):
meta = o.metaclass.accept(AliasPrinter(self))
base_types.append('metaclass=' + meta)
elif self.analyzed and o.info.is_abstract:
base_types.append('metaclass=abc.ABCMeta')
self.import_tracker.add_import('abc')
self.import_tracker.require_name('abc')
if base_types:
self.add('(%s)' % ', '.join(base_types))
self.add(':\n')
n = len(self._output)
self._indent += ' '
Expand Down Expand Up @@ -867,7 +888,8 @@ def collect_build_targets(options: Options, mypy_opts: MypyOptions) -> Tuple[Lis
if options.no_import:
py_modules = find_module_paths_using_search(options.modules,
options.packages,
options.search_path)
options.search_path,
options.pyversion)
c_modules = [] # type: List[StubSource]
else:
# Using imports is the default, since we can also find C modules.
Expand Down Expand Up @@ -919,15 +941,17 @@ def find_module_paths_using_imports(modules: List[str], packages: List[str],


def find_module_paths_using_search(modules: List[str], packages: List[str],
search_path: List[str]) -> List[StubSource]:
search_path: List[str],
pyversion: Tuple[int, int]) -> List[StubSource]:
"""Find sources for modules and packages requested.

This function just looks for source files at the file system level.
This is used if user passes --no-import, and will not find C modules.
Exit if some of the modules or packages can't be found.
"""
result = [] # type: List[StubSource]
search_paths = SearchPaths(('.',) + tuple(search_path), (), (), ())
typeshed_path = default_lib_path(mypy.build.default_data_dir(), pyversion, None)
search_paths = SearchPaths(('.',) + tuple(search_path), (), (), tuple(typeshed_path))
cache = FindModuleCache(search_paths)
for module in modules:
module_path = cache.find_module(module)
Expand Down
53 changes: 53 additions & 0 deletions test-data/unit/stubgen.test
Original file line number Diff line number Diff line change
Expand Up @@ -1382,3 +1382,56 @@ from typing import Any, Dict

funcs: Dict[Any, Any]
f: Any

[case testAbstractMethodNameExpr]
from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):
@abstractmethod
def meth(self):
pass
[out]
from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):
@abstractmethod
def meth(self) -> None: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should the return type be Any?

Copy link
Member Author

Choose a reason for hiding this comment

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

The return is Any only if we run semantic analyzer (test name should end in _semanal), see a test below. But on the second thought it looks like it is not always necessary, in most common cases (like when we add the decorator here) it is better to return Any. I will fix this now.


[case testAbstractMethodMemberExpr]
import abc

class A(metaclass=abc.ABCMeta):
@abc.abstractmethod
def meth(self):
pass
[out]
import abc

class A(metaclass=abc.ABCMeta):
@abc.abstractmethod
def meth(self) -> None: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, should the return type be Any?


[case testABCMeta_semanal]
from base import base
from abc import abstractmethod

class C(Base):
@abstractmethod
def other(self):
pass

[file base.py]
from abc import abstractmethod, ABCMeta

class Base(metaclass=ABCMeta):
@abstractmethod
def meth(self):
pass
[out]
import abc
from abc import abstractmethod
from typing import Any

class C(Base, metaclass=abc.ABCMeta):
@abstractmethod
def other(self) -> Any: ...