summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/pydoc_data/topics.py2
-rw-r--r--Lib/sre_compile.py117
-rw-r--r--Lib/string.py9
-rw-r--r--Lib/test/test_collections.py8
-rw-r--r--Lib/test/test_dictviews.py22
-rw-r--r--Lib/test/test_os.py19
-rw-r--r--Lib/test/test_symbol.py45
-rw-r--r--Lib/test/test_typing.py251
-rw-r--r--Lib/typing.py166
9 files changed, 234 insertions, 405 deletions
diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py
index cc0c6ab7db..38857d24b3 100644
--- a/Lib/pydoc_data/topics.py
+++ b/Lib/pydoc_data/topics.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Sat May 30 16:57:51 2015
+# Autogenerated by Sphinx on Sat May 23 17:38:41 2015
topics = {'assert': u'\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n',
'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n',
'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n',
diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py
index 502b0616c6..4edb03fa30 100644
--- a/Lib/sre_compile.py
+++ b/Lib/sre_compile.py
@@ -409,57 +409,39 @@ def _generate_overlap_table(prefix):
table[i] = idx + 1
return table
-def _compile_info(code, pattern, flags):
- # internal: compile an info block. in the current version,
- # this contains min/max pattern width, and an optional literal
- # prefix or a character map
- lo, hi = pattern.getwidth()
- if hi > MAXCODE:
- hi = MAXCODE
- if lo == 0:
- code.extend([INFO, 4, 0, lo, hi])
- return
- # look for a literal prefix
+def _get_literal_prefix(pattern):
+ # look for literal prefix
prefix = []
prefixappend = prefix.append
- prefix_skip = 0
+ prefix_skip = None
+ got_all = True
+ for op, av in pattern.data:
+ if op is LITERAL:
+ prefixappend(av)
+ elif op is SUBPATTERN:
+ prefix1, prefix_skip1, got_all = _get_literal_prefix(av[1])
+ if prefix_skip is None:
+ if av[0] is not None:
+ prefix_skip = len(prefix)
+ elif prefix_skip1 is not None:
+ prefix_skip = len(prefix) + prefix_skip1
+ prefix.extend(prefix1)
+ if not got_all:
+ break
+ else:
+ got_all = False
+ break
+ return prefix, prefix_skip, got_all
+
+def _get_charset_prefix(pattern):
charset = [] # not used
charsetappend = charset.append
- if not (flags & SRE_FLAG_IGNORECASE):
- # look for literal prefix
- for op, av in pattern.data:
+ if pattern.data:
+ op, av = pattern.data[0]
+ if op is SUBPATTERN and av[1]:
+ op, av = av[1][0]
if op is LITERAL:
- if len(prefix) == prefix_skip:
- prefix_skip = prefix_skip + 1
- prefixappend(av)
- elif op is SUBPATTERN and len(av[1]) == 1:
- op, av = av[1][0]
- if op is LITERAL:
- prefixappend(av)
- else:
- break
- else:
- break
- # if no prefix, look for charset prefix
- if not prefix and pattern.data:
- op, av = pattern.data[0]
- if op is SUBPATTERN and av[1]:
- op, av = av[1][0]
- if op is LITERAL:
- charsetappend((op, av))
- elif op is BRANCH:
- c = []
- cappend = c.append
- for p in av[1]:
- if not p:
- break
- op, av = p[0]
- if op is LITERAL:
- cappend((op, av))
- else:
- break
- else:
- charset = c
+ charsetappend((op, av))
elif op is BRANCH:
c = []
cappend = c.append
@@ -473,8 +455,43 @@ def _compile_info(code, pattern, flags):
break
else:
charset = c
- elif op is IN:
- charset = av
+ elif op is BRANCH:
+ c = []
+ cappend = c.append
+ for p in av[1]:
+ if not p:
+ break
+ op, av = p[0]
+ if op is LITERAL:
+ cappend((op, av))
+ else:
+ break
+ else:
+ charset = c
+ elif op is IN:
+ charset = av
+ return charset
+
+def _compile_info(code, pattern, flags):
+ # internal: compile an info block. in the current version,
+ # this contains min/max pattern width, and an optional literal
+ # prefix or a character map
+ lo, hi = pattern.getwidth()
+ if hi > MAXCODE:
+ hi = MAXCODE
+ if lo == 0:
+ code.extend([INFO, 4, 0, lo, hi])
+ return
+ # look for a literal prefix
+ prefix = []
+ prefix_skip = 0
+ charset = [] # not used
+ if not (flags & SRE_FLAG_IGNORECASE):
+ # look for literal prefix
+ prefix, prefix_skip, got_all = _get_literal_prefix(pattern)
+ # if no prefix, look for charset prefix
+ if not prefix:
+ charset = _get_charset_prefix(pattern)
## if prefix:
## print("*** PREFIX", prefix, prefix_skip)
## if charset:
@@ -487,7 +504,7 @@ def _compile_info(code, pattern, flags):
mask = 0
if prefix:
mask = SRE_INFO_PREFIX
- if len(prefix) == prefix_skip == len(pattern.data):
+ if prefix_skip is None and got_all:
mask = mask | SRE_INFO_LITERAL
elif charset:
mask = mask | SRE_INFO_CHARSET
@@ -502,6 +519,8 @@ def _compile_info(code, pattern, flags):
# add literal prefix
if prefix:
emit(len(prefix)) # length
+ if prefix_skip is None:
+ prefix_skip = len(prefix)
emit(prefix_skip) # skip
code.extend(prefix)
# generate overlap table
diff --git a/Lib/string.py b/Lib/string.py
index f3365c67fb..e7b692d7f7 100644
--- a/Lib/string.py
+++ b/Lib/string.py
@@ -112,10 +112,7 @@ class Template(metaclass=_TemplateMetaclass):
# Check the most common path first.
named = mo.group('named') or mo.group('braced')
if named is not None:
- val = mapping[named]
- # We use this idiom instead of str() because the latter will
- # fail if val is a Unicode containing non-ASCII characters.
- return '%s' % (val,)
+ return str(mapping[named])
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
@@ -142,9 +139,7 @@ class Template(metaclass=_TemplateMetaclass):
named = mo.group('named') or mo.group('braced')
if named is not None:
try:
- # We use this idiom instead of str() because the latter
- # will fail if val is a Unicode containing non-ASCII
- return '%s' % (mapping[named],)
+ return str(mapping[named])
except KeyError:
return mo.group()
if mo.group('escaped') is not None:
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index ab2b733b03..698805d4db 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -1988,6 +1988,14 @@ class OrderedDictTests:
od = OrderedDict(**d)
self.assertGreater(sys.getsizeof(od), sys.getsizeof(d))
+ def test_views(self):
+ OrderedDict = self.module.OrderedDict
+ # See http://bugs.python.org/issue24286
+ s = 'the quick brown fox jumped over a lazy dog yesterday before dawn'.split()
+ od = OrderedDict.fromkeys(s)
+ self.assertEqual(od.keys(), dict(od).keys())
+ self.assertEqual(od.items(), dict(od).items())
+
def test_override_update(self):
OrderedDict = self.module.OrderedDict
# Verify that subclasses can override update() without breaking __init__()
diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py
index 280353a3a2..d96832e576 100644
--- a/Lib/test/test_dictviews.py
+++ b/Lib/test/test_dictviews.py
@@ -1,3 +1,4 @@
+import collections
import unittest
class DictSetTest(unittest.TestCase):
@@ -197,6 +198,27 @@ class DictSetTest(unittest.TestCase):
d[42] = d.values()
self.assertRaises(RuntimeError, repr, d)
+ def test_abc_registry(self):
+ d = dict(a=1)
+
+ self.assertIsInstance(d.keys(), collections.KeysView)
+ self.assertIsInstance(d.keys(), collections.MappingView)
+ self.assertIsInstance(d.keys(), collections.Set)
+ self.assertIsInstance(d.keys(), collections.Sized)
+ self.assertIsInstance(d.keys(), collections.Iterable)
+ self.assertIsInstance(d.keys(), collections.Container)
+
+ self.assertIsInstance(d.values(), collections.ValuesView)
+ self.assertIsInstance(d.values(), collections.MappingView)
+ self.assertIsInstance(d.values(), collections.Sized)
+
+ self.assertIsInstance(d.items(), collections.ItemsView)
+ self.assertIsInstance(d.items(), collections.MappingView)
+ self.assertIsInstance(d.items(), collections.Set)
+ self.assertIsInstance(d.items(), collections.Sized)
+ self.assertIsInstance(d.items(), collections.Iterable)
+ self.assertIsInstance(d.items(), collections.Container)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 6581e350d0..fd8269d10f 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -213,15 +213,10 @@ class FileTests(unittest.TestCase):
# Test attributes on return values from os.*stat* family.
class StatAttributeTests(unittest.TestCase):
def setUp(self):
- os.mkdir(support.TESTFN)
- self.fname = os.path.join(support.TESTFN, "f1")
- f = open(self.fname, 'wb')
- f.write(b"ABC")
- f.close()
-
- def tearDown(self):
- os.unlink(self.fname)
- os.rmdir(support.TESTFN)
+ self.fname = support.TESTFN
+ self.addCleanup(support.unlink, self.fname)
+ with open(self.fname, 'wb') as fp:
+ fp.write(b"ABC")
@unittest.skipUnless(hasattr(os, 'stat'), 'test needs os.stat()')
def check_stat_attributes(self, fname):
@@ -413,7 +408,11 @@ class StatAttributeTests(unittest.TestCase):
0)
# test directory st_file_attributes (FILE_ATTRIBUTE_DIRECTORY set)
- result = os.stat(support.TESTFN)
+ dirname = support.TESTFN + "dir"
+ os.mkdir(dirname)
+ self.addCleanup(os.rmdir, dirname)
+
+ result = os.stat(dirname)
self.check_file_attributes(result)
self.assertEqual(
result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
diff --git a/Lib/test/test_symbol.py b/Lib/test/test_symbol.py
new file mode 100644
index 0000000000..4475bbcac4
--- /dev/null
+++ b/Lib/test/test_symbol.py
@@ -0,0 +1,45 @@
+import unittest
+from test import support
+import filecmp
+import os
+import sys
+import subprocess
+
+
+SYMBOL_FILE = support.findfile('symbol.py')
+GRAMMAR_FILE = os.path.join(os.path.dirname(__file__),
+ '..', '..', 'Include', 'graminit.h')
+TEST_PY_FILE = 'symbol_test.py'
+
+
+class TestSymbolGeneration(unittest.TestCase):
+
+ def _copy_file_without_generated_symbols(self, source_file, dest_file):
+ with open(source_file, 'rb') as fp:
+ lines = fp.readlines()
+ nl = lines[0][len(lines[0].rstrip()):]
+ with open(dest_file, 'wb') as fp:
+ fp.writelines(lines[:lines.index(b"#--start constants--" + nl) + 1])
+ fp.writelines(lines[lines.index(b"#--end constants--" + nl):])
+
+ def _generate_symbols(self, grammar_file, target_symbol_py_file):
+ proc = subprocess.Popen([sys.executable,
+ SYMBOL_FILE,
+ grammar_file,
+ target_symbol_py_file], stderr=subprocess.PIPE)
+ stderr = proc.communicate()[1]
+ return proc.returncode, stderr
+
+ @unittest.skipIf(not os.path.exists(GRAMMAR_FILE),
+ 'test only works from source build directory')
+ def test_real_grammar_and_symbol_file(self):
+ self._copy_file_without_generated_symbols(SYMBOL_FILE, TEST_PY_FILE)
+ self.addCleanup(support.unlink, TEST_PY_FILE)
+ self.assertFalse(filecmp.cmp(SYMBOL_FILE, TEST_PY_FILE))
+ self.assertEqual((0, b''), self._generate_symbols(GRAMMAR_FILE,
+ TEST_PY_FILE))
+ self.assertTrue(filecmp.cmp(SYMBOL_FILE, TEST_PY_FILE))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index c37e1130a1..2bb21edc18 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -41,11 +41,9 @@ class ManagingFounder(Manager, Founder):
class AnyTests(TestCase):
- def test_any_instance(self):
- self.assertIsInstance(Employee(), Any)
- self.assertIsInstance(42, Any)
- self.assertIsInstance(None, Any)
- self.assertIsInstance(object(), Any)
+ def test_any_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Any)
def test_any_subclass(self):
self.assertTrue(issubclass(Employee, Any))
@@ -109,9 +107,6 @@ class TypeVarTests(TestCase):
def test_basic_plain(self):
T = TypeVar('T')
- # Nothing is an instance if T.
- with self.assertRaises(TypeError):
- isinstance('', T)
# Every class is a subclass of T.
assert issubclass(int, T)
assert issubclass(str, T)
@@ -119,12 +114,16 @@ class TypeVarTests(TestCase):
assert T == T
# T is a subclass of itself.
assert issubclass(T, T)
+ # T is an instance of TypeVar
+ assert isinstance(T, TypeVar)
+
+ def test_typevar_instance_type_error(self):
+ T = TypeVar('T')
+ with self.assertRaises(TypeError):
+ isinstance(42, T)
def test_basic_constrained(self):
A = TypeVar('A', str, bytes)
- # Nothing is an instance of A.
- with self.assertRaises(TypeError):
- isinstance('', A)
# Only str and bytes are subclasses of A.
assert issubclass(str, A)
assert issubclass(bytes, A)
@@ -213,8 +212,6 @@ class UnionTests(TestCase):
def test_basics(self):
u = Union[int, float]
self.assertNotEqual(u, Union)
- self.assertIsInstance(42, u)
- self.assertIsInstance(3.14, u)
self.assertTrue(issubclass(int, u))
self.assertTrue(issubclass(float, u))
@@ -247,7 +244,6 @@ class UnionTests(TestCase):
def test_subclass(self):
u = Union[int, Employee]
- self.assertIsInstance(Manager(), u)
self.assertTrue(issubclass(Manager, u))
def test_self_subclass(self):
@@ -256,7 +252,6 @@ class UnionTests(TestCase):
def test_multiple_inheritance(self):
u = Union[int, Employee]
- self.assertIsInstance(ManagingFounder(), u)
self.assertTrue(issubclass(ManagingFounder, u))
def test_single_class_disappears(self):
@@ -309,9 +304,6 @@ class UnionTests(TestCase):
o = Optional[int]
u = Union[int, None]
self.assertEqual(o, u)
- self.assertIsInstance(42, o)
- self.assertIsInstance(None, o)
- self.assertNotIsInstance(3.14, o)
def test_empty(self):
with self.assertRaises(TypeError):
@@ -321,11 +313,9 @@ class UnionTests(TestCase):
assert issubclass(Union[int, str], Union)
assert not issubclass(int, Union)
- def test_isinstance_union(self):
- # Nothing is an instance of bare Union.
- assert not isinstance(42, Union)
- assert not isinstance(int, Union)
- assert not isinstance(Union[int, str], Union)
+ def test_union_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[int, str])
class TypeVarUnionTests(TestCase):
@@ -352,22 +342,11 @@ class TypeVarUnionTests(TestCase):
TU = TypeVar('TU', Union[int, float], None)
assert issubclass(int, TU)
assert issubclass(float, TU)
- with self.assertRaises(TypeError):
- isinstance(42, TU)
- with self.assertRaises(TypeError):
- isinstance('', TU)
class TupleTests(TestCase):
def test_basics(self):
- self.assertIsInstance((42, 3.14, ''), Tuple)
- self.assertIsInstance((42, 3.14, ''), Tuple[int, float, str])
- self.assertIsInstance((42,), Tuple[int])
- self.assertNotIsInstance((3.14,), Tuple[int])
- self.assertNotIsInstance((42, 3.14), Tuple[int, float, str])
- self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float, str])
- self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float])
self.assertTrue(issubclass(Tuple[int, str], Tuple))
self.assertTrue(issubclass(Tuple[int, str], Tuple[int, str]))
self.assertFalse(issubclass(int, Tuple))
@@ -382,14 +361,11 @@ class TupleTests(TestCase):
pass
self.assertTrue(issubclass(MyTuple, Tuple))
- def test_tuple_ellipsis(self):
- t = Tuple[int, ...]
- assert isinstance((), t)
- assert isinstance((1,), t)
- assert isinstance((1, 2), t)
- assert isinstance((1, 2, 3), t)
- assert not isinstance((3.14,), t)
- assert not isinstance((1, 2, 3.14,), t)
+ def test_tuple_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance((0, 0), Tuple[int, int])
+ with self.assertRaises(TypeError):
+ isinstance((0, 0), Tuple)
def test_tuple_ellipsis_subclass(self):
@@ -419,18 +395,6 @@ class TupleTests(TestCase):
class CallableTests(TestCase):
- def test_basics(self):
- c = Callable[[int, float], str]
-
- def flub(a: int, b: float) -> str:
- return str(a * b)
-
- def flob(a: int, b: int) -> str:
- return str(a * b)
-
- self.assertIsInstance(flub, c)
- self.assertNotIsInstance(flob, c)
-
def test_self_subclass(self):
self.assertTrue(issubclass(Callable[[int], int], Callable))
self.assertFalse(issubclass(Callable, Callable[[int], int]))
@@ -453,91 +417,6 @@ class CallableTests(TestCase):
self.assertNotEqual(Callable[[int], int], Callable[[], int])
self.assertNotEqual(Callable[[int], int], Callable)
- def test_with_none(self):
- c = Callable[[None], None]
-
- def flub(self: None) -> None:
- pass
-
- def flab(self: Any) -> None:
- pass
-
- def flob(self: None) -> Any:
- pass
-
- self.assertIsInstance(flub, c)
- self.assertIsInstance(flab, c)
- self.assertNotIsInstance(flob, c) # Test contravariance.
-
- def test_with_subclasses(self):
- c = Callable[[Employee, Manager], Employee]
-
- def flub(a: Employee, b: Employee) -> Manager:
- return Manager()
-
- def flob(a: Manager, b: Manager) -> Employee:
- return Employee()
-
- self.assertIsInstance(flub, c)
- self.assertNotIsInstance(flob, c)
-
- def test_with_default_args(self):
- c = Callable[[int], int]
-
- def flub(a: int, b: float = 3.14) -> int:
- return a
-
- def flab(a: int, *, b: float = 3.14) -> int:
- return a
-
- def flob(a: int = 42) -> int:
- return a
-
- self.assertIsInstance(flub, c)
- self.assertIsInstance(flab, c)
- self.assertIsInstance(flob, c)
-
- def test_with_varargs(self):
- c = Callable[[int], int]
-
- def flub(*args) -> int:
- return 42
-
- def flab(*args: int) -> int:
- return 42
-
- def flob(*args: float) -> int:
- return 42
-
- self.assertIsInstance(flub, c)
- self.assertIsInstance(flab, c)
- self.assertNotIsInstance(flob, c)
-
- def test_with_method(self):
-
- class C:
-
- def imethod(self, arg: int) -> int:
- self.last_arg = arg
- return arg + 1
-
- @classmethod
- def cmethod(cls, arg: int) -> int:
- cls.last_cls_arg = arg
- return arg + 1
-
- @staticmethod
- def smethod(arg: int) -> int:
- return arg + 1
-
- ct = Callable[[int], int]
- self.assertIsInstance(C().imethod, ct)
- self.assertIsInstance(C().cmethod, ct)
- self.assertIsInstance(C.cmethod, ct)
- self.assertIsInstance(C().smethod, ct)
- self.assertIsInstance(C.smethod, ct)
- self.assertIsInstance(C.imethod, Callable[[Any, int], int])
-
def test_cannot_subclass(self):
with self.assertRaises(TypeError):
@@ -556,21 +435,21 @@ class CallableTests(TestCase):
with self.assertRaises(TypeError):
c()
- def test_varargs(self):
- ct = Callable[..., int]
-
- def foo(a, b) -> int:
- return 42
+ def test_callable_instance_works(self):
+ f = lambda: None
+ assert isinstance(f, Callable)
+ assert not isinstance(None, Callable)
- def bar(a=42) -> int:
- return a
-
- def baz(*, x, y, z) -> int:
- return 100
-
- self.assertIsInstance(foo, ct)
- self.assertIsInstance(bar, ct)
- self.assertIsInstance(baz, ct)
+ def test_callable_instance_type_error(self):
+ f = lambda: None
+ with self.assertRaises(TypeError):
+ assert isinstance(f, Callable[[], None])
+ with self.assertRaises(TypeError):
+ assert isinstance(f, Callable[[], Any])
+ with self.assertRaises(TypeError):
+ assert not isinstance(None, Callable[[], None])
+ with self.assertRaises(TypeError):
+ assert not isinstance(None, Callable[[], Any])
def test_repr(self):
ct0 = Callable[[], bool]
@@ -659,6 +538,10 @@ class ProtocolTests(TestCase):
assert issubclass(list, typing.Reversible)
assert not issubclass(int, typing.Reversible)
+ def test_protocol_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance([], typing.Reversible)
+
class GenericTests(TestCase):
@@ -824,11 +707,11 @@ class VarianceTests(TestCase):
typing.Sequence[Manager])
def test_covariance_mapping(self):
- # Ditto for Mapping (a generic class with two parameters).
+ # Ditto for Mapping (covariant in the value, invariant in the key).
assert issubclass(typing.Mapping[Employee, Manager],
typing.Mapping[Employee, Employee])
- assert issubclass(typing.Mapping[Manager, Employee],
- typing.Mapping[Employee, Employee])
+ assert not issubclass(typing.Mapping[Manager, Employee],
+ typing.Mapping[Employee, Employee])
assert not issubclass(typing.Mapping[Employee, Manager],
typing.Mapping[Manager, Manager])
assert not issubclass(typing.Mapping[Manager, Employee],
@@ -889,6 +772,11 @@ class ForwardRefTests(TestCase):
right_hints = get_type_hints(t.add_right, globals(), locals())
assert right_hints['node'] == Optional[Node[T]]
+ def test_forwardref_instance_type_error(self):
+ fr = typing._ForwardRef('int')
+ with self.assertRaises(TypeError):
+ isinstance(42, fr)
+
def test_union_forward(self):
def foo(a: Union['T']):
@@ -1069,50 +957,17 @@ class CollectionsAbcTests(TestCase):
def test_list(self):
assert issubclass(list, typing.List)
- assert isinstance([], typing.List)
- assert not isinstance((), typing.List)
- t = typing.List[int]
- assert isinstance([], t)
- assert isinstance([42], t)
- assert not isinstance([''], t)
def test_set(self):
assert issubclass(set, typing.Set)
assert not issubclass(frozenset, typing.Set)
- assert isinstance(set(), typing.Set)
- assert not isinstance({}, typing.Set)
- t = typing.Set[int]
- assert isinstance(set(), t)
- assert isinstance({42}, t)
- assert not isinstance({''}, t)
def test_frozenset(self):
assert issubclass(frozenset, typing.FrozenSet)
assert not issubclass(set, typing.FrozenSet)
- assert isinstance(frozenset(), typing.FrozenSet)
- assert not isinstance({}, typing.FrozenSet)
- t = typing.FrozenSet[int]
- assert isinstance(frozenset(), t)
- assert isinstance(frozenset({42}), t)
- assert not isinstance(frozenset({''}), t)
- assert not isinstance({42}, t)
-
- def test_mapping_views(self):
- # TODO: These tests are kind of lame.
- assert isinstance({}.keys(), typing.KeysView)
- assert isinstance({}.items(), typing.ItemsView)
- assert isinstance({}.values(), typing.ValuesView)
def test_dict(self):
assert issubclass(dict, typing.Dict)
- assert isinstance({}, typing.Dict)
- assert not isinstance([], typing.Dict)
- t = typing.Dict[int, str]
- assert isinstance({}, t)
- assert isinstance({42: ''}, t)
- assert not isinstance({42: 42}, t)
- assert not isinstance({'': 42}, t)
- assert not isinstance({'': ''}, t)
def test_no_list_instantiation(self):
with self.assertRaises(TypeError):
@@ -1191,8 +1046,6 @@ class CollectionsAbcTests(TestCase):
yield 42
g = foo()
assert issubclass(type(g), typing.Generator)
- assert isinstance(g, typing.Generator)
- assert not isinstance(foo, typing.Generator)
assert issubclass(typing.Generator[Manager, Employee, Manager],
typing.Generator[Employee, Manager, Employee])
assert not issubclass(typing.Generator[Manager, Manager, Manager],
@@ -1228,12 +1081,6 @@ class CollectionsAbcTests(TestCase):
assert len(MMB[str, str]()) == 0
assert len(MMB[KT, VT]()) == 0
- def test_recursive_dict(self):
- D = typing.Dict[int, 'D'] # Uses a _ForwardRef
- assert isinstance({}, D) # Easy
- assert isinstance({0: {}}, D) # Touches _ForwardRef
- assert isinstance({0: {0: {}}}, D) # Etc...
-
class NamedTupleTests(TestCase):
@@ -1294,8 +1141,6 @@ class RETests(TestCase):
def test_basics(self):
pat = re.compile('[a-z]+', re.I)
assert issubclass(pat.__class__, Pattern)
- assert isinstance(pat, Pattern[str])
- assert not isinstance(pat, Pattern[bytes])
assert issubclass(type(pat), Pattern)
assert issubclass(type(pat), Pattern[str])
@@ -1307,12 +1152,10 @@ class RETests(TestCase):
assert issubclass(type(mat), Match[str])
p = Pattern[Union[str, bytes]]
- assert isinstance(pat, p)
assert issubclass(Pattern[str], Pattern)
assert issubclass(Pattern[str], p)
m = Match[Union[bytes, str]]
- assert isinstance(mat, m)
assert issubclass(Match[bytes], Match)
assert issubclass(Match[bytes], m)
@@ -1327,6 +1170,12 @@ class RETests(TestCase):
with self.assertRaises(TypeError):
# Too complicated?
m[str]
+ with self.assertRaises(TypeError):
+ # We don't support isinstance().
+ isinstance(42, Pattern)
+ with self.assertRaises(TypeError):
+ # We don't support isinstance().
+ isinstance(42, Pattern[str])
def test_repr(self):
assert repr(Pattern) == 'Pattern[~AnyStr]'
diff --git a/Lib/typing.py b/Lib/typing.py
index 38e07ad50b..bc6fcdd03d 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -176,6 +176,9 @@ class _ForwardRef(TypingMeta):
self.__forward_evaluated__ = True
return self.__forward_value__
+ def __instancecheck__(self, obj):
+ raise TypeError("Forward references cannot be used with isinstance().")
+
def __subclasscheck__(self, cls):
if not self.__forward_evaluated__:
globalns = self.__forward_frame__.f_globals
@@ -186,16 +189,6 @@ class _ForwardRef(TypingMeta):
return False # Too early.
return issubclass(cls, self.__forward_value__)
- def __instancecheck__(self, obj):
- if not self.__forward_evaluated__:
- globalns = self.__forward_frame__.f_globals
- localns = self.__forward_frame__.f_locals
- try:
- self._eval_type(globalns, localns)
- except NameError:
- return False # Too early.
- return isinstance(obj, self.__forward_value__)
-
def __repr__(self):
return '_ForwardRef(%r)' % (self.__forward_arg__,)
@@ -259,8 +252,7 @@ class _TypeAlias:
self.impl_type, self.type_checker)
def __instancecheck__(self, obj):
- return (isinstance(obj, self.impl_type) and
- isinstance(self.type_checker(obj), self.type_var))
+ raise TypeError("Type aliases cannot be used with isinstance().")
def __subclasscheck__(self, cls):
if cls is Any:
@@ -332,8 +324,8 @@ class AnyMeta(TypingMeta):
self = super().__new__(cls, name, bases, namespace, _root=_root)
return self
- def __instancecheck__(self, instance):
- return True
+ def __instancecheck__(self, obj):
+ raise TypeError("Any cannot be used with isinstance().")
def __subclasscheck__(self, cls):
if not isinstance(cls, type):
@@ -447,7 +439,6 @@ KT = TypeVar('KT') # Key type.
VT = TypeVar('VT') # Value type.
T_co = TypeVar('T_co', covariant=True) # Any type covariant containers.
V_co = TypeVar('V_co', covariant=True) # Any type covariant containers.
-KT_co = TypeVar('KT_co', covariant=True) # Key type covariant containers.
VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers.
T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant.
@@ -548,9 +539,8 @@ class UnionMeta(TypingMeta):
def __hash__(self):
return hash(self.__union_set_params__)
- def __instancecheck__(self, instance):
- return (self.__union_set_params__ is not None and
- any(isinstance(instance, t) for t in self.__union_params__))
+ def __instancecheck__(self, obj):
+ raise TypeError("Unions cannot be used with isinstance().")
def __subclasscheck__(self, cls):
if cls is Any:
@@ -709,18 +699,8 @@ class TupleMeta(TypingMeta):
def __hash__(self):
return hash(self.__tuple_params__)
- def __instancecheck__(self, t):
- if not isinstance(t, tuple):
- return False
- if self.__tuple_params__ is None:
- return True
- if self.__tuple_use_ellipsis__:
- p = self.__tuple_params__[0]
- return all(isinstance(x, p) for x in t)
- else:
- return (len(t) == len(self.__tuple_params__) and
- all(isinstance(x, p)
- for x, p in zip(t, self.__tuple_params__)))
+ def __instancecheck__(self, obj):
+ raise TypeError("Tuples cannot be used with isinstance().")
def __subclasscheck__(self, cls):
if cls is Any:
@@ -826,57 +806,14 @@ class CallableMeta(TypingMeta):
def __hash__(self):
return hash(self.__args__) ^ hash(self.__result__)
- def __instancecheck__(self, instance):
- if not callable(instance):
- return False
+ def __instancecheck__(self, obj):
+ # For unparametrized Callable we allow this, because
+ # typing.Callable should be equivalent to
+ # collections.abc.Callable.
if self.__args__ is None and self.__result__ is None:
- return True
- assert self.__args__ is not None
- assert self.__result__ is not None
- my_args, my_result = self.__args__, self.__result__
- import inspect # TODO: Avoid this import.
- # Would it be better to use Signature objects?
- try:
- (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults,
- annotations) = inspect.getfullargspec(instance)
- except TypeError:
- return False # We can't find the signature. Give up.
- msg = ("When testing isinstance(<callable>, Callable[...], "
- "<calleble>'s annotations must be types.")
- if my_args is not Ellipsis:
- if kwonlyargs and (not kwonlydefaults or
- len(kwonlydefaults) < len(kwonlyargs)):
- return False
- if isinstance(instance, types.MethodType):
- # For methods, getfullargspec() includes self/cls,
- # but it's not part of the call signature, so drop it.
- del args[0]
- min_call_args = len(args)
- if defaults:
- min_call_args -= len(defaults)
- if varargs:
- max_call_args = 999999999
- if len(args) < len(my_args):
- args += [varargs] * (len(my_args) - len(args))
- else:
- max_call_args = len(args)
- if not min_call_args <= len(my_args) <= max_call_args:
- return False
- for my_arg_type, name in zip(my_args, args):
- if name in annotations:
- annot_type = _type_check(annotations[name], msg)
- else:
- annot_type = Any
- if not issubclass(my_arg_type, annot_type):
- return False
- # TODO: If mutable type, check invariance?
- if 'return' in annotations:
- annot_return_type = _type_check(annotations['return'], msg)
- # Note contravariance here!
- if not issubclass(annot_return_type, my_result):
- return False
- # Can't find anything wrong...
- return True
+ return isinstance(obj, collections_abc.Callable)
+ else:
+ raise TypeError("Callable[] cannot be used with isinstance().")
def __subclasscheck__(self, cls):
if cls is Any:
@@ -1073,13 +1010,6 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
return False
return issubclass(cls, self.__extra__)
- def __instancecheck__(self, obj):
- if super().__instancecheck__(obj):
- return True
- if self.__extra__ is None:
- return False
- return isinstance(obj, self.__extra__)
-
class Generic(metaclass=GenericMeta):
"""Abstract base class for generic types.
@@ -1234,6 +1164,9 @@ class _ProtocolMeta(GenericMeta):
from Generic.
"""
+ def __instancecheck__(self, obj):
+ raise TypeError("Protocols cannot be used with isinstance().")
+
def __subclasscheck__(self, cls):
if not self._is_protocol:
# No structural checks since this isn't a protocol.
@@ -1374,7 +1307,8 @@ class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet):
pass
-class Mapping(Sized, Iterable[KT_co], Container[KT_co], Generic[KT_co, VT_co],
+# NOTE: Only the value type is covariant.
+class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co],
extra=collections_abc.Mapping):
pass
@@ -1399,19 +1333,7 @@ class ByteString(Sequence[int], extra=collections_abc.ByteString):
ByteString.register(type(memoryview(b'')))
-class _ListMeta(GenericMeta):
-
- def __instancecheck__(self, obj):
- if not super().__instancecheck__(obj):
- return False
- itemtype = self.__parameters__[0]
- for x in obj:
- if not isinstance(x, itemtype):
- return False
- return True
-
-
-class List(list, MutableSequence[T], metaclass=_ListMeta):
+class List(list, MutableSequence[T]):
def __new__(cls, *args, **kwds):
if _geqv(cls, List):
@@ -1420,19 +1342,7 @@ class List(list, MutableSequence[T], metaclass=_ListMeta):
return list.__new__(cls, *args, **kwds)
-class _SetMeta(GenericMeta):
-
- def __instancecheck__(self, obj):
- if not super().__instancecheck__(obj):
- return False
- itemtype = self.__parameters__[0]
- for x in obj:
- if not isinstance(x, itemtype):
- return False
- return True
-
-
-class Set(set, MutableSet[T], metaclass=_SetMeta):
+class Set(set, MutableSet[T]):
def __new__(cls, *args, **kwds):
if _geqv(cls, Set):
@@ -1441,7 +1351,7 @@ class Set(set, MutableSet[T], metaclass=_SetMeta):
return set.__new__(cls, *args, **kwds)
-class _FrozenSetMeta(_SetMeta):
+class _FrozenSetMeta(GenericMeta):
"""This metaclass ensures set is not a subclass of FrozenSet.
Without this metaclass, set would be considered a subclass of
@@ -1454,11 +1364,6 @@ class _FrozenSetMeta(_SetMeta):
return False
return super().__subclasscheck__(cls)
- def __instancecheck__(self, obj):
- if issubclass(obj.__class__, Set):
- return False
- return super().__instancecheck__(obj)
-
class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta):
@@ -1473,13 +1378,13 @@ class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView):
pass
-class KeysView(MappingView[KT_co], AbstractSet[KT_co],
+class KeysView(MappingView[KT], AbstractSet[KT],
extra=collections_abc.KeysView):
pass
-# TODO: Enable Set[Tuple[KT_co, VT_co]] instead of Generic[KT_co, VT_co].
-class ItemsView(MappingView, Generic[KT_co, VT_co],
+# TODO: Enable Set[Tuple[KT, VT_co]] instead of Generic[KT, VT_co].
+class ItemsView(MappingView, Generic[KT, VT_co],
extra=collections_abc.ItemsView):
pass
@@ -1488,20 +1393,7 @@ class ValuesView(MappingView[VT_co], extra=collections_abc.ValuesView):
pass
-class _DictMeta(GenericMeta):
-
- def __instancecheck__(self, obj):
- if not super().__instancecheck__(obj):
- return False
- keytype, valuetype = self.__parameters__
- for key, value in obj.items():
- if not (isinstance(key, keytype) and
- isinstance(value, valuetype)):
- return False
- return True
-
-
-class Dict(dict, MutableMapping[KT, VT], metaclass=_DictMeta):
+class Dict(dict, MutableMapping[KT, VT]):
def __new__(cls, *args, **kwds):
if _geqv(cls, Dict):