Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
b32cc41f
Commit
b32cc41f
authored
Nov 09, 2016
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #28556: More typing.py updates from upstream.
parent
47c1c874
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
119 additions
and
150 deletions
+119
-150
Lib/test/test_typing.py
Lib/test/test_typing.py
+47
-16
Lib/typing.py
Lib/typing.py
+72
-134
No files found.
Lib/test/test_typing.py
View file @
b32cc41f
...
@@ -378,6 +378,16 @@ class CallableTests(BaseTestCase):
...
@@ -378,6 +378,16 @@ class CallableTests(BaseTestCase):
with
self
.
assertRaises
(
TypeError
):
with
self
.
assertRaises
(
TypeError
):
type
(
c
)()
type
(
c
)()
def
test_callable_wrong_forms
(
self
):
with
self
.
assertRaises
(
TypeError
):
Callable
[[...],
int
]
with
self
.
assertRaises
(
TypeError
):
Callable
[(),
int
]
with
self
.
assertRaises
(
TypeError
):
Callable
[[()],
int
]
with
self
.
assertRaises
(
TypeError
):
Callable
[[
int
,
1
],
2
]
def
test_callable_instance_works
(
self
):
def
test_callable_instance_works
(
self
):
def
f
():
def
f
():
pass
pass
...
@@ -1296,9 +1306,10 @@ PY36 = sys.version_info[:2] >= (3, 6)
...
@@ -1296,9 +1306,10 @@ PY36 = sys.version_info[:2] >= (3, 6)
PY36_TESTS
=
"""
PY36_TESTS
=
"""
from test import ann_module, ann_module2, ann_module3
from test import ann_module, ann_module2, ann_module3
from collections import ChainMap
class B:
class A:
y: float
class B(A):
x: ClassVar[Optional['B']] = None
x: ClassVar[Optional['B']] = None
y: int
y: int
class CSub(B):
class CSub(B):
...
@@ -1317,6 +1328,15 @@ if PY36:
...
@@ -1317,6 +1328,15 @@ if PY36:
gth
=
get_type_hints
gth
=
get_type_hints
class
GetTypeHintTests
(
BaseTestCase
):
class
GetTypeHintTests
(
BaseTestCase
):
def
test_get_type_hints_from_various_objects
(
self
):
# For invalid objects should fail with TypeError (not AttributeError etc).
with
self
.
assertRaises
(
TypeError
):
gth
(
123
)
with
self
.
assertRaises
(
TypeError
):
gth
(
'abc'
)
with
self
.
assertRaises
(
TypeError
):
gth
(
None
)
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
def
test_get_type_hints_modules
(
self
):
def
test_get_type_hints_modules
(
self
):
self
.
assertEqual
(
gth
(
ann_module
),
{
1
:
2
,
'f'
:
Tuple
[
int
,
int
],
'x'
:
int
,
'y'
:
str
})
self
.
assertEqual
(
gth
(
ann_module
),
{
1
:
2
,
'f'
:
Tuple
[
int
,
int
],
'x'
:
int
,
'y'
:
str
})
...
@@ -1326,18 +1346,15 @@ class GetTypeHintTests(BaseTestCase):
...
@@ -1326,18 +1346,15 @@ class GetTypeHintTests(BaseTestCase):
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
def
test_get_type_hints_classes
(
self
):
def
test_get_type_hints_classes
(
self
):
self
.
assertEqual
(
gth
(
ann_module
.
C
,
ann_module
.
__dict__
),
self
.
assertEqual
(
gth
(
ann_module
.
C
,
ann_module
.
__dict__
),
ChainMap
({
'y'
:
Optional
[
ann_module
.
C
]},
{}))
{
'y'
:
Optional
[
ann_module
.
C
]})
self
.
assertEqual
(
repr
(
gth
(
ann_module
.
j_class
)),
'ChainMap({}, {})'
)
self
.
assertIsInstance
(
gth
(
ann_module
.
j_class
),
dict
)
self
.
assertEqual
(
gth
(
ann_module
.
M
),
ChainMap
({
'123'
:
123
,
'o'
:
type
},
self
.
assertEqual
(
gth
(
ann_module
.
M
),
{
'123'
:
123
,
'o'
:
type
})
{},
{}))
self
.
assertEqual
(
gth
(
ann_module
.
D
),
self
.
assertEqual
(
gth
(
ann_module
.
D
),
ChainMap
({
'j'
:
str
,
'k'
:
str
,
{
'j'
:
str
,
'k'
:
str
,
'y'
:
Optional
[
ann_module
.
C
]})
'y'
:
Optional
[
ann_module
.
C
]},
{}))
self
.
assertEqual
(
gth
(
ann_module
.
Y
),
{
'z'
:
int
})
self
.
assertEqual
(
gth
(
ann_module
.
Y
),
ChainMap
({
'z'
:
int
},
{}))
self
.
assertEqual
(
gth
(
ann_module
.
h_class
),
self
.
assertEqual
(
gth
(
ann_module
.
h_class
),
ChainMap
({},
{
'y'
:
Optional
[
ann_module
.
C
]},
{}))
{
'y'
:
Optional
[
ann_module
.
C
]})
self
.
assertEqual
(
gth
(
ann_module
.
S
),
ChainMap
({
'x'
:
str
,
'y'
:
str
},
self
.
assertEqual
(
gth
(
ann_module
.
S
),
{
'x'
:
str
,
'y'
:
str
})
{}))
self
.
assertEqual
(
gth
(
ann_module
.
foo
),
{
'x'
:
int
})
self
.
assertEqual
(
gth
(
ann_module
.
foo
),
{
'x'
:
int
})
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
...
@@ -1355,20 +1372,34 @@ class GetTypeHintTests(BaseTestCase):
...
@@ -1355,20 +1372,34 @@ class GetTypeHintTests(BaseTestCase):
class
Der
(
ABase
):
...
class
Der
(
ABase
):
...
self
.
assertEqual
(
gth
(
ABase
.
meth
),
{
'x'
:
int
})
self
.
assertEqual
(
gth
(
ABase
.
meth
),
{
'x'
:
int
})
def
test_get_type_hints_for_builins
(
self
):
# Should not fail for built-in classes and functions.
self
.
assertEqual
(
gth
(
int
),
{})
self
.
assertEqual
(
gth
(
type
),
{})
self
.
assertEqual
(
gth
(
dir
),
{})
self
.
assertEqual
(
gth
(
len
),
{})
def
test_previous_behavior
(
self
):
def
test_previous_behavior
(
self
):
def
testf
(
x
,
y
):
...
def
testf
(
x
,
y
):
...
testf
.
__annotations__
[
'x'
]
=
'int'
testf
.
__annotations__
[
'x'
]
=
'int'
self
.
assertEqual
(
gth
(
testf
),
{
'x'
:
int
})
self
.
assertEqual
(
gth
(
testf
),
{
'x'
:
int
})
def
test_get_type_hints_for_object_with_annotations
(
self
):
class
A
:
...
class
B
:
...
b
=
B
()
b
.
__annotations__
=
{
'x'
:
'A'
}
self
.
assertEqual
(
gth
(
b
,
locals
()),
{
'x'
:
A
})
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
@
skipUnless
(
PY36
,
'Python 3.6 required'
)
def
test_get_type_hints_ClassVar
(
self
):
def
test_get_type_hints_ClassVar
(
self
):
self
.
assertEqual
(
gth
(
ann_module2
.
CV
,
ann_module2
.
__dict__
),
{
'var'
:
typing
.
ClassVar
[
ann_module2
.
CV
]})
self
.
assertEqual
(
gth
(
B
,
globals
()),
self
.
assertEqual
(
gth
(
B
,
globals
()),
ChainMap
({
'y'
:
int
,
'x'
:
ClassVar
[
Optional
[
B
]]},
{})
)
{
'y'
:
int
,
'x'
:
ClassVar
[
Optional
[
B
]]}
)
self
.
assertEqual
(
gth
(
CSub
,
globals
()),
self
.
assertEqual
(
gth
(
CSub
,
globals
()),
ChainMap
({
'z'
:
ClassVar
[
CSub
]},
{
'z'
:
ClassVar
[
CSub
],
'y'
:
int
,
'x'
:
ClassVar
[
Optional
[
B
]]})
{
'y'
:
int
,
'x'
:
ClassVar
[
Optional
[
B
]]},
{}))
self
.
assertEqual
(
gth
(
G
),
{
'lst'
:
ClassVar
[
List
[
T
]]})
self
.
assertEqual
(
gth
(
G
),
ChainMap
({
'lst'
:
ClassVar
[
List
[
T
]]},{},{}))
class
CollectionsAbcTests
(
BaseTestCase
):
class
CollectionsAbcTests
(
BaseTestCase
):
...
...
Lib/typing.py
View file @
b32cc41f
...
@@ -10,8 +10,6 @@ try:
...
@@ -10,8 +10,6 @@ try:
import
collections.abc
as
collections_abc
import
collections.abc
as
collections_abc
except
ImportError
:
except
ImportError
:
import
collections
as
collections_abc
# Fallback for PY3.2.
import
collections
as
collections_abc
# Fallback for PY3.2.
if
sys
.
version_info
[:
2
]
>=
(
3
,
3
):
from
collections
import
ChainMap
# Please keep __all__ alphabetized within each category.
# Please keep __all__ alphabetized within each category.
...
@@ -1194,14 +1192,12 @@ class CallableMeta(GenericMeta):
...
@@ -1194,14 +1192,12 @@ class CallableMeta(GenericMeta):
# super()._tree_repr() for nice formatting.
# super()._tree_repr() for nice formatting.
arg_list
=
[]
arg_list
=
[]
for
arg
in
tree
[
1
:]:
for
arg
in
tree
[
1
:]:
if
arg
==
():
if
not
isinstance
(
arg
,
tuple
):
arg_list
.
append
(
'[]'
)
elif
not
isinstance
(
arg
,
tuple
):
arg_list
.
append
(
_type_repr
(
arg
))
arg_list
.
append
(
_type_repr
(
arg
))
else
:
else
:
arg_list
.
append
(
arg
[
0
].
_tree_repr
(
arg
))
arg_list
.
append
(
arg
[
0
].
_tree_repr
(
arg
))
if
len
(
arg_list
)
==
2
:
if
arg_list
[
0
]
==
'...'
:
return
repr
(
tree
[
0
])
+
'[
%s]'
%
', '
.
join
(
arg_list
)
return
repr
(
tree
[
0
])
+
'[
..., %s]'
%
arg_list
[
1
]
return
(
repr
(
tree
[
0
])
+
return
(
repr
(
tree
[
0
])
+
'[[%s], %s]'
%
(
', '
.
join
(
arg_list
[:
-
1
]),
arg_list
[
-
1
]))
'[[%s], %s]'
%
(
', '
.
join
(
arg_list
[:
-
1
]),
arg_list
[
-
1
]))
...
@@ -1216,26 +1212,22 @@ class CallableMeta(GenericMeta):
...
@@ -1216,26 +1212,22 @@ class CallableMeta(GenericMeta):
raise
TypeError
(
"Callable must be used as "
raise
TypeError
(
"Callable must be used as "
"Callable[[arg, ...], result]."
)
"Callable[[arg, ...], result]."
)
args
,
result
=
parameters
args
,
result
=
parameters
if
args
is
...:
if
args
is
Ellipsis
:
parameters
=
(...,
result
)
parameters
=
(
Ellipsis
,
result
)
elif
args
==
[]:
parameters
=
((),
result
)
else
:
else
:
if
not
isinstance
(
args
,
list
):
if
not
isinstance
(
args
,
list
):
raise
TypeError
(
"Callable[args, result]: args must be a list."
raise
TypeError
(
"Callable[args, result]: args must be a list."
" Got %.100r."
%
(
args
,))
" Got %.100r."
%
(
args
,))
parameters
=
tuple
(
args
)
+
(
result
,
)
parameters
=
(
tuple
(
args
),
result
)
return
self
.
__getitem_inner__
(
parameters
)
return
self
.
__getitem_inner__
(
parameters
)
@
_tp_cache
@
_tp_cache
def
__getitem_inner__
(
self
,
parameters
):
def
__getitem_inner__
(
self
,
parameters
):
*
args
,
result
=
parameters
args
,
result
=
parameters
msg
=
"Callable[args, result]: result must be a type."
msg
=
"Callable[args, result]: result must be a type."
result
=
_type_check
(
result
,
msg
)
result
=
_type_check
(
result
,
msg
)
if
args
==
[...,]
:
if
args
is
Ellipsis
:
return
super
().
__getitem__
((
_TypingEllipsis
,
result
))
return
super
().
__getitem__
((
_TypingEllipsis
,
result
))
if
args
==
[(),]:
return
super
().
__getitem__
((
_TypingEmpty
,
result
))
msg
=
"Callable[[arg, ...], result]: each arg must be a type."
msg
=
"Callable[[arg, ...], result]: each arg must be a type."
args
=
tuple
(
_type_check
(
arg
,
msg
)
for
arg
in
args
)
args
=
tuple
(
_type_check
(
arg
,
msg
)
for
arg
in
args
)
parameters
=
args
+
(
result
,)
parameters
=
args
+
(
result
,)
...
@@ -1332,7 +1324,11 @@ def cast(typ, val):
...
@@ -1332,7 +1324,11 @@ def cast(typ, val):
def
_get_defaults
(
func
):
def
_get_defaults
(
func
):
"""Internal helper to extract the default arguments, by name."""
"""Internal helper to extract the default arguments, by name."""
code
=
func
.
__code__
try
:
code
=
func
.
__code__
except
AttributeError
:
# Some built-in functions don't have __code__, __defaults__, etc.
return
{}
pos_count
=
code
.
co_argcount
pos_count
=
code
.
co_argcount
arg_names
=
code
.
co_varnames
arg_names
=
code
.
co_varnames
arg_names
=
arg_names
[:
pos_count
]
arg_names
=
arg_names
[:
pos_count
]
...
@@ -1346,138 +1342,80 @@ def _get_defaults(func):
...
@@ -1346,138 +1342,80 @@ def _get_defaults(func):
return
res
return
res
if
sys
.
version_info
[:
2
]
>=
(
3
,
3
):
def
get_type_hints
(
obj
,
globalns
=
None
,
localns
=
None
):
def
get_type_hints
(
obj
,
globalns
=
None
,
localns
=
None
):
"""Return type hints for an object.
"""Return type hints for an object.
This is often the same as obj.__annotations__, but it handles
This is often the same as obj.__annotations__, but it handles
forward references encoded as string literals, and if necessary
forward references encoded as string literals, and if necessary
adds Optional[t] if a default value equal to None is set.
adds Optional[t] if a default value equal to None is set.
The argument may be a module, class, method, or function. The annotations
The argument may be a module, class, method, or function. The annotations
are returned as a dictionary, or in the case of a class, a ChainMap of
are returned as a dictionary. For classes, annotations include also
dictionarie
s.
inherited member
s.
TypeError is raised if the argument is not of a type that can contain
TypeError is raised if the argument is not of a type that can contain
annotations, and an empty dictionary is returned if no annotations are
annotations, and an empty dictionary is returned if no annotations are
present.
present.
BEWARE -- the behavior of globalns and localns is counterintuitive
BEWARE -- the behavior of globalns and localns is counterintuitive
(unless you are familiar with how eval() and exec() work). The
(unless you are familiar with how eval() and exec() work). The
search order is locals first, then globals.
search order is locals first, then globals.
- If no dict arguments are passed, an attempt is made to use the
- If no dict arguments are passed, an attempt is made to use the
globals from obj, and these are also used as the locals. If the
globals from obj, and these are also used as the locals. If the
object does not appear to have globals, an exception is raised.
object does not appear to have globals, an exception is raised.
- If one dict argument is passed, it is used for both globals and
- If one dict argument is passed, it is used for both globals and
locals.
locals.
- If two dict arguments are passed, they specify globals and
- If two dict arguments are passed, they specify globals and
locals, respectively.
locals, respectively.
"""
"""
if
getattr
(
obj
,
'__no_type_check__'
,
None
):
if
getattr
(
obj
,
'__no_type_check__'
,
None
):
return
{}
return
{}
if
globalns
is
None
:
if
globalns
is
None
:
globalns
=
getattr
(
obj
,
'__globals__'
,
{})
globalns
=
getattr
(
obj
,
'__globals__'
,
{})
if
localns
is
None
:
if
localns
is
None
:
localns
=
globalns
elif
localns
is
None
:
localns
=
globalns
localns
=
globalns
elif
localns
is
None
:
if
(
isinstance
(
obj
,
types
.
FunctionType
)
or
localns
=
globalns
isinstance
(
obj
,
types
.
BuiltinFunctionType
)
or
# Classes require a special treatment.
isinstance
(
obj
,
types
.
MethodType
)):
if
isinstance
(
obj
,
type
):
defaults
=
_get_defaults
(
obj
)
hints
=
{}
hints
=
obj
.
__annotations__
for
base
in
reversed
(
obj
.
__mro__
):
for
name
,
value
in
hints
.
items
():
ann
=
base
.
__dict__
.
get
(
'__annotations__'
,
{})
if
value
is
None
:
for
name
,
value
in
ann
.
items
():
value
=
type
(
None
)
if
isinstance
(
value
,
str
):
value
=
_ForwardRef
(
value
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
if
name
in
defaults
and
defaults
[
name
]
is
None
:
value
=
Optional
[
value
]
hints
[
name
]
=
value
return
hints
if
isinstance
(
obj
,
types
.
ModuleType
):
try
:
hints
=
obj
.
__annotations__
except
AttributeError
:
return
{}
for
name
,
value
in
hints
.
items
():
if
value
is
None
:
if
value
is
None
:
value
=
type
(
None
)
value
=
type
(
None
)
if
isinstance
(
value
,
str
):
if
isinstance
(
value
,
str
):
value
=
_ForwardRef
(
value
)
value
=
_ForwardRef
(
value
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
hints
[
name
]
=
value
hints
[
name
]
=
value
return
hints
if
isinstance
(
object
,
type
):
cmap
=
None
for
base
in
reversed
(
obj
.
__mro__
):
new_map
=
collections
.
ChainMap
if
cmap
is
None
else
cmap
.
new_child
try
:
hints
=
base
.
__dict__
[
'__annotations__'
]
except
KeyError
:
cmap
=
new_map
()
else
:
for
name
,
value
in
hints
.
items
():
if
value
is
None
:
value
=
type
(
None
)
if
isinstance
(
value
,
str
):
value
=
_ForwardRef
(
value
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
hints
[
name
]
=
value
cmap
=
new_map
(
hints
)
return
cmap
raise
TypeError
(
'{!r} is not a module, class, method, '
'or function.'
.
format
(
obj
))
else
:
def
get_type_hints
(
obj
,
globalns
=
None
,
localns
=
None
):
"""Return type hints for a function or method object.
This is often the same as obj.__annotations__, but it handles
forward references encoded as string literals, and if necessary
adds Optional[t] if a default value equal to None is set.
BEWARE -- the behavior of globalns and localns is counterintuitive
(unless you are familiar with how eval() and exec() work). The
search order is locals first, then globals.
- If no dict arguments are passed, an attempt is made to use the
globals from obj, and these are also used as the locals. If the
object does not appear to have globals, an exception is raised.
- If one dict argument is passed, it is used for both globals and
locals.
- If two dict arguments are passed, they specify globals and
locals, respectively.
"""
if
getattr
(
obj
,
'__no_type_check__'
,
None
):
return
{}
if
globalns
is
None
:
globalns
=
getattr
(
obj
,
'__globals__'
,
{})
if
localns
is
None
:
localns
=
globalns
elif
localns
is
None
:
localns
=
globalns
defaults
=
_get_defaults
(
obj
)
hints
=
dict
(
obj
.
__annotations__
)
for
name
,
value
in
hints
.
items
():
if
isinstance
(
value
,
str
):
value
=
_ForwardRef
(
value
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
if
name
in
defaults
and
defaults
[
name
]
is
None
:
value
=
Optional
[
value
]
hints
[
name
]
=
value
return
hints
return
hints
hints
=
getattr
(
obj
,
'__annotations__'
,
None
)
if
hints
is
None
:
# Return empty annotations for something that _could_ have them.
if
(
isinstance
(
obj
,
types
.
FunctionType
)
or
isinstance
(
obj
,
types
.
BuiltinFunctionType
)
or
isinstance
(
obj
,
types
.
MethodType
)
or
isinstance
(
obj
,
types
.
ModuleType
)):
return
{}
else
:
raise
TypeError
(
'{!r} is not a module, class, method, '
'or function.'
.
format
(
obj
))
defaults
=
_get_defaults
(
obj
)
hints
=
dict
(
hints
)
for
name
,
value
in
hints
.
items
():
if
value
is
None
:
value
=
type
(
None
)
if
isinstance
(
value
,
str
):
value
=
_ForwardRef
(
value
)
value
=
_eval_type
(
value
,
globalns
,
localns
)
if
name
in
defaults
and
defaults
[
name
]
is
None
:
value
=
Optional
[
value
]
hints
[
name
]
=
value
return
hints
def
no_type_check
(
arg
):
def
no_type_check
(
arg
):
...
@@ -2160,7 +2098,7 @@ class TextIO(IO[str]):
...
@@ -2160,7 +2098,7 @@ class TextIO(IO[str]):
pass
pass
@
abstractproperty
@
abstractproperty
def
errors
(
self
)
->
str
:
def
errors
(
self
)
->
Optional
[
str
]
:
pass
pass
@
abstractproperty
@
abstractproperty
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment