Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5700456

Browse files
authored
Add machinery for marking places we subvert the type system (#5467)
We need this for compiling with mypyc, which inserts runtime typechecks that cause problems when we subvert the type system. So when compiling with mypyc, we turn those places into Any, while keeping the types around for normal typechecks. Since this causes the runtype types to be Any, this is best used in places where efficient access to properties is not important. For those cases some other technique should be used.
1 parent 9093291 commit 5700456

8 files changed

Lines changed: 80 additions & 37 deletions

File tree

mypy/bogus_type.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""A Bogus[T] type alias for marking when we subvert the type system
2+
3+
We need this for compiling with mypyc, which inserts runtime
4+
typechecks that cause problems when we subvert the type system. So
5+
when compiling with mypyc, we turn those places into Any, while
6+
keeping the types around for normal typechecks.
7+
8+
Since this causes the runtime types to be Any, this is best used
9+
in places where efficient access to properties is not important.
10+
For those cases some other technique should be used.
11+
"""
12+
13+
from mypy_extensions import FlexibleAlias
14+
from typing import TypeVar, Any
15+
16+
T = TypeVar('T')
17+
18+
SUPPRESS_BOGUS_TYPES = False
19+
if SUPPRESS_BOGUS_TYPES:
20+
Bogus = FlexibleAlias[T, Any]
21+
else:
22+
Bogus = FlexibleAlias[T, T]

mypy/nodes.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from mypy.visitor import NodeVisitor, StatementVisitor, ExpressionVisitor
1717
from mypy.mypyc_hacks import SymbolTable
1818

19+
from mypy.bogus_type import Bogus
20+
1921

2022
class Context:
2123
"""Base type for objects that are valid as error message locations."""
@@ -177,8 +179,11 @@ class SymbolNode(Node):
177179
@abstractmethod
178180
def name(self) -> str: pass
179181

182+
# fullname can often be None even though the type system
183+
# disagrees. We mark this with Bogus to let mypyc know not to
184+
# worry about it.
180185
@abstractmethod
181-
def fullname(self) -> str: pass
186+
def fullname(self) -> Bogus[str]: pass
182187

183188
@abstractmethod
184189
def serialize(self) -> JsonDict: pass
@@ -195,10 +200,8 @@ def deserialize(cls, data: JsonDict) -> 'SymbolNode':
195200
class MypyFile(SymbolNode):
196201
"""The abstract syntax tree of a single source file."""
197202

198-
# Module name ('__main__' for initial file)
199-
_name = None # type: str
200203
# Fully qualified module name
201-
_fullname = None # type: str
204+
_fullname = None # type: Bogus[str]
202205
# Path to the file (None if not known)
203206
path = ''
204207
# Top-level definitions and statements
@@ -238,9 +241,9 @@ def __init__(self,
238241
self.ignored_lines = set()
239242

240243
def name(self) -> str:
241-
return self._name
244+
return '' if not self._fullname else self._fullname.split('.')[-1]
242245

243-
def fullname(self) -> str:
246+
def fullname(self) -> Bogus[str]:
244247
return self._fullname
245248

246249
def accept(self, visitor: NodeVisitor[T]) -> T:
@@ -252,7 +255,6 @@ def is_package_init_file(self) -> bool:
252255

253256
def serialize(self) -> JsonDict:
254257
return {'.class': 'MypyFile',
255-
'_name': self._name,
256258
'_fullname': self._fullname,
257259
'names': self.names.serialize(self._fullname),
258260
'is_stub': self.is_stub,
@@ -264,7 +266,6 @@ def serialize(self) -> JsonDict:
264266
def deserialize(cls, data: JsonDict) -> 'MypyFile':
265267
assert data['.class'] == 'MypyFile', data
266268
tree = MypyFile([], [])
267-
tree._name = data['_name']
268269
tree._fullname = data['_fullname']
269270
tree.names = SymbolTable.deserialize(data['names'])
270271
tree.is_stub = data['is_stub']
@@ -405,12 +406,12 @@ def __init__(self) -> None:
405406
self.is_static = False
406407
# Name with module prefix
407408
# TODO: Type should be Optional[str]
408-
self._fullname = cast(str, None)
409+
self._fullname = cast(Bogus[str], None)
409410

410411
@abstractmethod
411412
def name(self) -> str: pass
412413

413-
def fullname(self) -> str:
414+
def fullname(self) -> Bogus[str]:
414415
return self._fullname
415416

416417

@@ -660,7 +661,7 @@ def __init__(self, func: FuncDef, decorators: List[Expression],
660661
def name(self) -> str:
661662
return self.func.name()
662663

663-
def fullname(self) -> str:
664+
def fullname(self) -> Bogus[str]:
664665
return self.func.fullname()
665666

666667
@property
@@ -725,7 +726,7 @@ def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None:
725726
super().__init__()
726727
self._name = name # Name without module prefix
727728
# TODO: Should be Optional[str]
728-
self._fullname = cast(str, None) # Name with module prefix
729+
self._fullname = cast(Bogus[str], None) # Name with module prefix
729730
# TODO: Should be Optional[TypeInfo]
730731
self.info = VAR_NO_INFO
731732
self.type = type # type: Optional[mypy.types.Type] # Declared or inferred type, or None
@@ -748,7 +749,7 @@ def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None:
748749
def name(self) -> str:
749750
return self._name
750751

751-
def fullname(self) -> str:
752+
def fullname(self) -> Bogus[str]:
752753
return self._fullname
753754

754755
def accept(self, visitor: StatementVisitor[T]) -> T:
@@ -780,7 +781,7 @@ class ClassDef(Statement):
780781
"""Class definition"""
781782

782783
name = None # type: str # Name of the class without module prefix
783-
fullname = None # type: str # Fully qualified name of the class
784+
fullname = None # type: Bogus[str] # Fully qualified name of the class
784785
defs = None # type: Block
785786
type_vars = None # type: List[mypy.types.TypeVarDef]
786787
# Base class expressions (not semantically analyzed -- can be arbitrary expressions)
@@ -2053,7 +2054,7 @@ class is generic then it will be a type constructor of higher kind.
20532054
the appropriate number of arguments.
20542055
"""
20552056

2056-
_fullname = None # type: str # Fully qualified name
2057+
_fullname = None # type: Bogus[str] # Fully qualified name
20572058
# Fully qualified name for the module this type was defined in. This
20582059
# information is also in the fullname, but is harder to extract in the
20592060
# case of nested class definitions.
@@ -2193,7 +2194,7 @@ def name(self) -> str:
21932194
"""Short name."""
21942195
return self.defn.name
21952196

2196-
def fullname(self) -> str:
2197+
def fullname(self) -> Bogus[str]:
21972198
return self._fullname
21982199

21992200
def is_generic(self) -> bool:

mypy/treetransform.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ def visit_mypy_file(self, node: MypyFile) -> MypyFile:
6161
# NOTE: The 'names' and 'imports' instance variables will be empty!
6262
new = MypyFile(self.statements(node.defs), [], node.is_bom,
6363
ignored_lines=set(node.ignored_lines))
64-
new._name = node._name
6564
new._fullname = node._fullname
6665
new.path = node.path
6766
new.names = SymbolTable()

mypy/types.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
)
2222
from mypy.sharedparse import argument_elide_name
2323
from mypy.util import IdMapper
24+
from mypy.bogus_type import Bogus
2425

2526
from mypy.mypyc_hacks import TypeOfAny
2627

@@ -320,8 +321,9 @@ def accept(self, visitor: 'TypeVisitor[T]') -> T:
320321
return visitor.visit_any(self)
321322

322323
def copy_modified(self,
323-
type_of_any: TypeOfAny = _dummy,
324-
original_any: Optional['AnyType'] = _dummy,
324+
# Mark with Bogus because _dummy is just an object (with type Any)
325+
type_of_any: Bogus[TypeOfAny] = _dummy,
326+
original_any: Bogus[Optional['AnyType']] = _dummy,
325327
) -> 'AnyType':
326328
if type_of_any is _dummy:
327329
type_of_any = self.type_of_any
@@ -720,22 +722,22 @@ def __init__(self,
720722
self.def_extras = {}
721723

722724
def copy_modified(self,
723-
arg_types: List[Type] = _dummy,
724-
arg_kinds: List[int] = _dummy,
725-
arg_names: List[Optional[str]] = _dummy,
726-
ret_type: Type = _dummy,
727-
fallback: Instance = _dummy,
728-
name: Optional[str] = _dummy,
729-
definition: SymbolNode = _dummy,
730-
variables: List[TypeVarDef] = _dummy,
731-
line: int = _dummy,
732-
column: int = _dummy,
733-
is_ellipsis_args: bool = _dummy,
734-
implicit: bool = _dummy,
735-
special_sig: Optional[str] = _dummy,
736-
from_type_type: bool = _dummy,
737-
bound_args: List[Optional[Type]] = _dummy,
738-
def_extras: Dict[str, Any] = _dummy) -> 'CallableType':
725+
arg_types: Bogus[List[Type]] = _dummy,
726+
arg_kinds: Bogus[List[int]] = _dummy,
727+
arg_names: Bogus[List[Optional[str]]] = _dummy,
728+
ret_type: Bogus[Type] = _dummy,
729+
fallback: Bogus[Instance] = _dummy,
730+
name: Bogus[Optional[str]] = _dummy,
731+
definition: Bogus[SymbolNode] = _dummy,
732+
variables: Bogus[List[TypeVarDef]] = _dummy,
733+
line: Bogus[int] = _dummy,
734+
column: Bogus[int] = _dummy,
735+
is_ellipsis_args: Bogus[bool] = _dummy,
736+
implicit: Bogus[bool] = _dummy,
737+
special_sig: Bogus[Optional[str]] = _dummy,
738+
from_type_type: Bogus[bool] = _dummy,
739+
bound_args: Bogus[List[Optional[Type]]] = _dummy,
740+
def_extras: Bogus[Dict[str, Any]] = _dummy) -> 'CallableType':
739741
return CallableType(
740742
arg_types=arg_types if arg_types is not _dummy else self.arg_types,
741743
arg_kinds=arg_kinds if arg_kinds is not _dummy else self.arg_kinds,
@@ -1434,8 +1436,9 @@ class TypeType(Type):
14341436
# a generic class instance, a union, Any, a type variable...
14351437
item = None # type: Type
14361438

1437-
def __init__(self, item: Union[Instance, AnyType, TypeVarType, TupleType, NoneTyp,
1438-
CallableType], *, line: int = -1, column: int = -1) -> None:
1439+
def __init__(self, item: Bogus[Union[Instance, AnyType, TypeVarType, TupleType, NoneTyp,
1440+
CallableType]], *,
1441+
line: int = -1, column: int = -1) -> None:
14391442
"""To ensure Type[Union[A, B]] is always represented as Union[Type[A], Type[B]], item of
14401443
type UnionType must be handled through make_normalized static method.
14411444
"""

mypy_bootstrap.ini

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[mypy]
2+
disallow_untyped_defs = True
3+
disallow_subclassing_any = True
4+
warn_no_return = True
5+
strict_optional = True
6+
no_implicit_optional = True
7+
disallow_any_generics = True
8+
disallow_any_unimported = True
9+
warn_redundant_casts = True
10+
warn_unused_configs = True
11+
always_true = SUPPRESS_BOGUS_TYPES
12+
13+
# needs py2 compatibility
14+
[mypy-mypy.test.testextensions]
15+
disallow_untyped_defs = False

mypy_self_check.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ disallow_any_generics = True
88
disallow_any_unimported = True
99
warn_redundant_casts = True
1010
warn_unused_configs = True
11+
always_false = SUPPRESS_BOGUS_TYPES
1112

1213
# needs py2 compatibility
1314
[mypy-mypy.test.testextensions]

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def run(self):
104104
classifiers=classifiers,
105105
cmdclass={'build_py': CustomPythonBuild},
106106
install_requires = ['typed-ast >= 1.1.0, < 1.2.0',
107+
'mypy_extensions >= 0.4.0, < 0.5.0',
107108
],
108109
extras_require = {
109110
':python_version < "3.5"': 'typing >= 3.5.3',

test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ flake8
33
flake8-bugbear; python_version >= '3.5'
44
flake8-pyi; python_version >= '3.6'
55
lxml==4.2.4
6+
mypy_extensions==0.4.0
67
psutil==5.4.0
78
pytest>=3.4
89
pytest-xdist>=1.22

0 commit comments

Comments
 (0)