From 724f6a67f241f39394b15c419570920ebdfefacb Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Fri, 9 Sep 2016 12:55:37 -0700 Subject: Rename test_pep####.py files --- Lib/test/test_baseexception.py | 183 ++++++ Lib/test/test_dict_version.py | 186 ++++++ Lib/test/test_exception_hierarchy.py | 204 +++++++ Lib/test/test_generator_stop.py | 34 ++ Lib/test/test_pep277.py | 195 ------ Lib/test/test_pep3120.py | 43 -- Lib/test/test_pep3131.py | 31 - Lib/test/test_pep3151.py | 204 ------- Lib/test/test_pep352.py | 183 ------ Lib/test/test_pep380.py | 1017 ------------------------------- Lib/test/test_pep479.py | 34 -- Lib/test/test_pep509.py | 186 ------ Lib/test/test_tokenize.py | 11 +- Lib/test/test_unicode_file_functions.py | 195 ++++++ Lib/test/test_unicode_identifiers.py | 31 + Lib/test/test_utf8source.py | 43 ++ Lib/test/test_yield_from.py | 1017 +++++++++++++++++++++++++++++++ 17 files changed, 1899 insertions(+), 1898 deletions(-) create mode 100644 Lib/test/test_baseexception.py create mode 100644 Lib/test/test_dict_version.py create mode 100644 Lib/test/test_exception_hierarchy.py create mode 100644 Lib/test/test_generator_stop.py delete mode 100644 Lib/test/test_pep277.py delete mode 100644 Lib/test/test_pep3120.py delete mode 100644 Lib/test/test_pep3131.py delete mode 100644 Lib/test/test_pep3151.py delete mode 100644 Lib/test/test_pep352.py delete mode 100644 Lib/test/test_pep380.py delete mode 100644 Lib/test/test_pep479.py delete mode 100644 Lib/test/test_pep509.py create mode 100644 Lib/test/test_unicode_file_functions.py create mode 100644 Lib/test/test_unicode_identifiers.py create mode 100644 Lib/test/test_utf8source.py create mode 100644 Lib/test/test_yield_from.py diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py new file mode 100644 index 0000000..27d514f --- /dev/null +++ b/Lib/test/test_baseexception.py @@ -0,0 +1,183 @@ +import unittest +import builtins +import os +from platform import system as platform_system + + +class ExceptionClassTests(unittest.TestCase): + + """Tests for anything relating to exception objects themselves (e.g., + inheritance hierarchy)""" + + def test_builtins_new_style(self): + self.assertTrue(issubclass(Exception, object)) + + def verify_instance_interface(self, ins): + for attr in ("args", "__str__", "__repr__"): + self.assertTrue(hasattr(ins, attr), + "%s missing %s attribute" % + (ins.__class__.__name__, attr)) + + def test_inheritance(self): + # Make sure the inheritance hierarchy matches the documentation + exc_set = set() + for object_ in builtins.__dict__.values(): + try: + if issubclass(object_, BaseException): + exc_set.add(object_.__name__) + except TypeError: + pass + + inheritance_tree = open(os.path.join(os.path.split(__file__)[0], + 'exception_hierarchy.txt')) + try: + superclass_name = inheritance_tree.readline().rstrip() + try: + last_exc = getattr(builtins, superclass_name) + except AttributeError: + self.fail("base class %s not a built-in" % superclass_name) + self.assertIn(superclass_name, exc_set, + '%s not found' % superclass_name) + exc_set.discard(superclass_name) + superclasses = [] # Loop will insert base exception + last_depth = 0 + for exc_line in inheritance_tree: + exc_line = exc_line.rstrip() + depth = exc_line.rindex('-') + exc_name = exc_line[depth+2:] # Slice past space + if '(' in exc_name: + paren_index = exc_name.index('(') + platform_name = exc_name[paren_index+1:-1] + exc_name = exc_name[:paren_index-1] # Slice off space + if platform_system() != platform_name: + exc_set.discard(exc_name) + continue + if '[' in exc_name: + left_bracket = exc_name.index('[') + exc_name = exc_name[:left_bracket-1] # cover space + try: + exc = getattr(builtins, exc_name) + except AttributeError: + self.fail("%s not a built-in exception" % exc_name) + if last_depth < depth: + superclasses.append((last_depth, last_exc)) + elif last_depth > depth: + while superclasses[-1][0] >= depth: + superclasses.pop() + self.assertTrue(issubclass(exc, superclasses[-1][1]), + "%s is not a subclass of %s" % (exc.__name__, + superclasses[-1][1].__name__)) + try: # Some exceptions require arguments; just skip them + self.verify_instance_interface(exc()) + except TypeError: + pass + self.assertIn(exc_name, exc_set) + exc_set.discard(exc_name) + last_exc = exc + last_depth = depth + finally: + inheritance_tree.close() + self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set) + + interface_tests = ("length", "args", "str", "repr") + + def interface_test_driver(self, results): + for test_name, (given, expected) in zip(self.interface_tests, results): + self.assertEqual(given, expected, "%s: %s != %s" % (test_name, + given, expected)) + + def test_interface_single_arg(self): + # Make sure interface works properly when given a single argument + arg = "spam" + exc = Exception(arg) + results = ([len(exc.args), 1], [exc.args[0], arg], + [str(exc), str(arg)], + [repr(exc), exc.__class__.__name__ + repr(exc.args)]) + self.interface_test_driver(results) + + def test_interface_multi_arg(self): + # Make sure interface correct when multiple arguments given + arg_count = 3 + args = tuple(range(arg_count)) + exc = Exception(*args) + results = ([len(exc.args), arg_count], [exc.args, args], + [str(exc), str(args)], + [repr(exc), exc.__class__.__name__ + repr(exc.args)]) + self.interface_test_driver(results) + + def test_interface_no_arg(self): + # Make sure that with no args that interface is correct + exc = Exception() + results = ([len(exc.args), 0], [exc.args, tuple()], + [str(exc), ''], + [repr(exc), exc.__class__.__name__ + '()']) + self.interface_test_driver(results) + +class UsageTests(unittest.TestCase): + + """Test usage of exceptions""" + + def raise_fails(self, object_): + """Make sure that raising 'object_' triggers a TypeError.""" + try: + raise object_ + except TypeError: + return # What is expected. + self.fail("TypeError expected for raising %s" % type(object_)) + + def catch_fails(self, object_): + """Catching 'object_' should raise a TypeError.""" + try: + try: + raise Exception + except object_: + pass + except TypeError: + pass + except Exception: + self.fail("TypeError expected when catching %s" % type(object_)) + + try: + try: + raise Exception + except (object_,): + pass + except TypeError: + return + except Exception: + self.fail("TypeError expected when catching %s as specified in a " + "tuple" % type(object_)) + + def test_raise_new_style_non_exception(self): + # You cannot raise a new-style class that does not inherit from + # BaseException; the ability was not possible until BaseException's + # introduction so no need to support new-style objects that do not + # inherit from it. + class NewStyleClass(object): + pass + self.raise_fails(NewStyleClass) + self.raise_fails(NewStyleClass()) + + def test_raise_string(self): + # Raising a string raises TypeError. + self.raise_fails("spam") + + def test_catch_non_BaseException(self): + # Tryinng to catch an object that does not inherit from BaseException + # is not allowed. + class NonBaseException(object): + pass + self.catch_fails(NonBaseException) + self.catch_fails(NonBaseException()) + + def test_catch_BaseException_instance(self): + # Catching an instance of a BaseException subclass won't work. + self.catch_fails(BaseException()) + + def test_catch_string(self): + # Catching a string is bad. + self.catch_fails("spam") + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_dict_version.py b/Lib/test/test_dict_version.py new file mode 100644 index 0000000..5671f9f --- /dev/null +++ b/Lib/test/test_dict_version.py @@ -0,0 +1,186 @@ +""" +Test implementation of the PEP 509: dictionary versionning. +""" +import unittest +from test import support + +# PEP 509 is implemented in CPython but other Python implementations +# don't require to implement it +_testcapi = support.import_module('_testcapi') + + +class DictVersionTests(unittest.TestCase): + type2test = dict + + def setUp(self): + self.seen_versions = set() + self.dict = None + + def check_version_unique(self, mydict): + version = _testcapi.dict_get_version(mydict) + self.assertNotIn(version, self.seen_versions) + self.seen_versions.add(version) + + def check_version_changed(self, mydict, method, *args, **kw): + result = method(*args, **kw) + self.check_version_unique(mydict) + return result + + def check_version_dont_change(self, mydict, method, *args, **kw): + version1 = _testcapi.dict_get_version(mydict) + self.seen_versions.add(version1) + + result = method(*args, **kw) + + version2 = _testcapi.dict_get_version(mydict) + self.assertEqual(version2, version1, "version changed") + + return result + + def new_dict(self, *args, **kw): + d = self.type2test(*args, **kw) + self.check_version_unique(d) + return d + + def test_constructor(self): + # new empty dictionaries must all have an unique version + empty1 = self.new_dict() + empty2 = self.new_dict() + empty3 = self.new_dict() + + # non-empty dictionaries must also have an unique version + nonempty1 = self.new_dict(x='x') + nonempty2 = self.new_dict(x='x', y='y') + + def test_copy(self): + d = self.new_dict(a=1, b=2) + + d2 = self.check_version_dont_change(d, d.copy) + + # dict.copy() must create a dictionary with a new unique version + self.check_version_unique(d2) + + def test_setitem(self): + d = self.new_dict() + + # creating new keys must change the version + self.check_version_changed(d, d.__setitem__, 'x', 'x') + self.check_version_changed(d, d.__setitem__, 'y', 'y') + + # changing values must change the version + self.check_version_changed(d, d.__setitem__, 'x', 1) + self.check_version_changed(d, d.__setitem__, 'y', 2) + + def test_setitem_same_value(self): + value = object() + d = self.new_dict() + + # setting a key must change the version + self.check_version_changed(d, d.__setitem__, 'key', value) + + # setting a key to the same value with dict.__setitem__ + # must change the version + self.check_version_changed(d, d.__setitem__, 'key', value) + + # setting a key to the same value with dict.update + # must change the version + self.check_version_changed(d, d.update, key=value) + + d2 = self.new_dict(key=value) + self.check_version_changed(d, d.update, d2) + + def test_setitem_equal(self): + class AlwaysEqual: + def __eq__(self, other): + return True + + value1 = AlwaysEqual() + value2 = AlwaysEqual() + self.assertTrue(value1 == value2) + self.assertFalse(value1 != value2) + + d = self.new_dict() + self.check_version_changed(d, d.__setitem__, 'key', value1) + + # setting a key to a value equal to the current value + # with dict.__setitem__() must change the version + self.check_version_changed(d, d.__setitem__, 'key', value2) + + # setting a key to a value equal to the current value + # with dict.update() must change the version + self.check_version_changed(d, d.update, key=value1) + + d2 = self.new_dict(key=value2) + self.check_version_changed(d, d.update, d2) + + def test_setdefault(self): + d = self.new_dict() + + # setting a key with dict.setdefault() must change the version + self.check_version_changed(d, d.setdefault, 'key', 'value1') + + # don't change the version if the key already exists + self.check_version_dont_change(d, d.setdefault, 'key', 'value2') + + def test_delitem(self): + d = self.new_dict(key='value') + + # deleting a key with dict.__delitem__() must change the version + self.check_version_changed(d, d.__delitem__, 'key') + + # don't change the version if the key doesn't exist + self.check_version_dont_change(d, self.assertRaises, KeyError, + d.__delitem__, 'key') + + def test_pop(self): + d = self.new_dict(key='value') + + # pop() must change the version if the key exists + self.check_version_changed(d, d.pop, 'key') + + # pop() must not change the version if the key does not exist + self.check_version_dont_change(d, self.assertRaises, KeyError, + d.pop, 'key') + + def test_popitem(self): + d = self.new_dict(key='value') + + # popitem() must change the version if the dict is not empty + self.check_version_changed(d, d.popitem) + + # popitem() must not change the version if the dict is empty + self.check_version_dont_change(d, self.assertRaises, KeyError, + d.popitem) + + def test_update(self): + d = self.new_dict(key='value') + + # update() calling with no argument must not change the version + self.check_version_dont_change(d, d.update) + + # update() must change the version + self.check_version_changed(d, d.update, key='new value') + + d2 = self.new_dict(key='value 3') + self.check_version_changed(d, d.update, d2) + + def test_clear(self): + d = self.new_dict(key='value') + + # clear() must change the version if the dict is not empty + self.check_version_changed(d, d.clear) + + # clear() must not change the version if the dict is empty + self.check_version_dont_change(d, d.clear) + + +class Dict(dict): + pass + + +class DictSubtypeVersionTests(DictVersionTests): + type2test = Dict + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_exception_hierarchy.py b/Lib/test/test_exception_hierarchy.py new file mode 100644 index 0000000..8649596 --- /dev/null +++ b/Lib/test/test_exception_hierarchy.py @@ -0,0 +1,204 @@ +import builtins +import os +import select +import socket +import unittest +import errno +from errno import EEXIST + + +class SubOSError(OSError): + pass + +class SubOSErrorWithInit(OSError): + def __init__(self, message, bar): + self.bar = bar + super().__init__(message) + +class SubOSErrorWithNew(OSError): + def __new__(cls, message, baz): + self = super().__new__(cls, message) + self.baz = baz + return self + +class SubOSErrorCombinedInitFirst(SubOSErrorWithInit, SubOSErrorWithNew): + pass + +class SubOSErrorCombinedNewFirst(SubOSErrorWithNew, SubOSErrorWithInit): + pass + +class SubOSErrorWithStandaloneInit(OSError): + def __init__(self): + pass + + +class HierarchyTest(unittest.TestCase): + + def test_builtin_errors(self): + self.assertEqual(OSError.__name__, 'OSError') + self.assertIs(IOError, OSError) + self.assertIs(EnvironmentError, OSError) + + def test_socket_errors(self): + self.assertIs(socket.error, IOError) + self.assertIs(socket.gaierror.__base__, OSError) + self.assertIs(socket.herror.__base__, OSError) + self.assertIs(socket.timeout.__base__, OSError) + + def test_select_error(self): + self.assertIs(select.error, OSError) + + # mmap.error is tested in test_mmap + + _pep_map = """ + +-- BlockingIOError EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS + +-- ChildProcessError ECHILD + +-- ConnectionError + +-- BrokenPipeError EPIPE, ESHUTDOWN + +-- ConnectionAbortedError ECONNABORTED + +-- ConnectionRefusedError ECONNREFUSED + +-- ConnectionResetError ECONNRESET + +-- FileExistsError EEXIST + +-- FileNotFoundError ENOENT + +-- InterruptedError EINTR + +-- IsADirectoryError EISDIR + +-- NotADirectoryError ENOTDIR + +-- PermissionError EACCES, EPERM + +-- ProcessLookupError ESRCH + +-- TimeoutError ETIMEDOUT + """ + def _make_map(s): + _map = {} + for line in s.splitlines(): + line = line.strip('+- ') + if not line: + continue + excname, _, errnames = line.partition(' ') + for errname in filter(None, errnames.strip().split(', ')): + _map[getattr(errno, errname)] = getattr(builtins, excname) + return _map + _map = _make_map(_pep_map) + + def test_errno_mapping(self): + # The OSError constructor maps errnos to subclasses + # A sample test for the basic functionality + e = OSError(EEXIST, "Bad file descriptor") + self.assertIs(type(e), FileExistsError) + # Exhaustive testing + for errcode, exc in self._map.items(): + e = OSError(errcode, "Some message") + self.assertIs(type(e), exc) + othercodes = set(errno.errorcode) - set(self._map) + for errcode in othercodes: + e = OSError(errcode, "Some message") + self.assertIs(type(e), OSError) + + def test_try_except(self): + filename = "some_hopefully_non_existing_file" + + # This checks that try .. except checks the concrete exception + # (FileNotFoundError) and not the base type specified when + # PyErr_SetFromErrnoWithFilenameObject was called. + # (it is therefore deliberate that it doesn't use assertRaises) + try: + open(filename) + except FileNotFoundError: + pass + else: + self.fail("should have raised a FileNotFoundError") + + # Another test for PyErr_SetExcFromWindowsErrWithFilenameObject() + self.assertFalse(os.path.exists(filename)) + try: + os.unlink(filename) + except FileNotFoundError: + pass + else: + self.fail("should have raised a FileNotFoundError") + + +class AttributesTest(unittest.TestCase): + + def test_windows_error(self): + if os.name == "nt": + self.assertIn('winerror', dir(OSError)) + else: + self.assertNotIn('winerror', dir(OSError)) + + def test_posix_error(self): + e = OSError(EEXIST, "File already exists", "foo.txt") + self.assertEqual(e.errno, EEXIST) + self.assertEqual(e.args[0], EEXIST) + self.assertEqual(e.strerror, "File already exists") + self.assertEqual(e.filename, "foo.txt") + if os.name == "nt": + self.assertEqual(e.winerror, None) + + @unittest.skipUnless(os.name == "nt", "Windows-specific test") + def test_errno_translation(self): + # ERROR_ALREADY_EXISTS (183) -> EEXIST + e = OSError(0, "File already exists", "foo.txt", 183) + self.assertEqual(e.winerror, 183) + self.assertEqual(e.errno, EEXIST) + self.assertEqual(e.args[0], EEXIST) + self.assertEqual(e.strerror, "File already exists") + self.assertEqual(e.filename, "foo.txt") + + def test_blockingioerror(self): + args = ("a", "b", "c", "d", "e") + for n in range(6): + e = BlockingIOError(*args[:n]) + with self.assertRaises(AttributeError): + e.characters_written + e = BlockingIOError("a", "b", 3) + self.assertEqual(e.characters_written, 3) + e.characters_written = 5 + self.assertEqual(e.characters_written, 5) + + +class ExplicitSubclassingTest(unittest.TestCase): + + def test_errno_mapping(self): + # When constructing an OSError subclass, errno mapping isn't done + e = SubOSError(EEXIST, "Bad file descriptor") + self.assertIs(type(e), SubOSError) + + def test_init_overridden(self): + e = SubOSErrorWithInit("some message", "baz") + self.assertEqual(e.bar, "baz") + self.assertEqual(e.args, ("some message",)) + + def test_init_kwdargs(self): + e = SubOSErrorWithInit("some message", bar="baz") + self.assertEqual(e.bar, "baz") + self.assertEqual(e.args, ("some message",)) + + def test_new_overridden(self): + e = SubOSErrorWithNew("some message", "baz") + self.assertEqual(e.baz, "baz") + self.assertEqual(e.args, ("some message",)) + + def test_new_kwdargs(self): + e = SubOSErrorWithNew("some message", baz="baz") + self.assertEqual(e.baz, "baz") + self.assertEqual(e.args, ("some message",)) + + def test_init_new_overridden(self): + e = SubOSErrorCombinedInitFirst("some message", "baz") + self.assertEqual(e.bar, "baz") + self.assertEqual(e.baz, "baz") + self.assertEqual(e.args, ("some message",)) + e = SubOSErrorCombinedNewFirst("some message", "baz") + self.assertEqual(e.bar, "baz") + self.assertEqual(e.baz, "baz") + self.assertEqual(e.args, ("some message",)) + + def test_init_standalone(self): + # __init__ doesn't propagate to OSError.__init__ (see issue #15229) + e = SubOSErrorWithStandaloneInit() + self.assertEqual(e.args, ()) + self.assertEqual(str(e), '') + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_generator_stop.py b/Lib/test/test_generator_stop.py new file mode 100644 index 0000000..bc235ce --- /dev/null +++ b/Lib/test/test_generator_stop.py @@ -0,0 +1,34 @@ +from __future__ import generator_stop + +import unittest + + +class TestPEP479(unittest.TestCase): + def test_stopiteration_wrapping(self): + def f(): + raise StopIteration + def g(): + yield f() + with self.assertRaisesRegex(RuntimeError, + "generator raised StopIteration"): + next(g()) + + def test_stopiteration_wrapping_context(self): + def f(): + raise StopIteration + def g(): + yield f() + + try: + next(g()) + except RuntimeError as exc: + self.assertIs(type(exc.__cause__), StopIteration) + self.assertIs(type(exc.__context__), StopIteration) + self.assertTrue(exc.__suppress_context__) + else: + self.fail('__cause__, __context__, or __suppress_context__ ' + 'were not properly set') + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_pep277.py b/Lib/test/test_pep277.py deleted file mode 100644 index 98c716b..0000000 --- a/Lib/test/test_pep277.py +++ /dev/null @@ -1,195 +0,0 @@ -# Test the Unicode versions of normal file functions -# open, os.open, os.stat. os.listdir, os.rename, os.remove, os.mkdir, os.chdir, os.rmdir -import os -import sys -import unittest -import warnings -from unicodedata import normalize -from test import support - -filenames = [ - '1_abc', - '2_ascii', - '3_Gr\xfc\xdf-Gott', - '4_\u0393\u03b5\u03b9\u03ac-\u03c3\u03b1\u03c2', - '5_\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435', - '6_\u306b\u307d\u3093', - '7_\u05d4\u05e9\u05e7\u05e6\u05e5\u05e1', - '8_\u66e8\u66e9\u66eb', - '9_\u66e8\u05e9\u3093\u0434\u0393\xdf', - # Specific code points: fn, NFC(fn) and NFKC(fn) all differents - '10_\u1fee\u1ffd', - ] - -# Mac OS X decomposes Unicode names, using Normal Form D. -# http://developer.apple.com/mac/library/qa/qa2001/qa1173.html -# "However, most volume formats do not follow the exact specification for -# these normal forms. For example, HFS Plus uses a variant of Normal Form D -# in which U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through -# U+2FAFF are not decomposed." -if sys.platform != 'darwin': - filenames.extend([ - # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all differents - '11_\u0385\u03d3\u03d4', - '12_\u00a8\u0301\u03d2\u0301\u03d2\u0308', # == NFD('\u0385\u03d3\u03d4') - '13_\u0020\u0308\u0301\u038e\u03ab', # == NFKC('\u0385\u03d3\u03d4') - '14_\u1e9b\u1fc1\u1fcd\u1fce\u1fcf\u1fdd\u1fde\u1fdf\u1fed', - - # Specific code points: fn, NFC(fn) and NFKC(fn) all differents - '15_\u1fee\u1ffd\ufad1', - '16_\u2000\u2000\u2000A', - '17_\u2001\u2001\u2001A', - '18_\u2003\u2003\u2003A', # == NFC('\u2001\u2001\u2001A') - '19_\u0020\u0020\u0020A', # '\u0020' == ' ' == NFKC('\u2000') == - # NFKC('\u2001') == NFKC('\u2003') - ]) - - -# Is it Unicode-friendly? -if not os.path.supports_unicode_filenames: - fsencoding = sys.getfilesystemencoding() - try: - for name in filenames: - name.encode(fsencoding) - except UnicodeEncodeError: - raise unittest.SkipTest("only NT+ and systems with " - "Unicode-friendly filesystem encoding") - - -class UnicodeFileTests(unittest.TestCase): - files = set(filenames) - normal_form = None - - def setUp(self): - try: - os.mkdir(support.TESTFN) - except FileExistsError: - pass - self.addCleanup(support.rmtree, support.TESTFN) - - files = set() - for name in self.files: - name = os.path.join(support.TESTFN, self.norm(name)) - with open(name, 'wb') as f: - f.write((name+'\n').encode("utf-8")) - os.stat(name) - files.add(name) - self.files = files - - def norm(self, s): - if self.normal_form: - return normalize(self.normal_form, s) - return s - - def _apply_failure(self, fn, filename, - expected_exception=FileNotFoundError, - check_filename=True): - with self.assertRaises(expected_exception) as c: - fn(filename) - exc_filename = c.exception.filename - if check_filename: - self.assertEqual(exc_filename, filename, "Function '%s(%a) failed " - "with bad filename in the exception: %a" % - (fn.__name__, filename, exc_filename)) - - def test_failures(self): - # Pass non-existing Unicode filenames all over the place. - for name in self.files: - name = "not_" + name - self._apply_failure(open, name) - self._apply_failure(os.stat, name) - self._apply_failure(os.chdir, name) - self._apply_failure(os.rmdir, name) - self._apply_failure(os.remove, name) - self._apply_failure(os.listdir, name) - - if sys.platform == 'win32': - # Windows is lunatic. Issue #13366. - _listdir_failure = NotADirectoryError, FileNotFoundError - else: - _listdir_failure = NotADirectoryError - - def test_open(self): - for name in self.files: - f = open(name, 'wb') - f.write((name+'\n').encode("utf-8")) - f.close() - os.stat(name) - self._apply_failure(os.listdir, name, self._listdir_failure) - - # Skip the test on darwin, because darwin does normalize the filename to - # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC, - # NFKD in Python is useless, because darwin will normalize it later and so - # open(), os.stat(), etc. don't raise any exception. - @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') - def test_normalize(self): - files = set(self.files) - others = set() - for nf in set(['NFC', 'NFD', 'NFKC', 'NFKD']): - others |= set(normalize(nf, file) for file in files) - others -= files - for name in others: - self._apply_failure(open, name) - self._apply_failure(os.stat, name) - self._apply_failure(os.chdir, name) - self._apply_failure(os.rmdir, name) - self._apply_failure(os.remove, name) - self._apply_failure(os.listdir, name) - - # Skip the test on darwin, because darwin uses a normalization different - # than Python NFD normalization: filenames are different even if we use - # Python NFD normalization. - @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') - def test_listdir(self): - sf0 = set(self.files) - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - f1 = os.listdir(support.TESTFN.encode(sys.getfilesystemencoding())) - f2 = os.listdir(support.TESTFN) - sf2 = set(os.path.join(support.TESTFN, f) for f in f2) - self.assertEqual(sf0, sf2, "%a != %a" % (sf0, sf2)) - self.assertEqual(len(f1), len(f2)) - - def test_rename(self): - for name in self.files: - os.rename(name, "tmp") - os.rename("tmp", name) - - def test_directory(self): - dirname = os.path.join(support.TESTFN, 'Gr\xfc\xdf-\u66e8\u66e9\u66eb') - filename = '\xdf-\u66e8\u66e9\u66eb' - with support.temp_cwd(dirname): - with open(filename, 'wb') as f: - f.write((filename + '\n').encode("utf-8")) - os.access(filename,os.R_OK) - os.remove(filename) - - -class UnicodeNFCFileTests(UnicodeFileTests): - normal_form = 'NFC' - - -class UnicodeNFDFileTests(UnicodeFileTests): - normal_form = 'NFD' - - -class UnicodeNFKCFileTests(UnicodeFileTests): - normal_form = 'NFKC' - - -class UnicodeNFKDFileTests(UnicodeFileTests): - normal_form = 'NFKD' - - -def test_main(): - support.run_unittest( - UnicodeFileTests, - UnicodeNFCFileTests, - UnicodeNFDFileTests, - UnicodeNFKCFileTests, - UnicodeNFKDFileTests, - ) - - -if __name__ == "__main__": - test_main() diff --git a/Lib/test/test_pep3120.py b/Lib/test/test_pep3120.py deleted file mode 100644 index 97dced8..0000000 --- a/Lib/test/test_pep3120.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is marked as binary in the CVS, to prevent MacCVS from recoding it. - -import unittest - -class PEP3120Test(unittest.TestCase): - - def test_pep3120(self): - self.assertEqual( - "Питон".encode("utf-8"), - b'\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd' - ) - self.assertEqual( - "\П".encode("utf-8"), - b'\\\xd0\x9f' - ) - - def test_badsyntax(self): - try: - import test.badsyntax_pep3120 - except SyntaxError as msg: - msg = str(msg).lower() - self.assertTrue('utf-8' in msg) - else: - self.fail("expected exception didn't occur") - - -class BuiltinCompileTests(unittest.TestCase): - - # Issue 3574. - def test_latin1(self): - # Allow compile() to read Latin-1 source. - source_code = '# coding: Latin-1\nu = "Ç"\n'.encode("Latin-1") - try: - code = compile(source_code, '', 'exec') - except SyntaxError: - self.fail("compile() cannot handle Latin-1 source") - ns = {} - exec(code, ns) - self.assertEqual('Ç', ns['u']) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_pep3131.py b/Lib/test/test_pep3131.py deleted file mode 100644 index 0679845..0000000 --- a/Lib/test/test_pep3131.py +++ /dev/null @@ -1,31 +0,0 @@ -import unittest -import sys - -class PEP3131Test(unittest.TestCase): - - def test_valid(self): - class T: - ä = 1 - µ = 2 # this is a compatibility character - 蟒 = 3 - x󠄀 = 4 - self.assertEqual(getattr(T, "\xe4"), 1) - self.assertEqual(getattr(T, "\u03bc"), 2) - self.assertEqual(getattr(T, '\u87d2'), 3) - self.assertEqual(getattr(T, 'x\U000E0100'), 4) - - def test_non_bmp_normalized(self): - 𝔘𝔫𝔦𝔠𝔬𝔡𝔢 = 1 - self.assertIn("Unicode", dir()) - - def test_invalid(self): - try: - from test import badsyntax_3131 - except SyntaxError as s: - self.assertEqual(str(s), - "invalid character in identifier (badsyntax_3131.py, line 2)") - else: - self.fail("expected exception didn't occur") - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_pep3151.py b/Lib/test/test_pep3151.py deleted file mode 100644 index 8649596..0000000 --- a/Lib/test/test_pep3151.py +++ /dev/null @@ -1,204 +0,0 @@ -import builtins -import os -import select -import socket -import unittest -import errno -from errno import EEXIST - - -class SubOSError(OSError): - pass - -class SubOSErrorWithInit(OSError): - def __init__(self, message, bar): - self.bar = bar - super().__init__(message) - -class SubOSErrorWithNew(OSError): - def __new__(cls, message, baz): - self = super().__new__(cls, message) - self.baz = baz - return self - -class SubOSErrorCombinedInitFirst(SubOSErrorWithInit, SubOSErrorWithNew): - pass - -class SubOSErrorCombinedNewFirst(SubOSErrorWithNew, SubOSErrorWithInit): - pass - -class SubOSErrorWithStandaloneInit(OSError): - def __init__(self): - pass - - -class HierarchyTest(unittest.TestCase): - - def test_builtin_errors(self): - self.assertEqual(OSError.__name__, 'OSError') - self.assertIs(IOError, OSError) - self.assertIs(EnvironmentError, OSError) - - def test_socket_errors(self): - self.assertIs(socket.error, IOError) - self.assertIs(socket.gaierror.__base__, OSError) - self.assertIs(socket.herror.__base__, OSError) - self.assertIs(socket.timeout.__base__, OSError) - - def test_select_error(self): - self.assertIs(select.error, OSError) - - # mmap.error is tested in test_mmap - - _pep_map = """ - +-- BlockingIOError EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS - +-- ChildProcessError ECHILD - +-- ConnectionError - +-- BrokenPipeError EPIPE, ESHUTDOWN - +-- ConnectionAbortedError ECONNABORTED - +-- ConnectionRefusedError ECONNREFUSED - +-- ConnectionResetError ECONNRESET - +-- FileExistsError EEXIST - +-- FileNotFoundError ENOENT - +-- InterruptedError EINTR - +-- IsADirectoryError EISDIR - +-- NotADirectoryError ENOTDIR - +-- PermissionError EACCES, EPERM - +-- ProcessLookupError ESRCH - +-- TimeoutError ETIMEDOUT - """ - def _make_map(s): - _map = {} - for line in s.splitlines(): - line = line.strip('+- ') - if not line: - continue - excname, _, errnames = line.partition(' ') - for errname in filter(None, errnames.strip().split(', ')): - _map[getattr(errno, errname)] = getattr(builtins, excname) - return _map - _map = _make_map(_pep_map) - - def test_errno_mapping(self): - # The OSError constructor maps errnos to subclasses - # A sample test for the basic functionality - e = OSError(EEXIST, "Bad file descriptor") - self.assertIs(type(e), FileExistsError) - # Exhaustive testing - for errcode, exc in self._map.items(): - e = OSError(errcode, "Some message") - self.assertIs(type(e), exc) - othercodes = set(errno.errorcode) - set(self._map) - for errcode in othercodes: - e = OSError(errcode, "Some message") - self.assertIs(type(e), OSError) - - def test_try_except(self): - filename = "some_hopefully_non_existing_file" - - # This checks that try .. except checks the concrete exception - # (FileNotFoundError) and not the base type specified when - # PyErr_SetFromErrnoWithFilenameObject was called. - # (it is therefore deliberate that it doesn't use assertRaises) - try: - open(filename) - except FileNotFoundError: - pass - else: - self.fail("should have raised a FileNotFoundError") - - # Another test for PyErr_SetExcFromWindowsErrWithFilenameObject() - self.assertFalse(os.path.exists(filename)) - try: - os.unlink(filename) - except FileNotFoundError: - pass - else: - self.fail("should have raised a FileNotFoundError") - - -class AttributesTest(unittest.TestCase): - - def test_windows_error(self): - if os.name == "nt": - self.assertIn('winerror', dir(OSError)) - else: - self.assertNotIn('winerror', dir(OSError)) - - def test_posix_error(self): - e = OSError(EEXIST, "File already exists", "foo.txt") - self.assertEqual(e.errno, EEXIST) - self.assertEqual(e.args[0], EEXIST) - self.assertEqual(e.strerror, "File already exists") - self.assertEqual(e.filename, "foo.txt") - if os.name == "nt": - self.assertEqual(e.winerror, None) - - @unittest.skipUnless(os.name == "nt", "Windows-specific test") - def test_errno_translation(self): - # ERROR_ALREADY_EXISTS (183) -> EEXIST - e = OSError(0, "File already exists", "foo.txt", 183) - self.assertEqual(e.winerror, 183) - self.assertEqual(e.errno, EEXIST) - self.assertEqual(e.args[0], EEXIST) - self.assertEqual(e.strerror, "File already exists") - self.assertEqual(e.filename, "foo.txt") - - def test_blockingioerror(self): - args = ("a", "b", "c", "d", "e") - for n in range(6): - e = BlockingIOError(*args[:n]) - with self.assertRaises(AttributeError): - e.characters_written - e = BlockingIOError("a", "b", 3) - self.assertEqual(e.characters_written, 3) - e.characters_written = 5 - self.assertEqual(e.characters_written, 5) - - -class ExplicitSubclassingTest(unittest.TestCase): - - def test_errno_mapping(self): - # When constructing an OSError subclass, errno mapping isn't done - e = SubOSError(EEXIST, "Bad file descriptor") - self.assertIs(type(e), SubOSError) - - def test_init_overridden(self): - e = SubOSErrorWithInit("some message", "baz") - self.assertEqual(e.bar, "baz") - self.assertEqual(e.args, ("some message",)) - - def test_init_kwdargs(self): - e = SubOSErrorWithInit("some message", bar="baz") - self.assertEqual(e.bar, "baz") - self.assertEqual(e.args, ("some message",)) - - def test_new_overridden(self): - e = SubOSErrorWithNew("some message", "baz") - self.assertEqual(e.baz, "baz") - self.assertEqual(e.args, ("some message",)) - - def test_new_kwdargs(self): - e = SubOSErrorWithNew("some message", baz="baz") - self.assertEqual(e.baz, "baz") - self.assertEqual(e.args, ("some message",)) - - def test_init_new_overridden(self): - e = SubOSErrorCombinedInitFirst("some message", "baz") - self.assertEqual(e.bar, "baz") - self.assertEqual(e.baz, "baz") - self.assertEqual(e.args, ("some message",)) - e = SubOSErrorCombinedNewFirst("some message", "baz") - self.assertEqual(e.bar, "baz") - self.assertEqual(e.baz, "baz") - self.assertEqual(e.args, ("some message",)) - - def test_init_standalone(self): - # __init__ doesn't propagate to OSError.__init__ (see issue #15229) - e = SubOSErrorWithStandaloneInit() - self.assertEqual(e.args, ()) - self.assertEqual(str(e), '') - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_pep352.py b/Lib/test/test_pep352.py deleted file mode 100644 index 27d514f..0000000 --- a/Lib/test/test_pep352.py +++ /dev/null @@ -1,183 +0,0 @@ -import unittest -import builtins -import os -from platform import system as platform_system - - -class ExceptionClassTests(unittest.TestCase): - - """Tests for anything relating to exception objects themselves (e.g., - inheritance hierarchy)""" - - def test_builtins_new_style(self): - self.assertTrue(issubclass(Exception, object)) - - def verify_instance_interface(self, ins): - for attr in ("args", "__str__", "__repr__"): - self.assertTrue(hasattr(ins, attr), - "%s missing %s attribute" % - (ins.__class__.__name__, attr)) - - def test_inheritance(self): - # Make sure the inheritance hierarchy matches the documentation - exc_set = set() - for object_ in builtins.__dict__.values(): - try: - if issubclass(object_, BaseException): - exc_set.add(object_.__name__) - except TypeError: - pass - - inheritance_tree = open(os.path.join(os.path.split(__file__)[0], - 'exception_hierarchy.txt')) - try: - superclass_name = inheritance_tree.readline().rstrip() - try: - last_exc = getattr(builtins, superclass_name) - except AttributeError: - self.fail("base class %s not a built-in" % superclass_name) - self.assertIn(superclass_name, exc_set, - '%s not found' % superclass_name) - exc_set.discard(superclass_name) - superclasses = [] # Loop will insert base exception - last_depth = 0 - for exc_line in inheritance_tree: - exc_line = exc_line.rstrip() - depth = exc_line.rindex('-') - exc_name = exc_line[depth+2:] # Slice past space - if '(' in exc_name: - paren_index = exc_name.index('(') - platform_name = exc_name[paren_index+1:-1] - exc_name = exc_name[:paren_index-1] # Slice off space - if platform_system() != platform_name: - exc_set.discard(exc_name) - continue - if '[' in exc_name: - left_bracket = exc_name.index('[') - exc_name = exc_name[:left_bracket-1] # cover space - try: - exc = getattr(builtins, exc_name) - except AttributeError: - self.fail("%s not a built-in exception" % exc_name) - if last_depth < depth: - superclasses.append((last_depth, last_exc)) - elif last_depth > depth: - while superclasses[-1][0] >= depth: - superclasses.pop() - self.assertTrue(issubclass(exc, superclasses[-1][1]), - "%s is not a subclass of %s" % (exc.__name__, - superclasses[-1][1].__name__)) - try: # Some exceptions require arguments; just skip them - self.verify_instance_interface(exc()) - except TypeError: - pass - self.assertIn(exc_name, exc_set) - exc_set.discard(exc_name) - last_exc = exc - last_depth = depth - finally: - inheritance_tree.close() - self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set) - - interface_tests = ("length", "args", "str", "repr") - - def interface_test_driver(self, results): - for test_name, (given, expected) in zip(self.interface_tests, results): - self.assertEqual(given, expected, "%s: %s != %s" % (test_name, - given, expected)) - - def test_interface_single_arg(self): - # Make sure interface works properly when given a single argument - arg = "spam" - exc = Exception(arg) - results = ([len(exc.args), 1], [exc.args[0], arg], - [str(exc), str(arg)], - [repr(exc), exc.__class__.__name__ + repr(exc.args)]) - self.interface_test_driver(results) - - def test_interface_multi_arg(self): - # Make sure interface correct when multiple arguments given - arg_count = 3 - args = tuple(range(arg_count)) - exc = Exception(*args) - results = ([len(exc.args), arg_count], [exc.args, args], - [str(exc), str(args)], - [repr(exc), exc.__class__.__name__ + repr(exc.args)]) - self.interface_test_driver(results) - - def test_interface_no_arg(self): - # Make sure that with no args that interface is correct - exc = Exception() - results = ([len(exc.args), 0], [exc.args, tuple()], - [str(exc), ''], - [repr(exc), exc.__class__.__name__ + '()']) - self.interface_test_driver(results) - -class UsageTests(unittest.TestCase): - - """Test usage of exceptions""" - - def raise_fails(self, object_): - """Make sure that raising 'object_' triggers a TypeError.""" - try: - raise object_ - except TypeError: - return # What is expected. - self.fail("TypeError expected for raising %s" % type(object_)) - - def catch_fails(self, object_): - """Catching 'object_' should raise a TypeError.""" - try: - try: - raise Exception - except object_: - pass - except TypeError: - pass - except Exception: - self.fail("TypeError expected when catching %s" % type(object_)) - - try: - try: - raise Exception - except (object_,): - pass - except TypeError: - return - except Exception: - self.fail("TypeError expected when catching %s as specified in a " - "tuple" % type(object_)) - - def test_raise_new_style_non_exception(self): - # You cannot raise a new-style class that does not inherit from - # BaseException; the ability was not possible until BaseException's - # introduction so no need to support new-style objects that do not - # inherit from it. - class NewStyleClass(object): - pass - self.raise_fails(NewStyleClass) - self.raise_fails(NewStyleClass()) - - def test_raise_string(self): - # Raising a string raises TypeError. - self.raise_fails("spam") - - def test_catch_non_BaseException(self): - # Tryinng to catch an object that does not inherit from BaseException - # is not allowed. - class NonBaseException(object): - pass - self.catch_fails(NonBaseException) - self.catch_fails(NonBaseException()) - - def test_catch_BaseException_instance(self): - # Catching an instance of a BaseException subclass won't work. - self.catch_fails(BaseException()) - - def test_catch_string(self): - # Catching a string is bad. - self.catch_fails("spam") - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py deleted file mode 100644 index 23ffbed..0000000 --- a/Lib/test/test_pep380.py +++ /dev/null @@ -1,1017 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -Test suite for PEP 380 implementation - -adapted from original tests written by Greg Ewing -see -""" - -import unittest -import io -import sys -import inspect -import parser - -from test.support import captured_stderr, disable_gc, gc_collect - -class TestPEP380Operation(unittest.TestCase): - """ - Test semantics. - """ - - def test_delegation_of_initial_next_to_subgenerator(self): - """ - Test delegation of initial next() call to subgenerator - """ - trace = [] - def g1(): - trace.append("Starting g1") - yield from g2() - trace.append("Finishing g1") - def g2(): - trace.append("Starting g2") - yield 42 - trace.append("Finishing g2") - for x in g1(): - trace.append("Yielded %s" % (x,)) - self.assertEqual(trace,[ - "Starting g1", - "Starting g2", - "Yielded 42", - "Finishing g2", - "Finishing g1", - ]) - - def test_raising_exception_in_initial_next_call(self): - """ - Test raising exception in initial next() call - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield from g2() - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - raise ValueError("spanish inquisition occurred") - finally: - trace.append("Finishing g2") - try: - for x in g1(): - trace.append("Yielded %s" % (x,)) - except ValueError as e: - self.assertEqual(e.args[0], "spanish inquisition occurred") - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Starting g1", - "Starting g2", - "Finishing g2", - "Finishing g1", - ]) - - def test_delegation_of_next_call_to_subgenerator(self): - """ - Test delegation of next() call to subgenerator - """ - trace = [] - def g1(): - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - trace.append("Finishing g1") - def g2(): - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - trace.append("Finishing g2") - for x in g1(): - trace.append("Yielded %s" % (x,)) - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Yielded g2 more spam", - "Finishing g2", - "Yielded g1 eggs", - "Finishing g1", - ]) - - def test_raising_exception_in_delegated_next_call(self): - """ - Test raising exception in delegated next() call - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - yield "g2 spam" - raise ValueError("hovercraft is full of eels") - yield "g2 more spam" - finally: - trace.append("Finishing g2") - try: - for x in g1(): - trace.append("Yielded %s" % (x,)) - except ValueError as e: - self.assertEqual(e.args[0], "hovercraft is full of eels") - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Finishing g2", - "Finishing g1", - ]) - - def test_delegation_of_send(self): - """ - Test delegation of send() - """ - trace = [] - def g1(): - trace.append("Starting g1") - x = yield "g1 ham" - trace.append("g1 received %s" % (x,)) - yield from g2() - x = yield "g1 eggs" - trace.append("g1 received %s" % (x,)) - trace.append("Finishing g1") - def g2(): - trace.append("Starting g2") - x = yield "g2 spam" - trace.append("g2 received %s" % (x,)) - x = yield "g2 more spam" - trace.append("g2 received %s" % (x,)) - trace.append("Finishing g2") - g = g1() - y = next(g) - x = 1 - try: - while 1: - y = g.send(x) - trace.append("Yielded %s" % (y,)) - x += 1 - except StopIteration: - pass - self.assertEqual(trace,[ - "Starting g1", - "g1 received 1", - "Starting g2", - "Yielded g2 spam", - "g2 received 2", - "Yielded g2 more spam", - "g2 received 3", - "Finishing g2", - "Yielded g1 eggs", - "g1 received 4", - "Finishing g1", - ]) - - def test_handling_exception_while_delegating_send(self): - """ - Test handling exception while delegating 'send' - """ - trace = [] - def g1(): - trace.append("Starting g1") - x = yield "g1 ham" - trace.append("g1 received %s" % (x,)) - yield from g2() - x = yield "g1 eggs" - trace.append("g1 received %s" % (x,)) - trace.append("Finishing g1") - def g2(): - trace.append("Starting g2") - x = yield "g2 spam" - trace.append("g2 received %s" % (x,)) - raise ValueError("hovercraft is full of eels") - x = yield "g2 more spam" - trace.append("g2 received %s" % (x,)) - trace.append("Finishing g2") - def run(): - g = g1() - y = next(g) - x = 1 - try: - while 1: - y = g.send(x) - trace.append("Yielded %s" % (y,)) - x += 1 - except StopIteration: - trace.append("StopIteration") - self.assertRaises(ValueError,run) - self.assertEqual(trace,[ - "Starting g1", - "g1 received 1", - "Starting g2", - "Yielded g2 spam", - "g2 received 2", - ]) - - def test_delegating_close(self): - """ - Test delegating 'close' - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - finally: - trace.append("Finishing g2") - g = g1() - for i in range(2): - x = next(g) - trace.append("Yielded %s" % (x,)) - g.close() - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Finishing g2", - "Finishing g1" - ]) - - def test_handing_exception_while_delegating_close(self): - """ - Test handling exception while delegating 'close' - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - finally: - trace.append("Finishing g2") - raise ValueError("nybbles have exploded with delight") - try: - g = g1() - for i in range(2): - x = next(g) - trace.append("Yielded %s" % (x,)) - g.close() - except ValueError as e: - self.assertEqual(e.args[0], "nybbles have exploded with delight") - self.assertIsInstance(e.__context__, GeneratorExit) - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Finishing g2", - "Finishing g1", - ]) - - def test_delegating_throw(self): - """ - Test delegating 'throw' - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - finally: - trace.append("Finishing g2") - try: - g = g1() - for i in range(2): - x = next(g) - trace.append("Yielded %s" % (x,)) - e = ValueError("tomato ejected") - g.throw(e) - except ValueError as e: - self.assertEqual(e.args[0], "tomato ejected") - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Finishing g2", - "Finishing g1", - ]) - - def test_value_attribute_of_StopIteration_exception(self): - """ - Test 'value' attribute of StopIteration exception - """ - trace = [] - def pex(e): - trace.append("%s: %s" % (e.__class__.__name__, e)) - trace.append("value = %s" % (e.value,)) - e = StopIteration() - pex(e) - e = StopIteration("spam") - pex(e) - e.value = "eggs" - pex(e) - self.assertEqual(trace,[ - "StopIteration: ", - "value = None", - "StopIteration: spam", - "value = spam", - "StopIteration: spam", - "value = eggs", - ]) - - - def test_exception_value_crash(self): - # There used to be a refcount error when the return value - # stored in the StopIteration has a refcount of 1. - def g1(): - yield from g2() - def g2(): - yield "g2" - return [42] - self.assertEqual(list(g1()), ["g2"]) - - - def test_generator_return_value(self): - """ - Test generator return value - """ - trace = [] - def g1(): - trace.append("Starting g1") - yield "g1 ham" - ret = yield from g2() - trace.append("g2 returned %s" % (ret,)) - ret = yield from g2(42) - trace.append("g2 returned %s" % (ret,)) - yield "g1 eggs" - trace.append("Finishing g1") - def g2(v = None): - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - trace.append("Finishing g2") - if v: - return v - for x in g1(): - trace.append("Yielded %s" % (x,)) - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Yielded g2 more spam", - "Finishing g2", - "g2 returned None", - "Starting g2", - "Yielded g2 spam", - "Yielded g2 more spam", - "Finishing g2", - "g2 returned 42", - "Yielded g1 eggs", - "Finishing g1", - ]) - - def test_delegation_of_next_to_non_generator(self): - """ - Test delegation of next() to non-generator - """ - trace = [] - def g(): - yield from range(3) - for x in g(): - trace.append("Yielded %s" % (x,)) - self.assertEqual(trace,[ - "Yielded 0", - "Yielded 1", - "Yielded 2", - ]) - - - def test_conversion_of_sendNone_to_next(self): - """ - Test conversion of send(None) to next() - """ - trace = [] - def g(): - yield from range(3) - gi = g() - for x in range(3): - y = gi.send(None) - trace.append("Yielded: %s" % (y,)) - self.assertEqual(trace,[ - "Yielded: 0", - "Yielded: 1", - "Yielded: 2", - ]) - - def test_delegation_of_close_to_non_generator(self): - """ - Test delegation of close() to non-generator - """ - trace = [] - def g(): - try: - trace.append("starting g") - yield from range(3) - trace.append("g should not be here") - finally: - trace.append("finishing g") - gi = g() - next(gi) - with captured_stderr() as output: - gi.close() - self.assertEqual(output.getvalue(), '') - self.assertEqual(trace,[ - "starting g", - "finishing g", - ]) - - def test_delegating_throw_to_non_generator(self): - """ - Test delegating 'throw' to non-generator - """ - trace = [] - def g(): - try: - trace.append("Starting g") - yield from range(10) - finally: - trace.append("Finishing g") - try: - gi = g() - for i in range(5): - x = next(gi) - trace.append("Yielded %s" % (x,)) - e = ValueError("tomato ejected") - gi.throw(e) - except ValueError as e: - self.assertEqual(e.args[0],"tomato ejected") - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Starting g", - "Yielded 0", - "Yielded 1", - "Yielded 2", - "Yielded 3", - "Yielded 4", - "Finishing g", - ]) - - def test_attempting_to_send_to_non_generator(self): - """ - Test attempting to send to non-generator - """ - trace = [] - def g(): - try: - trace.append("starting g") - yield from range(3) - trace.append("g should not be here") - finally: - trace.append("finishing g") - try: - gi = g() - next(gi) - for x in range(3): - y = gi.send(42) - trace.append("Should not have yielded: %s" % (y,)) - except AttributeError as e: - self.assertIn("send", e.args[0]) - else: - self.fail("was able to send into non-generator") - self.assertEqual(trace,[ - "starting g", - "finishing g", - ]) - - def test_broken_getattr_handling(self): - """ - Test subiterator with a broken getattr implementation - """ - class Broken: - def __iter__(self): - return self - def __next__(self): - return 1 - def __getattr__(self, attr): - 1/0 - - def g(): - yield from Broken() - - with self.assertRaises(ZeroDivisionError): - gi = g() - self.assertEqual(next(gi), 1) - gi.send(1) - - with self.assertRaises(ZeroDivisionError): - gi = g() - self.assertEqual(next(gi), 1) - gi.throw(AttributeError) - - with captured_stderr() as output: - gi = g() - self.assertEqual(next(gi), 1) - gi.close() - self.assertIn('ZeroDivisionError', output.getvalue()) - - def test_exception_in_initial_next_call(self): - """ - Test exception in initial next() call - """ - trace = [] - def g1(): - trace.append("g1 about to yield from g2") - yield from g2() - trace.append("g1 should not be here") - def g2(): - yield 1/0 - def run(): - gi = g1() - next(gi) - self.assertRaises(ZeroDivisionError,run) - self.assertEqual(trace,[ - "g1 about to yield from g2" - ]) - - def test_attempted_yield_from_loop(self): - """ - Test attempted yield-from loop - """ - trace = [] - def g1(): - trace.append("g1: starting") - yield "y1" - trace.append("g1: about to yield from g2") - yield from g2() - trace.append("g1 should not be here") - - def g2(): - trace.append("g2: starting") - yield "y2" - trace.append("g2: about to yield from g1") - yield from gi - trace.append("g2 should not be here") - try: - gi = g1() - for y in gi: - trace.append("Yielded: %s" % (y,)) - except ValueError as e: - self.assertEqual(e.args[0],"generator already executing") - else: - self.fail("subgenerator didn't raise ValueError") - self.assertEqual(trace,[ - "g1: starting", - "Yielded: y1", - "g1: about to yield from g2", - "g2: starting", - "Yielded: y2", - "g2: about to yield from g1", - ]) - - def test_returning_value_from_delegated_throw(self): - """ - Test returning value from delegated 'throw' - """ - trace = [] - def g1(): - try: - trace.append("Starting g1") - yield "g1 ham" - yield from g2() - yield "g1 eggs" - finally: - trace.append("Finishing g1") - def g2(): - try: - trace.append("Starting g2") - yield "g2 spam" - yield "g2 more spam" - except LunchError: - trace.append("Caught LunchError in g2") - yield "g2 lunch saved" - yield "g2 yet more spam" - class LunchError(Exception): - pass - g = g1() - for i in range(2): - x = next(g) - trace.append("Yielded %s" % (x,)) - e = LunchError("tomato ejected") - g.throw(e) - for x in g: - trace.append("Yielded %s" % (x,)) - self.assertEqual(trace,[ - "Starting g1", - "Yielded g1 ham", - "Starting g2", - "Yielded g2 spam", - "Caught LunchError in g2", - "Yielded g2 yet more spam", - "Yielded g1 eggs", - "Finishing g1", - ]) - - def test_next_and_return_with_value(self): - """ - Test next and return with value - """ - trace = [] - def f(r): - gi = g(r) - next(gi) - try: - trace.append("f resuming g") - next(gi) - trace.append("f SHOULD NOT BE HERE") - except StopIteration as e: - trace.append("f caught %s" % (repr(e),)) - def g(r): - trace.append("g starting") - yield - trace.append("g returning %s" % (r,)) - return r - f(None) - f(42) - self.assertEqual(trace,[ - "g starting", - "f resuming g", - "g returning None", - "f caught StopIteration()", - "g starting", - "f resuming g", - "g returning 42", - "f caught StopIteration(42,)", - ]) - - def test_send_and_return_with_value(self): - """ - Test send and return with value - """ - trace = [] - def f(r): - gi = g(r) - next(gi) - try: - trace.append("f sending spam to g") - gi.send("spam") - trace.append("f SHOULD NOT BE HERE") - except StopIteration as e: - trace.append("f caught %r" % (e,)) - def g(r): - trace.append("g starting") - x = yield - trace.append("g received %s" % (x,)) - trace.append("g returning %s" % (r,)) - return r - f(None) - f(42) - self.assertEqual(trace,[ - "g starting", - "f sending spam to g", - "g received spam", - "g returning None", - "f caught StopIteration()", - "g starting", - "f sending spam to g", - "g received spam", - "g returning 42", - "f caught StopIteration(42,)", - ]) - - def test_catching_exception_from_subgen_and_returning(self): - """ - Test catching an exception thrown into a - subgenerator and returning a value - """ - trace = [] - def inner(): - try: - yield 1 - except ValueError: - trace.append("inner caught ValueError") - return 2 - - def outer(): - v = yield from inner() - trace.append("inner returned %r to outer" % v) - yield v - g = outer() - trace.append(next(g)) - trace.append(g.throw(ValueError)) - self.assertEqual(trace,[ - 1, - "inner caught ValueError", - "inner returned 2 to outer", - 2, - ]) - - def test_throwing_GeneratorExit_into_subgen_that_returns(self): - """ - Test throwing GeneratorExit into a subgenerator that - catches it and returns normally. - """ - trace = [] - def f(): - try: - trace.append("Enter f") - yield - trace.append("Exit f") - except GeneratorExit: - return - def g(): - trace.append("Enter g") - yield from f() - trace.append("Exit g") - try: - gi = g() - next(gi) - gi.throw(GeneratorExit) - except GeneratorExit: - pass - else: - self.fail("subgenerator failed to raise GeneratorExit") - self.assertEqual(trace,[ - "Enter g", - "Enter f", - ]) - - def test_throwing_GeneratorExit_into_subgenerator_that_yields(self): - """ - Test throwing GeneratorExit into a subgenerator that - catches it and yields. - """ - trace = [] - def f(): - try: - trace.append("Enter f") - yield - trace.append("Exit f") - except GeneratorExit: - yield - def g(): - trace.append("Enter g") - yield from f() - trace.append("Exit g") - try: - gi = g() - next(gi) - gi.throw(GeneratorExit) - except RuntimeError as e: - self.assertEqual(e.args[0], "generator ignored GeneratorExit") - else: - self.fail("subgenerator failed to raise GeneratorExit") - self.assertEqual(trace,[ - "Enter g", - "Enter f", - ]) - - def test_throwing_GeneratorExit_into_subgen_that_raises(self): - """ - Test throwing GeneratorExit into a subgenerator that - catches it and raises a different exception. - """ - trace = [] - def f(): - try: - trace.append("Enter f") - yield - trace.append("Exit f") - except GeneratorExit: - raise ValueError("Vorpal bunny encountered") - def g(): - trace.append("Enter g") - yield from f() - trace.append("Exit g") - try: - gi = g() - next(gi) - gi.throw(GeneratorExit) - except ValueError as e: - self.assertEqual(e.args[0], "Vorpal bunny encountered") - self.assertIsInstance(e.__context__, GeneratorExit) - else: - self.fail("subgenerator failed to raise ValueError") - self.assertEqual(trace,[ - "Enter g", - "Enter f", - ]) - - def test_yield_from_empty(self): - def g(): - yield from () - self.assertRaises(StopIteration, next, g()) - - def test_delegating_generators_claim_to_be_running(self): - # Check with basic iteration - def one(): - yield 0 - yield from two() - yield 3 - def two(): - yield 1 - try: - yield from g1 - except ValueError: - pass - yield 2 - g1 = one() - self.assertEqual(list(g1), [0, 1, 2, 3]) - # Check with send - g1 = one() - res = [next(g1)] - try: - while True: - res.append(g1.send(42)) - except StopIteration: - pass - self.assertEqual(res, [0, 1, 2, 3]) - # Check with throw - class MyErr(Exception): - pass - def one(): - try: - yield 0 - except MyErr: - pass - yield from two() - try: - yield 3 - except MyErr: - pass - def two(): - try: - yield 1 - except MyErr: - pass - try: - yield from g1 - except ValueError: - pass - try: - yield 2 - except MyErr: - pass - g1 = one() - res = [next(g1)] - try: - while True: - res.append(g1.throw(MyErr)) - except StopIteration: - pass - # Check with close - class MyIt(object): - def __iter__(self): - return self - def __next__(self): - return 42 - def close(self_): - self.assertTrue(g1.gi_running) - self.assertRaises(ValueError, next, g1) - def one(): - yield from MyIt() - g1 = one() - next(g1) - g1.close() - - def test_delegator_is_visible_to_debugger(self): - def call_stack(): - return [f[3] for f in inspect.stack()] - - def gen(): - yield call_stack() - yield call_stack() - yield call_stack() - - def spam(g): - yield from g - - def eggs(g): - yield from g - - for stack in spam(gen()): - self.assertTrue('spam' in stack) - - for stack in spam(eggs(gen())): - self.assertTrue('spam' in stack and 'eggs' in stack) - - def test_custom_iterator_return(self): - # See issue #15568 - class MyIter: - def __iter__(self): - return self - def __next__(self): - raise StopIteration(42) - def gen(): - nonlocal ret - ret = yield from MyIter() - ret = None - list(gen()) - self.assertEqual(ret, 42) - - def test_close_with_cleared_frame(self): - # See issue #17669. - # - # Create a stack of generators: outer() delegating to inner() - # delegating to innermost(). The key point is that the instance of - # inner is created first: this ensures that its frame appears before - # the instance of outer in the GC linked list. - # - # At the gc.collect call: - # - frame_clear is called on the inner_gen frame. - # - gen_dealloc is called on the outer_gen generator (the only - # reference is in the frame's locals). - # - gen_close is called on the outer_gen generator. - # - gen_close_iter is called to close the inner_gen generator, which - # in turn calls gen_close, and gen_yf. - # - # Previously, gen_yf would crash since inner_gen's frame had been - # cleared (and in particular f_stacktop was NULL). - - def innermost(): - yield - def inner(): - outer_gen = yield - yield from innermost() - def outer(): - inner_gen = yield - yield from inner_gen - - with disable_gc(): - inner_gen = inner() - outer_gen = outer() - outer_gen.send(None) - outer_gen.send(inner_gen) - outer_gen.send(outer_gen) - - del outer_gen - del inner_gen - gc_collect() - - def test_send_tuple_with_custom_generator(self): - # See issue #21209. - class MyGen: - def __iter__(self): - return self - def __next__(self): - return 42 - def send(self, what): - nonlocal v - v = what - return None - def outer(): - v = yield from MyGen() - g = outer() - next(g) - v = None - g.send((1, 2, 3, 4)) - self.assertEqual(v, (1, 2, 3, 4)) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_pep479.py b/Lib/test/test_pep479.py deleted file mode 100644 index bc235ce..0000000 --- a/Lib/test/test_pep479.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import generator_stop - -import unittest - - -class TestPEP479(unittest.TestCase): - def test_stopiteration_wrapping(self): - def f(): - raise StopIteration - def g(): - yield f() - with self.assertRaisesRegex(RuntimeError, - "generator raised StopIteration"): - next(g()) - - def test_stopiteration_wrapping_context(self): - def f(): - raise StopIteration - def g(): - yield f() - - try: - next(g()) - except RuntimeError as exc: - self.assertIs(type(exc.__cause__), StopIteration) - self.assertIs(type(exc.__context__), StopIteration) - self.assertTrue(exc.__suppress_context__) - else: - self.fail('__cause__, __context__, or __suppress_context__ ' - 'were not properly set') - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_pep509.py b/Lib/test/test_pep509.py deleted file mode 100644 index 5671f9f..0000000 --- a/Lib/test/test_pep509.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -Test implementation of the PEP 509: dictionary versionning. -""" -import unittest -from test import support - -# PEP 509 is implemented in CPython but other Python implementations -# don't require to implement it -_testcapi = support.import_module('_testcapi') - - -class DictVersionTests(unittest.TestCase): - type2test = dict - - def setUp(self): - self.seen_versions = set() - self.dict = None - - def check_version_unique(self, mydict): - version = _testcapi.dict_get_version(mydict) - self.assertNotIn(version, self.seen_versions) - self.seen_versions.add(version) - - def check_version_changed(self, mydict, method, *args, **kw): - result = method(*args, **kw) - self.check_version_unique(mydict) - return result - - def check_version_dont_change(self, mydict, method, *args, **kw): - version1 = _testcapi.dict_get_version(mydict) - self.seen_versions.add(version1) - - result = method(*args, **kw) - - version2 = _testcapi.dict_get_version(mydict) - self.assertEqual(version2, version1, "version changed") - - return result - - def new_dict(self, *args, **kw): - d = self.type2test(*args, **kw) - self.check_version_unique(d) - return d - - def test_constructor(self): - # new empty dictionaries must all have an unique version - empty1 = self.new_dict() - empty2 = self.new_dict() - empty3 = self.new_dict() - - # non-empty dictionaries must also have an unique version - nonempty1 = self.new_dict(x='x') - nonempty2 = self.new_dict(x='x', y='y') - - def test_copy(self): - d = self.new_dict(a=1, b=2) - - d2 = self.check_version_dont_change(d, d.copy) - - # dict.copy() must create a dictionary with a new unique version - self.check_version_unique(d2) - - def test_setitem(self): - d = self.new_dict() - - # creating new keys must change the version - self.check_version_changed(d, d.__setitem__, 'x', 'x') - self.check_version_changed(d, d.__setitem__, 'y', 'y') - - # changing values must change the version - self.check_version_changed(d, d.__setitem__, 'x', 1) - self.check_version_changed(d, d.__setitem__, 'y', 2) - - def test_setitem_same_value(self): - value = object() - d = self.new_dict() - - # setting a key must change the version - self.check_version_changed(d, d.__setitem__, 'key', value) - - # setting a key to the same value with dict.__setitem__ - # must change the version - self.check_version_changed(d, d.__setitem__, 'key', value) - - # setting a key to the same value with dict.update - # must change the version - self.check_version_changed(d, d.update, key=value) - - d2 = self.new_dict(key=value) - self.check_version_changed(d, d.update, d2) - - def test_setitem_equal(self): - class AlwaysEqual: - def __eq__(self, other): - return True - - value1 = AlwaysEqual() - value2 = AlwaysEqual() - self.assertTrue(value1 == value2) - self.assertFalse(value1 != value2) - - d = self.new_dict() - self.check_version_changed(d, d.__setitem__, 'key', value1) - - # setting a key to a value equal to the current value - # with dict.__setitem__() must change the version - self.check_version_changed(d, d.__setitem__, 'key', value2) - - # setting a key to a value equal to the current value - # with dict.update() must change the version - self.check_version_changed(d, d.update, key=value1) - - d2 = self.new_dict(key=value2) - self.check_version_changed(d, d.update, d2) - - def test_setdefault(self): - d = self.new_dict() - - # setting a key with dict.setdefault() must change the version - self.check_version_changed(d, d.setdefault, 'key', 'value1') - - # don't change the version if the key already exists - self.check_version_dont_change(d, d.setdefault, 'key', 'value2') - - def test_delitem(self): - d = self.new_dict(key='value') - - # deleting a key with dict.__delitem__() must change the version - self.check_version_changed(d, d.__delitem__, 'key') - - # don't change the version if the key doesn't exist - self.check_version_dont_change(d, self.assertRaises, KeyError, - d.__delitem__, 'key') - - def test_pop(self): - d = self.new_dict(key='value') - - # pop() must change the version if the key exists - self.check_version_changed(d, d.pop, 'key') - - # pop() must not change the version if the key does not exist - self.check_version_dont_change(d, self.assertRaises, KeyError, - d.pop, 'key') - - def test_popitem(self): - d = self.new_dict(key='value') - - # popitem() must change the version if the dict is not empty - self.check_version_changed(d, d.popitem) - - # popitem() must not change the version if the dict is empty - self.check_version_dont_change(d, self.assertRaises, KeyError, - d.popitem) - - def test_update(self): - d = self.new_dict(key='value') - - # update() calling with no argument must not change the version - self.check_version_dont_change(d, d.update) - - # update() must change the version - self.check_version_changed(d, d.update, key='new value') - - d2 = self.new_dict(key='value 3') - self.check_version_changed(d, d.update, d2) - - def test_clear(self): - d = self.new_dict(key='value') - - # clear() must change the version if the dict is not empty - self.check_version_changed(d, d.clear) - - # clear() must not change the version if the dict is empty - self.check_version_dont_change(d, d.clear) - - -class Dict(dict): - pass - - -class DictSubtypeVersionTests(DictVersionTests): - type2test = Dict - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 77c0423..4c469a8 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1529,12 +1529,13 @@ class TestRoundtrip(TestCase): tempdir = os.path.dirname(fn) or os.curdir testfiles = glob.glob(os.path.join(tempdir, "test*.py")) - # Tokenize is broken on test_pep3131.py because regular expressions are - # broken on the obscure unicode identifiers in it. *sigh* - # With roundtrip extended to test the 5-tuple mode of untokenize, - # 7 more testfiles fail. Remove them also until the failure is diagnosed. + # Tokenize is broken on test_unicode_identifiers.py because regular + # expressions are broken on the obscure unicode identifiers in it. + # *sigh* With roundtrip extended to test the 5-tuple mode of + # untokenize, 7 more testfiles fail. Remove them also until the + # failure is diagnosed. - testfiles.remove(os.path.join(tempdir, "test_pep3131.py")) + testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py")) for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'): testfiles.remove(os.path.join(tempdir, "test_%s.py") % f) diff --git a/Lib/test/test_unicode_file_functions.py b/Lib/test/test_unicode_file_functions.py new file mode 100644 index 0000000..98c716b --- /dev/null +++ b/Lib/test/test_unicode_file_functions.py @@ -0,0 +1,195 @@ +# Test the Unicode versions of normal file functions +# open, os.open, os.stat. os.listdir, os.rename, os.remove, os.mkdir, os.chdir, os.rmdir +import os +import sys +import unittest +import warnings +from unicodedata import normalize +from test import support + +filenames = [ + '1_abc', + '2_ascii', + '3_Gr\xfc\xdf-Gott', + '4_\u0393\u03b5\u03b9\u03ac-\u03c3\u03b1\u03c2', + '5_\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435', + '6_\u306b\u307d\u3093', + '7_\u05d4\u05e9\u05e7\u05e6\u05e5\u05e1', + '8_\u66e8\u66e9\u66eb', + '9_\u66e8\u05e9\u3093\u0434\u0393\xdf', + # Specific code points: fn, NFC(fn) and NFKC(fn) all differents + '10_\u1fee\u1ffd', + ] + +# Mac OS X decomposes Unicode names, using Normal Form D. +# http://developer.apple.com/mac/library/qa/qa2001/qa1173.html +# "However, most volume formats do not follow the exact specification for +# these normal forms. For example, HFS Plus uses a variant of Normal Form D +# in which U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through +# U+2FAFF are not decomposed." +if sys.platform != 'darwin': + filenames.extend([ + # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all differents + '11_\u0385\u03d3\u03d4', + '12_\u00a8\u0301\u03d2\u0301\u03d2\u0308', # == NFD('\u0385\u03d3\u03d4') + '13_\u0020\u0308\u0301\u038e\u03ab', # == NFKC('\u0385\u03d3\u03d4') + '14_\u1e9b\u1fc1\u1fcd\u1fce\u1fcf\u1fdd\u1fde\u1fdf\u1fed', + + # Specific code points: fn, NFC(fn) and NFKC(fn) all differents + '15_\u1fee\u1ffd\ufad1', + '16_\u2000\u2000\u2000A', + '17_\u2001\u2001\u2001A', + '18_\u2003\u2003\u2003A', # == NFC('\u2001\u2001\u2001A') + '19_\u0020\u0020\u0020A', # '\u0020' == ' ' == NFKC('\u2000') == + # NFKC('\u2001') == NFKC('\u2003') + ]) + + +# Is it Unicode-friendly? +if not os.path.supports_unicode_filenames: + fsencoding = sys.getfilesystemencoding() + try: + for name in filenames: + name.encode(fsencoding) + except UnicodeEncodeError: + raise unittest.SkipTest("only NT+ and systems with " + "Unicode-friendly filesystem encoding") + + +class UnicodeFileTests(unittest.TestCase): + files = set(filenames) + normal_form = None + + def setUp(self): + try: + os.mkdir(support.TESTFN) + except FileExistsError: + pass + self.addCleanup(support.rmtree, support.TESTFN) + + files = set() + for name in self.files: + name = os.path.join(support.TESTFN, self.norm(name)) + with open(name, 'wb') as f: + f.write((name+'\n').encode("utf-8")) + os.stat(name) + files.add(name) + self.files = files + + def norm(self, s): + if self.normal_form: + return normalize(self.normal_form, s) + return s + + def _apply_failure(self, fn, filename, + expected_exception=FileNotFoundError, + check_filename=True): + with self.assertRaises(expected_exception) as c: + fn(filename) + exc_filename = c.exception.filename + if check_filename: + self.assertEqual(exc_filename, filename, "Function '%s(%a) failed " + "with bad filename in the exception: %a" % + (fn.__name__, filename, exc_filename)) + + def test_failures(self): + # Pass non-existing Unicode filenames all over the place. + for name in self.files: + name = "not_" + name + self._apply_failure(open, name) + self._apply_failure(os.stat, name) + self._apply_failure(os.chdir, name) + self._apply_failure(os.rmdir, name) + self._apply_failure(os.remove, name) + self._apply_failure(os.listdir, name) + + if sys.platform == 'win32': + # Windows is lunatic. Issue #13366. + _listdir_failure = NotADirectoryError, FileNotFoundError + else: + _listdir_failure = NotADirectoryError + + def test_open(self): + for name in self.files: + f = open(name, 'wb') + f.write((name+'\n').encode("utf-8")) + f.close() + os.stat(name) + self._apply_failure(os.listdir, name, self._listdir_failure) + + # Skip the test on darwin, because darwin does normalize the filename to + # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC, + # NFKD in Python is useless, because darwin will normalize it later and so + # open(), os.stat(), etc. don't raise any exception. + @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') + def test_normalize(self): + files = set(self.files) + others = set() + for nf in set(['NFC', 'NFD', 'NFKC', 'NFKD']): + others |= set(normalize(nf, file) for file in files) + others -= files + for name in others: + self._apply_failure(open, name) + self._apply_failure(os.stat, name) + self._apply_failure(os.chdir, name) + self._apply_failure(os.rmdir, name) + self._apply_failure(os.remove, name) + self._apply_failure(os.listdir, name) + + # Skip the test on darwin, because darwin uses a normalization different + # than Python NFD normalization: filenames are different even if we use + # Python NFD normalization. + @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') + def test_listdir(self): + sf0 = set(self.files) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + f1 = os.listdir(support.TESTFN.encode(sys.getfilesystemencoding())) + f2 = os.listdir(support.TESTFN) + sf2 = set(os.path.join(support.TESTFN, f) for f in f2) + self.assertEqual(sf0, sf2, "%a != %a" % (sf0, sf2)) + self.assertEqual(len(f1), len(f2)) + + def test_rename(self): + for name in self.files: + os.rename(name, "tmp") + os.rename("tmp", name) + + def test_directory(self): + dirname = os.path.join(support.TESTFN, 'Gr\xfc\xdf-\u66e8\u66e9\u66eb') + filename = '\xdf-\u66e8\u66e9\u66eb' + with support.temp_cwd(dirname): + with open(filename, 'wb') as f: + f.write((filename + '\n').encode("utf-8")) + os.access(filename,os.R_OK) + os.remove(filename) + + +class UnicodeNFCFileTests(UnicodeFileTests): + normal_form = 'NFC' + + +class UnicodeNFDFileTests(UnicodeFileTests): + normal_form = 'NFD' + + +class UnicodeNFKCFileTests(UnicodeFileTests): + normal_form = 'NFKC' + + +class UnicodeNFKDFileTests(UnicodeFileTests): + normal_form = 'NFKD' + + +def test_main(): + support.run_unittest( + UnicodeFileTests, + UnicodeNFCFileTests, + UnicodeNFDFileTests, + UnicodeNFKCFileTests, + UnicodeNFKDFileTests, + ) + + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_unicode_identifiers.py b/Lib/test/test_unicode_identifiers.py new file mode 100644 index 0000000..0679845 --- /dev/null +++ b/Lib/test/test_unicode_identifiers.py @@ -0,0 +1,31 @@ +import unittest +import sys + +class PEP3131Test(unittest.TestCase): + + def test_valid(self): + class T: + ä = 1 + µ = 2 # this is a compatibility character + 蟒 = 3 + x󠄀 = 4 + self.assertEqual(getattr(T, "\xe4"), 1) + self.assertEqual(getattr(T, "\u03bc"), 2) + self.assertEqual(getattr(T, '\u87d2'), 3) + self.assertEqual(getattr(T, 'x\U000E0100'), 4) + + def test_non_bmp_normalized(self): + 𝔘𝔫𝔦𝔠𝔬𝔡𝔢 = 1 + self.assertIn("Unicode", dir()) + + def test_invalid(self): + try: + from test import badsyntax_3131 + except SyntaxError as s: + self.assertEqual(str(s), + "invalid character in identifier (badsyntax_3131.py, line 2)") + else: + self.fail("expected exception didn't occur") + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_utf8source.py b/Lib/test/test_utf8source.py new file mode 100644 index 0000000..97dced8 --- /dev/null +++ b/Lib/test/test_utf8source.py @@ -0,0 +1,43 @@ +# This file is marked as binary in the CVS, to prevent MacCVS from recoding it. + +import unittest + +class PEP3120Test(unittest.TestCase): + + def test_pep3120(self): + self.assertEqual( + "Питон".encode("utf-8"), + b'\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd' + ) + self.assertEqual( + "\П".encode("utf-8"), + b'\\\xd0\x9f' + ) + + def test_badsyntax(self): + try: + import test.badsyntax_pep3120 + except SyntaxError as msg: + msg = str(msg).lower() + self.assertTrue('utf-8' in msg) + else: + self.fail("expected exception didn't occur") + + +class BuiltinCompileTests(unittest.TestCase): + + # Issue 3574. + def test_latin1(self): + # Allow compile() to read Latin-1 source. + source_code = '# coding: Latin-1\nu = "Ç"\n'.encode("Latin-1") + try: + code = compile(source_code, '', 'exec') + except SyntaxError: + self.fail("compile() cannot handle Latin-1 source") + ns = {} + exec(code, ns) + self.assertEqual('Ç', ns['u']) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_yield_from.py b/Lib/test/test_yield_from.py new file mode 100644 index 0000000..23ffbed --- /dev/null +++ b/Lib/test/test_yield_from.py @@ -0,0 +1,1017 @@ +# -*- coding: utf-8 -*- + +""" +Test suite for PEP 380 implementation + +adapted from original tests written by Greg Ewing +see +""" + +import unittest +import io +import sys +import inspect +import parser + +from test.support import captured_stderr, disable_gc, gc_collect + +class TestPEP380Operation(unittest.TestCase): + """ + Test semantics. + """ + + def test_delegation_of_initial_next_to_subgenerator(self): + """ + Test delegation of initial next() call to subgenerator + """ + trace = [] + def g1(): + trace.append("Starting g1") + yield from g2() + trace.append("Finishing g1") + def g2(): + trace.append("Starting g2") + yield 42 + trace.append("Finishing g2") + for x in g1(): + trace.append("Yielded %s" % (x,)) + self.assertEqual(trace,[ + "Starting g1", + "Starting g2", + "Yielded 42", + "Finishing g2", + "Finishing g1", + ]) + + def test_raising_exception_in_initial_next_call(self): + """ + Test raising exception in initial next() call + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield from g2() + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + raise ValueError("spanish inquisition occurred") + finally: + trace.append("Finishing g2") + try: + for x in g1(): + trace.append("Yielded %s" % (x,)) + except ValueError as e: + self.assertEqual(e.args[0], "spanish inquisition occurred") + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Starting g1", + "Starting g2", + "Finishing g2", + "Finishing g1", + ]) + + def test_delegation_of_next_call_to_subgenerator(self): + """ + Test delegation of next() call to subgenerator + """ + trace = [] + def g1(): + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + trace.append("Finishing g1") + def g2(): + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + trace.append("Finishing g2") + for x in g1(): + trace.append("Yielded %s" % (x,)) + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Yielded g2 more spam", + "Finishing g2", + "Yielded g1 eggs", + "Finishing g1", + ]) + + def test_raising_exception_in_delegated_next_call(self): + """ + Test raising exception in delegated next() call + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + yield "g2 spam" + raise ValueError("hovercraft is full of eels") + yield "g2 more spam" + finally: + trace.append("Finishing g2") + try: + for x in g1(): + trace.append("Yielded %s" % (x,)) + except ValueError as e: + self.assertEqual(e.args[0], "hovercraft is full of eels") + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Finishing g2", + "Finishing g1", + ]) + + def test_delegation_of_send(self): + """ + Test delegation of send() + """ + trace = [] + def g1(): + trace.append("Starting g1") + x = yield "g1 ham" + trace.append("g1 received %s" % (x,)) + yield from g2() + x = yield "g1 eggs" + trace.append("g1 received %s" % (x,)) + trace.append("Finishing g1") + def g2(): + trace.append("Starting g2") + x = yield "g2 spam" + trace.append("g2 received %s" % (x,)) + x = yield "g2 more spam" + trace.append("g2 received %s" % (x,)) + trace.append("Finishing g2") + g = g1() + y = next(g) + x = 1 + try: + while 1: + y = g.send(x) + trace.append("Yielded %s" % (y,)) + x += 1 + except StopIteration: + pass + self.assertEqual(trace,[ + "Starting g1", + "g1 received 1", + "Starting g2", + "Yielded g2 spam", + "g2 received 2", + "Yielded g2 more spam", + "g2 received 3", + "Finishing g2", + "Yielded g1 eggs", + "g1 received 4", + "Finishing g1", + ]) + + def test_handling_exception_while_delegating_send(self): + """ + Test handling exception while delegating 'send' + """ + trace = [] + def g1(): + trace.append("Starting g1") + x = yield "g1 ham" + trace.append("g1 received %s" % (x,)) + yield from g2() + x = yield "g1 eggs" + trace.append("g1 received %s" % (x,)) + trace.append("Finishing g1") + def g2(): + trace.append("Starting g2") + x = yield "g2 spam" + trace.append("g2 received %s" % (x,)) + raise ValueError("hovercraft is full of eels") + x = yield "g2 more spam" + trace.append("g2 received %s" % (x,)) + trace.append("Finishing g2") + def run(): + g = g1() + y = next(g) + x = 1 + try: + while 1: + y = g.send(x) + trace.append("Yielded %s" % (y,)) + x += 1 + except StopIteration: + trace.append("StopIteration") + self.assertRaises(ValueError,run) + self.assertEqual(trace,[ + "Starting g1", + "g1 received 1", + "Starting g2", + "Yielded g2 spam", + "g2 received 2", + ]) + + def test_delegating_close(self): + """ + Test delegating 'close' + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + finally: + trace.append("Finishing g2") + g = g1() + for i in range(2): + x = next(g) + trace.append("Yielded %s" % (x,)) + g.close() + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Finishing g2", + "Finishing g1" + ]) + + def test_handing_exception_while_delegating_close(self): + """ + Test handling exception while delegating 'close' + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + finally: + trace.append("Finishing g2") + raise ValueError("nybbles have exploded with delight") + try: + g = g1() + for i in range(2): + x = next(g) + trace.append("Yielded %s" % (x,)) + g.close() + except ValueError as e: + self.assertEqual(e.args[0], "nybbles have exploded with delight") + self.assertIsInstance(e.__context__, GeneratorExit) + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Finishing g2", + "Finishing g1", + ]) + + def test_delegating_throw(self): + """ + Test delegating 'throw' + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + finally: + trace.append("Finishing g2") + try: + g = g1() + for i in range(2): + x = next(g) + trace.append("Yielded %s" % (x,)) + e = ValueError("tomato ejected") + g.throw(e) + except ValueError as e: + self.assertEqual(e.args[0], "tomato ejected") + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Finishing g2", + "Finishing g1", + ]) + + def test_value_attribute_of_StopIteration_exception(self): + """ + Test 'value' attribute of StopIteration exception + """ + trace = [] + def pex(e): + trace.append("%s: %s" % (e.__class__.__name__, e)) + trace.append("value = %s" % (e.value,)) + e = StopIteration() + pex(e) + e = StopIteration("spam") + pex(e) + e.value = "eggs" + pex(e) + self.assertEqual(trace,[ + "StopIteration: ", + "value = None", + "StopIteration: spam", + "value = spam", + "StopIteration: spam", + "value = eggs", + ]) + + + def test_exception_value_crash(self): + # There used to be a refcount error when the return value + # stored in the StopIteration has a refcount of 1. + def g1(): + yield from g2() + def g2(): + yield "g2" + return [42] + self.assertEqual(list(g1()), ["g2"]) + + + def test_generator_return_value(self): + """ + Test generator return value + """ + trace = [] + def g1(): + trace.append("Starting g1") + yield "g1 ham" + ret = yield from g2() + trace.append("g2 returned %s" % (ret,)) + ret = yield from g2(42) + trace.append("g2 returned %s" % (ret,)) + yield "g1 eggs" + trace.append("Finishing g1") + def g2(v = None): + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + trace.append("Finishing g2") + if v: + return v + for x in g1(): + trace.append("Yielded %s" % (x,)) + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Yielded g2 more spam", + "Finishing g2", + "g2 returned None", + "Starting g2", + "Yielded g2 spam", + "Yielded g2 more spam", + "Finishing g2", + "g2 returned 42", + "Yielded g1 eggs", + "Finishing g1", + ]) + + def test_delegation_of_next_to_non_generator(self): + """ + Test delegation of next() to non-generator + """ + trace = [] + def g(): + yield from range(3) + for x in g(): + trace.append("Yielded %s" % (x,)) + self.assertEqual(trace,[ + "Yielded 0", + "Yielded 1", + "Yielded 2", + ]) + + + def test_conversion_of_sendNone_to_next(self): + """ + Test conversion of send(None) to next() + """ + trace = [] + def g(): + yield from range(3) + gi = g() + for x in range(3): + y = gi.send(None) + trace.append("Yielded: %s" % (y,)) + self.assertEqual(trace,[ + "Yielded: 0", + "Yielded: 1", + "Yielded: 2", + ]) + + def test_delegation_of_close_to_non_generator(self): + """ + Test delegation of close() to non-generator + """ + trace = [] + def g(): + try: + trace.append("starting g") + yield from range(3) + trace.append("g should not be here") + finally: + trace.append("finishing g") + gi = g() + next(gi) + with captured_stderr() as output: + gi.close() + self.assertEqual(output.getvalue(), '') + self.assertEqual(trace,[ + "starting g", + "finishing g", + ]) + + def test_delegating_throw_to_non_generator(self): + """ + Test delegating 'throw' to non-generator + """ + trace = [] + def g(): + try: + trace.append("Starting g") + yield from range(10) + finally: + trace.append("Finishing g") + try: + gi = g() + for i in range(5): + x = next(gi) + trace.append("Yielded %s" % (x,)) + e = ValueError("tomato ejected") + gi.throw(e) + except ValueError as e: + self.assertEqual(e.args[0],"tomato ejected") + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Starting g", + "Yielded 0", + "Yielded 1", + "Yielded 2", + "Yielded 3", + "Yielded 4", + "Finishing g", + ]) + + def test_attempting_to_send_to_non_generator(self): + """ + Test attempting to send to non-generator + """ + trace = [] + def g(): + try: + trace.append("starting g") + yield from range(3) + trace.append("g should not be here") + finally: + trace.append("finishing g") + try: + gi = g() + next(gi) + for x in range(3): + y = gi.send(42) + trace.append("Should not have yielded: %s" % (y,)) + except AttributeError as e: + self.assertIn("send", e.args[0]) + else: + self.fail("was able to send into non-generator") + self.assertEqual(trace,[ + "starting g", + "finishing g", + ]) + + def test_broken_getattr_handling(self): + """ + Test subiterator with a broken getattr implementation + """ + class Broken: + def __iter__(self): + return self + def __next__(self): + return 1 + def __getattr__(self, attr): + 1/0 + + def g(): + yield from Broken() + + with self.assertRaises(ZeroDivisionError): + gi = g() + self.assertEqual(next(gi), 1) + gi.send(1) + + with self.assertRaises(ZeroDivisionError): + gi = g() + self.assertEqual(next(gi), 1) + gi.throw(AttributeError) + + with captured_stderr() as output: + gi = g() + self.assertEqual(next(gi), 1) + gi.close() + self.assertIn('ZeroDivisionError', output.getvalue()) + + def test_exception_in_initial_next_call(self): + """ + Test exception in initial next() call + """ + trace = [] + def g1(): + trace.append("g1 about to yield from g2") + yield from g2() + trace.append("g1 should not be here") + def g2(): + yield 1/0 + def run(): + gi = g1() + next(gi) + self.assertRaises(ZeroDivisionError,run) + self.assertEqual(trace,[ + "g1 about to yield from g2" + ]) + + def test_attempted_yield_from_loop(self): + """ + Test attempted yield-from loop + """ + trace = [] + def g1(): + trace.append("g1: starting") + yield "y1" + trace.append("g1: about to yield from g2") + yield from g2() + trace.append("g1 should not be here") + + def g2(): + trace.append("g2: starting") + yield "y2" + trace.append("g2: about to yield from g1") + yield from gi + trace.append("g2 should not be here") + try: + gi = g1() + for y in gi: + trace.append("Yielded: %s" % (y,)) + except ValueError as e: + self.assertEqual(e.args[0],"generator already executing") + else: + self.fail("subgenerator didn't raise ValueError") + self.assertEqual(trace,[ + "g1: starting", + "Yielded: y1", + "g1: about to yield from g2", + "g2: starting", + "Yielded: y2", + "g2: about to yield from g1", + ]) + + def test_returning_value_from_delegated_throw(self): + """ + Test returning value from delegated 'throw' + """ + trace = [] + def g1(): + try: + trace.append("Starting g1") + yield "g1 ham" + yield from g2() + yield "g1 eggs" + finally: + trace.append("Finishing g1") + def g2(): + try: + trace.append("Starting g2") + yield "g2 spam" + yield "g2 more spam" + except LunchError: + trace.append("Caught LunchError in g2") + yield "g2 lunch saved" + yield "g2 yet more spam" + class LunchError(Exception): + pass + g = g1() + for i in range(2): + x = next(g) + trace.append("Yielded %s" % (x,)) + e = LunchError("tomato ejected") + g.throw(e) + for x in g: + trace.append("Yielded %s" % (x,)) + self.assertEqual(trace,[ + "Starting g1", + "Yielded g1 ham", + "Starting g2", + "Yielded g2 spam", + "Caught LunchError in g2", + "Yielded g2 yet more spam", + "Yielded g1 eggs", + "Finishing g1", + ]) + + def test_next_and_return_with_value(self): + """ + Test next and return with value + """ + trace = [] + def f(r): + gi = g(r) + next(gi) + try: + trace.append("f resuming g") + next(gi) + trace.append("f SHOULD NOT BE HERE") + except StopIteration as e: + trace.append("f caught %s" % (repr(e),)) + def g(r): + trace.append("g starting") + yield + trace.append("g returning %s" % (r,)) + return r + f(None) + f(42) + self.assertEqual(trace,[ + "g starting", + "f resuming g", + "g returning None", + "f caught StopIteration()", + "g starting", + "f resuming g", + "g returning 42", + "f caught StopIteration(42,)", + ]) + + def test_send_and_return_with_value(self): + """ + Test send and return with value + """ + trace = [] + def f(r): + gi = g(r) + next(gi) + try: + trace.append("f sending spam to g") + gi.send("spam") + trace.append("f SHOULD NOT BE HERE") + except StopIteration as e: + trace.append("f caught %r" % (e,)) + def g(r): + trace.append("g starting") + x = yield + trace.append("g received %s" % (x,)) + trace.append("g returning %s" % (r,)) + return r + f(None) + f(42) + self.assertEqual(trace,[ + "g starting", + "f sending spam to g", + "g received spam", + "g returning None", + "f caught StopIteration()", + "g starting", + "f sending spam to g", + "g received spam", + "g returning 42", + "f caught StopIteration(42,)", + ]) + + def test_catching_exception_from_subgen_and_returning(self): + """ + Test catching an exception thrown into a + subgenerator and returning a value + """ + trace = [] + def inner(): + try: + yield 1 + except ValueError: + trace.append("inner caught ValueError") + return 2 + + def outer(): + v = yield from inner() + trace.append("inner returned %r to outer" % v) + yield v + g = outer() + trace.append(next(g)) + trace.append(g.throw(ValueError)) + self.assertEqual(trace,[ + 1, + "inner caught ValueError", + "inner returned 2 to outer", + 2, + ]) + + def test_throwing_GeneratorExit_into_subgen_that_returns(self): + """ + Test throwing GeneratorExit into a subgenerator that + catches it and returns normally. + """ + trace = [] + def f(): + try: + trace.append("Enter f") + yield + trace.append("Exit f") + except GeneratorExit: + return + def g(): + trace.append("Enter g") + yield from f() + trace.append("Exit g") + try: + gi = g() + next(gi) + gi.throw(GeneratorExit) + except GeneratorExit: + pass + else: + self.fail("subgenerator failed to raise GeneratorExit") + self.assertEqual(trace,[ + "Enter g", + "Enter f", + ]) + + def test_throwing_GeneratorExit_into_subgenerator_that_yields(self): + """ + Test throwing GeneratorExit into a subgenerator that + catches it and yields. + """ + trace = [] + def f(): + try: + trace.append("Enter f") + yield + trace.append("Exit f") + except GeneratorExit: + yield + def g(): + trace.append("Enter g") + yield from f() + trace.append("Exit g") + try: + gi = g() + next(gi) + gi.throw(GeneratorExit) + except RuntimeError as e: + self.assertEqual(e.args[0], "generator ignored GeneratorExit") + else: + self.fail("subgenerator failed to raise GeneratorExit") + self.assertEqual(trace,[ + "Enter g", + "Enter f", + ]) + + def test_throwing_GeneratorExit_into_subgen_that_raises(self): + """ + Test throwing GeneratorExit into a subgenerator that + catches it and raises a different exception. + """ + trace = [] + def f(): + try: + trace.append("Enter f") + yield + trace.append("Exit f") + except GeneratorExit: + raise ValueError("Vorpal bunny encountered") + def g(): + trace.append("Enter g") + yield from f() + trace.append("Exit g") + try: + gi = g() + next(gi) + gi.throw(GeneratorExit) + except ValueError as e: + self.assertEqual(e.args[0], "Vorpal bunny encountered") + self.assertIsInstance(e.__context__, GeneratorExit) + else: + self.fail("subgenerator failed to raise ValueError") + self.assertEqual(trace,[ + "Enter g", + "Enter f", + ]) + + def test_yield_from_empty(self): + def g(): + yield from () + self.assertRaises(StopIteration, next, g()) + + def test_delegating_generators_claim_to_be_running(self): + # Check with basic iteration + def one(): + yield 0 + yield from two() + yield 3 + def two(): + yield 1 + try: + yield from g1 + except ValueError: + pass + yield 2 + g1 = one() + self.assertEqual(list(g1), [0, 1, 2, 3]) + # Check with send + g1 = one() + res = [next(g1)] + try: + while True: + res.append(g1.send(42)) + except StopIteration: + pass + self.assertEqual(res, [0, 1, 2, 3]) + # Check with throw + class MyErr(Exception): + pass + def one(): + try: + yield 0 + except MyErr: + pass + yield from two() + try: + yield 3 + except MyErr: + pass + def two(): + try: + yield 1 + except MyErr: + pass + try: + yield from g1 + except ValueError: + pass + try: + yield 2 + except MyErr: + pass + g1 = one() + res = [next(g1)] + try: + while True: + res.append(g1.throw(MyErr)) + except StopIteration: + pass + # Check with close + class MyIt(object): + def __iter__(self): + return self + def __next__(self): + return 42 + def close(self_): + self.assertTrue(g1.gi_running) + self.assertRaises(ValueError, next, g1) + def one(): + yield from MyIt() + g1 = one() + next(g1) + g1.close() + + def test_delegator_is_visible_to_debugger(self): + def call_stack(): + return [f[3] for f in inspect.stack()] + + def gen(): + yield call_stack() + yield call_stack() + yield call_stack() + + def spam(g): + yield from g + + def eggs(g): + yield from g + + for stack in spam(gen()): + self.assertTrue('spam' in stack) + + for stack in spam(eggs(gen())): + self.assertTrue('spam' in stack and 'eggs' in stack) + + def test_custom_iterator_return(self): + # See issue #15568 + class MyIter: + def __iter__(self): + return self + def __next__(self): + raise StopIteration(42) + def gen(): + nonlocal ret + ret = yield from MyIter() + ret = None + list(gen()) + self.assertEqual(ret, 42) + + def test_close_with_cleared_frame(self): + # See issue #17669. + # + # Create a stack of generators: outer() delegating to inner() + # delegating to innermost(). The key point is that the instance of + # inner is created first: this ensures that its frame appears before + # the instance of outer in the GC linked list. + # + # At the gc.collect call: + # - frame_clear is called on the inner_gen frame. + # - gen_dealloc is called on the outer_gen generator (the only + # reference is in the frame's locals). + # - gen_close is called on the outer_gen generator. + # - gen_close_iter is called to close the inner_gen generator, which + # in turn calls gen_close, and gen_yf. + # + # Previously, gen_yf would crash since inner_gen's frame had been + # cleared (and in particular f_stacktop was NULL). + + def innermost(): + yield + def inner(): + outer_gen = yield + yield from innermost() + def outer(): + inner_gen = yield + yield from inner_gen + + with disable_gc(): + inner_gen = inner() + outer_gen = outer() + outer_gen.send(None) + outer_gen.send(inner_gen) + outer_gen.send(outer_gen) + + del outer_gen + del inner_gen + gc_collect() + + def test_send_tuple_with_custom_generator(self): + # See issue #21209. + class MyGen: + def __iter__(self): + return self + def __next__(self): + return 42 + def send(self, what): + nonlocal v + v = what + return None + def outer(): + v = yield from MyGen() + g = outer() + next(g) + v = None + g.send((1, 2, 3, 4)) + self.assertEqual(v, (1, 2, 3, 4)) + + +if __name__ == '__main__': + unittest.main() -- cgit v0.12