From webhook-mailer at python.org Sun Apr 1 03:26:36 2018 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Sun, 01 Apr 2018 07:26:36 -0000 Subject: [Python-checkins] [2.7] bpo-33132: Fix reference counting issues in the compiler. (GH-6209). (GH-6322) Message-ID: https://github.com/python/cpython/commit/72f3e0887500e00867fa16ce5aaab12fae853b63 commit: 72f3e0887500e00867fa16ce5aaab12fae853b63 branch: 2.7 author: Serhiy Storchaka committer: GitHub date: 2018-04-01T10:26:33+03:00 summary: [2.7] bpo-33132: Fix reference counting issues in the compiler. (GH-6209). (GH-6322) (cherry picked from commit a95d98607efe0c43475b354543e49bf8e240bc6f) Co-authored-by: Serhiy Storchaka files: M Python/compile.c diff --git a/Python/compile.c b/Python/compile.c index 9c9b23698520..4fe69e12bf84 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1075,6 +1075,15 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) return 0; \ } +/* Same as ADDOP_O, but steals a reference. */ +#define ADDOP_N(C, OP, O, TYPE) { \ + if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \ + Py_DECREF((O)); \ + return 0; \ + } \ + Py_DECREF((O)); \ +} + #define ADDOP_NAME(C, OP, O, TYPE) { \ if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \ return 0; \ @@ -1890,8 +1899,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) dot ? dot - src : strlen(src)); if (!attr) return 0; - ADDOP_O(c, LOAD_ATTR, attr, names); - Py_DECREF(attr); + ADDOP_N(c, LOAD_ATTR, attr, names); src = dot + 1; } } @@ -1923,8 +1931,7 @@ compiler_import(struct compiler *c, stmt_ty s) if (level == NULL) return 0; - ADDOP_O(c, LOAD_CONST, level, consts); - Py_DECREF(level); + ADDOP_N(c, LOAD_CONST, level, consts); ADDOP_O(c, LOAD_CONST, Py_None, consts); ADDOP_NAME(c, IMPORT_NAME, alias->name, names); @@ -1959,8 +1966,7 @@ compiler_from_import(struct compiler *c, stmt_ty s) { int i, n = asdl_seq_LEN(s->v.ImportFrom.names); - PyObject *names = PyTuple_New(n); - PyObject *level; + PyObject *level, *names; static PyObject *empty_string; if (!empty_string) { @@ -1969,9 +1975,6 @@ compiler_from_import(struct compiler *c, stmt_ty s) return 0; } - if (!names) - return 0; - if (s->v.ImportFrom.level == 0 && c->c_flags && !(c->c_flags->cf_flags & CO_FUTURE_ABSOLUTE_IMPORT)) level = PyInt_FromLong(-1); @@ -1979,9 +1982,13 @@ compiler_from_import(struct compiler *c, stmt_ty s) level = PyInt_FromLong(s->v.ImportFrom.level); if (!level) { - Py_DECREF(names); return 0; } + ADDOP_N(c, LOAD_CONST, level, consts); + + names = PyTuple_New(n); + if (!names) + return 0; /* build up the names */ for (i = 0; i < n; i++) { @@ -1992,16 +1999,12 @@ compiler_from_import(struct compiler *c, stmt_ty s) if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module && !strcmp(PyString_AS_STRING(s->v.ImportFrom.module), "__future__")) { - Py_DECREF(level); Py_DECREF(names); return compiler_error(c, "from __future__ imports must occur " "at the beginning of the file"); } + ADDOP_N(c, LOAD_CONST, names, consts); - ADDOP_O(c, LOAD_CONST, level, consts); - Py_DECREF(level); - ADDOP_O(c, LOAD_CONST, names, consts); - Py_DECREF(names); if (s->v.ImportFrom.module) { ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); } @@ -2024,7 +2027,6 @@ compiler_from_import(struct compiler *c, stmt_ty s) store_name = alias->asname; if (!compiler_nameop(c, store_name, Store)) { - Py_DECREF(names); return 0; } } @@ -2391,8 +2393,7 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) "param invalid for local variable"); return 0; } - ADDOP_O(c, op, mangled, varnames); - Py_DECREF(mangled); + ADDOP_N(c, op, mangled, varnames); return 1; case OP_GLOBAL: switch (ctx) { From solipsis at pitrou.net Sun Apr 1 05:12:23 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 01 Apr 2018 09:12:23 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=4 Message-ID: <20180401091223.1.A608DFD305146A4D@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_functools leaked [0, 3, 1] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogO6YRBC', '--timeout', '7200'] From webhook-mailer at python.org Sun Apr 1 07:33:16 2018 From: webhook-mailer at python.org (Ivan Levkivskyi) Date: Sun, 01 Apr 2018 11:33:16 -0000 Subject: [Python-checkins] Allow dynamic creation of generic dataclasses (GH-6319) (GH-6320) Message-ID: https://github.com/python/cpython/commit/d063ad8962a83f41fccdca774b728c3826639f62 commit: d063ad8962a83f41fccdca774b728c3826639f62 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ivan Levkivskyi date: 2018-04-01T12:33:13+01:00 summary: Allow dynamic creation of generic dataclasses (GH-6319) (GH-6320) (cherry picked from commit 5a7092de1226a95a50f0f384eea8ddb288959249) Co-authored-by: Ivan Levkivskyi files: M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index bd7252c683ca..04e07f8cf8c2 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1004,7 +1004,9 @@ class C(Base): anns[name] = tp namespace['__annotations__'] = anns - cls = type(cls_name, bases, namespace) + # We use `types.new_class()` instead of simply `type()` to allow dynamic creation + # of generic dataclassses. + cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace)) return dataclass(cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 5cd424cf5760..26bfc4e75a00 100755 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -8,7 +8,7 @@ import inspect import unittest from unittest.mock import Mock -from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar +from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional from collections import deque, OrderedDict, namedtuple from functools import total_ordering @@ -1690,6 +1690,23 @@ def new_method(self): c = Alias(10, 1.0) self.assertEqual(c.new_method(), 1.0) + def test_generic_dynamic(self): + T = TypeVar('T') + + @dataclass + class Parent(Generic[T]): + x: T + Child = make_dataclass('Child', [('y', T), ('z', Optional[T], None)], + bases=(Parent[int], Generic[T]), namespace={'other': 42}) + self.assertIs(Child[int](1, 2).z, None) + self.assertEqual(Child[int](1, 2, 3).z, 3) + self.assertEqual(Child[int](1, 2, 3).other, 42) + # Check that type aliases work correctly. + Alias = Child[T] + self.assertEqual(Alias[int](1, 2).x, 1) + # Check MRO resolution. + self.assertEqual(Child.__mro__, (Child, Parent, Generic, object)) + def test_helper_replace(self): @dataclass(frozen=True) class C: From webhook-mailer at python.org Sun Apr 1 15:01:51 2018 From: webhook-mailer at python.org (Gregory P. Smith) Date: Sun, 01 Apr 2018 19:01:51 -0000 Subject: [Python-checkins] bpo-20104: Add os.posix_spawn documentation. (#6334) Message-ID: https://github.com/python/cpython/commit/79760ed256987cead08d668b95675afba6b3760f commit: 79760ed256987cead08d668b95675afba6b3760f branch: master author: Gregory P. Smith committer: GitHub date: 2018-04-01T12:01:48-07:00 summary: bpo-20104: Add os.posix_spawn documentation. (#6334) files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index bae432d33b0b..e685b33302bd 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3353,6 +3353,31 @@ written in Python, such as a mail server's external command delivery program. subprocesses. +.. function:: posix_spawn(path, argv, env, file_actions=None) + + Wraps the posix_spawn() C library API for use from Python. + + Most users should use :class:`subprocess.run` instead of posix_spawn. + + The *path*, *args*, and *env* arguments are similar to :func:`execve`. + + The *file_actions* argument may be a sequence of tuples describing actions + to take on specific file descriptors in the child process between the C + library implementation's fork and exec steps. The first item in each tuple + must be one of the three type indicator listed below describing the + remaining tuple elements: + + (os.POSIX_SPAWN_OPEN, fd, path, open flags, mode) + (os.POSIX_SPAWN_CLOSE, fd) + (os.POSIX_SPAWN_DUP2, fd, new_fd) + + These tuples correspond to the C library posix_spawn_file_actions_addopen, + posix_spawn_file_actions_addclose, and posix_spawn_file_actions_adddup2 API + calls used to prepare for the posix_spawn call itself. + + .. versionadded:: 3.7 + + .. function:: register_at_fork(*, before=None, after_in_parent=None, \ after_in_child=None) From webhook-mailer at python.org Sun Apr 1 15:13:40 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Sun, 01 Apr 2018 19:13:40 -0000 Subject: [Python-checkins] bpo-20104: Add os.posix_spawn documentation. (GH-6334) Message-ID: https://github.com/python/cpython/commit/ab8457232121dfdfb1d4bfcf806a842fbe402722 commit: ab8457232121dfdfb1d4bfcf806a842fbe402722 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-01T12:13:37-07:00 summary: bpo-20104: Add os.posix_spawn documentation. (GH-6334) (cherry picked from commit 79760ed256987cead08d668b95675afba6b3760f) Co-authored-by: Gregory P. Smith files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index bae432d33b0b..e685b33302bd 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3353,6 +3353,31 @@ written in Python, such as a mail server's external command delivery program. subprocesses. +.. function:: posix_spawn(path, argv, env, file_actions=None) + + Wraps the posix_spawn() C library API for use from Python. + + Most users should use :class:`subprocess.run` instead of posix_spawn. + + The *path*, *args*, and *env* arguments are similar to :func:`execve`. + + The *file_actions* argument may be a sequence of tuples describing actions + to take on specific file descriptors in the child process between the C + library implementation's fork and exec steps. The first item in each tuple + must be one of the three type indicator listed below describing the + remaining tuple elements: + + (os.POSIX_SPAWN_OPEN, fd, path, open flags, mode) + (os.POSIX_SPAWN_CLOSE, fd) + (os.POSIX_SPAWN_DUP2, fd, new_fd) + + These tuples correspond to the C library posix_spawn_file_actions_addopen, + posix_spawn_file_actions_addclose, and posix_spawn_file_actions_adddup2 API + calls used to prepare for the posix_spawn call itself. + + .. versionadded:: 3.7 + + .. function:: register_at_fork(*, before=None, after_in_parent=None, \ after_in_child=None) From webhook-mailer at python.org Mon Apr 2 01:29:05 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Mon, 02 Apr 2018 05:29:05 -0000 Subject: [Python-checkins] [2.7] bpo-27212: Modify islice recipe to consume initial values preceding start (GH-6195) (GH-6339) Message-ID: https://github.com/python/cpython/commit/325191bd6b3a2d5e3012adee868f19baf3e2c3ab commit: 325191bd6b3a2d5e3012adee868f19baf3e2c3ab branch: 2.7 author: Cheryl Sabella committer: Raymond Hettinger date: 2018-04-01T22:29:01-07:00 summary: [2.7] bpo-27212: Modify islice recipe to consume initial values preceding start (GH-6195) (GH-6339) (cherry picked from commit da1734c58d2f97387ccc9676074717d38b044128) files: A Misc/NEWS.d/next/Documentation/2018-03-22-19-23-04.bpo-27212.wrE5KR.rst M Doc/library/itertools.rst M Lib/test/test_itertools.py diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 57ba4d45e9b2..17303dd01cef 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -411,12 +411,24 @@ loops that truncate the stream. # islice('ABCDEFG', 2, None) --> C D E F G # islice('ABCDEFG', 0, None, 2) --> A C E G s = slice(*args) - it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1)) - nexti = next(it) - for i, element in enumerate(iterable): - if i == nexti: - yield element - nexti = next(it) + start, stop, step = s.start or 0, s.stop or sys.maxint, s.step or 1 + it = iter(xrange(start, stop, step))) + try: + nexti = next(it) + except StopIteration: + # Consume *iterable* up to the *start* position. + for i, element in izip(xrange(start), iterable): + pass + return + try: + for i, element in enumerate(iterable): + if i == nexti: + yield element + nexti = next(it) + except StopIteration: + # Consume to *stop*. + for i, element in izip(xrange(i + 1, stop), iterable): + pass If *start* is ``None``, then iteration starts at zero. If *step* is ``None``, then the step defaults to one. @@ -681,8 +693,8 @@ which incur interpreter overhead. "Return function(0), function(1), ..." return imap(function, count(start)) - def consume(iterator, n): - "Advance the iterator n-steps ahead. If n is none, consume entirely." + def consume(iterator, n=None): + "Advance the iterator n-steps ahead. If n is None, consume entirely." # Use functions that consume iterators at C speed. if n is None: # feed the entire iterator into a zero-length deque diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 1e6db3426e4f..04279792065e 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -802,6 +802,7 @@ def test_islice(self): (10, 20, 3), (10, 3, 20), (10, 20), + (10, 10), (10, 3), (20,) ]: @@ -826,6 +827,10 @@ def test_islice(self): self.assertEqual(list(islice(it, 3)), range(3)) self.assertEqual(list(it), range(3, 10)) + it = iter(range(10)) + self.assertEqual(list(islice(it, 3, 3)), []) + self.assertEqual(list(it), range(3, 10)) + # Test invalid arguments self.assertRaises(TypeError, islice, xrange(10)) self.assertRaises(TypeError, islice, xrange(10), 1, 2, 3, 4) @@ -1084,6 +1089,48 @@ def test_takewhile(self): self.assertEqual(list(takewhile(lambda x: x<5, [1,4,6,4,1])), [1,4]) +class TestPurePythonRoughEquivalents(unittest.TestCase): + + @staticmethod + def islice(iterable, *args): + s = slice(*args) + start, stop, step = s.start or 0, s.stop or sys.maxint, s.step or 1 + it = iter(xrange(start, stop, step)) + try: + nexti = next(it) + except StopIteration: + # Consume *iterable* up to the *start* position. + for i, element in izip(xrange(start), iterable): + pass + return + try: + for i, element in enumerate(iterable): + if i == nexti: + yield element + nexti = next(it) + except StopIteration: + # Consume to *stop*. + for i, element in izip(xrange(i + 1, stop), iterable): + pass + + def test_islice_recipe(self): + self.assertEqual(list(self.islice('ABCDEFG', 2)), list('AB')) + self.assertEqual(list(self.islice('ABCDEFG', 2, 4)), list('CD')) + self.assertEqual(list(self.islice('ABCDEFG', 2, None)), list('CDEFG')) + self.assertEqual(list(self.islice('ABCDEFG', 0, None, 2)), list('ACEG')) + # Test items consumed. + it = iter(xrange(10)) + self.assertEqual(list(self.islice(it, 3)), range(3)) + self.assertEqual(list(it), range(3, 10)) + it = iter(xrange(10)) + self.assertEqual(list(self.islice(it, 3, 3)), []) + self.assertEqual(list(it), range(3, 10)) + # Test that slice finishes in predictable state. + c = count() + self.assertEqual(list(self.islice(c, 1, 3, 50)), [1]) + self.assertEqual(next(c), 3) + + class TestGC(unittest.TestCase): def makecycle(self, iterator, container): @@ -1577,6 +1624,17 @@ def __init__(self, newarg=None, *args): ... "Return function(0), function(1), ..." ... return imap(function, count(start)) +>>> import collections +>>> def consume(iterator, n=None): +... "Advance the iterator n-steps ahead. If n is None, consume entirely." +... # Use functions that consume iterators at C speed. +... if n is None: +... # feed the entire iterator into a zero-length deque +... collections.deque(iterator, maxlen=0) +... else: +... # advance to the empty slice starting at position n +... next(islice(iterator, n, n), None) + >>> def nth(iterable, n, default=None): ... "Returns the nth item or a default value" ... return next(islice(iterable, n, None), default) @@ -1678,6 +1736,14 @@ def __init__(self, newarg=None, *args): >>> list(islice(tabulate(lambda x: 2*x), 4)) [0, 2, 4, 6] +>>> it = iter(xrange(10)) +>>> consume(it, 3) +>>> next(it) +3 +>>> consume(it) +>>> next(it, 'Done') +'Done' + >>> nth('abcde', 3) 'd' @@ -1753,7 +1819,8 @@ def __init__(self, newarg=None, *args): def test_main(verbose=None): test_classes = (TestBasicOps, TestVariousIteratorArgs, TestGC, RegressionTests, LengthTransparency, - SubclassWithKwargsTest, TestExamples) + SubclassWithKwargsTest, TestExamples, + TestPurePythonRoughEquivalents) test_support.run_unittest(*test_classes) # verify reference counting diff --git a/Misc/NEWS.d/next/Documentation/2018-03-22-19-23-04.bpo-27212.wrE5KR.rst b/Misc/NEWS.d/next/Documentation/2018-03-22-19-23-04.bpo-27212.wrE5KR.rst new file mode 100644 index 000000000000..5910d2c17342 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-03-22-19-23-04.bpo-27212.wrE5KR.rst @@ -0,0 +1,2 @@ +Modify documentation for the :func:`islice` recipe to consume initial values +up to the start index. From webhook-mailer at python.org Mon Apr 2 01:47:49 2018 From: webhook-mailer at python.org (Terry Jan Reedy) Date: Mon, 02 Apr 2018 05:47:49 -0000 Subject: [Python-checkins] bpo-33204: IDLE: consistently color invalid string prefixes (#6344) Message-ID: https://github.com/python/cpython/commit/da58533ac67b01ce8f6466e6f03ff6b8b3bb04d5 commit: da58533ac67b01ce8f6466e6f03ff6b8b3bb04d5 branch: master author: Terry Jan Reedy committer: GitHub date: 2018-04-02T01:47:46-04:00 summary: bpo-33204: IDLE: consistently color invalid string prefixes (#6344) A 'u' string prefix cannot be paired with either 'r' or 'f'. Consistently color as much of the prefix, starting at the right, as is valid. files: A Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst M Lib/idlelib/colorizer.py diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index ff4084528804..f835e5874b7e 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -21,7 +21,7 @@ def make_pat(): # 1st 'file' colorized normal, 2nd as builtin, 3rd as string builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b" comment = any("COMMENT", [r"#[^\n]*"]) - stringprefix = r"(?i:\br|u|f|fr|rf|b|br|rb)?" + stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?" sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?" dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?' sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" @@ -265,11 +265,14 @@ def _color_delegator(parent): # htest # source = ("# Following has syntax errors\n" "if True: then int 1\nelif False: print 0\nelse: float(None)\n" "if iF + If + IF: 'keywork matching must respect case'\n" - "# All valid prefixes for unicode and byte strings should be colored\n" + "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" - "r'x', u'x', R'x', U'x', f'x', F'x', ur'is invalid'\n" + "r'x', u'x', R'x', U'x', f'x', F'x'\n" "fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n" - "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n") + "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n" + "# Invalid combinations of legal characters should be half colored.\n" + "ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'" + ) text = Text(top, background="white") text.pack(expand=1, fill="both") text.insert("insert", source) diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst new file mode 100644 index 000000000000..d5d769846eb1 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -0,0 +1,3 @@ +IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. From webhook-mailer at python.org Mon Apr 2 02:09:21 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Mon, 02 Apr 2018 06:09:21 -0000 Subject: [Python-checkins] bpo-33204: IDLE: consistently color invalid string prefixes (GH-6344) Message-ID: https://github.com/python/cpython/commit/6130675efeb3c23cebc43ab07c49eb62cd03cacf commit: 6130675efeb3c23cebc43ab07c49eb62cd03cacf branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-01T23:09:18-07:00 summary: bpo-33204: IDLE: consistently color invalid string prefixes (GH-6344) A 'u' string prefix cannot be paired with either 'r' or 'f'. Consistently color as much of the prefix, starting at the right, as is valid. (cherry picked from commit da58533ac67b01ce8f6466e6f03ff6b8b3bb04d5) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst M Lib/idlelib/colorizer.py diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index ff4084528804..f835e5874b7e 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -21,7 +21,7 @@ def make_pat(): # 1st 'file' colorized normal, 2nd as builtin, 3rd as string builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b" comment = any("COMMENT", [r"#[^\n]*"]) - stringprefix = r"(?i:\br|u|f|fr|rf|b|br|rb)?" + stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?" sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?" dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?' sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" @@ -265,11 +265,14 @@ def _color_delegator(parent): # htest # source = ("# Following has syntax errors\n" "if True: then int 1\nelif False: print 0\nelse: float(None)\n" "if iF + If + IF: 'keywork matching must respect case'\n" - "# All valid prefixes for unicode and byte strings should be colored\n" + "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" - "r'x', u'x', R'x', U'x', f'x', F'x', ur'is invalid'\n" + "r'x', u'x', R'x', U'x', f'x', F'x'\n" "fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n" - "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n") + "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n" + "# Invalid combinations of legal characters should be half colored.\n" + "ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'" + ) text = Text(top, background="white") text.pack(expand=1, fill="both") text.insert("insert", source) diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst new file mode 100644 index 000000000000..d5d769846eb1 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -0,0 +1,3 @@ +IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. From webhook-mailer at python.org Mon Apr 2 02:33:28 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Mon, 02 Apr 2018 06:33:28 -0000 Subject: [Python-checkins] bpo-33204: IDLE: consistently color invalid string prefixes (GH-6344) Message-ID: https://github.com/python/cpython/commit/16cf84b4fbe78f9d876e0335f33459f1b92b7bf0 commit: 16cf84b4fbe78f9d876e0335f33459f1b92b7bf0 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-01T23:33:25-07:00 summary: bpo-33204: IDLE: consistently color invalid string prefixes (GH-6344) A 'u' string prefix cannot be paired with either 'r' or 'f'. Consistently color as much of the prefix, starting at the right, as is valid. (cherry picked from commit da58533ac67b01ce8f6466e6f03ff6b8b3bb04d5) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst M Lib/idlelib/colorizer.py diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index ff4084528804..f835e5874b7e 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -21,7 +21,7 @@ def make_pat(): # 1st 'file' colorized normal, 2nd as builtin, 3rd as string builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b" comment = any("COMMENT", [r"#[^\n]*"]) - stringprefix = r"(?i:\br|u|f|fr|rf|b|br|rb)?" + stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?" sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?" dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?' sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" @@ -265,11 +265,14 @@ def _color_delegator(parent): # htest # source = ("# Following has syntax errors\n" "if True: then int 1\nelif False: print 0\nelse: float(None)\n" "if iF + If + IF: 'keywork matching must respect case'\n" - "# All valid prefixes for unicode and byte strings should be colored\n" + "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" - "r'x', u'x', R'x', U'x', f'x', F'x', ur'is invalid'\n" + "r'x', u'x', R'x', U'x', f'x', F'x'\n" "fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n" - "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n") + "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n" + "# Invalid combinations of legal characters should be half colored.\n" + "ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'" + ) text = Text(top, background="white") text.pack(expand=1, fill="both") text.insert("insert", source) diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst new file mode 100644 index 000000000000..d5d769846eb1 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -0,0 +1,3 @@ +IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. From solipsis at pitrou.net Mon Apr 2 05:10:53 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 02 Apr 2018 09:10:53 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=3 Message-ID: <20180402091053.1.E6D13A714661D634@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [-7, 8, 0] memory blocks, sum=1 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_forkserver leaked [0, 0, -2] memory blocks, sum=-2 test_multiprocessing_spawn leaked [-1, -1, 2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/refloglf9oZi', '--timeout', '7200'] From webhook-mailer at python.org Mon Apr 2 11:18:07 2018 From: webhook-mailer at python.org (Terry Jan Reedy) Date: Mon, 02 Apr 2018 15:18:07 -0000 Subject: [Python-checkins] bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Message-ID: https://github.com/python/cpython/commit/55966f3a0d5f1bf823bd22ce1abbde267b06552f commit: 55966f3a0d5f1bf823bd22ce1abbde267b06552f branch: master author: Terry Jan Reedy committer: GitHub date: 2018-04-02T11:18:02-04:00 summary: bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Followup to primary PR for the issue, GH-6344. files: M Lib/idlelib/colorizer.py M Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index f835e5874b7e..5cb85f24dfd7 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -262,9 +262,12 @@ def _color_delegator(parent): # htest # top.title("Test ColorDelegator") x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("700x250+%d+%d" % (x + 20, y + 175)) - source = ("# Following has syntax errors\n" - "if True: then int 1\nelif False: print 0\nelse: float(None)\n" - "if iF + If + IF: 'keywork matching must respect case'\n" + source = ( + "if True: int ('1') # keyword, builtin, string, comment\n" + "elif False: print(0)\n" + "else: float(None)\n" + "if iF + If + IF: 'keyword matching must respect case'\n" + "if'': x or'' # valid string-keyword no-space combinations\n" "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" "r'x', u'x', R'x', U'x', f'x', F'x'\n" diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst index d5d769846eb1..3ae937bab930 100644 --- a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -1,3 +1,3 @@ IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot -be paired with either 'r' or 'f'. Consistently color as much of the prefix, -starting at the right, as is valid. +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. Revise and extend colorizer test. From webhook-mailer at python.org Mon Apr 2 12:03:57 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Mon, 02 Apr 2018 16:03:57 -0000 Subject: [Python-checkins] bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Message-ID: https://github.com/python/cpython/commit/fa91aff07c16ad48a63580c2909934be92a5e9c8 commit: fa91aff07c16ad48a63580c2909934be92a5e9c8 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T09:03:52-07:00 summary: bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Followup to primary PR for the issue, GH-6344. (cherry picked from commit 55966f3a0d5f1bf823bd22ce1abbde267b06552f) Co-authored-by: Terry Jan Reedy files: M Lib/idlelib/colorizer.py M Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index f835e5874b7e..5cb85f24dfd7 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -262,9 +262,12 @@ def _color_delegator(parent): # htest # top.title("Test ColorDelegator") x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("700x250+%d+%d" % (x + 20, y + 175)) - source = ("# Following has syntax errors\n" - "if True: then int 1\nelif False: print 0\nelse: float(None)\n" - "if iF + If + IF: 'keywork matching must respect case'\n" + source = ( + "if True: int ('1') # keyword, builtin, string, comment\n" + "elif False: print(0)\n" + "else: float(None)\n" + "if iF + If + IF: 'keyword matching must respect case'\n" + "if'': x or'' # valid string-keyword no-space combinations\n" "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" "r'x', u'x', R'x', U'x', f'x', F'x'\n" diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst index d5d769846eb1..3ae937bab930 100644 --- a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -1,3 +1,3 @@ IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot -be paired with either 'r' or 'f'. Consistently color as much of the prefix, -starting at the right, as is valid. +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. Revise and extend colorizer test. From webhook-mailer at python.org Mon Apr 2 12:13:00 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Mon, 02 Apr 2018 16:13:00 -0000 Subject: [Python-checkins] bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Message-ID: https://github.com/python/cpython/commit/306559e6ca15b86eb230609f484f48132b7ca383 commit: 306559e6ca15b86eb230609f484f48132b7ca383 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T09:12:56-07:00 summary: bpo-33204: IDLE - revise and extend colorizer test. (GH-6347) Followup to primary PR for the issue, GH-6344. (cherry picked from commit 55966f3a0d5f1bf823bd22ce1abbde267b06552f) Co-authored-by: Terry Jan Reedy files: M Lib/idlelib/colorizer.py M Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index f835e5874b7e..5cb85f24dfd7 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -262,9 +262,12 @@ def _color_delegator(parent): # htest # top.title("Test ColorDelegator") x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("700x250+%d+%d" % (x + 20, y + 175)) - source = ("# Following has syntax errors\n" - "if True: then int 1\nelif False: print 0\nelse: float(None)\n" - "if iF + If + IF: 'keywork matching must respect case'\n" + source = ( + "if True: int ('1') # keyword, builtin, string, comment\n" + "elif False: print(0)\n" + "else: float(None)\n" + "if iF + If + IF: 'keyword matching must respect case'\n" + "if'': x or'' # valid string-keyword no-space combinations\n" "# All valid prefixes for unicode and byte strings should be colored.\n" "'x', '''x''', \"x\", \"\"\"x\"\"\"\n" "r'x', u'x', R'x', U'x', f'x', F'x'\n" diff --git a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst index d5d769846eb1..3ae937bab930 100644 --- a/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst +++ b/Misc/NEWS.d/next/IDLE/2018-04-02-00-28-13.bpo-33204.NBsuIv.rst @@ -1,3 +1,3 @@ IDLE: consistently color invalid string prefixes. A 'u' string prefix cannot -be paired with either 'r' or 'f'. Consistently color as much of the prefix, -starting at the right, as is valid. +be paired with either 'r' or 'f'. Consistently color as much of the prefix, +starting at the right, as is valid. Revise and extend colorizer test. From webhook-mailer at python.org Mon Apr 2 18:41:48 2018 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Mon, 02 Apr 2018 22:41:48 -0000 Subject: [Python-checkins] bpo-29922: Improve error messages in 'async with' (GH-6352) Message-ID: https://github.com/python/cpython/commit/a68f2f0578bbf812fa2264d0e0bb388340d6e230 commit: a68f2f0578bbf812fa2264d0e0bb388340d6e230 branch: master author: Serhiy Storchaka committer: GitHub date: 2018-04-03T01:41:38+03:00 summary: bpo-29922: Improve error messages in 'async with' (GH-6352) when __aenter__() or __aexit__() return non-awaitable object. files: A Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst M Lib/test/test_coroutines.py M Python/ceval.c diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index fe26199f95af..9ad7ff9564bc 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1255,7 +1255,9 @@ def __aexit__(self, *e): pass with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): + TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: int"): # it's important that __aexit__ wasn't called run_async(foo()) @@ -1275,7 +1277,9 @@ def __aexit__(self, *e): run_async(foo()) except TypeError as exc: self.assertRegex( - exc.args[0], "object int can't be used in 'await' expression") + exc.args[0], + "'async with' received an object from __aexit__ " + "that does not implement __await__: int") self.assertTrue(exc.__context__ is not None) self.assertTrue(isinstance(exc.__context__, ZeroDivisionError)) else: @@ -1299,8 +1303,9 @@ def __aexit__(self, *e): with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): - + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): run_async(foo()) self.assertEqual(CNT, 1) diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst new file mode 100644 index 000000000000..d8c144e59d6c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst @@ -0,0 +1,2 @@ +Improved error messages in 'async with' when ``__aenter__()`` or +``__aexit__()`` return non-awaitable object. diff --git a/Python/ceval.c b/Python/ceval.c index d18a284e9f9d..da83e41f5ddd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -69,6 +69,7 @@ static PyObject * unicode_concatenate(PyObject *, PyObject *, static PyObject * special_lookup(PyObject *, _Py_Identifier *); static int check_args_iterable(PyObject *func, PyObject *vararg); static void format_kwargs_mapping_error(PyObject *func, PyObject *kwargs); +static void format_awaitable_error(PyTypeObject *, int); #define NAME_ERROR_MSG \ "name '%.200s' is not defined" @@ -1736,6 +1737,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject *iterable = TOP(); PyObject *iter = _PyCoro_GetAwaitableIter(iterable); + if (iter == NULL) { + format_awaitable_error(Py_TYPE(iterable), + _Py_OPCODE(next_instr[-2])); + } + Py_DECREF(iterable); if (iter != NULL && PyCoro_CheckExact(iter)) { @@ -4985,6 +4991,25 @@ format_exc_unbound(PyCodeObject *co, int oparg) } } +static void +format_awaitable_error(PyTypeObject *type, int prevopcode) +{ + if (type->tp_as_async == NULL || type->tp_as_async->am_await == NULL) { + if (prevopcode == BEFORE_ASYNC_WITH) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + else if (prevopcode == WITH_CLEANUP_START) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + } +} + static PyObject * unicode_concatenate(PyObject *v, PyObject *w, PyFrameObject *f, const _Py_CODEUNIT *next_instr) From lp_benchmark_robot at intel.com Mon Apr 2 20:02:27 2018 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 2 Apr 2018 17:02:27 -0700 Subject: [Python-checkins] [65 flat] Results for Python (master branch) 2018-04-02 Message-ID: <4c25134e-77ca-47d7-8a71-8029a21db74a@orsmsx104.amr.corp.intel.com> Results for project python/master, build date: 2018-04-02 03:04:32-07:00. - commit: da58533 - previous commit: 233de02 - revision date: 2018-04-02 01:47:46-04:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.158% | -0.750% | +8.279% | +7.852% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 1.078% | +0.696% | +25.832% | +10.867% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 4.330% | +0.174% | +25.342% | +8.950% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 1.379% | +0.236% | +24.731% | +8.064% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 4.604% | +0.790% | +9.467% | +15.487% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.769% | -1.154% | +9.751% | +13.029% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 0.995% | -0.257% | +6.894% | +11.346% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.423% | -1.036% | -0.454% | +9.396% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.440% | -1.691% | +12.087% | +16.702% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 4.267% | +0.875% | +13.465% | +16.013% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.117% | +0.974% | +5.257% | +6.179% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 0.517% | -0.776% | +6.360% | +4.626% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 1.112% | -0.074% | +3.705% | +5.923% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 0.978% | +0.610% | +13.737% | +11.628% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.833% | +1.129% | +10.712% | +11.353% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 7.392% | +0.312% | +4.202% | +11.550% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.554% | +0.235% | +11.892% | +11.546% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 2.515% | -0.641% | +11.539% | +11.078% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 2.059% | +0.750% | +2.208% | +10.952% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 3.704% | +0.058% | -0.143% | +13.572% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.573% | -0.209% | +18.590% | +12.650% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 6.159% | -0.463% | +47.720% | +13.923% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.486% | +0.110% | +13.484% | +13.148% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.568% | -1.542% | +15.843% | +15.730% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 2.322% | -0.510% | +8.621% | +10.859% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 0.925% | +0.065% | +4.710% | +7.219% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 1.394% | -0.009% | -2.796% | +4.574% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.746% | -0.805% | +5.098% | +7.201% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.426% | -1.116% | +0.814% | +12.023% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 1.479% | -0.509% | +1.306% | +18.372% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.140% | -0.023% | +0.910% | +19.168% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 0.722% | -0.310% | +4.888% | +18.137% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 4.359% | +0.080% | +11.853% | +12.227% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.224% | -0.030% | +0.204% | +9.685% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.129% | +0.045% | +18.138% | +5.220% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.084% | +0.031% | +5.092% | +5.493% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 1.262% | -0.682% | +10.129% | +13.781% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 4.905% | +0.581% | +5.942% | +10.672% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_dna| 0.613% | +2.106% | -0.378% | +8.624% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 1.529% | +4.671% | -3.300% | +3.664% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_v8| 1.403% | +0.752% | +3.872% | +6.433% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.134% | +0.294% | +10.542% | +14.338% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 0.386% | -1.256% | -1.872% | +5.346% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 2.433% | -1.301% | +23.408% | +13.272% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 1.905% | -0.159% | +4.242% | +6.703% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 1.217% | -0.470% | +14.692% | +9.687% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 1.191% | -1.736% | -4.832% | -1.887% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.460% | -0.836% | +4.552% | +5.466% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 1.212% | -0.855% | +6.431% | +6.701% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 3.226% | +0.608% | +7.207% | +5.229% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 2.556% | +1.252% | +1.657% | +9.717% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 3.093% | -0.338% | +16.777% | +7.927% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.256% | +0.111% | +12.825% | +6.389% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 3.078% | +0.789% | +17.727% | +8.466% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 5.807% | +1.610% | +16.223% | +9.360% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 4.209% | +0.048% | +20.966% | +8.680% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 0.847% | +0.249% | +7.348% | +5.853% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 0.807% | -0.014% | +2.118% | +0.202% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 4.063% | +0.772% | +10.076% | +21.102% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 1.214% | +1.285% | -0.527% | +13.804% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 1.836% | -0.103% | +8.257% | +7.232% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 0.933% | +0.347% | +4.768% | +10.579% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 2.200% | +0.803% | +2.054% | +10.094% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 3.810% | -0.733% | -8.777% | +13.275% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 1.110% | +0.078% | +6.160% | +10.771% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/65-flat-results-for-python-master-branch-2018-04-02 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Mon Apr 2 22:43:56 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Tue, 03 Apr 2018 02:43:56 -0000 Subject: [Python-checkins] bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) Message-ID: https://github.com/python/cpython/commit/d1c82c5cc7be0c21dddf86fd19c1702f6218459b commit: d1c82c5cc7be0c21dddf86fd19c1702f6218459b branch: master author: INADA Naoki committer: GitHub date: 2018-04-03T11:43:53+09:00 summary: bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) files: A Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst M Objects/dictobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst new file mode 100644 index 000000000000..22abf8d00011 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst @@ -0,0 +1,2 @@ +Fix ``ma_version_tag`` in dict implementation is uninitialized when copying +from key-sharing dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index bb4ea1f5f9c5..be895d4c1524 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2551,6 +2551,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_values = newvalues; split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; + split_copy->ma_version_tag = DICT_NEXT_VERSION(); DK_INCREF(mp->ma_keys); for (i = 0, n = size; i < n; i++) { PyObject *value = mp->ma_values[i]; From webhook-mailer at python.org Mon Apr 2 22:48:57 2018 From: webhook-mailer at python.org (Benjamin Peterson) Date: Tue, 03 Apr 2018 02:48:57 -0000 Subject: [Python-checkins] closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) Message-ID: https://github.com/python/cpython/commit/badb894bbbb8aaa8b669c4a6f675a0bc7d98e188 commit: badb894bbbb8aaa8b669c4a6f675a0bc7d98e188 branch: master author: Andr?s Delfino <34587441+andresdelfino at users.noreply.github.com> committer: Benjamin Peterson date: 2018-04-02T19:48:54-07:00 summary: closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index e685b33302bd..d269d0b0eaa6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2812,7 +2812,7 @@ features: no effect on the behavior of the walk, because in bottom-up mode the directories in *dirnames* are generated before *dirpath* itself is generated. - By default, errors from the :func:`listdir` call are ignored. If optional + By default, errors from the :func:`scandir` call are ignored. If optional argument *onerror* is specified, it should be a function; it will be called with one argument, an :exc:`OSError` instance. It can report the error to continue with the walk, or raise the exception to abort the walk. Note that the filename From webhook-mailer at python.org Mon Apr 2 23:00:29 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 03:00:29 -0000 Subject: [Python-checkins] bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) Message-ID: https://github.com/python/cpython/commit/de755129a7a14cb3bee89aa256ca2e4a9a6605ce commit: de755129a7a14cb3bee89aa256ca2e4a9a6605ce branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T20:00:26-07:00 summary: bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) (cherry picked from commit d1c82c5cc7be0c21dddf86fd19c1702f6218459b) Co-authored-by: INADA Naoki files: A Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst M Objects/dictobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst new file mode 100644 index 000000000000..22abf8d00011 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst @@ -0,0 +1,2 @@ +Fix ``ma_version_tag`` in dict implementation is uninitialized when copying +from key-sharing dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index bb4ea1f5f9c5..be895d4c1524 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2551,6 +2551,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_values = newvalues; split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; + split_copy->ma_version_tag = DICT_NEXT_VERSION(); DK_INCREF(mp->ma_keys); for (i = 0, n = size; i < n; i++) { PyObject *value = mp->ma_values[i]; From webhook-mailer at python.org Mon Apr 2 23:22:17 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 03:22:17 -0000 Subject: [Python-checkins] bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) Message-ID: https://github.com/python/cpython/commit/9a90826c9b64183713ebe5a98ec82423d9cae3ee commit: 9a90826c9b64183713ebe5a98ec82423d9cae3ee branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T20:22:14-07:00 summary: bpo-33199: Initialize ma_version_tag in PyDict_Copy (GH-6341) (cherry picked from commit d1c82c5cc7be0c21dddf86fd19c1702f6218459b) Co-authored-by: INADA Naoki files: A Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst M Objects/dictobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst new file mode 100644 index 000000000000..22abf8d00011 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-02-09-32-40.bpo-33199.TPnxQu.rst @@ -0,0 +1,2 @@ +Fix ``ma_version_tag`` in dict implementation is uninitialized when copying +from key-sharing dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 8862be81482d..ddd05826ea5f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2654,6 +2654,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_values = newvalues; split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; + split_copy->ma_version_tag = DICT_NEXT_VERSION(); DK_INCREF(mp->ma_keys); for (i = 0, n = size; i < n; i++) { PyObject *value = mp->ma_values[i]; From webhook-mailer at python.org Mon Apr 2 23:33:41 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 03:33:41 -0000 Subject: [Python-checkins] closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) Message-ID: https://github.com/python/cpython/commit/f6d1d65803f290dfe14048f17d8125f8093a61ec commit: f6d1d65803f290dfe14048f17d8125f8093a61ec branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T20:33:38-07:00 summary: closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) (cherry picked from commit badb894bbbb8aaa8b669c4a6f675a0bc7d98e188) Co-authored-by: Andr?s Delfino <34587441+andresdelfino at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index e685b33302bd..d269d0b0eaa6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2812,7 +2812,7 @@ features: no effect on the behavior of the walk, because in bottom-up mode the directories in *dirnames* are generated before *dirpath* itself is generated. - By default, errors from the :func:`listdir` call are ignored. If optional + By default, errors from the :func:`scandir` call are ignored. If optional argument *onerror* is specified, it should be a function; it will be called with one argument, an :exc:`OSError` instance. It can report the error to continue with the walk, or raise the exception to abort the walk. Note that the filename From webhook-mailer at python.org Mon Apr 2 23:39:17 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 03:39:17 -0000 Subject: [Python-checkins] closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) Message-ID: https://github.com/python/cpython/commit/fa5157e0499f7afdb59e220e3f4fdbf44adb5ac8 commit: fa5157e0499f7afdb59e220e3f4fdbf44adb5ac8 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T20:39:14-07:00 summary: closes bpo-33202: fix os.walk mentioning os.listdir instead of os.scandir (GH-6335) (cherry picked from commit badb894bbbb8aaa8b669c4a6f675a0bc7d98e188) Co-authored-by: Andr?s Delfino <34587441+andresdelfino at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index b2722168bc21..b3179acac0d8 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2725,7 +2725,7 @@ features: no effect on the behavior of the walk, because in bottom-up mode the directories in *dirnames* are generated before *dirpath* itself is generated. - By default, errors from the :func:`listdir` call are ignored. If optional + By default, errors from the :func:`scandir` call are ignored. If optional argument *onerror* is specified, it should be a function; it will be called with one argument, an :exc:`OSError` instance. It can report the error to continue with the walk, or raise the exception to abort the walk. Note that the filename From webhook-mailer at python.org Mon Apr 2 23:39:50 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Tue, 03 Apr 2018 03:39:50 -0000 Subject: [Python-checkins] bpo-32360: Remove object_pairs_hook=OrderedDict examples (GH-5001) Message-ID: https://github.com/python/cpython/commit/629338f1404ea9cd75e4fb0389a2fbe1b589de43 commit: 629338f1404ea9cd75e4fb0389a2fbe1b589de43 branch: master author: INADA Naoki committer: GitHub date: 2018-04-03T12:39:47+09:00 summary: bpo-32360: Remove object_pairs_hook=OrderedDict examples (GH-5001) files: M Doc/library/json.rst M Lib/json/__init__.py M Lib/json/decoder.py diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 829218d55843..bcad61aeca3b 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -230,10 +230,8 @@ Basic Usage *object_pairs_hook* is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders that - rely on the order that the key and value pairs are decoded (for example, - :func:`collections.OrderedDict` will remember the order of insertion). If - *object_hook* is also defined, the *object_pairs_hook* takes priority. + :class:`dict`. This feature can be used to implement custom decoders. + If *object_hook* is also defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. @@ -325,10 +323,8 @@ Encoders and Decoders *object_pairs_hook*, if specified will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of *object_pairs_hook* will be used instead of the :class:`dict`. This - feature can be used to implement custom decoders that rely on the order - that the key and value pairs are decoded (for example, - :func:`collections.OrderedDict` will remember the order of insertion). If - *object_hook* is also defined, the *object_pairs_hook* takes priority. + feature can be used to implement custom decoders. If *object_hook* is also + defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index a5660099af75..3bb4490e818b 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -28,8 +28,7 @@ Compact encoding:: >>> import json - >>> from collections import OrderedDict - >>> mydict = OrderedDict([('4', 5), ('6', 7)]) + >>> mydict = {'4': 5, '6': 7} >>> json.dumps([1,2,3,mydict], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' @@ -285,14 +284,11 @@ def load(fp, *, cls=None, object_hook=None, parse_float=None, ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. + This feature can be used to implement custom decoders. If ``object_hook`` + is also defined, the ``object_pairs_hook`` takes priority. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. - """ return loads(fp.read(), cls=cls, object_hook=object_hook, @@ -313,10 +309,8 @@ def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. + This feature can be used to implement custom decoders. If ``object_hook`` + is also defined, the ``object_pairs_hook`` takes priority. ``parse_float``, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to @@ -337,7 +331,6 @@ def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, kwarg; otherwise ``JSONDecoder`` is used. The ``encoding`` argument is ignored and deprecated. - """ if isinstance(s, str): if s.startswith('\ufeff'): diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index 3741deed7d52..d7d824454e1b 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -292,10 +292,8 @@ def __init__(self, *, object_hook=None, parse_float=None, ``object_pairs_hook``, if specified will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes + This feature can be used to implement custom decoders. + If ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. ``parse_float``, if specified, will be called with the string @@ -317,7 +315,6 @@ def __init__(self, *, object_hook=None, parse_float=None, characters will be allowed inside strings. Control characters in this context are those with character codes in the 0-31 range, including ``'\\t'`` (tab), ``'\\n'``, ``'\\r'`` and ``'\\0'``. - """ self.object_hook = object_hook self.parse_float = parse_float or float From webhook-mailer at python.org Tue Apr 3 00:31:30 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 04:31:30 -0000 Subject: [Python-checkins] bpo-32360: Remove object_pairs_hook=OrderedDict examples (GH-5001) Message-ID: https://github.com/python/cpython/commit/0c533573c527c63dacab5921becb66dc3eb274c1 commit: 0c533573c527c63dacab5921becb66dc3eb274c1 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-02T21:31:27-07:00 summary: bpo-32360: Remove object_pairs_hook=OrderedDict examples (GH-5001) (cherry picked from commit 629338f1404ea9cd75e4fb0389a2fbe1b589de43) Co-authored-by: INADA Naoki files: M Doc/library/json.rst M Lib/json/__init__.py M Lib/json/decoder.py diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 829218d55843..bcad61aeca3b 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -230,10 +230,8 @@ Basic Usage *object_pairs_hook* is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders that - rely on the order that the key and value pairs are decoded (for example, - :func:`collections.OrderedDict` will remember the order of insertion). If - *object_hook* is also defined, the *object_pairs_hook* takes priority. + :class:`dict`. This feature can be used to implement custom decoders. + If *object_hook* is also defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. @@ -325,10 +323,8 @@ Encoders and Decoders *object_pairs_hook*, if specified will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of *object_pairs_hook* will be used instead of the :class:`dict`. This - feature can be used to implement custom decoders that rely on the order - that the key and value pairs are decoded (for example, - :func:`collections.OrderedDict` will remember the order of insertion). If - *object_hook* is also defined, the *object_pairs_hook* takes priority. + feature can be used to implement custom decoders. If *object_hook* is also + defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index a5660099af75..3bb4490e818b 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -28,8 +28,7 @@ Compact encoding:: >>> import json - >>> from collections import OrderedDict - >>> mydict = OrderedDict([('4', 5), ('6', 7)]) + >>> mydict = {'4': 5, '6': 7} >>> json.dumps([1,2,3,mydict], separators=(',', ':')) '[1,2,3,{"4":5,"6":7}]' @@ -285,14 +284,11 @@ def load(fp, *, cls=None, object_hook=None, parse_float=None, ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. + This feature can be used to implement custom decoders. If ``object_hook`` + is also defined, the ``object_pairs_hook`` takes priority. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. - """ return loads(fp.read(), cls=cls, object_hook=object_hook, @@ -313,10 +309,8 @@ def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, ``object_pairs_hook`` is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. + This feature can be used to implement custom decoders. If ``object_hook`` + is also defined, the ``object_pairs_hook`` takes priority. ``parse_float``, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to @@ -337,7 +331,6 @@ def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, kwarg; otherwise ``JSONDecoder`` is used. The ``encoding`` argument is ignored and deprecated. - """ if isinstance(s, str): if s.startswith('\ufeff'): diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index 3741deed7d52..d7d824454e1b 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -292,10 +292,8 @@ def __init__(self, *, object_hook=None, parse_float=None, ``object_pairs_hook``, if specified will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders that rely on the - order that the key and value pairs are decoded (for example, - collections.OrderedDict will remember the order of insertion). If - ``object_hook`` is also defined, the ``object_pairs_hook`` takes + This feature can be used to implement custom decoders. + If ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. ``parse_float``, if specified, will be called with the string @@ -317,7 +315,6 @@ def __init__(self, *, object_hook=None, parse_float=None, characters will be allowed inside strings. Control characters in this context are those with character codes in the 0-31 range, including ``'\\t'`` (tab), ``'\\n'``, ``'\\r'`` and ``'\\0'``. - """ self.object_hook = object_hook self.parse_float = parse_float or float From solipsis at pitrou.net Tue Apr 3 05:11:46 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 03 Apr 2018 09:11:46 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=-1 Message-ID: <20180403091146.1.3D683F91A2F6C324@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [-7, 8, -7] memory blocks, sum=-6 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_fork leaked [2, 0, -1] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogjc2pIZ', '--timeout', '7200'] From webhook-mailer at python.org Tue Apr 3 17:11:32 2018 From: webhook-mailer at python.org (=?utf-8?q?=C5=81ukasz?= Langa) Date: Tue, 03 Apr 2018 21:11:32 -0000 Subject: [Python-checkins] bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6363) Message-ID: https://github.com/python/cpython/commit/c869529ea9fbed574d34cf7ac139ca3f81b62ef0 commit: c869529ea9fbed574d34cf7ac139ca3f81b62ef0 branch: master author: Serhiy Storchaka committer: ?ukasz Langa date: 2018-04-03T14:11:27-07:00 summary: bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6363) files: A Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst M Lib/test/pickletester.py M Modules/_pickle.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index b84b87861d01..71c2feadb613 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2781,29 +2781,30 @@ def test_clear_pickler_memo(self): # object again, the third serialized form should be identical to the # first one we obtained. data = ["abcdefg", "abcdefg", 44] - f = io.BytesIO() - pickler = self.pickler_class(f) + for proto in protocols: + f = io.BytesIO() + pickler = self.pickler_class(f, proto) - pickler.dump(data) - first_pickled = f.getvalue() + pickler.dump(data) + first_pickled = f.getvalue() - # Reset BytesIO object. - f.seek(0) - f.truncate() + # Reset BytesIO object. + f.seek(0) + f.truncate() - pickler.dump(data) - second_pickled = f.getvalue() + pickler.dump(data) + second_pickled = f.getvalue() - # Reset the Pickler and BytesIO objects. - pickler.clear_memo() - f.seek(0) - f.truncate() + # Reset the Pickler and BytesIO objects. + pickler.clear_memo() + f.seek(0) + f.truncate() - pickler.dump(data) - third_pickled = f.getvalue() + pickler.dump(data) + third_pickled = f.getvalue() - self.assertNotEqual(first_pickled, second_pickled) - self.assertEqual(first_pickled, third_pickled) + self.assertNotEqual(first_pickled, second_pickled) + self.assertEqual(first_pickled, third_pickled) def test_priming_pickler_memo(self): # Verify that we can set the Pickler's memo attribute. diff --git a/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst new file mode 100644 index 000000000000..d98b1e174e55 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst @@ -0,0 +1 @@ +End framing at the end of C implementation of :func:`pickle.Pickler.dump`. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 9525ad6d9661..6a684f25fefd 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4152,9 +4152,10 @@ dump(PicklerObject *self, PyObject *obj) } if (save(self, obj, 0) < 0 || - _Pickler_Write(self, &stop_op, 1) < 0) + _Pickler_Write(self, &stop_op, 1) < 0 || + _Pickler_CommitFrame(self) < 0) return -1; - + self->framing = 0; return 0; } From webhook-mailer at python.org Tue Apr 3 17:35:14 2018 From: webhook-mailer at python.org (=?utf-8?q?=C5=81ukasz?= Langa) Date: Tue, 03 Apr 2018 21:35:14 -0000 Subject: [Python-checkins] bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6366) Message-ID: https://github.com/python/cpython/commit/74735e2a404949b2a0c17ac13a2de0e0cac6fc41 commit: 74735e2a404949b2a0c17ac13a2de0e0cac6fc41 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ?ukasz Langa date: 2018-04-03T14:35:11-07:00 summary: bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6366) (cherry picked from commit c869529ea9fbed574d34cf7ac139ca3f81b62ef0) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst M Lib/test/pickletester.py M Modules/_pickle.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index b84b87861d01..71c2feadb613 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2781,29 +2781,30 @@ def test_clear_pickler_memo(self): # object again, the third serialized form should be identical to the # first one we obtained. data = ["abcdefg", "abcdefg", 44] - f = io.BytesIO() - pickler = self.pickler_class(f) + for proto in protocols: + f = io.BytesIO() + pickler = self.pickler_class(f, proto) - pickler.dump(data) - first_pickled = f.getvalue() + pickler.dump(data) + first_pickled = f.getvalue() - # Reset BytesIO object. - f.seek(0) - f.truncate() + # Reset BytesIO object. + f.seek(0) + f.truncate() - pickler.dump(data) - second_pickled = f.getvalue() + pickler.dump(data) + second_pickled = f.getvalue() - # Reset the Pickler and BytesIO objects. - pickler.clear_memo() - f.seek(0) - f.truncate() + # Reset the Pickler and BytesIO objects. + pickler.clear_memo() + f.seek(0) + f.truncate() - pickler.dump(data) - third_pickled = f.getvalue() + pickler.dump(data) + third_pickled = f.getvalue() - self.assertNotEqual(first_pickled, second_pickled) - self.assertEqual(first_pickled, third_pickled) + self.assertNotEqual(first_pickled, second_pickled) + self.assertEqual(first_pickled, third_pickled) def test_priming_pickler_memo(self): # Verify that we can set the Pickler's memo attribute. diff --git a/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst new file mode 100644 index 000000000000..d98b1e174e55 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst @@ -0,0 +1 @@ +End framing at the end of C implementation of :func:`pickle.Pickler.dump`. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 9525ad6d9661..6a684f25fefd 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4152,9 +4152,10 @@ dump(PicklerObject *self, PyObject *obj) } if (save(self, obj, 0) < 0 || - _Pickler_Write(self, &stop_op, 1) < 0) + _Pickler_Write(self, &stop_op, 1) < 0 || + _Pickler_CommitFrame(self) < 0) return -1; - + self->framing = 0; return 0; } From webhook-mailer at python.org Tue Apr 3 18:05:20 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Tue, 03 Apr 2018 22:05:20 -0000 Subject: [Python-checkins] bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6363) Message-ID: https://github.com/python/cpython/commit/a5c8830637cde632ab3bcf5475698dcf0fb0546d commit: a5c8830637cde632ab3bcf5475698dcf0fb0546d branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-03T15:05:11-07:00 summary: bpo-33209: End framing at the end of C implementation of pickle.Pickler.dump(). (GH-6363) (cherry picked from commit c869529ea9fbed574d34cf7ac139ca3f81b62ef0) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst M Lib/test/pickletester.py M Modules/_pickle.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index a1c0bd726fe2..764057a86641 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2667,29 +2667,30 @@ def test_clear_pickler_memo(self): # object again, the third serialized form should be identical to the # first one we obtained. data = ["abcdefg", "abcdefg", 44] - f = io.BytesIO() - pickler = self.pickler_class(f) + for proto in protocols: + f = io.BytesIO() + pickler = self.pickler_class(f, proto) - pickler.dump(data) - first_pickled = f.getvalue() + pickler.dump(data) + first_pickled = f.getvalue() - # Reset BytesIO object. - f.seek(0) - f.truncate() + # Reset BytesIO object. + f.seek(0) + f.truncate() - pickler.dump(data) - second_pickled = f.getvalue() + pickler.dump(data) + second_pickled = f.getvalue() - # Reset the Pickler and BytesIO objects. - pickler.clear_memo() - f.seek(0) - f.truncate() + # Reset the Pickler and BytesIO objects. + pickler.clear_memo() + f.seek(0) + f.truncate() - pickler.dump(data) - third_pickled = f.getvalue() + pickler.dump(data) + third_pickled = f.getvalue() - self.assertNotEqual(first_pickled, second_pickled) - self.assertEqual(first_pickled, third_pickled) + self.assertNotEqual(first_pickled, second_pickled) + self.assertEqual(first_pickled, third_pickled) def test_priming_pickler_memo(self): # Verify that we can set the Pickler's memo attribute. diff --git a/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst new file mode 100644 index 000000000000..d98b1e174e55 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-03-10-37-13.bpo-33209.9sGWE_.rst @@ -0,0 +1 @@ +End framing at the end of C implementation of :func:`pickle.Pickler.dump`. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 7e9bb9895ca2..792c7604b59e 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4061,9 +4061,10 @@ dump(PicklerObject *self, PyObject *obj) } if (save(self, obj, 0) < 0 || - _Pickler_Write(self, &stop_op, 1) < 0) + _Pickler_Write(self, &stop_op, 1) < 0 || + _Pickler_CommitFrame(self) < 0) return -1; - + self->framing = 0; return 0; } From lp_benchmark_robot at intel.com Tue Apr 3 19:59:23 2018 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 3 Apr 2018 16:59:23 -0700 Subject: [Python-checkins] [65 flat] Results for Python (master branch) 2018-04-03 Message-ID: <1bd93390-7fa9-4154-a422-016764405fd4@orsmsx110.amr.corp.intel.com> Results for project python/master, build date: 2018-04-03 03:04:29-07:00. - commit: 629338f - previous commit: da58533 - revision date: 2018-04-03 12:39:47+09:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.160% | -0.132% | +8.159% | +8.139% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 0.614% | -1.330% | +24.845% | +9.031% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 1.088% | +1.323% | +26.330% | +10.010% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 0.851% | -1.400% | +23.677% | +8.349% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 3.324% | -0.173% | +9.310% | +15.400% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.509% | +3.596% | +12.996% | +11.958% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 1.143% | +0.335% | +7.206% | +10.567% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.695% | -1.126% | -1.585% | +10.509% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.592% | -0.674% | +11.495% | +17.039% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 4.289% | +1.172% | +14.479% | +15.028% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.467% | +0.250% | +5.494% | +7.689% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 0.262% | -0.070% | +6.295% | +6.122% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 1.249% | -1.000% | +2.742% | +7.632% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 1.659% | +0.688% | +14.330% | +9.605% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.314% | -0.147% | +10.581% | +10.984% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 7.223% | +0.491% | +4.673% | +12.808% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.501% | -0.508% | +11.445% | +12.303% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 2.730% | +1.492% | +12.859% | +9.590% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 1.477% | -0.383% | +1.833% | +11.400% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 5.977% | -3.714% | -3.862% | +13.327% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.916% | +0.735% | +19.189% | +10.462% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 2.580% | -0.751% | +47.328% | +13.107% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.707% | -0.647% | +12.924% | +11.949% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.620% | +1.779% | +17.340% | +15.103% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 1.834% | +0.576% | +9.147% | +10.547% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 2.151% | +1.043% | +5.704% | +5.421% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 0.658% | +2.894% | +0.178% | +1.021% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.496% | +0.977% | +6.025% | +7.422% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.323% | +1.223% | +2.026% | +9.107% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 5.125% | -1.124% | +0.197% | +18.939% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.289% | +0.739% | +1.642% | +15.151% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 0.896% | -0.522% | +4.392% | +16.729% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 3.989% | +0.083% | +11.926% | +10.284% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.215% | -0.057% | +0.148% | +9.892% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.125% | +0.100% | +18.219% | +4.918% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.091% | +0.135% | +5.220% | +5.003% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 1.188% | +0.437% | +10.523% | +13.748% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 4.179% | +0.617% | +6.522% | +10.345% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_dna| 0.384% | -1.681% | -2.066% | +11.897% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 2.240% | -3.663% | -7.084% | +7.910% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_v8| 1.387% | -0.128% | +3.748% | +9.848% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.269% | +0.105% | +10.636% | +15.099% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 2.176% | -0.686% | -2.570% | +6.353% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 3.158% | +0.810% | +24.029% | +11.787% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 2.488% | -0.496% | +3.767% | +6.301% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 2.090% | -0.473% | +14.288% | +10.447% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 4.524% | -2.807% | -7.775% | +4.422% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.454% | -1.806% | +2.828% | +7.746% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 1.381% | +0.192% | +6.611% | +6.898% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 3.100% | +0.888% | +8.031% | +4.628% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 3.797% | -1.266% | +0.413% | +10.941% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 3.378% | +0.432% | +17.137% | +8.302% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.681% | +0.228% | +13.023% | +6.493% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 3.786% | +0.200% | +17.891% | +9.032% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 6.027% | +0.501% | +16.643% | +10.205% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 5.026% | -0.930% | +20.231% | +9.480% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 0.923% | +0.552% | +7.859% | +6.230% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 1.171% | +0.141% | +2.256% | +2.627% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 7.743% | -4.008% | +6.472% | +22.780% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 3.270% | -2.290% | -2.828% | +15.784% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 0.808% | +0.059% | +8.312% | +7.125% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 1.049% | +0.522% | +5.266% | +10.420% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 1.805% | +1.561% | +3.583% | +8.019% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 2.880% | +2.679% | -5.863% | +11.102% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 2.090% | -0.061% | +6.103% | +10.629% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/65-flat-results-for-python-master-branch-2018-04-03 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Wed Apr 4 00:55:09 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Wed, 04 Apr 2018 04:55:09 -0000 Subject: [Python-checkins] bpo-32337: Update documentats about dict order (GH-4973) Message-ID: https://github.com/python/cpython/commit/dfbbbf16f9aab82330c634913441b5ac73267d9c commit: dfbbbf16f9aab82330c634913441b5ac73267d9c branch: master author: hui shang committer: INADA Naoki date: 2018-04-04T13:55:05+09:00 summary: bpo-32337: Update documentats about dict order (GH-4973) files: A Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst M Doc/library/stdtypes.rst M Doc/tutorial/datastructures.rst M Misc/ACKS diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index ad7f578e0860..a213189a3407 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4256,17 +4256,17 @@ support membership tests: Return an iterator over the keys, values or items (represented as tuples of ``(key, value)``) in the dictionary. - Keys and values are iterated over in an arbitrary order which is non-random, - varies across Python implementations, and depends on the dictionary's history - of insertions and deletions. If keys, values and items views are iterated - over with no intervening modifications to the dictionary, the order of items - will directly correspond. This allows the creation of ``(value, key)`` pairs + Keys and values are iterated over in insertion order. + This allows the creation of ``(value, key)`` pairs using :func:`zip`: ``pairs = zip(d.values(), d.keys())``. Another way to create the same list is ``pairs = [(v, k) for (k, v) in d.items()]``. Iterating views while adding or deleting entries in the dictionary may raise a :exc:`RuntimeError` or fail to iterate over all entries. + .. versionchanged:: 3.7 + Dict order is guaranteed to be insertion order. + .. describe:: x in dictview Return ``True`` if *x* is in the underlying dictionary's keys, values or @@ -4293,9 +4293,9 @@ An example of dictionary view usage:: >>> print(n) 504 - >>> # keys and values are iterated over in the same order + >>> # keys and values are iterated over in the same order (insertion order) >>> list(keys) - ['eggs', 'bacon', 'sausage', 'spam'] + ['eggs', 'sausage', 'bacon', 'spam'] >>> list(values) [2, 1, 1, 500] @@ -4303,7 +4303,7 @@ An example of dictionary view usage:: >>> del dishes['eggs'] >>> del dishes['sausage'] >>> list(keys) - ['spam', 'bacon'] + ['bacon', 'spam'] >>> # set operations >>> keys & {'eggs', 'bacon', 'salad'} diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index b95aca885252..7855ef2d2882 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -497,7 +497,7 @@ You can't use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like :meth:`append` and :meth:`extend`. -It is best to think of a dictionary as an unordered set of *key: value* pairs, +It is best to think of a dictionary as a set of *key: value* pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: ``{}``. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the @@ -509,9 +509,9 @@ pair with ``del``. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key. -Performing ``list(d.keys())`` on a dictionary returns a list of all the keys -used in the dictionary, in arbitrary order (if you want it sorted, just use -``sorted(d.keys())`` instead). [2]_ To check whether a single key is in the +Performing ``list(d)`` on a dictionary returns a list of all the keys +used in the dictionary, in insertion order (if you want it sorted, just use +``sorted(d)`` instead). To check whether a single key is in the dictionary, use the :keyword:`in` keyword. Here is a small example using a dictionary:: @@ -519,16 +519,16 @@ Here is a small example using a dictionary:: >>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel - {'sape': 4139, 'guido': 4127, 'jack': 4098} + {'jack': 4098, 'sape': 4139, 'guido': 4127} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel - {'guido': 4127, 'irv': 4127, 'jack': 4098} - >>> list(tel.keys()) - ['irv', 'guido', 'jack'] - >>> sorted(tel.keys()) + {'jack': 4098, 'guido': 4127, 'irv': 4127} + >>> list(tel) + ['jack', 'guido', 'irv'] + >>> sorted(tel) ['guido', 'irv', 'jack'] >>> 'guido' in tel True @@ -539,7 +539,7 @@ The :func:`dict` constructor builds dictionaries directly from sequences of key-value pairs:: >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) - {'sape': 4139, 'jack': 4098, 'guido': 4127} + {'sape': 4139, 'guido': 4127, 'jack': 4098} In addition, dict comprehensions can be used to create dictionaries from arbitrary key and value expressions:: @@ -551,7 +551,7 @@ When the keys are simple strings, it is sometimes easier to specify pairs using keyword arguments:: >>> dict(sape=4139, guido=4127, jack=4098) - {'sape': 4139, 'jack': 4098, 'guido': 4127} + {'sape': 4139, 'guido': 4127, 'jack': 4098} .. _tut-loopidioms: @@ -710,7 +710,3 @@ interpreter will raise a :exc:`TypeError` exception. .. [1] Other languages may return the mutated object, which allows method chaining, such as ``d->insert("a")->remove("b")->sort();``. - -.. [2] Calling ``d.keys()`` will return a :dfn:`dictionary view` object. It - supports operations like membership test and iteration, but its contents - are not independent of the original dictionary -- it is only a *view*. diff --git a/Misc/ACKS b/Misc/ACKS index c7bdbd4a2312..f7ac37ea7ac8 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1451,6 +1451,7 @@ Ian Seyer Dmitry Shachnev Anish Shah Daniel Shahaf +Hui Shang Mark Shannon Ha Shao Richard Shapiro diff --git a/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst b/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst new file mode 100644 index 000000000000..a905467cd59f --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst @@ -0,0 +1 @@ +Update documentation related with ``dict`` order. From webhook-mailer at python.org Wed Apr 4 00:59:11 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Wed, 04 Apr 2018 04:59:11 -0000 Subject: [Python-checkins] bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Message-ID: https://github.com/python/cpython/commit/42ec190761a2e8503aaa06f0bfaaabe98749179b commit: 42ec190761a2e8503aaa06f0bfaaabe98749179b branch: master author: INADA Naoki committer: GitHub date: 2018-04-04T13:59:08+09:00 summary: bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Py_UNICODE is deprecated since Python 3.3. But the deprecation is missed in the c-api/arg document. files: A Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst M Doc/c-api/arg.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index e4b48e66bc2d..b41130ede416 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -151,19 +151,35 @@ which disallows mutable objects such as :class:`bytearray`. Previously, :exc:`TypeError` was raised when embedded null code points were encountered in the Python string. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``u#`` (:class:`str`) [const Py_UNICODE \*, int] This variant on ``u`` stores into two C variables, the first one a pointer to a Unicode data buffer, the second one its length. This variant allows null code points. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z`` (:class:`str` or ``None``) [const Py_UNICODE \*] Like ``u``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z#`` (:class:`str` or ``None``) [const Py_UNICODE \*, int] Like ``u#``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode @@ -552,12 +568,13 @@ Building values ``z#`` (:class:`str` or ``None``) [const char \*, int] Same as ``s#``. - ``u`` (:class:`str`) [const Py_UNICODE \*] - Convert a null-terminated buffer of Unicode (UCS-2 or UCS-4) data to a Python - Unicode object. If the Unicode buffer pointer is *NULL*, ``None`` is returned. + ``u`` (:class:`str`) [const wchar_t \*] + Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + data to a Python Unicode object. If the Unicode buffer pointer is *NULL*, + ``None`` is returned. - ``u#`` (:class:`str`) [const Py_UNICODE \*, int] - Convert a Unicode (UCS-2 or UCS-4) data buffer and its length to a Python + ``u#`` (:class:`str`) [const wchar_t \*, int] + Convert a Unicode (UTF-16 or UCS-4) data buffer and its length to a Python Unicode object. If the Unicode buffer pointer is *NULL*, the length is ignored and ``None`` is returned. diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst new file mode 100644 index 000000000000..6884640325b0 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst @@ -0,0 +1,3 @@ +Deprecate ``Py_UNICODE`` usage in ``c-api/arg`` document. ``Py_UNICODE`` +related APIs are deprecated since Python 3.3, but it is missed in the +document. From webhook-mailer at python.org Wed Apr 4 01:01:49 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 05:01:49 -0000 Subject: [Python-checkins] bpo-32337: Update documentats about dict order (GH-4973) Message-ID: https://github.com/python/cpython/commit/9216dffbc8a2aa62789f81f51f64bc1ec7bf6883 commit: 9216dffbc8a2aa62789f81f51f64bc1ec7bf6883 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-03T22:01:46-07:00 summary: bpo-32337: Update documentats about dict order (GH-4973) (cherry picked from commit dfbbbf16f9aab82330c634913441b5ac73267d9c) Co-authored-by: hui shang files: A Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst M Doc/library/stdtypes.rst M Doc/tutorial/datastructures.rst M Misc/ACKS diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index ad7f578e0860..a213189a3407 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4256,17 +4256,17 @@ support membership tests: Return an iterator over the keys, values or items (represented as tuples of ``(key, value)``) in the dictionary. - Keys and values are iterated over in an arbitrary order which is non-random, - varies across Python implementations, and depends on the dictionary's history - of insertions and deletions. If keys, values and items views are iterated - over with no intervening modifications to the dictionary, the order of items - will directly correspond. This allows the creation of ``(value, key)`` pairs + Keys and values are iterated over in insertion order. + This allows the creation of ``(value, key)`` pairs using :func:`zip`: ``pairs = zip(d.values(), d.keys())``. Another way to create the same list is ``pairs = [(v, k) for (k, v) in d.items()]``. Iterating views while adding or deleting entries in the dictionary may raise a :exc:`RuntimeError` or fail to iterate over all entries. + .. versionchanged:: 3.7 + Dict order is guaranteed to be insertion order. + .. describe:: x in dictview Return ``True`` if *x* is in the underlying dictionary's keys, values or @@ -4293,9 +4293,9 @@ An example of dictionary view usage:: >>> print(n) 504 - >>> # keys and values are iterated over in the same order + >>> # keys and values are iterated over in the same order (insertion order) >>> list(keys) - ['eggs', 'bacon', 'sausage', 'spam'] + ['eggs', 'sausage', 'bacon', 'spam'] >>> list(values) [2, 1, 1, 500] @@ -4303,7 +4303,7 @@ An example of dictionary view usage:: >>> del dishes['eggs'] >>> del dishes['sausage'] >>> list(keys) - ['spam', 'bacon'] + ['bacon', 'spam'] >>> # set operations >>> keys & {'eggs', 'bacon', 'salad'} diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index b95aca885252..7855ef2d2882 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -497,7 +497,7 @@ You can't use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like :meth:`append` and :meth:`extend`. -It is best to think of a dictionary as an unordered set of *key: value* pairs, +It is best to think of a dictionary as a set of *key: value* pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: ``{}``. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the @@ -509,9 +509,9 @@ pair with ``del``. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key. -Performing ``list(d.keys())`` on a dictionary returns a list of all the keys -used in the dictionary, in arbitrary order (if you want it sorted, just use -``sorted(d.keys())`` instead). [2]_ To check whether a single key is in the +Performing ``list(d)`` on a dictionary returns a list of all the keys +used in the dictionary, in insertion order (if you want it sorted, just use +``sorted(d)`` instead). To check whether a single key is in the dictionary, use the :keyword:`in` keyword. Here is a small example using a dictionary:: @@ -519,16 +519,16 @@ Here is a small example using a dictionary:: >>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel - {'sape': 4139, 'guido': 4127, 'jack': 4098} + {'jack': 4098, 'sape': 4139, 'guido': 4127} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel - {'guido': 4127, 'irv': 4127, 'jack': 4098} - >>> list(tel.keys()) - ['irv', 'guido', 'jack'] - >>> sorted(tel.keys()) + {'jack': 4098, 'guido': 4127, 'irv': 4127} + >>> list(tel) + ['jack', 'guido', 'irv'] + >>> sorted(tel) ['guido', 'irv', 'jack'] >>> 'guido' in tel True @@ -539,7 +539,7 @@ The :func:`dict` constructor builds dictionaries directly from sequences of key-value pairs:: >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) - {'sape': 4139, 'jack': 4098, 'guido': 4127} + {'sape': 4139, 'guido': 4127, 'jack': 4098} In addition, dict comprehensions can be used to create dictionaries from arbitrary key and value expressions:: @@ -551,7 +551,7 @@ When the keys are simple strings, it is sometimes easier to specify pairs using keyword arguments:: >>> dict(sape=4139, guido=4127, jack=4098) - {'sape': 4139, 'jack': 4098, 'guido': 4127} + {'sape': 4139, 'guido': 4127, 'jack': 4098} .. _tut-loopidioms: @@ -710,7 +710,3 @@ interpreter will raise a :exc:`TypeError` exception. .. [1] Other languages may return the mutated object, which allows method chaining, such as ``d->insert("a")->remove("b")->sort();``. - -.. [2] Calling ``d.keys()`` will return a :dfn:`dictionary view` object. It - supports operations like membership test and iteration, but its contents - are not independent of the original dictionary -- it is only a *view*. diff --git a/Misc/ACKS b/Misc/ACKS index 729e88e56582..c70f62efcf5f 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1449,6 +1449,7 @@ Ian Seyer Dmitry Shachnev Anish Shah Daniel Shahaf +Hui Shang Mark Shannon Ha Shao Richard Shapiro diff --git a/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst b/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst new file mode 100644 index 000000000000..a905467cd59f --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2017-12-22-17-29-37.bpo-32337.eZe-ID.rst @@ -0,0 +1 @@ +Update documentation related with ``dict`` order. From webhook-mailer at python.org Wed Apr 4 01:13:41 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 05:13:41 -0000 Subject: [Python-checkins] bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Message-ID: https://github.com/python/cpython/commit/b8fc2d658094941250116a48577f54d1f6300362 commit: b8fc2d658094941250116a48577f54d1f6300362 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-03T22:13:38-07:00 summary: bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Py_UNICODE is deprecated since Python 3.3. But the deprecation is missed in the c-api/arg document. (cherry picked from commit 42ec190761a2e8503aaa06f0bfaaabe98749179b) Co-authored-by: INADA Naoki files: A Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst M Doc/c-api/arg.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index e4b48e66bc2d..b41130ede416 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -151,19 +151,35 @@ which disallows mutable objects such as :class:`bytearray`. Previously, :exc:`TypeError` was raised when embedded null code points were encountered in the Python string. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``u#`` (:class:`str`) [const Py_UNICODE \*, int] This variant on ``u`` stores into two C variables, the first one a pointer to a Unicode data buffer, the second one its length. This variant allows null code points. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z`` (:class:`str` or ``None``) [const Py_UNICODE \*] Like ``u``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z#`` (:class:`str` or ``None``) [const Py_UNICODE \*, int] Like ``u#``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode @@ -552,12 +568,13 @@ Building values ``z#`` (:class:`str` or ``None``) [const char \*, int] Same as ``s#``. - ``u`` (:class:`str`) [const Py_UNICODE \*] - Convert a null-terminated buffer of Unicode (UCS-2 or UCS-4) data to a Python - Unicode object. If the Unicode buffer pointer is *NULL*, ``None`` is returned. + ``u`` (:class:`str`) [const wchar_t \*] + Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + data to a Python Unicode object. If the Unicode buffer pointer is *NULL*, + ``None`` is returned. - ``u#`` (:class:`str`) [const Py_UNICODE \*, int] - Convert a Unicode (UCS-2 or UCS-4) data buffer and its length to a Python + ``u#`` (:class:`str`) [const wchar_t \*, int] + Convert a Unicode (UTF-16 or UCS-4) data buffer and its length to a Python Unicode object. If the Unicode buffer pointer is *NULL*, the length is ignored and ``None`` is returned. diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst new file mode 100644 index 000000000000..6884640325b0 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst @@ -0,0 +1,3 @@ +Deprecate ``Py_UNICODE`` usage in ``c-api/arg`` document. ``Py_UNICODE`` +related APIs are deprecated since Python 3.3, but it is missed in the +document. From webhook-mailer at python.org Wed Apr 4 02:06:57 2018 From: webhook-mailer at python.org (=?utf-8?q?=C5=81ukasz?= Langa) Date: Wed, 04 Apr 2018 06:06:57 -0000 Subject: [Python-checkins] bpo-23403: Bump pickle.DEFAULT_PROTOCOL to 4 (#6355) Message-ID: https://github.com/python/cpython/commit/c51d8c9ba6211d77db639487501f89aa9b4bcbb1 commit: c51d8c9ba6211d77db639487501f89aa9b4bcbb1 branch: master author: ?ukasz Langa committer: GitHub date: 2018-04-03T23:06:53-07:00 summary: bpo-23403: Bump pickle.DEFAULT_PROTOCOL to 4 (#6355) This makes performance better and produces shorter pickles. This change is backwards compatible up to the oldest currently supported version of Python (3.4). files: A Misc/NEWS.d/next/Library/2018-04-02-16-10-12.bpo-23403.KG7ADV.rst M Doc/library/pickle.rst M Doc/whatsnew/3.8.rst M Lib/pickle.py M Modules/_pickle.c M Modules/clinic/_pickle.c.h diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index d0c4cf937c8a..ea854fae1944 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -135,14 +135,14 @@ to read the pickle produced. information about improvements brought by protocol 2. * Protocol version 3 was added in Python 3.0. It has explicit support for - :class:`bytes` objects and cannot be unpickled by Python 2.x. This is - the default protocol, and the recommended protocol when compatibility with - other Python 3 versions is required. + :class:`bytes` objects and cannot be unpickled by Python 2.x. This was + the default protocol in Python 3.0--3.7. * Protocol version 4 was added in Python 3.4. It adds support for very large objects, pickling more kinds of objects, and some data format - optimizations. Refer to :pep:`3154` for information about improvements - brought by protocol 4. + optimizations. It is the default protocol starting with Python 3.8. + Refer to :pep:`3154` for information about improvements brought by + protocol 4. .. note:: Serialization is a more primitive notion than persistence; although @@ -179,8 +179,16 @@ The :mod:`pickle` module provides the following constants: An integer, the default :ref:`protocol version ` used for pickling. May be less than :data:`HIGHEST_PROTOCOL`. Currently the - default protocol is 3, a new protocol designed for Python 3. + default protocol is 4, first introduced in Python 3.4 and incompatible + with previous versions. + .. versionchanged:: 3.0 + + The default protocol is 3. + + .. versionchanged:: 3.8 + + The default protocol is 4. The :mod:`pickle` module provides the following functions to make the pickling process more convenient: diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 4e6c85173751..2f42a9f8ba77 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -94,6 +94,9 @@ Improved Modules Optimizations ============= +* The default protocol in the :mod:`pickle` module is now Protocol 4, + first introduced in Python 3.4. It offers better performance and smaller + size compared to Protocol 3 available since Python 3.0. Build and C API Changes ======================= diff --git a/Lib/pickle.py b/Lib/pickle.py index e6d003787bad..b852fbd2296b 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -57,9 +57,9 @@ HIGHEST_PROTOCOL = 4 # The protocol we write by default. May be less than HIGHEST_PROTOCOL. -# We intentionally write a protocol that Python 2.x cannot read; -# there are too many issues with that. -DEFAULT_PROTOCOL = 3 +# Only bump this if the oldest still supported version of Python already +# includes it. +DEFAULT_PROTOCOL = 4 class PickleError(Exception): """A common base class for the other pickling exceptions.""" @@ -376,8 +376,8 @@ def __init__(self, file, protocol=None, *, fix_imports=True): The optional *protocol* argument tells the pickler to use the given protocol; supported protocols are 0, 1, 2, 3 and 4. The - default protocol is 3; a backward-incompatible protocol designed - for Python 3. + default protocol is 4. It was introduced in Python 3.4, it is + incompatible with previous versions. Specifying a negative protocol version selects the highest protocol version supported. The higher the protocol used, the diff --git a/Misc/NEWS.d/next/Library/2018-04-02-16-10-12.bpo-23403.KG7ADV.rst b/Misc/NEWS.d/next/Library/2018-04-02-16-10-12.bpo-23403.KG7ADV.rst new file mode 100644 index 000000000000..d1fbbebfadc6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-02-16-10-12.bpo-23403.KG7ADV.rst @@ -0,0 +1,4 @@ +``DEFAULT_PROTOCOL`` in :mod:`pickle` was bumped to 4. Protocol 4 is +described in :pep:`3154` and available since Python 3.4. It offers +better performance and smaller size compared to protocol 3 introduced +in Python 3.0. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 6a684f25fefd..aa672afacffd 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -20,10 +20,12 @@ class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "&UnpicklerMemoPro [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b3e113468a58e6c]*/ -/* Bump this when new opcodes are added to the pickle protocol. */ +/* Bump HIGHEST_PROTOCOL when new opcodes are added to the pickle protocol. + Bump DEFAULT_PROTOCOL only when the oldest still supported version of Python + already includes it. */ enum { HIGHEST_PROTOCOL = 4, - DEFAULT_PROTOCOL = 3 + DEFAULT_PROTOCOL = 4 }; /* Pickle opcodes. These must be kept updated with pickle.py. @@ -7176,8 +7178,9 @@ This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may be more efficient. The optional *protocol* argument tells the pickler to use the given -protocol supported protocols are 0, 1, 2, 3 and 4. The default -protocol is 3; a backward-incompatible protocol designed for Python 3. +protocol; supported protocols are 0, 1, 2, 3 and 4. The default +protocol is 4. It was introduced in Python 3.4, it is incompatible +with previous versions. Specifying a negative protocol version selects the highest protocol version supported. The higher the protocol used, the more recent the @@ -7196,7 +7199,7 @@ to map the new Python 3 names to the old module names used in Python static PyObject * _pickle_dump_impl(PyObject *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: output=a4774d5fde7d34de input=830f8a64cef6f042]*/ +/*[clinic end generated code: output=a4774d5fde7d34de input=93f1408489a87472]*/ { PicklerObject *pickler = _Pickler_New(); @@ -7236,7 +7239,8 @@ Return the pickled representation of the object as a bytes object. The optional *protocol* argument tells the pickler to use the given protocol; supported protocols are 0, 1, 2, 3 and 4. The default -protocol is 3; a backward-incompatible protocol designed for Python 3. +protocol is 4. It was introduced in Python 3.4, it is incompatible +with previous versions. Specifying a negative protocol version selects the highest protocol version supported. The higher the protocol used, the more recent the @@ -7250,7 +7254,7 @@ Python 2, so that the pickle data stream is readable with Python 2. static PyObject * _pickle_dumps_impl(PyObject *module, PyObject *obj, PyObject *protocol, int fix_imports) -/*[clinic end generated code: output=d75d5cda456fd261 input=293dbeda181580b7]*/ +/*[clinic end generated code: output=d75d5cda456fd261 input=b6efb45a7d19b5ab]*/ { PyObject *result; PicklerObject *pickler = _Pickler_New(); diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h index 7fc00a00479c..6d9072832cea 100644 --- a/Modules/clinic/_pickle.c.h +++ b/Modules/clinic/_pickle.c.h @@ -367,8 +367,9 @@ PyDoc_STRVAR(_pickle_dump__doc__, "be more efficient.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" -"protocol supported protocols are 0, 1, 2, 3 and 4. The default\n" -"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" +"protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" +"protocol is 4. It was introduced in Python 3.4, it is incompatible\n" +"with previous versions.\n" "\n" "Specifying a negative protocol version selects the highest protocol\n" "version supported. The higher the protocol used, the more recent the\n" @@ -419,7 +420,8 @@ PyDoc_STRVAR(_pickle_dumps__doc__, "\n" "The optional *protocol* argument tells the pickler to use the given\n" "protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" -"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" +"protocol is 4. It was introduced in Python 3.4, it is incompatible\n" +"with previous versions.\n" "\n" "Specifying a negative protocol version selects the highest protocol\n" "version supported. The higher the protocol used, the more recent the\n" @@ -560,4 +562,4 @@ _pickle_loads(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=e995dd494045d876 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6fc104b8299c82dd input=a9049054013a1b77]*/ From solipsis at pitrou.net Wed Apr 4 05:11:22 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 04 Apr 2018 09:11:22 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=2 Message-ID: <20180404091122.1.A127B73A932617C9@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [7, -7, 1] memory blocks, sum=1 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_fork leaked [-2, 2, -2] memory blocks, sum=-2 test_multiprocessing_forkserver leaked [0, -2, 2] memory blocks, sum=0 test_multiprocessing_spawn leaked [0, -2, 1] memory blocks, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogTNfHga', '--timeout', '7200'] From webhook-mailer at python.org Wed Apr 4 10:09:03 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 14:09:03 -0000 Subject: [Python-checkins] bpo-29922: Improve error messages in 'async with' (GH-6352) Message-ID: https://github.com/python/cpython/commit/fcd4e03e08a2d4ec1cde17beb66e2b22a052500f commit: fcd4e03e08a2d4ec1cde17beb66e2b22a052500f branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T07:09:00-07:00 summary: bpo-29922: Improve error messages in 'async with' (GH-6352) when __aenter__() or __aexit__() return non-awaitable object. (cherry picked from commit a68f2f0578bbf812fa2264d0e0bb388340d6e230) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst M Lib/test/test_coroutines.py M Python/ceval.c diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 72e404da09be..429de489ad1d 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1255,7 +1255,9 @@ def __aexit__(self, *e): pass with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): + TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: int"): # it's important that __aexit__ wasn't called run_async(foo()) @@ -1275,7 +1277,9 @@ def __aexit__(self, *e): run_async(foo()) except TypeError as exc: self.assertRegex( - exc.args[0], "object int can't be used in 'await' expression") + exc.args[0], + "'async with' received an object from __aexit__ " + "that does not implement __await__: int") self.assertTrue(exc.__context__ is not None) self.assertTrue(isinstance(exc.__context__, ZeroDivisionError)) else: @@ -1299,8 +1303,9 @@ def __aexit__(self, *e): with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): - + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): run_async(foo()) self.assertEqual(CNT, 1) diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst new file mode 100644 index 000000000000..d8c144e59d6c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst @@ -0,0 +1,2 @@ +Improved error messages in 'async with' when ``__aenter__()`` or +``__aexit__()`` return non-awaitable object. diff --git a/Python/ceval.c b/Python/ceval.c index af5eb99d6c90..b37205e50a61 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -69,6 +69,7 @@ static PyObject * unicode_concatenate(PyObject *, PyObject *, static PyObject * special_lookup(PyObject *, _Py_Identifier *); static int check_args_iterable(PyObject *func, PyObject *vararg); static void format_kwargs_mapping_error(PyObject *func, PyObject *kwargs); +static void format_awaitable_error(PyTypeObject *, int); #define NAME_ERROR_MSG \ "name '%.200s' is not defined" @@ -1739,6 +1740,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject *iterable = TOP(); PyObject *iter = _PyCoro_GetAwaitableIter(iterable); + if (iter == NULL) { + format_awaitable_error(Py_TYPE(iterable), + _Py_OPCODE(next_instr[-2])); + } + Py_DECREF(iterable); if (iter != NULL && PyCoro_CheckExact(iter)) { @@ -4948,6 +4954,25 @@ format_exc_unbound(PyCodeObject *co, int oparg) } } +static void +format_awaitable_error(PyTypeObject *type, int prevopcode) +{ + if (type->tp_as_async == NULL || type->tp_as_async->am_await == NULL) { + if (prevopcode == BEFORE_ASYNC_WITH) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + else if (prevopcode == WITH_CLEANUP_START) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + } +} + static PyObject * unicode_concatenate(PyObject *v, PyObject *w, PyFrameObject *f, const _Py_CODEUNIT *next_instr) From webhook-mailer at python.org Wed Apr 4 10:09:17 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 14:09:17 -0000 Subject: [Python-checkins] bpo-29922: Improve error messages in 'async with' (GH-6352) Message-ID: https://github.com/python/cpython/commit/4fd6c27dc8ba7ca97aa70e1ab98729f2207bbe19 commit: 4fd6c27dc8ba7ca97aa70e1ab98729f2207bbe19 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T07:09:14-07:00 summary: bpo-29922: Improve error messages in 'async with' (GH-6352) when __aenter__() or __aexit__() return non-awaitable object. (cherry picked from commit a68f2f0578bbf812fa2264d0e0bb388340d6e230) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst M Lib/test/test_coroutines.py M Python/ceval.c diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 41126b675b5c..769879f082c5 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1229,7 +1229,9 @@ def __aexit__(self, *e): pass with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): + TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: int"): # it's important that __aexit__ wasn't called run_async(foo()) @@ -1249,7 +1251,9 @@ def __aexit__(self, *e): run_async(foo()) except TypeError as exc: self.assertRegex( - exc.args[0], "object int can't be used in 'await' expression") + exc.args[0], + "'async with' received an object from __aexit__ " + "that does not implement __await__: int") self.assertTrue(exc.__context__ is not None) self.assertTrue(isinstance(exc.__context__, ZeroDivisionError)) else: @@ -1273,8 +1277,9 @@ def __aexit__(self, *e): with self.assertRaisesRegex( - TypeError, "object int can't be used in 'await' expression"): - + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): run_async(foo()) self.assertEqual(CNT, 1) diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst new file mode 100644 index 000000000000..d8c144e59d6c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-03-00-30-25.bpo-29922.CdLuMl.rst @@ -0,0 +1,2 @@ +Improved error messages in 'async with' when ``__aenter__()`` or +``__aexit__()`` return non-awaitable object. diff --git a/Python/ceval.c b/Python/ceval.c index 9ad582b15c57..6252e89c9106 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -66,6 +66,7 @@ static PyObject * unicode_concatenate(PyObject *, PyObject *, static PyObject * special_lookup(PyObject *, _Py_Identifier *); static int check_args_iterable(PyObject *func, PyObject *vararg); static void format_kwargs_mapping_error(PyObject *func, PyObject *kwargs); +static void format_awaitable_error(PyTypeObject *, int); #define NAME_ERROR_MSG \ "name '%.200s' is not defined" @@ -2040,6 +2041,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject *iterable = TOP(); PyObject *iter = _PyCoro_GetAwaitableIter(iterable); + if (iter == NULL) { + format_awaitable_error(Py_TYPE(iterable), + _Py_OPCODE(next_instr[-2])); + } + Py_DECREF(iterable); if (iter != NULL && PyCoro_CheckExact(iter)) { @@ -5403,6 +5409,25 @@ format_exc_unbound(PyCodeObject *co, int oparg) } } +static void +format_awaitable_error(PyTypeObject *type, int prevopcode) +{ + if (type->tp_as_async == NULL || type->tp_as_async->am_await == NULL) { + if (prevopcode == BEFORE_ASYNC_WITH) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aenter__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + else if (prevopcode == WITH_CLEANUP_START) { + PyErr_Format(PyExc_TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: %.100s", + type->tp_name); + } + } +} + static PyObject * unicode_concatenate(PyObject *v, PyObject *w, PyFrameObject *f, const _Py_CODEUNIT *next_instr) From webhook-mailer at python.org Wed Apr 4 11:45:20 2018 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Wed, 04 Apr 2018 15:45:20 -0000 Subject: [Python-checkins] bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Message-ID: https://github.com/python/cpython/commit/2eeac269dd1e04a2a179384576986c3e47895ee0 commit: 2eeac269dd1e04a2a179384576986c3e47895ee0 branch: master author: Serhiy Storchaka committer: GitHub date: 2018-04-04T18:45:10+03:00 summary: bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Different paths are executed for normal exit and for leaving the 'async with' block with 'break', 'continue' or 'return'. files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 9ad7ff9564bc..10f7cca50473 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1269,6 +1269,7 @@ class CM: def __aexit__(self, *e): return 444 + # Exit with exception async def foo(): async with CM(): 1/0 @@ -1296,19 +1297,58 @@ class CM: def __aexit__(self, *e): return 456 + # Normal exit async def foo(): nonlocal CNT async with CM(): CNT += 1 + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 1) + # Exit with 'break' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + break + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 2) + # Exit with 'continue' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + continue with self.assertRaisesRegex( TypeError, "'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(foo()) + self.assertEqual(CNT, 3) - self.assertEqual(CNT, 1) + # Exit with 'return' + async def foo(): + nonlocal CNT + async with CM(): + CNT += 1 + return + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 4) def test_with_9(self): From webhook-mailer at python.org Wed Apr 4 12:00:20 2018 From: webhook-mailer at python.org (Ivan Levkivskyi) Date: Wed, 04 Apr 2018 16:00:20 -0000 Subject: [Python-checkins] Call super in Generic.__init_subclass__ (#6356) Message-ID: https://github.com/python/cpython/commit/ee566fe526f3d069aa313578ee81ca6cbc25ff52 commit: ee566fe526f3d069aa313578ee81ca6cbc25ff52 branch: master author: Ivan Levkivskyi committer: GitHub date: 2018-04-04T17:00:15+01:00 summary: Call super in Generic.__init_subclass__ (#6356) files: M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 09e39fec45e4..b12e5ea2fb80 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1232,6 +1232,25 @@ class B(Generic[S]): ... class C(List[int], B): ... self.assertEqual(C.__mro__, (C, list, B, Generic, object)) + def test_init_subclass_super_called(self): + class FinalException(Exception): + pass + + class Final: + def __init_subclass__(cls, **kwargs) -> None: + for base in cls.__bases__: + if base is not Final and issubclass(base, Final): + raise FinalException(base) + super().__init_subclass__(**kwargs) + class Test(Generic[T], Final): + pass + with self.assertRaises(FinalException): + class Subclass(Test): + pass + with self.assertRaises(FinalException): + class Subclass(Test[int]): + pass + def test_nested(self): G = Generic diff --git a/Lib/typing.py b/Lib/typing.py index 510574c413e3..3ac3b9382262 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -850,6 +850,7 @@ def __class_getitem__(cls, params): return _GenericAlias(cls, params) def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) tvars = [] if '__orig_bases__' in cls.__dict__: error = Generic in cls.__orig_bases__ From webhook-mailer at python.org Wed Apr 4 12:28:52 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 16:28:52 -0000 Subject: [Python-checkins] bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Message-ID: https://github.com/python/cpython/commit/785f36c876721c12f653371e9893527a25140624 commit: 785f36c876721c12f653371e9893527a25140624 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T09:28:46-07:00 summary: bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Different paths are executed for normal exit and for leaving the 'async with' block with 'break', 'continue' or 'return'. (cherry picked from commit 2eeac269dd1e04a2a179384576986c3e47895ee0) Co-authored-by: Serhiy Storchaka files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 429de489ad1d..ea54bca0df0d 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1269,6 +1269,7 @@ class CM: def __aexit__(self, *e): return 444 + # Exit with exception async def foo(): async with CM(): 1/0 @@ -1296,19 +1297,58 @@ class CM: def __aexit__(self, *e): return 456 + # Normal exit async def foo(): nonlocal CNT async with CM(): CNT += 1 + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 1) + # Exit with 'break' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + break + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 2) + # Exit with 'continue' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + continue with self.assertRaisesRegex( TypeError, "'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(foo()) + self.assertEqual(CNT, 3) - self.assertEqual(CNT, 1) + # Exit with 'return' + async def foo(): + nonlocal CNT + async with CM(): + CNT += 1 + return + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 4) def test_with_9(self): From webhook-mailer at python.org Wed Apr 4 12:51:37 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 16:51:37 -0000 Subject: [Python-checkins] Call super in Generic.__init_subclass__ (GH-6356) Message-ID: https://github.com/python/cpython/commit/bd85c9738296cf4a53859ed17e9a6812d2071a21 commit: bd85c9738296cf4a53859ed17e9a6812d2071a21 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T09:51:34-07:00 summary: Call super in Generic.__init_subclass__ (GH-6356) (cherry picked from commit ee566fe526f3d069aa313578ee81ca6cbc25ff52) Co-authored-by: Ivan Levkivskyi files: M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 09e39fec45e4..b12e5ea2fb80 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1232,6 +1232,25 @@ class B(Generic[S]): ... class C(List[int], B): ... self.assertEqual(C.__mro__, (C, list, B, Generic, object)) + def test_init_subclass_super_called(self): + class FinalException(Exception): + pass + + class Final: + def __init_subclass__(cls, **kwargs) -> None: + for base in cls.__bases__: + if base is not Final and issubclass(base, Final): + raise FinalException(base) + super().__init_subclass__(**kwargs) + class Test(Generic[T], Final): + pass + with self.assertRaises(FinalException): + class Subclass(Test): + pass + with self.assertRaises(FinalException): + class Subclass(Test[int]): + pass + def test_nested(self): G = Generic diff --git a/Lib/typing.py b/Lib/typing.py index 510574c413e3..3ac3b9382262 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -850,6 +850,7 @@ def __class_getitem__(cls, params): return _GenericAlias(cls, params) def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) tvars = [] if '__orig_bases__' in cls.__dict__: error = Generic in cls.__orig_bases__ From webhook-mailer at python.org Wed Apr 4 13:18:59 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Wed, 04 Apr 2018 17:18:59 -0000 Subject: [Python-checkins] bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Message-ID: https://github.com/python/cpython/commit/1487cd14bb1e04de5b98fffc5ec41c6cf6b5d5f1 commit: 1487cd14bb1e04de5b98fffc5ec41c6cf6b5d5f1 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T10:18:56-07:00 summary: bpo-29922: Add more tests for error messages in 'async with'. (GH-6370) Different paths are executed for normal exit and for leaving the 'async with' block with 'break', 'continue' or 'return'. (cherry picked from commit 2eeac269dd1e04a2a179384576986c3e47895ee0) Co-authored-by: Serhiy Storchaka files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 769879f082c5..d0b44c44bd54 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1243,6 +1243,7 @@ class CM: def __aexit__(self, *e): return 444 + # Exit with exception async def foo(): async with CM(): 1/0 @@ -1270,19 +1271,58 @@ class CM: def __aexit__(self, *e): return 456 + # Normal exit async def foo(): nonlocal CNT async with CM(): CNT += 1 + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 1) + # Exit with 'break' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + break + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 2) + # Exit with 'continue' + async def foo(): + nonlocal CNT + for i in range(2): + async with CM(): + CNT += 1 + continue with self.assertRaisesRegex( TypeError, "'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(foo()) + self.assertEqual(CNT, 3) - self.assertEqual(CNT, 1) + # Exit with 'return' + async def foo(): + nonlocal CNT + async with CM(): + CNT += 1 + return + with self.assertRaisesRegex( + TypeError, + "'async with' received an object from __aexit__ " + "that does not implement __await__: int"): + run_async(foo()) + self.assertEqual(CNT, 4) def test_with_9(self): From lp_benchmark_robot at intel.com Wed Apr 4 19:33:17 2018 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 4 Apr 2018 16:33:17 -0700 Subject: [Python-checkins] [65 flat] Results for Python (master branch) 2018-04-04 Message-ID: <77979041-1a37-49c6-848b-133c2f1294b8@orsmsx156.amr.corp.intel.com> Results for project python/master, build date: 2018-04-04 03:04:31-07:00. - commit: c51d8c9 - previous commit: 629338f - revision date: 2018-04-03 23:06:53-07:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.138% | -0.150% | +8.021% | +8.187% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 0.651% | -0.059% | +24.801% | +12.228% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 2.114% | -0.349% | +26.073% | +11.206% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 1.801% | -0.568% | +23.244% | +12.946% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 2.681% | +0.468% | +9.735% | +14.532% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.389% | -0.066% | +12.939% | +11.683% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 0.756% | +0.026% | +7.231% | +9.732% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.627% | +0.265% | -1.317% | +9.148% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.480% | -0.116% | +11.391% | +16.702% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 4.436% | -0.197% | +14.310% | +17.232% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.035% | +0.361% | +5.836% | +7.149% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 1.340% | -0.252% | +6.058% | +6.285% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 1.183% | -0.434% | +2.320% | +9.137% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 1.277% | +0.069% | +14.389% | +10.403% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.795% | -0.668% | +9.984% | +12.156% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 7.796% | -0.985% | +3.733% | +13.258% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.840% | -0.284% | +11.194% | +11.844% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 2.868% | -0.397% | +12.513% | +9.787% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 2.533% | -0.407% | +1.433% | +10.684% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 1.516% | +1.500% | -2.303% | +14.620% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.491% | -0.728% | +18.601% | +11.847% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 2.568% | +0.173% | +47.419% | +14.301% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.464% | +0.628% | +13.471% | +11.747% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.421% | -0.063% | +17.288% | +13.715% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 2.114% | -0.064% | +9.089% | +11.521% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 1.916% | -0.257% | +5.462% | +5.124% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 0.613% | +0.087% | +0.265% | -0.224% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.570% | -0.074% | +5.955% | +6.756% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.473% | -0.449% | +1.586% | +10.237% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 1.875% | +1.535% | +1.730% | +19.739% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.255% | +1.287% | +2.908% | +16.632% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 5.886% | -1.603% | +2.859% | +18.842% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 3.749% | +0.489% | +12.357% | +11.418% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.126% | +0.039% | +0.187% | +10.267% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.122% | -0.169% | +18.081% | +5.218% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.095% | -0.118% | +5.109% | +5.352% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 1.080% | -0.016% | +10.508% | +13.071% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 4.617% | -0.355% | +6.190% | +10.816% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_dna| 0.359% | +0.124% | -1.939% | +10.595% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 2.286% | +0.736% | -6.296% | +7.492% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_v8| 0.993% | -0.180% | +3.576% | +7.543% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.312% | -0.210% | +10.448% | +14.906% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 1.844% | -0.057% | -2.629% | +3.934% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 3.155% | -0.914% | +23.335% | +12.939% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 2.808% | +0.804% | +4.541% | +6.210% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 2.227% | -0.565% | +13.804% | +10.461% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 0.730% | +0.639% | -7.086% | +5.663% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.530% | +0.066% | +2.892% | +7.690% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 1.226% | +0.129% | +6.731% | +7.033% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 2.963% | +0.808% | +8.774% | +4.346% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 4.759% | -0.611% | -0.196% | +10.356% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 3.366% | +0.346% | +17.424% | +8.384% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.179% | +0.183% | +13.183% | +6.750% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 3.594% | -0.543% | +17.446% | +9.661% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 6.029% | -0.296% | +16.396% | +11.052% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 5.174% | -0.266% | +20.019% | +11.481% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 1.121% | +0.045% | +7.901% | +4.615% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 0.877% | +0.054% | +2.309% | +0.194% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 3.926% | +3.277% | +9.537% | +20.460% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 5.616% | +0.465% | -2.350% | +13.785% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 2.353% | -0.111% | +8.210% | +8.233% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 1.677% | -0.728% | +4.576% | +11.348% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 1.742% | +0.105% | +3.684% | +8.813% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 3.040% | -0.461% | -6.351% | +10.130% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 1.220% | +0.171% | +6.263% | +9.973% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/65-flat-results-for-python-master-branch-2018-04-04 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Wed Apr 4 20:25:18 2018 From: webhook-mailer at python.org (Ivan Levkivskyi) Date: Thu, 05 Apr 2018 00:25:18 -0000 Subject: [Python-checkins] bpo-32873: Remove a name hack for generic aliases in typing module (GH-6376) Message-ID: https://github.com/python/cpython/commit/2a363d2930e29ec6d8a774973ed5a4965f881f5f commit: 2a363d2930e29ec6d8a774973ed5a4965f881f5f branch: master author: Ivan Levkivskyi committer: GitHub date: 2018-04-05T01:25:15+01:00 summary: bpo-32873: Remove a name hack for generic aliases in typing module (GH-6376) This removes a hack and replaces it with a proper mapping {'list': 'List', 'dict': 'Dict', ...}. files: M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b12e5ea2fb80..390fe60fcc10 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1058,14 +1058,15 @@ class C(B[int]): self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) samples = [Any, Union, Tuple, Callable, ClassVar, - Union[int, str], ClassVar[List], Tuple[int, ...], Callable[[str], bytes]] + Union[int, str], ClassVar[List], Tuple[int, ...], Callable[[str], bytes], + typing.DefaultDict, typing.FrozenSet[int]] for s in samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) x = pickle.loads(z) self.assertEqual(s, x) more_samples = [List, typing.Iterable, typing.Type, List[int], - typing.Type[typing.Mapping]] + typing.Type[typing.Mapping], typing.AbstractSet[Tuple[int, str]]] for s in more_samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) diff --git a/Lib/typing.py b/Lib/typing.py index 3ac3b9382262..d45502ffee48 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -611,6 +611,19 @@ def __reduce__(self): # * __args__ is a tuple of all arguments used in subscripting, # e.g., Dict[T, int].__args__ == (T, int). + +# Mapping from non-generic type names that have a generic alias in typing +# but with a different name. +_normalize_alias = {'list': 'List', + 'tuple': 'Tuple', + 'dict': 'Dict', + 'set': 'Set', + 'frozenset': 'FrozenSet', + 'deque': 'Deque', + 'defaultdict': 'DefaultDict', + 'type': 'Type', + 'Set': 'AbstractSet'} + def _is_dunder(attr): return attr.startswith('__') and attr.endswith('__') @@ -629,7 +642,7 @@ def __init__(self, origin, params, *, inst=True, special=False, name=None): self._special = special if special and name is None: orig_name = origin.__name__ - name = orig_name[0].title() + orig_name[1:] + name = _normalize_alias.get(orig_name, orig_name) self._name = name if not isinstance(params, tuple): params = (params,) From webhook-mailer at python.org Wed Apr 4 20:46:43 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Thu, 05 Apr 2018 00:46:43 -0000 Subject: [Python-checkins] bpo-32873: Remove a name hack for generic aliases in typing module (GH-6376) Message-ID: https://github.com/python/cpython/commit/04eac02088f60192c7e54c7364bcaa892d7c05cf commit: 04eac02088f60192c7e54c7364bcaa892d7c05cf branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-04T17:46:40-07:00 summary: bpo-32873: Remove a name hack for generic aliases in typing module (GH-6376) This removes a hack and replaces it with a proper mapping {'list': 'List', 'dict': 'Dict', ...}. (cherry picked from commit 2a363d2930e29ec6d8a774973ed5a4965f881f5f) Co-authored-by: Ivan Levkivskyi files: M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b12e5ea2fb80..390fe60fcc10 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1058,14 +1058,15 @@ class C(B[int]): self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) samples = [Any, Union, Tuple, Callable, ClassVar, - Union[int, str], ClassVar[List], Tuple[int, ...], Callable[[str], bytes]] + Union[int, str], ClassVar[List], Tuple[int, ...], Callable[[str], bytes], + typing.DefaultDict, typing.FrozenSet[int]] for s in samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) x = pickle.loads(z) self.assertEqual(s, x) more_samples = [List, typing.Iterable, typing.Type, List[int], - typing.Type[typing.Mapping]] + typing.Type[typing.Mapping], typing.AbstractSet[Tuple[int, str]]] for s in more_samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) diff --git a/Lib/typing.py b/Lib/typing.py index 3ac3b9382262..d45502ffee48 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -611,6 +611,19 @@ def __reduce__(self): # * __args__ is a tuple of all arguments used in subscripting, # e.g., Dict[T, int].__args__ == (T, int). + +# Mapping from non-generic type names that have a generic alias in typing +# but with a different name. +_normalize_alias = {'list': 'List', + 'tuple': 'Tuple', + 'dict': 'Dict', + 'set': 'Set', + 'frozenset': 'FrozenSet', + 'deque': 'Deque', + 'defaultdict': 'DefaultDict', + 'type': 'Type', + 'Set': 'AbstractSet'} + def _is_dunder(attr): return attr.startswith('__') and attr.endswith('__') @@ -629,7 +642,7 @@ def __init__(self, origin, params, *, inst=True, special=False, name=None): self._special = special if special and name is None: orig_name = origin.__name__ - name = orig_name[0].title() + orig_name[1:] + name = _normalize_alias.get(orig_name, orig_name) self._name = name if not isinstance(params, tuple): params = (params,) From webhook-mailer at python.org Wed Apr 4 22:12:42 2018 From: webhook-mailer at python.org (Brett Cannon) Date: Thu, 05 Apr 2018 02:12:42 -0000 Subject: [Python-checkins] Add a webhook for Zulip to the Travis configuration (GH-6379) Message-ID: https://github.com/python/cpython/commit/0876505bd32b5ab3a14fa4cc0528d763916440a8 commit: 0876505bd32b5ab3a14fa4cc0528d763916440a8 branch: master author: Brett Cannon committer: GitHub date: 2018-04-04T19:12:39-07:00 summary: Add a webhook for Zulip to the Travis configuration (GH-6379) files: M .travis.yml diff --git a/.travis.yml b/.travis.yml index af3cdf54654d..fecad290d8bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -149,6 +149,11 @@ script: notifications: email: false + webhooks: + urls: + - https://python.zulipchat.com/api/v1/external/travis?api_key=QTP4LAknlFml0NuPQmAetvH4KQaokiQE&stream=core%2Ftest+runs + on_success: change + on_failure: always irc: channels: # This is set to a secure variable to prevent forks from notifying the From webhook-mailer at python.org Thu Apr 5 05:08:52 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Thu, 05 Apr 2018 09:08:52 -0000 Subject: [Python-checkins] bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Message-ID: https://github.com/python/cpython/commit/29bc6f6347b1e05b22180fd296013bb2a104d589 commit: 29bc6f6347b1e05b22180fd296013bb2a104d589 branch: 3.6 author: INADA Naoki committer: GitHub date: 2018-04-05T18:08:43+09:00 summary: bpo-33195: Doc: Deprecate Py_UNICODE in c-api/arg (GH-6329) Py_UNICODE is deprecated since Python 3.3. But the deprecation is missed in the c-api/arg document. (cherry picked from commit 42ec190) files: A Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst M Doc/c-api/arg.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index e8e7e0d55930..dc58e152a6b5 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -151,19 +151,35 @@ which disallows mutable objects such as :class:`bytearray`. Previously, :exc:`TypeError` was raised when embedded null code points were encountered in the Python string. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``u#`` (:class:`str`) [Py_UNICODE \*, int] This variant on ``u`` stores into two C variables, the first one a pointer to a Unicode data buffer, the second one its length. This variant allows null code points. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z`` (:class:`str` or ``None``) [Py_UNICODE \*] Like ``u``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``Z#`` (:class:`str` or ``None``) [Py_UNICODE \*, int] Like ``u#``, but the Python object may also be ``None``, in which case the :c:type:`Py_UNICODE` pointer is set to *NULL*. + .. deprecated-removed:: 3.3 4.0 + Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using + :c:func:`PyUnicode_AsWideCharString`. + ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode @@ -552,12 +568,13 @@ Building values ``z#`` (:class:`str` or ``None``) [char \*, int] Same as ``s#``. - ``u`` (:class:`str`) [Py_UNICODE \*] - Convert a null-terminated buffer of Unicode (UCS-2 or UCS-4) data to a Python - Unicode object. If the Unicode buffer pointer is *NULL*, ``None`` is returned. + ``u`` (:class:`str`) [wchar_t \*] + Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + data to a Python Unicode object. If the Unicode buffer pointer is *NULL*, + ``None`` is returned. - ``u#`` (:class:`str`) [Py_UNICODE \*, int] - Convert a Unicode (UCS-2 or UCS-4) data buffer and its length to a Python + ``u#`` (:class:`str`) [wchar_t \*, int] + Convert a Unicode (UTF-16 or UCS-4) data buffer and its length to a Python Unicode object. If the Unicode buffer pointer is *NULL*, the length is ignored and ``None`` is returned. diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst new file mode 100644 index 000000000000..6884640325b0 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-14-30-36.bpo-33195.dRS-XX.rst @@ -0,0 +1,3 @@ +Deprecate ``Py_UNICODE`` usage in ``c-api/arg`` document. ``Py_UNICODE`` +related APIs are deprecated since Python 3.3, but it is missed in the +document. From solipsis at pitrou.net Thu Apr 5 05:12:27 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 05 Apr 2018 09:12:27 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=4 Message-ID: <20180405091227.1.36C06B191B7E499B@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_forkserver leaked [-2, 2, 0] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogUVLyTY', '--timeout', '7200'] From webhook-mailer at python.org Thu Apr 5 06:50:26 2018 From: webhook-mailer at python.org (Eric V. Smith) Date: Thu, 05 Apr 2018 10:50:26 -0000 Subject: [Python-checkins] Clean up and enhance frozen dataclass tests. (GH-6380) Message-ID: https://github.com/python/cpython/commit/74940913d26d9f94b8572eca794369841fa6d9b6 commit: 74940913d26d9f94b8572eca794369841fa6d9b6 branch: master author: Eric V. Smith committer: GitHub date: 2018-04-05T06:50:18-04:00 summary: Clean up and enhance frozen dataclass tests. (GH-6380) * Add a test for frozen with unhashable field value. * Improve a comment. files: M Lib/test/test_dataclasses.py diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 26bfc4e75a00..2c890a2cbe92 100755 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2191,33 +2191,6 @@ def __repr__(self): self.assertEqual(repr(C(0)), 'x') -class TestFrozen(unittest.TestCase): - def test_overwriting_frozen(self): - # frozen uses __setattr__ and __delattr__. - with self.assertRaisesRegex(TypeError, - 'Cannot overwrite attribute __setattr__'): - @dataclass(frozen=True) - class C: - x: int - def __setattr__(self): - pass - - with self.assertRaisesRegex(TypeError, - 'Cannot overwrite attribute __delattr__'): - @dataclass(frozen=True) - class C: - x: int - def __delattr__(self): - pass - - @dataclass(frozen=False) - class C: - x: int - def __setattr__(self, name, value): - self.__dict__['x'] = value * 2 - self.assertEqual(C(10).x, 20) - - class TestEq(unittest.TestCase): def test_no_eq(self): # Test a class with no __eq__ and eq=False. @@ -2672,6 +2645,44 @@ class S(D): self.assertEqual(s.y, 10) self.assertEqual(s.cached, True) + def test_overwriting_frozen(self): + # frozen uses __setattr__ and __delattr__. + with self.assertRaisesRegex(TypeError, + 'Cannot overwrite attribute __setattr__'): + @dataclass(frozen=True) + class C: + x: int + def __setattr__(self): + pass + + with self.assertRaisesRegex(TypeError, + 'Cannot overwrite attribute __delattr__'): + @dataclass(frozen=True) + class C: + x: int + def __delattr__(self): + pass + + @dataclass(frozen=False) + class C: + x: int + def __setattr__(self, name, value): + self.__dict__['x'] = value * 2 + self.assertEqual(C(10).x, 20) + + def test_frozen_hash(self): + @dataclass(frozen=True) + class C: + x: Any + + # If x is immutable, we can compute the hash. No exception is + # raised. + hash(C(3)) + + # If x is mutable, computing the hash is an error. + with self.assertRaisesRegex(TypeError, 'unhashable type'): + hash(C({})) + class TestSlots(unittest.TestCase): def test_simple(self): From webhook-mailer at python.org Thu Apr 5 07:12:34 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Thu, 05 Apr 2018 11:12:34 -0000 Subject: [Python-checkins] Clean up and enhance frozen dataclass tests. (GH-6380) Message-ID: https://github.com/python/cpython/commit/83f564fd242c1af9dbe6d4273ad50586489000e3 commit: 83f564fd242c1af9dbe6d4273ad50586489000e3 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-05T04:12:31-07:00 summary: Clean up and enhance frozen dataclass tests. (GH-6380) * Add a test for frozen with unhashable field value. * Improve a comment. (cherry picked from commit 74940913d26d9f94b8572eca794369841fa6d9b6) Co-authored-by: Eric V. Smith files: M Lib/test/test_dataclasses.py diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 26bfc4e75a00..2c890a2cbe92 100755 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2191,33 +2191,6 @@ def __repr__(self): self.assertEqual(repr(C(0)), 'x') -class TestFrozen(unittest.TestCase): - def test_overwriting_frozen(self): - # frozen uses __setattr__ and __delattr__. - with self.assertRaisesRegex(TypeError, - 'Cannot overwrite attribute __setattr__'): - @dataclass(frozen=True) - class C: - x: int - def __setattr__(self): - pass - - with self.assertRaisesRegex(TypeError, - 'Cannot overwrite attribute __delattr__'): - @dataclass(frozen=True) - class C: - x: int - def __delattr__(self): - pass - - @dataclass(frozen=False) - class C: - x: int - def __setattr__(self, name, value): - self.__dict__['x'] = value * 2 - self.assertEqual(C(10).x, 20) - - class TestEq(unittest.TestCase): def test_no_eq(self): # Test a class with no __eq__ and eq=False. @@ -2672,6 +2645,44 @@ class S(D): self.assertEqual(s.y, 10) self.assertEqual(s.cached, True) + def test_overwriting_frozen(self): + # frozen uses __setattr__ and __delattr__. + with self.assertRaisesRegex(TypeError, + 'Cannot overwrite attribute __setattr__'): + @dataclass(frozen=True) + class C: + x: int + def __setattr__(self): + pass + + with self.assertRaisesRegex(TypeError, + 'Cannot overwrite attribute __delattr__'): + @dataclass(frozen=True) + class C: + x: int + def __delattr__(self): + pass + + @dataclass(frozen=False) + class C: + x: int + def __setattr__(self, name, value): + self.__dict__['x'] = value * 2 + self.assertEqual(C(10).x, 20) + + def test_frozen_hash(self): + @dataclass(frozen=True) + class C: + x: Any + + # If x is immutable, we can compute the hash. No exception is + # raised. + hash(C(3)) + + # If x is mutable, computing the hash is an error. + with self.assertRaisesRegex(TypeError, 'unhashable type'): + hash(C({})) + class TestSlots(unittest.TestCase): def test_simple(self): From webhook-mailer at python.org Thu Apr 5 11:19:54 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 15:19:54 -0000 Subject: [Python-checkins] bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) Message-ID: https://github.com/python/cpython/commit/091e95e9004b794280ab35becec2c3e30dd5e96e commit: 091e95e9004b794280ab35becec2c3e30dd5e96e branch: master author: Wolfgang Maier committer: Raymond Hettinger date: 2018-04-05T08:19:44-07:00 summary: bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) files: A Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst M Lib/random.py M Lib/test/test_random.py diff --git a/Lib/random.py b/Lib/random.py index 91065b7e3037..0bc24174e13f 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -242,6 +242,8 @@ def _randbelow(self, n, int=int, maxsize=1<= maxsize) self.gen._randbelow(maxsize+1, maxsize = maxsize) self.gen._randbelow(5640, maxsize = maxsize) - + # issue 33203: test that _randbelow raises ValueError on + # n == 0 also in its getrandbits-independent branch. + with self.assertRaises(ValueError): + self.gen._randbelow(0, maxsize=maxsize) # This might be going too far to test a single line, but because of our # noble aim of achieving 100% test coverage we need to write a case in # which the following line in Random._randbelow() gets executed: diff --git a/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst new file mode 100644 index 000000000000..ab6d17b5d1ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst @@ -0,0 +1,3 @@ +``random.Random.choice()`` now raises ``IndexError`` for empty sequences +consistently even when called from subclasses without a ``getrandbits()`` +implementation. From webhook-mailer at python.org Thu Apr 5 12:02:15 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 16:02:15 -0000 Subject: [Python-checkins] bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) (GH-6387) Message-ID: https://github.com/python/cpython/commit/baf304e82e1b54dbeee6b78ddf168e33ed8d557a commit: baf304e82e1b54dbeee6b78ddf168e33ed8d557a branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Raymond Hettinger date: 2018-04-05T09:02:12-07:00 summary: bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) (GH-6387) (cherry picked from commit 091e95e9004b794280ab35becec2c3e30dd5e96e) Co-authored-by: Wolfgang Maier files: A Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst M Lib/random.py M Lib/test/test_random.py diff --git a/Lib/random.py b/Lib/random.py index 91065b7e3037..0bc24174e13f 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -242,6 +242,8 @@ def _randbelow(self, n, int=int, maxsize=1<= maxsize) self.gen._randbelow(maxsize+1, maxsize = maxsize) self.gen._randbelow(5640, maxsize = maxsize) - + # issue 33203: test that _randbelow raises ValueError on + # n == 0 also in its getrandbits-independent branch. + with self.assertRaises(ValueError): + self.gen._randbelow(0, maxsize=maxsize) # This might be going too far to test a single line, but because of our # noble aim of achieving 100% test coverage we need to write a case in # which the following line in Random._randbelow() gets executed: diff --git a/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst new file mode 100644 index 000000000000..ab6d17b5d1ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst @@ -0,0 +1,3 @@ +``random.Random.choice()`` now raises ``IndexError`` for empty sequences +consistently even when called from subclasses without a ``getrandbits()`` +implementation. From webhook-mailer at python.org Thu Apr 5 12:24:30 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 16:24:30 -0000 Subject: [Python-checkins] bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) (GH-6388) Message-ID: https://github.com/python/cpython/commit/e25af930a300c01aa043745058a8c7f6c32d89ae commit: e25af930a300c01aa043745058a8c7f6c32d89ae branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Raymond Hettinger date: 2018-04-05T09:24:27-07:00 summary: bpo-33203: Ensure random.choice always raises IndexError on empty sequence (GH-6338) (GH-6388) (cherry picked from commit 091e95e9004b794280ab35becec2c3e30dd5e96e) Co-authored-by: Wolfgang Maier files: A Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst M Lib/random.py M Lib/test/test_random.py diff --git a/Lib/random.py b/Lib/random.py index 0152e5ea12bf..7a2585e01ab3 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -241,6 +241,8 @@ def _randbelow(self, n, int=int, maxsize=1<= maxsize) self.gen._randbelow(maxsize+1, maxsize = maxsize) self.gen._randbelow(5640, maxsize = maxsize) - + # issue 33203: test that _randbelow raises ValueError on + # n == 0 also in its getrandbits-independent branch. + with self.assertRaises(ValueError): + self.gen._randbelow(0, maxsize=maxsize) # This might be going too far to test a single line, but because of our # noble aim of achieving 100% test coverage we need to write a case in # which the following line in Random._randbelow() gets executed: diff --git a/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst new file mode 100644 index 000000000000..ab6d17b5d1ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-05-11-09-45.bpo-33203.Hje9Py.rst @@ -0,0 +1,3 @@ +``random.Random.choice()`` now raises ``IndexError`` for empty sequences +consistently even when called from subclasses without a ``getrandbits()`` +implementation. From webhook-mailer at python.org Thu Apr 5 13:34:46 2018 From: webhook-mailer at python.org (Ned Deily) Date: Thu, 05 Apr 2018 17:34:46 -0000 Subject: [Python-checkins] bpo-15817: Expose command documentation to gdb help (GH-6384) Message-ID: https://github.com/python/cpython/commit/7286dbd8b20bd0a26fabe1a07ff368082a9c5ed6 commit: 7286dbd8b20bd0a26fabe1a07ff368082a9c5ed6 branch: master author: Skip Montanaro committer: Ned Deily date: 2018-04-05T13:34:44-04:00 summary: bpo-15817: Expose command documentation to gdb help (GH-6384) Original patch by Alexander Belopolsky. Patch by Skip Montanaro. files: M Misc/gdbinit diff --git a/Misc/gdbinit b/Misc/gdbinit index 3b6fe50ef931..9f216215eac2 100644 --- a/Misc/gdbinit +++ b/Misc/gdbinit @@ -14,9 +14,11 @@ # with embedded macros that you may find superior to what is in here. # See Tools/gdb/libpython.py and http://bugs.python.org/issue8032. -# Prints a representation of the object to stderr, along with the -# number of reference counts it current has and the hex address the -# object is allocated at. The argument must be a PyObject* +document pyo + Prints a representation of the object to stderr, along with the + number of reference counts it currently has and the hex address the + object is allocated at. The argument must be a PyObject* +end define pyo # side effect of calling _PyObject_Dump is to dump the object's # info - assigning just prevents gdb from printing the @@ -24,14 +26,18 @@ define pyo set $_unused_void = _PyObject_Dump($arg0) end -# Prints a representation of the object to stderr, along with the -# number of reference counts it current has and the hex address the -# object is allocated at. The argument must be a PyGC_Head* +document pyg + Prints a representation of the object to stderr, along with the + number of reference counts it currently has and the hex address the + object is allocated at. The argument must be a PyGC_Head* +end define pyg print _PyGC_Dump($arg0) end -# print the local variables of the current frame +document pylocals + Print the local variables of the current frame. +end define pylocals set $_i = 0 while $_i < f->f_code->co_nlocals @@ -69,7 +75,9 @@ define lineno printf "%d", $__li end -# print the current frame - verbose +document pyframev + Print the current frame - verbose +end define pyframev pyframe pylocals @@ -126,7 +134,9 @@ end # the interpreter you may will have to change the functions you compare with # $pc. -# print the entire Python call stack +document pystack + Print the entire Python call stack +end define pystack while $pc < Py_Main || $pc > Py_GetArgcArgv if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx @@ -137,7 +147,9 @@ define pystack select-frame 0 end -# print the entire Python call stack - verbose mode +document pystackv + Print the entire Python call stack - verbose mode +end define pystackv while $pc < Py_Main || $pc > Py_GetArgcArgv if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx @@ -148,7 +160,9 @@ define pystackv select-frame 0 end -# generally useful macro to print a Unicode string +document pu + Generally useful macro to print a Unicode string +end def pu set $uni = $arg0 set $i = 0 From webhook-mailer at python.org Thu Apr 5 14:20:00 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 18:20:00 -0000 Subject: [Python-checkins] bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) Message-ID: https://github.com/python/cpython/commit/01b731fc2b04744a11e32f93aba8bfb9ddb3dd29 commit: 01b731fc2b04744a11e32f93aba8bfb9ddb3dd29 branch: master author: Raymond Hettinger committer: GitHub date: 2018-04-05T11:19:57-07:00 summary: bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) files: A Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst M Lib/difflib.py M Lib/test/test_difflib.py diff --git a/Lib/difflib.py b/Lib/difflib.py index 043a169c28be..887c3c26cae4 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1634,14 +1634,18 @@ def _line_pair_iterator(): lines_to_write -= 1 # Now yield the context lines after the change lines_to_write = context-1 - while(lines_to_write): - from_line, to_line, found_diff = next(line_pair_iterator) - # If another change within the context, extend the context - if found_diff: - lines_to_write = context-1 - else: - lines_to_write -= 1 - yield from_line, to_line, found_diff + try: + while(lines_to_write): + from_line, to_line, found_diff = next(line_pair_iterator) + # If another change within the context, extend the context + if found_diff: + lines_to_write = context-1 + else: + lines_to_write -= 1 + yield from_line, to_line, found_diff + except StopIteration: + # Catch exception from next() and return normally + return _file_template = """ diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index aaefe6db0291..745ccbd6659e 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -93,6 +93,14 @@ def test_added_tab_hint(self): self.assertEqual("+ \t\tI am a bug", diff[2]) self.assertEqual("? +\n", diff[3]) + def test_mdiff_catch_stop_iteration(self): + # Issue #33224 + self.assertEqual( + list(difflib._mdiff(["2"], ["3"], 1)), + [((1, '\x00-2\x01'), (1, '\x00+3\x01'), True)], + ) + + patch914575_from1 = """ 1. Beautiful is beTTer than ugly. 2. Explicit is better than implicit. diff --git a/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst new file mode 100644 index 000000000000..87ff100da4b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst @@ -0,0 +1,2 @@ +Update difflib.mdiff() for PEP 479. Convert an uncaught StopIteration in a +generator into a return-statement. From webhook-mailer at python.org Thu Apr 5 14:45:36 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 18:45:36 -0000 Subject: [Python-checkins] bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) (GH-6390) Message-ID: https://github.com/python/cpython/commit/28c179094bcb7829d184fb3cfb3ef626505b9f77 commit: 28c179094bcb7829d184fb3cfb3ef626505b9f77 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Raymond Hettinger date: 2018-04-05T11:45:33-07:00 summary: bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) (GH-6390) files: A Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst M Lib/difflib.py M Lib/test/test_difflib.py diff --git a/Lib/difflib.py b/Lib/difflib.py index 043a169c28be..887c3c26cae4 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1634,14 +1634,18 @@ def _line_pair_iterator(): lines_to_write -= 1 # Now yield the context lines after the change lines_to_write = context-1 - while(lines_to_write): - from_line, to_line, found_diff = next(line_pair_iterator) - # If another change within the context, extend the context - if found_diff: - lines_to_write = context-1 - else: - lines_to_write -= 1 - yield from_line, to_line, found_diff + try: + while(lines_to_write): + from_line, to_line, found_diff = next(line_pair_iterator) + # If another change within the context, extend the context + if found_diff: + lines_to_write = context-1 + else: + lines_to_write -= 1 + yield from_line, to_line, found_diff + except StopIteration: + # Catch exception from next() and return normally + return _file_template = """ diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index aaefe6db0291..745ccbd6659e 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -93,6 +93,14 @@ def test_added_tab_hint(self): self.assertEqual("+ \t\tI am a bug", diff[2]) self.assertEqual("? +\n", diff[3]) + def test_mdiff_catch_stop_iteration(self): + # Issue #33224 + self.assertEqual( + list(difflib._mdiff(["2"], ["3"], 1)), + [((1, '\x00-2\x01'), (1, '\x00+3\x01'), True)], + ) + + patch914575_from1 = """ 1. Beautiful is beTTer than ugly. 2. Explicit is better than implicit. diff --git a/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst new file mode 100644 index 000000000000..87ff100da4b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst @@ -0,0 +1,2 @@ +Update difflib.mdiff() for PEP 479. Convert an uncaught StopIteration in a +generator into a return-statement. From webhook-mailer at python.org Thu Apr 5 15:18:05 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Thu, 05 Apr 2018 19:18:05 -0000 Subject: [Python-checkins] bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) (GH-6391) Message-ID: https://github.com/python/cpython/commit/8da15f09458fd4f4fe341861e41723892b25a11b commit: 8da15f09458fd4f4fe341861e41723892b25a11b branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Raymond Hettinger date: 2018-04-05T12:18:02-07:00 summary: bpo-33224: PEP 479 fix for difflib.mdiff() (GH-6381) (GH-6391) (cherry picked from commit 01b731fc2b04744a11e32f93aba8bfb9ddb3dd29) Co-authored-by: Raymond Hettinger files: A Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst M Lib/difflib.py M Lib/test/test_difflib.py diff --git a/Lib/difflib.py b/Lib/difflib.py index 72971d5b87a9..7cebd64978ea 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1634,14 +1634,18 @@ def _line_pair_iterator(): lines_to_write -= 1 # Now yield the context lines after the change lines_to_write = context-1 - while(lines_to_write): - from_line, to_line, found_diff = next(line_pair_iterator) - # If another change within the context, extend the context - if found_diff: - lines_to_write = context-1 - else: - lines_to_write -= 1 - yield from_line, to_line, found_diff + try: + while(lines_to_write): + from_line, to_line, found_diff = next(line_pair_iterator) + # If another change within the context, extend the context + if found_diff: + lines_to_write = context-1 + else: + lines_to_write -= 1 + yield from_line, to_line, found_diff + except StopIteration: + # Catch exception from next() and return normally + return _file_template = """ diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index aaefe6db0291..745ccbd6659e 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -93,6 +93,14 @@ def test_added_tab_hint(self): self.assertEqual("+ \t\tI am a bug", diff[2]) self.assertEqual("? +\n", diff[3]) + def test_mdiff_catch_stop_iteration(self): + # Issue #33224 + self.assertEqual( + list(difflib._mdiff(["2"], ["3"], 1)), + [((1, '\x00-2\x01'), (1, '\x00+3\x01'), True)], + ) + + patch914575_from1 = """ 1. Beautiful is beTTer than ugly. 2. Explicit is better than implicit. diff --git a/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst new file mode 100644 index 000000000000..87ff100da4b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-04-23-41-30.bpo-33224.pyR0jB.rst @@ -0,0 +1,2 @@ +Update difflib.mdiff() for PEP 479. Convert an uncaught StopIteration in a +generator into a return-statement. From lp_benchmark_robot at intel.com Thu Apr 5 20:13:23 2018 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 5 Apr 2018 17:13:23 -0700 Subject: [Python-checkins] [65 flat] Results for Python (master branch) 2018-04-05 Message-ID: Results for project python/master, build date: 2018-04-05 03:02:42-07:00. - commit: 0876505 - previous commit: c51d8c9 - revision date: 2018-04-04 19:12:39-07:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.097% | +0.234% | +8.236% | +7.794% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 1.018% | -0.052% | +24.762% | +11.822% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 1.834% | +0.301% | +26.295% | +9.054% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 1.420% | +0.255% | +23.439% | +11.135% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 1.950% | +0.446% | +10.137% | +14.431% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.634% | -0.259% | +12.713% | +10.788% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 0.740% | +0.207% | +7.423% | +9.676% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.617% | -0.089% | -1.407% | +9.845% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.654% | +0.121% | +11.499% | +17.578% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 4.396% | +0.488% | +14.729% | +15.257% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.379% | -0.051% | +5.788% | +7.057% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 0.407% | +0.264% | +6.306% | +5.535% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 1.197% | +0.241% | +2.555% | +8.360% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 1.473% | -0.562% | +13.908% | +11.093% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.682% | -0.164% | +9.835% | +11.999% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 7.852% | +0.239% | +3.964% | +12.699% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.554% | +0.272% | +11.436% | +12.408% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 2.542% | +0.163% | +12.656% | +10.070% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 1.342% | +0.554% | +1.980% | +10.390% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 5.262% | -1.380% | -3.715% | +16.005% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.605% | +0.096% | +18.678% | +12.155% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 2.898% | -0.089% | +47.372% | +14.510% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.631% | +0.505% | +13.908% | +11.893% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.650% | +0.087% | +17.360% | +14.796% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 1.374% | +0.336% | +9.395% | +10.102% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 2.056% | +0.215% | +5.665% | +4.631% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 0.516% | -0.012% | +0.253% | +0.308% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.711% | -0.152% | +5.812% | +7.950% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.684% | -0.027% | +1.560% | +10.856% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 1.141% | -0.053% | +1.678% | +18.952% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.647% | -0.087% | +2.824% | +15.822% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 0.736% | +0.593% | +3.435% | +18.389% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 5.793% | -1.099% | +11.393% | +12.046% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.084% | +0.010% | +0.197% | +10.191% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.127% | +0.146% | +18.201% | +5.161% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.088% | +0.055% | +5.161% | +5.365% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 0.976% | +0.262% | +10.743% | +12.911% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 5.109% | -0.521% | +5.702% | +12.083% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_dna| 0.445% | -0.064% | -2.004% | +11.015% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 2.009% | +0.236% | -6.044% | +6.650% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_v8| 0.975% | +0.426% | +3.986% | +6.912% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.349% | -0.114% | +10.346% | +15.834% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 1.669% | +0.108% | -2.518% | +5.440% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 2.927% | +1.152% | +24.218% | +10.875% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 3.183% | -0.168% | +4.381% | +5.465% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 1.483% | +0.537% | +14.267% | +9.709% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 0.338% | +0.163% | -6.912% | +5.542% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.724% | -0.287% | +2.614% | +7.520% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 1.319% | +0.110% | +6.833% | +7.557% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 3.046% | -0.297% | +8.503% | +4.557% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 3.269% | +1.147% | +0.953% | +8.828% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 2.602% | +0.750% | +18.043% | +7.416% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.428% | -0.055% | +13.135% | +6.812% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 3.746% | +0.455% | +17.822% | +8.872% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 6.132% | -0.393% | +16.067% | +11.827% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 5.175% | +0.263% | +20.229% | +8.669% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 0.804% | +0.150% | +8.040% | +4.970% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 1.151% | -0.188% | +2.125% | +0.513% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 7.283% | -2.142% | +7.600% | +23.335% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 0.740% | +0.925% | -1.404% | +16.206% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 2.273% | +0.020% | +8.228% | +7.847% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 1.448% | +0.449% | +5.005% | +10.889% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 2.454% | +0.143% | +3.822% | +8.248% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 2.983% | +0.329% | -6.001% | +9.651% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 1.966% | -0.401% | +5.887% | +10.973% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/65-flat-results-for-python-master-branch-2018-04-05 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Fri Apr 6 02:51:30 2018 From: webhook-mailer at python.org (INADA Naoki) Date: Fri, 06 Apr 2018 06:51:30 -0000 Subject: [Python-checkins] bpo-33231: Fix potential leak in normalizestring() (GH-6386) Message-ID: https://github.com/python/cpython/commit/0c1c4563a65ac451021d927058e4f25013934eb2 commit: 0c1c4563a65ac451021d927058e4f25013934eb2 branch: master author: INADA Naoki committer: GitHub date: 2018-04-06T15:51:24+09:00 summary: bpo-33231: Fix potential leak in normalizestring() (GH-6386) files: A Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst M Python/codecs.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst new file mode 100644 index 000000000000..de54fbb52671 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst @@ -0,0 +1 @@ +Fix potential memory leak in ``normalizestring()``. diff --git a/Python/codecs.c b/Python/codecs.c index 223ccca603fc..eb3cd35fb8e2 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -78,8 +78,6 @@ PyObject *normalizestring(const char *string) } p[i] = '\0'; v = PyUnicode_FromString(p); - if (v == NULL) - return NULL; PyMem_Free(p); return v; } From webhook-mailer at python.org Fri Apr 6 03:12:41 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Fri, 06 Apr 2018 07:12:41 -0000 Subject: [Python-checkins] bpo-33231: Fix potential leak in normalizestring() (GH-6386) Message-ID: https://github.com/python/cpython/commit/64421d9237e33725e3c2916cdf2b6d6da1751c2a commit: 64421d9237e33725e3c2916cdf2b6d6da1751c2a branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-06T00:12:38-07:00 summary: bpo-33231: Fix potential leak in normalizestring() (GH-6386) (cherry picked from commit 0c1c4563a65ac451021d927058e4f25013934eb2) Co-authored-by: INADA Naoki files: A Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst M Python/codecs.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst new file mode 100644 index 000000000000..de54fbb52671 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst @@ -0,0 +1 @@ +Fix potential memory leak in ``normalizestring()``. diff --git a/Python/codecs.c b/Python/codecs.c index 223ccca603fc..eb3cd35fb8e2 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -78,8 +78,6 @@ PyObject *normalizestring(const char *string) } p[i] = '\0'; v = PyUnicode_FromString(p); - if (v == NULL) - return NULL; PyMem_Free(p); return v; } From webhook-mailer at python.org Fri Apr 6 03:37:07 2018 From: webhook-mailer at python.org (Miss Islington (bot)) Date: Fri, 06 Apr 2018 07:37:07 -0000 Subject: [Python-checkins] bpo-33231: Fix potential leak in normalizestring() (GH-6386) Message-ID: https://github.com/python/cpython/commit/2350a4765265158072bf7ad9f04402406d3d1ada commit: 2350a4765265158072bf7ad9f04402406d3d1ada branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: GitHub date: 2018-04-06T00:37:03-07:00 summary: bpo-33231: Fix potential leak in normalizestring() (GH-6386) (cherry picked from commit 0c1c4563a65ac451021d927058e4f25013934eb2) Co-authored-by: INADA Naoki files: A Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst M Python/codecs.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst new file mode 100644 index 000000000000..de54fbb52671 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-05-22-20-44.bpo-33231.3Jmo0q.rst @@ -0,0 +1 @@ +Fix potential memory leak in ``normalizestring()``. diff --git a/Python/codecs.c b/Python/codecs.c index fe57d0dc42d4..4ff83014d8bc 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -77,8 +77,6 @@ PyObject *normalizestring(const char *string) } p[i] = '\0'; v = PyUnicode_FromString(p); - if (v == NULL) - return NULL; PyMem_Free(p); return v; } From solipsis at pitrou.net Fri Apr 6 05:12:13 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 06 Apr 2018 09:12:13 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=4 Message-ID: <20180406091213.1.E138013098386014@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [7, 0, -7] memory blocks, sum=0 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_forkserver leaked [-2, 0, 2] memory blocks, sum=0 test_multiprocessing_spawn leaked [0, -2, 2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogMaRXc7', '--timeout', '7200'] From webhook-mailer at python.org Fri Apr 6 08:26:52 2018 From: webhook-mailer at python.org (Alex Gaynor) Date: Fri, 06 Apr 2018 12:26:52 -0000 Subject: [Python-checkins] fixed capitalization of class name (GH-6396) Message-ID: https://github.com/python/cpython/commit/1d87c7b80bf74a3030034a022a7a54ea4e3cdaff commit: 1d87c7b80bf74a3030034a022a7a54ea4e3cdaff branch: master author: Alex Gaynor committer: GitHub date: 2018-04-06T08:26:49-04:00 summary: fixed capitalization of class name (GH-6396) files: M Doc/library/http.server.rst diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 278ae5537504..16cfa1798aef 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -36,7 +36,7 @@ handler. Code to create and run the server looks like this:: .. class:: ThreadedHTTPServer(server_address, RequestHandlerClass) This class is identical to HTTPServer but uses threads to handle - requests by using the :class:`~socketserver.ThreadingMixin`. This + requests by using the :class:`~socketserver.ThreadingMixIn`. This is useful to handle web browsers pre-opening sockets, on which :class:`HTTPServer` would wait indefinitely. From webhook-mailer at python.org Fri Apr 6 08:46:09 2018 From: webhook-mailer at python.org (Alex Gaynor) Date: Fri, 06 Apr 2018 12:46:09 -0000 Subject: [Python-checkins] fixed capitalization of class name (GH-6396) (GH-6397) Message-ID: https://github.com/python/cpython/commit/252f10cbac0132924faed8de44ed7b15e774cbcb commit: 252f10cbac0132924faed8de44ed7b15e774cbcb branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Alex Gaynor date: 2018-04-06T08:46:05-04:00 summary: fixed capitalization of class name (GH-6396) (GH-6397) (cherry picked from commit 1d87c7b80bf74a3030034a022a7a54ea4e3cdaff) Co-authored-by: Alex Gaynor files: M Doc/library/http.server.rst diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 278ae5537504..16cfa1798aef 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -36,7 +36,7 @@ handler. Code to create and run the server looks like this:: .. class:: ThreadedHTTPServer(server_address, RequestHandlerClass) This class is identical to HTTPServer but uses threads to handle - requests by using the :class:`~socketserver.ThreadingMixin`. This + requests by using the :class:`~socketserver.ThreadingMixIn`. This is useful to handle web browsers pre-opening sockets, on which :class:`HTTPServer` would wait indefinitely. From webhook-mailer at python.org Fri Apr 6 17:22:14 2018 From: webhook-mailer at python.org (Ned Deily) Date: Fri, 06 Apr 2018 21:22:14 -0000 Subject: [Python-checkins] bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) Message-ID: https://github.com/python/cpython/commit/3a9ccee0e5dbf7d67f5ab79f6095755969db117c commit: 3a9ccee0e5dbf7d67f5ab79f6095755969db117c branch: master author: Marcel Plch committer: Ned Deily date: 2018-04-06T17:22:04-04:00 summary: bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) files: A Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst M Misc/ACKS M Misc/gdbinit M Python/ceval.c diff --git a/Misc/ACKS b/Misc/ACKS index f7ac37ea7ac8..b951446bab7b 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1250,6 +1250,7 @@ Zero Piraeus Antoine Pitrou Jean-Fran?ois Pi?ronne Oleg Plakhotnyuk +Marcel Plch Remi Pointel Jon Poler Ariel Poliak diff --git a/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst new file mode 100644 index 000000000000..3d515b3ee4db --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst @@ -0,0 +1 @@ +Fix pystackv and pystack gdbinit macros. diff --git a/Misc/gdbinit b/Misc/gdbinit index 9f216215eac2..afefe0818e4c 100644 --- a/Misc/gdbinit +++ b/Misc/gdbinit @@ -42,8 +42,8 @@ define pylocals set $_i = 0 while $_i < f->f_code->co_nlocals if f->f_localsplus + $_i != 0 - set $_names = co->co_varnames - set $_name = _PyUnicode_AsString(PyTuple_GetItem($_names, $_i)) + set $_names = f->f_code->co_varnames + set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) printf "%s:\n", $_name pyo f->f_localsplus[$_i] end @@ -84,8 +84,8 @@ define pyframev end define pyframe - set $__fn = _PyUnicode_AsString(co->co_filename) - set $__n = _PyUnicode_AsString(co->co_name) + set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) + set $__n = PyUnicode_AsUTF8(f->f_code->co_name) printf "%s (", $__fn lineno printf "): %s\n", $__n @@ -110,7 +110,7 @@ end #end define printframe - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe else frame @@ -139,7 +139,7 @@ document pystack end define pystack while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe end up-silently 1 @@ -152,7 +152,7 @@ document pystackv end define pystackv while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframev end up-silently 1 diff --git a/Python/ceval.c b/Python/ceval.c index da83e41f5ddd..422a29ed77d6 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3661,7 +3661,7 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount, } /* This is gonna seem *real weird*, but if you put some other code between - PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust + PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject * From webhook-mailer at python.org Fri Apr 6 18:14:32 2018 From: webhook-mailer at python.org (Ned Deily) Date: Fri, 06 Apr 2018 22:14:32 -0000 Subject: [Python-checkins] [3.7] bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) (GH-6399) Message-ID: https://github.com/python/cpython/commit/3c193cf8afce525b1283986f113de0e16f23e115 commit: 3c193cf8afce525b1283986f113de0e16f23e115 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-06T18:14:29-04:00 summary: [3.7] bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) (GH-6399) (cherry picked from commit 3a9ccee0e5dbf7d67f5ab79f6095755969db117c) Co-authored-by: Marcel Plch files: A Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst M Misc/ACKS M Misc/gdbinit M Python/ceval.c diff --git a/Misc/ACKS b/Misc/ACKS index c70f62efcf5f..554307a51aad 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1248,6 +1248,7 @@ Zero Piraeus Antoine Pitrou Jean-Fran?ois Pi?ronne Oleg Plakhotnyuk +Marcel Plch Remi Pointel Jon Poler Ariel Poliak diff --git a/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst new file mode 100644 index 000000000000..3d515b3ee4db --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst @@ -0,0 +1 @@ +Fix pystackv and pystack gdbinit macros. diff --git a/Misc/gdbinit b/Misc/gdbinit index 3b6fe50ef931..bb10bdba799a 100644 --- a/Misc/gdbinit +++ b/Misc/gdbinit @@ -36,8 +36,8 @@ define pylocals set $_i = 0 while $_i < f->f_code->co_nlocals if f->f_localsplus + $_i != 0 - set $_names = co->co_varnames - set $_name = _PyUnicode_AsString(PyTuple_GetItem($_names, $_i)) + set $_names = f->f_code->co_varnames + set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) printf "%s:\n", $_name pyo f->f_localsplus[$_i] end @@ -76,8 +76,8 @@ define pyframev end define pyframe - set $__fn = _PyUnicode_AsString(co->co_filename) - set $__n = _PyUnicode_AsString(co->co_name) + set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) + set $__n = PyUnicode_AsUTF8(f->f_code->co_name) printf "%s (", $__fn lineno printf "): %s\n", $__n @@ -102,7 +102,7 @@ end #end define printframe - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe else frame @@ -129,7 +129,7 @@ end # print the entire Python call stack define pystack while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe end up-silently 1 @@ -140,7 +140,7 @@ end # print the entire Python call stack - verbose mode define pystackv while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframev end up-silently 1 diff --git a/Python/ceval.c b/Python/ceval.c index b37205e50a61..df5c0932f417 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3650,7 +3650,7 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount, } /* This is gonna seem *real weird*, but if you put some other code between - PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust + PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject * From webhook-mailer at python.org Fri Apr 6 18:15:37 2018 From: webhook-mailer at python.org (Ned Deily) Date: Fri, 06 Apr 2018 22:15:37 -0000 Subject: [Python-checkins] [3.6] bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) (GH-6400) Message-ID: https://github.com/python/cpython/commit/3468a05f6a7d730a656d254730a3f5b6b7e85983 commit: 3468a05f6a7d730a656d254730a3f5b6b7e85983 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-06T18:15:34-04:00 summary: [3.6] bpo-29673: fix gdb scripts pystack and pystackv (GH-6126) (GH-6400) (cherry picked from commit 3a9ccee0e5dbf7d67f5ab79f6095755969db117c) Co-authored-by: Marcel Plch files: A Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst M Misc/ACKS M Misc/gdbinit M Python/ceval.c diff --git a/Misc/ACKS b/Misc/ACKS index ca8eaefc5b46..7eaee80727dc 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1221,6 +1221,7 @@ Zero Piraeus Antoine Pitrou Jean-Fran?ois Pi?ronne Oleg Plakhotnyuk +Marcel Plch Remi Pointel Jon Poler Ariel Poliak diff --git a/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst new file mode 100644 index 000000000000..3d515b3ee4db --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2018-03-16-17-25-05.bpo-29673.m8QtaW.rst @@ -0,0 +1 @@ +Fix pystackv and pystack gdbinit macros. diff --git a/Misc/gdbinit b/Misc/gdbinit index 3b6fe50ef931..bb10bdba799a 100644 --- a/Misc/gdbinit +++ b/Misc/gdbinit @@ -36,8 +36,8 @@ define pylocals set $_i = 0 while $_i < f->f_code->co_nlocals if f->f_localsplus + $_i != 0 - set $_names = co->co_varnames - set $_name = _PyUnicode_AsString(PyTuple_GetItem($_names, $_i)) + set $_names = f->f_code->co_varnames + set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) printf "%s:\n", $_name pyo f->f_localsplus[$_i] end @@ -76,8 +76,8 @@ define pyframev end define pyframe - set $__fn = _PyUnicode_AsString(co->co_filename) - set $__n = _PyUnicode_AsString(co->co_name) + set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) + set $__n = PyUnicode_AsUTF8(f->f_code->co_name) printf "%s (", $__fn lineno printf "): %s\n", $__n @@ -102,7 +102,7 @@ end #end define printframe - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe else frame @@ -129,7 +129,7 @@ end # print the entire Python call stack define pystack while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframe end up-silently 1 @@ -140,7 +140,7 @@ end # print the entire Python call stack - verbose mode define pystackv while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault pyframev end up-silently 1 diff --git a/Python/ceval.c b/Python/ceval.c index 6252e89c9106..646f6a5bea9c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3888,7 +3888,7 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount, } /* This is gonna seem *real weird*, but if you put some other code between - PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust + PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ static PyObject * From webhook-mailer at python.org Fri Apr 6 19:10:23 2018 From: webhook-mailer at python.org (Brett Cannon) Date: Fri, 06 Apr 2018 23:10:23 -0000 Subject: [Python-checkins] bpo-33169: Remove values of `None` from sys.path_importer_cache when invalidating caches (GH-6402) Message-ID: https://github.com/python/cpython/commit/9e2be60634914f23db2ae5624e4acc9335bf5fea commit: 9e2be60634914f23db2ae5624e4acc9335bf5fea branch: master author: Brett Cannon committer: GitHub date: 2018-04-06T16:10:18-07:00 summary: bpo-33169: Remove values of `None` from sys.path_importer_cache when invalidating caches (GH-6402) An entry of None in sys.path_importer_cache represents a negative/missing finder for a path, so clearing it out makes sense. files: A Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst M Doc/library/importlib.rst M Lib/importlib/_bootstrap_external.py M Lib/test/test_importlib/import_/test_path.py M Lib/test/test_importlib/test_api.py M Python/importlib_external.h diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index f9387c07e18c..130aabf119a6 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1081,7 +1081,12 @@ find and load modules. .. classmethod:: invalidate_caches() Calls :meth:`importlib.abc.PathEntryFinder.invalidate_caches` on all - finders stored in :attr:`sys.path_importer_cache`. + finders stored in :data:`sys.path_importer_cache` that define the method. + Otherwise entries in :data:`sys.path_importer_cache` set to ``None`` are + deleted. + + .. versionchanged:: 3.7 + Entries of ``None`` in :data:`sys.path_importer_cache` are deleted. .. versionchanged:: 3.4 Calls objects in :data:`sys.path_hooks` with the current working diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 420ecc83439a..da9a75c673bc 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -1181,8 +1181,10 @@ class PathFinder: def invalidate_caches(cls): """Call the invalidate_caches() method on all path entry finders stored in sys.path_importer_caches (where implemented).""" - for finder in sys.path_importer_cache.values(): - if hasattr(finder, 'invalidate_caches'): + for name, finder in list(sys.path_importer_cache.items()): + if finder is None: + del sys.path_importer_cache[name] + elif hasattr(finder, 'invalidate_caches'): finder.invalidate_caches() @classmethod diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py index 7aa26b0eee74..18c81dda45c8 100644 --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -184,6 +184,27 @@ def test_deleted_cwd(self): # Do not want FileNotFoundError raised. self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) + def test_invalidate_caches_finders(self): + # Finders with an invalidate_caches() method have it called. + class FakeFinder: + def __init__(self): + self.called = False + + def invalidate_caches(self): + self.called = True + + cache = {'leave_alone': object(), 'finder_to_invalidate': FakeFinder()} + with util.import_state(path_importer_cache=cache): + self.machinery.PathFinder.invalidate_caches() + self.assertTrue(cache['finder_to_invalidate'].called) + + def test_invalidate_caches_clear_out_None(self): + # Clear out None in sys.path_importer_cache() when invalidating caches. + cache = {'clear_out': None} + with util.import_state(path_importer_cache=cache): + self.machinery.PathFinder.invalidate_caches() + self.assertEqual(len(cache), 0) + class FindModuleTests(FinderTests): def find(self, *args, **kwargs): diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 8beb4244eac8..edb745c2cd49 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -406,7 +406,7 @@ def test_method_lacking(self): # There should be no issues if the method is not defined. key = 'gobbledeegook' sys.path_importer_cache[key] = None - self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key)) + self.addCleanup(lambda: sys.path_importer_cache.pop(key, None)) self.init.invalidate_caches() # Shouldn't trigger an exception. diff --git a/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst b/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst new file mode 100644 index 000000000000..b5bacfcb5732 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst @@ -0,0 +1,2 @@ +Delete entries of ``None`` in :data:`sys.path_importer_cache` when +:meth:`importlib.machinery.invalidate_caches` is called. diff --git a/Python/importlib_external.h b/Python/importlib_external.h index 220f7147443e..930755da21e1 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -1989,623 +1989,625 @@ const unsigned char _Py_M__importlib_external[] = { 100,101,114,32,102,111,114,32,115,121,115,46,112,97,116,104, 32,97,110,100,32,112,97,99,107,97,103,101,32,95,95,112, 97,116,104,95,95,32,97,116,116,114,105,98,117,116,101,115, - 46,99,1,0,0,0,0,0,0,0,2,0,0,0,4,0, - 0,0,67,0,0,0,115,38,0,0,0,116,0,106,1,160, - 2,161,0,68,0,93,22,125,1,116,3,124,1,100,1,131, - 2,114,10,124,1,160,4,161,0,1,0,113,10,100,2,83, - 0,41,3,122,125,67,97,108,108,32,116,104,101,32,105,110, - 118,97,108,105,100,97,116,101,95,99,97,99,104,101,115,40, - 41,32,109,101,116,104,111,100,32,111,110,32,97,108,108,32, - 112,97,116,104,32,101,110,116,114,121,32,102,105,110,100,101, - 114,115,10,32,32,32,32,32,32,32,32,115,116,111,114,101, - 100,32,105,110,32,115,121,115,46,112,97,116,104,95,105,109, - 112,111,114,116,101,114,95,99,97,99,104,101,115,32,40,119, - 104,101,114,101,32,105,109,112,108,101,109,101,110,116,101,100, - 41,46,218,17,105,110,118,97,108,105,100,97,116,101,95,99, - 97,99,104,101,115,78,41,5,114,6,0,0,0,218,19,112, + 46,99,1,0,0,0,0,0,0,0,3,0,0,0,4,0, + 0,0,67,0,0,0,115,64,0,0,0,116,0,116,1,106, + 2,160,3,161,0,131,1,68,0,93,44,92,2,125,1,125, + 2,124,2,100,1,107,8,114,40,116,1,106,2,124,1,61, + 0,113,14,116,4,124,2,100,2,131,2,114,14,124,2,160, + 5,161,0,1,0,113,14,100,1,83,0,41,3,122,125,67, + 97,108,108,32,116,104,101,32,105,110,118,97,108,105,100,97, + 116,101,95,99,97,99,104,101,115,40,41,32,109,101,116,104, + 111,100,32,111,110,32,97,108,108,32,112,97,116,104,32,101, + 110,116,114,121,32,102,105,110,100,101,114,115,10,32,32,32, + 32,32,32,32,32,115,116,111,114,101,100,32,105,110,32,115, + 121,115,46,112,97,116,104,95,105,109,112,111,114,116,101,114, + 95,99,97,99,104,101,115,32,40,119,104,101,114,101,32,105, + 109,112,108,101,109,101,110,116,101,100,41,46,78,218,17,105, + 110,118,97,108,105,100,97,116,101,95,99,97,99,104,101,115, + 41,6,218,4,108,105,115,116,114,6,0,0,0,218,19,112, 97,116,104,95,105,109,112,111,114,116,101,114,95,99,97,99, - 104,101,218,6,118,97,108,117,101,115,114,110,0,0,0,114, - 6,1,0,0,41,2,114,172,0,0,0,218,6,102,105,110, - 100,101,114,114,2,0,0,0,114,2,0,0,0,114,4,0, - 0,0,114,6,1,0,0,156,4,0,0,115,6,0,0,0, - 0,4,14,1,10,1,122,28,80,97,116,104,70,105,110,100, - 101,114,46,105,110,118,97,108,105,100,97,116,101,95,99,97, - 99,104,101,115,99,2,0,0,0,0,0,0,0,3,0,0, - 0,9,0,0,0,67,0,0,0,115,84,0,0,0,116,0, - 106,1,100,1,107,9,114,28,116,0,106,1,115,28,116,2, - 160,3,100,2,116,4,161,2,1,0,116,0,106,1,68,0, - 93,44,125,2,122,14,124,2,124,1,131,1,87,0,2,0, - 1,0,83,0,4,0,116,5,107,10,114,76,1,0,1,0, - 1,0,89,0,113,34,89,0,113,34,88,0,113,34,100,1, - 83,0,41,3,122,46,83,101,97,114,99,104,32,115,121,115, - 46,112,97,116,104,95,104,111,111,107,115,32,102,111,114,32, - 97,32,102,105,110,100,101,114,32,102,111,114,32,39,112,97, - 116,104,39,46,78,122,23,115,121,115,46,112,97,116,104,95, - 104,111,111,107,115,32,105,115,32,101,109,112,116,121,41,6, - 114,6,0,0,0,218,10,112,97,116,104,95,104,111,111,107, - 115,114,61,0,0,0,114,62,0,0,0,114,120,0,0,0, - 114,101,0,0,0,41,3,114,172,0,0,0,114,35,0,0, - 0,90,4,104,111,111,107,114,2,0,0,0,114,2,0,0, - 0,114,4,0,0,0,218,11,95,112,97,116,104,95,104,111, - 111,107,115,164,4,0,0,115,16,0,0,0,0,3,16,1, - 12,1,10,1,2,1,14,1,14,1,12,2,122,22,80,97, - 116,104,70,105,110,100,101,114,46,95,112,97,116,104,95,104, - 111,111,107,115,99,2,0,0,0,0,0,0,0,3,0,0, - 0,8,0,0,0,67,0,0,0,115,104,0,0,0,124,1, - 100,1,107,2,114,44,122,12,116,0,160,1,161,0,125,1, - 87,0,110,22,4,0,116,2,107,10,114,42,1,0,1,0, - 1,0,89,0,100,2,83,0,88,0,122,14,116,3,106,4, - 124,1,25,0,125,2,87,0,110,40,4,0,116,5,107,10, - 114,98,1,0,1,0,1,0,124,0,160,6,124,1,161,1, - 125,2,124,2,116,3,106,4,124,1,60,0,89,0,110,2, - 88,0,124,2,83,0,41,3,122,210,71,101,116,32,116,104, - 101,32,102,105,110,100,101,114,32,102,111,114,32,116,104,101, - 32,112,97,116,104,32,101,110,116,114,121,32,102,114,111,109, - 32,115,121,115,46,112,97,116,104,95,105,109,112,111,114,116, - 101,114,95,99,97,99,104,101,46,10,10,32,32,32,32,32, - 32,32,32,73,102,32,116,104,101,32,112,97,116,104,32,101, - 110,116,114,121,32,105,115,32,110,111,116,32,105,110,32,116, - 104,101,32,99,97,99,104,101,44,32,102,105,110,100,32,116, - 104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,102, - 105,110,100,101,114,10,32,32,32,32,32,32,32,32,97,110, - 100,32,99,97,99,104,101,32,105,116,46,32,73,102,32,110, - 111,32,102,105,110,100,101,114,32,105,115,32,97,118,97,105, - 108,97,98,108,101,44,32,115,116,111,114,101,32,78,111,110, - 101,46,10,10,32,32,32,32,32,32,32,32,114,30,0,0, - 0,78,41,7,114,1,0,0,0,114,45,0,0,0,114,224, - 0,0,0,114,6,0,0,0,114,7,1,0,0,218,8,75, - 101,121,69,114,114,111,114,114,11,1,0,0,41,3,114,172, - 0,0,0,114,35,0,0,0,114,9,1,0,0,114,2,0, - 0,0,114,2,0,0,0,114,4,0,0,0,218,20,95,112, - 97,116,104,95,105,109,112,111,114,116,101,114,95,99,97,99, - 104,101,177,4,0,0,115,22,0,0,0,0,8,8,1,2, - 1,12,1,14,3,8,1,2,1,14,1,14,1,10,1,16, - 1,122,31,80,97,116,104,70,105,110,100,101,114,46,95,112, + 104,101,218,5,105,116,101,109,115,114,110,0,0,0,114,6, + 1,0,0,41,3,114,172,0,0,0,114,100,0,0,0,218, + 6,102,105,110,100,101,114,114,2,0,0,0,114,2,0,0, + 0,114,4,0,0,0,114,6,1,0,0,156,4,0,0,115, + 10,0,0,0,0,4,22,1,8,1,10,1,10,1,122,28, + 80,97,116,104,70,105,110,100,101,114,46,105,110,118,97,108, + 105,100,97,116,101,95,99,97,99,104,101,115,99,2,0,0, + 0,0,0,0,0,3,0,0,0,9,0,0,0,67,0,0, + 0,115,84,0,0,0,116,0,106,1,100,1,107,9,114,28, + 116,0,106,1,115,28,116,2,160,3,100,2,116,4,161,2, + 1,0,116,0,106,1,68,0,93,44,125,2,122,14,124,2, + 124,1,131,1,87,0,2,0,1,0,83,0,4,0,116,5, + 107,10,114,76,1,0,1,0,1,0,89,0,113,34,89,0, + 113,34,88,0,113,34,100,1,83,0,41,3,122,46,83,101, + 97,114,99,104,32,115,121,115,46,112,97,116,104,95,104,111, + 111,107,115,32,102,111,114,32,97,32,102,105,110,100,101,114, + 32,102,111,114,32,39,112,97,116,104,39,46,78,122,23,115, + 121,115,46,112,97,116,104,95,104,111,111,107,115,32,105,115, + 32,101,109,112,116,121,41,6,114,6,0,0,0,218,10,112, + 97,116,104,95,104,111,111,107,115,114,61,0,0,0,114,62, + 0,0,0,114,120,0,0,0,114,101,0,0,0,41,3,114, + 172,0,0,0,114,35,0,0,0,90,4,104,111,111,107,114, + 2,0,0,0,114,2,0,0,0,114,4,0,0,0,218,11, + 95,112,97,116,104,95,104,111,111,107,115,166,4,0,0,115, + 16,0,0,0,0,3,16,1,12,1,10,1,2,1,14,1, + 14,1,12,2,122,22,80,97,116,104,70,105,110,100,101,114, + 46,95,112,97,116,104,95,104,111,111,107,115,99,2,0,0, + 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0, + 0,115,104,0,0,0,124,1,100,1,107,2,114,44,122,12, + 116,0,160,1,161,0,125,1,87,0,110,22,4,0,116,2, + 107,10,114,42,1,0,1,0,1,0,89,0,100,2,83,0, + 88,0,122,14,116,3,106,4,124,1,25,0,125,2,87,0, + 110,40,4,0,116,5,107,10,114,98,1,0,1,0,1,0, + 124,0,160,6,124,1,161,1,125,2,124,2,116,3,106,4, + 124,1,60,0,89,0,110,2,88,0,124,2,83,0,41,3, + 122,210,71,101,116,32,116,104,101,32,102,105,110,100,101,114, + 32,102,111,114,32,116,104,101,32,112,97,116,104,32,101,110, + 116,114,121,32,102,114,111,109,32,115,121,115,46,112,97,116, + 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, + 46,10,10,32,32,32,32,32,32,32,32,73,102,32,116,104, + 101,32,112,97,116,104,32,101,110,116,114,121,32,105,115,32, + 110,111,116,32,105,110,32,116,104,101,32,99,97,99,104,101, + 44,32,102,105,110,100,32,116,104,101,32,97,112,112,114,111, + 112,114,105,97,116,101,32,102,105,110,100,101,114,10,32,32, + 32,32,32,32,32,32,97,110,100,32,99,97,99,104,101,32, + 105,116,46,32,73,102,32,110,111,32,102,105,110,100,101,114, + 32,105,115,32,97,118,97,105,108,97,98,108,101,44,32,115, + 116,111,114,101,32,78,111,110,101,46,10,10,32,32,32,32, + 32,32,32,32,114,30,0,0,0,78,41,7,114,1,0,0, + 0,114,45,0,0,0,114,224,0,0,0,114,6,0,0,0, + 114,8,1,0,0,218,8,75,101,121,69,114,114,111,114,114, + 12,1,0,0,41,3,114,172,0,0,0,114,35,0,0,0, + 114,10,1,0,0,114,2,0,0,0,114,2,0,0,0,114, + 4,0,0,0,218,20,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,179,4,0,0,115,22, + 0,0,0,0,8,8,1,2,1,12,1,14,3,8,1,2, + 1,14,1,14,1,10,1,16,1,122,31,80,97,116,104,70, + 105,110,100,101,114,46,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,99,3,0,0,0,0, + 0,0,0,6,0,0,0,4,0,0,0,67,0,0,0,115, + 82,0,0,0,116,0,124,2,100,1,131,2,114,26,124,2, + 160,1,124,1,161,1,92,2,125,3,125,4,110,14,124,2, + 160,2,124,1,161,1,125,3,103,0,125,4,124,3,100,0, + 107,9,114,60,116,3,160,4,124,1,124,3,161,2,83,0, + 116,3,160,5,124,1,100,0,161,2,125,5,124,4,124,5, + 95,6,124,5,83,0,41,2,78,114,119,0,0,0,41,7, + 114,110,0,0,0,114,119,0,0,0,114,183,0,0,0,114, + 116,0,0,0,114,180,0,0,0,114,162,0,0,0,114,158, + 0,0,0,41,6,114,172,0,0,0,114,121,0,0,0,114, + 10,1,0,0,114,122,0,0,0,114,123,0,0,0,114,166, + 0,0,0,114,2,0,0,0,114,2,0,0,0,114,4,0, + 0,0,218,16,95,108,101,103,97,99,121,95,103,101,116,95, + 115,112,101,99,201,4,0,0,115,18,0,0,0,0,4,10, + 1,16,2,10,1,4,1,8,1,12,1,12,1,6,1,122, + 27,80,97,116,104,70,105,110,100,101,114,46,95,108,101,103, + 97,99,121,95,103,101,116,95,115,112,101,99,78,99,4,0, + 0,0,0,0,0,0,9,0,0,0,5,0,0,0,67,0, + 0,0,115,166,0,0,0,103,0,125,4,124,2,68,0,93, + 134,125,5,116,0,124,5,116,1,116,2,102,2,131,2,115, + 28,113,8,124,0,160,3,124,5,161,1,125,6,124,6,100, + 1,107,9,114,8,116,4,124,6,100,2,131,2,114,70,124, + 6,160,5,124,1,124,3,161,2,125,7,110,12,124,0,160, + 6,124,1,124,6,161,2,125,7,124,7,100,1,107,8,114, + 92,113,8,124,7,106,7,100,1,107,9,114,110,124,7,2, + 0,1,0,83,0,124,7,106,8,125,8,124,8,100,1,107, + 8,114,132,116,9,100,3,131,1,130,1,124,4,160,10,124, + 8,161,1,1,0,113,8,116,11,160,12,124,1,100,1,161, + 2,125,7,124,4,124,7,95,8,124,7,83,0,41,4,122, + 63,70,105,110,100,32,116,104,101,32,108,111,97,100,101,114, + 32,111,114,32,110,97,109,101,115,112,97,99,101,95,112,97, + 116,104,32,102,111,114,32,116,104,105,115,32,109,111,100,117, + 108,101,47,112,97,99,107,97,103,101,32,110,97,109,101,46, + 78,114,182,0,0,0,122,19,115,112,101,99,32,109,105,115, + 115,105,110,103,32,108,111,97,100,101,114,41,13,114,141,0, + 0,0,114,71,0,0,0,218,5,98,121,116,101,115,114,14, + 1,0,0,114,110,0,0,0,114,182,0,0,0,114,15,1, + 0,0,114,122,0,0,0,114,158,0,0,0,114,101,0,0, + 0,114,147,0,0,0,114,116,0,0,0,114,162,0,0,0, + 41,9,114,172,0,0,0,114,121,0,0,0,114,35,0,0, + 0,114,181,0,0,0,218,14,110,97,109,101,115,112,97,99, + 101,95,112,97,116,104,90,5,101,110,116,114,121,114,10,1, + 0,0,114,166,0,0,0,114,123,0,0,0,114,2,0,0, + 0,114,2,0,0,0,114,4,0,0,0,218,9,95,103,101, + 116,95,115,112,101,99,216,4,0,0,115,40,0,0,0,0, + 5,4,1,8,1,14,1,2,1,10,1,8,1,10,1,14, + 2,12,1,8,1,2,1,10,1,8,1,6,1,8,1,8, + 5,12,2,12,1,6,1,122,20,80,97,116,104,70,105,110, + 100,101,114,46,95,103,101,116,95,115,112,101,99,99,4,0, + 0,0,0,0,0,0,6,0,0,0,5,0,0,0,67,0, + 0,0,115,100,0,0,0,124,2,100,1,107,8,114,14,116, + 0,106,1,125,2,124,0,160,2,124,1,124,2,124,3,161, + 3,125,4,124,4,100,1,107,8,114,40,100,1,83,0,124, + 4,106,3,100,1,107,8,114,92,124,4,106,4,125,5,124, + 5,114,86,100,1,124,4,95,5,116,6,124,1,124,5,124, + 0,106,2,131,3,124,4,95,4,124,4,83,0,100,1,83, + 0,110,4,124,4,83,0,100,1,83,0,41,2,122,141,84, + 114,121,32,116,111,32,102,105,110,100,32,97,32,115,112,101, + 99,32,102,111,114,32,39,102,117,108,108,110,97,109,101,39, + 32,111,110,32,115,121,115,46,112,97,116,104,32,111,114,32, + 39,112,97,116,104,39,46,10,10,32,32,32,32,32,32,32, + 32,84,104,101,32,115,101,97,114,99,104,32,105,115,32,98, + 97,115,101,100,32,111,110,32,115,121,115,46,112,97,116,104, + 95,104,111,111,107,115,32,97,110,100,32,115,121,115,46,112, 97,116,104,95,105,109,112,111,114,116,101,114,95,99,97,99, - 104,101,99,3,0,0,0,0,0,0,0,6,0,0,0,4, - 0,0,0,67,0,0,0,115,82,0,0,0,116,0,124,2, - 100,1,131,2,114,26,124,2,160,1,124,1,161,1,92,2, - 125,3,125,4,110,14,124,2,160,2,124,1,161,1,125,3, - 103,0,125,4,124,3,100,0,107,9,114,60,116,3,160,4, - 124,1,124,3,161,2,83,0,116,3,160,5,124,1,100,0, - 161,2,125,5,124,4,124,5,95,6,124,5,83,0,41,2, - 78,114,119,0,0,0,41,7,114,110,0,0,0,114,119,0, - 0,0,114,183,0,0,0,114,116,0,0,0,114,180,0,0, - 0,114,162,0,0,0,114,158,0,0,0,41,6,114,172,0, - 0,0,114,121,0,0,0,114,9,1,0,0,114,122,0,0, - 0,114,123,0,0,0,114,166,0,0,0,114,2,0,0,0, - 114,2,0,0,0,114,4,0,0,0,218,16,95,108,101,103, - 97,99,121,95,103,101,116,95,115,112,101,99,199,4,0,0, - 115,18,0,0,0,0,4,10,1,16,2,10,1,4,1,8, - 1,12,1,12,1,6,1,122,27,80,97,116,104,70,105,110, - 100,101,114,46,95,108,101,103,97,99,121,95,103,101,116,95, - 115,112,101,99,78,99,4,0,0,0,0,0,0,0,9,0, - 0,0,5,0,0,0,67,0,0,0,115,166,0,0,0,103, - 0,125,4,124,2,68,0,93,134,125,5,116,0,124,5,116, - 1,116,2,102,2,131,2,115,28,113,8,124,0,160,3,124, - 5,161,1,125,6,124,6,100,1,107,9,114,8,116,4,124, - 6,100,2,131,2,114,70,124,6,160,5,124,1,124,3,161, - 2,125,7,110,12,124,0,160,6,124,1,124,6,161,2,125, - 7,124,7,100,1,107,8,114,92,113,8,124,7,106,7,100, - 1,107,9,114,110,124,7,2,0,1,0,83,0,124,7,106, - 8,125,8,124,8,100,1,107,8,114,132,116,9,100,3,131, - 1,130,1,124,4,160,10,124,8,161,1,1,0,113,8,116, - 11,160,12,124,1,100,1,161,2,125,7,124,4,124,7,95, - 8,124,7,83,0,41,4,122,63,70,105,110,100,32,116,104, - 101,32,108,111,97,100,101,114,32,111,114,32,110,97,109,101, - 115,112,97,99,101,95,112,97,116,104,32,102,111,114,32,116, - 104,105,115,32,109,111,100,117,108,101,47,112,97,99,107,97, - 103,101,32,110,97,109,101,46,78,114,182,0,0,0,122,19, - 115,112,101,99,32,109,105,115,115,105,110,103,32,108,111,97, - 100,101,114,41,13,114,141,0,0,0,114,71,0,0,0,218, - 5,98,121,116,101,115,114,13,1,0,0,114,110,0,0,0, - 114,182,0,0,0,114,14,1,0,0,114,122,0,0,0,114, - 158,0,0,0,114,101,0,0,0,114,147,0,0,0,114,116, - 0,0,0,114,162,0,0,0,41,9,114,172,0,0,0,114, - 121,0,0,0,114,35,0,0,0,114,181,0,0,0,218,14, - 110,97,109,101,115,112,97,99,101,95,112,97,116,104,90,5, - 101,110,116,114,121,114,9,1,0,0,114,166,0,0,0,114, - 123,0,0,0,114,2,0,0,0,114,2,0,0,0,114,4, - 0,0,0,218,9,95,103,101,116,95,115,112,101,99,214,4, - 0,0,115,40,0,0,0,0,5,4,1,8,1,14,1,2, - 1,10,1,8,1,10,1,14,2,12,1,8,1,2,1,10, - 1,8,1,6,1,8,1,8,5,12,2,12,1,6,1,122, - 20,80,97,116,104,70,105,110,100,101,114,46,95,103,101,116, - 95,115,112,101,99,99,4,0,0,0,0,0,0,0,6,0, - 0,0,5,0,0,0,67,0,0,0,115,100,0,0,0,124, - 2,100,1,107,8,114,14,116,0,106,1,125,2,124,0,160, - 2,124,1,124,2,124,3,161,3,125,4,124,4,100,1,107, - 8,114,40,100,1,83,0,124,4,106,3,100,1,107,8,114, - 92,124,4,106,4,125,5,124,5,114,86,100,1,124,4,95, - 5,116,6,124,1,124,5,124,0,106,2,131,3,124,4,95, - 4,124,4,83,0,100,1,83,0,110,4,124,4,83,0,100, - 1,83,0,41,2,122,141,84,114,121,32,116,111,32,102,105, - 110,100,32,97,32,115,112,101,99,32,102,111,114,32,39,102, - 117,108,108,110,97,109,101,39,32,111,110,32,115,121,115,46, - 112,97,116,104,32,111,114,32,39,112,97,116,104,39,46,10, - 10,32,32,32,32,32,32,32,32,84,104,101,32,115,101,97, - 114,99,104,32,105,115,32,98,97,115,101,100,32,111,110,32, - 115,121,115,46,112,97,116,104,95,104,111,111,107,115,32,97, - 110,100,32,115,121,115,46,112,97,116,104,95,105,109,112,111, - 114,116,101,114,95,99,97,99,104,101,46,10,32,32,32,32, - 32,32,32,32,78,41,7,114,6,0,0,0,114,35,0,0, - 0,114,17,1,0,0,114,122,0,0,0,114,158,0,0,0, - 114,160,0,0,0,114,241,0,0,0,41,6,114,172,0,0, - 0,114,121,0,0,0,114,35,0,0,0,114,181,0,0,0, - 114,166,0,0,0,114,16,1,0,0,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,114,182,0,0,0,246,4, - 0,0,115,26,0,0,0,0,6,8,1,6,1,14,1,8, - 1,4,1,10,1,6,1,4,3,6,1,16,1,4,2,6, - 2,122,20,80,97,116,104,70,105,110,100,101,114,46,102,105, - 110,100,95,115,112,101,99,99,3,0,0,0,0,0,0,0, - 4,0,0,0,4,0,0,0,67,0,0,0,115,30,0,0, - 0,124,0,160,0,124,1,124,2,161,2,125,3,124,3,100, - 1,107,8,114,24,100,1,83,0,124,3,106,1,83,0,41, - 2,122,170,102,105,110,100,32,116,104,101,32,109,111,100,117, - 108,101,32,111,110,32,115,121,115,46,112,97,116,104,32,111, - 114,32,39,112,97,116,104,39,32,98,97,115,101,100,32,111, - 110,32,115,121,115,46,112,97,116,104,95,104,111,111,107,115, - 32,97,110,100,10,32,32,32,32,32,32,32,32,115,121,115, - 46,112,97,116,104,95,105,109,112,111,114,116,101,114,95,99, - 97,99,104,101,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,102, - 105,110,100,95,115,112,101,99,40,41,32,105,110,115,116,101, - 97,100,46,10,10,32,32,32,32,32,32,32,32,78,41,2, - 114,182,0,0,0,114,122,0,0,0,41,4,114,172,0,0, - 0,114,121,0,0,0,114,35,0,0,0,114,166,0,0,0, - 114,2,0,0,0,114,2,0,0,0,114,4,0,0,0,114, - 183,0,0,0,14,5,0,0,115,8,0,0,0,0,8,12, - 1,8,1,4,1,122,22,80,97,116,104,70,105,110,100,101, - 114,46,102,105,110,100,95,109,111,100,117,108,101,41,1,78, - 41,2,78,78,41,1,78,41,12,114,107,0,0,0,114,106, - 0,0,0,114,108,0,0,0,114,109,0,0,0,114,184,0, - 0,0,114,6,1,0,0,114,11,1,0,0,114,13,1,0, - 0,114,14,1,0,0,114,17,1,0,0,114,182,0,0,0, - 114,183,0,0,0,114,2,0,0,0,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,114,5,1,0,0,152,4, - 0,0,115,20,0,0,0,12,4,12,8,12,13,12,22,12, - 15,2,1,12,31,2,1,12,23,2,1,114,5,1,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0, - 0,64,0,0,0,115,90,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,100,2,100,3,132,0,90,4,100,4, - 100,5,132,0,90,5,101,6,90,7,100,6,100,7,132,0, - 90,8,100,8,100,9,132,0,90,9,100,19,100,11,100,12, - 132,1,90,10,100,13,100,14,132,0,90,11,101,12,100,15, - 100,16,132,0,131,1,90,13,100,17,100,18,132,0,90,14, - 100,10,83,0,41,20,218,10,70,105,108,101,70,105,110,100, - 101,114,122,172,70,105,108,101,45,98,97,115,101,100,32,102, - 105,110,100,101,114,46,10,10,32,32,32,32,73,110,116,101, - 114,97,99,116,105,111,110,115,32,119,105,116,104,32,116,104, - 101,32,102,105,108,101,32,115,121,115,116,101,109,32,97,114, - 101,32,99,97,99,104,101,100,32,102,111,114,32,112,101,114, - 102,111,114,109,97,110,99,101,44,32,98,101,105,110,103,10, - 32,32,32,32,114,101,102,114,101,115,104,101,100,32,119,104, - 101,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121, - 32,116,104,101,32,102,105,110,100,101,114,32,105,115,32,104, - 97,110,100,108,105,110,103,32,104,97,115,32,98,101,101,110, - 32,109,111,100,105,102,105,101,100,46,10,10,32,32,32,32, - 99,2,0,0,0,0,0,0,0,5,0,0,0,6,0,0, - 0,7,0,0,0,115,84,0,0,0,103,0,125,3,124,2, - 68,0,93,32,92,2,137,0,125,4,124,3,160,0,135,0, - 102,1,100,1,100,2,132,8,124,4,68,0,131,1,161,1, - 1,0,113,8,124,3,124,0,95,1,124,1,112,54,100,3, - 124,0,95,2,100,4,124,0,95,3,116,4,131,0,124,0, - 95,5,116,4,131,0,124,0,95,6,100,5,83,0,41,6, - 122,154,73,110,105,116,105,97,108,105,122,101,32,119,105,116, - 104,32,116,104,101,32,112,97,116,104,32,116,111,32,115,101, - 97,114,99,104,32,111,110,32,97,110,100,32,97,32,118,97, - 114,105,97,98,108,101,32,110,117,109,98,101,114,32,111,102, - 10,32,32,32,32,32,32,32,32,50,45,116,117,112,108,101, - 115,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101, - 32,108,111,97,100,101,114,32,97,110,100,32,116,104,101,32, - 102,105,108,101,32,115,117,102,102,105,120,101,115,32,116,104, - 101,32,108,111,97,100,101,114,10,32,32,32,32,32,32,32, - 32,114,101,99,111,103,110,105,122,101,115,46,99,1,0,0, - 0,0,0,0,0,2,0,0,0,3,0,0,0,51,0,0, - 0,115,22,0,0,0,124,0,93,14,125,1,124,1,136,0, - 102,2,86,0,1,0,113,2,100,0,83,0,41,1,78,114, - 2,0,0,0,41,2,114,22,0,0,0,114,236,0,0,0, - 41,1,114,122,0,0,0,114,2,0,0,0,114,4,0,0, - 0,114,238,0,0,0,43,5,0,0,115,2,0,0,0,4, - 0,122,38,70,105,108,101,70,105,110,100,101,114,46,95,95, - 105,110,105,116,95,95,46,60,108,111,99,97,108,115,62,46, - 60,103,101,110,101,120,112,114,62,114,59,0,0,0,114,89, - 0,0,0,78,41,7,114,147,0,0,0,218,8,95,108,111, - 97,100,101,114,115,114,35,0,0,0,218,11,95,112,97,116, - 104,95,109,116,105,109,101,218,3,115,101,116,218,11,95,112, - 97,116,104,95,99,97,99,104,101,218,19,95,114,101,108,97, - 120,101,100,95,112,97,116,104,95,99,97,99,104,101,41,5, - 114,102,0,0,0,114,35,0,0,0,218,14,108,111,97,100, - 101,114,95,100,101,116,97,105,108,115,90,7,108,111,97,100, - 101,114,115,114,168,0,0,0,114,2,0,0,0,41,1,114, - 122,0,0,0,114,4,0,0,0,114,186,0,0,0,37,5, - 0,0,115,16,0,0,0,0,4,4,1,12,1,26,1,6, - 2,10,1,6,1,8,1,122,19,70,105,108,101,70,105,110, - 100,101,114,46,95,95,105,110,105,116,95,95,99,1,0,0, - 0,0,0,0,0,1,0,0,0,2,0,0,0,67,0,0, - 0,115,10,0,0,0,100,1,124,0,95,0,100,2,83,0, - 41,3,122,31,73,110,118,97,108,105,100,97,116,101,32,116, - 104,101,32,100,105,114,101,99,116,111,114,121,32,109,116,105, - 109,101,46,114,89,0,0,0,78,41,1,114,20,1,0,0, - 41,1,114,102,0,0,0,114,2,0,0,0,114,2,0,0, - 0,114,4,0,0,0,114,6,1,0,0,51,5,0,0,115, - 2,0,0,0,0,2,122,28,70,105,108,101,70,105,110,100, - 101,114,46,105,110,118,97,108,105,100,97,116,101,95,99,97, - 99,104,101,115,99,2,0,0,0,0,0,0,0,3,0,0, - 0,3,0,0,0,67,0,0,0,115,42,0,0,0,124,0, - 160,0,124,1,161,1,125,2,124,2,100,1,107,8,114,26, - 100,1,103,0,102,2,83,0,124,2,106,1,124,2,106,2, - 112,38,103,0,102,2,83,0,41,2,122,197,84,114,121,32, - 116,111,32,102,105,110,100,32,97,32,108,111,97,100,101,114, - 32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105, - 101,100,32,109,111,100,117,108,101,44,32,111,114,32,116,104, - 101,32,110,97,109,101,115,112,97,99,101,10,32,32,32,32, - 32,32,32,32,112,97,99,107,97,103,101,32,112,111,114,116, - 105,111,110,115,46,32,82,101,116,117,114,110,115,32,40,108, - 111,97,100,101,114,44,32,108,105,115,116,45,111,102,45,112, - 111,114,116,105,111,110,115,41,46,10,10,32,32,32,32,32, - 32,32,32,84,104,105,115,32,109,101,116,104,111,100,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,85, - 115,101,32,102,105,110,100,95,115,112,101,99,40,41,32,105, - 110,115,116,101,97,100,46,10,10,32,32,32,32,32,32,32, - 32,78,41,3,114,182,0,0,0,114,122,0,0,0,114,158, - 0,0,0,41,3,114,102,0,0,0,114,121,0,0,0,114, - 166,0,0,0,114,2,0,0,0,114,2,0,0,0,114,4, - 0,0,0,114,119,0,0,0,57,5,0,0,115,8,0,0, - 0,0,7,10,1,8,1,8,1,122,22,70,105,108,101,70, - 105,110,100,101,114,46,102,105,110,100,95,108,111,97,100,101, - 114,99,6,0,0,0,0,0,0,0,7,0,0,0,6,0, - 0,0,67,0,0,0,115,26,0,0,0,124,1,124,2,124, - 3,131,2,125,6,116,0,124,2,124,3,124,6,124,4,100, - 1,141,4,83,0,41,2,78,41,2,114,122,0,0,0,114, - 158,0,0,0,41,1,114,169,0,0,0,41,7,114,102,0, - 0,0,114,167,0,0,0,114,121,0,0,0,114,35,0,0, - 0,90,4,115,109,115,108,114,181,0,0,0,114,122,0,0, - 0,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, - 114,17,1,0,0,69,5,0,0,115,6,0,0,0,0,1, - 10,1,8,1,122,20,70,105,108,101,70,105,110,100,101,114, - 46,95,103,101,116,95,115,112,101,99,78,99,3,0,0,0, - 0,0,0,0,14,0,0,0,8,0,0,0,67,0,0,0, - 115,98,1,0,0,100,1,125,3,124,1,160,0,100,2,161, - 1,100,3,25,0,125,4,122,24,116,1,124,0,106,2,112, - 34,116,3,160,4,161,0,131,1,106,5,125,5,87,0,110, - 24,4,0,116,6,107,10,114,66,1,0,1,0,1,0,100, - 4,125,5,89,0,110,2,88,0,124,5,124,0,106,7,107, - 3,114,92,124,0,160,8,161,0,1,0,124,5,124,0,95, - 7,116,9,131,0,114,114,124,0,106,10,125,6,124,4,160, - 11,161,0,125,7,110,10,124,0,106,12,125,6,124,4,125, - 7,124,7,124,6,107,6,114,218,116,13,124,0,106,2,124, - 4,131,2,125,8,124,0,106,14,68,0,93,58,92,2,125, - 9,125,10,100,5,124,9,23,0,125,11,116,13,124,8,124, - 11,131,2,125,12,116,15,124,12,131,1,114,150,124,0,160, - 16,124,10,124,1,124,12,124,8,103,1,124,2,161,5,2, - 0,1,0,83,0,113,150,116,17,124,8,131,1,125,3,124, - 0,106,14,68,0,93,82,92,2,125,9,125,10,116,13,124, - 0,106,2,124,4,124,9,23,0,131,2,125,12,116,18,106, - 19,100,6,124,12,100,3,100,7,141,3,1,0,124,7,124, - 9,23,0,124,6,107,6,114,224,116,15,124,12,131,1,114, - 224,124,0,160,16,124,10,124,1,124,12,100,8,124,2,161, - 5,2,0,1,0,83,0,113,224,124,3,144,1,114,94,116, - 18,160,19,100,9,124,8,161,2,1,0,116,18,160,20,124, - 1,100,8,161,2,125,13,124,8,103,1,124,13,95,21,124, - 13,83,0,100,8,83,0,41,10,122,111,84,114,121,32,116, - 111,32,102,105,110,100,32,97,32,115,112,101,99,32,102,111, - 114,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32, - 109,111,100,117,108,101,46,10,10,32,32,32,32,32,32,32, - 32,82,101,116,117,114,110,115,32,116,104,101,32,109,97,116, - 99,104,105,110,103,32,115,112,101,99,44,32,111,114,32,78, - 111,110,101,32,105,102,32,110,111,116,32,102,111,117,110,100, - 46,10,32,32,32,32,32,32,32,32,70,114,59,0,0,0, - 114,57,0,0,0,114,89,0,0,0,114,186,0,0,0,122, - 9,116,114,121,105,110,103,32,123,125,41,1,90,9,118,101, - 114,98,111,115,105,116,121,78,122,25,112,111,115,115,105,98, - 108,101,32,110,97,109,101,115,112,97,99,101,32,102,111,114, - 32,123,125,41,22,114,32,0,0,0,114,39,0,0,0,114, - 35,0,0,0,114,1,0,0,0,114,45,0,0,0,114,230, - 0,0,0,114,40,0,0,0,114,20,1,0,0,218,11,95, - 102,105,108,108,95,99,97,99,104,101,114,5,0,0,0,114, - 23,1,0,0,114,90,0,0,0,114,22,1,0,0,114,28, - 0,0,0,114,19,1,0,0,114,44,0,0,0,114,17,1, - 0,0,114,46,0,0,0,114,116,0,0,0,114,130,0,0, - 0,114,162,0,0,0,114,158,0,0,0,41,14,114,102,0, - 0,0,114,121,0,0,0,114,181,0,0,0,90,12,105,115, - 95,110,97,109,101,115,112,97,99,101,90,11,116,97,105,108, - 95,109,111,100,117,108,101,114,149,0,0,0,90,5,99,97, - 99,104,101,90,12,99,97,99,104,101,95,109,111,100,117,108, - 101,90,9,98,97,115,101,95,112,97,116,104,114,236,0,0, - 0,114,167,0,0,0,90,13,105,110,105,116,95,102,105,108, - 101,110,97,109,101,90,9,102,117,108,108,95,112,97,116,104, - 114,166,0,0,0,114,2,0,0,0,114,2,0,0,0,114, - 4,0,0,0,114,182,0,0,0,74,5,0,0,115,70,0, - 0,0,0,5,4,1,14,1,2,1,24,1,14,1,10,1, - 10,1,8,1,6,2,6,1,6,1,10,2,6,1,4,2, - 8,1,12,1,14,1,8,1,10,1,8,1,26,4,8,2, - 14,1,16,1,16,1,12,1,8,1,10,1,14,1,6,1, - 12,1,12,1,8,1,4,1,122,20,70,105,108,101,70,105, - 110,100,101,114,46,102,105,110,100,95,115,112,101,99,99,1, - 0,0,0,0,0,0,0,9,0,0,0,10,0,0,0,67, - 0,0,0,115,190,0,0,0,124,0,106,0,125,1,122,22, - 116,1,160,2,124,1,112,22,116,1,160,3,161,0,161,1, - 125,2,87,0,110,30,4,0,116,4,116,5,116,6,102,3, - 107,10,114,58,1,0,1,0,1,0,103,0,125,2,89,0, - 110,2,88,0,116,7,106,8,160,9,100,1,161,1,115,84, - 116,10,124,2,131,1,124,0,95,11,110,74,116,10,131,0, - 125,3,124,2,68,0,93,56,125,4,124,4,160,12,100,2, - 161,1,92,3,125,5,125,6,125,7,124,6,114,136,100,3, - 160,13,124,5,124,7,160,14,161,0,161,2,125,8,110,4, - 124,5,125,8,124,3,160,15,124,8,161,1,1,0,113,94, - 124,3,124,0,95,11,116,7,106,8,160,9,116,16,161,1, - 114,186,100,4,100,5,132,0,124,2,68,0,131,1,124,0, - 95,17,100,6,83,0,41,7,122,68,70,105,108,108,32,116, - 104,101,32,99,97,99,104,101,32,111,102,32,112,111,116,101, - 110,116,105,97,108,32,109,111,100,117,108,101,115,32,97,110, - 100,32,112,97,99,107,97,103,101,115,32,102,111,114,32,116, - 104,105,115,32,100,105,114,101,99,116,111,114,121,46,114,0, - 0,0,0,114,59,0,0,0,122,5,123,125,46,123,125,99, - 1,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0, - 83,0,0,0,115,20,0,0,0,104,0,124,0,93,12,125, - 1,124,1,160,0,161,0,146,2,113,4,83,0,114,2,0, - 0,0,41,1,114,90,0,0,0,41,2,114,22,0,0,0, - 90,2,102,110,114,2,0,0,0,114,2,0,0,0,114,4, - 0,0,0,250,9,60,115,101,116,99,111,109,112,62,151,5, - 0,0,115,2,0,0,0,6,0,122,41,70,105,108,101,70, - 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, - 101,46,60,108,111,99,97,108,115,62,46,60,115,101,116,99, - 111,109,112,62,78,41,18,114,35,0,0,0,114,1,0,0, - 0,114,227,0,0,0,114,45,0,0,0,114,224,0,0,0, - 218,15,80,101,114,109,105,115,115,105,111,110,69,114,114,111, - 114,218,18,78,111,116,65,68,105,114,101,99,116,111,114,121, - 69,114,114,111,114,114,6,0,0,0,114,7,0,0,0,114, - 8,0,0,0,114,21,1,0,0,114,22,1,0,0,114,85, - 0,0,0,114,48,0,0,0,114,90,0,0,0,218,3,97, - 100,100,114,9,0,0,0,114,23,1,0,0,41,9,114,102, - 0,0,0,114,35,0,0,0,114,228,0,0,0,90,21,108, - 111,119,101,114,95,115,117,102,102,105,120,95,99,111,110,116, - 101,110,116,115,114,1,1,0,0,114,100,0,0,0,114,248, - 0,0,0,114,236,0,0,0,90,8,110,101,119,95,110,97, - 109,101,114,2,0,0,0,114,2,0,0,0,114,4,0,0, - 0,114,25,1,0,0,122,5,0,0,115,34,0,0,0,0, - 2,6,1,2,1,22,1,20,3,10,3,12,1,12,7,6, - 1,8,1,16,1,4,1,18,2,4,1,12,1,6,1,12, - 1,122,22,70,105,108,101,70,105,110,100,101,114,46,95,102, - 105,108,108,95,99,97,99,104,101,99,1,0,0,0,0,0, - 0,0,3,0,0,0,3,0,0,0,7,0,0,0,115,18, - 0,0,0,135,0,135,1,102,2,100,1,100,2,132,8,125, - 2,124,2,83,0,41,3,97,20,1,0,0,65,32,99,108, - 97,115,115,32,109,101,116,104,111,100,32,119,104,105,99,104, - 32,114,101,116,117,114,110,115,32,97,32,99,108,111,115,117, - 114,101,32,116,111,32,117,115,101,32,111,110,32,115,121,115, - 46,112,97,116,104,95,104,111,111,107,10,32,32,32,32,32, - 32,32,32,119,104,105,99,104,32,119,105,108,108,32,114,101, - 116,117,114,110,32,97,110,32,105,110,115,116,97,110,99,101, - 32,117,115,105,110,103,32,116,104,101,32,115,112,101,99,105, - 102,105,101,100,32,108,111,97,100,101,114,115,32,97,110,100, - 32,116,104,101,32,112,97,116,104,10,32,32,32,32,32,32, - 32,32,99,97,108,108,101,100,32,111,110,32,116,104,101,32, - 99,108,111,115,117,114,101,46,10,10,32,32,32,32,32,32, - 32,32,73,102,32,116,104,101,32,112,97,116,104,32,99,97, - 108,108,101,100,32,111,110,32,116,104,101,32,99,108,111,115, - 117,114,101,32,105,115,32,110,111,116,32,97,32,100,105,114, - 101,99,116,111,114,121,44,32,73,109,112,111,114,116,69,114, - 114,111,114,32,105,115,10,32,32,32,32,32,32,32,32,114, - 97,105,115,101,100,46,10,10,32,32,32,32,32,32,32,32, - 99,1,0,0,0,0,0,0,0,1,0,0,0,4,0,0, - 0,19,0,0,0,115,34,0,0,0,116,0,124,0,131,1, - 115,20,116,1,100,1,124,0,100,2,141,2,130,1,136,0, - 124,0,102,1,136,1,158,2,142,0,83,0,41,3,122,45, - 80,97,116,104,32,104,111,111,107,32,102,111,114,32,105,109, - 112,111,114,116,108,105,98,46,109,97,99,104,105,110,101,114, - 121,46,70,105,108,101,70,105,110,100,101,114,46,122,30,111, - 110,108,121,32,100,105,114,101,99,116,111,114,105,101,115,32, - 97,114,101,32,115,117,112,112,111,114,116,101,100,41,1,114, - 35,0,0,0,41,2,114,46,0,0,0,114,101,0,0,0, - 41,1,114,35,0,0,0,41,2,114,172,0,0,0,114,24, - 1,0,0,114,2,0,0,0,114,4,0,0,0,218,24,112, - 97,116,104,95,104,111,111,107,95,102,111,114,95,70,105,108, - 101,70,105,110,100,101,114,163,5,0,0,115,6,0,0,0, - 0,2,8,1,12,1,122,54,70,105,108,101,70,105,110,100, - 101,114,46,112,97,116,104,95,104,111,111,107,46,60,108,111, - 99,97,108,115,62,46,112,97,116,104,95,104,111,111,107,95, - 102,111,114,95,70,105,108,101,70,105,110,100,101,114,114,2, - 0,0,0,41,3,114,172,0,0,0,114,24,1,0,0,114, - 30,1,0,0,114,2,0,0,0,41,2,114,172,0,0,0, - 114,24,1,0,0,114,4,0,0,0,218,9,112,97,116,104, - 95,104,111,111,107,153,5,0,0,115,4,0,0,0,0,10, - 14,6,122,20,70,105,108,101,70,105,110,100,101,114,46,112, - 97,116,104,95,104,111,111,107,99,1,0,0,0,0,0,0, - 0,1,0,0,0,3,0,0,0,67,0,0,0,115,12,0, - 0,0,100,1,160,0,124,0,106,1,161,1,83,0,41,2, - 78,122,16,70,105,108,101,70,105,110,100,101,114,40,123,33, - 114,125,41,41,2,114,48,0,0,0,114,35,0,0,0,41, - 1,114,102,0,0,0,114,2,0,0,0,114,2,0,0,0, - 114,4,0,0,0,114,0,1,0,0,171,5,0,0,115,2, - 0,0,0,0,1,122,19,70,105,108,101,70,105,110,100,101, - 114,46,95,95,114,101,112,114,95,95,41,1,78,41,15,114, - 107,0,0,0,114,106,0,0,0,114,108,0,0,0,114,109, - 0,0,0,114,186,0,0,0,114,6,1,0,0,114,125,0, - 0,0,114,183,0,0,0,114,119,0,0,0,114,17,1,0, - 0,114,182,0,0,0,114,25,1,0,0,114,184,0,0,0, - 114,31,1,0,0,114,0,1,0,0,114,2,0,0,0,114, - 2,0,0,0,114,2,0,0,0,114,4,0,0,0,114,18, - 1,0,0,28,5,0,0,115,18,0,0,0,12,9,8,14, - 8,4,4,2,8,12,8,5,10,48,8,31,12,18,114,18, - 1,0,0,99,4,0,0,0,0,0,0,0,6,0,0,0, - 8,0,0,0,67,0,0,0,115,146,0,0,0,124,0,160, - 0,100,1,161,1,125,4,124,0,160,0,100,2,161,1,125, - 5,124,4,115,66,124,5,114,36,124,5,106,1,125,4,110, - 30,124,2,124,3,107,2,114,56,116,2,124,1,124,2,131, - 2,125,4,110,10,116,3,124,1,124,2,131,2,125,4,124, - 5,115,84,116,4,124,1,124,2,124,4,100,3,141,3,125, - 5,122,36,124,5,124,0,100,2,60,0,124,4,124,0,100, - 1,60,0,124,2,124,0,100,4,60,0,124,3,124,0,100, - 5,60,0,87,0,110,20,4,0,116,5,107,10,114,140,1, - 0,1,0,1,0,89,0,110,2,88,0,100,0,83,0,41, - 6,78,218,10,95,95,108,111,97,100,101,114,95,95,218,8, - 95,95,115,112,101,99,95,95,41,1,114,122,0,0,0,90, - 8,95,95,102,105,108,101,95,95,90,10,95,95,99,97,99, - 104,101,100,95,95,41,6,218,3,103,101,116,114,122,0,0, - 0,114,234,0,0,0,114,229,0,0,0,114,169,0,0,0, - 218,9,69,120,99,101,112,116,105,111,110,41,6,90,2,110, - 115,114,100,0,0,0,90,8,112,97,116,104,110,97,109,101, - 90,9,99,112,97,116,104,110,97,109,101,114,122,0,0,0, - 114,166,0,0,0,114,2,0,0,0,114,2,0,0,0,114, - 4,0,0,0,218,14,95,102,105,120,95,117,112,95,109,111, - 100,117,108,101,177,5,0,0,115,34,0,0,0,0,2,10, - 1,10,1,4,1,4,1,8,1,8,1,12,2,10,1,4, - 1,14,1,2,1,8,1,8,1,8,1,12,1,14,2,114, - 36,1,0,0,99,0,0,0,0,0,0,0,0,3,0,0, - 0,3,0,0,0,67,0,0,0,115,38,0,0,0,116,0, - 116,1,160,2,161,0,102,2,125,0,116,3,116,4,102,2, - 125,1,116,5,116,6,102,2,125,2,124,0,124,1,124,2, - 103,3,83,0,41,1,122,95,82,101,116,117,114,110,115,32, - 97,32,108,105,115,116,32,111,102,32,102,105,108,101,45,98, - 97,115,101,100,32,109,111,100,117,108,101,32,108,111,97,100, - 101,114,115,46,10,10,32,32,32,32,69,97,99,104,32,105, - 116,101,109,32,105,115,32,97,32,116,117,112,108,101,32,40, - 108,111,97,100,101,114,44,32,115,117,102,102,105,120,101,115, - 41,46,10,32,32,32,32,41,7,114,235,0,0,0,114,143, - 0,0,0,218,18,101,120,116,101,110,115,105,111,110,95,115, - 117,102,102,105,120,101,115,114,229,0,0,0,114,86,0,0, - 0,114,234,0,0,0,114,76,0,0,0,41,3,90,10,101, - 120,116,101,110,115,105,111,110,115,90,6,115,111,117,114,99, - 101,90,8,98,121,116,101,99,111,100,101,114,2,0,0,0, - 114,2,0,0,0,114,4,0,0,0,114,163,0,0,0,200, - 5,0,0,115,8,0,0,0,0,5,12,1,8,1,8,1, - 114,163,0,0,0,99,1,0,0,0,0,0,0,0,12,0, - 0,0,9,0,0,0,67,0,0,0,115,156,1,0,0,124, - 0,97,0,116,0,106,1,97,1,116,0,106,2,97,2,116, - 1,106,3,116,4,25,0,125,1,100,1,68,0,93,48,125, - 2,124,2,116,1,106,3,107,7,114,56,116,0,160,5,124, - 2,161,1,125,3,110,10,116,1,106,3,124,2,25,0,125, - 3,116,6,124,1,124,2,124,3,131,3,1,0,113,30,100, - 2,100,3,103,1,102,2,100,4,100,5,100,3,103,2,102, - 2,102,2,125,4,124,4,68,0,93,110,92,2,125,5,125, - 6,116,7,100,6,100,7,132,0,124,6,68,0,131,1,131, - 1,115,136,116,8,130,1,124,6,100,8,25,0,125,7,124, - 5,116,1,106,3,107,6,114,170,116,1,106,3,124,5,25, - 0,125,8,1,0,113,226,113,106,122,20,116,0,160,5,124, - 5,161,1,125,8,87,0,1,0,113,226,87,0,113,106,4, - 0,116,9,107,10,114,214,1,0,1,0,1,0,89,0,113, - 106,89,0,113,106,88,0,113,106,116,9,100,9,131,1,130, - 1,116,6,124,1,100,10,124,8,131,3,1,0,116,6,124, - 1,100,11,124,7,131,3,1,0,116,6,124,1,100,12,100, - 13,160,10,124,6,161,1,131,3,1,0,116,0,160,5,100, - 14,161,1,125,9,116,6,124,1,100,14,124,9,131,3,1, - 0,116,0,160,5,100,15,161,1,125,10,116,6,124,1,100, - 15,124,10,131,3,1,0,124,5,100,4,107,2,144,1,114, - 88,116,0,160,5,100,16,161,1,125,11,116,6,124,1,100, - 17,124,11,131,3,1,0,116,6,124,1,100,18,116,11,131, - 0,131,3,1,0,116,12,160,13,116,2,160,14,161,0,161, - 1,1,0,124,5,100,4,107,2,144,1,114,152,116,15,160, - 16,100,19,161,1,1,0,100,20,116,12,107,6,144,1,114, - 152,100,21,116,17,95,18,100,22,83,0,41,23,122,205,83, - 101,116,117,112,32,116,104,101,32,112,97,116,104,45,98,97, - 115,101,100,32,105,109,112,111,114,116,101,114,115,32,102,111, - 114,32,105,109,112,111,114,116,108,105,98,32,98,121,32,105, - 109,112,111,114,116,105,110,103,32,110,101,101,100,101,100,10, - 32,32,32,32,98,117,105,108,116,45,105,110,32,109,111,100, - 117,108,101,115,32,97,110,100,32,105,110,106,101,99,116,105, - 110,103,32,116,104,101,109,32,105,110,116,111,32,116,104,101, - 32,103,108,111,98,97,108,32,110,97,109,101,115,112,97,99, - 101,46,10,10,32,32,32,32,79,116,104,101,114,32,99,111, - 109,112,111,110,101,110,116,115,32,97,114,101,32,101,120,116, - 114,97,99,116,101,100,32,102,114,111,109,32,116,104,101,32, - 99,111,114,101,32,98,111,111,116,115,116,114,97,112,32,109, - 111,100,117,108,101,46,10,10,32,32,32,32,41,4,114,50, - 0,0,0,114,61,0,0,0,218,8,98,117,105,108,116,105, - 110,115,114,140,0,0,0,90,5,112,111,115,105,120,250,1, - 47,90,2,110,116,250,1,92,99,1,0,0,0,0,0,0, - 0,2,0,0,0,3,0,0,0,115,0,0,0,115,26,0, - 0,0,124,0,93,18,125,1,116,0,124,1,131,1,100,0, - 107,2,86,0,1,0,113,2,100,1,83,0,41,2,114,29, - 0,0,0,78,41,1,114,31,0,0,0,41,2,114,22,0, - 0,0,114,79,0,0,0,114,2,0,0,0,114,2,0,0, - 0,114,4,0,0,0,114,238,0,0,0,236,5,0,0,115, - 2,0,0,0,4,0,122,25,95,115,101,116,117,112,46,60, + 104,101,46,10,32,32,32,32,32,32,32,32,78,41,7,114, + 6,0,0,0,114,35,0,0,0,114,18,1,0,0,114,122, + 0,0,0,114,158,0,0,0,114,160,0,0,0,114,241,0, + 0,0,41,6,114,172,0,0,0,114,121,0,0,0,114,35, + 0,0,0,114,181,0,0,0,114,166,0,0,0,114,17,1, + 0,0,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,114,182,0,0,0,248,4,0,0,115,26,0,0,0,0, + 6,8,1,6,1,14,1,8,1,4,1,10,1,6,1,4, + 3,6,1,16,1,4,2,6,2,122,20,80,97,116,104,70, + 105,110,100,101,114,46,102,105,110,100,95,115,112,101,99,99, + 3,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0, + 67,0,0,0,115,30,0,0,0,124,0,160,0,124,1,124, + 2,161,2,125,3,124,3,100,1,107,8,114,24,100,1,83, + 0,124,3,106,1,83,0,41,2,122,170,102,105,110,100,32, + 116,104,101,32,109,111,100,117,108,101,32,111,110,32,115,121, + 115,46,112,97,116,104,32,111,114,32,39,112,97,116,104,39, + 32,98,97,115,101,100,32,111,110,32,115,121,115,46,112,97, + 116,104,95,104,111,111,107,115,32,97,110,100,10,32,32,32, + 32,32,32,32,32,115,121,115,46,112,97,116,104,95,105,109, + 112,111,114,116,101,114,95,99,97,99,104,101,46,10,10,32, + 32,32,32,32,32,32,32,84,104,105,115,32,109,101,116,104, + 111,100,32,105,115,32,100,101,112,114,101,99,97,116,101,100, + 46,32,32,85,115,101,32,102,105,110,100,95,115,112,101,99, + 40,41,32,105,110,115,116,101,97,100,46,10,10,32,32,32, + 32,32,32,32,32,78,41,2,114,182,0,0,0,114,122,0, + 0,0,41,4,114,172,0,0,0,114,121,0,0,0,114,35, + 0,0,0,114,166,0,0,0,114,2,0,0,0,114,2,0, + 0,0,114,4,0,0,0,114,183,0,0,0,16,5,0,0, + 115,8,0,0,0,0,8,12,1,8,1,4,1,122,22,80, + 97,116,104,70,105,110,100,101,114,46,102,105,110,100,95,109, + 111,100,117,108,101,41,1,78,41,2,78,78,41,1,78,41, + 12,114,107,0,0,0,114,106,0,0,0,114,108,0,0,0, + 114,109,0,0,0,114,184,0,0,0,114,6,1,0,0,114, + 12,1,0,0,114,14,1,0,0,114,15,1,0,0,114,18, + 1,0,0,114,182,0,0,0,114,183,0,0,0,114,2,0, + 0,0,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,114,5,1,0,0,152,4,0,0,115,20,0,0,0,12, + 4,12,10,12,13,12,22,12,15,2,1,12,31,2,1,12, + 23,2,1,114,5,1,0,0,99,0,0,0,0,0,0,0, + 0,0,0,0,0,3,0,0,0,64,0,0,0,115,90,0, + 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, + 100,3,132,0,90,4,100,4,100,5,132,0,90,5,101,6, + 90,7,100,6,100,7,132,0,90,8,100,8,100,9,132,0, + 90,9,100,19,100,11,100,12,132,1,90,10,100,13,100,14, + 132,0,90,11,101,12,100,15,100,16,132,0,131,1,90,13, + 100,17,100,18,132,0,90,14,100,10,83,0,41,20,218,10, + 70,105,108,101,70,105,110,100,101,114,122,172,70,105,108,101, + 45,98,97,115,101,100,32,102,105,110,100,101,114,46,10,10, + 32,32,32,32,73,110,116,101,114,97,99,116,105,111,110,115, + 32,119,105,116,104,32,116,104,101,32,102,105,108,101,32,115, + 121,115,116,101,109,32,97,114,101,32,99,97,99,104,101,100, + 32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101, + 44,32,98,101,105,110,103,10,32,32,32,32,114,101,102,114, + 101,115,104,101,100,32,119,104,101,110,32,116,104,101,32,100, + 105,114,101,99,116,111,114,121,32,116,104,101,32,102,105,110, + 100,101,114,32,105,115,32,104,97,110,100,108,105,110,103,32, + 104,97,115,32,98,101,101,110,32,109,111,100,105,102,105,101, + 100,46,10,10,32,32,32,32,99,2,0,0,0,0,0,0, + 0,5,0,0,0,6,0,0,0,7,0,0,0,115,84,0, + 0,0,103,0,125,3,124,2,68,0,93,32,92,2,137,0, + 125,4,124,3,160,0,135,0,102,1,100,1,100,2,132,8, + 124,4,68,0,131,1,161,1,1,0,113,8,124,3,124,0, + 95,1,124,1,112,54,100,3,124,0,95,2,100,4,124,0, + 95,3,116,4,131,0,124,0,95,5,116,4,131,0,124,0, + 95,6,100,5,83,0,41,6,122,154,73,110,105,116,105,97, + 108,105,122,101,32,119,105,116,104,32,116,104,101,32,112,97, + 116,104,32,116,111,32,115,101,97,114,99,104,32,111,110,32, + 97,110,100,32,97,32,118,97,114,105,97,98,108,101,32,110, + 117,109,98,101,114,32,111,102,10,32,32,32,32,32,32,32, + 32,50,45,116,117,112,108,101,115,32,99,111,110,116,97,105, + 110,105,110,103,32,116,104,101,32,108,111,97,100,101,114,32, + 97,110,100,32,116,104,101,32,102,105,108,101,32,115,117,102, + 102,105,120,101,115,32,116,104,101,32,108,111,97,100,101,114, + 10,32,32,32,32,32,32,32,32,114,101,99,111,103,110,105, + 122,101,115,46,99,1,0,0,0,0,0,0,0,2,0,0, + 0,3,0,0,0,51,0,0,0,115,22,0,0,0,124,0, + 93,14,125,1,124,1,136,0,102,2,86,0,1,0,113,2, + 100,0,83,0,41,1,78,114,2,0,0,0,41,2,114,22, + 0,0,0,114,236,0,0,0,41,1,114,122,0,0,0,114, + 2,0,0,0,114,4,0,0,0,114,238,0,0,0,45,5, + 0,0,115,2,0,0,0,4,0,122,38,70,105,108,101,70, + 105,110,100,101,114,46,95,95,105,110,105,116,95,95,46,60, 108,111,99,97,108,115,62,46,60,103,101,110,101,120,112,114, - 62,114,60,0,0,0,122,30,105,109,112,111,114,116,108,105, - 98,32,114,101,113,117,105,114,101,115,32,112,111,115,105,120, - 32,111,114,32,110,116,114,1,0,0,0,114,25,0,0,0, - 114,21,0,0,0,114,30,0,0,0,90,7,95,116,104,114, - 101,97,100,90,8,95,119,101,97,107,114,101,102,90,6,119, - 105,110,114,101,103,114,171,0,0,0,114,5,0,0,0,122, - 4,46,112,121,119,122,6,95,100,46,112,121,100,84,78,41, - 19,114,116,0,0,0,114,6,0,0,0,114,143,0,0,0, - 114,250,0,0,0,114,107,0,0,0,90,18,95,98,117,105, - 108,116,105,110,95,102,114,111,109,95,110,97,109,101,114,111, - 0,0,0,218,3,97,108,108,114,151,0,0,0,114,101,0, - 0,0,114,26,0,0,0,114,11,0,0,0,114,240,0,0, - 0,114,147,0,0,0,114,37,1,0,0,114,86,0,0,0, - 114,165,0,0,0,114,170,0,0,0,114,174,0,0,0,41, - 12,218,17,95,98,111,111,116,115,116,114,97,112,95,109,111, - 100,117,108,101,90,11,115,101,108,102,95,109,111,100,117,108, - 101,90,12,98,117,105,108,116,105,110,95,110,97,109,101,90, - 14,98,117,105,108,116,105,110,95,109,111,100,117,108,101,90, - 10,111,115,95,100,101,116,97,105,108,115,90,10,98,117,105, - 108,116,105,110,95,111,115,114,21,0,0,0,114,25,0,0, - 0,90,9,111,115,95,109,111,100,117,108,101,90,13,116,104, - 114,101,97,100,95,109,111,100,117,108,101,90,14,119,101,97, - 107,114,101,102,95,109,111,100,117,108,101,90,13,119,105,110, - 114,101,103,95,109,111,100,117,108,101,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,218,6,95,115,101,116,117, - 112,211,5,0,0,115,76,0,0,0,0,8,4,1,6,1, - 6,3,10,1,8,1,10,1,12,2,10,1,14,3,22,1, - 12,2,22,1,8,1,10,1,10,1,6,2,2,1,10,1, - 10,1,14,1,12,2,8,1,12,1,12,1,18,3,10,1, - 12,3,10,1,12,3,10,1,10,1,12,3,14,1,14,1, - 10,1,10,1,10,1,114,43,1,0,0,99,1,0,0,0, - 0,0,0,0,2,0,0,0,4,0,0,0,67,0,0,0, - 115,50,0,0,0,116,0,124,0,131,1,1,0,116,1,131, - 0,125,1,116,2,106,3,160,4,116,5,106,6,124,1,142, - 0,103,1,161,1,1,0,116,2,106,7,160,8,116,9,161, - 1,1,0,100,1,83,0,41,2,122,41,73,110,115,116,97, - 108,108,32,116,104,101,32,112,97,116,104,45,98,97,115,101, - 100,32,105,109,112,111,114,116,32,99,111,109,112,111,110,101, - 110,116,115,46,78,41,10,114,43,1,0,0,114,163,0,0, - 0,114,6,0,0,0,114,10,1,0,0,114,147,0,0,0, - 114,18,1,0,0,114,31,1,0,0,218,9,109,101,116,97, - 95,112,97,116,104,114,165,0,0,0,114,5,1,0,0,41, - 2,114,42,1,0,0,90,17,115,117,112,112,111,114,116,101, - 100,95,108,111,97,100,101,114,115,114,2,0,0,0,114,2, - 0,0,0,114,4,0,0,0,218,8,95,105,110,115,116,97, - 108,108,19,6,0,0,115,8,0,0,0,0,2,8,1,6, - 1,20,1,114,45,1,0,0,41,1,114,47,0,0,0,41, - 1,78,41,3,78,78,78,41,2,114,60,0,0,0,114,60, - 0,0,0,41,1,84,41,1,78,41,1,78,41,61,114,109, - 0,0,0,114,10,0,0,0,90,37,95,67,65,83,69,95, - 73,78,83,69,78,83,73,84,73,86,69,95,80,76,65,84, - 70,79,82,77,83,95,66,89,84,69,83,95,75,69,89,114, - 9,0,0,0,114,11,0,0,0,114,17,0,0,0,114,19, - 0,0,0,114,28,0,0,0,114,38,0,0,0,114,39,0, - 0,0,114,43,0,0,0,114,44,0,0,0,114,46,0,0, - 0,114,56,0,0,0,218,4,116,121,112,101,218,8,95,95, - 99,111,100,101,95,95,114,142,0,0,0,114,15,0,0,0, - 114,129,0,0,0,114,14,0,0,0,114,18,0,0,0,114, - 209,0,0,0,114,75,0,0,0,114,74,0,0,0,114,86, - 0,0,0,114,76,0,0,0,90,23,68,69,66,85,71,95, - 66,89,84,69,67,79,68,69,95,83,85,70,70,73,88,69, - 83,90,27,79,80,84,73,77,73,90,69,68,95,66,89,84, - 69,67,79,68,69,95,83,85,70,70,73,88,69,83,114,81, - 0,0,0,114,87,0,0,0,114,93,0,0,0,114,97,0, - 0,0,114,99,0,0,0,114,118,0,0,0,114,125,0,0, - 0,114,133,0,0,0,114,137,0,0,0,114,139,0,0,0, - 114,145,0,0,0,114,150,0,0,0,114,152,0,0,0,114, - 157,0,0,0,218,6,111,98,106,101,99,116,114,164,0,0, - 0,114,169,0,0,0,114,170,0,0,0,114,185,0,0,0, - 114,195,0,0,0,114,212,0,0,0,114,229,0,0,0,114, - 234,0,0,0,114,240,0,0,0,114,235,0,0,0,114,241, - 0,0,0,114,3,1,0,0,114,5,1,0,0,114,18,1, - 0,0,114,36,1,0,0,114,163,0,0,0,114,43,1,0, - 0,114,45,1,0,0,114,2,0,0,0,114,2,0,0,0, - 114,2,0,0,0,114,4,0,0,0,218,8,60,109,111,100, - 117,108,101,62,23,0,0,0,115,118,0,0,0,4,0,4, - 1,4,1,2,1,6,3,8,17,8,5,8,5,8,6,8, - 12,8,10,8,9,8,5,8,7,10,22,10,127,0,5,16, - 1,12,2,4,1,4,2,6,2,6,2,8,2,16,45,8, - 34,8,19,8,12,8,12,8,28,8,17,8,33,8,28,8, - 24,10,13,10,10,10,11,8,14,6,3,4,1,14,67,14, - 64,14,29,16,127,0,17,14,68,18,45,18,26,4,3,18, - 53,14,60,14,42,14,127,0,5,14,127,0,22,10,23,8, - 11,8,64, + 62,114,59,0,0,0,114,89,0,0,0,78,41,7,114,147, + 0,0,0,218,8,95,108,111,97,100,101,114,115,114,35,0, + 0,0,218,11,95,112,97,116,104,95,109,116,105,109,101,218, + 3,115,101,116,218,11,95,112,97,116,104,95,99,97,99,104, + 101,218,19,95,114,101,108,97,120,101,100,95,112,97,116,104, + 95,99,97,99,104,101,41,5,114,102,0,0,0,114,35,0, + 0,0,218,14,108,111,97,100,101,114,95,100,101,116,97,105, + 108,115,90,7,108,111,97,100,101,114,115,114,168,0,0,0, + 114,2,0,0,0,41,1,114,122,0,0,0,114,4,0,0, + 0,114,186,0,0,0,39,5,0,0,115,16,0,0,0,0, + 4,4,1,12,1,26,1,6,2,10,1,6,1,8,1,122, + 19,70,105,108,101,70,105,110,100,101,114,46,95,95,105,110, + 105,116,95,95,99,1,0,0,0,0,0,0,0,1,0,0, + 0,2,0,0,0,67,0,0,0,115,10,0,0,0,100,1, + 124,0,95,0,100,2,83,0,41,3,122,31,73,110,118,97, + 108,105,100,97,116,101,32,116,104,101,32,100,105,114,101,99, + 116,111,114,121,32,109,116,105,109,101,46,114,89,0,0,0, + 78,41,1,114,21,1,0,0,41,1,114,102,0,0,0,114, + 2,0,0,0,114,2,0,0,0,114,4,0,0,0,114,6, + 1,0,0,53,5,0,0,115,2,0,0,0,0,2,122,28, + 70,105,108,101,70,105,110,100,101,114,46,105,110,118,97,108, + 105,100,97,116,101,95,99,97,99,104,101,115,99,2,0,0, + 0,0,0,0,0,3,0,0,0,3,0,0,0,67,0,0, + 0,115,42,0,0,0,124,0,160,0,124,1,161,1,125,2, + 124,2,100,1,107,8,114,26,100,1,103,0,102,2,83,0, + 124,2,106,1,124,2,106,2,112,38,103,0,102,2,83,0, + 41,2,122,197,84,114,121,32,116,111,32,102,105,110,100,32, + 97,32,108,111,97,100,101,114,32,102,111,114,32,116,104,101, + 32,115,112,101,99,105,102,105,101,100,32,109,111,100,117,108, + 101,44,32,111,114,32,116,104,101,32,110,97,109,101,115,112, + 97,99,101,10,32,32,32,32,32,32,32,32,112,97,99,107, + 97,103,101,32,112,111,114,116,105,111,110,115,46,32,82,101, + 116,117,114,110,115,32,40,108,111,97,100,101,114,44,32,108, + 105,115,116,45,111,102,45,112,111,114,116,105,111,110,115,41, + 46,10,10,32,32,32,32,32,32,32,32,84,104,105,115,32, + 109,101,116,104,111,100,32,105,115,32,100,101,112,114,101,99, + 97,116,101,100,46,32,32,85,115,101,32,102,105,110,100,95, + 115,112,101,99,40,41,32,105,110,115,116,101,97,100,46,10, + 10,32,32,32,32,32,32,32,32,78,41,3,114,182,0,0, + 0,114,122,0,0,0,114,158,0,0,0,41,3,114,102,0, + 0,0,114,121,0,0,0,114,166,0,0,0,114,2,0,0, + 0,114,2,0,0,0,114,4,0,0,0,114,119,0,0,0, + 59,5,0,0,115,8,0,0,0,0,7,10,1,8,1,8, + 1,122,22,70,105,108,101,70,105,110,100,101,114,46,102,105, + 110,100,95,108,111,97,100,101,114,99,6,0,0,0,0,0, + 0,0,7,0,0,0,6,0,0,0,67,0,0,0,115,26, + 0,0,0,124,1,124,2,124,3,131,2,125,6,116,0,124, + 2,124,3,124,6,124,4,100,1,141,4,83,0,41,2,78, + 41,2,114,122,0,0,0,114,158,0,0,0,41,1,114,169, + 0,0,0,41,7,114,102,0,0,0,114,167,0,0,0,114, + 121,0,0,0,114,35,0,0,0,90,4,115,109,115,108,114, + 181,0,0,0,114,122,0,0,0,114,2,0,0,0,114,2, + 0,0,0,114,4,0,0,0,114,18,1,0,0,71,5,0, + 0,115,6,0,0,0,0,1,10,1,8,1,122,20,70,105, + 108,101,70,105,110,100,101,114,46,95,103,101,116,95,115,112, + 101,99,78,99,3,0,0,0,0,0,0,0,14,0,0,0, + 8,0,0,0,67,0,0,0,115,98,1,0,0,100,1,125, + 3,124,1,160,0,100,2,161,1,100,3,25,0,125,4,122, + 24,116,1,124,0,106,2,112,34,116,3,160,4,161,0,131, + 1,106,5,125,5,87,0,110,24,4,0,116,6,107,10,114, + 66,1,0,1,0,1,0,100,4,125,5,89,0,110,2,88, + 0,124,5,124,0,106,7,107,3,114,92,124,0,160,8,161, + 0,1,0,124,5,124,0,95,7,116,9,131,0,114,114,124, + 0,106,10,125,6,124,4,160,11,161,0,125,7,110,10,124, + 0,106,12,125,6,124,4,125,7,124,7,124,6,107,6,114, + 218,116,13,124,0,106,2,124,4,131,2,125,8,124,0,106, + 14,68,0,93,58,92,2,125,9,125,10,100,5,124,9,23, + 0,125,11,116,13,124,8,124,11,131,2,125,12,116,15,124, + 12,131,1,114,150,124,0,160,16,124,10,124,1,124,12,124, + 8,103,1,124,2,161,5,2,0,1,0,83,0,113,150,116, + 17,124,8,131,1,125,3,124,0,106,14,68,0,93,82,92, + 2,125,9,125,10,116,13,124,0,106,2,124,4,124,9,23, + 0,131,2,125,12,116,18,106,19,100,6,124,12,100,3,100, + 7,141,3,1,0,124,7,124,9,23,0,124,6,107,6,114, + 224,116,15,124,12,131,1,114,224,124,0,160,16,124,10,124, + 1,124,12,100,8,124,2,161,5,2,0,1,0,83,0,113, + 224,124,3,144,1,114,94,116,18,160,19,100,9,124,8,161, + 2,1,0,116,18,160,20,124,1,100,8,161,2,125,13,124, + 8,103,1,124,13,95,21,124,13,83,0,100,8,83,0,41, + 10,122,111,84,114,121,32,116,111,32,102,105,110,100,32,97, + 32,115,112,101,99,32,102,111,114,32,116,104,101,32,115,112, + 101,99,105,102,105,101,100,32,109,111,100,117,108,101,46,10, + 10,32,32,32,32,32,32,32,32,82,101,116,117,114,110,115, + 32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,112, + 101,99,44,32,111,114,32,78,111,110,101,32,105,102,32,110, + 111,116,32,102,111,117,110,100,46,10,32,32,32,32,32,32, + 32,32,70,114,59,0,0,0,114,57,0,0,0,114,89,0, + 0,0,114,186,0,0,0,122,9,116,114,121,105,110,103,32, + 123,125,41,1,90,9,118,101,114,98,111,115,105,116,121,78, + 122,25,112,111,115,115,105,98,108,101,32,110,97,109,101,115, + 112,97,99,101,32,102,111,114,32,123,125,41,22,114,32,0, + 0,0,114,39,0,0,0,114,35,0,0,0,114,1,0,0, + 0,114,45,0,0,0,114,230,0,0,0,114,40,0,0,0, + 114,21,1,0,0,218,11,95,102,105,108,108,95,99,97,99, + 104,101,114,5,0,0,0,114,24,1,0,0,114,90,0,0, + 0,114,23,1,0,0,114,28,0,0,0,114,20,1,0,0, + 114,44,0,0,0,114,18,1,0,0,114,46,0,0,0,114, + 116,0,0,0,114,130,0,0,0,114,162,0,0,0,114,158, + 0,0,0,41,14,114,102,0,0,0,114,121,0,0,0,114, + 181,0,0,0,90,12,105,115,95,110,97,109,101,115,112,97, + 99,101,90,11,116,97,105,108,95,109,111,100,117,108,101,114, + 149,0,0,0,90,5,99,97,99,104,101,90,12,99,97,99, + 104,101,95,109,111,100,117,108,101,90,9,98,97,115,101,95, + 112,97,116,104,114,236,0,0,0,114,167,0,0,0,90,13, + 105,110,105,116,95,102,105,108,101,110,97,109,101,90,9,102, + 117,108,108,95,112,97,116,104,114,166,0,0,0,114,2,0, + 0,0,114,2,0,0,0,114,4,0,0,0,114,182,0,0, + 0,76,5,0,0,115,70,0,0,0,0,5,4,1,14,1, + 2,1,24,1,14,1,10,1,10,1,8,1,6,2,6,1, + 6,1,10,2,6,1,4,2,8,1,12,1,14,1,8,1, + 10,1,8,1,26,4,8,2,14,1,16,1,16,1,12,1, + 8,1,10,1,14,1,6,1,12,1,12,1,8,1,4,1, + 122,20,70,105,108,101,70,105,110,100,101,114,46,102,105,110, + 100,95,115,112,101,99,99,1,0,0,0,0,0,0,0,9, + 0,0,0,10,0,0,0,67,0,0,0,115,190,0,0,0, + 124,0,106,0,125,1,122,22,116,1,160,2,124,1,112,22, + 116,1,160,3,161,0,161,1,125,2,87,0,110,30,4,0, + 116,4,116,5,116,6,102,3,107,10,114,58,1,0,1,0, + 1,0,103,0,125,2,89,0,110,2,88,0,116,7,106,8, + 160,9,100,1,161,1,115,84,116,10,124,2,131,1,124,0, + 95,11,110,74,116,10,131,0,125,3,124,2,68,0,93,56, + 125,4,124,4,160,12,100,2,161,1,92,3,125,5,125,6, + 125,7,124,6,114,136,100,3,160,13,124,5,124,7,160,14, + 161,0,161,2,125,8,110,4,124,5,125,8,124,3,160,15, + 124,8,161,1,1,0,113,94,124,3,124,0,95,11,116,7, + 106,8,160,9,116,16,161,1,114,186,100,4,100,5,132,0, + 124,2,68,0,131,1,124,0,95,17,100,6,83,0,41,7, + 122,68,70,105,108,108,32,116,104,101,32,99,97,99,104,101, + 32,111,102,32,112,111,116,101,110,116,105,97,108,32,109,111, + 100,117,108,101,115,32,97,110,100,32,112,97,99,107,97,103, + 101,115,32,102,111,114,32,116,104,105,115,32,100,105,114,101, + 99,116,111,114,121,46,114,0,0,0,0,114,59,0,0,0, + 122,5,123,125,46,123,125,99,1,0,0,0,0,0,0,0, + 2,0,0,0,4,0,0,0,83,0,0,0,115,20,0,0, + 0,104,0,124,0,93,12,125,1,124,1,160,0,161,0,146, + 2,113,4,83,0,114,2,0,0,0,41,1,114,90,0,0, + 0,41,2,114,22,0,0,0,90,2,102,110,114,2,0,0, + 0,114,2,0,0,0,114,4,0,0,0,250,9,60,115,101, + 116,99,111,109,112,62,153,5,0,0,115,2,0,0,0,6, + 0,122,41,70,105,108,101,70,105,110,100,101,114,46,95,102, + 105,108,108,95,99,97,99,104,101,46,60,108,111,99,97,108, + 115,62,46,60,115,101,116,99,111,109,112,62,78,41,18,114, + 35,0,0,0,114,1,0,0,0,114,227,0,0,0,114,45, + 0,0,0,114,224,0,0,0,218,15,80,101,114,109,105,115, + 115,105,111,110,69,114,114,111,114,218,18,78,111,116,65,68, + 105,114,101,99,116,111,114,121,69,114,114,111,114,114,6,0, + 0,0,114,7,0,0,0,114,8,0,0,0,114,22,1,0, + 0,114,23,1,0,0,114,85,0,0,0,114,48,0,0,0, + 114,90,0,0,0,218,3,97,100,100,114,9,0,0,0,114, + 24,1,0,0,41,9,114,102,0,0,0,114,35,0,0,0, + 114,228,0,0,0,90,21,108,111,119,101,114,95,115,117,102, + 102,105,120,95,99,111,110,116,101,110,116,115,114,1,1,0, + 0,114,100,0,0,0,114,248,0,0,0,114,236,0,0,0, + 90,8,110,101,119,95,110,97,109,101,114,2,0,0,0,114, + 2,0,0,0,114,4,0,0,0,114,26,1,0,0,124,5, + 0,0,115,34,0,0,0,0,2,6,1,2,1,22,1,20, + 3,10,3,12,1,12,7,6,1,8,1,16,1,4,1,18, + 2,4,1,12,1,6,1,12,1,122,22,70,105,108,101,70, + 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, + 101,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, + 0,0,7,0,0,0,115,18,0,0,0,135,0,135,1,102, + 2,100,1,100,2,132,8,125,2,124,2,83,0,41,3,97, + 20,1,0,0,65,32,99,108,97,115,115,32,109,101,116,104, + 111,100,32,119,104,105,99,104,32,114,101,116,117,114,110,115, + 32,97,32,99,108,111,115,117,114,101,32,116,111,32,117,115, + 101,32,111,110,32,115,121,115,46,112,97,116,104,95,104,111, + 111,107,10,32,32,32,32,32,32,32,32,119,104,105,99,104, + 32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32, + 105,110,115,116,97,110,99,101,32,117,115,105,110,103,32,116, + 104,101,32,115,112,101,99,105,102,105,101,100,32,108,111,97, + 100,101,114,115,32,97,110,100,32,116,104,101,32,112,97,116, + 104,10,32,32,32,32,32,32,32,32,99,97,108,108,101,100, + 32,111,110,32,116,104,101,32,99,108,111,115,117,114,101,46, + 10,10,32,32,32,32,32,32,32,32,73,102,32,116,104,101, + 32,112,97,116,104,32,99,97,108,108,101,100,32,111,110,32, + 116,104,101,32,99,108,111,115,117,114,101,32,105,115,32,110, + 111,116,32,97,32,100,105,114,101,99,116,111,114,121,44,32, + 73,109,112,111,114,116,69,114,114,111,114,32,105,115,10,32, + 32,32,32,32,32,32,32,114,97,105,115,101,100,46,10,10, + 32,32,32,32,32,32,32,32,99,1,0,0,0,0,0,0, + 0,1,0,0,0,4,0,0,0,19,0,0,0,115,34,0, + 0,0,116,0,124,0,131,1,115,20,116,1,100,1,124,0, + 100,2,141,2,130,1,136,0,124,0,102,1,136,1,158,2, + 142,0,83,0,41,3,122,45,80,97,116,104,32,104,111,111, + 107,32,102,111,114,32,105,109,112,111,114,116,108,105,98,46, + 109,97,99,104,105,110,101,114,121,46,70,105,108,101,70,105, + 110,100,101,114,46,122,30,111,110,108,121,32,100,105,114,101, + 99,116,111,114,105,101,115,32,97,114,101,32,115,117,112,112, + 111,114,116,101,100,41,1,114,35,0,0,0,41,2,114,46, + 0,0,0,114,101,0,0,0,41,1,114,35,0,0,0,41, + 2,114,172,0,0,0,114,25,1,0,0,114,2,0,0,0, + 114,4,0,0,0,218,24,112,97,116,104,95,104,111,111,107, + 95,102,111,114,95,70,105,108,101,70,105,110,100,101,114,165, + 5,0,0,115,6,0,0,0,0,2,8,1,12,1,122,54, + 70,105,108,101,70,105,110,100,101,114,46,112,97,116,104,95, + 104,111,111,107,46,60,108,111,99,97,108,115,62,46,112,97, + 116,104,95,104,111,111,107,95,102,111,114,95,70,105,108,101, + 70,105,110,100,101,114,114,2,0,0,0,41,3,114,172,0, + 0,0,114,25,1,0,0,114,31,1,0,0,114,2,0,0, + 0,41,2,114,172,0,0,0,114,25,1,0,0,114,4,0, + 0,0,218,9,112,97,116,104,95,104,111,111,107,155,5,0, + 0,115,4,0,0,0,0,10,14,6,122,20,70,105,108,101, + 70,105,110,100,101,114,46,112,97,116,104,95,104,111,111,107, + 99,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0, + 0,67,0,0,0,115,12,0,0,0,100,1,160,0,124,0, + 106,1,161,1,83,0,41,2,78,122,16,70,105,108,101,70, + 105,110,100,101,114,40,123,33,114,125,41,41,2,114,48,0, + 0,0,114,35,0,0,0,41,1,114,102,0,0,0,114,2, + 0,0,0,114,2,0,0,0,114,4,0,0,0,114,0,1, + 0,0,173,5,0,0,115,2,0,0,0,0,1,122,19,70, + 105,108,101,70,105,110,100,101,114,46,95,95,114,101,112,114, + 95,95,41,1,78,41,15,114,107,0,0,0,114,106,0,0, + 0,114,108,0,0,0,114,109,0,0,0,114,186,0,0,0, + 114,6,1,0,0,114,125,0,0,0,114,183,0,0,0,114, + 119,0,0,0,114,18,1,0,0,114,182,0,0,0,114,26, + 1,0,0,114,184,0,0,0,114,32,1,0,0,114,0,1, + 0,0,114,2,0,0,0,114,2,0,0,0,114,2,0,0, + 0,114,4,0,0,0,114,19,1,0,0,30,5,0,0,115, + 18,0,0,0,12,9,8,14,8,4,4,2,8,12,8,5, + 10,48,8,31,12,18,114,19,1,0,0,99,4,0,0,0, + 0,0,0,0,6,0,0,0,8,0,0,0,67,0,0,0, + 115,146,0,0,0,124,0,160,0,100,1,161,1,125,4,124, + 0,160,0,100,2,161,1,125,5,124,4,115,66,124,5,114, + 36,124,5,106,1,125,4,110,30,124,2,124,3,107,2,114, + 56,116,2,124,1,124,2,131,2,125,4,110,10,116,3,124, + 1,124,2,131,2,125,4,124,5,115,84,116,4,124,1,124, + 2,124,4,100,3,141,3,125,5,122,36,124,5,124,0,100, + 2,60,0,124,4,124,0,100,1,60,0,124,2,124,0,100, + 4,60,0,124,3,124,0,100,5,60,0,87,0,110,20,4, + 0,116,5,107,10,114,140,1,0,1,0,1,0,89,0,110, + 2,88,0,100,0,83,0,41,6,78,218,10,95,95,108,111, + 97,100,101,114,95,95,218,8,95,95,115,112,101,99,95,95, + 41,1,114,122,0,0,0,90,8,95,95,102,105,108,101,95, + 95,90,10,95,95,99,97,99,104,101,100,95,95,41,6,218, + 3,103,101,116,114,122,0,0,0,114,234,0,0,0,114,229, + 0,0,0,114,169,0,0,0,218,9,69,120,99,101,112,116, + 105,111,110,41,6,90,2,110,115,114,100,0,0,0,90,8, + 112,97,116,104,110,97,109,101,90,9,99,112,97,116,104,110, + 97,109,101,114,122,0,0,0,114,166,0,0,0,114,2,0, + 0,0,114,2,0,0,0,114,4,0,0,0,218,14,95,102, + 105,120,95,117,112,95,109,111,100,117,108,101,179,5,0,0, + 115,34,0,0,0,0,2,10,1,10,1,4,1,4,1,8, + 1,8,1,12,2,10,1,4,1,14,1,2,1,8,1,8, + 1,8,1,12,1,14,2,114,37,1,0,0,99,0,0,0, + 0,0,0,0,0,3,0,0,0,3,0,0,0,67,0,0, + 0,115,38,0,0,0,116,0,116,1,160,2,161,0,102,2, + 125,0,116,3,116,4,102,2,125,1,116,5,116,6,102,2, + 125,2,124,0,124,1,124,2,103,3,83,0,41,1,122,95, + 82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111, + 102,32,102,105,108,101,45,98,97,115,101,100,32,109,111,100, + 117,108,101,32,108,111,97,100,101,114,115,46,10,10,32,32, + 32,32,69,97,99,104,32,105,116,101,109,32,105,115,32,97, + 32,116,117,112,108,101,32,40,108,111,97,100,101,114,44,32, + 115,117,102,102,105,120,101,115,41,46,10,32,32,32,32,41, + 7,114,235,0,0,0,114,143,0,0,0,218,18,101,120,116, + 101,110,115,105,111,110,95,115,117,102,102,105,120,101,115,114, + 229,0,0,0,114,86,0,0,0,114,234,0,0,0,114,76, + 0,0,0,41,3,90,10,101,120,116,101,110,115,105,111,110, + 115,90,6,115,111,117,114,99,101,90,8,98,121,116,101,99, + 111,100,101,114,2,0,0,0,114,2,0,0,0,114,4,0, + 0,0,114,163,0,0,0,202,5,0,0,115,8,0,0,0, + 0,5,12,1,8,1,8,1,114,163,0,0,0,99,1,0, + 0,0,0,0,0,0,12,0,0,0,9,0,0,0,67,0, + 0,0,115,156,1,0,0,124,0,97,0,116,0,106,1,97, + 1,116,0,106,2,97,2,116,1,106,3,116,4,25,0,125, + 1,100,1,68,0,93,48,125,2,124,2,116,1,106,3,107, + 7,114,56,116,0,160,5,124,2,161,1,125,3,110,10,116, + 1,106,3,124,2,25,0,125,3,116,6,124,1,124,2,124, + 3,131,3,1,0,113,30,100,2,100,3,103,1,102,2,100, + 4,100,5,100,3,103,2,102,2,102,2,125,4,124,4,68, + 0,93,110,92,2,125,5,125,6,116,7,100,6,100,7,132, + 0,124,6,68,0,131,1,131,1,115,136,116,8,130,1,124, + 6,100,8,25,0,125,7,124,5,116,1,106,3,107,6,114, + 170,116,1,106,3,124,5,25,0,125,8,1,0,113,226,113, + 106,122,20,116,0,160,5,124,5,161,1,125,8,87,0,1, + 0,113,226,87,0,113,106,4,0,116,9,107,10,114,214,1, + 0,1,0,1,0,89,0,113,106,89,0,113,106,88,0,113, + 106,116,9,100,9,131,1,130,1,116,6,124,1,100,10,124, + 8,131,3,1,0,116,6,124,1,100,11,124,7,131,3,1, + 0,116,6,124,1,100,12,100,13,160,10,124,6,161,1,131, + 3,1,0,116,0,160,5,100,14,161,1,125,9,116,6,124, + 1,100,14,124,9,131,3,1,0,116,0,160,5,100,15,161, + 1,125,10,116,6,124,1,100,15,124,10,131,3,1,0,124, + 5,100,4,107,2,144,1,114,88,116,0,160,5,100,16,161, + 1,125,11,116,6,124,1,100,17,124,11,131,3,1,0,116, + 6,124,1,100,18,116,11,131,0,131,3,1,0,116,12,160, + 13,116,2,160,14,161,0,161,1,1,0,124,5,100,4,107, + 2,144,1,114,152,116,15,160,16,100,19,161,1,1,0,100, + 20,116,12,107,6,144,1,114,152,100,21,116,17,95,18,100, + 22,83,0,41,23,122,205,83,101,116,117,112,32,116,104,101, + 32,112,97,116,104,45,98,97,115,101,100,32,105,109,112,111, + 114,116,101,114,115,32,102,111,114,32,105,109,112,111,114,116, + 108,105,98,32,98,121,32,105,109,112,111,114,116,105,110,103, + 32,110,101,101,100,101,100,10,32,32,32,32,98,117,105,108, + 116,45,105,110,32,109,111,100,117,108,101,115,32,97,110,100, + 32,105,110,106,101,99,116,105,110,103,32,116,104,101,109,32, + 105,110,116,111,32,116,104,101,32,103,108,111,98,97,108,32, + 110,97,109,101,115,112,97,99,101,46,10,10,32,32,32,32, + 79,116,104,101,114,32,99,111,109,112,111,110,101,110,116,115, + 32,97,114,101,32,101,120,116,114,97,99,116,101,100,32,102, + 114,111,109,32,116,104,101,32,99,111,114,101,32,98,111,111, + 116,115,116,114,97,112,32,109,111,100,117,108,101,46,10,10, + 32,32,32,32,41,4,114,50,0,0,0,114,61,0,0,0, + 218,8,98,117,105,108,116,105,110,115,114,140,0,0,0,90, + 5,112,111,115,105,120,250,1,47,90,2,110,116,250,1,92, + 99,1,0,0,0,0,0,0,0,2,0,0,0,3,0,0, + 0,115,0,0,0,115,26,0,0,0,124,0,93,18,125,1, + 116,0,124,1,131,1,100,0,107,2,86,0,1,0,113,2, + 100,1,83,0,41,2,114,29,0,0,0,78,41,1,114,31, + 0,0,0,41,2,114,22,0,0,0,114,79,0,0,0,114, + 2,0,0,0,114,2,0,0,0,114,4,0,0,0,114,238, + 0,0,0,238,5,0,0,115,2,0,0,0,4,0,122,25, + 95,115,101,116,117,112,46,60,108,111,99,97,108,115,62,46, + 60,103,101,110,101,120,112,114,62,114,60,0,0,0,122,30, + 105,109,112,111,114,116,108,105,98,32,114,101,113,117,105,114, + 101,115,32,112,111,115,105,120,32,111,114,32,110,116,114,1, + 0,0,0,114,25,0,0,0,114,21,0,0,0,114,30,0, + 0,0,90,7,95,116,104,114,101,97,100,90,8,95,119,101, + 97,107,114,101,102,90,6,119,105,110,114,101,103,114,171,0, + 0,0,114,5,0,0,0,122,4,46,112,121,119,122,6,95, + 100,46,112,121,100,84,78,41,19,114,116,0,0,0,114,6, + 0,0,0,114,143,0,0,0,114,250,0,0,0,114,107,0, + 0,0,90,18,95,98,117,105,108,116,105,110,95,102,114,111, + 109,95,110,97,109,101,114,111,0,0,0,218,3,97,108,108, + 114,151,0,0,0,114,101,0,0,0,114,26,0,0,0,114, + 11,0,0,0,114,240,0,0,0,114,147,0,0,0,114,38, + 1,0,0,114,86,0,0,0,114,165,0,0,0,114,170,0, + 0,0,114,174,0,0,0,41,12,218,17,95,98,111,111,116, + 115,116,114,97,112,95,109,111,100,117,108,101,90,11,115,101, + 108,102,95,109,111,100,117,108,101,90,12,98,117,105,108,116, + 105,110,95,110,97,109,101,90,14,98,117,105,108,116,105,110, + 95,109,111,100,117,108,101,90,10,111,115,95,100,101,116,97, + 105,108,115,90,10,98,117,105,108,116,105,110,95,111,115,114, + 21,0,0,0,114,25,0,0,0,90,9,111,115,95,109,111, + 100,117,108,101,90,13,116,104,114,101,97,100,95,109,111,100, + 117,108,101,90,14,119,101,97,107,114,101,102,95,109,111,100, + 117,108,101,90,13,119,105,110,114,101,103,95,109,111,100,117, + 108,101,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,218,6,95,115,101,116,117,112,213,5,0,0,115,76,0, + 0,0,0,8,4,1,6,1,6,3,10,1,8,1,10,1, + 12,2,10,1,14,3,22,1,12,2,22,1,8,1,10,1, + 10,1,6,2,2,1,10,1,10,1,14,1,12,2,8,1, + 12,1,12,1,18,3,10,1,12,3,10,1,12,3,10,1, + 10,1,12,3,14,1,14,1,10,1,10,1,10,1,114,44, + 1,0,0,99,1,0,0,0,0,0,0,0,2,0,0,0, + 4,0,0,0,67,0,0,0,115,50,0,0,0,116,0,124, + 0,131,1,1,0,116,1,131,0,125,1,116,2,106,3,160, + 4,116,5,106,6,124,1,142,0,103,1,161,1,1,0,116, + 2,106,7,160,8,116,9,161,1,1,0,100,1,83,0,41, + 2,122,41,73,110,115,116,97,108,108,32,116,104,101,32,112, + 97,116,104,45,98,97,115,101,100,32,105,109,112,111,114,116, + 32,99,111,109,112,111,110,101,110,116,115,46,78,41,10,114, + 44,1,0,0,114,163,0,0,0,114,6,0,0,0,114,11, + 1,0,0,114,147,0,0,0,114,19,1,0,0,114,32,1, + 0,0,218,9,109,101,116,97,95,112,97,116,104,114,165,0, + 0,0,114,5,1,0,0,41,2,114,43,1,0,0,90,17, + 115,117,112,112,111,114,116,101,100,95,108,111,97,100,101,114, + 115,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, + 218,8,95,105,110,115,116,97,108,108,21,6,0,0,115,8, + 0,0,0,0,2,8,1,6,1,20,1,114,46,1,0,0, + 41,1,114,47,0,0,0,41,1,78,41,3,78,78,78,41, + 2,114,60,0,0,0,114,60,0,0,0,41,1,84,41,1, + 78,41,1,78,41,61,114,109,0,0,0,114,10,0,0,0, + 90,37,95,67,65,83,69,95,73,78,83,69,78,83,73,84, + 73,86,69,95,80,76,65,84,70,79,82,77,83,95,66,89, + 84,69,83,95,75,69,89,114,9,0,0,0,114,11,0,0, + 0,114,17,0,0,0,114,19,0,0,0,114,28,0,0,0, + 114,38,0,0,0,114,39,0,0,0,114,43,0,0,0,114, + 44,0,0,0,114,46,0,0,0,114,56,0,0,0,218,4, + 116,121,112,101,218,8,95,95,99,111,100,101,95,95,114,142, + 0,0,0,114,15,0,0,0,114,129,0,0,0,114,14,0, + 0,0,114,18,0,0,0,114,209,0,0,0,114,75,0,0, + 0,114,74,0,0,0,114,86,0,0,0,114,76,0,0,0, + 90,23,68,69,66,85,71,95,66,89,84,69,67,79,68,69, + 95,83,85,70,70,73,88,69,83,90,27,79,80,84,73,77, + 73,90,69,68,95,66,89,84,69,67,79,68,69,95,83,85, + 70,70,73,88,69,83,114,81,0,0,0,114,87,0,0,0, + 114,93,0,0,0,114,97,0,0,0,114,99,0,0,0,114, + 118,0,0,0,114,125,0,0,0,114,133,0,0,0,114,137, + 0,0,0,114,139,0,0,0,114,145,0,0,0,114,150,0, + 0,0,114,152,0,0,0,114,157,0,0,0,218,6,111,98, + 106,101,99,116,114,164,0,0,0,114,169,0,0,0,114,170, + 0,0,0,114,185,0,0,0,114,195,0,0,0,114,212,0, + 0,0,114,229,0,0,0,114,234,0,0,0,114,240,0,0, + 0,114,235,0,0,0,114,241,0,0,0,114,3,1,0,0, + 114,5,1,0,0,114,19,1,0,0,114,37,1,0,0,114, + 163,0,0,0,114,44,1,0,0,114,46,1,0,0,114,2, + 0,0,0,114,2,0,0,0,114,2,0,0,0,114,4,0, + 0,0,218,8,60,109,111,100,117,108,101,62,23,0,0,0, + 115,118,0,0,0,4,0,4,1,4,1,2,1,6,3,8, + 17,8,5,8,5,8,6,8,12,8,10,8,9,8,5,8, + 7,10,22,10,127,0,5,16,1,12,2,4,1,4,2,6, + 2,6,2,8,2,16,45,8,34,8,19,8,12,8,12,8, + 28,8,17,8,33,8,28,8,24,10,13,10,10,10,11,8, + 14,6,3,4,1,14,67,14,64,14,29,16,127,0,17,14, + 68,18,45,18,26,4,3,18,53,14,60,14,42,14,127,0, + 7,14,127,0,22,10,23,8,11,8,64, }; From webhook-mailer at python.org Fri Apr 6 20:02:21 2018 From: webhook-mailer at python.org (Brett Cannon) Date: Sat, 07 Apr 2018 00:02:21 -0000 Subject: [Python-checkins] [3.7] bpo-33169: Remove values of `None` from sys.path_importer_cache when invalidating caches (GH-6402) (GH-6403) Message-ID: https://github.com/python/cpython/commit/a09bb87c1eebb07b01b8105cf536704893aec565 commit: a09bb87c1eebb07b01b8105cf536704893aec565 branch: 3.7 author: Brett Cannon committer: GitHub date: 2018-04-06T17:02:18-07:00 summary: [3.7] bpo-33169: Remove values of `None` from sys.path_importer_cache when invalidating caches (GH-6402) (GH-6403) An entry of None in sys.path_importer_cache represents a negative/missing finder for a path, so clearing it out makes sense. (cherry picked from commit 9e2be60634914f23db2ae5624e4acc9335bf5fea) files: A Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst M Doc/library/importlib.rst M Doc/whatsnew/3.7.rst M Lib/importlib/_bootstrap_external.py M Lib/test/test_importlib/import_/test_path.py M Lib/test/test_importlib/test_api.py M Python/importlib_external.h diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index f9387c07e18c..130aabf119a6 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1081,7 +1081,12 @@ find and load modules. .. classmethod:: invalidate_caches() Calls :meth:`importlib.abc.PathEntryFinder.invalidate_caches` on all - finders stored in :attr:`sys.path_importer_cache`. + finders stored in :data:`sys.path_importer_cache` that define the method. + Otherwise entries in :data:`sys.path_importer_cache` set to ``None`` are + deleted. + + .. versionchanged:: 3.7 + Entries of ``None`` in :data:`sys.path_importer_cache` are deleted. .. versionchanged:: 3.4 Calls objects in :data:`sys.path_hooks` with the current working diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 1f524884adae..08c7b12574c6 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -561,7 +561,7 @@ importlib --------- The :class:`importlib.abc.ResourceReader` ABC was introduced to -support the loading of resource from packages. +support the loading of resources from packages. locale ------ @@ -1274,6 +1274,11 @@ Changes in the Python API previous behaviour, or use :attr:`STARTUPINFO.lpAttributeList `. +* :meth:`importlib.machinery.PathFinder.invalidate_caches` -- which implicitly + affects :func:`importlib.invalidate_caches` -- now deletes entries + in :data:`sys.path_importer_cache` which are set to ``None``. + (Contributed by Brett Cannon in :issue:`33169`.) + Changes in the C API -------------------- diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index e2951746835e..490f20db49c6 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -1179,8 +1179,10 @@ class PathFinder: def invalidate_caches(cls): """Call the invalidate_caches() method on all path entry finders stored in sys.path_importer_caches (where implemented).""" - for finder in sys.path_importer_cache.values(): - if hasattr(finder, 'invalidate_caches'): + for name, finder in list(sys.path_importer_cache.items()): + if finder is None: + del sys.path_importer_cache[name] + elif hasattr(finder, 'invalidate_caches'): finder.invalidate_caches() @classmethod diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py index 7aa26b0eee74..18c81dda45c8 100644 --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -184,6 +184,27 @@ def test_deleted_cwd(self): # Do not want FileNotFoundError raised. self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) + def test_invalidate_caches_finders(self): + # Finders with an invalidate_caches() method have it called. + class FakeFinder: + def __init__(self): + self.called = False + + def invalidate_caches(self): + self.called = True + + cache = {'leave_alone': object(), 'finder_to_invalidate': FakeFinder()} + with util.import_state(path_importer_cache=cache): + self.machinery.PathFinder.invalidate_caches() + self.assertTrue(cache['finder_to_invalidate'].called) + + def test_invalidate_caches_clear_out_None(self): + # Clear out None in sys.path_importer_cache() when invalidating caches. + cache = {'clear_out': None} + with util.import_state(path_importer_cache=cache): + self.machinery.PathFinder.invalidate_caches() + self.assertEqual(len(cache), 0) + class FindModuleTests(FinderTests): def find(self, *args, **kwargs): diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 8beb4244eac8..edb745c2cd49 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -406,7 +406,7 @@ def test_method_lacking(self): # There should be no issues if the method is not defined. key = 'gobbledeegook' sys.path_importer_cache[key] = None - self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key)) + self.addCleanup(lambda: sys.path_importer_cache.pop(key, None)) self.init.invalidate_caches() # Shouldn't trigger an exception. diff --git a/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst b/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst new file mode 100644 index 000000000000..b5bacfcb5732 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-06-14-56-26.bpo-33169.ByhDqb.rst @@ -0,0 +1,2 @@ +Delete entries of ``None`` in :data:`sys.path_importer_cache` when +:meth:`importlib.machinery.invalidate_caches` is called. diff --git a/Python/importlib_external.h b/Python/importlib_external.h index 7dd82492ef32..273188bfb8e7 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -1988,623 +1988,626 @@ const unsigned char _Py_M__importlib_external[] = { 114,32,115,121,115,46,112,97,116,104,32,97,110,100,32,112, 97,99,107,97,103,101,32,95,95,112,97,116,104,95,95,32, 97,116,116,114,105,98,117,116,101,115,46,99,1,0,0,0, - 0,0,0,0,2,0,0,0,4,0,0,0,67,0,0,0, - 115,42,0,0,0,120,36,116,0,106,1,160,2,161,0,68, - 0,93,22,125,1,116,3,124,1,100,1,131,2,114,12,124, - 1,160,4,161,0,1,0,113,12,87,0,100,2,83,0,41, - 3,122,125,67,97,108,108,32,116,104,101,32,105,110,118,97, - 108,105,100,97,116,101,95,99,97,99,104,101,115,40,41,32, - 109,101,116,104,111,100,32,111,110,32,97,108,108,32,112,97, - 116,104,32,101,110,116,114,121,32,102,105,110,100,101,114,115, - 10,32,32,32,32,32,32,32,32,115,116,111,114,101,100,32, - 105,110,32,115,121,115,46,112,97,116,104,95,105,109,112,111, - 114,116,101,114,95,99,97,99,104,101,115,32,40,119,104,101, - 114,101,32,105,109,112,108,101,109,101,110,116,101,100,41,46, - 218,17,105,110,118,97,108,105,100,97,116,101,95,99,97,99, - 104,101,115,78,41,5,114,6,0,0,0,218,19,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 218,6,118,97,108,117,101,115,114,110,0,0,0,114,6,1, - 0,0,41,2,114,172,0,0,0,218,6,102,105,110,100,101, - 114,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, - 114,6,1,0,0,154,4,0,0,115,6,0,0,0,0,4, - 16,1,10,1,122,28,80,97,116,104,70,105,110,100,101,114, - 46,105,110,118,97,108,105,100,97,116,101,95,99,97,99,104, - 101,115,99,2,0,0,0,0,0,0,0,3,0,0,0,9, - 0,0,0,67,0,0,0,115,84,0,0,0,116,0,106,1, - 100,1,107,9,114,28,116,0,106,1,115,28,116,2,160,3, - 100,2,116,4,161,2,1,0,120,50,116,0,106,1,68,0, - 93,36,125,2,121,8,124,2,124,1,131,1,83,0,4,0, - 116,5,107,10,114,70,1,0,1,0,1,0,119,36,89,0, - 113,36,88,0,113,36,87,0,100,1,83,0,100,1,83,0, - 41,3,122,46,83,101,97,114,99,104,32,115,121,115,46,112, - 97,116,104,95,104,111,111,107,115,32,102,111,114,32,97,32, - 102,105,110,100,101,114,32,102,111,114,32,39,112,97,116,104, - 39,46,78,122,23,115,121,115,46,112,97,116,104,95,104,111, - 111,107,115,32,105,115,32,101,109,112,116,121,41,6,114,6, - 0,0,0,218,10,112,97,116,104,95,104,111,111,107,115,114, - 61,0,0,0,114,62,0,0,0,114,120,0,0,0,114,101, - 0,0,0,41,3,114,172,0,0,0,114,35,0,0,0,90, - 4,104,111,111,107,114,2,0,0,0,114,2,0,0,0,114, - 4,0,0,0,218,11,95,112,97,116,104,95,104,111,111,107, - 115,162,4,0,0,115,16,0,0,0,0,3,16,1,12,1, - 12,1,2,1,8,1,14,1,12,2,122,22,80,97,116,104, - 70,105,110,100,101,114,46,95,112,97,116,104,95,104,111,111, - 107,115,99,2,0,0,0,0,0,0,0,3,0,0,0,8, - 0,0,0,67,0,0,0,115,102,0,0,0,124,1,100,1, - 107,2,114,42,121,12,116,0,160,1,161,0,125,1,87,0, - 110,20,4,0,116,2,107,10,114,40,1,0,1,0,1,0, - 100,2,83,0,88,0,121,14,116,3,106,4,124,1,25,0, - 125,2,87,0,110,40,4,0,116,5,107,10,114,96,1,0, - 1,0,1,0,124,0,160,6,124,1,161,1,125,2,124,2, - 116,3,106,4,124,1,60,0,89,0,110,2,88,0,124,2, - 83,0,41,3,122,210,71,101,116,32,116,104,101,32,102,105, - 110,100,101,114,32,102,111,114,32,116,104,101,32,112,97,116, - 104,32,101,110,116,114,121,32,102,114,111,109,32,115,121,115, + 0,0,0,0,3,0,0,0,4,0,0,0,67,0,0,0, + 115,68,0,0,0,120,62,116,0,116,1,106,2,160,3,161, + 0,131,1,68,0,93,44,92,2,125,1,125,2,124,2,100, + 1,107,8,114,42,116,1,106,2,124,1,61,0,113,16,116, + 4,124,2,100,2,131,2,114,16,124,2,160,5,161,0,1, + 0,113,16,87,0,100,1,83,0,41,3,122,125,67,97,108, + 108,32,116,104,101,32,105,110,118,97,108,105,100,97,116,101, + 95,99,97,99,104,101,115,40,41,32,109,101,116,104,111,100, + 32,111,110,32,97,108,108,32,112,97,116,104,32,101,110,116, + 114,121,32,102,105,110,100,101,114,115,10,32,32,32,32,32, + 32,32,32,115,116,111,114,101,100,32,105,110,32,115,121,115, 46,112,97,116,104,95,105,109,112,111,114,116,101,114,95,99, - 97,99,104,101,46,10,10,32,32,32,32,32,32,32,32,73, - 102,32,116,104,101,32,112,97,116,104,32,101,110,116,114,121, - 32,105,115,32,110,111,116,32,105,110,32,116,104,101,32,99, - 97,99,104,101,44,32,102,105,110,100,32,116,104,101,32,97, - 112,112,114,111,112,114,105,97,116,101,32,102,105,110,100,101, - 114,10,32,32,32,32,32,32,32,32,97,110,100,32,99,97, - 99,104,101,32,105,116,46,32,73,102,32,110,111,32,102,105, - 110,100,101,114,32,105,115,32,97,118,97,105,108,97,98,108, - 101,44,32,115,116,111,114,101,32,78,111,110,101,46,10,10, - 32,32,32,32,32,32,32,32,114,30,0,0,0,78,41,7, - 114,1,0,0,0,114,45,0,0,0,114,224,0,0,0,114, - 6,0,0,0,114,7,1,0,0,218,8,75,101,121,69,114, - 114,111,114,114,11,1,0,0,41,3,114,172,0,0,0,114, - 35,0,0,0,114,9,1,0,0,114,2,0,0,0,114,2, - 0,0,0,114,4,0,0,0,218,20,95,112,97,116,104,95, - 105,109,112,111,114,116,101,114,95,99,97,99,104,101,175,4, - 0,0,115,22,0,0,0,0,8,8,1,2,1,12,1,14, - 3,6,1,2,1,14,1,14,1,10,1,16,1,122,31,80, - 97,116,104,70,105,110,100,101,114,46,95,112,97,116,104,95, - 105,109,112,111,114,116,101,114,95,99,97,99,104,101,99,3, - 0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,67, - 0,0,0,115,82,0,0,0,116,0,124,2,100,1,131,2, - 114,26,124,2,160,1,124,1,161,1,92,2,125,3,125,4, - 110,14,124,2,160,2,124,1,161,1,125,3,103,0,125,4, - 124,3,100,0,107,9,114,60,116,3,160,4,124,1,124,3, - 161,2,83,0,116,3,160,5,124,1,100,0,161,2,125,5, - 124,4,124,5,95,6,124,5,83,0,41,2,78,114,119,0, - 0,0,41,7,114,110,0,0,0,114,119,0,0,0,114,183, - 0,0,0,114,116,0,0,0,114,180,0,0,0,114,162,0, - 0,0,114,158,0,0,0,41,6,114,172,0,0,0,114,121, - 0,0,0,114,9,1,0,0,114,122,0,0,0,114,123,0, - 0,0,114,166,0,0,0,114,2,0,0,0,114,2,0,0, - 0,114,4,0,0,0,218,16,95,108,101,103,97,99,121,95, - 103,101,116,95,115,112,101,99,197,4,0,0,115,18,0,0, - 0,0,4,10,1,16,2,10,1,4,1,8,1,12,1,12, - 1,6,1,122,27,80,97,116,104,70,105,110,100,101,114,46, + 97,99,104,101,115,32,40,119,104,101,114,101,32,105,109,112, + 108,101,109,101,110,116,101,100,41,46,78,218,17,105,110,118, + 97,108,105,100,97,116,101,95,99,97,99,104,101,115,41,6, + 218,4,108,105,115,116,114,6,0,0,0,218,19,112,97,116, + 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, + 218,5,105,116,101,109,115,114,110,0,0,0,114,6,1,0, + 0,41,3,114,172,0,0,0,114,100,0,0,0,218,6,102, + 105,110,100,101,114,114,2,0,0,0,114,2,0,0,0,114, + 4,0,0,0,114,6,1,0,0,154,4,0,0,115,10,0, + 0,0,0,4,24,1,8,1,10,1,10,1,122,28,80,97, + 116,104,70,105,110,100,101,114,46,105,110,118,97,108,105,100, + 97,116,101,95,99,97,99,104,101,115,99,2,0,0,0,0, + 0,0,0,3,0,0,0,9,0,0,0,67,0,0,0,115, + 84,0,0,0,116,0,106,1,100,1,107,9,114,28,116,0, + 106,1,115,28,116,2,160,3,100,2,116,4,161,2,1,0, + 120,50,116,0,106,1,68,0,93,36,125,2,121,8,124,2, + 124,1,131,1,83,0,4,0,116,5,107,10,114,70,1,0, + 1,0,1,0,119,36,89,0,113,36,88,0,113,36,87,0, + 100,1,83,0,100,1,83,0,41,3,122,46,83,101,97,114, + 99,104,32,115,121,115,46,112,97,116,104,95,104,111,111,107, + 115,32,102,111,114,32,97,32,102,105,110,100,101,114,32,102, + 111,114,32,39,112,97,116,104,39,46,78,122,23,115,121,115, + 46,112,97,116,104,95,104,111,111,107,115,32,105,115,32,101, + 109,112,116,121,41,6,114,6,0,0,0,218,10,112,97,116, + 104,95,104,111,111,107,115,114,61,0,0,0,114,62,0,0, + 0,114,120,0,0,0,114,101,0,0,0,41,3,114,172,0, + 0,0,114,35,0,0,0,90,4,104,111,111,107,114,2,0, + 0,0,114,2,0,0,0,114,4,0,0,0,218,11,95,112, + 97,116,104,95,104,111,111,107,115,164,4,0,0,115,16,0, + 0,0,0,3,16,1,12,1,12,1,2,1,8,1,14,1, + 12,2,122,22,80,97,116,104,70,105,110,100,101,114,46,95, + 112,97,116,104,95,104,111,111,107,115,99,2,0,0,0,0, + 0,0,0,3,0,0,0,8,0,0,0,67,0,0,0,115, + 102,0,0,0,124,1,100,1,107,2,114,42,121,12,116,0, + 160,1,161,0,125,1,87,0,110,20,4,0,116,2,107,10, + 114,40,1,0,1,0,1,0,100,2,83,0,88,0,121,14, + 116,3,106,4,124,1,25,0,125,2,87,0,110,40,4,0, + 116,5,107,10,114,96,1,0,1,0,1,0,124,0,160,6, + 124,1,161,1,125,2,124,2,116,3,106,4,124,1,60,0, + 89,0,110,2,88,0,124,2,83,0,41,3,122,210,71,101, + 116,32,116,104,101,32,102,105,110,100,101,114,32,102,111,114, + 32,116,104,101,32,112,97,116,104,32,101,110,116,114,121,32, + 102,114,111,109,32,115,121,115,46,112,97,116,104,95,105,109, + 112,111,114,116,101,114,95,99,97,99,104,101,46,10,10,32, + 32,32,32,32,32,32,32,73,102,32,116,104,101,32,112,97, + 116,104,32,101,110,116,114,121,32,105,115,32,110,111,116,32, + 105,110,32,116,104,101,32,99,97,99,104,101,44,32,102,105, + 110,100,32,116,104,101,32,97,112,112,114,111,112,114,105,97, + 116,101,32,102,105,110,100,101,114,10,32,32,32,32,32,32, + 32,32,97,110,100,32,99,97,99,104,101,32,105,116,46,32, + 73,102,32,110,111,32,102,105,110,100,101,114,32,105,115,32, + 97,118,97,105,108,97,98,108,101,44,32,115,116,111,114,101, + 32,78,111,110,101,46,10,10,32,32,32,32,32,32,32,32, + 114,30,0,0,0,78,41,7,114,1,0,0,0,114,45,0, + 0,0,114,224,0,0,0,114,6,0,0,0,114,8,1,0, + 0,218,8,75,101,121,69,114,114,111,114,114,12,1,0,0, + 41,3,114,172,0,0,0,114,35,0,0,0,114,10,1,0, + 0,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, + 218,20,95,112,97,116,104,95,105,109,112,111,114,116,101,114, + 95,99,97,99,104,101,177,4,0,0,115,22,0,0,0,0, + 8,8,1,2,1,12,1,14,3,6,1,2,1,14,1,14, + 1,10,1,16,1,122,31,80,97,116,104,70,105,110,100,101, + 114,46,95,112,97,116,104,95,105,109,112,111,114,116,101,114, + 95,99,97,99,104,101,99,3,0,0,0,0,0,0,0,6, + 0,0,0,4,0,0,0,67,0,0,0,115,82,0,0,0, + 116,0,124,2,100,1,131,2,114,26,124,2,160,1,124,1, + 161,1,92,2,125,3,125,4,110,14,124,2,160,2,124,1, + 161,1,125,3,103,0,125,4,124,3,100,0,107,9,114,60, + 116,3,160,4,124,1,124,3,161,2,83,0,116,3,160,5, + 124,1,100,0,161,2,125,5,124,4,124,5,95,6,124,5, + 83,0,41,2,78,114,119,0,0,0,41,7,114,110,0,0, + 0,114,119,0,0,0,114,183,0,0,0,114,116,0,0,0, + 114,180,0,0,0,114,162,0,0,0,114,158,0,0,0,41, + 6,114,172,0,0,0,114,121,0,0,0,114,10,1,0,0, + 114,122,0,0,0,114,123,0,0,0,114,166,0,0,0,114, + 2,0,0,0,114,2,0,0,0,114,4,0,0,0,218,16, 95,108,101,103,97,99,121,95,103,101,116,95,115,112,101,99, - 78,99,4,0,0,0,0,0,0,0,9,0,0,0,5,0, - 0,0,67,0,0,0,115,170,0,0,0,103,0,125,4,120, - 160,124,2,68,0,93,130,125,5,116,0,124,5,116,1,116, - 2,102,2,131,2,115,30,113,10,124,0,160,3,124,5,161, - 1,125,6,124,6,100,1,107,9,114,10,116,4,124,6,100, - 2,131,2,114,72,124,6,160,5,124,1,124,3,161,2,125, - 7,110,12,124,0,160,6,124,1,124,6,161,2,125,7,124, - 7,100,1,107,8,114,94,113,10,124,7,106,7,100,1,107, - 9,114,108,124,7,83,0,124,7,106,8,125,8,124,8,100, - 1,107,8,114,130,116,9,100,3,131,1,130,1,124,4,160, - 10,124,8,161,1,1,0,113,10,87,0,116,11,160,12,124, - 1,100,1,161,2,125,7,124,4,124,7,95,8,124,7,83, - 0,100,1,83,0,41,4,122,63,70,105,110,100,32,116,104, - 101,32,108,111,97,100,101,114,32,111,114,32,110,97,109,101, - 115,112,97,99,101,95,112,97,116,104,32,102,111,114,32,116, - 104,105,115,32,109,111,100,117,108,101,47,112,97,99,107,97, - 103,101,32,110,97,109,101,46,78,114,182,0,0,0,122,19, - 115,112,101,99,32,109,105,115,115,105,110,103,32,108,111,97, - 100,101,114,41,13,114,141,0,0,0,114,71,0,0,0,218, - 5,98,121,116,101,115,114,13,1,0,0,114,110,0,0,0, - 114,182,0,0,0,114,14,1,0,0,114,122,0,0,0,114, - 158,0,0,0,114,101,0,0,0,114,147,0,0,0,114,116, - 0,0,0,114,162,0,0,0,41,9,114,172,0,0,0,114, - 121,0,0,0,114,35,0,0,0,114,181,0,0,0,218,14, - 110,97,109,101,115,112,97,99,101,95,112,97,116,104,90,5, - 101,110,116,114,121,114,9,1,0,0,114,166,0,0,0,114, - 123,0,0,0,114,2,0,0,0,114,2,0,0,0,114,4, - 0,0,0,218,9,95,103,101,116,95,115,112,101,99,212,4, - 0,0,115,40,0,0,0,0,5,4,1,10,1,14,1,2, - 1,10,1,8,1,10,1,14,2,12,1,8,1,2,1,10, - 1,4,1,6,1,8,1,8,5,14,2,12,1,6,1,122, - 20,80,97,116,104,70,105,110,100,101,114,46,95,103,101,116, - 95,115,112,101,99,99,4,0,0,0,0,0,0,0,6,0, - 0,0,5,0,0,0,67,0,0,0,115,100,0,0,0,124, - 2,100,1,107,8,114,14,116,0,106,1,125,2,124,0,160, - 2,124,1,124,2,124,3,161,3,125,4,124,4,100,1,107, - 8,114,40,100,1,83,0,124,4,106,3,100,1,107,8,114, - 92,124,4,106,4,125,5,124,5,114,86,100,1,124,4,95, - 5,116,6,124,1,124,5,124,0,106,2,131,3,124,4,95, - 4,124,4,83,0,100,1,83,0,110,4,124,4,83,0,100, - 1,83,0,41,2,122,141,84,114,121,32,116,111,32,102,105, - 110,100,32,97,32,115,112,101,99,32,102,111,114,32,39,102, - 117,108,108,110,97,109,101,39,32,111,110,32,115,121,115,46, - 112,97,116,104,32,111,114,32,39,112,97,116,104,39,46,10, - 10,32,32,32,32,32,32,32,32,84,104,101,32,115,101,97, - 114,99,104,32,105,115,32,98,97,115,101,100,32,111,110,32, - 115,121,115,46,112,97,116,104,95,104,111,111,107,115,32,97, - 110,100,32,115,121,115,46,112,97,116,104,95,105,109,112,111, - 114,116,101,114,95,99,97,99,104,101,46,10,32,32,32,32, - 32,32,32,32,78,41,7,114,6,0,0,0,114,35,0,0, - 0,114,17,1,0,0,114,122,0,0,0,114,158,0,0,0, - 114,160,0,0,0,114,241,0,0,0,41,6,114,172,0,0, - 0,114,121,0,0,0,114,35,0,0,0,114,181,0,0,0, - 114,166,0,0,0,114,16,1,0,0,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,114,182,0,0,0,244,4, - 0,0,115,26,0,0,0,0,6,8,1,6,1,14,1,8, - 1,4,1,10,1,6,1,4,3,6,1,16,1,4,2,6, - 2,122,20,80,97,116,104,70,105,110,100,101,114,46,102,105, - 110,100,95,115,112,101,99,99,3,0,0,0,0,0,0,0, - 4,0,0,0,4,0,0,0,67,0,0,0,115,30,0,0, - 0,124,0,160,0,124,1,124,2,161,2,125,3,124,3,100, - 1,107,8,114,24,100,1,83,0,124,3,106,1,83,0,41, - 2,122,170,102,105,110,100,32,116,104,101,32,109,111,100,117, - 108,101,32,111,110,32,115,121,115,46,112,97,116,104,32,111, - 114,32,39,112,97,116,104,39,32,98,97,115,101,100,32,111, - 110,32,115,121,115,46,112,97,116,104,95,104,111,111,107,115, - 32,97,110,100,10,32,32,32,32,32,32,32,32,115,121,115, - 46,112,97,116,104,95,105,109,112,111,114,116,101,114,95,99, - 97,99,104,101,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,102, - 105,110,100,95,115,112,101,99,40,41,32,105,110,115,116,101, - 97,100,46,10,10,32,32,32,32,32,32,32,32,78,41,2, - 114,182,0,0,0,114,122,0,0,0,41,4,114,172,0,0, - 0,114,121,0,0,0,114,35,0,0,0,114,166,0,0,0, - 114,2,0,0,0,114,2,0,0,0,114,4,0,0,0,114, - 183,0,0,0,12,5,0,0,115,8,0,0,0,0,8,12, - 1,8,1,4,1,122,22,80,97,116,104,70,105,110,100,101, - 114,46,102,105,110,100,95,109,111,100,117,108,101,41,1,78, - 41,2,78,78,41,1,78,41,12,114,107,0,0,0,114,106, - 0,0,0,114,108,0,0,0,114,109,0,0,0,114,184,0, - 0,0,114,6,1,0,0,114,11,1,0,0,114,13,1,0, - 0,114,14,1,0,0,114,17,1,0,0,114,182,0,0,0, - 114,183,0,0,0,114,2,0,0,0,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,114,5,1,0,0,150,4, - 0,0,115,20,0,0,0,12,4,12,8,12,13,12,22,12, - 15,2,1,12,31,2,1,12,23,2,1,114,5,1,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0, - 0,64,0,0,0,115,90,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,100,2,100,3,132,0,90,4,100,4, - 100,5,132,0,90,5,101,6,90,7,100,6,100,7,132,0, - 90,8,100,8,100,9,132,0,90,9,100,19,100,11,100,12, - 132,1,90,10,100,13,100,14,132,0,90,11,101,12,100,15, - 100,16,132,0,131,1,90,13,100,17,100,18,132,0,90,14, - 100,10,83,0,41,20,218,10,70,105,108,101,70,105,110,100, - 101,114,122,172,70,105,108,101,45,98,97,115,101,100,32,102, - 105,110,100,101,114,46,10,10,32,32,32,32,73,110,116,101, - 114,97,99,116,105,111,110,115,32,119,105,116,104,32,116,104, - 101,32,102,105,108,101,32,115,121,115,116,101,109,32,97,114, - 101,32,99,97,99,104,101,100,32,102,111,114,32,112,101,114, - 102,111,114,109,97,110,99,101,44,32,98,101,105,110,103,10, - 32,32,32,32,114,101,102,114,101,115,104,101,100,32,119,104, - 101,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121, - 32,116,104,101,32,102,105,110,100,101,114,32,105,115,32,104, - 97,110,100,108,105,110,103,32,104,97,115,32,98,101,101,110, - 32,109,111,100,105,102,105,101,100,46,10,10,32,32,32,32, - 99,2,0,0,0,0,0,0,0,5,0,0,0,6,0,0, - 0,7,0,0,0,115,88,0,0,0,103,0,125,3,120,40, - 124,2,68,0,93,32,92,2,137,0,125,4,124,3,160,0, - 135,0,102,1,100,1,100,2,132,8,124,4,68,0,131,1, - 161,1,1,0,113,10,87,0,124,3,124,0,95,1,124,1, - 112,58,100,3,124,0,95,2,100,4,124,0,95,3,116,4, - 131,0,124,0,95,5,116,4,131,0,124,0,95,6,100,5, - 83,0,41,6,122,154,73,110,105,116,105,97,108,105,122,101, - 32,119,105,116,104,32,116,104,101,32,112,97,116,104,32,116, - 111,32,115,101,97,114,99,104,32,111,110,32,97,110,100,32, - 97,32,118,97,114,105,97,98,108,101,32,110,117,109,98,101, - 114,32,111,102,10,32,32,32,32,32,32,32,32,50,45,116, - 117,112,108,101,115,32,99,111,110,116,97,105,110,105,110,103, - 32,116,104,101,32,108,111,97,100,101,114,32,97,110,100,32, - 116,104,101,32,102,105,108,101,32,115,117,102,102,105,120,101, - 115,32,116,104,101,32,108,111,97,100,101,114,10,32,32,32, - 32,32,32,32,32,114,101,99,111,103,110,105,122,101,115,46, - 99,1,0,0,0,0,0,0,0,2,0,0,0,3,0,0, - 0,51,0,0,0,115,22,0,0,0,124,0,93,14,125,1, - 124,1,136,0,102,2,86,0,1,0,113,2,100,0,83,0, - 41,1,78,114,2,0,0,0,41,2,114,22,0,0,0,114, - 236,0,0,0,41,1,114,122,0,0,0,114,2,0,0,0, - 114,4,0,0,0,114,238,0,0,0,41,5,0,0,115,2, - 0,0,0,4,0,122,38,70,105,108,101,70,105,110,100,101, - 114,46,95,95,105,110,105,116,95,95,46,60,108,111,99,97, - 108,115,62,46,60,103,101,110,101,120,112,114,62,114,59,0, - 0,0,114,89,0,0,0,78,41,7,114,147,0,0,0,218, - 8,95,108,111,97,100,101,114,115,114,35,0,0,0,218,11, - 95,112,97,116,104,95,109,116,105,109,101,218,3,115,101,116, - 218,11,95,112,97,116,104,95,99,97,99,104,101,218,19,95, - 114,101,108,97,120,101,100,95,112,97,116,104,95,99,97,99, - 104,101,41,5,114,102,0,0,0,114,35,0,0,0,218,14, - 108,111,97,100,101,114,95,100,101,116,97,105,108,115,90,7, - 108,111,97,100,101,114,115,114,168,0,0,0,114,2,0,0, - 0,41,1,114,122,0,0,0,114,4,0,0,0,114,186,0, - 0,0,35,5,0,0,115,16,0,0,0,0,4,4,1,14, - 1,28,1,6,2,10,1,6,1,8,1,122,19,70,105,108, - 101,70,105,110,100,101,114,46,95,95,105,110,105,116,95,95, - 99,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0, - 0,67,0,0,0,115,10,0,0,0,100,1,124,0,95,0, - 100,2,83,0,41,3,122,31,73,110,118,97,108,105,100,97, - 116,101,32,116,104,101,32,100,105,114,101,99,116,111,114,121, - 32,109,116,105,109,101,46,114,89,0,0,0,78,41,1,114, - 20,1,0,0,41,1,114,102,0,0,0,114,2,0,0,0, - 114,2,0,0,0,114,4,0,0,0,114,6,1,0,0,49, - 5,0,0,115,2,0,0,0,0,2,122,28,70,105,108,101, - 70,105,110,100,101,114,46,105,110,118,97,108,105,100,97,116, - 101,95,99,97,99,104,101,115,99,2,0,0,0,0,0,0, - 0,3,0,0,0,3,0,0,0,67,0,0,0,115,42,0, - 0,0,124,0,160,0,124,1,161,1,125,2,124,2,100,1, - 107,8,114,26,100,1,103,0,102,2,83,0,124,2,106,1, - 124,2,106,2,112,38,103,0,102,2,83,0,41,2,122,197, - 84,114,121,32,116,111,32,102,105,110,100,32,97,32,108,111, - 97,100,101,114,32,102,111,114,32,116,104,101,32,115,112,101, - 99,105,102,105,101,100,32,109,111,100,117,108,101,44,32,111, - 114,32,116,104,101,32,110,97,109,101,115,112,97,99,101,10, - 32,32,32,32,32,32,32,32,112,97,99,107,97,103,101,32, - 112,111,114,116,105,111,110,115,46,32,82,101,116,117,114,110, - 115,32,40,108,111,97,100,101,114,44,32,108,105,115,116,45, - 111,102,45,112,111,114,116,105,111,110,115,41,46,10,10,32, + 199,4,0,0,115,18,0,0,0,0,4,10,1,16,2,10, + 1,4,1,8,1,12,1,12,1,6,1,122,27,80,97,116, + 104,70,105,110,100,101,114,46,95,108,101,103,97,99,121,95, + 103,101,116,95,115,112,101,99,78,99,4,0,0,0,0,0, + 0,0,9,0,0,0,5,0,0,0,67,0,0,0,115,170, + 0,0,0,103,0,125,4,120,160,124,2,68,0,93,130,125, + 5,116,0,124,5,116,1,116,2,102,2,131,2,115,30,113, + 10,124,0,160,3,124,5,161,1,125,6,124,6,100,1,107, + 9,114,10,116,4,124,6,100,2,131,2,114,72,124,6,160, + 5,124,1,124,3,161,2,125,7,110,12,124,0,160,6,124, + 1,124,6,161,2,125,7,124,7,100,1,107,8,114,94,113, + 10,124,7,106,7,100,1,107,9,114,108,124,7,83,0,124, + 7,106,8,125,8,124,8,100,1,107,8,114,130,116,9,100, + 3,131,1,130,1,124,4,160,10,124,8,161,1,1,0,113, + 10,87,0,116,11,160,12,124,1,100,1,161,2,125,7,124, + 4,124,7,95,8,124,7,83,0,100,1,83,0,41,4,122, + 63,70,105,110,100,32,116,104,101,32,108,111,97,100,101,114, + 32,111,114,32,110,97,109,101,115,112,97,99,101,95,112,97, + 116,104,32,102,111,114,32,116,104,105,115,32,109,111,100,117, + 108,101,47,112,97,99,107,97,103,101,32,110,97,109,101,46, + 78,114,182,0,0,0,122,19,115,112,101,99,32,109,105,115, + 115,105,110,103,32,108,111,97,100,101,114,41,13,114,141,0, + 0,0,114,71,0,0,0,218,5,98,121,116,101,115,114,14, + 1,0,0,114,110,0,0,0,114,182,0,0,0,114,15,1, + 0,0,114,122,0,0,0,114,158,0,0,0,114,101,0,0, + 0,114,147,0,0,0,114,116,0,0,0,114,162,0,0,0, + 41,9,114,172,0,0,0,114,121,0,0,0,114,35,0,0, + 0,114,181,0,0,0,218,14,110,97,109,101,115,112,97,99, + 101,95,112,97,116,104,90,5,101,110,116,114,121,114,10,1, + 0,0,114,166,0,0,0,114,123,0,0,0,114,2,0,0, + 0,114,2,0,0,0,114,4,0,0,0,218,9,95,103,101, + 116,95,115,112,101,99,214,4,0,0,115,40,0,0,0,0, + 5,4,1,10,1,14,1,2,1,10,1,8,1,10,1,14, + 2,12,1,8,1,2,1,10,1,4,1,6,1,8,1,8, + 5,14,2,12,1,6,1,122,20,80,97,116,104,70,105,110, + 100,101,114,46,95,103,101,116,95,115,112,101,99,99,4,0, + 0,0,0,0,0,0,6,0,0,0,5,0,0,0,67,0, + 0,0,115,100,0,0,0,124,2,100,1,107,8,114,14,116, + 0,106,1,125,2,124,0,160,2,124,1,124,2,124,3,161, + 3,125,4,124,4,100,1,107,8,114,40,100,1,83,0,124, + 4,106,3,100,1,107,8,114,92,124,4,106,4,125,5,124, + 5,114,86,100,1,124,4,95,5,116,6,124,1,124,5,124, + 0,106,2,131,3,124,4,95,4,124,4,83,0,100,1,83, + 0,110,4,124,4,83,0,100,1,83,0,41,2,122,141,84, + 114,121,32,116,111,32,102,105,110,100,32,97,32,115,112,101, + 99,32,102,111,114,32,39,102,117,108,108,110,97,109,101,39, + 32,111,110,32,115,121,115,46,112,97,116,104,32,111,114,32, + 39,112,97,116,104,39,46,10,10,32,32,32,32,32,32,32, + 32,84,104,101,32,115,101,97,114,99,104,32,105,115,32,98, + 97,115,101,100,32,111,110,32,115,121,115,46,112,97,116,104, + 95,104,111,111,107,115,32,97,110,100,32,115,121,115,46,112, + 97,116,104,95,105,109,112,111,114,116,101,114,95,99,97,99, + 104,101,46,10,32,32,32,32,32,32,32,32,78,41,7,114, + 6,0,0,0,114,35,0,0,0,114,18,1,0,0,114,122, + 0,0,0,114,158,0,0,0,114,160,0,0,0,114,241,0, + 0,0,41,6,114,172,0,0,0,114,121,0,0,0,114,35, + 0,0,0,114,181,0,0,0,114,166,0,0,0,114,17,1, + 0,0,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,114,182,0,0,0,246,4,0,0,115,26,0,0,0,0, + 6,8,1,6,1,14,1,8,1,4,1,10,1,6,1,4, + 3,6,1,16,1,4,2,6,2,122,20,80,97,116,104,70, + 105,110,100,101,114,46,102,105,110,100,95,115,112,101,99,99, + 3,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0, + 67,0,0,0,115,30,0,0,0,124,0,160,0,124,1,124, + 2,161,2,125,3,124,3,100,1,107,8,114,24,100,1,83, + 0,124,3,106,1,83,0,41,2,122,170,102,105,110,100,32, + 116,104,101,32,109,111,100,117,108,101,32,111,110,32,115,121, + 115,46,112,97,116,104,32,111,114,32,39,112,97,116,104,39, + 32,98,97,115,101,100,32,111,110,32,115,121,115,46,112,97, + 116,104,95,104,111,111,107,115,32,97,110,100,10,32,32,32, + 32,32,32,32,32,115,121,115,46,112,97,116,104,95,105,109, + 112,111,114,116,101,114,95,99,97,99,104,101,46,10,10,32, 32,32,32,32,32,32,32,84,104,105,115,32,109,101,116,104, 111,100,32,105,115,32,100,101,112,114,101,99,97,116,101,100, 46,32,32,85,115,101,32,102,105,110,100,95,115,112,101,99, 40,41,32,105,110,115,116,101,97,100,46,10,10,32,32,32, - 32,32,32,32,32,78,41,3,114,182,0,0,0,114,122,0, - 0,0,114,158,0,0,0,41,3,114,102,0,0,0,114,121, + 32,32,32,32,32,78,41,2,114,182,0,0,0,114,122,0, + 0,0,41,4,114,172,0,0,0,114,121,0,0,0,114,35, 0,0,0,114,166,0,0,0,114,2,0,0,0,114,2,0, - 0,0,114,4,0,0,0,114,119,0,0,0,55,5,0,0, - 115,8,0,0,0,0,7,10,1,8,1,8,1,122,22,70, - 105,108,101,70,105,110,100,101,114,46,102,105,110,100,95,108, - 111,97,100,101,114,99,6,0,0,0,0,0,0,0,7,0, - 0,0,6,0,0,0,67,0,0,0,115,26,0,0,0,124, - 1,124,2,124,3,131,2,125,6,116,0,124,2,124,3,124, - 6,124,4,100,1,141,4,83,0,41,2,78,41,2,114,122, - 0,0,0,114,158,0,0,0,41,1,114,169,0,0,0,41, - 7,114,102,0,0,0,114,167,0,0,0,114,121,0,0,0, - 114,35,0,0,0,90,4,115,109,115,108,114,181,0,0,0, - 114,122,0,0,0,114,2,0,0,0,114,2,0,0,0,114, - 4,0,0,0,114,17,1,0,0,67,5,0,0,115,6,0, - 0,0,0,1,10,1,8,1,122,20,70,105,108,101,70,105, - 110,100,101,114,46,95,103,101,116,95,115,112,101,99,78,99, - 3,0,0,0,0,0,0,0,14,0,0,0,8,0,0,0, - 67,0,0,0,115,98,1,0,0,100,1,125,3,124,1,160, - 0,100,2,161,1,100,3,25,0,125,4,121,24,116,1,124, - 0,106,2,112,34,116,3,160,4,161,0,131,1,106,5,125, - 5,87,0,110,24,4,0,116,6,107,10,114,66,1,0,1, - 0,1,0,100,4,125,5,89,0,110,2,88,0,124,5,124, - 0,106,7,107,3,114,92,124,0,160,8,161,0,1,0,124, - 5,124,0,95,7,116,9,131,0,114,114,124,0,106,10,125, - 6,124,4,160,11,161,0,125,7,110,10,124,0,106,12,125, - 6,124,4,125,7,124,7,124,6,107,6,114,218,116,13,124, - 0,106,2,124,4,131,2,125,8,120,72,124,0,106,14,68, - 0,93,54,92,2,125,9,125,10,100,5,124,9,23,0,125, - 11,116,13,124,8,124,11,131,2,125,12,116,15,124,12,131, - 1,114,152,124,0,160,16,124,10,124,1,124,12,124,8,103, - 1,124,2,161,5,83,0,113,152,87,0,116,17,124,8,131, - 1,125,3,120,88,124,0,106,14,68,0,93,78,92,2,125, - 9,125,10,116,13,124,0,106,2,124,4,124,9,23,0,131, - 2,125,12,116,18,106,19,100,6,124,12,100,3,100,7,141, - 3,1,0,124,7,124,9,23,0,124,6,107,6,114,226,116, - 15,124,12,131,1,114,226,124,0,160,16,124,10,124,1,124, - 12,100,8,124,2,161,5,83,0,113,226,87,0,124,3,144, - 1,114,94,116,18,160,19,100,9,124,8,161,2,1,0,116, - 18,160,20,124,1,100,8,161,2,125,13,124,8,103,1,124, - 13,95,21,124,13,83,0,100,8,83,0,41,10,122,111,84, - 114,121,32,116,111,32,102,105,110,100,32,97,32,115,112,101, - 99,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102, - 105,101,100,32,109,111,100,117,108,101,46,10,10,32,32,32, - 32,32,32,32,32,82,101,116,117,114,110,115,32,116,104,101, - 32,109,97,116,99,104,105,110,103,32,115,112,101,99,44,32, - 111,114,32,78,111,110,101,32,105,102,32,110,111,116,32,102, - 111,117,110,100,46,10,32,32,32,32,32,32,32,32,70,114, - 59,0,0,0,114,57,0,0,0,114,89,0,0,0,114,186, - 0,0,0,122,9,116,114,121,105,110,103,32,123,125,41,1, - 90,9,118,101,114,98,111,115,105,116,121,78,122,25,112,111, - 115,115,105,98,108,101,32,110,97,109,101,115,112,97,99,101, - 32,102,111,114,32,123,125,41,22,114,32,0,0,0,114,39, - 0,0,0,114,35,0,0,0,114,1,0,0,0,114,45,0, - 0,0,114,230,0,0,0,114,40,0,0,0,114,20,1,0, - 0,218,11,95,102,105,108,108,95,99,97,99,104,101,114,5, - 0,0,0,114,23,1,0,0,114,90,0,0,0,114,22,1, - 0,0,114,28,0,0,0,114,19,1,0,0,114,44,0,0, - 0,114,17,1,0,0,114,46,0,0,0,114,116,0,0,0, - 114,130,0,0,0,114,162,0,0,0,114,158,0,0,0,41, - 14,114,102,0,0,0,114,121,0,0,0,114,181,0,0,0, - 90,12,105,115,95,110,97,109,101,115,112,97,99,101,90,11, - 116,97,105,108,95,109,111,100,117,108,101,114,149,0,0,0, - 90,5,99,97,99,104,101,90,12,99,97,99,104,101,95,109, - 111,100,117,108,101,90,9,98,97,115,101,95,112,97,116,104, - 114,236,0,0,0,114,167,0,0,0,90,13,105,110,105,116, - 95,102,105,108,101,110,97,109,101,90,9,102,117,108,108,95, - 112,97,116,104,114,166,0,0,0,114,2,0,0,0,114,2, - 0,0,0,114,4,0,0,0,114,182,0,0,0,72,5,0, - 0,115,70,0,0,0,0,5,4,1,14,1,2,1,24,1, - 14,1,10,1,10,1,8,1,6,2,6,1,6,1,10,2, - 6,1,4,2,8,1,12,1,16,1,8,1,10,1,8,1, - 24,4,8,2,16,1,16,1,16,1,12,1,8,1,10,1, - 12,1,6,1,12,1,12,1,8,1,4,1,122,20,70,105, - 108,101,70,105,110,100,101,114,46,102,105,110,100,95,115,112, - 101,99,99,1,0,0,0,0,0,0,0,9,0,0,0,10, - 0,0,0,67,0,0,0,115,194,0,0,0,124,0,106,0, - 125,1,121,22,116,1,160,2,124,1,112,22,116,1,160,3, - 161,0,161,1,125,2,87,0,110,30,4,0,116,4,116,5, - 116,6,102,3,107,10,114,58,1,0,1,0,1,0,103,0, - 125,2,89,0,110,2,88,0,116,7,106,8,160,9,100,1, - 161,1,115,84,116,10,124,2,131,1,124,0,95,11,110,78, - 116,10,131,0,125,3,120,64,124,2,68,0,93,56,125,4, - 124,4,160,12,100,2,161,1,92,3,125,5,125,6,125,7, - 124,6,114,138,100,3,160,13,124,5,124,7,160,14,161,0, - 161,2,125,8,110,4,124,5,125,8,124,3,160,15,124,8, - 161,1,1,0,113,96,87,0,124,3,124,0,95,11,116,7, - 106,8,160,9,116,16,161,1,114,190,100,4,100,5,132,0, - 124,2,68,0,131,1,124,0,95,17,100,6,83,0,41,7, - 122,68,70,105,108,108,32,116,104,101,32,99,97,99,104,101, - 32,111,102,32,112,111,116,101,110,116,105,97,108,32,109,111, - 100,117,108,101,115,32,97,110,100,32,112,97,99,107,97,103, - 101,115,32,102,111,114,32,116,104,105,115,32,100,105,114,101, - 99,116,111,114,121,46,114,0,0,0,0,114,59,0,0,0, - 122,5,123,125,46,123,125,99,1,0,0,0,0,0,0,0, - 2,0,0,0,4,0,0,0,83,0,0,0,115,20,0,0, - 0,104,0,124,0,93,12,125,1,124,1,160,0,161,0,146, - 2,113,4,83,0,114,2,0,0,0,41,1,114,90,0,0, - 0,41,2,114,22,0,0,0,90,2,102,110,114,2,0,0, - 0,114,2,0,0,0,114,4,0,0,0,250,9,60,115,101, - 116,99,111,109,112,62,149,5,0,0,115,2,0,0,0,6, - 0,122,41,70,105,108,101,70,105,110,100,101,114,46,95,102, - 105,108,108,95,99,97,99,104,101,46,60,108,111,99,97,108, - 115,62,46,60,115,101,116,99,111,109,112,62,78,41,18,114, - 35,0,0,0,114,1,0,0,0,114,227,0,0,0,114,45, - 0,0,0,114,224,0,0,0,218,15,80,101,114,109,105,115, - 115,105,111,110,69,114,114,111,114,218,18,78,111,116,65,68, - 105,114,101,99,116,111,114,121,69,114,114,111,114,114,6,0, - 0,0,114,7,0,0,0,114,8,0,0,0,114,21,1,0, - 0,114,22,1,0,0,114,85,0,0,0,114,48,0,0,0, - 114,90,0,0,0,218,3,97,100,100,114,9,0,0,0,114, - 23,1,0,0,41,9,114,102,0,0,0,114,35,0,0,0, - 114,228,0,0,0,90,21,108,111,119,101,114,95,115,117,102, - 102,105,120,95,99,111,110,116,101,110,116,115,114,1,1,0, - 0,114,100,0,0,0,114,248,0,0,0,114,236,0,0,0, - 90,8,110,101,119,95,110,97,109,101,114,2,0,0,0,114, - 2,0,0,0,114,4,0,0,0,114,25,1,0,0,120,5, - 0,0,115,34,0,0,0,0,2,6,1,2,1,22,1,20, - 3,10,3,12,1,12,7,6,1,10,1,16,1,4,1,18, - 2,4,1,14,1,6,1,12,1,122,22,70,105,108,101,70, - 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, - 101,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, - 0,0,7,0,0,0,115,18,0,0,0,135,0,135,1,102, - 2,100,1,100,2,132,8,125,2,124,2,83,0,41,3,97, - 20,1,0,0,65,32,99,108,97,115,115,32,109,101,116,104, - 111,100,32,119,104,105,99,104,32,114,101,116,117,114,110,115, - 32,97,32,99,108,111,115,117,114,101,32,116,111,32,117,115, - 101,32,111,110,32,115,121,115,46,112,97,116,104,95,104,111, - 111,107,10,32,32,32,32,32,32,32,32,119,104,105,99,104, - 32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32, - 105,110,115,116,97,110,99,101,32,117,115,105,110,103,32,116, - 104,101,32,115,112,101,99,105,102,105,101,100,32,108,111,97, - 100,101,114,115,32,97,110,100,32,116,104,101,32,112,97,116, - 104,10,32,32,32,32,32,32,32,32,99,97,108,108,101,100, - 32,111,110,32,116,104,101,32,99,108,111,115,117,114,101,46, - 10,10,32,32,32,32,32,32,32,32,73,102,32,116,104,101, - 32,112,97,116,104,32,99,97,108,108,101,100,32,111,110,32, - 116,104,101,32,99,108,111,115,117,114,101,32,105,115,32,110, - 111,116,32,97,32,100,105,114,101,99,116,111,114,121,44,32, - 73,109,112,111,114,116,69,114,114,111,114,32,105,115,10,32, - 32,32,32,32,32,32,32,114,97,105,115,101,100,46,10,10, - 32,32,32,32,32,32,32,32,99,1,0,0,0,0,0,0, - 0,1,0,0,0,4,0,0,0,19,0,0,0,115,34,0, - 0,0,116,0,124,0,131,1,115,20,116,1,100,1,124,0, - 100,2,141,2,130,1,136,0,124,0,102,1,136,1,158,2, - 142,0,83,0,41,3,122,45,80,97,116,104,32,104,111,111, - 107,32,102,111,114,32,105,109,112,111,114,116,108,105,98,46, - 109,97,99,104,105,110,101,114,121,46,70,105,108,101,70,105, - 110,100,101,114,46,122,30,111,110,108,121,32,100,105,114,101, - 99,116,111,114,105,101,115,32,97,114,101,32,115,117,112,112, - 111,114,116,101,100,41,1,114,35,0,0,0,41,2,114,46, - 0,0,0,114,101,0,0,0,41,1,114,35,0,0,0,41, - 2,114,172,0,0,0,114,24,1,0,0,114,2,0,0,0, - 114,4,0,0,0,218,24,112,97,116,104,95,104,111,111,107, - 95,102,111,114,95,70,105,108,101,70,105,110,100,101,114,161, - 5,0,0,115,6,0,0,0,0,2,8,1,12,1,122,54, - 70,105,108,101,70,105,110,100,101,114,46,112,97,116,104,95, - 104,111,111,107,46,60,108,111,99,97,108,115,62,46,112,97, - 116,104,95,104,111,111,107,95,102,111,114,95,70,105,108,101, - 70,105,110,100,101,114,114,2,0,0,0,41,3,114,172,0, - 0,0,114,24,1,0,0,114,30,1,0,0,114,2,0,0, - 0,41,2,114,172,0,0,0,114,24,1,0,0,114,4,0, - 0,0,218,9,112,97,116,104,95,104,111,111,107,151,5,0, - 0,115,4,0,0,0,0,10,14,6,122,20,70,105,108,101, - 70,105,110,100,101,114,46,112,97,116,104,95,104,111,111,107, - 99,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0, - 0,67,0,0,0,115,12,0,0,0,100,1,160,0,124,0, - 106,1,161,1,83,0,41,2,78,122,16,70,105,108,101,70, - 105,110,100,101,114,40,123,33,114,125,41,41,2,114,48,0, - 0,0,114,35,0,0,0,41,1,114,102,0,0,0,114,2, - 0,0,0,114,2,0,0,0,114,4,0,0,0,114,0,1, - 0,0,169,5,0,0,115,2,0,0,0,0,1,122,19,70, - 105,108,101,70,105,110,100,101,114,46,95,95,114,101,112,114, - 95,95,41,1,78,41,15,114,107,0,0,0,114,106,0,0, - 0,114,108,0,0,0,114,109,0,0,0,114,186,0,0,0, - 114,6,1,0,0,114,125,0,0,0,114,183,0,0,0,114, - 119,0,0,0,114,17,1,0,0,114,182,0,0,0,114,25, - 1,0,0,114,184,0,0,0,114,31,1,0,0,114,0,1, - 0,0,114,2,0,0,0,114,2,0,0,0,114,2,0,0, - 0,114,4,0,0,0,114,18,1,0,0,26,5,0,0,115, - 18,0,0,0,12,9,8,14,8,4,4,2,8,12,8,5, - 10,48,8,31,12,18,114,18,1,0,0,99,4,0,0,0, - 0,0,0,0,6,0,0,0,8,0,0,0,67,0,0,0, - 115,146,0,0,0,124,0,160,0,100,1,161,1,125,4,124, - 0,160,0,100,2,161,1,125,5,124,4,115,66,124,5,114, - 36,124,5,106,1,125,4,110,30,124,2,124,3,107,2,114, - 56,116,2,124,1,124,2,131,2,125,4,110,10,116,3,124, - 1,124,2,131,2,125,4,124,5,115,84,116,4,124,1,124, - 2,124,4,100,3,141,3,125,5,121,36,124,5,124,0,100, - 2,60,0,124,4,124,0,100,1,60,0,124,2,124,0,100, - 4,60,0,124,3,124,0,100,5,60,0,87,0,110,20,4, - 0,116,5,107,10,114,140,1,0,1,0,1,0,89,0,110, - 2,88,0,100,0,83,0,41,6,78,218,10,95,95,108,111, - 97,100,101,114,95,95,218,8,95,95,115,112,101,99,95,95, - 41,1,114,122,0,0,0,90,8,95,95,102,105,108,101,95, - 95,90,10,95,95,99,97,99,104,101,100,95,95,41,6,218, - 3,103,101,116,114,122,0,0,0,114,234,0,0,0,114,229, - 0,0,0,114,169,0,0,0,218,9,69,120,99,101,112,116, - 105,111,110,41,6,90,2,110,115,114,100,0,0,0,90,8, - 112,97,116,104,110,97,109,101,90,9,99,112,97,116,104,110, - 97,109,101,114,122,0,0,0,114,166,0,0,0,114,2,0, - 0,0,114,2,0,0,0,114,4,0,0,0,218,14,95,102, - 105,120,95,117,112,95,109,111,100,117,108,101,175,5,0,0, - 115,34,0,0,0,0,2,10,1,10,1,4,1,4,1,8, - 1,8,1,12,2,10,1,4,1,14,1,2,1,8,1,8, - 1,8,1,12,1,14,2,114,36,1,0,0,99,0,0,0, - 0,0,0,0,0,3,0,0,0,3,0,0,0,67,0,0, - 0,115,38,0,0,0,116,0,116,1,160,2,161,0,102,2, - 125,0,116,3,116,4,102,2,125,1,116,5,116,6,102,2, - 125,2,124,0,124,1,124,2,103,3,83,0,41,1,122,95, - 82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111, - 102,32,102,105,108,101,45,98,97,115,101,100,32,109,111,100, - 117,108,101,32,108,111,97,100,101,114,115,46,10,10,32,32, - 32,32,69,97,99,104,32,105,116,101,109,32,105,115,32,97, - 32,116,117,112,108,101,32,40,108,111,97,100,101,114,44,32, - 115,117,102,102,105,120,101,115,41,46,10,32,32,32,32,41, - 7,114,235,0,0,0,114,143,0,0,0,218,18,101,120,116, - 101,110,115,105,111,110,95,115,117,102,102,105,120,101,115,114, - 229,0,0,0,114,86,0,0,0,114,234,0,0,0,114,76, - 0,0,0,41,3,90,10,101,120,116,101,110,115,105,111,110, - 115,90,6,115,111,117,114,99,101,90,8,98,121,116,101,99, - 111,100,101,114,2,0,0,0,114,2,0,0,0,114,4,0, - 0,0,114,163,0,0,0,198,5,0,0,115,8,0,0,0, - 0,5,12,1,8,1,8,1,114,163,0,0,0,99,1,0, - 0,0,0,0,0,0,12,0,0,0,9,0,0,0,67,0, - 0,0,115,156,1,0,0,124,0,97,0,116,0,106,1,97, - 1,116,0,106,2,97,2,116,1,106,3,116,4,25,0,125, - 1,120,56,100,1,68,0,93,48,125,2,124,2,116,1,106, - 3,107,7,114,58,116,0,160,5,124,2,161,1,125,3,110, - 10,116,1,106,3,124,2,25,0,125,3,116,6,124,1,124, - 2,124,3,131,3,1,0,113,32,87,0,100,2,100,3,103, - 1,102,2,100,4,100,5,100,3,103,2,102,2,102,2,125, - 4,120,118,124,4,68,0,93,102,92,2,125,5,125,6,116, - 7,100,6,100,7,132,0,124,6,68,0,131,1,131,1,115, - 142,116,8,130,1,124,6,100,8,25,0,125,7,124,5,116, - 1,106,3,107,6,114,174,116,1,106,3,124,5,25,0,125, - 8,80,0,113,112,121,16,116,0,160,5,124,5,161,1,125, - 8,80,0,87,0,113,112,4,0,116,9,107,10,114,212,1, - 0,1,0,1,0,119,112,89,0,113,112,88,0,113,112,87, - 0,116,9,100,9,131,1,130,1,116,6,124,1,100,10,124, - 8,131,3,1,0,116,6,124,1,100,11,124,7,131,3,1, - 0,116,6,124,1,100,12,100,13,160,10,124,6,161,1,131, - 3,1,0,116,0,160,5,100,14,161,1,125,9,116,6,124, - 1,100,14,124,9,131,3,1,0,116,0,160,5,100,15,161, - 1,125,10,116,6,124,1,100,15,124,10,131,3,1,0,124, - 5,100,4,107,2,144,1,114,88,116,0,160,5,100,16,161, - 1,125,11,116,6,124,1,100,17,124,11,131,3,1,0,116, - 6,124,1,100,18,116,11,131,0,131,3,1,0,116,12,160, - 13,116,2,160,14,161,0,161,1,1,0,124,5,100,4,107, - 2,144,1,114,152,116,15,160,16,100,19,161,1,1,0,100, - 20,116,12,107,6,144,1,114,152,100,21,116,17,95,18,100, - 22,83,0,41,23,122,205,83,101,116,117,112,32,116,104,101, - 32,112,97,116,104,45,98,97,115,101,100,32,105,109,112,111, - 114,116,101,114,115,32,102,111,114,32,105,109,112,111,114,116, - 108,105,98,32,98,121,32,105,109,112,111,114,116,105,110,103, - 32,110,101,101,100,101,100,10,32,32,32,32,98,117,105,108, - 116,45,105,110,32,109,111,100,117,108,101,115,32,97,110,100, - 32,105,110,106,101,99,116,105,110,103,32,116,104,101,109,32, - 105,110,116,111,32,116,104,101,32,103,108,111,98,97,108,32, - 110,97,109,101,115,112,97,99,101,46,10,10,32,32,32,32, - 79,116,104,101,114,32,99,111,109,112,111,110,101,110,116,115, - 32,97,114,101,32,101,120,116,114,97,99,116,101,100,32,102, - 114,111,109,32,116,104,101,32,99,111,114,101,32,98,111,111, - 116,115,116,114,97,112,32,109,111,100,117,108,101,46,10,10, - 32,32,32,32,41,4,114,50,0,0,0,114,61,0,0,0, - 218,8,98,117,105,108,116,105,110,115,114,140,0,0,0,90, - 5,112,111,115,105,120,250,1,47,90,2,110,116,250,1,92, - 99,1,0,0,0,0,0,0,0,2,0,0,0,3,0,0, - 0,115,0,0,0,115,26,0,0,0,124,0,93,18,125,1, - 116,0,124,1,131,1,100,0,107,2,86,0,1,0,113,2, - 100,1,83,0,41,2,114,29,0,0,0,78,41,1,114,31, - 0,0,0,41,2,114,22,0,0,0,114,79,0,0,0,114, - 2,0,0,0,114,2,0,0,0,114,4,0,0,0,114,238, - 0,0,0,234,5,0,0,115,2,0,0,0,4,0,122,25, - 95,115,101,116,117,112,46,60,108,111,99,97,108,115,62,46, - 60,103,101,110,101,120,112,114,62,114,60,0,0,0,122,30, - 105,109,112,111,114,116,108,105,98,32,114,101,113,117,105,114, - 101,115,32,112,111,115,105,120,32,111,114,32,110,116,114,1, - 0,0,0,114,25,0,0,0,114,21,0,0,0,114,30,0, - 0,0,90,7,95,116,104,114,101,97,100,90,8,95,119,101, - 97,107,114,101,102,90,6,119,105,110,114,101,103,114,171,0, - 0,0,114,5,0,0,0,122,4,46,112,121,119,122,6,95, - 100,46,112,121,100,84,78,41,19,114,116,0,0,0,114,6, - 0,0,0,114,143,0,0,0,114,250,0,0,0,114,107,0, - 0,0,90,18,95,98,117,105,108,116,105,110,95,102,114,111, - 109,95,110,97,109,101,114,111,0,0,0,218,3,97,108,108, - 114,151,0,0,0,114,101,0,0,0,114,26,0,0,0,114, - 11,0,0,0,114,240,0,0,0,114,147,0,0,0,114,37, - 1,0,0,114,86,0,0,0,114,165,0,0,0,114,170,0, - 0,0,114,174,0,0,0,41,12,218,17,95,98,111,111,116, - 115,116,114,97,112,95,109,111,100,117,108,101,90,11,115,101, - 108,102,95,109,111,100,117,108,101,90,12,98,117,105,108,116, - 105,110,95,110,97,109,101,90,14,98,117,105,108,116,105,110, - 95,109,111,100,117,108,101,90,10,111,115,95,100,101,116,97, - 105,108,115,90,10,98,117,105,108,116,105,110,95,111,115,114, - 21,0,0,0,114,25,0,0,0,90,9,111,115,95,109,111, - 100,117,108,101,90,13,116,104,114,101,97,100,95,109,111,100, - 117,108,101,90,14,119,101,97,107,114,101,102,95,109,111,100, - 117,108,101,90,13,119,105,110,114,101,103,95,109,111,100,117, - 108,101,114,2,0,0,0,114,2,0,0,0,114,4,0,0, - 0,218,6,95,115,101,116,117,112,209,5,0,0,115,76,0, - 0,0,0,8,4,1,6,1,6,3,10,1,10,1,10,1, - 12,2,10,1,16,3,22,1,14,2,22,1,8,1,10,1, - 10,1,4,2,2,1,10,1,6,1,14,1,12,2,8,1, - 12,1,12,1,18,3,10,1,12,3,10,1,12,3,10,1, - 10,1,12,3,14,1,14,1,10,1,10,1,10,1,114,43, - 1,0,0,99,1,0,0,0,0,0,0,0,2,0,0,0, - 4,0,0,0,67,0,0,0,115,50,0,0,0,116,0,124, - 0,131,1,1,0,116,1,131,0,125,1,116,2,106,3,160, - 4,116,5,106,6,124,1,142,0,103,1,161,1,1,0,116, - 2,106,7,160,8,116,9,161,1,1,0,100,1,83,0,41, - 2,122,41,73,110,115,116,97,108,108,32,116,104,101,32,112, - 97,116,104,45,98,97,115,101,100,32,105,109,112,111,114,116, - 32,99,111,109,112,111,110,101,110,116,115,46,78,41,10,114, - 43,1,0,0,114,163,0,0,0,114,6,0,0,0,114,10, - 1,0,0,114,147,0,0,0,114,18,1,0,0,114,31,1, - 0,0,218,9,109,101,116,97,95,112,97,116,104,114,165,0, - 0,0,114,5,1,0,0,41,2,114,42,1,0,0,90,17, - 115,117,112,112,111,114,116,101,100,95,108,111,97,100,101,114, - 115,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, - 218,8,95,105,110,115,116,97,108,108,17,6,0,0,115,8, - 0,0,0,0,2,8,1,6,1,20,1,114,45,1,0,0, - 41,1,114,47,0,0,0,41,1,78,41,3,78,78,78,41, - 2,114,60,0,0,0,114,60,0,0,0,41,1,84,41,1, - 78,41,1,78,41,61,114,109,0,0,0,114,10,0,0,0, - 90,37,95,67,65,83,69,95,73,78,83,69,78,83,73,84, - 73,86,69,95,80,76,65,84,70,79,82,77,83,95,66,89, - 84,69,83,95,75,69,89,114,9,0,0,0,114,11,0,0, - 0,114,17,0,0,0,114,19,0,0,0,114,28,0,0,0, - 114,38,0,0,0,114,39,0,0,0,114,43,0,0,0,114, - 44,0,0,0,114,46,0,0,0,114,56,0,0,0,218,4, - 116,121,112,101,218,8,95,95,99,111,100,101,95,95,114,142, - 0,0,0,114,15,0,0,0,114,129,0,0,0,114,14,0, - 0,0,114,18,0,0,0,114,209,0,0,0,114,75,0,0, - 0,114,74,0,0,0,114,86,0,0,0,114,76,0,0,0, - 90,23,68,69,66,85,71,95,66,89,84,69,67,79,68,69, - 95,83,85,70,70,73,88,69,83,90,27,79,80,84,73,77, - 73,90,69,68,95,66,89,84,69,67,79,68,69,95,83,85, - 70,70,73,88,69,83,114,81,0,0,0,114,87,0,0,0, - 114,93,0,0,0,114,97,0,0,0,114,99,0,0,0,114, - 118,0,0,0,114,125,0,0,0,114,133,0,0,0,114,137, - 0,0,0,114,139,0,0,0,114,145,0,0,0,114,150,0, - 0,0,114,152,0,0,0,114,157,0,0,0,218,6,111,98, - 106,101,99,116,114,164,0,0,0,114,169,0,0,0,114,170, - 0,0,0,114,185,0,0,0,114,195,0,0,0,114,212,0, - 0,0,114,229,0,0,0,114,234,0,0,0,114,240,0,0, - 0,114,235,0,0,0,114,241,0,0,0,114,3,1,0,0, - 114,5,1,0,0,114,18,1,0,0,114,36,1,0,0,114, - 163,0,0,0,114,43,1,0,0,114,45,1,0,0,114,2, + 0,0,114,4,0,0,0,114,183,0,0,0,14,5,0,0, + 115,8,0,0,0,0,8,12,1,8,1,4,1,122,22,80, + 97,116,104,70,105,110,100,101,114,46,102,105,110,100,95,109, + 111,100,117,108,101,41,1,78,41,2,78,78,41,1,78,41, + 12,114,107,0,0,0,114,106,0,0,0,114,108,0,0,0, + 114,109,0,0,0,114,184,0,0,0,114,6,1,0,0,114, + 12,1,0,0,114,14,1,0,0,114,15,1,0,0,114,18, + 1,0,0,114,182,0,0,0,114,183,0,0,0,114,2,0, + 0,0,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,114,5,1,0,0,150,4,0,0,115,20,0,0,0,12, + 4,12,10,12,13,12,22,12,15,2,1,12,31,2,1,12, + 23,2,1,114,5,1,0,0,99,0,0,0,0,0,0,0, + 0,0,0,0,0,3,0,0,0,64,0,0,0,115,90,0, + 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, + 100,3,132,0,90,4,100,4,100,5,132,0,90,5,101,6, + 90,7,100,6,100,7,132,0,90,8,100,8,100,9,132,0, + 90,9,100,19,100,11,100,12,132,1,90,10,100,13,100,14, + 132,0,90,11,101,12,100,15,100,16,132,0,131,1,90,13, + 100,17,100,18,132,0,90,14,100,10,83,0,41,20,218,10, + 70,105,108,101,70,105,110,100,101,114,122,172,70,105,108,101, + 45,98,97,115,101,100,32,102,105,110,100,101,114,46,10,10, + 32,32,32,32,73,110,116,101,114,97,99,116,105,111,110,115, + 32,119,105,116,104,32,116,104,101,32,102,105,108,101,32,115, + 121,115,116,101,109,32,97,114,101,32,99,97,99,104,101,100, + 32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101, + 44,32,98,101,105,110,103,10,32,32,32,32,114,101,102,114, + 101,115,104,101,100,32,119,104,101,110,32,116,104,101,32,100, + 105,114,101,99,116,111,114,121,32,116,104,101,32,102,105,110, + 100,101,114,32,105,115,32,104,97,110,100,108,105,110,103,32, + 104,97,115,32,98,101,101,110,32,109,111,100,105,102,105,101, + 100,46,10,10,32,32,32,32,99,2,0,0,0,0,0,0, + 0,5,0,0,0,6,0,0,0,7,0,0,0,115,88,0, + 0,0,103,0,125,3,120,40,124,2,68,0,93,32,92,2, + 137,0,125,4,124,3,160,0,135,0,102,1,100,1,100,2, + 132,8,124,4,68,0,131,1,161,1,1,0,113,10,87,0, + 124,3,124,0,95,1,124,1,112,58,100,3,124,0,95,2, + 100,4,124,0,95,3,116,4,131,0,124,0,95,5,116,4, + 131,0,124,0,95,6,100,5,83,0,41,6,122,154,73,110, + 105,116,105,97,108,105,122,101,32,119,105,116,104,32,116,104, + 101,32,112,97,116,104,32,116,111,32,115,101,97,114,99,104, + 32,111,110,32,97,110,100,32,97,32,118,97,114,105,97,98, + 108,101,32,110,117,109,98,101,114,32,111,102,10,32,32,32, + 32,32,32,32,32,50,45,116,117,112,108,101,115,32,99,111, + 110,116,97,105,110,105,110,103,32,116,104,101,32,108,111,97, + 100,101,114,32,97,110,100,32,116,104,101,32,102,105,108,101, + 32,115,117,102,102,105,120,101,115,32,116,104,101,32,108,111, + 97,100,101,114,10,32,32,32,32,32,32,32,32,114,101,99, + 111,103,110,105,122,101,115,46,99,1,0,0,0,0,0,0, + 0,2,0,0,0,3,0,0,0,51,0,0,0,115,22,0, + 0,0,124,0,93,14,125,1,124,1,136,0,102,2,86,0, + 1,0,113,2,100,0,83,0,41,1,78,114,2,0,0,0, + 41,2,114,22,0,0,0,114,236,0,0,0,41,1,114,122, + 0,0,0,114,2,0,0,0,114,4,0,0,0,114,238,0, + 0,0,43,5,0,0,115,2,0,0,0,4,0,122,38,70, + 105,108,101,70,105,110,100,101,114,46,95,95,105,110,105,116, + 95,95,46,60,108,111,99,97,108,115,62,46,60,103,101,110, + 101,120,112,114,62,114,59,0,0,0,114,89,0,0,0,78, + 41,7,114,147,0,0,0,218,8,95,108,111,97,100,101,114, + 115,114,35,0,0,0,218,11,95,112,97,116,104,95,109,116, + 105,109,101,218,3,115,101,116,218,11,95,112,97,116,104,95, + 99,97,99,104,101,218,19,95,114,101,108,97,120,101,100,95, + 112,97,116,104,95,99,97,99,104,101,41,5,114,102,0,0, + 0,114,35,0,0,0,218,14,108,111,97,100,101,114,95,100, + 101,116,97,105,108,115,90,7,108,111,97,100,101,114,115,114, + 168,0,0,0,114,2,0,0,0,41,1,114,122,0,0,0, + 114,4,0,0,0,114,186,0,0,0,37,5,0,0,115,16, + 0,0,0,0,4,4,1,14,1,28,1,6,2,10,1,6, + 1,8,1,122,19,70,105,108,101,70,105,110,100,101,114,46, + 95,95,105,110,105,116,95,95,99,1,0,0,0,0,0,0, + 0,1,0,0,0,2,0,0,0,67,0,0,0,115,10,0, + 0,0,100,1,124,0,95,0,100,2,83,0,41,3,122,31, + 73,110,118,97,108,105,100,97,116,101,32,116,104,101,32,100, + 105,114,101,99,116,111,114,121,32,109,116,105,109,101,46,114, + 89,0,0,0,78,41,1,114,21,1,0,0,41,1,114,102, 0,0,0,114,2,0,0,0,114,2,0,0,0,114,4,0, - 0,0,218,8,60,109,111,100,117,108,101,62,23,0,0,0, - 115,118,0,0,0,4,0,4,1,4,1,2,1,6,3,8, - 17,8,5,8,5,8,6,8,12,8,10,8,9,8,5,8, - 7,10,22,10,127,0,3,16,1,12,2,4,1,4,2,6, - 2,6,2,8,2,16,45,8,34,8,19,8,12,8,12,8, - 28,8,17,8,33,8,28,8,24,10,13,10,10,10,11,8, - 14,6,3,4,1,14,67,14,64,14,29,16,127,0,17,14, - 68,18,45,18,26,4,3,18,53,14,60,14,42,14,127,0, - 5,14,127,0,22,10,23,8,11,8,64, + 0,0,114,6,1,0,0,51,5,0,0,115,2,0,0,0, + 0,2,122,28,70,105,108,101,70,105,110,100,101,114,46,105, + 110,118,97,108,105,100,97,116,101,95,99,97,99,104,101,115, + 99,2,0,0,0,0,0,0,0,3,0,0,0,3,0,0, + 0,67,0,0,0,115,42,0,0,0,124,0,160,0,124,1, + 161,1,125,2,124,2,100,1,107,8,114,26,100,1,103,0, + 102,2,83,0,124,2,106,1,124,2,106,2,112,38,103,0, + 102,2,83,0,41,2,122,197,84,114,121,32,116,111,32,102, + 105,110,100,32,97,32,108,111,97,100,101,114,32,102,111,114, + 32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,109, + 111,100,117,108,101,44,32,111,114,32,116,104,101,32,110,97, + 109,101,115,112,97,99,101,10,32,32,32,32,32,32,32,32, + 112,97,99,107,97,103,101,32,112,111,114,116,105,111,110,115, + 46,32,82,101,116,117,114,110,115,32,40,108,111,97,100,101, + 114,44,32,108,105,115,116,45,111,102,45,112,111,114,116,105, + 111,110,115,41,46,10,10,32,32,32,32,32,32,32,32,84, + 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, + 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,102, + 105,110,100,95,115,112,101,99,40,41,32,105,110,115,116,101, + 97,100,46,10,10,32,32,32,32,32,32,32,32,78,41,3, + 114,182,0,0,0,114,122,0,0,0,114,158,0,0,0,41, + 3,114,102,0,0,0,114,121,0,0,0,114,166,0,0,0, + 114,2,0,0,0,114,2,0,0,0,114,4,0,0,0,114, + 119,0,0,0,57,5,0,0,115,8,0,0,0,0,7,10, + 1,8,1,8,1,122,22,70,105,108,101,70,105,110,100,101, + 114,46,102,105,110,100,95,108,111,97,100,101,114,99,6,0, + 0,0,0,0,0,0,7,0,0,0,6,0,0,0,67,0, + 0,0,115,26,0,0,0,124,1,124,2,124,3,131,2,125, + 6,116,0,124,2,124,3,124,6,124,4,100,1,141,4,83, + 0,41,2,78,41,2,114,122,0,0,0,114,158,0,0,0, + 41,1,114,169,0,0,0,41,7,114,102,0,0,0,114,167, + 0,0,0,114,121,0,0,0,114,35,0,0,0,90,4,115, + 109,115,108,114,181,0,0,0,114,122,0,0,0,114,2,0, + 0,0,114,2,0,0,0,114,4,0,0,0,114,18,1,0, + 0,69,5,0,0,115,6,0,0,0,0,1,10,1,8,1, + 122,20,70,105,108,101,70,105,110,100,101,114,46,95,103,101, + 116,95,115,112,101,99,78,99,3,0,0,0,0,0,0,0, + 14,0,0,0,8,0,0,0,67,0,0,0,115,98,1,0, + 0,100,1,125,3,124,1,160,0,100,2,161,1,100,3,25, + 0,125,4,121,24,116,1,124,0,106,2,112,34,116,3,160, + 4,161,0,131,1,106,5,125,5,87,0,110,24,4,0,116, + 6,107,10,114,66,1,0,1,0,1,0,100,4,125,5,89, + 0,110,2,88,0,124,5,124,0,106,7,107,3,114,92,124, + 0,160,8,161,0,1,0,124,5,124,0,95,7,116,9,131, + 0,114,114,124,0,106,10,125,6,124,4,160,11,161,0,125, + 7,110,10,124,0,106,12,125,6,124,4,125,7,124,7,124, + 6,107,6,114,218,116,13,124,0,106,2,124,4,131,2,125, + 8,120,72,124,0,106,14,68,0,93,54,92,2,125,9,125, + 10,100,5,124,9,23,0,125,11,116,13,124,8,124,11,131, + 2,125,12,116,15,124,12,131,1,114,152,124,0,160,16,124, + 10,124,1,124,12,124,8,103,1,124,2,161,5,83,0,113, + 152,87,0,116,17,124,8,131,1,125,3,120,88,124,0,106, + 14,68,0,93,78,92,2,125,9,125,10,116,13,124,0,106, + 2,124,4,124,9,23,0,131,2,125,12,116,18,106,19,100, + 6,124,12,100,3,100,7,141,3,1,0,124,7,124,9,23, + 0,124,6,107,6,114,226,116,15,124,12,131,1,114,226,124, + 0,160,16,124,10,124,1,124,12,100,8,124,2,161,5,83, + 0,113,226,87,0,124,3,144,1,114,94,116,18,160,19,100, + 9,124,8,161,2,1,0,116,18,160,20,124,1,100,8,161, + 2,125,13,124,8,103,1,124,13,95,21,124,13,83,0,100, + 8,83,0,41,10,122,111,84,114,121,32,116,111,32,102,105, + 110,100,32,97,32,115,112,101,99,32,102,111,114,32,116,104, + 101,32,115,112,101,99,105,102,105,101,100,32,109,111,100,117, + 108,101,46,10,10,32,32,32,32,32,32,32,32,82,101,116, + 117,114,110,115,32,116,104,101,32,109,97,116,99,104,105,110, + 103,32,115,112,101,99,44,32,111,114,32,78,111,110,101,32, + 105,102,32,110,111,116,32,102,111,117,110,100,46,10,32,32, + 32,32,32,32,32,32,70,114,59,0,0,0,114,57,0,0, + 0,114,89,0,0,0,114,186,0,0,0,122,9,116,114,121, + 105,110,103,32,123,125,41,1,90,9,118,101,114,98,111,115, + 105,116,121,78,122,25,112,111,115,115,105,98,108,101,32,110, + 97,109,101,115,112,97,99,101,32,102,111,114,32,123,125,41, + 22,114,32,0,0,0,114,39,0,0,0,114,35,0,0,0, + 114,1,0,0,0,114,45,0,0,0,114,230,0,0,0,114, + 40,0,0,0,114,21,1,0,0,218,11,95,102,105,108,108, + 95,99,97,99,104,101,114,5,0,0,0,114,24,1,0,0, + 114,90,0,0,0,114,23,1,0,0,114,28,0,0,0,114, + 20,1,0,0,114,44,0,0,0,114,18,1,0,0,114,46, + 0,0,0,114,116,0,0,0,114,130,0,0,0,114,162,0, + 0,0,114,158,0,0,0,41,14,114,102,0,0,0,114,121, + 0,0,0,114,181,0,0,0,90,12,105,115,95,110,97,109, + 101,115,112,97,99,101,90,11,116,97,105,108,95,109,111,100, + 117,108,101,114,149,0,0,0,90,5,99,97,99,104,101,90, + 12,99,97,99,104,101,95,109,111,100,117,108,101,90,9,98, + 97,115,101,95,112,97,116,104,114,236,0,0,0,114,167,0, + 0,0,90,13,105,110,105,116,95,102,105,108,101,110,97,109, + 101,90,9,102,117,108,108,95,112,97,116,104,114,166,0,0, + 0,114,2,0,0,0,114,2,0,0,0,114,4,0,0,0, + 114,182,0,0,0,74,5,0,0,115,70,0,0,0,0,5, + 4,1,14,1,2,1,24,1,14,1,10,1,10,1,8,1, + 6,2,6,1,6,1,10,2,6,1,4,2,8,1,12,1, + 16,1,8,1,10,1,8,1,24,4,8,2,16,1,16,1, + 16,1,12,1,8,1,10,1,12,1,6,1,12,1,12,1, + 8,1,4,1,122,20,70,105,108,101,70,105,110,100,101,114, + 46,102,105,110,100,95,115,112,101,99,99,1,0,0,0,0, + 0,0,0,9,0,0,0,10,0,0,0,67,0,0,0,115, + 194,0,0,0,124,0,106,0,125,1,121,22,116,1,160,2, + 124,1,112,22,116,1,160,3,161,0,161,1,125,2,87,0, + 110,30,4,0,116,4,116,5,116,6,102,3,107,10,114,58, + 1,0,1,0,1,0,103,0,125,2,89,0,110,2,88,0, + 116,7,106,8,160,9,100,1,161,1,115,84,116,10,124,2, + 131,1,124,0,95,11,110,78,116,10,131,0,125,3,120,64, + 124,2,68,0,93,56,125,4,124,4,160,12,100,2,161,1, + 92,3,125,5,125,6,125,7,124,6,114,138,100,3,160,13, + 124,5,124,7,160,14,161,0,161,2,125,8,110,4,124,5, + 125,8,124,3,160,15,124,8,161,1,1,0,113,96,87,0, + 124,3,124,0,95,11,116,7,106,8,160,9,116,16,161,1, + 114,190,100,4,100,5,132,0,124,2,68,0,131,1,124,0, + 95,17,100,6,83,0,41,7,122,68,70,105,108,108,32,116, + 104,101,32,99,97,99,104,101,32,111,102,32,112,111,116,101, + 110,116,105,97,108,32,109,111,100,117,108,101,115,32,97,110, + 100,32,112,97,99,107,97,103,101,115,32,102,111,114,32,116, + 104,105,115,32,100,105,114,101,99,116,111,114,121,46,114,0, + 0,0,0,114,59,0,0,0,122,5,123,125,46,123,125,99, + 1,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0, + 83,0,0,0,115,20,0,0,0,104,0,124,0,93,12,125, + 1,124,1,160,0,161,0,146,2,113,4,83,0,114,2,0, + 0,0,41,1,114,90,0,0,0,41,2,114,22,0,0,0, + 90,2,102,110,114,2,0,0,0,114,2,0,0,0,114,4, + 0,0,0,250,9,60,115,101,116,99,111,109,112,62,151,5, + 0,0,115,2,0,0,0,6,0,122,41,70,105,108,101,70, + 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, + 101,46,60,108,111,99,97,108,115,62,46,60,115,101,116,99, + 111,109,112,62,78,41,18,114,35,0,0,0,114,1,0,0, + 0,114,227,0,0,0,114,45,0,0,0,114,224,0,0,0, + 218,15,80,101,114,109,105,115,115,105,111,110,69,114,114,111, + 114,218,18,78,111,116,65,68,105,114,101,99,116,111,114,121, + 69,114,114,111,114,114,6,0,0,0,114,7,0,0,0,114, + 8,0,0,0,114,22,1,0,0,114,23,1,0,0,114,85, + 0,0,0,114,48,0,0,0,114,90,0,0,0,218,3,97, + 100,100,114,9,0,0,0,114,24,1,0,0,41,9,114,102, + 0,0,0,114,35,0,0,0,114,228,0,0,0,90,21,108, + 111,119,101,114,95,115,117,102,102,105,120,95,99,111,110,116, + 101,110,116,115,114,1,1,0,0,114,100,0,0,0,114,248, + 0,0,0,114,236,0,0,0,90,8,110,101,119,95,110,97, + 109,101,114,2,0,0,0,114,2,0,0,0,114,4,0,0, + 0,114,26,1,0,0,122,5,0,0,115,34,0,0,0,0, + 2,6,1,2,1,22,1,20,3,10,3,12,1,12,7,6, + 1,10,1,16,1,4,1,18,2,4,1,14,1,6,1,12, + 1,122,22,70,105,108,101,70,105,110,100,101,114,46,95,102, + 105,108,108,95,99,97,99,104,101,99,1,0,0,0,0,0, + 0,0,3,0,0,0,3,0,0,0,7,0,0,0,115,18, + 0,0,0,135,0,135,1,102,2,100,1,100,2,132,8,125, + 2,124,2,83,0,41,3,97,20,1,0,0,65,32,99,108, + 97,115,115,32,109,101,116,104,111,100,32,119,104,105,99,104, + 32,114,101,116,117,114,110,115,32,97,32,99,108,111,115,117, + 114,101,32,116,111,32,117,115,101,32,111,110,32,115,121,115, + 46,112,97,116,104,95,104,111,111,107,10,32,32,32,32,32, + 32,32,32,119,104,105,99,104,32,119,105,108,108,32,114,101, + 116,117,114,110,32,97,110,32,105,110,115,116,97,110,99,101, + 32,117,115,105,110,103,32,116,104,101,32,115,112,101,99,105, + 102,105,101,100,32,108,111,97,100,101,114,115,32,97,110,100, + 32,116,104,101,32,112,97,116,104,10,32,32,32,32,32,32, + 32,32,99,97,108,108,101,100,32,111,110,32,116,104,101,32, + 99,108,111,115,117,114,101,46,10,10,32,32,32,32,32,32, + 32,32,73,102,32,116,104,101,32,112,97,116,104,32,99,97, + 108,108,101,100,32,111,110,32,116,104,101,32,99,108,111,115, + 117,114,101,32,105,115,32,110,111,116,32,97,32,100,105,114, + 101,99,116,111,114,121,44,32,73,109,112,111,114,116,69,114, + 114,111,114,32,105,115,10,32,32,32,32,32,32,32,32,114, + 97,105,115,101,100,46,10,10,32,32,32,32,32,32,32,32, + 99,1,0,0,0,0,0,0,0,1,0,0,0,4,0,0, + 0,19,0,0,0,115,34,0,0,0,116,0,124,0,131,1, + 115,20,116,1,100,1,124,0,100,2,141,2,130,1,136,0, + 124,0,102,1,136,1,158,2,142,0,83,0,41,3,122,45, + 80,97,116,104,32,104,111,111,107,32,102,111,114,32,105,109, + 112,111,114,116,108,105,98,46,109,97,99,104,105,110,101,114, + 121,46,70,105,108,101,70,105,110,100,101,114,46,122,30,111, + 110,108,121,32,100,105,114,101,99,116,111,114,105,101,115,32, + 97,114,101,32,115,117,112,112,111,114,116,101,100,41,1,114, + 35,0,0,0,41,2,114,46,0,0,0,114,101,0,0,0, + 41,1,114,35,0,0,0,41,2,114,172,0,0,0,114,25, + 1,0,0,114,2,0,0,0,114,4,0,0,0,218,24,112, + 97,116,104,95,104,111,111,107,95,102,111,114,95,70,105,108, + 101,70,105,110,100,101,114,163,5,0,0,115,6,0,0,0, + 0,2,8,1,12,1,122,54,70,105,108,101,70,105,110,100, + 101,114,46,112,97,116,104,95,104,111,111,107,46,60,108,111, + 99,97,108,115,62,46,112,97,116,104,95,104,111,111,107,95, + 102,111,114,95,70,105,108,101,70,105,110,100,101,114,114,2, + 0,0,0,41,3,114,172,0,0,0,114,25,1,0,0,114, + 31,1,0,0,114,2,0,0,0,41,2,114,172,0,0,0, + 114,25,1,0,0,114,4,0,0,0,218,9,112,97,116,104, + 95,104,111,111,107,153,5,0,0,115,4,0,0,0,0,10, + 14,6,122,20,70,105,108,101,70,105,110,100,101,114,46,112, + 97,116,104,95,104,111,111,107,99,1,0,0,0,0,0,0, + 0,1,0,0,0,3,0,0,0,67,0,0,0,115,12,0, + 0,0,100,1,160,0,124,0,106,1,161,1,83,0,41,2, + 78,122,16,70,105,108,101,70,105,110,100,101,114,40,123,33, + 114,125,41,41,2,114,48,0,0,0,114,35,0,0,0,41, + 1,114,102,0,0,0,114,2,0,0,0,114,2,0,0,0, + 114,4,0,0,0,114,0,1,0,0,171,5,0,0,115,2, + 0,0,0,0,1,122,19,70,105,108,101,70,105,110,100,101, + 114,46,95,95,114,101,112,114,95,95,41,1,78,41,15,114, + 107,0,0,0,114,106,0,0,0,114,108,0,0,0,114,109, + 0,0,0,114,186,0,0,0,114,6,1,0,0,114,125,0, + 0,0,114,183,0,0,0,114,119,0,0,0,114,18,1,0, + 0,114,182,0,0,0,114,26,1,0,0,114,184,0,0,0, + 114,32,1,0,0,114,0,1,0,0,114,2,0,0,0,114, + 2,0,0,0,114,2,0,0,0,114,4,0,0,0,114,19, + 1,0,0,28,5,0,0,115,18,0,0,0,12,9,8,14, + 8,4,4,2,8,12,8,5,10,48,8,31,12,18,114,19, + 1,0,0,99,4,0,0,0,0,0,0,0,6,0,0,0, + 8,0,0,0,67,0,0,0,115,146,0,0,0,124,0,160, + 0,100,1,161,1,125,4,124,0,160,0,100,2,161,1,125, + 5,124,4,115,66,124,5,114,36,124,5,106,1,125,4,110, + 30,124,2,124,3,107,2,114,56,116,2,124,1,124,2,131, + 2,125,4,110,10,116,3,124,1,124,2,131,2,125,4,124, + 5,115,84,116,4,124,1,124,2,124,4,100,3,141,3,125, + 5,121,36,124,5,124,0,100,2,60,0,124,4,124,0,100, + 1,60,0,124,2,124,0,100,4,60,0,124,3,124,0,100, + 5,60,0,87,0,110,20,4,0,116,5,107,10,114,140,1, + 0,1,0,1,0,89,0,110,2,88,0,100,0,83,0,41, + 6,78,218,10,95,95,108,111,97,100,101,114,95,95,218,8, + 95,95,115,112,101,99,95,95,41,1,114,122,0,0,0,90, + 8,95,95,102,105,108,101,95,95,90,10,95,95,99,97,99, + 104,101,100,95,95,41,6,218,3,103,101,116,114,122,0,0, + 0,114,234,0,0,0,114,229,0,0,0,114,169,0,0,0, + 218,9,69,120,99,101,112,116,105,111,110,41,6,90,2,110, + 115,114,100,0,0,0,90,8,112,97,116,104,110,97,109,101, + 90,9,99,112,97,116,104,110,97,109,101,114,122,0,0,0, + 114,166,0,0,0,114,2,0,0,0,114,2,0,0,0,114, + 4,0,0,0,218,14,95,102,105,120,95,117,112,95,109,111, + 100,117,108,101,177,5,0,0,115,34,0,0,0,0,2,10, + 1,10,1,4,1,4,1,8,1,8,1,12,2,10,1,4, + 1,14,1,2,1,8,1,8,1,8,1,12,1,14,2,114, + 37,1,0,0,99,0,0,0,0,0,0,0,0,3,0,0, + 0,3,0,0,0,67,0,0,0,115,38,0,0,0,116,0, + 116,1,160,2,161,0,102,2,125,0,116,3,116,4,102,2, + 125,1,116,5,116,6,102,2,125,2,124,0,124,1,124,2, + 103,3,83,0,41,1,122,95,82,101,116,117,114,110,115,32, + 97,32,108,105,115,116,32,111,102,32,102,105,108,101,45,98, + 97,115,101,100,32,109,111,100,117,108,101,32,108,111,97,100, + 101,114,115,46,10,10,32,32,32,32,69,97,99,104,32,105, + 116,101,109,32,105,115,32,97,32,116,117,112,108,101,32,40, + 108,111,97,100,101,114,44,32,115,117,102,102,105,120,101,115, + 41,46,10,32,32,32,32,41,7,114,235,0,0,0,114,143, + 0,0,0,218,18,101,120,116,101,110,115,105,111,110,95,115, + 117,102,102,105,120,101,115,114,229,0,0,0,114,86,0,0, + 0,114,234,0,0,0,114,76,0,0,0,41,3,90,10,101, + 120,116,101,110,115,105,111,110,115,90,6,115,111,117,114,99, + 101,90,8,98,121,116,101,99,111,100,101,114,2,0,0,0, + 114,2,0,0,0,114,4,0,0,0,114,163,0,0,0,200, + 5,0,0,115,8,0,0,0,0,5,12,1,8,1,8,1, + 114,163,0,0,0,99,1,0,0,0,0,0,0,0,12,0, + 0,0,9,0,0,0,67,0,0,0,115,156,1,0,0,124, + 0,97,0,116,0,106,1,97,1,116,0,106,2,97,2,116, + 1,106,3,116,4,25,0,125,1,120,56,100,1,68,0,93, + 48,125,2,124,2,116,1,106,3,107,7,114,58,116,0,160, + 5,124,2,161,1,125,3,110,10,116,1,106,3,124,2,25, + 0,125,3,116,6,124,1,124,2,124,3,131,3,1,0,113, + 32,87,0,100,2,100,3,103,1,102,2,100,4,100,5,100, + 3,103,2,102,2,102,2,125,4,120,118,124,4,68,0,93, + 102,92,2,125,5,125,6,116,7,100,6,100,7,132,0,124, + 6,68,0,131,1,131,1,115,142,116,8,130,1,124,6,100, + 8,25,0,125,7,124,5,116,1,106,3,107,6,114,174,116, + 1,106,3,124,5,25,0,125,8,80,0,113,112,121,16,116, + 0,160,5,124,5,161,1,125,8,80,0,87,0,113,112,4, + 0,116,9,107,10,114,212,1,0,1,0,1,0,119,112,89, + 0,113,112,88,0,113,112,87,0,116,9,100,9,131,1,130, + 1,116,6,124,1,100,10,124,8,131,3,1,0,116,6,124, + 1,100,11,124,7,131,3,1,0,116,6,124,1,100,12,100, + 13,160,10,124,6,161,1,131,3,1,0,116,0,160,5,100, + 14,161,1,125,9,116,6,124,1,100,14,124,9,131,3,1, + 0,116,0,160,5,100,15,161,1,125,10,116,6,124,1,100, + 15,124,10,131,3,1,0,124,5,100,4,107,2,144,1,114, + 88,116,0,160,5,100,16,161,1,125,11,116,6,124,1,100, + 17,124,11,131,3,1,0,116,6,124,1,100,18,116,11,131, + 0,131,3,1,0,116,12,160,13,116,2,160,14,161,0,161, + 1,1,0,124,5,100,4,107,2,144,1,114,152,116,15,160, + 16,100,19,161,1,1,0,100,20,116,12,107,6,144,1,114, + 152,100,21,116,17,95,18,100,22,83,0,41,23,122,205,83, + 101,116,117,112,32,116,104,101,32,112,97,116,104,45,98,97, + 115,101,100,32,105,109,112,111,114,116,101,114,115,32,102,111, + 114,32,105,109,112,111,114,116,108,105,98,32,98,121,32,105, + 109,112,111,114,116,105,110,103,32,110,101,101,100,101,100,10, + 32,32,32,32,98,117,105,108,116,45,105,110,32,109,111,100, + 117,108,101,115,32,97,110,100,32,105,110,106,101,99,116,105, + 110,103,32,116,104,101,109,32,105,110,116,111,32,116,104,101, + 32,103,108,111,98,97,108,32,110,97,109,101,115,112,97,99, + 101,46,10,10,32,32,32,32,79,116,104,101,114,32,99,111, + 109,112,111,110,101,110,116,115,32,97,114,101,32,101,120,116, + 114,97,99,116,101,100,32,102,114,111,109,32,116,104,101,32, + 99,111,114,101,32,98,111,111,116,115,116,114,97,112,32,109, + 111,100,117,108,101,46,10,10,32,32,32,32,41,4,114,50, + 0,0,0,114,61,0,0,0,218,8,98,117,105,108,116,105, + 110,115,114,140,0,0,0,90,5,112,111,115,105,120,250,1, + 47,90,2,110,116,250,1,92,99,1,0,0,0,0,0,0, + 0,2,0,0,0,3,0,0,0,115,0,0,0,115,26,0, + 0,0,124,0,93,18,125,1,116,0,124,1,131,1,100,0, + 107,2,86,0,1,0,113,2,100,1,83,0,41,2,114,29, + 0,0,0,78,41,1,114,31,0,0,0,41,2,114,22,0, + 0,0,114,79,0,0,0,114,2,0,0,0,114,2,0,0, + 0,114,4,0,0,0,114,238,0,0,0,236,5,0,0,115, + 2,0,0,0,4,0,122,25,95,115,101,116,117,112,46,60, + 108,111,99,97,108,115,62,46,60,103,101,110,101,120,112,114, + 62,114,60,0,0,0,122,30,105,109,112,111,114,116,108,105, + 98,32,114,101,113,117,105,114,101,115,32,112,111,115,105,120, + 32,111,114,32,110,116,114,1,0,0,0,114,25,0,0,0, + 114,21,0,0,0,114,30,0,0,0,90,7,95,116,104,114, + 101,97,100,90,8,95,119,101,97,107,114,101,102,90,6,119, + 105,110,114,101,103,114,171,0,0,0,114,5,0,0,0,122, + 4,46,112,121,119,122,6,95,100,46,112,121,100,84,78,41, + 19,114,116,0,0,0,114,6,0,0,0,114,143,0,0,0, + 114,250,0,0,0,114,107,0,0,0,90,18,95,98,117,105, + 108,116,105,110,95,102,114,111,109,95,110,97,109,101,114,111, + 0,0,0,218,3,97,108,108,114,151,0,0,0,114,101,0, + 0,0,114,26,0,0,0,114,11,0,0,0,114,240,0,0, + 0,114,147,0,0,0,114,38,1,0,0,114,86,0,0,0, + 114,165,0,0,0,114,170,0,0,0,114,174,0,0,0,41, + 12,218,17,95,98,111,111,116,115,116,114,97,112,95,109,111, + 100,117,108,101,90,11,115,101,108,102,95,109,111,100,117,108, + 101,90,12,98,117,105,108,116,105,110,95,110,97,109,101,90, + 14,98,117,105,108,116,105,110,95,109,111,100,117,108,101,90, + 10,111,115,95,100,101,116,97,105,108,115,90,10,98,117,105, + 108,116,105,110,95,111,115,114,21,0,0,0,114,25,0,0, + 0,90,9,111,115,95,109,111,100,117,108,101,90,13,116,104, + 114,101,97,100,95,109,111,100,117,108,101,90,14,119,101,97, + 107,114,101,102,95,109,111,100,117,108,101,90,13,119,105,110, + 114,101,103,95,109,111,100,117,108,101,114,2,0,0,0,114, + 2,0,0,0,114,4,0,0,0,218,6,95,115,101,116,117, + 112,211,5,0,0,115,76,0,0,0,0,8,4,1,6,1, + 6,3,10,1,10,1,10,1,12,2,10,1,16,3,22,1, + 14,2,22,1,8,1,10,1,10,1,4,2,2,1,10,1, + 6,1,14,1,12,2,8,1,12,1,12,1,18,3,10,1, + 12,3,10,1,12,3,10,1,10,1,12,3,14,1,14,1, + 10,1,10,1,10,1,114,44,1,0,0,99,1,0,0,0, + 0,0,0,0,2,0,0,0,4,0,0,0,67,0,0,0, + 115,50,0,0,0,116,0,124,0,131,1,1,0,116,1,131, + 0,125,1,116,2,106,3,160,4,116,5,106,6,124,1,142, + 0,103,1,161,1,1,0,116,2,106,7,160,8,116,9,161, + 1,1,0,100,1,83,0,41,2,122,41,73,110,115,116,97, + 108,108,32,116,104,101,32,112,97,116,104,45,98,97,115,101, + 100,32,105,109,112,111,114,116,32,99,111,109,112,111,110,101, + 110,116,115,46,78,41,10,114,44,1,0,0,114,163,0,0, + 0,114,6,0,0,0,114,11,1,0,0,114,147,0,0,0, + 114,19,1,0,0,114,32,1,0,0,218,9,109,101,116,97, + 95,112,97,116,104,114,165,0,0,0,114,5,1,0,0,41, + 2,114,43,1,0,0,90,17,115,117,112,112,111,114,116,101, + 100,95,108,111,97,100,101,114,115,114,2,0,0,0,114,2, + 0,0,0,114,4,0,0,0,218,8,95,105,110,115,116,97, + 108,108,19,6,0,0,115,8,0,0,0,0,2,8,1,6, + 1,20,1,114,46,1,0,0,41,1,114,47,0,0,0,41, + 1,78,41,3,78,78,78,41,2,114,60,0,0,0,114,60, + 0,0,0,41,1,84,41,1,78,41,1,78,41,61,114,109, + 0,0,0,114,10,0,0,0,90,37,95,67,65,83,69,95, + 73,78,83,69,78,83,73,84,73,86,69,95,80,76,65,84, + 70,79,82,77,83,95,66,89,84,69,83,95,75,69,89,114, + 9,0,0,0,114,11,0,0,0,114,17,0,0,0,114,19, + 0,0,0,114,28,0,0,0,114,38,0,0,0,114,39,0, + 0,0,114,43,0,0,0,114,44,0,0,0,114,46,0,0, + 0,114,56,0,0,0,218,4,116,121,112,101,218,8,95,95, + 99,111,100,101,95,95,114,142,0,0,0,114,15,0,0,0, + 114,129,0,0,0,114,14,0,0,0,114,18,0,0,0,114, + 209,0,0,0,114,75,0,0,0,114,74,0,0,0,114,86, + 0,0,0,114,76,0,0,0,90,23,68,69,66,85,71,95, + 66,89,84,69,67,79,68,69,95,83,85,70,70,73,88,69, + 83,90,27,79,80,84,73,77,73,90,69,68,95,66,89,84, + 69,67,79,68,69,95,83,85,70,70,73,88,69,83,114,81, + 0,0,0,114,87,0,0,0,114,93,0,0,0,114,97,0, + 0,0,114,99,0,0,0,114,118,0,0,0,114,125,0,0, + 0,114,133,0,0,0,114,137,0,0,0,114,139,0,0,0, + 114,145,0,0,0,114,150,0,0,0,114,152,0,0,0,114, + 157,0,0,0,218,6,111,98,106,101,99,116,114,164,0,0, + 0,114,169,0,0,0,114,170,0,0,0,114,185,0,0,0, + 114,195,0,0,0,114,212,0,0,0,114,229,0,0,0,114, + 234,0,0,0,114,240,0,0,0,114,235,0,0,0,114,241, + 0,0,0,114,3,1,0,0,114,5,1,0,0,114,19,1, + 0,0,114,37,1,0,0,114,163,0,0,0,114,44,1,0, + 0,114,46,1,0,0,114,2,0,0,0,114,2,0,0,0, + 114,2,0,0,0,114,4,0,0,0,218,8,60,109,111,100, + 117,108,101,62,23,0,0,0,115,118,0,0,0,4,0,4, + 1,4,1,2,1,6,3,8,17,8,5,8,5,8,6,8, + 12,8,10,8,9,8,5,8,7,10,22,10,127,0,3,16, + 1,12,2,4,1,4,2,6,2,6,2,8,2,16,45,8, + 34,8,19,8,12,8,12,8,28,8,17,8,33,8,28,8, + 24,10,13,10,10,10,11,8,14,6,3,4,1,14,67,14, + 64,14,29,16,127,0,17,14,68,18,45,18,26,4,3,18, + 53,14,60,14,42,14,127,0,7,14,127,0,22,10,23,8, + 11,8,64, }; From lp_benchmark_robot at intel.com Fri Apr 6 20:56:47 2018 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 6 Apr 2018 17:56:47 -0700 Subject: [Python-checkins] [65 flat] Results for Python (master branch) 2018-04-06 Message-ID: <0b38bdd1-1d21-41fe-821b-bfeb01dff924@orsmsx155.amr.corp.intel.com> Results for project python/master, build date: 2018-04-06 03:02:42-07:00. - commit: 0c1c456 - previous commit: 0876505 - revision date: 2018-04-06 15:51:24+09:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.204% | -0.120% | +8.126% | +8.532% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 0.770% | +0.034% | +24.788% | +13.063% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 2.302% | -0.204% | +26.145% | +11.396% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 0.999% | +0.195% | +23.589% | +12.626% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 1.682% | +0.422% | +10.516% | +14.222% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.243% | +0.092% | +12.793% | +10.021% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 0.921% | -0.044% | +7.382% | +10.242% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.543% | -0.378% | -1.790% | +11.200% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.682% | -0.558% | +11.005% | +17.637% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 3.972% | -1.257% | +13.657% | +16.995% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.472% | -0.327% | +5.479% | +7.389% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 0.414% | -0.036% | +6.272% | +5.510% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 2.554% | -0.131% | +2.427% | +8.179% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 1.478% | +0.698% | +14.509% | +10.450% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.121% | +0.972% | +10.712% | +10.697% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 7.335% | +0.612% | +4.551% | +12.253% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.684% | -0.213% | +11.247% | +11.897% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 2.586% | +0.096% | +12.740% | +10.699% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 1.542% | +0.373% | +2.345% | +10.718% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 1.479% | +1.100% | -2.575% | +14.426% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.673% | -0.065% | +18.626% | +13.205% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 2.457% | +0.371% | +47.567% | +12.802% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.507% | -0.128% | +13.798% | +13.300% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.287% | +0.111% | +17.452% | +14.606% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 1.853% | -0.371% | +9.059% | +10.074% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 2.381% | +0.356% | +6.000% | +5.312% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 0.860% | -0.053% | +0.201% | +2.816% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.674% | -0.010% | +5.803% | +8.543% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.297% | -0.359% | +1.206% | +9.146% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 1.119% | +0.334% | +2.006% | +18.846% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.227% | +0.045% | +2.867% | +19.135% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 0.844% | +0.152% | +3.582% | +21.003% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 4.947% | +0.817% | +12.117% | +11.037% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.190% | -0.015% | +0.182% | +10.554% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.131% | -0.190% | +18.046% | +5.446% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.113% | -0.096% | +5.070% | +5.532% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 0.937% | -0.045% | +10.703% | +13.453% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 4.252% | +0.200% | +5.890% | +11.829% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_dna| 0.383% | +0.019% | -1.985% | +11.176% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 2.358% | -0.613% | -6.695% | +7.893% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_v8| 1.270% | -0.366% | +3.635% | +10.814% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.844% | +0.081% | +10.419% | +15.730% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 0.532% | +0.364% | -2.145% | +5.269% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 3.524% | -0.764% | +23.639% | +13.178% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 2.466% | -0.144% | +4.243% | +6.986% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 1.427% | +0.177% | +14.419% | +10.608% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 0.847% | -0.230% | -7.157% | +0.904% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.535% | +0.182% | +2.792% | +8.200% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 1.381% | -0.011% | +6.823% | +8.020% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 2.941% | +0.380% | +8.850% | +4.845% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 3.243% | -0.493% | +0.465% | +9.468% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 2.921% | -0.533% | +17.606% | +8.129% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.681% | -0.194% | +12.966% | +6.866% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 4.015% | -0.642% | +17.294% | +9.819% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 5.928% | +0.749% | +16.696% | +11.189% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 5.090% | -0.212% | +20.060% | +11.362% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 0.903% | -0.312% | +7.752% | +7.109% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 2.524% | -0.487% | +1.648% | +1.053% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 6.716% | +0.479% | +8.042% | +22.245% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 1.552% | -0.278% | -1.685% | +12.731% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 0.851% | +0.202% | +8.413% | +7.258% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 1.290% | -0.161% | +4.852% | +11.096% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 1.880% | +0.182% | +3.997% | +7.715% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 2.203% | +0.463% | -5.510% | +10.077% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 1.350% | +0.031% | +5.917% | +11.279% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/65-flat-results-for-python-master-branch-2018-04-06 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Fri Apr 6 21:27:12 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 01:27:12 -0000 Subject: [Python-checkins] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) Message-ID: https://github.com/python/cpython/commit/ef5ce884a41c8553a7eff66ebace908c1dcc1f89 commit: ef5ce884a41c8553a7eff66ebace908c1dcc1f89 branch: master author: Jay Crotts committer: Ned Deily date: 2018-04-06T21:27:07-04:00 summary: bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) files: A Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst M Doc/library/curses.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 13717f7b35e6..2a2ee2be84af 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -685,6 +685,12 @@ the following methods and attributes: character previously painter at that location. By default, the character position and attributes are the current settings for the window object. + .. note:: + + Writing outside the window, subwindow, or pad raises a :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the character is printed. + .. method:: window.addnstr(str, n[, attr]) window.addnstr(y, x, str, n[, attr]) @@ -700,6 +706,12 @@ the following methods and attributes: Paint the character string *str* at ``(y, x)`` with attributes *attr*, overwriting anything previously on the display. + .. note:: + + Writing outside the window, subwindow, or pad raises :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the string is printed. + .. method:: window.attroff(attr) diff --git a/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst new file mode 100644 index 000000000000..a3520d05c095 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst @@ -0,0 +1,2 @@ +Add a note about curses.addch and curses.addstr exception behavior when +writing outside a window, or pad. From webhook-mailer at python.org Fri Apr 6 22:00:09 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 02:00:09 -0000 Subject: [Python-checkins] [3.7] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6404) Message-ID: https://github.com/python/cpython/commit/98e8ac8d82202aae32961f10b1014641ae1fffbf commit: 98e8ac8d82202aae32961f10b1014641ae1fffbf branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-06T22:00:06-04:00 summary: [3.7] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6404) (cherry picked from commit ef5ce884a41c8553a7eff66ebace908c1dcc1f89) Co-authored-by: Jay Crotts files: A Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst M Doc/library/curses.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 13717f7b35e6..2a2ee2be84af 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -685,6 +685,12 @@ the following methods and attributes: character previously painter at that location. By default, the character position and attributes are the current settings for the window object. + .. note:: + + Writing outside the window, subwindow, or pad raises a :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the character is printed. + .. method:: window.addnstr(str, n[, attr]) window.addnstr(y, x, str, n[, attr]) @@ -700,6 +706,12 @@ the following methods and attributes: Paint the character string *str* at ``(y, x)`` with attributes *attr*, overwriting anything previously on the display. + .. note:: + + Writing outside the window, subwindow, or pad raises :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the string is printed. + .. method:: window.attroff(attr) diff --git a/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst new file mode 100644 index 000000000000..a3520d05c095 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst @@ -0,0 +1,2 @@ +Add a note about curses.addch and curses.addstr exception behavior when +writing outside a window, or pad. From webhook-mailer at python.org Fri Apr 6 22:01:06 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 02:01:06 -0000 Subject: [Python-checkins] [3.6] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6406) Message-ID: https://github.com/python/cpython/commit/70c44465475c41ab3aa832858b250ede6f170aac commit: 70c44465475c41ab3aa832858b250ede6f170aac branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-06T22:01:03-04:00 summary: [3.6] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6406) (cherry picked from commit ef5ce884a41c8553a7eff66ebace908c1dcc1f89) Co-authored-by: Jay Crotts files: A Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst M Doc/library/curses.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 14e32d78e0d1..9d87db64a4a2 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -685,6 +685,12 @@ the following methods and attributes: character previously painter at that location. By default, the character position and attributes are the current settings for the window object. + .. note:: + + Writing outside the window, subwindow, or pad raises a :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the character is printed. + .. method:: window.addnstr(str, n[, attr]) window.addnstr(y, x, str, n[, attr]) @@ -700,6 +706,12 @@ the following methods and attributes: Paint the character string *str* at ``(y, x)`` with attributes *attr*, overwriting anything previously on the display. + .. note:: + + Writing outside the window, subwindow, or pad raises :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the string is printed. + .. method:: window.attroff(attr) diff --git a/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst new file mode 100644 index 000000000000..a3520d05c095 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst @@ -0,0 +1,2 @@ +Add a note about curses.addch and curses.addstr exception behavior when +writing outside a window, or pad. From webhook-mailer at python.org Fri Apr 6 22:01:38 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 02:01:38 -0000 Subject: [Python-checkins] [2.7] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6405) Message-ID: https://github.com/python/cpython/commit/77f0a41d72886513f5e9277e5587455745c29ac1 commit: 77f0a41d72886513f5e9277e5587455745c29ac1 branch: 2.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-06T22:01:35-04:00 summary: [2.7] bpo-8243: Doc patch for curses.window.addstr and curses.window.addch (GH-5179) (GH-6405) (cherry picked from commit ef5ce884a41c8553a7eff66ebace908c1dcc1f89) Co-authored-by: Jay Crotts files: A Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst M Doc/library/curses.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index b36b9d73e353..5ea246b83fe2 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -663,6 +663,12 @@ the following methods: character previously painter at that location. By default, the character position and attributes are the current settings for the window object. + .. note:: + + Writing outside the window, subwindow, or pad raises a :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the character is printed. + .. method:: window.addnstr(str, n[, attr]) window.addnstr(y, x, str, n[, attr]) @@ -677,6 +683,12 @@ the following methods: Paint the string *str* at ``(y, x)`` with attributes *attr*, overwriting anything previously on the display. + .. note:: + + Writing outside the window, subwindow, or pad raises :exc:`curses.error`. + Attempting to write to the lower right corner of a window, subwindow, + or pad will cause an exception to be raised after the string is printed. + .. method:: window.attroff(attr) diff --git a/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst new file mode 100644 index 000000000000..a3520d05c095 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-01-13-20-30-53.bpo-8243.s98r28.rst @@ -0,0 +1,2 @@ +Add a note about curses.addch and curses.addstr exception behavior when +writing outside a window, or pad. From webhook-mailer at python.org Sat Apr 7 02:36:06 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 06:36:06 -0000 Subject: [Python-checkins] bpo-33184: Update macOS installer build to use OpenSSL 1.1.0h. (GH-6407) Message-ID: https://github.com/python/cpython/commit/b405752dab95fa5dc65a19d94e798844d0378c61 commit: b405752dab95fa5dc65a19d94e798844d0378c61 branch: master author: Ned Deily committer: GitHub date: 2018-04-07T02:36:02-04:00 summary: bpo-33184: Update macOS installer build to use OpenSSL 1.1.0h. (GH-6407) files: A Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index d2e88d896cee..68868d97a65c 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -215,9 +215,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.0g", - url="https://www.openssl.org/source/openssl-1.1.0g.tar.gz", - checksum='ba5f1b8b835b88cadbce9b35ed9531a6', + name="OpenSSL 1.1.0h", + url="https://www.openssl.org/source/openssl-1.1.0h.tar.gz", + checksum='5271477e4d93f4ea032b665ef095ff24', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst b/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst new file mode 100644 index 000000000000..03308ed6a72b --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst @@ -0,0 +1 @@ +Update macOS installer build to use OpenSSL 1.1.0h. From webhook-mailer at python.org Sat Apr 7 03:02:43 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 07:02:43 -0000 Subject: [Python-checkins] bpo-33184: Update macOS installer build to use OpenSSL 1.1.0h. (GH-6407) (GH-6409) Message-ID: https://github.com/python/cpython/commit/12d1dcd1f8ec0a2f3d8c325aa8e3f2f05b75b188 commit: 12d1dcd1f8ec0a2f3d8c325aa8e3f2f05b75b188 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Ned Deily date: 2018-04-07T03:02:40-04:00 summary: bpo-33184: Update macOS installer build to use OpenSSL 1.1.0h. (GH-6407) (GH-6409) (cherry picked from commit b405752dab95fa5dc65a19d94e798844d0378c61) Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index d2e88d896cee..68868d97a65c 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -215,9 +215,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.0g", - url="https://www.openssl.org/source/openssl-1.1.0g.tar.gz", - checksum='ba5f1b8b835b88cadbce9b35ed9531a6', + name="OpenSSL 1.1.0h", + url="https://www.openssl.org/source/openssl-1.1.0h.tar.gz", + checksum='5271477e4d93f4ea032b665ef095ff24', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst b/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst new file mode 100644 index 000000000000..03308ed6a72b --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2018-04-07-00-51-34.bpo-33184.3j208P.rst @@ -0,0 +1 @@ +Update macOS installer build to use OpenSSL 1.1.0h. From webhook-mailer at python.org Sat Apr 7 03:04:06 2018 From: webhook-mailer at python.org (Ned Deily) Date: Sat, 07 Apr 2018 07:04:06 -0000 Subject: [Python-checkins] bpo-33184: Update macOS installer build to use OpenSSL 1.0.2o. (GH-6408) Message-ID: https://github.com/python/cpython/commit/76215a4481191b648de522a4e2120f60822f6b9c commit: 76215a4481191b648de522a4e2120f60822f6b9c branch: 3.6 author: Ned Deily committer: GitHub date: 2018-04-07T03:04:03-04:00 summary: bpo-33184: Update macOS installer build to use OpenSSL 1.0.2o. (GH-6408) files: A Misc/NEWS.d/next/macOS/2018-04-07-00-58-50.bpo-33184.rMTiqu.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index c33737e9d042..ef81bc147e21 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -210,9 +210,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.0.2n", - url="https://www.openssl.org/source/openssl-1.0.2n.tar.gz", - checksum='13bdc1b1d1ff39b6fd42a255e74676a4', + name="OpenSSL 1.0.2o", + url="https://www.openssl.org/source/openssl-1.0.2o.tar.gz", + checksum='44279b8557c3247cbe324e2322ecd114', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2018-04-07-00-58-50.bpo-33184.rMTiqu.rst b/Misc/NEWS.d/next/macOS/2018-04-07-00-58-50.bpo-33184.rMTiqu.rst new file mode 100644 index 000000000000..9840dc937220 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2018-04-07-00-58-50.bpo-33184.rMTiqu.rst @@ -0,0 +1 @@ +Update macOS installer build to use OpenSSL 1.0.2o. From solipsis at pitrou.net Sat Apr 7 05:13:18 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 07 Apr 2018 09:13:18 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=12 Message-ID: <20180407091318.1.99EC6F44B307341D@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_asyncio leaked [3, 0, 0] memory blocks, sum=3 test_collections leaked [0, 7, -7] memory blocks, sum=0 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_fork leaked [2, -2, 2] memory blocks, sum=2 test_multiprocessing_forkserver leaked [2, 0, 1] memory blocks, sum=3 test_multiprocessing_spawn leaked [1, -2, 1] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogliIiXq', '--timeout', '7200'] From webhook-mailer at python.org Sat Apr 7 12:14:12 2018 From: webhook-mailer at python.org (Antoine Pitrou) Date: Sat, 07 Apr 2018 16:14:12 -0000 Subject: [Python-checkins] bpo-33201: Modernize "Extension types" doc (GH-6337) Message-ID: https://github.com/python/cpython/commit/1d80a561734b9932961c546b0897405a3bfbf3e6 commit: 1d80a561734b9932961c546b0897405a3bfbf3e6 branch: master author: Antoine Pitrou committer: GitHub date: 2018-04-07T18:14:03+02:00 summary: bpo-33201: Modernize "Extension types" doc (GH-6337) * bpo-33201: Modernize "Extension types" doc * Split tutorial and other topics * Some small fixes * Address some review comments * Rename noddy* to custom* and shoddy to sublist * Fix markup files: A Doc/extending/newtypes_tutorial.rst A Doc/includes/custom.c A Doc/includes/custom2.c A Doc/includes/custom3.c A Doc/includes/custom4.c A Doc/includes/sublist.c A Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst D Doc/includes/noddy.c D Doc/includes/noddy2.c D Doc/includes/noddy3.c D Doc/includes/noddy4.c D Doc/includes/shoddy.c M Doc/extending/index.rst M Doc/extending/newtypes.rst M Doc/includes/test.py diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst index 80594e357fd4..0994e3e8627d 100644 --- a/Doc/extending/index.rst +++ b/Doc/extending/index.rst @@ -26,9 +26,11 @@ Recommended third party tools ============================= This guide only covers the basic tools for creating extensions provided -as part of this version of CPython. Third party tools like Cython, -``cffi``, SWIG and Numba offer both simpler and more sophisticated -approaches to creating C and C++ extensions for Python. +as part of this version of CPython. Third party tools like +`Cython `_, `cffi `_, +`SWIG `_ and `Numba `_ +offer both simpler and more sophisticated approaches to creating C and C++ +extensions for Python. .. seealso:: @@ -52,6 +54,7 @@ C extensions. :numbered: extending.rst + newtypes_tutorial.rst newtypes.rst building.rst windows.rst diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index d5eb7fb7c8b8..d0d2ec1f8820 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1,889 +1,11 @@ .. highlightlang:: c - -.. _defining-new-types: - -****************** -Defining New Types -****************** - -.. sectionauthor:: Michael Hudson -.. sectionauthor:: Dave Kuhlman -.. sectionauthor:: Jim Fulton - - -As mentioned in the last chapter, Python allows the writer of an extension -module to define new types that can be manipulated from Python code, much like -strings and lists in core Python. - -This is not hard; the code for all extension types follows a pattern, but there -are some details that you need to understand before you can get started. - - -.. _dnt-basics: - -The Basics -========== - -The Python runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. -:c:type:`PyObject` itself only contains the refcount and a pointer to the -object's "type object". This is where the action is; the type object determines -which (C) functions get called when, for instance, an attribute gets looked -up on an object or it is multiplied by another object. These C functions -are called "type methods". - -So, if you want to define a new object type, you need to create a new type -object. - -This sort of thing can only be explained by example, so here's a minimal, but -complete, module that defines a new type: - -.. literalinclude:: ../includes/noddy.c - - -Now that's quite a bit to take in at once, but hopefully bits will seem familiar -from the last chapter. - -The first bit that will be new is:: - - typedef struct { - PyObject_HEAD - } noddy_NoddyObject; - -This is what a Noddy object will contain---in this case, nothing more than what -every Python object contains---a field called ``ob_base`` of type -:c:type:`PyObject`. :c:type:`PyObject` in turn, contains an ``ob_refcnt`` -field and a pointer to a type object. These can be accessed using the macros -:c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE` respectively. These are the fields -the :c:macro:`PyObject_HEAD` macro brings in. The reason for the macro is to -standardize the layout and to enable special debugging fields in debug builds. - -Note that there is no semicolon after the :c:macro:`PyObject_HEAD` macro; -one is included in the macro definition. Be wary of adding one by -accident; it's easy to do from habit, and your compiler might not complain, -but someone else's probably will! (On Windows, MSVC is known to call this an -error and refuse to compile the code.) - -For contrast, let's take a look at the corresponding definition for standard -Python floats:: - - typedef struct { - PyObject_HEAD - double ob_fval; - } PyFloatObject; - -Moving on, we come to the crunch --- the type object. :: - - static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ - }; - -Now if you go and look up the definition of :c:type:`PyTypeObject` in -:file:`object.h` you'll see that it has many more fields that the definition -above. The remaining fields will be filled with zeros by the C compiler, and -it's common practice to not specify them explicitly unless you need them. - -This is so important that we're going to pick the top of it apart still -further:: - - PyVarObject_HEAD_INIT(NULL, 0) - -This line is a bit of a wart; what we'd like to write is:: - - PyVarObject_HEAD_INIT(&PyType_Type, 0) - -as the type of a type object is "type", but this isn't strictly conforming C and -some compilers complain. Fortunately, this member will be filled in for us by -:c:func:`PyType_Ready`. :: - - "noddy.Noddy", /* tp_name */ - -The name of our type. This will appear in the default textual representation of -our objects and in some error messages, for example:: - - >>> "" + noddy.new_noddy() - Traceback (most recent call last): - File "", line 1, in - TypeError: cannot add type "noddy.Noddy" to string - -Note that the name is a dotted name that includes both the module name and the -name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. -One side effect of using an undotted name is that the pydoc documentation tool -will not list the new type in the module documentation. :: - - sizeof(noddy_NoddyObject), /* tp_basicsize */ - -This is so that Python knows how much memory to allocate when you call -:c:func:`PyObject_New`. - -.. note:: - - If you want your type to be subclassable from Python, and your type has the same - :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple - inheritance. A Python subclass of your type will have to list your type first - in its :attr:`~class.__bases__`, or else it will not be able to call your type's - :meth:`__new__` method without getting an error. You can avoid this problem by - ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its - base type does. Most of the time, this will be true anyway, because either your - base type will be :class:`object`, or else you will be adding data members to - your base type, and therefore increasing its size. - -:: - - 0, /* tp_itemsize */ - -This has to do with variable length objects like lists and strings. Ignore this -for now. - -Skipping a number of type methods that we don't provide, we set the class flags -to :const:`Py_TPFLAGS_DEFAULT`. :: - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - -All types should include this constant in their flags. It enables all of the -members defined until at least Python 3.3. If you need further members, -you will need to OR the corresponding flags. - -We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: - - "Noddy objects", /* tp_doc */ - -Now we get into the type methods, the things that make your objects different -from the others. We aren't going to implement any of these in this version of -the module. We'll expand this example later to have more interesting behavior. - -For now, all we want to be able to do is to create new :class:`Noddy` objects. -To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` implementation. -In this case, we can just use the default implementation provided by the API -function :c:func:`PyType_GenericNew`. :: - - PyType_GenericNew, /* tp_new */ - -All the other type methods are *NULL*, so we'll go over them later --- that's -for a later section! - -Everything else in the file should be familiar, except for some code in -:c:func:`PyInit_noddy`:: - - if (PyType_Ready(&noddy_NoddyType) < 0) - return; - -This initializes the :class:`Noddy` type, filing in a number of members, -including :attr:`ob_type` that we initially set to *NULL*. :: - - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - -This adds the type to the module dictionary. This allows us to create -:class:`Noddy` instances by calling the :class:`Noddy` class:: - - >>> import noddy - >>> mynoddy = noddy.Noddy() - -That's it! All that remains is to build it; put the above code in a file called -:file:`noddy.c` and :: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[Extension("noddy", ["noddy.c"])]) - -in a file called :file:`setup.py`; then typing - -.. code-block:: shell-session - - $ python setup.py build - -at a shell should produce a file :file:`noddy.so` in a subdirectory; move to -that directory and fire up Python --- you should be able to ``import noddy`` and -play around with Noddy objects. - -That wasn't so hard, was it? - -Of course, the current Noddy type is pretty uninteresting. It has no data and -doesn't do anything. It can't even be subclassed. - - -Adding data and methods to the Basic example --------------------------------------------- - -Let's extend the basic example to add some data and methods. Let's also make -the type usable as a base class. We'll create a new module, :mod:`noddy2` that -adds these capabilities: - -.. literalinclude:: ../includes/noddy2.c - - -This version of the module has a number of changes. - -We've added an extra include:: - - #include - -This include provides declarations that we use to handle attributes, as -described a bit later. - -The name of the :class:`Noddy` object structure has been shortened to -:class:`Noddy`. The type object name has been shortened to :class:`NoddyType`. - -The :class:`Noddy` type now has three data attributes, *first*, *last*, and -*number*. The *first* and *last* variables are Python strings containing first -and last names. The *number* attribute is an integer. - -The object structure is updated accordingly:: - - typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; - } Noddy; - -Because we now have data to manage, we have to be more careful about object -allocation and deallocation. At a minimum, we need a deallocation method:: - - static void - Noddy_dealloc(Noddy* self) - { - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: - - (destructor)Noddy_dealloc, /*tp_dealloc*/ - -This method decrements the reference counts of the two Python attributes. We use -:c:func:`Py_XDECREF` here because the :attr:`first` and :attr:`last` members -could be *NULL*. It then calls the :c:member:`~PyTypeObject.tp_free` member of the object's type -to free the object's memory. Note that the object's type might not be -:class:`NoddyType`, because the object may be an instance of a subclass. - -We want to make sure that the first and last names are initialized to empty -strings, so we provide a new method:: - - static PyObject * - Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; - } - -and install it in the :c:member:`~PyTypeObject.tp_new` member:: - - Noddy_new, /* tp_new */ - -The new member is responsible for creating (as opposed to initializing) objects -of the type. It is exposed in Python as the :meth:`__new__` method. See the -paper titled "Unifying types and classes in Python" for a detailed discussion of -the :meth:`__new__` method. One reason to implement a new method is to assure -the initial values of instance variables. In this case, we use the new method -to make sure that the initial values of the members :attr:`first` and -:attr:`last` are not *NULL*. If we didn't care whether the initial values were -*NULL*, we could have used :c:func:`PyType_GenericNew` as our new method, as we -did before. :c:func:`PyType_GenericNew` initializes all of the instance variable -members to *NULL*. - -The new method is a static method that is passed the type being instantiated and -any arguments passed when the type was called, and that returns the new object -created. New methods always accept positional and keyword arguments, but they -often ignore the arguments, leaving the argument handling to initializer -methods. Note that if the type supports subclassing, the type passed may not be -the type being defined. The new method calls the :c:member:`~PyTypeObject.tp_alloc` slot to -allocate memory. We don't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather -:c:func:`PyType_Ready` fills it for us by inheriting it from our base class, -which is :class:`object` by default. Most types use the default allocation. - -.. note:: - - If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one that calls a base type's - :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), you must *not* try to determine what method - to call using method resolution order at runtime. Always statically determine - what type you are going to call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via - ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your - type that also inherit from other Python-defined classes may not work correctly. - (Specifically, you may not be able to create instances of such subclasses - without getting a :exc:`TypeError`.) - -We provide an initialization function:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; - } - -by filling the :c:member:`~PyTypeObject.tp_init` slot. :: - - (initproc)Noddy_init, /* tp_init */ - -The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the :meth:`__init__` method. It -is used to initialize an object after it's created. Unlike the new method, we -can't guarantee that the initializer is called. The initializer isn't called -when unpickling objects and it can be overridden. Our initializer accepts -arguments to provide initial values for our instance. Initializers always accept -positional and keyword arguments. Initializers should return either ``0`` on -success or ``-1`` on error. - -Initializers can be called multiple times. Anyone can call the :meth:`__init__` -method on our objects. For this reason, we have to be extra careful when -assigning the new values. We might be tempted, for example to assign the -:attr:`first` member like this:: - - if (first) { - Py_XDECREF(self->first); - Py_INCREF(first); - self->first = first; - } - -But this would be risky. Our type doesn't restrict the type of the -:attr:`first` member, so it could be any kind of object. It could have a -destructor that causes code to be executed that tries to access the -:attr:`first` member. To be paranoid and protect ourselves against this -possibility, we almost always reassign members before decrementing their -reference counts. When don't we have to do this? - -* when we absolutely know that the reference count is greater than 1 - -* when we know that deallocation of the object [#]_ will not cause any calls - back into our type's code - -* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` handler when - garbage-collections is not supported [#]_ - -We want to expose our instance variables as attributes. There are a -number of ways to do that. The simplest way is to define member definitions:: - - static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: - - Noddy_members, /* tp_members */ - -Each member definition has a member name, type, offset, access flags and -documentation string. See the :ref:`Generic-Attribute-Management` section below for -details. - -A disadvantage of this approach is that it doesn't provide a way to restrict the -types of objects that can be assigned to the Python attributes. We expect the -first and last names to be strings, but any Python objects can be assigned. -Further, the attributes can be deleted, setting the C pointers to *NULL*. Even -though we can make sure the members are initialized to non-*NULL* values, the -members can be set to *NULL* if the attributes are deleted. - -We define a single method, :meth:`name`, that outputs the objects name as the -concatenation of the first and last names. :: - - static PyObject * - Noddy_name(Noddy* self) - { - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); - } - -The method is implemented as a C function that takes a :class:`Noddy` (or -:class:`Noddy` subclass) instance as the first argument. Methods always take an -instance as the first argument. Methods often take positional and keyword -arguments as well, but in this case we don't take any and don't need to accept -a positional argument tuple or keyword argument dictionary. This method is -equivalent to the Python method:: - - def name(self): - return "%s %s" % (self.first, self.last) - -Note that we have to check for the possibility that our :attr:`first` and -:attr:`last` members are *NULL*. This is because they can be deleted, in which -case they are set to *NULL*. It would be better to prevent deletion of these -attributes and to restrict the attribute values to be strings. We'll see how to -do that in the next section. - -Now that we've defined the method, we need to create an array of method -definitions:: - - static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ - }; - -and assign them to the :c:member:`~PyTypeObject.tp_methods` slot:: - - Noddy_methods, /* tp_methods */ - -Note that we used the :const:`METH_NOARGS` flag to indicate that the method is -passed no arguments. - -Finally, we'll make our type usable as a base class. We've written our methods -carefully so far so that they don't make any assumptions about the type of the -object being created or used, so all we need to do is to add the -:const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - -We rename :c:func:`PyInit_noddy` to :c:func:`PyInit_noddy2` and update the module -name in the :c:type:`PyModuleDef` struct. - -Finally, we update our :file:`setup.py` file to build the new module:: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[ - Extension("noddy", ["noddy.c"]), - Extension("noddy2", ["noddy2.c"]), - ]) - - -Providing finer control over data attributes --------------------------------------------- - -In this section, we'll provide finer control over how the :attr:`first` and -:attr:`last` attributes are set in the :class:`Noddy` example. In the previous -version of our module, the instance variables :attr:`first` and :attr:`last` -could be set to non-string values or even deleted. We want to make sure that -these attributes always contain strings. - -.. literalinclude:: ../includes/noddy3.c - - -To provide greater control, over the :attr:`first` and :attr:`last` attributes, -we'll use custom getter and setter functions. Here are the functions for -getting and setting the :attr:`first` attribute:: - - Noddy_getfirst(Noddy *self, void *closure) - { - Py_INCREF(self->first); - return self->first; - } - - static int - Noddy_setfirst(Noddy *self, PyObject *value, void *closure) - { - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a str"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; - } - -The getter function is passed a :class:`Noddy` object and a "closure", which is -void pointer. In this case, the closure is ignored. (The closure supports an -advanced usage in which definition data is passed to the getter and setter. This -could, for example, be used to allow a single set of getter and setter functions -that decide the attribute to get or set based on data in the closure.) - -The setter function is passed the :class:`Noddy` object, the new value, and the -closure. The new value may be *NULL*, in which case the attribute is being -deleted. In our setter, we raise an error if the attribute is deleted or if the -attribute value is not a string. - -We create an array of :c:type:`PyGetSetDef` structures:: - - static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ - }; - -and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: - - Noddy_getseters, /* tp_getset */ - -to register our attribute getters and setters. - -The last item in a :c:type:`PyGetSetDef` structure is the closure mentioned -above. In this case, we aren't using the closure, so we just pass *NULL*. - -We also remove the member definitions for these attributes:: - - static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only allow strings [#]_ to -be passed:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; - } - -With these changes, we can assure that the :attr:`first` and :attr:`last` -members are never *NULL* so we can remove checks for *NULL* values in almost all -cases. This means that most of the :c:func:`Py_XDECREF` calls can be converted to -:c:func:`Py_DECREF` calls. The only place we can't change these calls is in the -deallocator, where there is the possibility that the initialization of these -members failed in the constructor. - -We also rename the module initialization function and module name in the -initialization function, as we did before, and we add an extra definition to the -:file:`setup.py` file. - - -Supporting cyclic garbage collection ------------------------------------- - -Python has a cyclic-garbage collector that can identify unneeded objects even -when their reference counts are not zero. This can happen when objects are -involved in cycles. For example, consider:: - - >>> l = [] - >>> l.append(l) - >>> del l - -In this example, we create a list that contains itself. When we delete it, it -still has a reference from itself. Its reference count doesn't drop to zero. -Fortunately, Python's cyclic-garbage collector will eventually figure out that -the list is garbage and free it. - -In the second version of the :class:`Noddy` example, we allowed any kind of -object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. This -means that :class:`Noddy` objects can participate in cycles:: - - >>> import noddy2 - >>> n = noddy2.Noddy() - >>> l = [n] - >>> n.first = l - -This is pretty silly, but it gives us an excuse to add support for the -cyclic-garbage collector to the :class:`Noddy` example. To support cyclic -garbage collection, types need to fill two slots and set a class flag that -enables these slots: - -.. literalinclude:: ../includes/noddy4.c - - -The traversal method provides access to subobjects that could participate in -cycles:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; - } - -For each subobject that can participate in cycles, we need to call the -:c:func:`visit` function, which is passed to the traversal method. The -:c:func:`visit` function takes as arguments the subobject and the extra argument -*arg* passed to the traversal method. It returns an integer value that must be -returned if it is non-zero. - -Python provides a :c:func:`Py_VISIT` macro that automates calling visit -functions. With :c:func:`Py_VISIT`, :c:func:`Noddy_traverse` can be simplified:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - Py_VISIT(self->first); - Py_VISIT(self->last); - return 0; - } - -.. note:: - - Note that the :c:member:`~PyTypeObject.tp_traverse` implementation must name its arguments exactly - *visit* and *arg* in order to use :c:func:`Py_VISIT`. This is to encourage - uniformity across these boring implementations. - -We also need to provide a method for clearing any subobjects that can -participate in cycles. - -:: - - static int - Noddy_clear(Noddy *self) - { - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; - } - -Notice the use of a temporary variable in :c:func:`Noddy_clear`. We use the -temporary variable so that we can set each member to *NULL* before decrementing -its reference count. We do this because, as was discussed earlier, if the -reference count drops to zero, we might cause code to run that calls back into -the object. In addition, because we now support garbage collection, we also -have to worry about code being run that triggers garbage collection. If garbage -collection is run, our :c:member:`~PyTypeObject.tp_traverse` handler could get called. We can't -take a chance of having :c:func:`Noddy_traverse` called when a member's reference -count has dropped to zero and its value hasn't been set to *NULL*. - -Python provides a :c:func:`Py_CLEAR` that automates the careful decrementing of -reference counts. With :c:func:`Py_CLEAR`, the :c:func:`Noddy_clear` function can -be simplified:: - - static int - Noddy_clear(Noddy *self) - { - Py_CLEAR(self->first); - Py_CLEAR(self->last); - return 0; - } - -Note that :c:func:`Noddy_dealloc` may call arbitrary functions through -``__del__`` method or weakref callback. It means circular GC can be -triggered inside the function. Since GC assumes reference count is not zero, -we need to untrack the object from GC by calling :c:func:`PyObject_GC_UnTrack` -before clearing members. Here is reimplemented deallocator which uses -:c:func:`PyObject_GC_UnTrack` and :c:func:`Noddy_clear`. - -:: - - static void - Noddy_dealloc(Noddy* self) - { - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - -That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or -:c:member:`~PyTypeObject.tp_free` slots, we'd need to modify them for cyclic-garbage collection. -Most extensions will use the versions automatically provided. - - -Subclassing other types ------------------------ - -It is possible to create new extension types that are derived from existing -types. It is easiest to inherit from the built in types, since an extension can -easily use the :class:`PyTypeObject` it needs. It can be difficult to share -these :class:`PyTypeObject` structures between extension modules. - -In this example we will create a :class:`Shoddy` type that inherits from the -built-in :class:`list` type. The new type will be completely compatible with -regular lists, but will have an additional :meth:`increment` method that -increases an internal counter. :: - - >>> import shoddy - >>> s = shoddy.Shoddy(range(3)) - >>> s.extend(s) - >>> print(len(s)) - 6 - >>> print(s.increment()) - 1 - >>> print(s.increment()) - 2 - -.. literalinclude:: ../includes/shoddy.c - - -As you can see, the source code closely resembles the :class:`Noddy` examples in -previous sections. We will break down the main differences between them. :: - - typedef struct { - PyListObject list; - int state; - } Shoddy; - -The primary difference for derived type objects is that the base type's object -structure must be the first value. The base type will already include the -:c:func:`PyObject_HEAD` at the beginning of its structure. - -When a Python object is a :class:`Shoddy` instance, its *PyObject\** pointer can -be safely cast to both *PyListObject\** and *Shoddy\**. :: - - static int - Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) - { - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; - } - -In the :attr:`__init__` method for our type, we can see how to call through to -the :attr:`__init__` method of the base type. - -This pattern is important when writing a type with custom :attr:`new` and -:attr:`dealloc` methods. The :attr:`new` method should not actually create the -memory for the object with :c:member:`~PyTypeObject.tp_alloc`, that will be handled by the base -class when calling its :c:member:`~PyTypeObject.tp_new`. - -When filling out the :c:func:`PyTypeObject` for the :class:`Shoddy` type, you see -a slot for :c:func:`tp_base`. Due to cross platform compiler issues, you can't -fill that field directly with the :c:func:`PyList_Type`; it can be done later in -the module's :c:func:`init` function. :: - - PyMODINIT_FUNC - PyInit_shoddy(void) - { - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; - } - -Before calling :c:func:`PyType_Ready`, the type structure must have the -:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving a new type, it is not -necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` slot with :c:func:`PyType_GenericNew` --- the allocate function from the base type will be inherited. - -After that, calling :c:func:`PyType_Ready` and adding the type object to the -module is the same as with the basic :class:`Noddy` examples. - +***************************************** +Defining Extension Types: Assorted Topics +***************************************** .. _dnt-type-methods: -Type Methods -============ - This section aims to give a quick fly-by on the various type methods you can implement and what they do. @@ -893,21 +15,20 @@ debug builds omitted: .. literalinclude:: ../includes/typestruct.h -Now that's a *lot* of methods. Don't worry too much though - if you have a type -you want to define, the chances are very good that you will only implement a -handful of these. +Now that's a *lot* of methods. Don't worry too much though -- if you have +a type you want to define, the chances are very good that you will only +implement a handful of these. As you probably expect by now, we're going to go over this and give more information about the various handlers. We won't go in the order they are defined in the structure, because there is a lot of historical baggage that -impacts the ordering of the fields; be sure your type initialization keeps the -fields in the right order! It's often easiest to find an example that includes -all the fields you need (even if they're initialized to ``0``) and then change -the values to suit your new type. :: +impacts the ordering of the fields. It's often easiest to find an example +that includes the fields you need and then change the values to suit your new +type. :: const char *tp_name; /* For printing */ -The name of the type - as mentioned in the last section, this will appear in +The name of the type -- as mentioned in the previous chapter, this will appear in various places, almost entirely for diagnostic purposes. Try to choose something that will be helpful in such a situation! :: @@ -915,7 +36,7 @@ that will be helpful in such a situation! :: These fields tell the runtime how much memory to allocate when new objects of this type are created. Python has some built-in support for variable length -structures (think: strings, lists) which is where the :c:member:`~PyTypeObject.tp_itemsize` field +structures (think: strings, tuples) which is where the :c:member:`~PyTypeObject.tp_itemsize` field comes in. This will be dealt with later. :: const char *tp_doc; @@ -923,7 +44,7 @@ comes in. This will be dealt with later. :: Here you can put a string (or its address) that you want returned when the Python script references ``obj.__doc__`` to retrieve the doc string. -Now we come to the basic type methods---the ones most extension types will +Now we come to the basic type methods -- the ones most extension types will implement. @@ -947,7 +68,7 @@ object itself needs to be freed here as well. Here is an example of this function:: static void - newdatatype_dealloc(newdatatypeobject * obj) + newdatatype_dealloc(newdatatypeobject *obj) { free(obj->obj_UnderlyingDatatypePtr); Py_TYPE(obj)->tp_free(obj); @@ -1035,7 +156,7 @@ example:: static PyObject * newdatatype_repr(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1055,7 +176,7 @@ Here is a simple example:: static PyObject * newdatatype_str(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Stringified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1236,7 +357,7 @@ example that simply raises an exception; if this were really all you wanted, the static int newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v) { - (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name); + PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name); return -1; } @@ -1321,17 +442,23 @@ these in the :file:`Objects` directory of the Python source distribution. :: hashfunc tp_hash; This function, if you choose to provide it, should return a hash number for an -instance of your data type. Here is a moderately pointless example:: +instance of your data type. Here is a simple example:: - static long + static Py_hash_t newdatatype_hash(newdatatypeobject *obj) { - long result; - result = obj->obj_UnderlyingDatatypePtr->size; - result = result * 3; + Py_hash_t result; + result = obj->some_size + 32767 * obj->some_number; + if (result == -1) + result = -2; return result; } +:c:type:`Py_hash_t` is a signed integer type with a platform-varying width. +Returning ``-1`` from :c:member:`~PyTypeObject.tp_hash` indicates an error, +which is why you should be careful to avoid returning it when hash computation +is successful, as seen above. + :: ternaryfunc tp_call; @@ -1342,27 +469,22 @@ contains ``obj1('hello')``, the :c:member:`~PyTypeObject.tp_call` handler is inv This function takes three arguments: -#. *arg1* is the instance of the data type which is the subject of the call. If - the call is ``obj1('hello')``, then *arg1* is ``obj1``. +#. *self* is the instance of the data type which is the subject of the call. + If the call is ``obj1('hello')``, then *self* is ``obj1``. -#. *arg2* is a tuple containing the arguments to the call. You can use +#. *args* is a tuple containing the arguments to the call. You can use :c:func:`PyArg_ParseTuple` to extract the arguments. -#. *arg3* is a dictionary of keyword arguments that were passed. If this is +#. *kwds* is a dictionary of keyword arguments that were passed. If this is non-*NULL* and you support keyword arguments, use - :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you do not - want to support keyword arguments and this is non-*NULL*, raise a + :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you + do not want to support keyword arguments and this is non-*NULL*, raise a :exc:`TypeError` with a message saying that keyword arguments are not supported. -Here is a desultory example of the implementation of the call function. :: +Here is a toy ``tp_call`` implementation:: - /* Implement the call function. - * obj1 is the instance receiving the call. - * obj2 is a tuple containing the arguments to the call, in this - * case 3 strings. - */ static PyObject * - newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *other) + newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds) { PyObject *result; const char *arg1; @@ -1373,7 +495,7 @@ Here is a desultory example of the implementation of the call function. :: return NULL; } result = PyUnicode_FromFormat( - "Returning -- value: [\%d] arg1: [\%s] arg2: [\%s] arg3: [\%s]\n", + "Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n", obj->obj_UnderlyingDatatypePtr->size, arg1, arg2, arg3); return result; @@ -1385,32 +507,36 @@ Here is a desultory example of the implementation of the call function. :: getiterfunc tp_iter; iternextfunc tp_iternext; -These functions provide support for the iterator protocol. Any object which -wishes to support iteration over its contents (which may be generated during -iteration) must implement the ``tp_iter`` handler. Objects which are returned -by a ``tp_iter`` handler must implement both the ``tp_iter`` and ``tp_iternext`` -handlers. Both handlers take exactly one parameter, the instance for which they -are being called, and return a new reference. In the case of an error, they -should set an exception and return *NULL*. - -For an object which represents an iterable collection, the ``tp_iter`` handler -must return an iterator object. The iterator object is responsible for -maintaining the state of the iteration. For collections which can support -multiple iterators which do not interfere with each other (as lists and tuples -do), a new iterator should be created and returned. Objects which can only be -iterated over once (usually due to side effects of iteration) should implement -this handler by returning a new reference to themselves, and should also -implement the ``tp_iternext`` handler. File objects are an example of such an -iterator. - -Iterator objects should implement both handlers. The ``tp_iter`` handler should -return a new reference to the iterator (this is the same as the ``tp_iter`` -handler for objects which can only be iterated over destructively). The -``tp_iternext`` handler should return a new reference to the next object in the -iteration if there is one. If the iteration has reached the end, it may return -*NULL* without setting an exception or it may set :exc:`StopIteration`; avoiding -the exception can yield slightly better performance. If an actual error occurs, -it should set an exception and return *NULL*. +These functions provide support for the iterator protocol. Both handlers +take exactly one parameter, the instance for which they are being called, +and return a new reference. In the case of an error, they should set an +exception and return *NULL*. :c:member:`~PyTypeObject.tp_iter` corresponds +to the Python :meth:`__iter__` method, while :c:member:`~PyTypeObject.tp_iternext` +corresponds to the Python :meth:`~iterator.__next__` method. + +Any :term:`iterable` object must implement the :c:member:`~PyTypeObject.tp_iter` +handler, which must return an :term:`iterator` object. Here the same guidelines +apply as for Python classes: + +* For collections (such as lists and tuples) which can support multiple + independent iterators, a new iterator should be created and returned by + each call to :c:member:`~PyTypeObject.tp_iter`. +* Objects which can only be iterated over once (usually due to side effects of + iteration, such as file objects) can implement :c:member:`~PyTypeObject.tp_iter` + by returning a new reference to themselves -- and should also therefore + implement the :c:member:`~PyTypeObject.tp_iternext` handler. + +Any :term:`iterator` object should implement both :c:member:`~PyTypeObject.tp_iter` +and :c:member:`~PyTypeObject.tp_iternext`. An iterator's +:c:member:`~PyTypeObject.tp_iter` handler should return a new reference +to the iterator. Its :c:member:`~PyTypeObject.tp_iternext` handler should +return a new reference to the next object in the iteration, if there is one. +If the iteration has reached the end, :c:member:`~PyTypeObject.tp_iternext` +may return *NULL* without setting an exception, or it may set +:exc:`StopIteration` *in addition* to returning *NULL*; avoiding +the exception can yield slightly better performance. If an actual error +occurs, :c:member:`~PyTypeObject.tp_iternext` should always set an exception +and return *NULL*. .. _weakref-support: @@ -1418,110 +544,76 @@ it should set an exception and return *NULL*. Weak Reference Support ---------------------- -One of the goals of Python's weak-reference implementation is to allow any type +One of the goals of Python's weak reference implementation is to allow any type to participate in the weak reference mechanism without incurring the overhead on -those objects which do not benefit by weak referencing (such as numbers). +performance-critical objects (such as numbers). -For an object to be weakly referencable, the extension must include a -:c:type:`PyObject\*` field in the instance structure for the use of the weak -reference mechanism; it must be initialized to *NULL* by the object's -constructor. It must also set the :c:member:`~PyTypeObject.tp_weaklistoffset` field of the -corresponding type object to the offset of the field. For example, the instance -type is defined with the following structure:: +.. seealso:: + Documentation for the :mod:`weakref` module. - typedef struct { - PyObject_HEAD - PyClassObject *in_class; /* The class object */ - PyObject *in_dict; /* A dictionary */ - PyObject *in_weakreflist; /* List of weak references */ - } PyInstanceObject; - -The statically-declared type object for instances is defined this way:: - - PyTypeObject PyInstance_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - 0, - "module.instance", - - /* Lots of stuff omitted for brevity... */ - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ - }; +For an object to be weakly referencable, the extension type must do two things: -The type constructor is responsible for initializing the weak reference list to -*NULL*:: +#. Include a :c:type:`PyObject\*` field in the C object structure dedicated to + the weak reference mechanism. The object's constructor should leave it + *NULL* (which is automatic when using the default + :c:member:`~PyTypeObject.tp_alloc`). - static PyObject * - instance_new() { - /* Other initialization stuff omitted for brevity */ +#. Set the :c:member:`~PyTypeObject.tp_weaklistoffset` type member + to the offset of the aforementioned field in the C object structure, + so that the interpreter knows how to access and modify that field. - self->in_weakreflist = NULL; +Concretely, here is how a trivial object structure would be augmented +with the required field:: - return (PyObject *) self; - } + typedef struct { + PyObject_HEAD + PyObject *weakreflist; /* List of weak references */ + } TrivialObject; -The only further addition is that the destructor needs to call the weak -reference manager to clear any weak references. This is only required if the -weak reference list is non-*NULL*:: +And the corresponding member in the statically-declared type object:: - static void - instance_dealloc(PyInstanceObject *inst) - { - /* Allocate temporaries if needed, but do not begin - destruction just yet. - */ + static PyTypeObject TrivialType = { + PyVarObject_HEAD_INIT(NULL, 0) + /* ... other members omitted for brevity ... */ + .tp_weaklistoffset = offsetof(TrivialObject, weakreflist), + }; - if (inst->in_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) inst); +The only further addition is that ``tp_dealloc`` needs to clear any weak +references (by calling :c:func:`PyObject_ClearWeakRefs`) if the field is +non-*NULL*:: - /* Proceed with object destruction normally. */ + static void + Trivial_dealloc(TrivialObject *self) + { + /* Clear weakrefs first before calling any destructors */ + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); + /* ... remainder of destruction code omitted for brevity ... */ + Py_TYPE(self)->tp_free((PyObject *) self); } More Suggestions ---------------- -Remember that you can omit most of these functions, in which case you provide -``0`` as a value. There are type definitions for each of the functions you must -provide. They are in :file:`object.h` in the Python include directory that -comes with the source distribution of Python. - In order to learn how to implement any specific method for your new data type, -do the following: Download and unpack the Python source distribution. Go to -the :file:`Objects` directory, then search the C source files for ``tp_`` plus -the function you want (for example, ``tp_richcompare``). You will find examples -of the function you want to implement. +get the :term:`CPython` source code. Go to the :file:`Objects` directory, +then search the C source files for ``tp_`` plus the function you want +(for example, ``tp_richcompare``). You will find examples of the function +you want to implement. -When you need to verify that an object is an instance of the type you are -implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of its use -might be something like the following:: +When you need to verify that an object is a concrete instance of the type you +are implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of +its use might be something like the following:: - if (! PyObject_TypeCheck(some_object, &MyType)) { + if (!PyObject_TypeCheck(some_object, &MyType)) { PyErr_SetString(PyExc_TypeError, "arg #1 not a mything"); return NULL; } -.. rubric:: Footnotes - -.. [#] This is true when we know that the object is a basic type, like a string or a - float. - -.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler in this example, because our - type doesn't support garbage collection. Even if a type supports garbage - collection, there are calls that can be made to "untrack" the object from - garbage collection, however, these calls are advanced and not covered here. - -.. [#] We now know that the first and last members are strings, so perhaps we could be - less careful about decrementing their reference counts, however, we accept - instances of string subclasses. Even though deallocating normal strings won't - call back into our objects, we can't guarantee that deallocating an instance of - a string subclass won't call back into our objects. +.. seealso:: + Download CPython source releases. + https://www.python.org/downloads/source/ -.. [#] Even in the third version, we aren't guaranteed to avoid cycles. Instances of - string subclasses are allowed and string subclasses could allow cycles even if - normal strings don't. + The CPython project on GitHub, where the CPython source code is developed. + https://github.com/python/cpython diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst new file mode 100644 index 000000000000..5e05cf693652 --- /dev/null +++ b/Doc/extending/newtypes_tutorial.rst @@ -0,0 +1,896 @@ +.. highlightlang:: c + +.. _defining-new-types: + +********************************** +Defining Extension Types: Tutorial +********************************** + +.. sectionauthor:: Michael Hudson +.. sectionauthor:: Dave Kuhlman +.. sectionauthor:: Jim Fulton + + +Python allows the writer of a C extension module to define new types that +can be manipulated from Python code, much like the built-in :class:`str` +and :class:`list` types. The code for all extension types follows a +pattern, but there are some details that you need to understand before you +can get started. This document is a gentle introduction to the topic. + + +.. _dnt-basics: + +The Basics +========== + +The :term:`CPython` runtime sees all Python objects as variables of type +:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +The :c:type:`PyObject` structure itself only contains the object's +:term:`reference count` and a pointer to the object's "type object". +This is where the action is; the type object determines which (C) functions +get called by the interpreter when, for instance, an attribute gets looked up +on an object, a method called, or it is multiplied by another object. These +C functions are called "type methods". + +So, if you want to define a new extension type, you need to create a new type +object. + +This sort of thing can only be explained by example, so here's a minimal, but +complete, module that defines a new type named :class:`Custom` inside a C +extension module :mod:`custom`: + +.. note:: + What we're showing here is the traditional way of defining *static* + extension types. It should be adequate for most uses. The C API also + allows defining heap-allocated extension types using the + :c:func:`PyType_FromSpec` function, which isn't covered in this tutorial. + +.. literalinclude:: ../includes/custom.c + +Now that's quite a bit to take in at once, but hopefully bits will seem familiar +from the previous chapter. This file defines three things: + +#. What a :class:`Custom` **object** contains: this is the ``CustomObject`` + struct, which is allocated once for each :class:`Custom` instance. +#. How the :class:`Custom` **type** behaves: this is the ``CustomType`` struct, + which defines a set of flags and function pointers that the interpreter + inspects when specific operations are requested. +#. How to initialize the :mod:`custom` module: this is the ``PyInit_custom`` + function and the associated ``custommodule`` struct. + +The first bit is:: + + typedef struct { + PyObject_HEAD + } CustomObject; + +This is what a Custom object will contain. ``PyObject_HEAD`` is mandatory +at the start of each object struct and defines a field called ``ob_base`` +of type :c:type:`PyObject`, containing a pointer to a type object and a +reference count (these can be accessed using the macros :c:macro:`Py_REFCNT` +and :c:macro:`Py_TYPE` respectively). The reason for the macro is to +abstract away the layout and to enable additional fields in debug builds. + +.. note:: + There is no semicolon above after the :c:macro:`PyObject_HEAD` macro. + Be wary of adding one by accident: some compilers will complain. + +Of course, objects generally store additional data besides the standard +``PyObject_HEAD`` boilerplate; for example, here is the definition for +standard Python floats:: + + typedef struct { + PyObject_HEAD + double ob_fval; + } PyFloatObject; + +The second bit is the definition of the type object. :: + + static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_new = PyType_GenericNew, + }; + +.. note:: + We recommend using C99-style designated initializers as above, to + avoid listing all the :c:type:`PyTypeObject` fields that you don't care + about and also to avoid caring about the fields' declaration order. + +The actual definition of :c:type:`PyTypeObject` in :file:`object.h` has +many more :ref:`fields ` than the definition above. The +remaining fields will be filled with zeros by the C compiler, and it's +common practice to not specify them explicitly unless you need them. + +We're going to pick it apart, one field at a time:: + + PyVarObject_HEAD_INIT(NULL, 0) + +This line is mandatory boilerplate to initialize the ``ob_base`` +field mentioned above. :: + + .tp_name = "custom.Custom", + +The name of our type. This will appear in the default textual representation of +our objects and in some error messages, for example: + +.. code-block:: python + + >>> "" + custom.Custom() + Traceback (most recent call last): + File "", line 1, in + TypeError: can only concatenate str (not "custom.Custom") to str + +Note that the name is a dotted name that includes both the module name and the +name of the type within the module. The module in this case is :mod:`custom` and +the type is :class:`Custom`, so we set the type name to :class:`custom.Custom`. +Using the real dotted import path is important to make your type compatible +with the :mod:`pydoc` and :mod:`pickle` modules. :: + + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + +This is so that Python knows how much memory to allocate when creating +new :class:`Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is +only used for variable-sized objects and should otherwise be zero. + +.. note:: + + If you want your type to be subclassable from Python, and your type has the same + :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple + inheritance. A Python subclass of your type will have to list your type first + in its :attr:`~class.__bases__`, or else it will not be able to call your type's + :meth:`__new__` method without getting an error. You can avoid this problem by + ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its + base type does. Most of the time, this will be true anyway, because either your + base type will be :class:`object`, or else you will be adding data members to + your base type, and therefore increasing its size. + +We set the class flags to :const:`Py_TPFLAGS_DEFAULT`. :: + + .tp_flags = Py_TPFLAGS_DEFAULT, + +All types should include this constant in their flags. It enables all of the +members defined until at least Python 3.3. If you need further members, +you will need to OR the corresponding flags. + +We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: + + .tp_doc = "Custom objects", + +To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` +handler. This is the equivalent of the Python method :meth:`__new__`, but +has to be specified explicitly. In this case, we can just use the default +implementation provided by the API function :c:func:`PyType_GenericNew`. :: + + .tp_new = PyType_GenericNew, + +Everything else in the file should be familiar, except for some code in +:c:func:`PyInit_custom`:: + + if (PyType_Ready(&CustomType) < 0) + return; + +This initializes the :class:`Custom` type, filling in a number of members +to the appropriate default values, including :attr:`ob_type` that we initially +set to *NULL*. :: + + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + +This adds the type to the module dictionary. This allows us to create +:class:`Custom` instances by calling the :class:`Custom` class: + +.. code-block:: python + + >>> import custom + >>> mycustom = custom.Custom() + +That's it! All that remains is to build it; put the above code in a file called +:file:`custom.c` and: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[Extension("custom", ["custom.c"])]) + +in a file called :file:`setup.py`; then typing + +.. code-block:: shell-session + + $ python setup.py build + +at a shell should produce a file :file:`custom.so` in a subdirectory; move to +that directory and fire up Python --- you should be able to ``import custom`` and +play around with Custom objects. + +That wasn't so hard, was it? + +Of course, the current Custom type is pretty uninteresting. It has no data and +doesn't do anything. It can't even be subclassed. + +.. note:: + While this documentation showcases the standard :mod:`distutils` module + for building C extensions, it is recommended in real-world use cases to + use the newer and better-maintained ``setuptools`` library. Documentation + on how to do this is out of scope for this document and can be found in + the `Python Packaging User's Guide `_. + + +Adding data and methods to the Basic example +============================================ + +Let's extend the basic example to add some data and methods. Let's also make +the type usable as a base class. We'll create a new module, :mod:`custom2` that +adds these capabilities: + +.. literalinclude:: ../includes/custom2.c + + +This version of the module has a number of changes. + +We've added an extra include:: + + #include + +This include provides declarations that we use to handle attributes, as +described a bit later. + +The :class:`Custom` type now has three data attributes in its C struct, +*first*, *last*, and *number*. The *first* and *last* variables are Python +strings containing first and last names. The *number* attribute is a C integer. + +The object structure is updated accordingly:: + + typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; + } CustomObject; + +Because we now have data to manage, we have to be more careful about object +allocation and deallocation. At a minimum, we need a deallocation method:: + + static void + Custom_dealloc(CustomObject *self) + { + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: + + .tp_dealloc = (destructor) Custom_dealloc, + +This method first clears the reference counts of the two Python attributes. +:c:func:`Py_XDECREF` correctly handles the case where its argument is +*NULL* (which might happen here if ``tp_new`` failed midway). It then +calls the :c:member:`~PyTypeObject.tp_free` member of the object's type +(computed by ``Py_TYPE(self)``) to free the object's memory. Note that +the object's type might not be :class:`CustomType`, because the object may +be an instance of a subclass. + +.. note:: + The explicit cast to ``destructor`` above is needed because we defined + ``Custom_dealloc`` to take a ``CustomObject *`` argument, but the ``tp_dealloc`` + function pointer expects to receive a ``PyObject *`` argument. Otherwise, + the compiler will emit a warning. This is object-oriented polymorphism, + in C! + +We want to make sure that the first and last names are initialized to empty +strings, so we provide a ``tp_new`` implementation:: + + static PyObject * + Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; + } + +and install it in the :c:member:`~PyTypeObject.tp_new` member:: + + .tp_new = Custom_new, + +The ``tp_new`` handler is responsible for creating (as opposed to initializing) +objects of the type. It is exposed in Python as the :meth:`__new__` method. +It is not required to define a ``tp_new`` member, and indeed many extension +types will simply reuse :c:func:`PyType_GenericNew` as done in the first +version of the ``Custom`` type above. In this case, we use the ``tp_new`` +handler to initialize the ``first`` and ``last`` attributes to non-*NULL* +default values. + +``tp_new`` is passed the type being instantiated (not necessarily ``CustomType``, +if a subclass is instantiated) and any arguments passed when the type was +called, and is expected to return the instance created. ``tp_new`` handlers +always accept positional and keyword arguments, but they often ignore the +arguments, leaving the argument handling to initializer (a.k.a. ``tp_init`` +in C or ``__init__`` in Python) methods. + +.. note:: + ``tp_new`` shouldn't call ``tp_init`` explicitly, as the interpreter + will do it itself. + +The ``tp_new`` implementation calls the :c:member:`~PyTypeObject.tp_alloc` +slot to allocate memory:: + + self = (CustomObject *) type->tp_alloc(type, 0); + +Since memory allocation may fail, we must check the :c:member:`~PyTypeObject.tp_alloc` +result against *NULL* before proceeding. + +.. note:: + We didn't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather + :c:func:`PyType_Ready` fills it for us by inheriting it from our base class, + which is :class:`object` by default. Most types use the default allocation + strategy. + +.. note:: + If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one + that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), + you must *not* try to determine what method to call using method resolution + order at runtime. Always statically determine what type you are going to + call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via + ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your + type that also inherit from other Python-defined classes may not work correctly. + (Specifically, you may not be able to create instances of such subclasses + without getting a :exc:`TypeError`.) + +We also define an initialization function which accepts arguments to provide +initial values for our instance:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; + } + +by filling the :c:member:`~PyTypeObject.tp_init` slot. :: + + .tp_init = (initproc) Custom_init, + +The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the +:meth:`__init__` method. It is used to initialize an object after it's +created. Initializers always accept positional and keyword arguments, +and they should return either ``0`` on success or ``-1`` on error. + +Unlike the ``tp_new`` handler, there is no guarantee that ``tp_init`` +is called at all (for example, the :mod:`pickle` module by default +doesn't call :meth:`__init__` on unpickled instances). It can also be +called multiple times. Anyone can call the :meth:`__init__` method on +our objects. For this reason, we have to be extra careful when assigning +the new attribute values. We might be tempted, for example to assign the +``first`` member like this:: + + if (first) { + Py_XDECREF(self->first); + Py_INCREF(first); + self->first = first; + } + +But this would be risky. Our type doesn't restrict the type of the +``first`` member, so it could be any kind of object. It could have a +destructor that causes code to be executed that tries to access the +``first`` member; or that destructor could release the +:term:`Global interpreter Lock` and let arbitrary code run in other +threads that accesses and modifies our object. + +To be paranoid and protect ourselves against this possibility, we almost +always reassign members before decrementing their reference counts. When +don't we have to do this? + +* when we absolutely know that the reference count is greater than 1; + +* when we know that deallocation of the object [#]_ will neither release + the :term:`GIL` nor cause any calls back into our type's code; + +* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` + handler on a type which doesn't support cyclic garbage collection [#]_. + +We want to expose our instance variables as attributes. There are a +number of ways to do that. The simplest way is to define member definitions:: + + static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: + + .tp_members = Custom_members, + +Each member definition has a member name, type, offset, access flags and +documentation string. See the :ref:`Generic-Attribute-Management` section +below for details. + +A disadvantage of this approach is that it doesn't provide a way to restrict the +types of objects that can be assigned to the Python attributes. We expect the +first and last names to be strings, but any Python objects can be assigned. +Further, the attributes can be deleted, setting the C pointers to *NULL*. Even +though we can make sure the members are initialized to non-*NULL* values, the +members can be set to *NULL* if the attributes are deleted. + +We define a single method, :meth:`Custom.name()`, that outputs the objects name as the +concatenation of the first and last names. :: + + static PyObject * + Custom_name(CustomObject *self) + { + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); + } + +The method is implemented as a C function that takes a :class:`Custom` (or +:class:`Custom` subclass) instance as the first argument. Methods always take an +instance as the first argument. Methods often take positional and keyword +arguments as well, but in this case we don't take any and don't need to accept +a positional argument tuple or keyword argument dictionary. This method is +equivalent to the Python method: + +.. code-block:: python + + def name(self): + return "%s %s" % (self.first, self.last) + +Note that we have to check for the possibility that our :attr:`first` and +:attr:`last` members are *NULL*. This is because they can be deleted, in which +case they are set to *NULL*. It would be better to prevent deletion of these +attributes and to restrict the attribute values to be strings. We'll see how to +do that in the next section. + +Now that we've defined the method, we need to create an array of method +definitions:: + + static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ + }; + +(note that we used the :const:`METH_NOARGS` flag to indicate that the method +is expecting no arguments other than *self*) + +and assign it to the :c:member:`~PyTypeObject.tp_methods` slot:: + + .tp_methods = Custom_methods, + +Finally, we'll make our type usable as a base class for subclassing. We've +written our methods carefully so far so that they don't make any assumptions +about the type of the object being created or used, so all we need to do is +to add the :const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +We rename :c:func:`PyInit_custom` to :c:func:`PyInit_custom2`, update the +module name in the :c:type:`PyModuleDef` struct, and update the full class +name in the :c:type:`PyTypeObject` struct. + +Finally, we update our :file:`setup.py` file to build the new module: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[ + Extension("custom", ["custom.c"]), + Extension("custom2", ["custom2.c"]), + ]) + + +Providing finer control over data attributes +============================================ + +In this section, we'll provide finer control over how the :attr:`first` and +:attr:`last` attributes are set in the :class:`Custom` example. In the previous +version of our module, the instance variables :attr:`first` and :attr:`last` +could be set to non-string values or even deleted. We want to make sure that +these attributes always contain strings. + +.. literalinclude:: ../includes/custom3.c + + +To provide greater control, over the :attr:`first` and :attr:`last` attributes, +we'll use custom getter and setter functions. Here are the functions for +getting and setting the :attr:`first` attribute:: + + static PyObject * + Custom_getfirst(CustomObject *self, void *closure) + { + Py_INCREF(self->first); + return self->first; + } + + static int + Custom_setfirst(CustomObject *self, PyObject *value, void *closure) + { + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; + } + +The getter function is passed a :class:`Custom` object and a "closure", which is +a void pointer. In this case, the closure is ignored. (The closure supports an +advanced usage in which definition data is passed to the getter and setter. This +could, for example, be used to allow a single set of getter and setter functions +that decide the attribute to get or set based on data in the closure.) + +The setter function is passed the :class:`Custom` object, the new value, and the +closure. The new value may be *NULL*, in which case the attribute is being +deleted. In our setter, we raise an error if the attribute is deleted or if its +new value is not a string. + +We create an array of :c:type:`PyGetSetDef` structures:: + + static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ + }; + +and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: + + .tp_getset = Custom_getsetters, + +The last item in a :c:type:`PyGetSetDef` structure is the "closure" mentioned +above. In this case, we aren't using a closure, so we just pass *NULL*. + +We also remove the member definitions for these attributes:: + + static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only +allow strings [#]_ to be passed:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; + } + +With these changes, we can assure that the ``first`` and ``last`` members are +never *NULL* so we can remove checks for *NULL* values in almost all cases. +This means that most of the :c:func:`Py_XDECREF` calls can be converted to +:c:func:`Py_DECREF` calls. The only place we can't change these calls is in +the ``tp_dealloc`` implementation, where there is the possibility that the +initialization of these members failed in ``tp_new``. + +We also rename the module initialization function and module name in the +initialization function, as we did before, and we add an extra definition to the +:file:`setup.py` file. + + +Supporting cyclic garbage collection +==================================== + +Python has a :term:`cyclic garbage collector (GC) ` that +can identify unneeded objects even when their reference counts are not zero. +This can happen when objects are involved in cycles. For example, consider: + +.. code-block:: python + + >>> l = [] + >>> l.append(l) + >>> del l + +In this example, we create a list that contains itself. When we delete it, it +still has a reference from itself. Its reference count doesn't drop to zero. +Fortunately, Python's cyclic garbage collector will eventually figure out that +the list is garbage and free it. + +In the second version of the :class:`Custom` example, we allowed any kind of +object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. +Besides, in the second and third versions, we allowed subclassing +:class:`Custom`, and subclasses may add arbitrary attributes. For any of +those two reasons, :class:`Custom` objects can participate in cycles: + +.. code-block:: python + + >>> import custom3 + >>> class Derived(custom3.Custom): pass + ... + >>> n = Derived() + >>> n.some_attribute = n + +To allow a :class:`Custom` instance participating in a reference cycle to +be properly detected and collected by the cyclic GC, our :class:`Custom` type +needs to fill two additional slots and to enable a flag that enables these slots: + +.. literalinclude:: ../includes/custom4.c + + +First, the traversal method lets the cyclic GC know about subobjects that could +participate in cycles:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + int vret; + if (self->first) { + vret = visit(self->first, arg); + if (vret != 0) + return vret; + } + if (self->last) { + vret = visit(self->last, arg); + if (vret != 0) + return vret; + } + return 0; + } + +For each subobject that can participate in cycles, we need to call the +:c:func:`visit` function, which is passed to the traversal method. The +:c:func:`visit` function takes as arguments the subobject and the extra argument +*arg* passed to the traversal method. It returns an integer value that must be +returned if it is non-zero. + +Python provides a :c:func:`Py_VISIT` macro that automates calling visit +functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate +in ``Custom_traverse``:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; + } + +.. note:: + The :c:member:`~PyTypeObject.tp_traverse` implementation must name its + arguments exactly *visit* and *arg* in order to use :c:func:`Py_VISIT`. + +Second, we need to provide a method for clearing any subobjects that can +participate in cycles:: + + static int + Custom_clear(CustomObject *self) + { + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; + } + +Notice the use of the :c:func:`Py_CLEAR` macro. It is the recommended and safe +way to clear data attributes of arbitrary types while decrementing +their reference counts. If you were to call :c:func:`Py_XDECREF` instead +on the attribute before setting it to *NULL*, there is a possibility +that the attribute's destructor would call back into code that reads the +attribute again (*especially* if there is a reference cycle). + +.. note:: + You could emulate :c:func:`Py_CLEAR` by writing:: + + PyObject *tmp; + tmp = self->first; + self->first = NULL; + Py_XDECREF(tmp); + + Nevertheless, it is much easier and less error-prone to always + use :c:func:`Py_CLEAR` when deleting an attribute. Don't + try to micro-optimize at the expense of robustness! + +The deallocator ``Custom_dealloc`` may call arbitrary code when clearing +attributes. It means the circular GC can be triggered inside the function. +Since the GC assumes reference count is not zero, we need to untrack the object +from the GC by calling :c:func:`PyObject_GC_UnTrack` before clearing members. +Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack` +and ``Custom_clear``:: + + static void + Custom_dealloc(CustomObject *self) + { + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + +That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or +:c:member:`~PyTypeObject.tp_free` handlers, we'd need to modify them for cyclic +garbage collection. Most extensions will use the versions automatically provided. + + +Subclassing other types +======================= + +It is possible to create new extension types that are derived from existing +types. It is easiest to inherit from the built in types, since an extension can +easily use the :c:type:`PyTypeObject` it needs. It can be difficult to share +these :c:type:`PyTypeObject` structures between extension modules. + +In this example we will create a :class:`SubList` type that inherits from the +built-in :class:`list` type. The new type will be completely compatible with +regular lists, but will have an additional :meth:`increment` method that +increases an internal counter: + +.. code-block:: python + + >>> import sublist + >>> s = sublist.SubList(range(3)) + >>> s.extend(s) + >>> print(len(s)) + 6 + >>> print(s.increment()) + 1 + >>> print(s.increment()) + 2 + +.. literalinclude:: ../includes/sublist.c + + +As you can see, the source code closely resembles the :class:`Custom` examples in +previous sections. We will break down the main differences between them. :: + + typedef struct { + PyListObject list; + int state; + } SubListObject; + +The primary difference for derived type objects is that the base type's +object structure must be the first value. The base type will already include +the :c:func:`PyObject_HEAD` at the beginning of its structure. + +When a Python object is a :class:`SubList` instance, its ``PyObject *`` pointer +can be safely cast to both ``PyListObject *`` and ``SubListObject *``:: + + static int + SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) + { + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; + } + +We see above how to call through to the :attr:`__init__` method of the base +type. + +This pattern is important when writing a type with custom +:c:member:`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_dealloc` +members. The :c:member:`~PyTypeObject.tp_new` handler should not actually +create the memory for the object with its :c:member:`~PyTypeObject.tp_alloc`, +but let the base class handle it by calling its own :c:member:`~PyTypeObject.tp_new`. + +The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject.tp_base` +specifying the type's concrete base class. Due to cross-platform compiler +issues, you can't fill that field directly with a reference to +:c:type:`PyList_Type`; it should be done later in the module initialization +function:: + + PyMODINIT_FUNC + PyInit_sublist(void) + { + PyObject* m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; + } + +Before calling :c:func:`PyType_Ready`, the type structure must have the +:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving an +existing type, it is not necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` +slot with :c:func:`PyType_GenericNew` -- the allocation function from the base +type will be inherited. + +After that, calling :c:func:`PyType_Ready` and adding the type object to the +module is the same as with the basic :class:`Custom` examples. + + +.. rubric:: Footnotes + +.. [#] This is true when we know that the object is a basic type, like a string or a + float. + +.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler + in this example, because our type doesn't support garbage collection. + +.. [#] We now know that the first and last members are strings, so perhaps we + could be less careful about decrementing their reference counts, however, + we accept instances of string subclasses. Even though deallocating normal + strings won't call back into our objects, we can't guarantee that deallocating + an instance of a string subclass won't call back into our objects. + +.. [#] Also, even with our attributes restricted to strings instances, the user + could pass arbitrary :class:`str` subclasses and therefore still create + reference cycles. diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c new file mode 100644 index 000000000000..fb2c7b2a430e --- /dev/null +++ b/Doc/includes/custom.c @@ -0,0 +1,39 @@ +#include + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ +} CustomObject; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = PyType_GenericNew, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c new file mode 100644 index 000000000000..51ab4b80d680 --- /dev/null +++ b/Doc/includes/custom2.c @@ -0,0 +1,132 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom2.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom2", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom2(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c new file mode 100644 index 000000000000..09e87355b91a --- /dev/null +++ b/Doc/includes/custom3.c @@ -0,0 +1,183 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + tmp = self->last; + Py_INCREF(value); + self->last = value; + Py_DECREF(tmp); + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom3.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom3", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom3(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c new file mode 100644 index 000000000000..0994d8fda0e5 --- /dev/null +++ b/Doc/includes/custom4.c @@ -0,0 +1,197 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static int +Custom_traverse(CustomObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; +} + +static int +Custom_clear(CustomObject *self) +{ + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; +} + +static void +Custom_dealloc(CustomObject *self) +{ + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->first); + self->first = value; + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->last); + self->last = value; + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom4.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_traverse = (traverseproc) Custom_traverse, + .tp_clear = (inquiry) Custom_clear, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom4", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom4(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/noddy.c b/Doc/includes/noddy.c deleted file mode 100644 index 07b5d5a9b83c..000000000000 --- a/Doc/includes/noddy.c +++ /dev/null @@ -1,72 +0,0 @@ -#include - -typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ -} noddy_NoddyObject; - -static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ -}; - -static PyModuleDef noddymodule = { - PyModuleDef_HEAD_INIT, - "noddy", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy(void) -{ - PyObject* m; - - if (PyType_Ready(&noddy_NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&noddy_NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - return m; -} diff --git a/Doc/includes/noddy2.c b/Doc/includes/noddy2.c deleted file mode 100644 index 964155845fee..000000000000 --- a/Doc/includes/noddy2.c +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy2module = { - PyModuleDef_HEAD_INIT, - "noddy2", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy2(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy2module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy3.c b/Doc/includes/noddy3.c deleted file mode 100644 index 8a5a753ca439..000000000000 --- a/Doc/includes/noddy3.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; -} - -static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_getfirst(Noddy *self, void *closure) -{ - Py_INCREF(self->first); - return self->first; -} - -static int -Noddy_setfirst(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a string"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; -} - -static PyObject * -Noddy_getlast(Noddy *self, void *closure) -{ - Py_INCREF(self->last); - return self->last; -} - -static int -Noddy_setlast(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The last attribute value must be a string"); - return -1; - } - - Py_DECREF(self->last); - Py_INCREF(value); - self->last = value; - - return 0; -} - -static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - Noddy_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy3module = { - PyModuleDef_HEAD_INIT, - "noddy3", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy3(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy3module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy4.c b/Doc/includes/noddy4.c deleted file mode 100644 index 08ba4c3d91a0..000000000000 --- a/Doc/includes/noddy4.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static int -Noddy_traverse(Noddy *self, visitproc visit, void *arg) -{ - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; -} - -static int -Noddy_clear(Noddy *self) -{ - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; -} - -static void -Noddy_dealloc(Noddy* self) -{ - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /* tp_flags */ - "Noddy objects", /* tp_doc */ - (traverseproc)Noddy_traverse, /* tp_traverse */ - (inquiry)Noddy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy4module = { - PyModuleDef_HEAD_INIT, - "noddy4", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy4(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy4module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/shoddy.c b/Doc/includes/shoddy.c deleted file mode 100644 index 0ef476532777..000000000000 --- a/Doc/includes/shoddy.c +++ /dev/null @@ -1,99 +0,0 @@ -#include - -typedef struct { - PyListObject list; - int state; -} Shoddy; - - -static PyObject * -Shoddy_increment(Shoddy *self, PyObject *unused) -{ - self->state++; - return PyLong_FromLong(self->state); -} - - -static PyMethodDef Shoddy_methods[] = { - {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, - PyDoc_STR("increment state counter")}, - {NULL}, -}; - -static int -Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) -{ - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; -} - - -static PyTypeObject ShoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "shoddy.Shoddy", /* tp_name */ - sizeof(Shoddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Shoddy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Shoddy_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -static PyModuleDef shoddymodule = { - PyModuleDef_HEAD_INIT, - "shoddy", - "Shoddy module", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_shoddy(void) -{ - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; -} diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c new file mode 100644 index 000000000000..376dddfac09c --- /dev/null +++ b/Doc/includes/sublist.c @@ -0,0 +1,63 @@ +#include + +typedef struct { + PyListObject list; + int state; +} SubListObject; + +static PyObject * +SubList_increment(SubListObject *self, PyObject *unused) +{ + self->state++; + return PyLong_FromLong(self->state); +} + +static PyMethodDef SubList_methods[] = { + {"increment", (PyCFunction) SubList_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL}, +}; + +static int +SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + +static PyTypeObject SubListType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "sublist.SubList", + .tp_doc = "SubList objects", + .tp_basicsize = sizeof(SubListObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_init = (initproc) SubList_init, + .tp_methods = SubList_methods, +}; + +static PyModuleDef sublistmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "sublist", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_sublist(void) +{ + PyObject *m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; +} diff --git a/Doc/includes/test.py b/Doc/includes/test.py index 9e9d4a67121c..09ebe3fec0bd 100644 --- a/Doc/includes/test.py +++ b/Doc/includes/test.py @@ -1,181 +1,168 @@ -"""Test module for the noddy examples +"""Test module for the custom examples -Noddy 1: +Custom 1: ->>> import noddy ->>> n1 = noddy.Noddy() ->>> n2 = noddy.Noddy() ->>> del n1 ->>> del n2 +>>> import custom +>>> c1 = custom.Custom() +>>> c2 = custom.Custom() +>>> del c1 +>>> del c2 -Noddy 2 +Custom 2 ->>> import noddy2 ->>> n1 = noddy2.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom2 +>>> c1 = custom2.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first +>>> c1.name() Traceback (most recent call last): ... AttributeError: first ->>> n1.first +>>> c1.first Traceback (most recent call last): ... AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() +>>> c1.first = 42 +>>> c1.name() '42 tell' ->>> n2 = noddy2.Noddy() ->>> n2.name() +>>> c2 = custom2.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first +>>> del c2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.name() +>>> c2.name() Traceback (most recent call last): File "", line 1, in ? AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy2.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom2.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 3 +Custom 3 ->>> import noddy3 ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1.name() +>>> import custom3 +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1.name() 'jim fulton' ->>> del n1.first +>>> del c1.first Traceback (most recent call last): File "", line 1, in ? TypeError: Cannot delete the first attribute ->>> n1.first = 42 +>>> c1.first = 42 Traceback (most recent call last): File "", line 1, in ? TypeError: The first attribute value must be a string ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n3 = noddy3.Noddy('jim', 'fulton', 'waaa') +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> n3 = custom3.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 4 +Custom 4 ->>> import noddy4 ->>> n1 = noddy4.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom4 +>>> c1 = custom4.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first Traceback (most recent call last): ... -AttributeError: first ->>> n1.first -Traceback (most recent call last): -... -AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +TypeError: Cannot delete the first attribute +>>> c1.name() +'will tell' +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() -'42 tell' ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2.name() +>>> c1.first = 42 +Traceback (most recent call last): +... +TypeError: The first attribute value must be a string +>>> c1.name() +'drew tell' +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.name() -Traceback (most recent call last): - File "", line 1, in ? -AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy4.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom4.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): - File "", line 1, in ? -TypeError: an integer is required +... +TypeError: an integer is required (got type str) Test cyclic gc(?) @@ -183,15 +170,14 @@ >>> import gc >>> gc.disable() ->>> x = [] ->>> l = [x] ->>> n2.first = l ->>> n2.first -[[]] ->>> l.append(n2) ->>> del l ->>> del n1 ->>> del n2 +>>> class Subclass(custom4.Custom): pass +... +>>> s = Subclass() +>>> s.cycle = [s] +>>> s.cycle.append(s.cycle) +>>> x = object() +>>> s.x = x +>>> del s >>> sys.getrefcount(x) 3 >>> ignore = gc.collect() diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst new file mode 100644 index 000000000000..bdee48ba0314 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst @@ -0,0 +1 @@ +Modernize documentation for writing C extension types. From webhook-mailer at python.org Sat Apr 7 12:27:09 2018 From: webhook-mailer at python.org (Antoine Pitrou) Date: Sat, 07 Apr 2018 16:27:09 -0000 Subject: [Python-checkins] bpo-33201: Modernize "Extension types" doc (GH-6337) (GH-6411) Message-ID: https://github.com/python/cpython/commit/31f1b52f1f6c2d84eacf3c6db3f6b9adf04b675e commit: 31f1b52f1f6c2d84eacf3c6db3f6b9adf04b675e branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Antoine Pitrou date: 2018-04-07T18:27:05+02:00 summary: bpo-33201: Modernize "Extension types" doc (GH-6337) (GH-6411) * bpo-33201: Modernize "Extension types" doc * Split tutorial and other topics * Some small fixes * Address some review comments * Rename noddy* to custom* and shoddy to sublist * Fix markup (cherry picked from commit 1d80a561734b9932961c546b0897405a3bfbf3e6) Co-authored-by: Antoine Pitrou files: A Doc/extending/newtypes_tutorial.rst A Doc/includes/custom.c A Doc/includes/custom2.c A Doc/includes/custom3.c A Doc/includes/custom4.c A Doc/includes/sublist.c A Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst D Doc/includes/noddy.c D Doc/includes/noddy2.c D Doc/includes/noddy3.c D Doc/includes/noddy4.c D Doc/includes/shoddy.c M Doc/extending/index.rst M Doc/extending/newtypes.rst M Doc/includes/test.py diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst index 80594e357fd4..0994e3e8627d 100644 --- a/Doc/extending/index.rst +++ b/Doc/extending/index.rst @@ -26,9 +26,11 @@ Recommended third party tools ============================= This guide only covers the basic tools for creating extensions provided -as part of this version of CPython. Third party tools like Cython, -``cffi``, SWIG and Numba offer both simpler and more sophisticated -approaches to creating C and C++ extensions for Python. +as part of this version of CPython. Third party tools like +`Cython `_, `cffi `_, +`SWIG `_ and `Numba `_ +offer both simpler and more sophisticated approaches to creating C and C++ +extensions for Python. .. seealso:: @@ -52,6 +54,7 @@ C extensions. :numbered: extending.rst + newtypes_tutorial.rst newtypes.rst building.rst windows.rst diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index d5eb7fb7c8b8..d0d2ec1f8820 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1,889 +1,11 @@ .. highlightlang:: c - -.. _defining-new-types: - -****************** -Defining New Types -****************** - -.. sectionauthor:: Michael Hudson -.. sectionauthor:: Dave Kuhlman -.. sectionauthor:: Jim Fulton - - -As mentioned in the last chapter, Python allows the writer of an extension -module to define new types that can be manipulated from Python code, much like -strings and lists in core Python. - -This is not hard; the code for all extension types follows a pattern, but there -are some details that you need to understand before you can get started. - - -.. _dnt-basics: - -The Basics -========== - -The Python runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. -:c:type:`PyObject` itself only contains the refcount and a pointer to the -object's "type object". This is where the action is; the type object determines -which (C) functions get called when, for instance, an attribute gets looked -up on an object or it is multiplied by another object. These C functions -are called "type methods". - -So, if you want to define a new object type, you need to create a new type -object. - -This sort of thing can only be explained by example, so here's a minimal, but -complete, module that defines a new type: - -.. literalinclude:: ../includes/noddy.c - - -Now that's quite a bit to take in at once, but hopefully bits will seem familiar -from the last chapter. - -The first bit that will be new is:: - - typedef struct { - PyObject_HEAD - } noddy_NoddyObject; - -This is what a Noddy object will contain---in this case, nothing more than what -every Python object contains---a field called ``ob_base`` of type -:c:type:`PyObject`. :c:type:`PyObject` in turn, contains an ``ob_refcnt`` -field and a pointer to a type object. These can be accessed using the macros -:c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE` respectively. These are the fields -the :c:macro:`PyObject_HEAD` macro brings in. The reason for the macro is to -standardize the layout and to enable special debugging fields in debug builds. - -Note that there is no semicolon after the :c:macro:`PyObject_HEAD` macro; -one is included in the macro definition. Be wary of adding one by -accident; it's easy to do from habit, and your compiler might not complain, -but someone else's probably will! (On Windows, MSVC is known to call this an -error and refuse to compile the code.) - -For contrast, let's take a look at the corresponding definition for standard -Python floats:: - - typedef struct { - PyObject_HEAD - double ob_fval; - } PyFloatObject; - -Moving on, we come to the crunch --- the type object. :: - - static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ - }; - -Now if you go and look up the definition of :c:type:`PyTypeObject` in -:file:`object.h` you'll see that it has many more fields that the definition -above. The remaining fields will be filled with zeros by the C compiler, and -it's common practice to not specify them explicitly unless you need them. - -This is so important that we're going to pick the top of it apart still -further:: - - PyVarObject_HEAD_INIT(NULL, 0) - -This line is a bit of a wart; what we'd like to write is:: - - PyVarObject_HEAD_INIT(&PyType_Type, 0) - -as the type of a type object is "type", but this isn't strictly conforming C and -some compilers complain. Fortunately, this member will be filled in for us by -:c:func:`PyType_Ready`. :: - - "noddy.Noddy", /* tp_name */ - -The name of our type. This will appear in the default textual representation of -our objects and in some error messages, for example:: - - >>> "" + noddy.new_noddy() - Traceback (most recent call last): - File "", line 1, in - TypeError: cannot add type "noddy.Noddy" to string - -Note that the name is a dotted name that includes both the module name and the -name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. -One side effect of using an undotted name is that the pydoc documentation tool -will not list the new type in the module documentation. :: - - sizeof(noddy_NoddyObject), /* tp_basicsize */ - -This is so that Python knows how much memory to allocate when you call -:c:func:`PyObject_New`. - -.. note:: - - If you want your type to be subclassable from Python, and your type has the same - :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple - inheritance. A Python subclass of your type will have to list your type first - in its :attr:`~class.__bases__`, or else it will not be able to call your type's - :meth:`__new__` method without getting an error. You can avoid this problem by - ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its - base type does. Most of the time, this will be true anyway, because either your - base type will be :class:`object`, or else you will be adding data members to - your base type, and therefore increasing its size. - -:: - - 0, /* tp_itemsize */ - -This has to do with variable length objects like lists and strings. Ignore this -for now. - -Skipping a number of type methods that we don't provide, we set the class flags -to :const:`Py_TPFLAGS_DEFAULT`. :: - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - -All types should include this constant in their flags. It enables all of the -members defined until at least Python 3.3. If you need further members, -you will need to OR the corresponding flags. - -We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: - - "Noddy objects", /* tp_doc */ - -Now we get into the type methods, the things that make your objects different -from the others. We aren't going to implement any of these in this version of -the module. We'll expand this example later to have more interesting behavior. - -For now, all we want to be able to do is to create new :class:`Noddy` objects. -To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` implementation. -In this case, we can just use the default implementation provided by the API -function :c:func:`PyType_GenericNew`. :: - - PyType_GenericNew, /* tp_new */ - -All the other type methods are *NULL*, so we'll go over them later --- that's -for a later section! - -Everything else in the file should be familiar, except for some code in -:c:func:`PyInit_noddy`:: - - if (PyType_Ready(&noddy_NoddyType) < 0) - return; - -This initializes the :class:`Noddy` type, filing in a number of members, -including :attr:`ob_type` that we initially set to *NULL*. :: - - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - -This adds the type to the module dictionary. This allows us to create -:class:`Noddy` instances by calling the :class:`Noddy` class:: - - >>> import noddy - >>> mynoddy = noddy.Noddy() - -That's it! All that remains is to build it; put the above code in a file called -:file:`noddy.c` and :: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[Extension("noddy", ["noddy.c"])]) - -in a file called :file:`setup.py`; then typing - -.. code-block:: shell-session - - $ python setup.py build - -at a shell should produce a file :file:`noddy.so` in a subdirectory; move to -that directory and fire up Python --- you should be able to ``import noddy`` and -play around with Noddy objects. - -That wasn't so hard, was it? - -Of course, the current Noddy type is pretty uninteresting. It has no data and -doesn't do anything. It can't even be subclassed. - - -Adding data and methods to the Basic example --------------------------------------------- - -Let's extend the basic example to add some data and methods. Let's also make -the type usable as a base class. We'll create a new module, :mod:`noddy2` that -adds these capabilities: - -.. literalinclude:: ../includes/noddy2.c - - -This version of the module has a number of changes. - -We've added an extra include:: - - #include - -This include provides declarations that we use to handle attributes, as -described a bit later. - -The name of the :class:`Noddy` object structure has been shortened to -:class:`Noddy`. The type object name has been shortened to :class:`NoddyType`. - -The :class:`Noddy` type now has three data attributes, *first*, *last*, and -*number*. The *first* and *last* variables are Python strings containing first -and last names. The *number* attribute is an integer. - -The object structure is updated accordingly:: - - typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; - } Noddy; - -Because we now have data to manage, we have to be more careful about object -allocation and deallocation. At a minimum, we need a deallocation method:: - - static void - Noddy_dealloc(Noddy* self) - { - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: - - (destructor)Noddy_dealloc, /*tp_dealloc*/ - -This method decrements the reference counts of the two Python attributes. We use -:c:func:`Py_XDECREF` here because the :attr:`first` and :attr:`last` members -could be *NULL*. It then calls the :c:member:`~PyTypeObject.tp_free` member of the object's type -to free the object's memory. Note that the object's type might not be -:class:`NoddyType`, because the object may be an instance of a subclass. - -We want to make sure that the first and last names are initialized to empty -strings, so we provide a new method:: - - static PyObject * - Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; - } - -and install it in the :c:member:`~PyTypeObject.tp_new` member:: - - Noddy_new, /* tp_new */ - -The new member is responsible for creating (as opposed to initializing) objects -of the type. It is exposed in Python as the :meth:`__new__` method. See the -paper titled "Unifying types and classes in Python" for a detailed discussion of -the :meth:`__new__` method. One reason to implement a new method is to assure -the initial values of instance variables. In this case, we use the new method -to make sure that the initial values of the members :attr:`first` and -:attr:`last` are not *NULL*. If we didn't care whether the initial values were -*NULL*, we could have used :c:func:`PyType_GenericNew` as our new method, as we -did before. :c:func:`PyType_GenericNew` initializes all of the instance variable -members to *NULL*. - -The new method is a static method that is passed the type being instantiated and -any arguments passed when the type was called, and that returns the new object -created. New methods always accept positional and keyword arguments, but they -often ignore the arguments, leaving the argument handling to initializer -methods. Note that if the type supports subclassing, the type passed may not be -the type being defined. The new method calls the :c:member:`~PyTypeObject.tp_alloc` slot to -allocate memory. We don't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather -:c:func:`PyType_Ready` fills it for us by inheriting it from our base class, -which is :class:`object` by default. Most types use the default allocation. - -.. note:: - - If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one that calls a base type's - :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), you must *not* try to determine what method - to call using method resolution order at runtime. Always statically determine - what type you are going to call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via - ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your - type that also inherit from other Python-defined classes may not work correctly. - (Specifically, you may not be able to create instances of such subclasses - without getting a :exc:`TypeError`.) - -We provide an initialization function:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; - } - -by filling the :c:member:`~PyTypeObject.tp_init` slot. :: - - (initproc)Noddy_init, /* tp_init */ - -The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the :meth:`__init__` method. It -is used to initialize an object after it's created. Unlike the new method, we -can't guarantee that the initializer is called. The initializer isn't called -when unpickling objects and it can be overridden. Our initializer accepts -arguments to provide initial values for our instance. Initializers always accept -positional and keyword arguments. Initializers should return either ``0`` on -success or ``-1`` on error. - -Initializers can be called multiple times. Anyone can call the :meth:`__init__` -method on our objects. For this reason, we have to be extra careful when -assigning the new values. We might be tempted, for example to assign the -:attr:`first` member like this:: - - if (first) { - Py_XDECREF(self->first); - Py_INCREF(first); - self->first = first; - } - -But this would be risky. Our type doesn't restrict the type of the -:attr:`first` member, so it could be any kind of object. It could have a -destructor that causes code to be executed that tries to access the -:attr:`first` member. To be paranoid and protect ourselves against this -possibility, we almost always reassign members before decrementing their -reference counts. When don't we have to do this? - -* when we absolutely know that the reference count is greater than 1 - -* when we know that deallocation of the object [#]_ will not cause any calls - back into our type's code - -* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` handler when - garbage-collections is not supported [#]_ - -We want to expose our instance variables as attributes. There are a -number of ways to do that. The simplest way is to define member definitions:: - - static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: - - Noddy_members, /* tp_members */ - -Each member definition has a member name, type, offset, access flags and -documentation string. See the :ref:`Generic-Attribute-Management` section below for -details. - -A disadvantage of this approach is that it doesn't provide a way to restrict the -types of objects that can be assigned to the Python attributes. We expect the -first and last names to be strings, but any Python objects can be assigned. -Further, the attributes can be deleted, setting the C pointers to *NULL*. Even -though we can make sure the members are initialized to non-*NULL* values, the -members can be set to *NULL* if the attributes are deleted. - -We define a single method, :meth:`name`, that outputs the objects name as the -concatenation of the first and last names. :: - - static PyObject * - Noddy_name(Noddy* self) - { - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); - } - -The method is implemented as a C function that takes a :class:`Noddy` (or -:class:`Noddy` subclass) instance as the first argument. Methods always take an -instance as the first argument. Methods often take positional and keyword -arguments as well, but in this case we don't take any and don't need to accept -a positional argument tuple or keyword argument dictionary. This method is -equivalent to the Python method:: - - def name(self): - return "%s %s" % (self.first, self.last) - -Note that we have to check for the possibility that our :attr:`first` and -:attr:`last` members are *NULL*. This is because they can be deleted, in which -case they are set to *NULL*. It would be better to prevent deletion of these -attributes and to restrict the attribute values to be strings. We'll see how to -do that in the next section. - -Now that we've defined the method, we need to create an array of method -definitions:: - - static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ - }; - -and assign them to the :c:member:`~PyTypeObject.tp_methods` slot:: - - Noddy_methods, /* tp_methods */ - -Note that we used the :const:`METH_NOARGS` flag to indicate that the method is -passed no arguments. - -Finally, we'll make our type usable as a base class. We've written our methods -carefully so far so that they don't make any assumptions about the type of the -object being created or used, so all we need to do is to add the -:const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - -We rename :c:func:`PyInit_noddy` to :c:func:`PyInit_noddy2` and update the module -name in the :c:type:`PyModuleDef` struct. - -Finally, we update our :file:`setup.py` file to build the new module:: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[ - Extension("noddy", ["noddy.c"]), - Extension("noddy2", ["noddy2.c"]), - ]) - - -Providing finer control over data attributes --------------------------------------------- - -In this section, we'll provide finer control over how the :attr:`first` and -:attr:`last` attributes are set in the :class:`Noddy` example. In the previous -version of our module, the instance variables :attr:`first` and :attr:`last` -could be set to non-string values or even deleted. We want to make sure that -these attributes always contain strings. - -.. literalinclude:: ../includes/noddy3.c - - -To provide greater control, over the :attr:`first` and :attr:`last` attributes, -we'll use custom getter and setter functions. Here are the functions for -getting and setting the :attr:`first` attribute:: - - Noddy_getfirst(Noddy *self, void *closure) - { - Py_INCREF(self->first); - return self->first; - } - - static int - Noddy_setfirst(Noddy *self, PyObject *value, void *closure) - { - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a str"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; - } - -The getter function is passed a :class:`Noddy` object and a "closure", which is -void pointer. In this case, the closure is ignored. (The closure supports an -advanced usage in which definition data is passed to the getter and setter. This -could, for example, be used to allow a single set of getter and setter functions -that decide the attribute to get or set based on data in the closure.) - -The setter function is passed the :class:`Noddy` object, the new value, and the -closure. The new value may be *NULL*, in which case the attribute is being -deleted. In our setter, we raise an error if the attribute is deleted or if the -attribute value is not a string. - -We create an array of :c:type:`PyGetSetDef` structures:: - - static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ - }; - -and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: - - Noddy_getseters, /* tp_getset */ - -to register our attribute getters and setters. - -The last item in a :c:type:`PyGetSetDef` structure is the closure mentioned -above. In this case, we aren't using the closure, so we just pass *NULL*. - -We also remove the member definitions for these attributes:: - - static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only allow strings [#]_ to -be passed:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; - } - -With these changes, we can assure that the :attr:`first` and :attr:`last` -members are never *NULL* so we can remove checks for *NULL* values in almost all -cases. This means that most of the :c:func:`Py_XDECREF` calls can be converted to -:c:func:`Py_DECREF` calls. The only place we can't change these calls is in the -deallocator, where there is the possibility that the initialization of these -members failed in the constructor. - -We also rename the module initialization function and module name in the -initialization function, as we did before, and we add an extra definition to the -:file:`setup.py` file. - - -Supporting cyclic garbage collection ------------------------------------- - -Python has a cyclic-garbage collector that can identify unneeded objects even -when their reference counts are not zero. This can happen when objects are -involved in cycles. For example, consider:: - - >>> l = [] - >>> l.append(l) - >>> del l - -In this example, we create a list that contains itself. When we delete it, it -still has a reference from itself. Its reference count doesn't drop to zero. -Fortunately, Python's cyclic-garbage collector will eventually figure out that -the list is garbage and free it. - -In the second version of the :class:`Noddy` example, we allowed any kind of -object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. This -means that :class:`Noddy` objects can participate in cycles:: - - >>> import noddy2 - >>> n = noddy2.Noddy() - >>> l = [n] - >>> n.first = l - -This is pretty silly, but it gives us an excuse to add support for the -cyclic-garbage collector to the :class:`Noddy` example. To support cyclic -garbage collection, types need to fill two slots and set a class flag that -enables these slots: - -.. literalinclude:: ../includes/noddy4.c - - -The traversal method provides access to subobjects that could participate in -cycles:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; - } - -For each subobject that can participate in cycles, we need to call the -:c:func:`visit` function, which is passed to the traversal method. The -:c:func:`visit` function takes as arguments the subobject and the extra argument -*arg* passed to the traversal method. It returns an integer value that must be -returned if it is non-zero. - -Python provides a :c:func:`Py_VISIT` macro that automates calling visit -functions. With :c:func:`Py_VISIT`, :c:func:`Noddy_traverse` can be simplified:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - Py_VISIT(self->first); - Py_VISIT(self->last); - return 0; - } - -.. note:: - - Note that the :c:member:`~PyTypeObject.tp_traverse` implementation must name its arguments exactly - *visit* and *arg* in order to use :c:func:`Py_VISIT`. This is to encourage - uniformity across these boring implementations. - -We also need to provide a method for clearing any subobjects that can -participate in cycles. - -:: - - static int - Noddy_clear(Noddy *self) - { - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; - } - -Notice the use of a temporary variable in :c:func:`Noddy_clear`. We use the -temporary variable so that we can set each member to *NULL* before decrementing -its reference count. We do this because, as was discussed earlier, if the -reference count drops to zero, we might cause code to run that calls back into -the object. In addition, because we now support garbage collection, we also -have to worry about code being run that triggers garbage collection. If garbage -collection is run, our :c:member:`~PyTypeObject.tp_traverse` handler could get called. We can't -take a chance of having :c:func:`Noddy_traverse` called when a member's reference -count has dropped to zero and its value hasn't been set to *NULL*. - -Python provides a :c:func:`Py_CLEAR` that automates the careful decrementing of -reference counts. With :c:func:`Py_CLEAR`, the :c:func:`Noddy_clear` function can -be simplified:: - - static int - Noddy_clear(Noddy *self) - { - Py_CLEAR(self->first); - Py_CLEAR(self->last); - return 0; - } - -Note that :c:func:`Noddy_dealloc` may call arbitrary functions through -``__del__`` method or weakref callback. It means circular GC can be -triggered inside the function. Since GC assumes reference count is not zero, -we need to untrack the object from GC by calling :c:func:`PyObject_GC_UnTrack` -before clearing members. Here is reimplemented deallocator which uses -:c:func:`PyObject_GC_UnTrack` and :c:func:`Noddy_clear`. - -:: - - static void - Noddy_dealloc(Noddy* self) - { - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - -That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or -:c:member:`~PyTypeObject.tp_free` slots, we'd need to modify them for cyclic-garbage collection. -Most extensions will use the versions automatically provided. - - -Subclassing other types ------------------------ - -It is possible to create new extension types that are derived from existing -types. It is easiest to inherit from the built in types, since an extension can -easily use the :class:`PyTypeObject` it needs. It can be difficult to share -these :class:`PyTypeObject` structures between extension modules. - -In this example we will create a :class:`Shoddy` type that inherits from the -built-in :class:`list` type. The new type will be completely compatible with -regular lists, but will have an additional :meth:`increment` method that -increases an internal counter. :: - - >>> import shoddy - >>> s = shoddy.Shoddy(range(3)) - >>> s.extend(s) - >>> print(len(s)) - 6 - >>> print(s.increment()) - 1 - >>> print(s.increment()) - 2 - -.. literalinclude:: ../includes/shoddy.c - - -As you can see, the source code closely resembles the :class:`Noddy` examples in -previous sections. We will break down the main differences between them. :: - - typedef struct { - PyListObject list; - int state; - } Shoddy; - -The primary difference for derived type objects is that the base type's object -structure must be the first value. The base type will already include the -:c:func:`PyObject_HEAD` at the beginning of its structure. - -When a Python object is a :class:`Shoddy` instance, its *PyObject\** pointer can -be safely cast to both *PyListObject\** and *Shoddy\**. :: - - static int - Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) - { - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; - } - -In the :attr:`__init__` method for our type, we can see how to call through to -the :attr:`__init__` method of the base type. - -This pattern is important when writing a type with custom :attr:`new` and -:attr:`dealloc` methods. The :attr:`new` method should not actually create the -memory for the object with :c:member:`~PyTypeObject.tp_alloc`, that will be handled by the base -class when calling its :c:member:`~PyTypeObject.tp_new`. - -When filling out the :c:func:`PyTypeObject` for the :class:`Shoddy` type, you see -a slot for :c:func:`tp_base`. Due to cross platform compiler issues, you can't -fill that field directly with the :c:func:`PyList_Type`; it can be done later in -the module's :c:func:`init` function. :: - - PyMODINIT_FUNC - PyInit_shoddy(void) - { - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; - } - -Before calling :c:func:`PyType_Ready`, the type structure must have the -:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving a new type, it is not -necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` slot with :c:func:`PyType_GenericNew` --- the allocate function from the base type will be inherited. - -After that, calling :c:func:`PyType_Ready` and adding the type object to the -module is the same as with the basic :class:`Noddy` examples. - +***************************************** +Defining Extension Types: Assorted Topics +***************************************** .. _dnt-type-methods: -Type Methods -============ - This section aims to give a quick fly-by on the various type methods you can implement and what they do. @@ -893,21 +15,20 @@ debug builds omitted: .. literalinclude:: ../includes/typestruct.h -Now that's a *lot* of methods. Don't worry too much though - if you have a type -you want to define, the chances are very good that you will only implement a -handful of these. +Now that's a *lot* of methods. Don't worry too much though -- if you have +a type you want to define, the chances are very good that you will only +implement a handful of these. As you probably expect by now, we're going to go over this and give more information about the various handlers. We won't go in the order they are defined in the structure, because there is a lot of historical baggage that -impacts the ordering of the fields; be sure your type initialization keeps the -fields in the right order! It's often easiest to find an example that includes -all the fields you need (even if they're initialized to ``0``) and then change -the values to suit your new type. :: +impacts the ordering of the fields. It's often easiest to find an example +that includes the fields you need and then change the values to suit your new +type. :: const char *tp_name; /* For printing */ -The name of the type - as mentioned in the last section, this will appear in +The name of the type -- as mentioned in the previous chapter, this will appear in various places, almost entirely for diagnostic purposes. Try to choose something that will be helpful in such a situation! :: @@ -915,7 +36,7 @@ that will be helpful in such a situation! :: These fields tell the runtime how much memory to allocate when new objects of this type are created. Python has some built-in support for variable length -structures (think: strings, lists) which is where the :c:member:`~PyTypeObject.tp_itemsize` field +structures (think: strings, tuples) which is where the :c:member:`~PyTypeObject.tp_itemsize` field comes in. This will be dealt with later. :: const char *tp_doc; @@ -923,7 +44,7 @@ comes in. This will be dealt with later. :: Here you can put a string (or its address) that you want returned when the Python script references ``obj.__doc__`` to retrieve the doc string. -Now we come to the basic type methods---the ones most extension types will +Now we come to the basic type methods -- the ones most extension types will implement. @@ -947,7 +68,7 @@ object itself needs to be freed here as well. Here is an example of this function:: static void - newdatatype_dealloc(newdatatypeobject * obj) + newdatatype_dealloc(newdatatypeobject *obj) { free(obj->obj_UnderlyingDatatypePtr); Py_TYPE(obj)->tp_free(obj); @@ -1035,7 +156,7 @@ example:: static PyObject * newdatatype_repr(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1055,7 +176,7 @@ Here is a simple example:: static PyObject * newdatatype_str(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Stringified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1236,7 +357,7 @@ example that simply raises an exception; if this were really all you wanted, the static int newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v) { - (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name); + PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name); return -1; } @@ -1321,17 +442,23 @@ these in the :file:`Objects` directory of the Python source distribution. :: hashfunc tp_hash; This function, if you choose to provide it, should return a hash number for an -instance of your data type. Here is a moderately pointless example:: +instance of your data type. Here is a simple example:: - static long + static Py_hash_t newdatatype_hash(newdatatypeobject *obj) { - long result; - result = obj->obj_UnderlyingDatatypePtr->size; - result = result * 3; + Py_hash_t result; + result = obj->some_size + 32767 * obj->some_number; + if (result == -1) + result = -2; return result; } +:c:type:`Py_hash_t` is a signed integer type with a platform-varying width. +Returning ``-1`` from :c:member:`~PyTypeObject.tp_hash` indicates an error, +which is why you should be careful to avoid returning it when hash computation +is successful, as seen above. + :: ternaryfunc tp_call; @@ -1342,27 +469,22 @@ contains ``obj1('hello')``, the :c:member:`~PyTypeObject.tp_call` handler is inv This function takes three arguments: -#. *arg1* is the instance of the data type which is the subject of the call. If - the call is ``obj1('hello')``, then *arg1* is ``obj1``. +#. *self* is the instance of the data type which is the subject of the call. + If the call is ``obj1('hello')``, then *self* is ``obj1``. -#. *arg2* is a tuple containing the arguments to the call. You can use +#. *args* is a tuple containing the arguments to the call. You can use :c:func:`PyArg_ParseTuple` to extract the arguments. -#. *arg3* is a dictionary of keyword arguments that were passed. If this is +#. *kwds* is a dictionary of keyword arguments that were passed. If this is non-*NULL* and you support keyword arguments, use - :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you do not - want to support keyword arguments and this is non-*NULL*, raise a + :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you + do not want to support keyword arguments and this is non-*NULL*, raise a :exc:`TypeError` with a message saying that keyword arguments are not supported. -Here is a desultory example of the implementation of the call function. :: +Here is a toy ``tp_call`` implementation:: - /* Implement the call function. - * obj1 is the instance receiving the call. - * obj2 is a tuple containing the arguments to the call, in this - * case 3 strings. - */ static PyObject * - newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *other) + newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds) { PyObject *result; const char *arg1; @@ -1373,7 +495,7 @@ Here is a desultory example of the implementation of the call function. :: return NULL; } result = PyUnicode_FromFormat( - "Returning -- value: [\%d] arg1: [\%s] arg2: [\%s] arg3: [\%s]\n", + "Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n", obj->obj_UnderlyingDatatypePtr->size, arg1, arg2, arg3); return result; @@ -1385,32 +507,36 @@ Here is a desultory example of the implementation of the call function. :: getiterfunc tp_iter; iternextfunc tp_iternext; -These functions provide support for the iterator protocol. Any object which -wishes to support iteration over its contents (which may be generated during -iteration) must implement the ``tp_iter`` handler. Objects which are returned -by a ``tp_iter`` handler must implement both the ``tp_iter`` and ``tp_iternext`` -handlers. Both handlers take exactly one parameter, the instance for which they -are being called, and return a new reference. In the case of an error, they -should set an exception and return *NULL*. - -For an object which represents an iterable collection, the ``tp_iter`` handler -must return an iterator object. The iterator object is responsible for -maintaining the state of the iteration. For collections which can support -multiple iterators which do not interfere with each other (as lists and tuples -do), a new iterator should be created and returned. Objects which can only be -iterated over once (usually due to side effects of iteration) should implement -this handler by returning a new reference to themselves, and should also -implement the ``tp_iternext`` handler. File objects are an example of such an -iterator. - -Iterator objects should implement both handlers. The ``tp_iter`` handler should -return a new reference to the iterator (this is the same as the ``tp_iter`` -handler for objects which can only be iterated over destructively). The -``tp_iternext`` handler should return a new reference to the next object in the -iteration if there is one. If the iteration has reached the end, it may return -*NULL* without setting an exception or it may set :exc:`StopIteration`; avoiding -the exception can yield slightly better performance. If an actual error occurs, -it should set an exception and return *NULL*. +These functions provide support for the iterator protocol. Both handlers +take exactly one parameter, the instance for which they are being called, +and return a new reference. In the case of an error, they should set an +exception and return *NULL*. :c:member:`~PyTypeObject.tp_iter` corresponds +to the Python :meth:`__iter__` method, while :c:member:`~PyTypeObject.tp_iternext` +corresponds to the Python :meth:`~iterator.__next__` method. + +Any :term:`iterable` object must implement the :c:member:`~PyTypeObject.tp_iter` +handler, which must return an :term:`iterator` object. Here the same guidelines +apply as for Python classes: + +* For collections (such as lists and tuples) which can support multiple + independent iterators, a new iterator should be created and returned by + each call to :c:member:`~PyTypeObject.tp_iter`. +* Objects which can only be iterated over once (usually due to side effects of + iteration, such as file objects) can implement :c:member:`~PyTypeObject.tp_iter` + by returning a new reference to themselves -- and should also therefore + implement the :c:member:`~PyTypeObject.tp_iternext` handler. + +Any :term:`iterator` object should implement both :c:member:`~PyTypeObject.tp_iter` +and :c:member:`~PyTypeObject.tp_iternext`. An iterator's +:c:member:`~PyTypeObject.tp_iter` handler should return a new reference +to the iterator. Its :c:member:`~PyTypeObject.tp_iternext` handler should +return a new reference to the next object in the iteration, if there is one. +If the iteration has reached the end, :c:member:`~PyTypeObject.tp_iternext` +may return *NULL* without setting an exception, or it may set +:exc:`StopIteration` *in addition* to returning *NULL*; avoiding +the exception can yield slightly better performance. If an actual error +occurs, :c:member:`~PyTypeObject.tp_iternext` should always set an exception +and return *NULL*. .. _weakref-support: @@ -1418,110 +544,76 @@ it should set an exception and return *NULL*. Weak Reference Support ---------------------- -One of the goals of Python's weak-reference implementation is to allow any type +One of the goals of Python's weak reference implementation is to allow any type to participate in the weak reference mechanism without incurring the overhead on -those objects which do not benefit by weak referencing (such as numbers). +performance-critical objects (such as numbers). -For an object to be weakly referencable, the extension must include a -:c:type:`PyObject\*` field in the instance structure for the use of the weak -reference mechanism; it must be initialized to *NULL* by the object's -constructor. It must also set the :c:member:`~PyTypeObject.tp_weaklistoffset` field of the -corresponding type object to the offset of the field. For example, the instance -type is defined with the following structure:: +.. seealso:: + Documentation for the :mod:`weakref` module. - typedef struct { - PyObject_HEAD - PyClassObject *in_class; /* The class object */ - PyObject *in_dict; /* A dictionary */ - PyObject *in_weakreflist; /* List of weak references */ - } PyInstanceObject; - -The statically-declared type object for instances is defined this way:: - - PyTypeObject PyInstance_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - 0, - "module.instance", - - /* Lots of stuff omitted for brevity... */ - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ - }; +For an object to be weakly referencable, the extension type must do two things: -The type constructor is responsible for initializing the weak reference list to -*NULL*:: +#. Include a :c:type:`PyObject\*` field in the C object structure dedicated to + the weak reference mechanism. The object's constructor should leave it + *NULL* (which is automatic when using the default + :c:member:`~PyTypeObject.tp_alloc`). - static PyObject * - instance_new() { - /* Other initialization stuff omitted for brevity */ +#. Set the :c:member:`~PyTypeObject.tp_weaklistoffset` type member + to the offset of the aforementioned field in the C object structure, + so that the interpreter knows how to access and modify that field. - self->in_weakreflist = NULL; +Concretely, here is how a trivial object structure would be augmented +with the required field:: - return (PyObject *) self; - } + typedef struct { + PyObject_HEAD + PyObject *weakreflist; /* List of weak references */ + } TrivialObject; -The only further addition is that the destructor needs to call the weak -reference manager to clear any weak references. This is only required if the -weak reference list is non-*NULL*:: +And the corresponding member in the statically-declared type object:: - static void - instance_dealloc(PyInstanceObject *inst) - { - /* Allocate temporaries if needed, but do not begin - destruction just yet. - */ + static PyTypeObject TrivialType = { + PyVarObject_HEAD_INIT(NULL, 0) + /* ... other members omitted for brevity ... */ + .tp_weaklistoffset = offsetof(TrivialObject, weakreflist), + }; - if (inst->in_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) inst); +The only further addition is that ``tp_dealloc`` needs to clear any weak +references (by calling :c:func:`PyObject_ClearWeakRefs`) if the field is +non-*NULL*:: - /* Proceed with object destruction normally. */ + static void + Trivial_dealloc(TrivialObject *self) + { + /* Clear weakrefs first before calling any destructors */ + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); + /* ... remainder of destruction code omitted for brevity ... */ + Py_TYPE(self)->tp_free((PyObject *) self); } More Suggestions ---------------- -Remember that you can omit most of these functions, in which case you provide -``0`` as a value. There are type definitions for each of the functions you must -provide. They are in :file:`object.h` in the Python include directory that -comes with the source distribution of Python. - In order to learn how to implement any specific method for your new data type, -do the following: Download and unpack the Python source distribution. Go to -the :file:`Objects` directory, then search the C source files for ``tp_`` plus -the function you want (for example, ``tp_richcompare``). You will find examples -of the function you want to implement. +get the :term:`CPython` source code. Go to the :file:`Objects` directory, +then search the C source files for ``tp_`` plus the function you want +(for example, ``tp_richcompare``). You will find examples of the function +you want to implement. -When you need to verify that an object is an instance of the type you are -implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of its use -might be something like the following:: +When you need to verify that an object is a concrete instance of the type you +are implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of +its use might be something like the following:: - if (! PyObject_TypeCheck(some_object, &MyType)) { + if (!PyObject_TypeCheck(some_object, &MyType)) { PyErr_SetString(PyExc_TypeError, "arg #1 not a mything"); return NULL; } -.. rubric:: Footnotes - -.. [#] This is true when we know that the object is a basic type, like a string or a - float. - -.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler in this example, because our - type doesn't support garbage collection. Even if a type supports garbage - collection, there are calls that can be made to "untrack" the object from - garbage collection, however, these calls are advanced and not covered here. - -.. [#] We now know that the first and last members are strings, so perhaps we could be - less careful about decrementing their reference counts, however, we accept - instances of string subclasses. Even though deallocating normal strings won't - call back into our objects, we can't guarantee that deallocating an instance of - a string subclass won't call back into our objects. +.. seealso:: + Download CPython source releases. + https://www.python.org/downloads/source/ -.. [#] Even in the third version, we aren't guaranteed to avoid cycles. Instances of - string subclasses are allowed and string subclasses could allow cycles even if - normal strings don't. + The CPython project on GitHub, where the CPython source code is developed. + https://github.com/python/cpython diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst new file mode 100644 index 000000000000..5e05cf693652 --- /dev/null +++ b/Doc/extending/newtypes_tutorial.rst @@ -0,0 +1,896 @@ +.. highlightlang:: c + +.. _defining-new-types: + +********************************** +Defining Extension Types: Tutorial +********************************** + +.. sectionauthor:: Michael Hudson +.. sectionauthor:: Dave Kuhlman +.. sectionauthor:: Jim Fulton + + +Python allows the writer of a C extension module to define new types that +can be manipulated from Python code, much like the built-in :class:`str` +and :class:`list` types. The code for all extension types follows a +pattern, but there are some details that you need to understand before you +can get started. This document is a gentle introduction to the topic. + + +.. _dnt-basics: + +The Basics +========== + +The :term:`CPython` runtime sees all Python objects as variables of type +:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +The :c:type:`PyObject` structure itself only contains the object's +:term:`reference count` and a pointer to the object's "type object". +This is where the action is; the type object determines which (C) functions +get called by the interpreter when, for instance, an attribute gets looked up +on an object, a method called, or it is multiplied by another object. These +C functions are called "type methods". + +So, if you want to define a new extension type, you need to create a new type +object. + +This sort of thing can only be explained by example, so here's a minimal, but +complete, module that defines a new type named :class:`Custom` inside a C +extension module :mod:`custom`: + +.. note:: + What we're showing here is the traditional way of defining *static* + extension types. It should be adequate for most uses. The C API also + allows defining heap-allocated extension types using the + :c:func:`PyType_FromSpec` function, which isn't covered in this tutorial. + +.. literalinclude:: ../includes/custom.c + +Now that's quite a bit to take in at once, but hopefully bits will seem familiar +from the previous chapter. This file defines three things: + +#. What a :class:`Custom` **object** contains: this is the ``CustomObject`` + struct, which is allocated once for each :class:`Custom` instance. +#. How the :class:`Custom` **type** behaves: this is the ``CustomType`` struct, + which defines a set of flags and function pointers that the interpreter + inspects when specific operations are requested. +#. How to initialize the :mod:`custom` module: this is the ``PyInit_custom`` + function and the associated ``custommodule`` struct. + +The first bit is:: + + typedef struct { + PyObject_HEAD + } CustomObject; + +This is what a Custom object will contain. ``PyObject_HEAD`` is mandatory +at the start of each object struct and defines a field called ``ob_base`` +of type :c:type:`PyObject`, containing a pointer to a type object and a +reference count (these can be accessed using the macros :c:macro:`Py_REFCNT` +and :c:macro:`Py_TYPE` respectively). The reason for the macro is to +abstract away the layout and to enable additional fields in debug builds. + +.. note:: + There is no semicolon above after the :c:macro:`PyObject_HEAD` macro. + Be wary of adding one by accident: some compilers will complain. + +Of course, objects generally store additional data besides the standard +``PyObject_HEAD`` boilerplate; for example, here is the definition for +standard Python floats:: + + typedef struct { + PyObject_HEAD + double ob_fval; + } PyFloatObject; + +The second bit is the definition of the type object. :: + + static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_new = PyType_GenericNew, + }; + +.. note:: + We recommend using C99-style designated initializers as above, to + avoid listing all the :c:type:`PyTypeObject` fields that you don't care + about and also to avoid caring about the fields' declaration order. + +The actual definition of :c:type:`PyTypeObject` in :file:`object.h` has +many more :ref:`fields ` than the definition above. The +remaining fields will be filled with zeros by the C compiler, and it's +common practice to not specify them explicitly unless you need them. + +We're going to pick it apart, one field at a time:: + + PyVarObject_HEAD_INIT(NULL, 0) + +This line is mandatory boilerplate to initialize the ``ob_base`` +field mentioned above. :: + + .tp_name = "custom.Custom", + +The name of our type. This will appear in the default textual representation of +our objects and in some error messages, for example: + +.. code-block:: python + + >>> "" + custom.Custom() + Traceback (most recent call last): + File "", line 1, in + TypeError: can only concatenate str (not "custom.Custom") to str + +Note that the name is a dotted name that includes both the module name and the +name of the type within the module. The module in this case is :mod:`custom` and +the type is :class:`Custom`, so we set the type name to :class:`custom.Custom`. +Using the real dotted import path is important to make your type compatible +with the :mod:`pydoc` and :mod:`pickle` modules. :: + + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + +This is so that Python knows how much memory to allocate when creating +new :class:`Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is +only used for variable-sized objects and should otherwise be zero. + +.. note:: + + If you want your type to be subclassable from Python, and your type has the same + :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple + inheritance. A Python subclass of your type will have to list your type first + in its :attr:`~class.__bases__`, or else it will not be able to call your type's + :meth:`__new__` method without getting an error. You can avoid this problem by + ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its + base type does. Most of the time, this will be true anyway, because either your + base type will be :class:`object`, or else you will be adding data members to + your base type, and therefore increasing its size. + +We set the class flags to :const:`Py_TPFLAGS_DEFAULT`. :: + + .tp_flags = Py_TPFLAGS_DEFAULT, + +All types should include this constant in their flags. It enables all of the +members defined until at least Python 3.3. If you need further members, +you will need to OR the corresponding flags. + +We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: + + .tp_doc = "Custom objects", + +To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` +handler. This is the equivalent of the Python method :meth:`__new__`, but +has to be specified explicitly. In this case, we can just use the default +implementation provided by the API function :c:func:`PyType_GenericNew`. :: + + .tp_new = PyType_GenericNew, + +Everything else in the file should be familiar, except for some code in +:c:func:`PyInit_custom`:: + + if (PyType_Ready(&CustomType) < 0) + return; + +This initializes the :class:`Custom` type, filling in a number of members +to the appropriate default values, including :attr:`ob_type` that we initially +set to *NULL*. :: + + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + +This adds the type to the module dictionary. This allows us to create +:class:`Custom` instances by calling the :class:`Custom` class: + +.. code-block:: python + + >>> import custom + >>> mycustom = custom.Custom() + +That's it! All that remains is to build it; put the above code in a file called +:file:`custom.c` and: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[Extension("custom", ["custom.c"])]) + +in a file called :file:`setup.py`; then typing + +.. code-block:: shell-session + + $ python setup.py build + +at a shell should produce a file :file:`custom.so` in a subdirectory; move to +that directory and fire up Python --- you should be able to ``import custom`` and +play around with Custom objects. + +That wasn't so hard, was it? + +Of course, the current Custom type is pretty uninteresting. It has no data and +doesn't do anything. It can't even be subclassed. + +.. note:: + While this documentation showcases the standard :mod:`distutils` module + for building C extensions, it is recommended in real-world use cases to + use the newer and better-maintained ``setuptools`` library. Documentation + on how to do this is out of scope for this document and can be found in + the `Python Packaging User's Guide `_. + + +Adding data and methods to the Basic example +============================================ + +Let's extend the basic example to add some data and methods. Let's also make +the type usable as a base class. We'll create a new module, :mod:`custom2` that +adds these capabilities: + +.. literalinclude:: ../includes/custom2.c + + +This version of the module has a number of changes. + +We've added an extra include:: + + #include + +This include provides declarations that we use to handle attributes, as +described a bit later. + +The :class:`Custom` type now has three data attributes in its C struct, +*first*, *last*, and *number*. The *first* and *last* variables are Python +strings containing first and last names. The *number* attribute is a C integer. + +The object structure is updated accordingly:: + + typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; + } CustomObject; + +Because we now have data to manage, we have to be more careful about object +allocation and deallocation. At a minimum, we need a deallocation method:: + + static void + Custom_dealloc(CustomObject *self) + { + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: + + .tp_dealloc = (destructor) Custom_dealloc, + +This method first clears the reference counts of the two Python attributes. +:c:func:`Py_XDECREF` correctly handles the case where its argument is +*NULL* (which might happen here if ``tp_new`` failed midway). It then +calls the :c:member:`~PyTypeObject.tp_free` member of the object's type +(computed by ``Py_TYPE(self)``) to free the object's memory. Note that +the object's type might not be :class:`CustomType`, because the object may +be an instance of a subclass. + +.. note:: + The explicit cast to ``destructor`` above is needed because we defined + ``Custom_dealloc`` to take a ``CustomObject *`` argument, but the ``tp_dealloc`` + function pointer expects to receive a ``PyObject *`` argument. Otherwise, + the compiler will emit a warning. This is object-oriented polymorphism, + in C! + +We want to make sure that the first and last names are initialized to empty +strings, so we provide a ``tp_new`` implementation:: + + static PyObject * + Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; + } + +and install it in the :c:member:`~PyTypeObject.tp_new` member:: + + .tp_new = Custom_new, + +The ``tp_new`` handler is responsible for creating (as opposed to initializing) +objects of the type. It is exposed in Python as the :meth:`__new__` method. +It is not required to define a ``tp_new`` member, and indeed many extension +types will simply reuse :c:func:`PyType_GenericNew` as done in the first +version of the ``Custom`` type above. In this case, we use the ``tp_new`` +handler to initialize the ``first`` and ``last`` attributes to non-*NULL* +default values. + +``tp_new`` is passed the type being instantiated (not necessarily ``CustomType``, +if a subclass is instantiated) and any arguments passed when the type was +called, and is expected to return the instance created. ``tp_new`` handlers +always accept positional and keyword arguments, but they often ignore the +arguments, leaving the argument handling to initializer (a.k.a. ``tp_init`` +in C or ``__init__`` in Python) methods. + +.. note:: + ``tp_new`` shouldn't call ``tp_init`` explicitly, as the interpreter + will do it itself. + +The ``tp_new`` implementation calls the :c:member:`~PyTypeObject.tp_alloc` +slot to allocate memory:: + + self = (CustomObject *) type->tp_alloc(type, 0); + +Since memory allocation may fail, we must check the :c:member:`~PyTypeObject.tp_alloc` +result against *NULL* before proceeding. + +.. note:: + We didn't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather + :c:func:`PyType_Ready` fills it for us by inheriting it from our base class, + which is :class:`object` by default. Most types use the default allocation + strategy. + +.. note:: + If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one + that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), + you must *not* try to determine what method to call using method resolution + order at runtime. Always statically determine what type you are going to + call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via + ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your + type that also inherit from other Python-defined classes may not work correctly. + (Specifically, you may not be able to create instances of such subclasses + without getting a :exc:`TypeError`.) + +We also define an initialization function which accepts arguments to provide +initial values for our instance:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; + } + +by filling the :c:member:`~PyTypeObject.tp_init` slot. :: + + .tp_init = (initproc) Custom_init, + +The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the +:meth:`__init__` method. It is used to initialize an object after it's +created. Initializers always accept positional and keyword arguments, +and they should return either ``0`` on success or ``-1`` on error. + +Unlike the ``tp_new`` handler, there is no guarantee that ``tp_init`` +is called at all (for example, the :mod:`pickle` module by default +doesn't call :meth:`__init__` on unpickled instances). It can also be +called multiple times. Anyone can call the :meth:`__init__` method on +our objects. For this reason, we have to be extra careful when assigning +the new attribute values. We might be tempted, for example to assign the +``first`` member like this:: + + if (first) { + Py_XDECREF(self->first); + Py_INCREF(first); + self->first = first; + } + +But this would be risky. Our type doesn't restrict the type of the +``first`` member, so it could be any kind of object. It could have a +destructor that causes code to be executed that tries to access the +``first`` member; or that destructor could release the +:term:`Global interpreter Lock` and let arbitrary code run in other +threads that accesses and modifies our object. + +To be paranoid and protect ourselves against this possibility, we almost +always reassign members before decrementing their reference counts. When +don't we have to do this? + +* when we absolutely know that the reference count is greater than 1; + +* when we know that deallocation of the object [#]_ will neither release + the :term:`GIL` nor cause any calls back into our type's code; + +* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` + handler on a type which doesn't support cyclic garbage collection [#]_. + +We want to expose our instance variables as attributes. There are a +number of ways to do that. The simplest way is to define member definitions:: + + static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: + + .tp_members = Custom_members, + +Each member definition has a member name, type, offset, access flags and +documentation string. See the :ref:`Generic-Attribute-Management` section +below for details. + +A disadvantage of this approach is that it doesn't provide a way to restrict the +types of objects that can be assigned to the Python attributes. We expect the +first and last names to be strings, but any Python objects can be assigned. +Further, the attributes can be deleted, setting the C pointers to *NULL*. Even +though we can make sure the members are initialized to non-*NULL* values, the +members can be set to *NULL* if the attributes are deleted. + +We define a single method, :meth:`Custom.name()`, that outputs the objects name as the +concatenation of the first and last names. :: + + static PyObject * + Custom_name(CustomObject *self) + { + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); + } + +The method is implemented as a C function that takes a :class:`Custom` (or +:class:`Custom` subclass) instance as the first argument. Methods always take an +instance as the first argument. Methods often take positional and keyword +arguments as well, but in this case we don't take any and don't need to accept +a positional argument tuple or keyword argument dictionary. This method is +equivalent to the Python method: + +.. code-block:: python + + def name(self): + return "%s %s" % (self.first, self.last) + +Note that we have to check for the possibility that our :attr:`first` and +:attr:`last` members are *NULL*. This is because they can be deleted, in which +case they are set to *NULL*. It would be better to prevent deletion of these +attributes and to restrict the attribute values to be strings. We'll see how to +do that in the next section. + +Now that we've defined the method, we need to create an array of method +definitions:: + + static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ + }; + +(note that we used the :const:`METH_NOARGS` flag to indicate that the method +is expecting no arguments other than *self*) + +and assign it to the :c:member:`~PyTypeObject.tp_methods` slot:: + + .tp_methods = Custom_methods, + +Finally, we'll make our type usable as a base class for subclassing. We've +written our methods carefully so far so that they don't make any assumptions +about the type of the object being created or used, so all we need to do is +to add the :const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +We rename :c:func:`PyInit_custom` to :c:func:`PyInit_custom2`, update the +module name in the :c:type:`PyModuleDef` struct, and update the full class +name in the :c:type:`PyTypeObject` struct. + +Finally, we update our :file:`setup.py` file to build the new module: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[ + Extension("custom", ["custom.c"]), + Extension("custom2", ["custom2.c"]), + ]) + + +Providing finer control over data attributes +============================================ + +In this section, we'll provide finer control over how the :attr:`first` and +:attr:`last` attributes are set in the :class:`Custom` example. In the previous +version of our module, the instance variables :attr:`first` and :attr:`last` +could be set to non-string values or even deleted. We want to make sure that +these attributes always contain strings. + +.. literalinclude:: ../includes/custom3.c + + +To provide greater control, over the :attr:`first` and :attr:`last` attributes, +we'll use custom getter and setter functions. Here are the functions for +getting and setting the :attr:`first` attribute:: + + static PyObject * + Custom_getfirst(CustomObject *self, void *closure) + { + Py_INCREF(self->first); + return self->first; + } + + static int + Custom_setfirst(CustomObject *self, PyObject *value, void *closure) + { + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; + } + +The getter function is passed a :class:`Custom` object and a "closure", which is +a void pointer. In this case, the closure is ignored. (The closure supports an +advanced usage in which definition data is passed to the getter and setter. This +could, for example, be used to allow a single set of getter and setter functions +that decide the attribute to get or set based on data in the closure.) + +The setter function is passed the :class:`Custom` object, the new value, and the +closure. The new value may be *NULL*, in which case the attribute is being +deleted. In our setter, we raise an error if the attribute is deleted or if its +new value is not a string. + +We create an array of :c:type:`PyGetSetDef` structures:: + + static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ + }; + +and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: + + .tp_getset = Custom_getsetters, + +The last item in a :c:type:`PyGetSetDef` structure is the "closure" mentioned +above. In this case, we aren't using a closure, so we just pass *NULL*. + +We also remove the member definitions for these attributes:: + + static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only +allow strings [#]_ to be passed:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; + } + +With these changes, we can assure that the ``first`` and ``last`` members are +never *NULL* so we can remove checks for *NULL* values in almost all cases. +This means that most of the :c:func:`Py_XDECREF` calls can be converted to +:c:func:`Py_DECREF` calls. The only place we can't change these calls is in +the ``tp_dealloc`` implementation, where there is the possibility that the +initialization of these members failed in ``tp_new``. + +We also rename the module initialization function and module name in the +initialization function, as we did before, and we add an extra definition to the +:file:`setup.py` file. + + +Supporting cyclic garbage collection +==================================== + +Python has a :term:`cyclic garbage collector (GC) ` that +can identify unneeded objects even when their reference counts are not zero. +This can happen when objects are involved in cycles. For example, consider: + +.. code-block:: python + + >>> l = [] + >>> l.append(l) + >>> del l + +In this example, we create a list that contains itself. When we delete it, it +still has a reference from itself. Its reference count doesn't drop to zero. +Fortunately, Python's cyclic garbage collector will eventually figure out that +the list is garbage and free it. + +In the second version of the :class:`Custom` example, we allowed any kind of +object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. +Besides, in the second and third versions, we allowed subclassing +:class:`Custom`, and subclasses may add arbitrary attributes. For any of +those two reasons, :class:`Custom` objects can participate in cycles: + +.. code-block:: python + + >>> import custom3 + >>> class Derived(custom3.Custom): pass + ... + >>> n = Derived() + >>> n.some_attribute = n + +To allow a :class:`Custom` instance participating in a reference cycle to +be properly detected and collected by the cyclic GC, our :class:`Custom` type +needs to fill two additional slots and to enable a flag that enables these slots: + +.. literalinclude:: ../includes/custom4.c + + +First, the traversal method lets the cyclic GC know about subobjects that could +participate in cycles:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + int vret; + if (self->first) { + vret = visit(self->first, arg); + if (vret != 0) + return vret; + } + if (self->last) { + vret = visit(self->last, arg); + if (vret != 0) + return vret; + } + return 0; + } + +For each subobject that can participate in cycles, we need to call the +:c:func:`visit` function, which is passed to the traversal method. The +:c:func:`visit` function takes as arguments the subobject and the extra argument +*arg* passed to the traversal method. It returns an integer value that must be +returned if it is non-zero. + +Python provides a :c:func:`Py_VISIT` macro that automates calling visit +functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate +in ``Custom_traverse``:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; + } + +.. note:: + The :c:member:`~PyTypeObject.tp_traverse` implementation must name its + arguments exactly *visit* and *arg* in order to use :c:func:`Py_VISIT`. + +Second, we need to provide a method for clearing any subobjects that can +participate in cycles:: + + static int + Custom_clear(CustomObject *self) + { + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; + } + +Notice the use of the :c:func:`Py_CLEAR` macro. It is the recommended and safe +way to clear data attributes of arbitrary types while decrementing +their reference counts. If you were to call :c:func:`Py_XDECREF` instead +on the attribute before setting it to *NULL*, there is a possibility +that the attribute's destructor would call back into code that reads the +attribute again (*especially* if there is a reference cycle). + +.. note:: + You could emulate :c:func:`Py_CLEAR` by writing:: + + PyObject *tmp; + tmp = self->first; + self->first = NULL; + Py_XDECREF(tmp); + + Nevertheless, it is much easier and less error-prone to always + use :c:func:`Py_CLEAR` when deleting an attribute. Don't + try to micro-optimize at the expense of robustness! + +The deallocator ``Custom_dealloc`` may call arbitrary code when clearing +attributes. It means the circular GC can be triggered inside the function. +Since the GC assumes reference count is not zero, we need to untrack the object +from the GC by calling :c:func:`PyObject_GC_UnTrack` before clearing members. +Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack` +and ``Custom_clear``:: + + static void + Custom_dealloc(CustomObject *self) + { + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + +That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or +:c:member:`~PyTypeObject.tp_free` handlers, we'd need to modify them for cyclic +garbage collection. Most extensions will use the versions automatically provided. + + +Subclassing other types +======================= + +It is possible to create new extension types that are derived from existing +types. It is easiest to inherit from the built in types, since an extension can +easily use the :c:type:`PyTypeObject` it needs. It can be difficult to share +these :c:type:`PyTypeObject` structures between extension modules. + +In this example we will create a :class:`SubList` type that inherits from the +built-in :class:`list` type. The new type will be completely compatible with +regular lists, but will have an additional :meth:`increment` method that +increases an internal counter: + +.. code-block:: python + + >>> import sublist + >>> s = sublist.SubList(range(3)) + >>> s.extend(s) + >>> print(len(s)) + 6 + >>> print(s.increment()) + 1 + >>> print(s.increment()) + 2 + +.. literalinclude:: ../includes/sublist.c + + +As you can see, the source code closely resembles the :class:`Custom` examples in +previous sections. We will break down the main differences between them. :: + + typedef struct { + PyListObject list; + int state; + } SubListObject; + +The primary difference for derived type objects is that the base type's +object structure must be the first value. The base type will already include +the :c:func:`PyObject_HEAD` at the beginning of its structure. + +When a Python object is a :class:`SubList` instance, its ``PyObject *`` pointer +can be safely cast to both ``PyListObject *`` and ``SubListObject *``:: + + static int + SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) + { + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; + } + +We see above how to call through to the :attr:`__init__` method of the base +type. + +This pattern is important when writing a type with custom +:c:member:`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_dealloc` +members. The :c:member:`~PyTypeObject.tp_new` handler should not actually +create the memory for the object with its :c:member:`~PyTypeObject.tp_alloc`, +but let the base class handle it by calling its own :c:member:`~PyTypeObject.tp_new`. + +The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject.tp_base` +specifying the type's concrete base class. Due to cross-platform compiler +issues, you can't fill that field directly with a reference to +:c:type:`PyList_Type`; it should be done later in the module initialization +function:: + + PyMODINIT_FUNC + PyInit_sublist(void) + { + PyObject* m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; + } + +Before calling :c:func:`PyType_Ready`, the type structure must have the +:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving an +existing type, it is not necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` +slot with :c:func:`PyType_GenericNew` -- the allocation function from the base +type will be inherited. + +After that, calling :c:func:`PyType_Ready` and adding the type object to the +module is the same as with the basic :class:`Custom` examples. + + +.. rubric:: Footnotes + +.. [#] This is true when we know that the object is a basic type, like a string or a + float. + +.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler + in this example, because our type doesn't support garbage collection. + +.. [#] We now know that the first and last members are strings, so perhaps we + could be less careful about decrementing their reference counts, however, + we accept instances of string subclasses. Even though deallocating normal + strings won't call back into our objects, we can't guarantee that deallocating + an instance of a string subclass won't call back into our objects. + +.. [#] Also, even with our attributes restricted to strings instances, the user + could pass arbitrary :class:`str` subclasses and therefore still create + reference cycles. diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c new file mode 100644 index 000000000000..fb2c7b2a430e --- /dev/null +++ b/Doc/includes/custom.c @@ -0,0 +1,39 @@ +#include + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ +} CustomObject; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = PyType_GenericNew, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c new file mode 100644 index 000000000000..51ab4b80d680 --- /dev/null +++ b/Doc/includes/custom2.c @@ -0,0 +1,132 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom2.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom2", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom2(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c new file mode 100644 index 000000000000..09e87355b91a --- /dev/null +++ b/Doc/includes/custom3.c @@ -0,0 +1,183 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + tmp = self->last; + Py_INCREF(value); + self->last = value; + Py_DECREF(tmp); + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom3.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom3", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom3(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c new file mode 100644 index 000000000000..0994d8fda0e5 --- /dev/null +++ b/Doc/includes/custom4.c @@ -0,0 +1,197 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static int +Custom_traverse(CustomObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; +} + +static int +Custom_clear(CustomObject *self) +{ + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; +} + +static void +Custom_dealloc(CustomObject *self) +{ + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->first); + self->first = value; + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->last); + self->last = value; + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom4.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_traverse = (traverseproc) Custom_traverse, + .tp_clear = (inquiry) Custom_clear, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom4", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom4(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/noddy.c b/Doc/includes/noddy.c deleted file mode 100644 index 07b5d5a9b83c..000000000000 --- a/Doc/includes/noddy.c +++ /dev/null @@ -1,72 +0,0 @@ -#include - -typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ -} noddy_NoddyObject; - -static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ -}; - -static PyModuleDef noddymodule = { - PyModuleDef_HEAD_INIT, - "noddy", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy(void) -{ - PyObject* m; - - if (PyType_Ready(&noddy_NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&noddy_NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - return m; -} diff --git a/Doc/includes/noddy2.c b/Doc/includes/noddy2.c deleted file mode 100644 index 964155845fee..000000000000 --- a/Doc/includes/noddy2.c +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy2module = { - PyModuleDef_HEAD_INIT, - "noddy2", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy2(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy2module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy3.c b/Doc/includes/noddy3.c deleted file mode 100644 index 8a5a753ca439..000000000000 --- a/Doc/includes/noddy3.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; -} - -static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_getfirst(Noddy *self, void *closure) -{ - Py_INCREF(self->first); - return self->first; -} - -static int -Noddy_setfirst(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a string"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; -} - -static PyObject * -Noddy_getlast(Noddy *self, void *closure) -{ - Py_INCREF(self->last); - return self->last; -} - -static int -Noddy_setlast(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The last attribute value must be a string"); - return -1; - } - - Py_DECREF(self->last); - Py_INCREF(value); - self->last = value; - - return 0; -} - -static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - Noddy_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy3module = { - PyModuleDef_HEAD_INIT, - "noddy3", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy3(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy3module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy4.c b/Doc/includes/noddy4.c deleted file mode 100644 index 08ba4c3d91a0..000000000000 --- a/Doc/includes/noddy4.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static int -Noddy_traverse(Noddy *self, visitproc visit, void *arg) -{ - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; -} - -static int -Noddy_clear(Noddy *self) -{ - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; -} - -static void -Noddy_dealloc(Noddy* self) -{ - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /* tp_flags */ - "Noddy objects", /* tp_doc */ - (traverseproc)Noddy_traverse, /* tp_traverse */ - (inquiry)Noddy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy4module = { - PyModuleDef_HEAD_INIT, - "noddy4", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy4(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy4module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/shoddy.c b/Doc/includes/shoddy.c deleted file mode 100644 index 0ef476532777..000000000000 --- a/Doc/includes/shoddy.c +++ /dev/null @@ -1,99 +0,0 @@ -#include - -typedef struct { - PyListObject list; - int state; -} Shoddy; - - -static PyObject * -Shoddy_increment(Shoddy *self, PyObject *unused) -{ - self->state++; - return PyLong_FromLong(self->state); -} - - -static PyMethodDef Shoddy_methods[] = { - {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, - PyDoc_STR("increment state counter")}, - {NULL}, -}; - -static int -Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) -{ - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; -} - - -static PyTypeObject ShoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "shoddy.Shoddy", /* tp_name */ - sizeof(Shoddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Shoddy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Shoddy_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -static PyModuleDef shoddymodule = { - PyModuleDef_HEAD_INIT, - "shoddy", - "Shoddy module", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_shoddy(void) -{ - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; -} diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c new file mode 100644 index 000000000000..376dddfac09c --- /dev/null +++ b/Doc/includes/sublist.c @@ -0,0 +1,63 @@ +#include + +typedef struct { + PyListObject list; + int state; +} SubListObject; + +static PyObject * +SubList_increment(SubListObject *self, PyObject *unused) +{ + self->state++; + return PyLong_FromLong(self->state); +} + +static PyMethodDef SubList_methods[] = { + {"increment", (PyCFunction) SubList_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL}, +}; + +static int +SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + +static PyTypeObject SubListType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "sublist.SubList", + .tp_doc = "SubList objects", + .tp_basicsize = sizeof(SubListObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_init = (initproc) SubList_init, + .tp_methods = SubList_methods, +}; + +static PyModuleDef sublistmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "sublist", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_sublist(void) +{ + PyObject *m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; +} diff --git a/Doc/includes/test.py b/Doc/includes/test.py index 9e9d4a67121c..09ebe3fec0bd 100644 --- a/Doc/includes/test.py +++ b/Doc/includes/test.py @@ -1,181 +1,168 @@ -"""Test module for the noddy examples +"""Test module for the custom examples -Noddy 1: +Custom 1: ->>> import noddy ->>> n1 = noddy.Noddy() ->>> n2 = noddy.Noddy() ->>> del n1 ->>> del n2 +>>> import custom +>>> c1 = custom.Custom() +>>> c2 = custom.Custom() +>>> del c1 +>>> del c2 -Noddy 2 +Custom 2 ->>> import noddy2 ->>> n1 = noddy2.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom2 +>>> c1 = custom2.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first +>>> c1.name() Traceback (most recent call last): ... AttributeError: first ->>> n1.first +>>> c1.first Traceback (most recent call last): ... AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() +>>> c1.first = 42 +>>> c1.name() '42 tell' ->>> n2 = noddy2.Noddy() ->>> n2.name() +>>> c2 = custom2.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first +>>> del c2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.name() +>>> c2.name() Traceback (most recent call last): File "", line 1, in ? AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy2.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom2.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 3 +Custom 3 ->>> import noddy3 ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1.name() +>>> import custom3 +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1.name() 'jim fulton' ->>> del n1.first +>>> del c1.first Traceback (most recent call last): File "", line 1, in ? TypeError: Cannot delete the first attribute ->>> n1.first = 42 +>>> c1.first = 42 Traceback (most recent call last): File "", line 1, in ? TypeError: The first attribute value must be a string ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n3 = noddy3.Noddy('jim', 'fulton', 'waaa') +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> n3 = custom3.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 4 +Custom 4 ->>> import noddy4 ->>> n1 = noddy4.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom4 +>>> c1 = custom4.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first Traceback (most recent call last): ... -AttributeError: first ->>> n1.first -Traceback (most recent call last): -... -AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +TypeError: Cannot delete the first attribute +>>> c1.name() +'will tell' +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() -'42 tell' ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2.name() +>>> c1.first = 42 +Traceback (most recent call last): +... +TypeError: The first attribute value must be a string +>>> c1.name() +'drew tell' +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.name() -Traceback (most recent call last): - File "", line 1, in ? -AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy4.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom4.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): - File "", line 1, in ? -TypeError: an integer is required +... +TypeError: an integer is required (got type str) Test cyclic gc(?) @@ -183,15 +170,14 @@ >>> import gc >>> gc.disable() ->>> x = [] ->>> l = [x] ->>> n2.first = l ->>> n2.first -[[]] ->>> l.append(n2) ->>> del l ->>> del n1 ->>> del n2 +>>> class Subclass(custom4.Custom): pass +... +>>> s = Subclass() +>>> s.cycle = [s] +>>> s.cycle.append(s.cycle) +>>> x = object() +>>> s.x = x +>>> del s >>> sys.getrefcount(x) 3 >>> ignore = gc.collect() diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst new file mode 100644 index 000000000000..bdee48ba0314 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst @@ -0,0 +1 @@ +Modernize documentation for writing C extension types. From webhook-mailer at python.org Sat Apr 7 12:35:38 2018 From: webhook-mailer at python.org (Antoine Pitrou) Date: Sat, 07 Apr 2018 16:35:38 -0000 Subject: [Python-checkins] [3.6] bpo-33201: Modernize "Extension types" doc (GH-6337) (GH-6412) Message-ID: https://github.com/python/cpython/commit/b603609e9dd19268b61b52e701cc0ee8e86784c5 commit: b603609e9dd19268b61b52e701cc0ee8e86784c5 branch: 3.6 author: Antoine Pitrou committer: GitHub date: 2018-04-07T18:35:35+02:00 summary: [3.6] bpo-33201: Modernize "Extension types" doc (GH-6337) (GH-6412) * bpo-33201: Modernize "Extension types" doc * Split tutorial and other topics * Some small fixes * Address some review comments * Rename noddy* to custom* and shoddy to sublist * Fix markup. (cherry picked from commit 1d80a561734b9932961c546b0897405a3bfbf3e6) files: A Doc/extending/newtypes_tutorial.rst A Doc/includes/custom.c A Doc/includes/custom2.c A Doc/includes/custom3.c A Doc/includes/custom4.c A Doc/includes/sublist.c A Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst D Doc/includes/noddy.c D Doc/includes/noddy2.c D Doc/includes/noddy3.c D Doc/includes/noddy4.c D Doc/includes/shoddy.c M Doc/extending/index.rst M Doc/extending/newtypes.rst M Doc/includes/test.py diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst index 9eec8c273af3..533ed985f829 100644 --- a/Doc/extending/index.rst +++ b/Doc/extending/index.rst @@ -26,9 +26,11 @@ Recommended third party tools ============================= This guide only covers the basic tools for creating extensions provided -as part of this version of CPython. Third party tools like Cython, -``cffi``, SWIG and Numba offer both simpler and more sophisticated -approaches to creating C and C++ extensions for Python. +as part of this version of CPython. Third party tools like +`Cython `_, `cffi `_, +`SWIG `_ and `Numba `_ +offer both simpler and more sophisticated approaches to creating C and C++ +extensions for Python. .. seealso:: @@ -52,6 +54,7 @@ C extensions. :numbered: extending.rst + newtypes_tutorial.rst newtypes.rst building.rst windows.rst diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index edba57e4a3e8..b55796421c0f 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1,896 +1,11 @@ .. highlightlang:: c - -.. _defining-new-types: - -****************** -Defining New Types -****************** - -.. sectionauthor:: Michael Hudson -.. sectionauthor:: Dave Kuhlman -.. sectionauthor:: Jim Fulton - - -As mentioned in the last chapter, Python allows the writer of an extension -module to define new types that can be manipulated from Python code, much like -strings and lists in core Python. - -This is not hard; the code for all extension types follows a pattern, but there -are some details that you need to understand before you can get started. - - -.. _dnt-basics: - -The Basics -========== - -The Python runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. -:c:type:`PyObject` itself only contains the refcount and a pointer to the -object's "type object". This is where the action is; the type object determines -which (C) functions get called when, for instance, an attribute gets looked -up on an object or it is multiplied by another object. These C functions -are called "type methods". - -So, if you want to define a new object type, you need to create a new type -object. - -This sort of thing can only be explained by example, so here's a minimal, but -complete, module that defines a new type: - -.. literalinclude:: ../includes/noddy.c - - -Now that's quite a bit to take in at once, but hopefully bits will seem familiar -from the last chapter. - -The first bit that will be new is:: - - typedef struct { - PyObject_HEAD - } noddy_NoddyObject; - -This is what a Noddy object will contain---in this case, nothing more than what -every Python object contains---a field called ``ob_base`` of type -:c:type:`PyObject`. :c:type:`PyObject` in turn, contains an ``ob_refcnt`` -field and a pointer to a type object. These can be accessed using the macros -:c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE` respectively. These are the fields -the :c:macro:`PyObject_HEAD` macro brings in. The reason for the macro is to -standardize the layout and to enable special debugging fields in debug builds. - -Note that there is no semicolon after the :c:macro:`PyObject_HEAD` macro; -one is included in the macro definition. Be wary of adding one by -accident; it's easy to do from habit, and your compiler might not complain, -but someone else's probably will! (On Windows, MSVC is known to call this an -error and refuse to compile the code.) - -For contrast, let's take a look at the corresponding definition for standard -Python floats:: - - typedef struct { - PyObject_HEAD - double ob_fval; - } PyFloatObject; - -Moving on, we come to the crunch --- the type object. :: - - static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ - }; - -Now if you go and look up the definition of :c:type:`PyTypeObject` in -:file:`object.h` you'll see that it has many more fields that the definition -above. The remaining fields will be filled with zeros by the C compiler, and -it's common practice to not specify them explicitly unless you need them. - -This is so important that we're going to pick the top of it apart still -further:: - - PyVarObject_HEAD_INIT(NULL, 0) - -This line is a bit of a wart; what we'd like to write is:: - - PyVarObject_HEAD_INIT(&PyType_Type, 0) - -as the type of a type object is "type", but this isn't strictly conforming C and -some compilers complain. Fortunately, this member will be filled in for us by -:c:func:`PyType_Ready`. :: - - "noddy.Noddy", /* tp_name */ - -The name of our type. This will appear in the default textual representation of -our objects and in some error messages, for example:: - - >>> "" + noddy.new_noddy() - Traceback (most recent call last): - File "", line 1, in - TypeError: cannot add type "noddy.Noddy" to string - -Note that the name is a dotted name that includes both the module name and the -name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. -One side effect of using an undotted name is that the pydoc documentation tool -will not list the new type in the module documentation. :: - - sizeof(noddy_NoddyObject), /* tp_basicsize */ - -This is so that Python knows how much memory to allocate when you call -:c:func:`PyObject_New`. - -.. note:: - - If you want your type to be subclassable from Python, and your type has the same - :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple - inheritance. A Python subclass of your type will have to list your type first - in its :attr:`~class.__bases__`, or else it will not be able to call your type's - :meth:`__new__` method without getting an error. You can avoid this problem by - ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its - base type does. Most of the time, this will be true anyway, because either your - base type will be :class:`object`, or else you will be adding data members to - your base type, and therefore increasing its size. - -:: - - 0, /* tp_itemsize */ - -This has to do with variable length objects like lists and strings. Ignore this -for now. - -Skipping a number of type methods that we don't provide, we set the class flags -to :const:`Py_TPFLAGS_DEFAULT`. :: - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - -All types should include this constant in their flags. It enables all of the -members defined until at least Python 3.3. If you need further members, -you will need to OR the corresponding flags. - -We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: - - "Noddy objects", /* tp_doc */ - -Now we get into the type methods, the things that make your objects different -from the others. We aren't going to implement any of these in this version of -the module. We'll expand this example later to have more interesting behavior. - -For now, all we want to be able to do is to create new :class:`Noddy` objects. -To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` implementation. -In this case, we can just use the default implementation provided by the API -function :c:func:`PyType_GenericNew`. We'd like to just assign this to the -:c:member:`~PyTypeObject.tp_new` slot, but we can't, for portability sake, On some platforms or -compilers, we can't statically initialize a structure member with a function -defined in another C module, so, instead, we'll assign the :c:member:`~PyTypeObject.tp_new` slot -in the module initialization function just before calling -:c:func:`PyType_Ready`:: - - noddy_NoddyType.tp_new = PyType_GenericNew; - if (PyType_Ready(&noddy_NoddyType) < 0) - return; - -All the other type methods are *NULL*, so we'll go over them later --- that's -for a later section! - -Everything else in the file should be familiar, except for some code in -:c:func:`PyInit_noddy`:: - - if (PyType_Ready(&noddy_NoddyType) < 0) - return; - -This initializes the :class:`Noddy` type, filing in a number of members, -including :attr:`ob_type` that we initially set to *NULL*. :: - - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - -This adds the type to the module dictionary. This allows us to create -:class:`Noddy` instances by calling the :class:`Noddy` class:: - - >>> import noddy - >>> mynoddy = noddy.Noddy() - -That's it! All that remains is to build it; put the above code in a file called -:file:`noddy.c` and :: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[Extension("noddy", ["noddy.c"])]) - -in a file called :file:`setup.py`; then typing - -.. code-block:: shell-session - - $ python setup.py build - -at a shell should produce a file :file:`noddy.so` in a subdirectory; move to -that directory and fire up Python --- you should be able to ``import noddy`` and -play around with Noddy objects. - -That wasn't so hard, was it? - -Of course, the current Noddy type is pretty uninteresting. It has no data and -doesn't do anything. It can't even be subclassed. - - -Adding data and methods to the Basic example --------------------------------------------- - -Let's extend the basic example to add some data and methods. Let's also make -the type usable as a base class. We'll create a new module, :mod:`noddy2` that -adds these capabilities: - -.. literalinclude:: ../includes/noddy2.c - - -This version of the module has a number of changes. - -We've added an extra include:: - - #include - -This include provides declarations that we use to handle attributes, as -described a bit later. - -The name of the :class:`Noddy` object structure has been shortened to -:class:`Noddy`. The type object name has been shortened to :class:`NoddyType`. - -The :class:`Noddy` type now has three data attributes, *first*, *last*, and -*number*. The *first* and *last* variables are Python strings containing first -and last names. The *number* attribute is an integer. - -The object structure is updated accordingly:: - - typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; - } Noddy; - -Because we now have data to manage, we have to be more careful about object -allocation and deallocation. At a minimum, we need a deallocation method:: - - static void - Noddy_dealloc(Noddy* self) - { - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: - - (destructor)Noddy_dealloc, /*tp_dealloc*/ - -This method decrements the reference counts of the two Python attributes. We use -:c:func:`Py_XDECREF` here because the :attr:`first` and :attr:`last` members -could be *NULL*. It then calls the :c:member:`~PyTypeObject.tp_free` member of the object's type -to free the object's memory. Note that the object's type might not be -:class:`NoddyType`, because the object may be an instance of a subclass. - -We want to make sure that the first and last names are initialized to empty -strings, so we provide a new method:: - - static PyObject * - Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; - } - -and install it in the :c:member:`~PyTypeObject.tp_new` member:: - - Noddy_new, /* tp_new */ - -The new member is responsible for creating (as opposed to initializing) objects -of the type. It is exposed in Python as the :meth:`__new__` method. See the -paper titled "Unifying types and classes in Python" for a detailed discussion of -the :meth:`__new__` method. One reason to implement a new method is to assure -the initial values of instance variables. In this case, we use the new method -to make sure that the initial values of the members :attr:`first` and -:attr:`last` are not *NULL*. If we didn't care whether the initial values were -*NULL*, we could have used :c:func:`PyType_GenericNew` as our new method, as we -did before. :c:func:`PyType_GenericNew` initializes all of the instance variable -members to *NULL*. - -The new method is a static method that is passed the type being instantiated and -any arguments passed when the type was called, and that returns the new object -created. New methods always accept positional and keyword arguments, but they -often ignore the arguments, leaving the argument handling to initializer -methods. Note that if the type supports subclassing, the type passed may not be -the type being defined. The new method calls the :c:member:`~PyTypeObject.tp_alloc` slot to -allocate memory. We don't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather -:c:func:`PyType_Ready` fills it for us by inheriting it from our base class, -which is :class:`object` by default. Most types use the default allocation. - -.. note:: - - If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one that calls a base type's - :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), you must *not* try to determine what method - to call using method resolution order at runtime. Always statically determine - what type you are going to call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via - ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your - type that also inherit from other Python-defined classes may not work correctly. - (Specifically, you may not be able to create instances of such subclasses - without getting a :exc:`TypeError`.) - -We provide an initialization function:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; - } - -by filling the :c:member:`~PyTypeObject.tp_init` slot. :: - - (initproc)Noddy_init, /* tp_init */ - -The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the :meth:`__init__` method. It -is used to initialize an object after it's created. Unlike the new method, we -can't guarantee that the initializer is called. The initializer isn't called -when unpickling objects and it can be overridden. Our initializer accepts -arguments to provide initial values for our instance. Initializers always accept -positional and keyword arguments. Initializers should return either ``0`` on -success or ``-1`` on error. - -Initializers can be called multiple times. Anyone can call the :meth:`__init__` -method on our objects. For this reason, we have to be extra careful when -assigning the new values. We might be tempted, for example to assign the -:attr:`first` member like this:: - - if (first) { - Py_XDECREF(self->first); - Py_INCREF(first); - self->first = first; - } - -But this would be risky. Our type doesn't restrict the type of the -:attr:`first` member, so it could be any kind of object. It could have a -destructor that causes code to be executed that tries to access the -:attr:`first` member. To be paranoid and protect ourselves against this -possibility, we almost always reassign members before decrementing their -reference counts. When don't we have to do this? - -* when we absolutely know that the reference count is greater than 1 - -* when we know that deallocation of the object [#]_ will not cause any calls - back into our type's code - -* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` handler when - garbage-collections is not supported [#]_ - -We want to expose our instance variables as attributes. There are a -number of ways to do that. The simplest way is to define member definitions:: - - static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: - - Noddy_members, /* tp_members */ - -Each member definition has a member name, type, offset, access flags and -documentation string. See the :ref:`Generic-Attribute-Management` section below for -details. - -A disadvantage of this approach is that it doesn't provide a way to restrict the -types of objects that can be assigned to the Python attributes. We expect the -first and last names to be strings, but any Python objects can be assigned. -Further, the attributes can be deleted, setting the C pointers to *NULL*. Even -though we can make sure the members are initialized to non-*NULL* values, the -members can be set to *NULL* if the attributes are deleted. - -We define a single method, :meth:`name`, that outputs the objects name as the -concatenation of the first and last names. :: - - static PyObject * - Noddy_name(Noddy* self) - { - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); - } - -The method is implemented as a C function that takes a :class:`Noddy` (or -:class:`Noddy` subclass) instance as the first argument. Methods always take an -instance as the first argument. Methods often take positional and keyword -arguments as well, but in this case we don't take any and don't need to accept -a positional argument tuple or keyword argument dictionary. This method is -equivalent to the Python method:: - - def name(self): - return "%s %s" % (self.first, self.last) - -Note that we have to check for the possibility that our :attr:`first` and -:attr:`last` members are *NULL*. This is because they can be deleted, in which -case they are set to *NULL*. It would be better to prevent deletion of these -attributes and to restrict the attribute values to be strings. We'll see how to -do that in the next section. - -Now that we've defined the method, we need to create an array of method -definitions:: - - static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ - }; - -and assign them to the :c:member:`~PyTypeObject.tp_methods` slot:: - - Noddy_methods, /* tp_methods */ - -Note that we used the :const:`METH_NOARGS` flag to indicate that the method is -passed no arguments. - -Finally, we'll make our type usable as a base class. We've written our methods -carefully so far so that they don't make any assumptions about the type of the -object being created or used, so all we need to do is to add the -:const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - -We rename :c:func:`PyInit_noddy` to :c:func:`PyInit_noddy2` and update the module -name in the :c:type:`PyModuleDef` struct. - -Finally, we update our :file:`setup.py` file to build the new module:: - - from distutils.core import setup, Extension - setup(name="noddy", version="1.0", - ext_modules=[ - Extension("noddy", ["noddy.c"]), - Extension("noddy2", ["noddy2.c"]), - ]) - - -Providing finer control over data attributes --------------------------------------------- - -In this section, we'll provide finer control over how the :attr:`first` and -:attr:`last` attributes are set in the :class:`Noddy` example. In the previous -version of our module, the instance variables :attr:`first` and :attr:`last` -could be set to non-string values or even deleted. We want to make sure that -these attributes always contain strings. - -.. literalinclude:: ../includes/noddy3.c - - -To provide greater control, over the :attr:`first` and :attr:`last` attributes, -we'll use custom getter and setter functions. Here are the functions for -getting and setting the :attr:`first` attribute:: - - Noddy_getfirst(Noddy *self, void *closure) - { - Py_INCREF(self->first); - return self->first; - } - - static int - Noddy_setfirst(Noddy *self, PyObject *value, void *closure) - { - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a str"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; - } - -The getter function is passed a :class:`Noddy` object and a "closure", which is -void pointer. In this case, the closure is ignored. (The closure supports an -advanced usage in which definition data is passed to the getter and setter. This -could, for example, be used to allow a single set of getter and setter functions -that decide the attribute to get or set based on data in the closure.) - -The setter function is passed the :class:`Noddy` object, the new value, and the -closure. The new value may be *NULL*, in which case the attribute is being -deleted. In our setter, we raise an error if the attribute is deleted or if the -attribute value is not a string. - -We create an array of :c:type:`PyGetSetDef` structures:: - - static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ - }; - -and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: - - Noddy_getseters, /* tp_getset */ - -to register our attribute getters and setters. - -The last item in a :c:type:`PyGetSetDef` structure is the closure mentioned -above. In this case, we aren't using the closure, so we just pass *NULL*. - -We also remove the member definitions for these attributes:: - - static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ - }; - -We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only allow strings [#]_ to -be passed:: - - static int - Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) - { - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; - } - -With these changes, we can assure that the :attr:`first` and :attr:`last` -members are never *NULL* so we can remove checks for *NULL* values in almost all -cases. This means that most of the :c:func:`Py_XDECREF` calls can be converted to -:c:func:`Py_DECREF` calls. The only place we can't change these calls is in the -deallocator, where there is the possibility that the initialization of these -members failed in the constructor. - -We also rename the module initialization function and module name in the -initialization function, as we did before, and we add an extra definition to the -:file:`setup.py` file. - - -Supporting cyclic garbage collection ------------------------------------- - -Python has a cyclic-garbage collector that can identify unneeded objects even -when their reference counts are not zero. This can happen when objects are -involved in cycles. For example, consider:: - - >>> l = [] - >>> l.append(l) - >>> del l - -In this example, we create a list that contains itself. When we delete it, it -still has a reference from itself. Its reference count doesn't drop to zero. -Fortunately, Python's cyclic-garbage collector will eventually figure out that -the list is garbage and free it. - -In the second version of the :class:`Noddy` example, we allowed any kind of -object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. This -means that :class:`Noddy` objects can participate in cycles:: - - >>> import noddy2 - >>> n = noddy2.Noddy() - >>> l = [n] - >>> n.first = l - -This is pretty silly, but it gives us an excuse to add support for the -cyclic-garbage collector to the :class:`Noddy` example. To support cyclic -garbage collection, types need to fill two slots and set a class flag that -enables these slots: - -.. literalinclude:: ../includes/noddy4.c - - -The traversal method provides access to subobjects that could participate in -cycles:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; - } - -For each subobject that can participate in cycles, we need to call the -:c:func:`visit` function, which is passed to the traversal method. The -:c:func:`visit` function takes as arguments the subobject and the extra argument -*arg* passed to the traversal method. It returns an integer value that must be -returned if it is non-zero. - -Python provides a :c:func:`Py_VISIT` macro that automates calling visit -functions. With :c:func:`Py_VISIT`, :c:func:`Noddy_traverse` can be simplified:: - - static int - Noddy_traverse(Noddy *self, visitproc visit, void *arg) - { - Py_VISIT(self->first); - Py_VISIT(self->last); - return 0; - } - -.. note:: - - Note that the :c:member:`~PyTypeObject.tp_traverse` implementation must name its arguments exactly - *visit* and *arg* in order to use :c:func:`Py_VISIT`. This is to encourage - uniformity across these boring implementations. - -We also need to provide a method for clearing any subobjects that can -participate in cycles. - -:: - - static int - Noddy_clear(Noddy *self) - { - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; - } - -Notice the use of a temporary variable in :c:func:`Noddy_clear`. We use the -temporary variable so that we can set each member to *NULL* before decrementing -its reference count. We do this because, as was discussed earlier, if the -reference count drops to zero, we might cause code to run that calls back into -the object. In addition, because we now support garbage collection, we also -have to worry about code being run that triggers garbage collection. If garbage -collection is run, our :c:member:`~PyTypeObject.tp_traverse` handler could get called. We can't -take a chance of having :c:func:`Noddy_traverse` called when a member's reference -count has dropped to zero and its value hasn't been set to *NULL*. - -Python provides a :c:func:`Py_CLEAR` that automates the careful decrementing of -reference counts. With :c:func:`Py_CLEAR`, the :c:func:`Noddy_clear` function can -be simplified:: - - static int - Noddy_clear(Noddy *self) - { - Py_CLEAR(self->first); - Py_CLEAR(self->last); - return 0; - } - -Note that :c:func:`Noddy_dealloc` may call arbitrary functions through -``__del__`` method or weakref callback. It means circular GC can be -triggered inside the function. Since GC assumes reference count is not zero, -we need to untrack the object from GC by calling :c:func:`PyObject_GC_UnTrack` -before clearing members. Here is reimplemented deallocator which uses -:c:func:`PyObject_GC_UnTrack` and :c:func:`Noddy_clear`. - -:: - - static void - Noddy_dealloc(Noddy* self) - { - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); - } - -Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: - - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - -That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or -:c:member:`~PyTypeObject.tp_free` slots, we'd need to modify them for cyclic-garbage collection. -Most extensions will use the versions automatically provided. - - -Subclassing other types ------------------------ - -It is possible to create new extension types that are derived from existing -types. It is easiest to inherit from the built in types, since an extension can -easily use the :class:`PyTypeObject` it needs. It can be difficult to share -these :class:`PyTypeObject` structures between extension modules. - -In this example we will create a :class:`Shoddy` type that inherits from the -built-in :class:`list` type. The new type will be completely compatible with -regular lists, but will have an additional :meth:`increment` method that -increases an internal counter. :: - - >>> import shoddy - >>> s = shoddy.Shoddy(range(3)) - >>> s.extend(s) - >>> print(len(s)) - 6 - >>> print(s.increment()) - 1 - >>> print(s.increment()) - 2 - -.. literalinclude:: ../includes/shoddy.c - - -As you can see, the source code closely resembles the :class:`Noddy` examples in -previous sections. We will break down the main differences between them. :: - - typedef struct { - PyListObject list; - int state; - } Shoddy; - -The primary difference for derived type objects is that the base type's object -structure must be the first value. The base type will already include the -:c:func:`PyObject_HEAD` at the beginning of its structure. - -When a Python object is a :class:`Shoddy` instance, its *PyObject\** pointer can -be safely cast to both *PyListObject\** and *Shoddy\**. :: - - static int - Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) - { - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; - } - -In the :attr:`__init__` method for our type, we can see how to call through to -the :attr:`__init__` method of the base type. - -This pattern is important when writing a type with custom :attr:`new` and -:attr:`dealloc` methods. The :attr:`new` method should not actually create the -memory for the object with :c:member:`~PyTypeObject.tp_alloc`, that will be handled by the base -class when calling its :c:member:`~PyTypeObject.tp_new`. - -When filling out the :c:func:`PyTypeObject` for the :class:`Shoddy` type, you see -a slot for :c:func:`tp_base`. Due to cross platform compiler issues, you can't -fill that field directly with the :c:func:`PyList_Type`; it can be done later in -the module's :c:func:`init` function. :: - - PyMODINIT_FUNC - PyInit_shoddy(void) - { - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; - } - -Before calling :c:func:`PyType_Ready`, the type structure must have the -:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving a new type, it is not -necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` slot with :c:func:`PyType_GenericNew` --- the allocate function from the base type will be inherited. - -After that, calling :c:func:`PyType_Ready` and adding the type object to the -module is the same as with the basic :class:`Noddy` examples. - +***************************************** +Defining Extension Types: Assorted Topics +***************************************** .. _dnt-type-methods: -Type Methods -============ - This section aims to give a quick fly-by on the various type methods you can implement and what they do. @@ -900,21 +15,20 @@ debug builds omitted: .. literalinclude:: ../includes/typestruct.h -Now that's a *lot* of methods. Don't worry too much though - if you have a type -you want to define, the chances are very good that you will only implement a -handful of these. +Now that's a *lot* of methods. Don't worry too much though -- if you have +a type you want to define, the chances are very good that you will only +implement a handful of these. As you probably expect by now, we're going to go over this and give more information about the various handlers. We won't go in the order they are defined in the structure, because there is a lot of historical baggage that -impacts the ordering of the fields; be sure your type initialization keeps the -fields in the right order! It's often easiest to find an example that includes -all the fields you need (even if they're initialized to ``0``) and then change -the values to suit your new type. :: +impacts the ordering of the fields. It's often easiest to find an example +that includes the fields you need and then change the values to suit your new +type. :: const char *tp_name; /* For printing */ -The name of the type - as mentioned in the last section, this will appear in +The name of the type -- as mentioned in the previous chapter, this will appear in various places, almost entirely for diagnostic purposes. Try to choose something that will be helpful in such a situation! :: @@ -922,7 +36,7 @@ that will be helpful in such a situation! :: These fields tell the runtime how much memory to allocate when new objects of this type are created. Python has some built-in support for variable length -structures (think: strings, lists) which is where the :c:member:`~PyTypeObject.tp_itemsize` field +structures (think: strings, tuples) which is where the :c:member:`~PyTypeObject.tp_itemsize` field comes in. This will be dealt with later. :: const char *tp_doc; @@ -930,7 +44,7 @@ comes in. This will be dealt with later. :: Here you can put a string (or its address) that you want returned when the Python script references ``obj.__doc__`` to retrieve the doc string. -Now we come to the basic type methods---the ones most extension types will +Now we come to the basic type methods -- the ones most extension types will implement. @@ -954,7 +68,7 @@ object itself needs to be freed here as well. Here is an example of this function:: static void - newdatatype_dealloc(newdatatypeobject * obj) + newdatatype_dealloc(newdatatypeobject *obj) { free(obj->obj_UnderlyingDatatypePtr); Py_TYPE(obj)->tp_free(obj); @@ -1042,7 +156,7 @@ example:: static PyObject * newdatatype_repr(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1062,7 +176,7 @@ Here is a simple example:: static PyObject * newdatatype_str(newdatatypeobject * obj) { - return PyUnicode_FromFormat("Stringified_newdatatype{{size:\%d}}", + return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); } @@ -1243,7 +357,7 @@ example that simply raises an exception; if this were really all you wanted, the static int newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v) { - (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name); + PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name); return -1; } @@ -1328,17 +442,23 @@ these in the :file:`Objects` directory of the Python source distribution. :: hashfunc tp_hash; This function, if you choose to provide it, should return a hash number for an -instance of your data type. Here is a moderately pointless example:: +instance of your data type. Here is a simple example:: - static long + static Py_hash_t newdatatype_hash(newdatatypeobject *obj) { - long result; - result = obj->obj_UnderlyingDatatypePtr->size; - result = result * 3; + Py_hash_t result; + result = obj->some_size + 32767 * obj->some_number; + if (result == -1) + result = -2; return result; } +:c:type:`Py_hash_t` is a signed integer type with a platform-varying width. +Returning ``-1`` from :c:member:`~PyTypeObject.tp_hash` indicates an error, +which is why you should be careful to avoid returning it when hash computation +is successful, as seen above. + :: ternaryfunc tp_call; @@ -1349,27 +469,22 @@ contains ``obj1('hello')``, the :c:member:`~PyTypeObject.tp_call` handler is inv This function takes three arguments: -#. *arg1* is the instance of the data type which is the subject of the call. If - the call is ``obj1('hello')``, then *arg1* is ``obj1``. +#. *self* is the instance of the data type which is the subject of the call. + If the call is ``obj1('hello')``, then *self* is ``obj1``. -#. *arg2* is a tuple containing the arguments to the call. You can use +#. *args* is a tuple containing the arguments to the call. You can use :c:func:`PyArg_ParseTuple` to extract the arguments. -#. *arg3* is a dictionary of keyword arguments that were passed. If this is +#. *kwds* is a dictionary of keyword arguments that were passed. If this is non-*NULL* and you support keyword arguments, use - :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you do not - want to support keyword arguments and this is non-*NULL*, raise a + :c:func:`PyArg_ParseTupleAndKeywords` to extract the arguments. If you + do not want to support keyword arguments and this is non-*NULL*, raise a :exc:`TypeError` with a message saying that keyword arguments are not supported. -Here is a desultory example of the implementation of the call function. :: +Here is a toy ``tp_call`` implementation:: - /* Implement the call function. - * obj1 is the instance receiving the call. - * obj2 is a tuple containing the arguments to the call, in this - * case 3 strings. - */ static PyObject * - newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *other) + newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds) { PyObject *result; char *arg1; @@ -1380,7 +495,7 @@ Here is a desultory example of the implementation of the call function. :: return NULL; } result = PyUnicode_FromFormat( - "Returning -- value: [\%d] arg1: [\%s] arg2: [\%s] arg3: [\%s]\n", + "Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n", obj->obj_UnderlyingDatatypePtr->size, arg1, arg2, arg3); return result; @@ -1392,32 +507,36 @@ Here is a desultory example of the implementation of the call function. :: getiterfunc tp_iter; iternextfunc tp_iternext; -These functions provide support for the iterator protocol. Any object which -wishes to support iteration over its contents (which may be generated during -iteration) must implement the ``tp_iter`` handler. Objects which are returned -by a ``tp_iter`` handler must implement both the ``tp_iter`` and ``tp_iternext`` -handlers. Both handlers take exactly one parameter, the instance for which they -are being called, and return a new reference. In the case of an error, they -should set an exception and return *NULL*. - -For an object which represents an iterable collection, the ``tp_iter`` handler -must return an iterator object. The iterator object is responsible for -maintaining the state of the iteration. For collections which can support -multiple iterators which do not interfere with each other (as lists and tuples -do), a new iterator should be created and returned. Objects which can only be -iterated over once (usually due to side effects of iteration) should implement -this handler by returning a new reference to themselves, and should also -implement the ``tp_iternext`` handler. File objects are an example of such an -iterator. - -Iterator objects should implement both handlers. The ``tp_iter`` handler should -return a new reference to the iterator (this is the same as the ``tp_iter`` -handler for objects which can only be iterated over destructively). The -``tp_iternext`` handler should return a new reference to the next object in the -iteration if there is one. If the iteration has reached the end, it may return -*NULL* without setting an exception or it may set :exc:`StopIteration`; avoiding -the exception can yield slightly better performance. If an actual error occurs, -it should set an exception and return *NULL*. +These functions provide support for the iterator protocol. Both handlers +take exactly one parameter, the instance for which they are being called, +and return a new reference. In the case of an error, they should set an +exception and return *NULL*. :c:member:`~PyTypeObject.tp_iter` corresponds +to the Python :meth:`__iter__` method, while :c:member:`~PyTypeObject.tp_iternext` +corresponds to the Python :meth:`~iterator.__next__` method. + +Any :term:`iterable` object must implement the :c:member:`~PyTypeObject.tp_iter` +handler, which must return an :term:`iterator` object. Here the same guidelines +apply as for Python classes: + +* For collections (such as lists and tuples) which can support multiple + independent iterators, a new iterator should be created and returned by + each call to :c:member:`~PyTypeObject.tp_iter`. +* Objects which can only be iterated over once (usually due to side effects of + iteration, such as file objects) can implement :c:member:`~PyTypeObject.tp_iter` + by returning a new reference to themselves -- and should also therefore + implement the :c:member:`~PyTypeObject.tp_iternext` handler. + +Any :term:`iterator` object should implement both :c:member:`~PyTypeObject.tp_iter` +and :c:member:`~PyTypeObject.tp_iternext`. An iterator's +:c:member:`~PyTypeObject.tp_iter` handler should return a new reference +to the iterator. Its :c:member:`~PyTypeObject.tp_iternext` handler should +return a new reference to the next object in the iteration, if there is one. +If the iteration has reached the end, :c:member:`~PyTypeObject.tp_iternext` +may return *NULL* without setting an exception, or it may set +:exc:`StopIteration` *in addition* to returning *NULL*; avoiding +the exception can yield slightly better performance. If an actual error +occurs, :c:member:`~PyTypeObject.tp_iternext` should always set an exception +and return *NULL*. .. _weakref-support: @@ -1425,110 +544,76 @@ it should set an exception and return *NULL*. Weak Reference Support ---------------------- -One of the goals of Python's weak-reference implementation is to allow any type +One of the goals of Python's weak reference implementation is to allow any type to participate in the weak reference mechanism without incurring the overhead on -those objects which do not benefit by weak referencing (such as numbers). +performance-critical objects (such as numbers). -For an object to be weakly referencable, the extension must include a -:c:type:`PyObject\*` field in the instance structure for the use of the weak -reference mechanism; it must be initialized to *NULL* by the object's -constructor. It must also set the :c:member:`~PyTypeObject.tp_weaklistoffset` field of the -corresponding type object to the offset of the field. For example, the instance -type is defined with the following structure:: +.. seealso:: + Documentation for the :mod:`weakref` module. - typedef struct { - PyObject_HEAD - PyClassObject *in_class; /* The class object */ - PyObject *in_dict; /* A dictionary */ - PyObject *in_weakreflist; /* List of weak references */ - } PyInstanceObject; - -The statically-declared type object for instances is defined this way:: - - PyTypeObject PyInstance_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - 0, - "module.instance", - - /* Lots of stuff omitted for brevity... */ - - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ - }; +For an object to be weakly referencable, the extension type must do two things: -The type constructor is responsible for initializing the weak reference list to -*NULL*:: +#. Include a :c:type:`PyObject\*` field in the C object structure dedicated to + the weak reference mechanism. The object's constructor should leave it + *NULL* (which is automatic when using the default + :c:member:`~PyTypeObject.tp_alloc`). - static PyObject * - instance_new() { - /* Other initialization stuff omitted for brevity */ +#. Set the :c:member:`~PyTypeObject.tp_weaklistoffset` type member + to the offset of the aforementioned field in the C object structure, + so that the interpreter knows how to access and modify that field. - self->in_weakreflist = NULL; +Concretely, here is how a trivial object structure would be augmented +with the required field:: - return (PyObject *) self; - } + typedef struct { + PyObject_HEAD + PyObject *weakreflist; /* List of weak references */ + } TrivialObject; -The only further addition is that the destructor needs to call the weak -reference manager to clear any weak references. This is only required if the -weak reference list is non-*NULL*:: +And the corresponding member in the statically-declared type object:: - static void - instance_dealloc(PyInstanceObject *inst) - { - /* Allocate temporaries if needed, but do not begin - destruction just yet. - */ + static PyTypeObject TrivialType = { + PyVarObject_HEAD_INIT(NULL, 0) + /* ... other members omitted for brevity ... */ + .tp_weaklistoffset = offsetof(TrivialObject, weakreflist), + }; - if (inst->in_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) inst); +The only further addition is that ``tp_dealloc`` needs to clear any weak +references (by calling :c:func:`PyObject_ClearWeakRefs`) if the field is +non-*NULL*:: - /* Proceed with object destruction normally. */ + static void + Trivial_dealloc(TrivialObject *self) + { + /* Clear weakrefs first before calling any destructors */ + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); + /* ... remainder of destruction code omitted for brevity ... */ + Py_TYPE(self)->tp_free((PyObject *) self); } More Suggestions ---------------- -Remember that you can omit most of these functions, in which case you provide -``0`` as a value. There are type definitions for each of the functions you must -provide. They are in :file:`object.h` in the Python include directory that -comes with the source distribution of Python. - In order to learn how to implement any specific method for your new data type, -do the following: Download and unpack the Python source distribution. Go to -the :file:`Objects` directory, then search the C source files for ``tp_`` plus -the function you want (for example, ``tp_richcompare``). You will find examples -of the function you want to implement. +get the :term:`CPython` source code. Go to the :file:`Objects` directory, +then search the C source files for ``tp_`` plus the function you want +(for example, ``tp_richcompare``). You will find examples of the function +you want to implement. -When you need to verify that an object is an instance of the type you are -implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of its use -might be something like the following:: +When you need to verify that an object is a concrete instance of the type you +are implementing, use the :c:func:`PyObject_TypeCheck` function. A sample of +its use might be something like the following:: - if (! PyObject_TypeCheck(some_object, &MyType)) { + if (!PyObject_TypeCheck(some_object, &MyType)) { PyErr_SetString(PyExc_TypeError, "arg #1 not a mything"); return NULL; } -.. rubric:: Footnotes - -.. [#] This is true when we know that the object is a basic type, like a string or a - float. - -.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler in this example, because our - type doesn't support garbage collection. Even if a type supports garbage - collection, there are calls that can be made to "untrack" the object from - garbage collection, however, these calls are advanced and not covered here. - -.. [#] We now know that the first and last members are strings, so perhaps we could be - less careful about decrementing their reference counts, however, we accept - instances of string subclasses. Even though deallocating normal strings won't - call back into our objects, we can't guarantee that deallocating an instance of - a string subclass won't call back into our objects. +.. seealso:: + Download CPython source releases. + https://www.python.org/downloads/source/ -.. [#] Even in the third version, we aren't guaranteed to avoid cycles. Instances of - string subclasses are allowed and string subclasses could allow cycles even if - normal strings don't. + The CPython project on GitHub, where the CPython source code is developed. + https://github.com/python/cpython diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst new file mode 100644 index 000000000000..5e05cf693652 --- /dev/null +++ b/Doc/extending/newtypes_tutorial.rst @@ -0,0 +1,896 @@ +.. highlightlang:: c + +.. _defining-new-types: + +********************************** +Defining Extension Types: Tutorial +********************************** + +.. sectionauthor:: Michael Hudson +.. sectionauthor:: Dave Kuhlman +.. sectionauthor:: Jim Fulton + + +Python allows the writer of a C extension module to define new types that +can be manipulated from Python code, much like the built-in :class:`str` +and :class:`list` types. The code for all extension types follows a +pattern, but there are some details that you need to understand before you +can get started. This document is a gentle introduction to the topic. + + +.. _dnt-basics: + +The Basics +========== + +The :term:`CPython` runtime sees all Python objects as variables of type +:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +The :c:type:`PyObject` structure itself only contains the object's +:term:`reference count` and a pointer to the object's "type object". +This is where the action is; the type object determines which (C) functions +get called by the interpreter when, for instance, an attribute gets looked up +on an object, a method called, or it is multiplied by another object. These +C functions are called "type methods". + +So, if you want to define a new extension type, you need to create a new type +object. + +This sort of thing can only be explained by example, so here's a minimal, but +complete, module that defines a new type named :class:`Custom` inside a C +extension module :mod:`custom`: + +.. note:: + What we're showing here is the traditional way of defining *static* + extension types. It should be adequate for most uses. The C API also + allows defining heap-allocated extension types using the + :c:func:`PyType_FromSpec` function, which isn't covered in this tutorial. + +.. literalinclude:: ../includes/custom.c + +Now that's quite a bit to take in at once, but hopefully bits will seem familiar +from the previous chapter. This file defines three things: + +#. What a :class:`Custom` **object** contains: this is the ``CustomObject`` + struct, which is allocated once for each :class:`Custom` instance. +#. How the :class:`Custom` **type** behaves: this is the ``CustomType`` struct, + which defines a set of flags and function pointers that the interpreter + inspects when specific operations are requested. +#. How to initialize the :mod:`custom` module: this is the ``PyInit_custom`` + function and the associated ``custommodule`` struct. + +The first bit is:: + + typedef struct { + PyObject_HEAD + } CustomObject; + +This is what a Custom object will contain. ``PyObject_HEAD`` is mandatory +at the start of each object struct and defines a field called ``ob_base`` +of type :c:type:`PyObject`, containing a pointer to a type object and a +reference count (these can be accessed using the macros :c:macro:`Py_REFCNT` +and :c:macro:`Py_TYPE` respectively). The reason for the macro is to +abstract away the layout and to enable additional fields in debug builds. + +.. note:: + There is no semicolon above after the :c:macro:`PyObject_HEAD` macro. + Be wary of adding one by accident: some compilers will complain. + +Of course, objects generally store additional data besides the standard +``PyObject_HEAD`` boilerplate; for example, here is the definition for +standard Python floats:: + + typedef struct { + PyObject_HEAD + double ob_fval; + } PyFloatObject; + +The second bit is the definition of the type object. :: + + static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_new = PyType_GenericNew, + }; + +.. note:: + We recommend using C99-style designated initializers as above, to + avoid listing all the :c:type:`PyTypeObject` fields that you don't care + about and also to avoid caring about the fields' declaration order. + +The actual definition of :c:type:`PyTypeObject` in :file:`object.h` has +many more :ref:`fields ` than the definition above. The +remaining fields will be filled with zeros by the C compiler, and it's +common practice to not specify them explicitly unless you need them. + +We're going to pick it apart, one field at a time:: + + PyVarObject_HEAD_INIT(NULL, 0) + +This line is mandatory boilerplate to initialize the ``ob_base`` +field mentioned above. :: + + .tp_name = "custom.Custom", + +The name of our type. This will appear in the default textual representation of +our objects and in some error messages, for example: + +.. code-block:: python + + >>> "" + custom.Custom() + Traceback (most recent call last): + File "", line 1, in + TypeError: can only concatenate str (not "custom.Custom") to str + +Note that the name is a dotted name that includes both the module name and the +name of the type within the module. The module in this case is :mod:`custom` and +the type is :class:`Custom`, so we set the type name to :class:`custom.Custom`. +Using the real dotted import path is important to make your type compatible +with the :mod:`pydoc` and :mod:`pickle` modules. :: + + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + +This is so that Python knows how much memory to allocate when creating +new :class:`Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is +only used for variable-sized objects and should otherwise be zero. + +.. note:: + + If you want your type to be subclassable from Python, and your type has the same + :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple + inheritance. A Python subclass of your type will have to list your type first + in its :attr:`~class.__bases__`, or else it will not be able to call your type's + :meth:`__new__` method without getting an error. You can avoid this problem by + ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its + base type does. Most of the time, this will be true anyway, because either your + base type will be :class:`object`, or else you will be adding data members to + your base type, and therefore increasing its size. + +We set the class flags to :const:`Py_TPFLAGS_DEFAULT`. :: + + .tp_flags = Py_TPFLAGS_DEFAULT, + +All types should include this constant in their flags. It enables all of the +members defined until at least Python 3.3. If you need further members, +you will need to OR the corresponding flags. + +We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: + + .tp_doc = "Custom objects", + +To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` +handler. This is the equivalent of the Python method :meth:`__new__`, but +has to be specified explicitly. In this case, we can just use the default +implementation provided by the API function :c:func:`PyType_GenericNew`. :: + + .tp_new = PyType_GenericNew, + +Everything else in the file should be familiar, except for some code in +:c:func:`PyInit_custom`:: + + if (PyType_Ready(&CustomType) < 0) + return; + +This initializes the :class:`Custom` type, filling in a number of members +to the appropriate default values, including :attr:`ob_type` that we initially +set to *NULL*. :: + + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + +This adds the type to the module dictionary. This allows us to create +:class:`Custom` instances by calling the :class:`Custom` class: + +.. code-block:: python + + >>> import custom + >>> mycustom = custom.Custom() + +That's it! All that remains is to build it; put the above code in a file called +:file:`custom.c` and: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[Extension("custom", ["custom.c"])]) + +in a file called :file:`setup.py`; then typing + +.. code-block:: shell-session + + $ python setup.py build + +at a shell should produce a file :file:`custom.so` in a subdirectory; move to +that directory and fire up Python --- you should be able to ``import custom`` and +play around with Custom objects. + +That wasn't so hard, was it? + +Of course, the current Custom type is pretty uninteresting. It has no data and +doesn't do anything. It can't even be subclassed. + +.. note:: + While this documentation showcases the standard :mod:`distutils` module + for building C extensions, it is recommended in real-world use cases to + use the newer and better-maintained ``setuptools`` library. Documentation + on how to do this is out of scope for this document and can be found in + the `Python Packaging User's Guide `_. + + +Adding data and methods to the Basic example +============================================ + +Let's extend the basic example to add some data and methods. Let's also make +the type usable as a base class. We'll create a new module, :mod:`custom2` that +adds these capabilities: + +.. literalinclude:: ../includes/custom2.c + + +This version of the module has a number of changes. + +We've added an extra include:: + + #include + +This include provides declarations that we use to handle attributes, as +described a bit later. + +The :class:`Custom` type now has three data attributes in its C struct, +*first*, *last*, and *number*. The *first* and *last* variables are Python +strings containing first and last names. The *number* attribute is a C integer. + +The object structure is updated accordingly:: + + typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; + } CustomObject; + +Because we now have data to manage, we have to be more careful about object +allocation and deallocation. At a minimum, we need a deallocation method:: + + static void + Custom_dealloc(CustomObject *self) + { + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member:: + + .tp_dealloc = (destructor) Custom_dealloc, + +This method first clears the reference counts of the two Python attributes. +:c:func:`Py_XDECREF` correctly handles the case where its argument is +*NULL* (which might happen here if ``tp_new`` failed midway). It then +calls the :c:member:`~PyTypeObject.tp_free` member of the object's type +(computed by ``Py_TYPE(self)``) to free the object's memory. Note that +the object's type might not be :class:`CustomType`, because the object may +be an instance of a subclass. + +.. note:: + The explicit cast to ``destructor`` above is needed because we defined + ``Custom_dealloc`` to take a ``CustomObject *`` argument, but the ``tp_dealloc`` + function pointer expects to receive a ``PyObject *`` argument. Otherwise, + the compiler will emit a warning. This is object-oriented polymorphism, + in C! + +We want to make sure that the first and last names are initialized to empty +strings, so we provide a ``tp_new`` implementation:: + + static PyObject * + Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; + } + +and install it in the :c:member:`~PyTypeObject.tp_new` member:: + + .tp_new = Custom_new, + +The ``tp_new`` handler is responsible for creating (as opposed to initializing) +objects of the type. It is exposed in Python as the :meth:`__new__` method. +It is not required to define a ``tp_new`` member, and indeed many extension +types will simply reuse :c:func:`PyType_GenericNew` as done in the first +version of the ``Custom`` type above. In this case, we use the ``tp_new`` +handler to initialize the ``first`` and ``last`` attributes to non-*NULL* +default values. + +``tp_new`` is passed the type being instantiated (not necessarily ``CustomType``, +if a subclass is instantiated) and any arguments passed when the type was +called, and is expected to return the instance created. ``tp_new`` handlers +always accept positional and keyword arguments, but they often ignore the +arguments, leaving the argument handling to initializer (a.k.a. ``tp_init`` +in C or ``__init__`` in Python) methods. + +.. note:: + ``tp_new`` shouldn't call ``tp_init`` explicitly, as the interpreter + will do it itself. + +The ``tp_new`` implementation calls the :c:member:`~PyTypeObject.tp_alloc` +slot to allocate memory:: + + self = (CustomObject *) type->tp_alloc(type, 0); + +Since memory allocation may fail, we must check the :c:member:`~PyTypeObject.tp_alloc` +result against *NULL* before proceeding. + +.. note:: + We didn't fill the :c:member:`~PyTypeObject.tp_alloc` slot ourselves. Rather + :c:func:`PyType_Ready` fills it for us by inheriting it from our base class, + which is :class:`object` by default. Most types use the default allocation + strategy. + +.. note:: + If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one + that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), + you must *not* try to determine what method to call using method resolution + order at runtime. Always statically determine what type you are going to + call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via + ``type->tp_base->tp_new``. If you do not do this, Python subclasses of your + type that also inherit from other Python-defined classes may not work correctly. + (Specifically, you may not be able to create instances of such subclasses + without getting a :exc:`TypeError`.) + +We also define an initialization function which accepts arguments to provide +initial values for our instance:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; + } + +by filling the :c:member:`~PyTypeObject.tp_init` slot. :: + + .tp_init = (initproc) Custom_init, + +The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the +:meth:`__init__` method. It is used to initialize an object after it's +created. Initializers always accept positional and keyword arguments, +and they should return either ``0`` on success or ``-1`` on error. + +Unlike the ``tp_new`` handler, there is no guarantee that ``tp_init`` +is called at all (for example, the :mod:`pickle` module by default +doesn't call :meth:`__init__` on unpickled instances). It can also be +called multiple times. Anyone can call the :meth:`__init__` method on +our objects. For this reason, we have to be extra careful when assigning +the new attribute values. We might be tempted, for example to assign the +``first`` member like this:: + + if (first) { + Py_XDECREF(self->first); + Py_INCREF(first); + self->first = first; + } + +But this would be risky. Our type doesn't restrict the type of the +``first`` member, so it could be any kind of object. It could have a +destructor that causes code to be executed that tries to access the +``first`` member; or that destructor could release the +:term:`Global interpreter Lock` and let arbitrary code run in other +threads that accesses and modifies our object. + +To be paranoid and protect ourselves against this possibility, we almost +always reassign members before decrementing their reference counts. When +don't we have to do this? + +* when we absolutely know that the reference count is greater than 1; + +* when we know that deallocation of the object [#]_ will neither release + the :term:`GIL` nor cause any calls back into our type's code; + +* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc` + handler on a type which doesn't support cyclic garbage collection [#]_. + +We want to expose our instance variables as attributes. There are a +number of ways to do that. The simplest way is to define member definitions:: + + static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +and put the definitions in the :c:member:`~PyTypeObject.tp_members` slot:: + + .tp_members = Custom_members, + +Each member definition has a member name, type, offset, access flags and +documentation string. See the :ref:`Generic-Attribute-Management` section +below for details. + +A disadvantage of this approach is that it doesn't provide a way to restrict the +types of objects that can be assigned to the Python attributes. We expect the +first and last names to be strings, but any Python objects can be assigned. +Further, the attributes can be deleted, setting the C pointers to *NULL*. Even +though we can make sure the members are initialized to non-*NULL* values, the +members can be set to *NULL* if the attributes are deleted. + +We define a single method, :meth:`Custom.name()`, that outputs the objects name as the +concatenation of the first and last names. :: + + static PyObject * + Custom_name(CustomObject *self) + { + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); + } + +The method is implemented as a C function that takes a :class:`Custom` (or +:class:`Custom` subclass) instance as the first argument. Methods always take an +instance as the first argument. Methods often take positional and keyword +arguments as well, but in this case we don't take any and don't need to accept +a positional argument tuple or keyword argument dictionary. This method is +equivalent to the Python method: + +.. code-block:: python + + def name(self): + return "%s %s" % (self.first, self.last) + +Note that we have to check for the possibility that our :attr:`first` and +:attr:`last` members are *NULL*. This is because they can be deleted, in which +case they are set to *NULL*. It would be better to prevent deletion of these +attributes and to restrict the attribute values to be strings. We'll see how to +do that in the next section. + +Now that we've defined the method, we need to create an array of method +definitions:: + + static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ + }; + +(note that we used the :const:`METH_NOARGS` flag to indicate that the method +is expecting no arguments other than *self*) + +and assign it to the :c:member:`~PyTypeObject.tp_methods` slot:: + + .tp_methods = Custom_methods, + +Finally, we'll make our type usable as a base class for subclassing. We've +written our methods carefully so far so that they don't make any assumptions +about the type of the object being created or used, so all we need to do is +to add the :const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +We rename :c:func:`PyInit_custom` to :c:func:`PyInit_custom2`, update the +module name in the :c:type:`PyModuleDef` struct, and update the full class +name in the :c:type:`PyTypeObject` struct. + +Finally, we update our :file:`setup.py` file to build the new module: + +.. code-block:: python + + from distutils.core import setup, Extension + setup(name="custom", version="1.0", + ext_modules=[ + Extension("custom", ["custom.c"]), + Extension("custom2", ["custom2.c"]), + ]) + + +Providing finer control over data attributes +============================================ + +In this section, we'll provide finer control over how the :attr:`first` and +:attr:`last` attributes are set in the :class:`Custom` example. In the previous +version of our module, the instance variables :attr:`first` and :attr:`last` +could be set to non-string values or even deleted. We want to make sure that +these attributes always contain strings. + +.. literalinclude:: ../includes/custom3.c + + +To provide greater control, over the :attr:`first` and :attr:`last` attributes, +we'll use custom getter and setter functions. Here are the functions for +getting and setting the :attr:`first` attribute:: + + static PyObject * + Custom_getfirst(CustomObject *self, void *closure) + { + Py_INCREF(self->first); + return self->first; + } + + static int + Custom_setfirst(CustomObject *self, PyObject *value, void *closure) + { + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; + } + +The getter function is passed a :class:`Custom` object and a "closure", which is +a void pointer. In this case, the closure is ignored. (The closure supports an +advanced usage in which definition data is passed to the getter and setter. This +could, for example, be used to allow a single set of getter and setter functions +that decide the attribute to get or set based on data in the closure.) + +The setter function is passed the :class:`Custom` object, the new value, and the +closure. The new value may be *NULL*, in which case the attribute is being +deleted. In our setter, we raise an error if the attribute is deleted or if its +new value is not a string. + +We create an array of :c:type:`PyGetSetDef` structures:: + + static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ + }; + +and register it in the :c:member:`~PyTypeObject.tp_getset` slot:: + + .tp_getset = Custom_getsetters, + +The last item in a :c:type:`PyGetSetDef` structure is the "closure" mentioned +above. In this case, we aren't using a closure, so we just pass *NULL*. + +We also remove the member definitions for these attributes:: + + static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ + }; + +We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only +allow strings [#]_ to be passed:: + + static int + Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; + } + +With these changes, we can assure that the ``first`` and ``last`` members are +never *NULL* so we can remove checks for *NULL* values in almost all cases. +This means that most of the :c:func:`Py_XDECREF` calls can be converted to +:c:func:`Py_DECREF` calls. The only place we can't change these calls is in +the ``tp_dealloc`` implementation, where there is the possibility that the +initialization of these members failed in ``tp_new``. + +We also rename the module initialization function and module name in the +initialization function, as we did before, and we add an extra definition to the +:file:`setup.py` file. + + +Supporting cyclic garbage collection +==================================== + +Python has a :term:`cyclic garbage collector (GC) ` that +can identify unneeded objects even when their reference counts are not zero. +This can happen when objects are involved in cycles. For example, consider: + +.. code-block:: python + + >>> l = [] + >>> l.append(l) + >>> del l + +In this example, we create a list that contains itself. When we delete it, it +still has a reference from itself. Its reference count doesn't drop to zero. +Fortunately, Python's cyclic garbage collector will eventually figure out that +the list is garbage and free it. + +In the second version of the :class:`Custom` example, we allowed any kind of +object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. +Besides, in the second and third versions, we allowed subclassing +:class:`Custom`, and subclasses may add arbitrary attributes. For any of +those two reasons, :class:`Custom` objects can participate in cycles: + +.. code-block:: python + + >>> import custom3 + >>> class Derived(custom3.Custom): pass + ... + >>> n = Derived() + >>> n.some_attribute = n + +To allow a :class:`Custom` instance participating in a reference cycle to +be properly detected and collected by the cyclic GC, our :class:`Custom` type +needs to fill two additional slots and to enable a flag that enables these slots: + +.. literalinclude:: ../includes/custom4.c + + +First, the traversal method lets the cyclic GC know about subobjects that could +participate in cycles:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + int vret; + if (self->first) { + vret = visit(self->first, arg); + if (vret != 0) + return vret; + } + if (self->last) { + vret = visit(self->last, arg); + if (vret != 0) + return vret; + } + return 0; + } + +For each subobject that can participate in cycles, we need to call the +:c:func:`visit` function, which is passed to the traversal method. The +:c:func:`visit` function takes as arguments the subobject and the extra argument +*arg* passed to the traversal method. It returns an integer value that must be +returned if it is non-zero. + +Python provides a :c:func:`Py_VISIT` macro that automates calling visit +functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate +in ``Custom_traverse``:: + + static int + Custom_traverse(CustomObject *self, visitproc visit, void *arg) + { + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; + } + +.. note:: + The :c:member:`~PyTypeObject.tp_traverse` implementation must name its + arguments exactly *visit* and *arg* in order to use :c:func:`Py_VISIT`. + +Second, we need to provide a method for clearing any subobjects that can +participate in cycles:: + + static int + Custom_clear(CustomObject *self) + { + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; + } + +Notice the use of the :c:func:`Py_CLEAR` macro. It is the recommended and safe +way to clear data attributes of arbitrary types while decrementing +their reference counts. If you were to call :c:func:`Py_XDECREF` instead +on the attribute before setting it to *NULL*, there is a possibility +that the attribute's destructor would call back into code that reads the +attribute again (*especially* if there is a reference cycle). + +.. note:: + You could emulate :c:func:`Py_CLEAR` by writing:: + + PyObject *tmp; + tmp = self->first; + self->first = NULL; + Py_XDECREF(tmp); + + Nevertheless, it is much easier and less error-prone to always + use :c:func:`Py_CLEAR` when deleting an attribute. Don't + try to micro-optimize at the expense of robustness! + +The deallocator ``Custom_dealloc`` may call arbitrary code when clearing +attributes. It means the circular GC can be triggered inside the function. +Since the GC assumes reference count is not zero, we need to untrack the object +from the GC by calling :c:func:`PyObject_GC_UnTrack` before clearing members. +Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack` +and ``Custom_clear``:: + + static void + Custom_dealloc(CustomObject *self) + { + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); + } + +Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + +That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or +:c:member:`~PyTypeObject.tp_free` handlers, we'd need to modify them for cyclic +garbage collection. Most extensions will use the versions automatically provided. + + +Subclassing other types +======================= + +It is possible to create new extension types that are derived from existing +types. It is easiest to inherit from the built in types, since an extension can +easily use the :c:type:`PyTypeObject` it needs. It can be difficult to share +these :c:type:`PyTypeObject` structures between extension modules. + +In this example we will create a :class:`SubList` type that inherits from the +built-in :class:`list` type. The new type will be completely compatible with +regular lists, but will have an additional :meth:`increment` method that +increases an internal counter: + +.. code-block:: python + + >>> import sublist + >>> s = sublist.SubList(range(3)) + >>> s.extend(s) + >>> print(len(s)) + 6 + >>> print(s.increment()) + 1 + >>> print(s.increment()) + 2 + +.. literalinclude:: ../includes/sublist.c + + +As you can see, the source code closely resembles the :class:`Custom` examples in +previous sections. We will break down the main differences between them. :: + + typedef struct { + PyListObject list; + int state; + } SubListObject; + +The primary difference for derived type objects is that the base type's +object structure must be the first value. The base type will already include +the :c:func:`PyObject_HEAD` at the beginning of its structure. + +When a Python object is a :class:`SubList` instance, its ``PyObject *`` pointer +can be safely cast to both ``PyListObject *`` and ``SubListObject *``:: + + static int + SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) + { + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; + } + +We see above how to call through to the :attr:`__init__` method of the base +type. + +This pattern is important when writing a type with custom +:c:member:`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_dealloc` +members. The :c:member:`~PyTypeObject.tp_new` handler should not actually +create the memory for the object with its :c:member:`~PyTypeObject.tp_alloc`, +but let the base class handle it by calling its own :c:member:`~PyTypeObject.tp_new`. + +The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject.tp_base` +specifying the type's concrete base class. Due to cross-platform compiler +issues, you can't fill that field directly with a reference to +:c:type:`PyList_Type`; it should be done later in the module initialization +function:: + + PyMODINIT_FUNC + PyInit_sublist(void) + { + PyObject* m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; + } + +Before calling :c:func:`PyType_Ready`, the type structure must have the +:c:member:`~PyTypeObject.tp_base` slot filled in. When we are deriving an +existing type, it is not necessary to fill out the :c:member:`~PyTypeObject.tp_alloc` +slot with :c:func:`PyType_GenericNew` -- the allocation function from the base +type will be inherited. + +After that, calling :c:func:`PyType_Ready` and adding the type object to the +module is the same as with the basic :class:`Custom` examples. + + +.. rubric:: Footnotes + +.. [#] This is true when we know that the object is a basic type, like a string or a + float. + +.. [#] We relied on this in the :c:member:`~PyTypeObject.tp_dealloc` handler + in this example, because our type doesn't support garbage collection. + +.. [#] We now know that the first and last members are strings, so perhaps we + could be less careful about decrementing their reference counts, however, + we accept instances of string subclasses. Even though deallocating normal + strings won't call back into our objects, we can't guarantee that deallocating + an instance of a string subclass won't call back into our objects. + +.. [#] Also, even with our attributes restricted to strings instances, the user + could pass arbitrary :class:`str` subclasses and therefore still create + reference cycles. diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c new file mode 100644 index 000000000000..fb2c7b2a430e --- /dev/null +++ b/Doc/includes/custom.c @@ -0,0 +1,39 @@ +#include + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ +} CustomObject; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = PyType_GenericNew, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c new file mode 100644 index 000000000000..51ab4b80d680 --- /dev/null +++ b/Doc/includes/custom2.c @@ -0,0 +1,132 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, + "last name"}, + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom2.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom2", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom2(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c new file mode 100644 index 000000000000..09e87355b91a --- /dev/null +++ b/Doc/includes/custom3.c @@ -0,0 +1,183 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static void +Custom_dealloc(CustomObject *self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + tmp = self->last; + Py_INCREF(value); + self->last = value; + Py_DECREF(tmp); + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom3.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom3", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom3(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c new file mode 100644 index 000000000000..0994d8fda0e5 --- /dev/null +++ b/Doc/includes/custom4.c @@ -0,0 +1,197 @@ +#include +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} CustomObject; + +static int +Custom_traverse(CustomObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->first); + Py_VISIT(self->last); + return 0; +} + +static int +Custom_clear(CustomObject *self) +{ + Py_CLEAR(self->first); + Py_CLEAR(self->last); + return 0; +} + +static void +Custom_dealloc(CustomObject *self) +{ + PyObject_GC_UnTrack(self); + Custom_clear(self); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CustomObject *self; + self = (CustomObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyUnicode_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + self->last = PyUnicode_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + self->number = 0; + } + return (PyObject *) self; +} + +static int +Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"first", "last", "number", NULL}; + PyObject *first = NULL, *last = NULL, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + return 0; +} + +static PyMemberDef Custom_members[] = { + {"number", T_INT, offsetof(CustomObject, number), 0, + "custom number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_getfirst(CustomObject *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->first); + self->first = value; + return 0; +} + +static PyObject * +Custom_getlast(CustomObject *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Custom_setlast(CustomObject *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + Py_INCREF(value); + Py_CLEAR(self->last); + self->last = value; + return 0; +} + +static PyGetSetDef Custom_getsetters[] = { + {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + "first name", NULL}, + {"last", (getter) Custom_getlast, (setter) Custom_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromFormat("%S %S", self->first, self->last); +} + +static PyMethodDef Custom_methods[] = { + {"name", (PyCFunction) Custom_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject CustomType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "custom4.Custom", + .tp_doc = "Custom objects", + .tp_basicsize = sizeof(CustomObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_new = Custom_new, + .tp_init = (initproc) Custom_init, + .tp_dealloc = (destructor) Custom_dealloc, + .tp_traverse = (traverseproc) Custom_traverse, + .tp_clear = (inquiry) Custom_clear, + .tp_members = Custom_members, + .tp_methods = Custom_methods, + .tp_getset = Custom_getsetters, +}; + +static PyModuleDef custommodule = { + PyModuleDef_HEAD_INIT, + .m_name = "custom4", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_custom4(void) +{ + PyObject *m; + if (PyType_Ready(&CustomType) < 0) + return NULL; + + m = PyModule_Create(&custommodule); + if (m == NULL) + return NULL; + + Py_INCREF(&CustomType); + PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + return m; +} diff --git a/Doc/includes/noddy.c b/Doc/includes/noddy.c deleted file mode 100644 index 19a27a89e883..000000000000 --- a/Doc/includes/noddy.c +++ /dev/null @@ -1,56 +0,0 @@ -#include - -typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ -} noddy_NoddyObject; - -static PyTypeObject noddy_NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(noddy_NoddyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Noddy objects", /* tp_doc */ -}; - -static PyModuleDef noddymodule = { - PyModuleDef_HEAD_INIT, - "noddy", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy(void) -{ - PyObject* m; - - noddy_NoddyType.tp_new = PyType_GenericNew; - if (PyType_Ready(&noddy_NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&noddy_NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); - return m; -} diff --git a/Doc/includes/noddy2.c b/Doc/includes/noddy2.c deleted file mode 100644 index 964155845fee..000000000000 --- a/Doc/includes/noddy2.c +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy2module = { - PyModuleDef_HEAD_INIT, - "noddy2", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy2(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy2module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy3.c b/Doc/includes/noddy3.c deleted file mode 100644 index 8a5a753ca439..000000000000 --- a/Doc/includes/noddy3.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static void -Noddy_dealloc(Noddy* self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - - return 0; -} - -static PyMemberDef Noddy_members[] = { - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_getfirst(Noddy *self, void *closure) -{ - Py_INCREF(self->first); - return self->first; -} - -static int -Noddy_setfirst(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a string"); - return -1; - } - - Py_DECREF(self->first); - Py_INCREF(value); - self->first = value; - - return 0; -} - -static PyObject * -Noddy_getlast(Noddy *self, void *closure) -{ - Py_INCREF(self->last); - return self->last; -} - -static int -Noddy_setlast(Noddy *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); - return -1; - } - - if (! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The last attribute value must be a string"); - return -1; - } - - Py_DECREF(self->last); - Py_INCREF(value); - self->last = value; - - return 0; -} - -static PyGetSetDef Noddy_getseters[] = { - {"first", - (getter)Noddy_getfirst, (setter)Noddy_setfirst, - "first name", - NULL}, - {"last", - (getter)Noddy_getlast, (setter)Noddy_setlast, - "last name", - NULL}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Noddy objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - Noddy_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy3module = { - PyModuleDef_HEAD_INIT, - "noddy3", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy3(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy3module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/noddy4.c b/Doc/includes/noddy4.c deleted file mode 100644 index 08ba4c3d91a0..000000000000 --- a/Doc/includes/noddy4.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; - PyObject *last; - int number; -} Noddy; - -static int -Noddy_traverse(Noddy *self, visitproc visit, void *arg) -{ - int vret; - - if (self->first) { - vret = visit(self->first, arg); - if (vret != 0) - return vret; - } - if (self->last) { - vret = visit(self->last, arg); - if (vret != 0) - return vret; - } - - return 0; -} - -static int -Noddy_clear(Noddy *self) -{ - PyObject *tmp; - - tmp = self->first; - self->first = NULL; - Py_XDECREF(tmp); - - tmp = self->last; - self->last = NULL; - Py_XDECREF(tmp); - - return 0; -} - -static void -Noddy_dealloc(Noddy* self) -{ - PyObject_GC_UnTrack(self); - Noddy_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject * -Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Noddy *self; - - self = (Noddy *)type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - - self->number = 0; - } - - return (PyObject *)self; -} - -static int -Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) -{ - PyObject *first=NULL, *last=NULL, *tmp; - - static char *kwlist[] = {"first", "last", "number", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - - return 0; -} - - -static PyMemberDef Noddy_members[] = { - {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, - "last name"}, - {"number", T_INT, offsetof(Noddy, number), 0, - "noddy number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Noddy_name(Noddy* self) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Noddy_methods[] = { - {"name", (PyCFunction)Noddy_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "noddy.Noddy", /* tp_name */ - sizeof(Noddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Noddy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /* tp_flags */ - "Noddy objects", /* tp_doc */ - (traverseproc)Noddy_traverse, /* tp_traverse */ - (inquiry)Noddy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Noddy_methods, /* tp_methods */ - Noddy_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Noddy_init, /* tp_init */ - 0, /* tp_alloc */ - Noddy_new, /* tp_new */ -}; - -static PyModuleDef noddy4module = { - PyModuleDef_HEAD_INIT, - "noddy4", - "Example module that creates an extension type.", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_noddy4(void) -{ - PyObject* m; - - if (PyType_Ready(&NoddyType) < 0) - return NULL; - - m = PyModule_Create(&noddy4module); - if (m == NULL) - return NULL; - - Py_INCREF(&NoddyType); - PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); - return m; -} diff --git a/Doc/includes/shoddy.c b/Doc/includes/shoddy.c deleted file mode 100644 index 0c6d412b3c4c..000000000000 --- a/Doc/includes/shoddy.c +++ /dev/null @@ -1,99 +0,0 @@ -#include - -typedef struct { - PyListObject list; - int state; -} Shoddy; - - -static PyObject * -Shoddy_increment(Shoddy *self, PyObject *unused) -{ - self->state++; - return PyLong_FromLong(self->state); -} - - -static PyMethodDef Shoddy_methods[] = { - {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, - PyDoc_STR("increment state counter")}, - {NULL, NULL}, -}; - -static int -Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) -{ - if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; -} - - -static PyTypeObject ShoddyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "shoddy.Shoddy", /* tp_name */ - sizeof(Shoddy), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Shoddy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Shoddy_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -static PyModuleDef shoddymodule = { - PyModuleDef_HEAD_INIT, - "shoddy", - "Shoddy module", - -1, - NULL, NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_shoddy(void) -{ - PyObject *m; - - ShoddyType.tp_base = &PyList_Type; - if (PyType_Ready(&ShoddyType) < 0) - return NULL; - - m = PyModule_Create(&shoddymodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ShoddyType); - PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); - return m; -} diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c new file mode 100644 index 000000000000..376dddfac09c --- /dev/null +++ b/Doc/includes/sublist.c @@ -0,0 +1,63 @@ +#include + +typedef struct { + PyListObject list; + int state; +} SubListObject; + +static PyObject * +SubList_increment(SubListObject *self, PyObject *unused) +{ + self->state++; + return PyLong_FromLong(self->state); +} + +static PyMethodDef SubList_methods[] = { + {"increment", (PyCFunction) SubList_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL}, +}; + +static int +SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + +static PyTypeObject SubListType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "sublist.SubList", + .tp_doc = "SubList objects", + .tp_basicsize = sizeof(SubListObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_init = (initproc) SubList_init, + .tp_methods = SubList_methods, +}; + +static PyModuleDef sublistmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "sublist", + .m_doc = "Example module that creates an extension type.", + .m_size = -1, +}; + +PyMODINIT_FUNC +PyInit_sublist(void) +{ + PyObject *m; + SubListType.tp_base = &PyList_Type; + if (PyType_Ready(&SubListType) < 0) + return NULL; + + m = PyModule_Create(&sublistmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&SubListType); + PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + return m; +} diff --git a/Doc/includes/test.py b/Doc/includes/test.py index 9e9d4a67121c..09ebe3fec0bd 100644 --- a/Doc/includes/test.py +++ b/Doc/includes/test.py @@ -1,181 +1,168 @@ -"""Test module for the noddy examples +"""Test module for the custom examples -Noddy 1: +Custom 1: ->>> import noddy ->>> n1 = noddy.Noddy() ->>> n2 = noddy.Noddy() ->>> del n1 ->>> del n2 +>>> import custom +>>> c1 = custom.Custom() +>>> c2 = custom.Custom() +>>> del c1 +>>> del c2 -Noddy 2 +Custom 2 ->>> import noddy2 ->>> n1 = noddy2.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom2 +>>> c1 = custom2.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first +>>> c1.name() Traceback (most recent call last): ... AttributeError: first ->>> n1.first +>>> c1.first Traceback (most recent call last): ... AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() +>>> c1.first = 42 +>>> c1.name() '42 tell' ->>> n2 = noddy2.Noddy() ->>> n2.name() +>>> c2 = custom2.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first +>>> del c2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.first +>>> c2.first Traceback (most recent call last): ... AttributeError: first ->>> n2.name() +>>> c2.name() Traceback (most recent call last): File "", line 1, in ? AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy2.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom2.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 3 +Custom 3 ->>> import noddy3 ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1 = noddy3.Noddy('jim', 'fulton', 42) ->>> n1.name() +>>> import custom3 +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1 = custom3.Custom('jim', 'fulton', 42) +>>> c1.name() 'jim fulton' ->>> del n1.first +>>> del c1.first Traceback (most recent call last): File "", line 1, in ? TypeError: Cannot delete the first attribute ->>> n1.first = 42 +>>> c1.first = 42 Traceback (most recent call last): File "", line 1, in ? TypeError: The first attribute value must be a string ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n2 = noddy3.Noddy() ->>> n3 = noddy3.Noddy('jim', 'fulton', 'waaa') +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> c2 = custom3.Custom() +>>> n3 = custom3.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): File "", line 1, in ? -TypeError: an integer is required ->>> del n1 ->>> del n2 +TypeError: an integer is required (got type str) +>>> del c1 +>>> del c2 -Noddy 4 +Custom 4 ->>> import noddy4 ->>> n1 = noddy4.Noddy('jim', 'fulton', 42) ->>> n1.first +>>> import custom4 +>>> c1 = custom4.Custom('jim', 'fulton', 42) +>>> c1.first 'jim' ->>> n1.last +>>> c1.last 'fulton' ->>> n1.number +>>> c1.number 42 ->>> n1.name() +>>> c1.name() 'jim fulton' ->>> n1.first = 'will' ->>> n1.name() +>>> c1.first = 'will' +>>> c1.name() 'will fulton' ->>> n1.last = 'tell' ->>> n1.name() +>>> c1.last = 'tell' +>>> c1.name() 'will tell' ->>> del n1.first ->>> n1.name() +>>> del c1.first Traceback (most recent call last): ... -AttributeError: first ->>> n1.first -Traceback (most recent call last): -... -AttributeError: first ->>> n1.first = 'drew' ->>> n1.first +TypeError: Cannot delete the first attribute +>>> c1.name() +'will tell' +>>> c1.first = 'drew' +>>> c1.first 'drew' ->>> del n1.number +>>> del c1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> n1.number=2 ->>> n1.number +>>> c1.number=2 +>>> c1.number 2 ->>> n1.first = 42 ->>> n1.name() -'42 tell' ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2 = noddy4.Noddy() ->>> n2.name() +>>> c1.first = 42 +Traceback (most recent call last): +... +TypeError: The first attribute value must be a string +>>> c1.name() +'drew tell' +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2 = custom4.Custom() +>>> c2.name() ' ' ->>> n2.first +>>> c2.first '' ->>> n2.last +>>> c2.last '' ->>> del n2.first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.first -Traceback (most recent call last): -... -AttributeError: first ->>> n2.name() -Traceback (most recent call last): - File "", line 1, in ? -AttributeError: first ->>> n2.number +>>> c2.number 0 ->>> n3 = noddy4.Noddy('jim', 'fulton', 'waaa') +>>> n3 = custom4.Custom('jim', 'fulton', 'waaa') Traceback (most recent call last): - File "", line 1, in ? -TypeError: an integer is required +... +TypeError: an integer is required (got type str) Test cyclic gc(?) @@ -183,15 +170,14 @@ >>> import gc >>> gc.disable() ->>> x = [] ->>> l = [x] ->>> n2.first = l ->>> n2.first -[[]] ->>> l.append(n2) ->>> del l ->>> del n1 ->>> del n2 +>>> class Subclass(custom4.Custom): pass +... +>>> s = Subclass() +>>> s.cycle = [s] +>>> s.cycle.append(s.cycle) +>>> x = object() +>>> s.x = x +>>> del s >>> sys.getrefcount(x) 3 >>> ignore = gc.collect() diff --git a/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst new file mode 100644 index 000000000000..bdee48ba0314 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-04-01-21-03-41.bpo-33201.aa8Lkl.rst @@ -0,0 +1 @@ +Modernize documentation for writing C extension types. From webhook-mailer at python.org Sat Apr 7 16:09:50 2018 From: webhook-mailer at python.org (Alex Gaynor) Date: Sat, 07 Apr 2018 20:09:50 -0000 Subject: [Python-checkins] bpo-29613: Added support for SameSite cookies (GH-6413) Message-ID: https://github.com/python/cpython/commit/c87eb09d2e3783b0b5dc0d7cb304050cbcc86ad3 commit: c87eb09d2e3783b0b5dc0d7cb304050cbcc86ad3 branch: master author: Alex Gaynor committer: GitHub date: 2018-04-07T16:09:42-04:00 summary: bpo-29613: Added support for SameSite cookies (GH-6413) * bpo-29613: Added support for SameSite cookies Implemented as per draft https://tools.ietf.org/html/draft-west-first-party-cookies-07 * Documented SameSite And suggestions by members. * Missing space :( * Updated News and contributors * Added version changed details. * Fix in documentation * fix in documentation * Clubbed test cases for same attribute into single. * Updates * Style nits + expand tests * review feedback files: A Misc/NEWS.d/next/Library/2018-04-07-13-49-39.bpo-29613.r6FDnB.rst M Doc/library/http.cookies.rst M Lib/http/cookies.py M Lib/test/test_http_cookies.py M Misc/ACKS diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst index fb8317ad59e6..f3457a0cdc7b 100644 --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -137,11 +137,16 @@ Morsel Objects * ``secure`` * ``version`` * ``httponly`` + * ``samesite`` The attribute :attr:`httponly` specifies that the cookie is only transferred in HTTP requests, and is not accessible through JavaScript. This is intended to mitigate some forms of cross-site scripting. + The attribute :attr:`samesite` specifies that the browser is not allowed to + send the cookie along with cross-site requests. This helps to mitigate CSRF + attacks. Valid values for this attribute are "Strict" and "Lax". + The keys are case-insensitive and their default value is ``''``. .. versionchanged:: 3.5 @@ -153,6 +158,9 @@ Morsel Objects :attr:`~Morsel.coded_value` are read-only. Use :meth:`~Morsel.set` for setting them. + .. versionchanged:: 3.8 + Added support for the :attr:`samesite` attribute. + .. attribute:: Morsel.value diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 7e0259ee32e4..4a44db8475ea 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -281,6 +281,7 @@ class Morsel(dict): "secure" : "Secure", "httponly" : "HttpOnly", "version" : "Version", + "samesite" : "SameSite", } _flags = {'secure', 'httponly'} diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index 2ff690243fc3..447f883390fd 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -121,6 +121,19 @@ def test_set_secure_httponly_attrs(self): self.assertEqual(C.output(), 'Set-Cookie: Customer="WILE_E_COYOTE"; HttpOnly; Secure') + def test_samesite_attrs(self): + samesite_values = ['Strict', 'Lax', 'strict', 'lax'] + for val in samesite_values: + with self.subTest(val=val): + C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') + C['Customer']['samesite'] = val + self.assertEqual(C.output(), + 'Set-Cookie: Customer="WILE_E_COYOTE"; SameSite=%s' % val) + + C = cookies.SimpleCookie() + C.load('Customer="WILL_E_COYOTE"; SameSite=%s' % val) + self.assertEqual(C['Customer']['samesite'], val) + def test_secure_httponly_false_if_not_present(self): C = cookies.SimpleCookie() C.load('eggs=scrambled; Path=/bacon') diff --git a/Misc/ACKS b/Misc/ACKS index b951446bab7b..8b2931f0bd35 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1461,6 +1461,7 @@ Varun Sharma Daniel Shaulov Vlad Shcherbina Justin Sheehy +Akash Shende Charlie Shepherd Bruce Sherwood Alexander Shigin diff --git a/Misc/NEWS.d/next/Library/2018-04-07-13-49-39.bpo-29613.r6FDnB.rst b/Misc/NEWS.d/next/Library/2018-04-07-13-49-39.bpo-29613.r6FDnB.rst new file mode 100644 index 000000000000..a679cd91194f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-07-13-49-39.bpo-29613.r6FDnB.rst @@ -0,0 +1,2 @@ +Added support for the ``SameSite`` cookie flag to the ``http.cookies`` +module. From solipsis at pitrou.net Sun Apr 8 05:11:41 2018 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 08 Apr 2018 09:11:41 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=7 Message-ID: <20180408091141.1.F16451E0AFF2D5A9@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [-7, 8, 0] memory blocks, sum=1 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_spawn leaked [2, 0, 0] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflog5oWdTv', '--timeout', '7200'] From webhook-mailer at python.org Sun Apr 8 11:44:25 2018 From: webhook-mailer at python.org (Raymond Hettinger) Date: Sun, 08 Apr 2018 15:44:25 -0000 Subject: [Python-checkins] Add a prepend() recipe to teach a chain() idiom (GH-6415) Message-ID: https://github.com/python/cpython/commit/9265dd72e5ec1cfa5fcdb5be8ebffe1d9994bd4b commit: 9265dd72e5ec1cfa5fcdb5be8ebffe1d9994bd4b branch: master author: Raymond Hettinger committer: GitHub date: 2018-04-08T08:44:20-07:00 summary: Add a prepend() recipe to teach a chain() idiom (GH-6415) files: M Doc/library/itertools.rst M Lib/test/test_itertools.py diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index a5a5356a9a1f..959424ff9143 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -688,6 +688,11 @@ which incur interpreter overhead. "Return first n items of the iterable as a list" return list(islice(iterable, n)) + def prepend(value, iterator): + "Prepend a single value in front of an iterator" + # prepend(1, [2, 3, 4]) -> 1 2 3 4 + return chain([value], iterator) + def tabulate(function, start=0): "Return function(0), function(1), ..." return map(function, count(start)) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index effd7f0e21be..cbbb4c4f71d3 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -2198,6 +2198,11 @@ def test_permutations_sizeof(self): ... "Return first n items of the iterable as a list" ... return list(islice(iterable, n)) +>>> def prepend(value, iterator): +... "Prepend a single value in front of an iterator" +... # prepend(1, [2, 3, 4]) -> 1 2 3 4 +... return chain([value], iterator) + >>> def enumerate(iterable, start=0): ... return zip(count(start), iterable) @@ -2350,6 +2355,9 @@ def test_permutations_sizeof(self): >>> take(10, count()) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +>>> list(prepend(1, [2, 3, 4])) +[1, 2, 3, 4] + >>> list(enumerate('abc')) [(0, 'a'), (1, 'b'), (2, 'c')] From webhook-mailer at python.org Sun Apr 8 12:18:08 2018 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Sun, 08 Apr 2018 16:18:08 -0000 Subject: [Python-checkins] Improve highlighting of some code blocks. (GH-6401) Message-ID: https://github.com/python/cpython/commit/46936d5a71d1683dbd8ddb6d7f39aab50ecfec50 commit: 46936d5a71d1683dbd8ddb6d7f39aab50ecfec50 branch: master author: Serhiy Storchaka committer: GitHub date: 2018-04-08T19:18:04+03:00 summary: Improve highlighting of some code blocks. (GH-6401) files: M Doc/distutils/configfile.rst M Doc/distutils/packageindex.rst M Doc/extending/embedding.rst M Doc/extending/extending.rst M Doc/extending/newtypes_tutorial.rst M Doc/faq/library.rst M Doc/faq/windows.rst M Doc/howto/argparse.rst M Doc/howto/clinic.rst M Doc/howto/instrumentation.rst M Doc/howto/logging-cookbook.rst M Doc/howto/logging.rst M Doc/howto/regex.rst M Doc/howto/unicode.rst M Doc/howto/urllib2.rst M Doc/install/index.rst M Doc/library/faulthandler.rst M Doc/library/json.rst M Doc/library/logging.config.rst M Doc/library/logging.rst M Doc/library/site.rst M Doc/library/timeit.rst M Doc/library/tokenize.rst M Doc/library/zipapp.rst M Doc/tutorial/appendix.rst M Doc/using/cmdline.rst M Doc/using/unix.rst M Doc/using/windows.rst M Doc/whatsnew/3.6.rst diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst index 21f1acdace5f..cd10a7fdf315 100644 --- a/Doc/distutils/configfile.rst +++ b/Doc/distutils/configfile.rst @@ -36,7 +36,9 @@ consequences: * installers can override anything in :file:`setup.cfg` using the command-line options to :file:`setup.py` -The basic syntax of the configuration file is simple:: +The basic syntax of the configuration file is simple: + +.. code-block:: ini [command] option=value @@ -51,9 +53,11 @@ option values can be split across multiple lines simply by indenting the continuation lines. You can find out the list of options supported by a particular command with the -universal :option:`!--help` option, e.g. :: +universal :option:`!--help` option, e.g. + +.. code-block:: shell-session - > python setup.py --help build_ext + $ python setup.py --help build_ext [...] Options for 'build_ext' command: --build-lib (-b) directory for compiled extension modules @@ -75,14 +79,18 @@ For example, say you want your extensions to be built "in-place"---that is, you have an extension :mod:`pkg.ext`, and you want the compiled extension file (:file:`ext.so` on Unix, say) to be put in the same source directory as your pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`!--inplace` option on the command-line to ensure this:: +:option:`!--inplace` option on the command-line to ensure this: + +.. code-block:: sh python setup.py build_ext --inplace But this requires that you always specify the :command:`build_ext` command explicitly, and remember to provide :option:`!--inplace`. An easier way is to "set and forget" this option, by encoding it in :file:`setup.cfg`, the -configuration file for this distribution:: +configuration file for this distribution: + +.. code-block:: ini [build_ext] inplace=1 @@ -103,7 +111,9 @@ information comes from the setup script, and some is automatically generated by the Distutils (such as the list of files installed). But some of it has to be supplied as options to :command:`bdist_rpm`, which would be very tedious to do on the command-line for every run. Hence, here is a snippet from the Distutils' -own :file:`setup.cfg`:: +own :file:`setup.cfg`: + +.. code-block:: ini [bdist_rpm] release = 1 diff --git a/Doc/distutils/packageindex.rst b/Doc/distutils/packageindex.rst index 44556e3df9c5..086e14eb255a 100644 --- a/Doc/distutils/packageindex.rst +++ b/Doc/distutils/packageindex.rst @@ -156,7 +156,9 @@ The :command:`register` and :command:`upload` commands both check for the existence of a :file:`.pypirc` file at the location :file:`$HOME/.pypirc`. If this file exists, the command uses the username, password, and repository URL configured in the file. The format of a :file:`.pypirc` file is as -follows:: +follows: + +.. code-block:: ini [distutils] index-servers = @@ -179,7 +181,9 @@ Each section describing a repository defines three variables: will be prompt to type it when needed. If you want to define another server a new section can be created and -listed in the *index-servers* variable:: +listed in the *index-servers* variable: + +.. code-block:: ini [distutils] index-servers = diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index ab2f61614afc..7e4fc19db83b 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -323,7 +323,7 @@ options. In this case, the :mod:`sysconfig` module is a useful tool to programmatically extract the configuration values that you will want to combine together. For example: -.. code-block:: python +.. code-block:: pycon >>> import sysconfig >>> sysconfig.get_config_var('LIBS') diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index e02f7837b69e..82b689e064c1 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -43,7 +43,9 @@ Let's create an extension module called ``spam`` (the favorite food of Monty Python fans...) and let's say we want to create a Python interface to the C library function :c:func:`system` [#]_. This function takes a null-terminated character string as argument and returns an integer. We want this function to -be callable from Python as follows:: +be callable from Python as follows: + +.. code-block:: pycon >>> import spam >>> status = spam.system("ls -l") @@ -439,7 +441,9 @@ part of the Python interpreter, you will have to change the configuration setup and rebuild the interpreter. Luckily, this is very simple on Unix: just place your file (:file:`spammodule.c` for example) in the :file:`Modules/` directory of an unpacked source distribution, add a line to the file -:file:`Modules/Setup.local` describing your file:: +:file:`Modules/Setup.local` describing your file: + +.. code-block:: sh spam spammodule.o @@ -450,7 +454,9 @@ subdirectory, but then you must first rebuild :file:`Makefile` there by running :file:`Setup` file.) If your module requires additional libraries to link with, these can be listed -on the line in the configuration file as well, for instance:: +on the line in the configuration file as well, for instance: + +.. code-block:: sh spam spammodule.o -lX11 diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 5e05cf693652..ac48637bbee9 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -117,7 +117,7 @@ field mentioned above. :: The name of our type. This will appear in the default textual representation of our objects and in some error messages, for example: -.. code-block:: python +.. code-block:: pycon >>> "" + custom.Custom() Traceback (most recent call last): @@ -183,7 +183,7 @@ set to *NULL*. :: This adds the type to the module dictionary. This allows us to create :class:`Custom` instances by calling the :class:`Custom` class: -.. code-block:: python +.. code-block:: pycon >>> import custom >>> mycustom = custom.Custom() @@ -655,7 +655,7 @@ Python has a :term:`cyclic garbage collector (GC) ` that can identify unneeded objects even when their reference counts are not zero. This can happen when objects are involved in cycles. For example, consider: -.. code-block:: python +.. code-block:: pycon >>> l = [] >>> l.append(l) @@ -672,7 +672,7 @@ Besides, in the second and third versions, we allowed subclassing :class:`Custom`, and subclasses may add arbitrary attributes. For any of those two reasons, :class:`Custom` objects can participate in cycles: -.. code-block:: python +.. code-block:: pycon >>> import custom3 >>> class Derived(custom3.Custom): pass @@ -796,7 +796,7 @@ built-in :class:`list` type. The new type will be completely compatible with regular lists, but will have an additional :meth:`increment` method that increases an internal counter: -.. code-block:: python +.. code-block:: pycon >>> import sublist >>> s = sublist.SubList(range(3)) diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index f84feadd7802..aec4bf9b85d5 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -74,7 +74,9 @@ interpreter. Occasionally, a user's environment is so full that the :program:`/usr/bin/env` program fails; or there's no env program at all. In that case, you can try the -following hack (due to Alex Rezinsky):: +following hack (due to Alex Rezinsky): + +.. code-block:: sh #! /bin/sh """:" diff --git a/Doc/faq/windows.rst b/Doc/faq/windows.rst index f049bc8387b7..7792cfaa16a1 100644 --- a/Doc/faq/windows.rst +++ b/Doc/faq/windows.rst @@ -1,5 +1,7 @@ :tocdepth: 2 +.. highlightlang:: none + .. _windows-faq: ===================== @@ -39,12 +41,16 @@ or "Command prompt window". Usually you can create such a window from your Start menu; under Windows 7 the menu selection is :menuselection:`Start --> Programs --> Accessories --> Command Prompt`. You should be able to recognize when you have started such a window because you will see a Windows "command -prompt", which usually looks like this:: +prompt", which usually looks like this: + +.. code-block:: doscon C:\> The letter may be different, and there might be other things after it, so you -might just as easily see something like:: +might just as easily see something like: + +.. code-block:: doscon D:\YourName\Projects\Python> @@ -60,11 +66,15 @@ program. So, how do you arrange for the interpreter to handle your Python? First, you need to make sure that your command window recognises the word "python" as an instruction to start the interpreter. If you have opened a command window, you should try entering the command ``python`` and hitting -return:: +return: + +.. code-block:: doscon C:\Users\YourName> python -You should then see something like:: +You should then see something like: + +.. code-block:: pycon Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. @@ -73,7 +83,9 @@ You should then see something like:: You have started the interpreter in "interactive mode". That means you can enter Python statements or expressions interactively and have them executed or evaluated while you wait. This is one of Python's strongest features. Check it -by entering a few expressions of your choice and seeing the results:: +by entering a few expressions of your choice and seeing the results: + +.. code-block:: pycon >>> print("Hello") Hello @@ -317,7 +329,9 @@ present, and ``getch()`` which gets one character without echoing it. How do I emulate os.kill() in Windows? -------------------------------------- -Prior to Python 2.7 and 3.2, to terminate a process, you can use :mod:`ctypes`:: +Prior to Python 2.7 and 3.2, to terminate a process, you can use :mod:`ctypes`: + +.. code-block:: python import ctypes diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index 9d770f5232b4..e78a022b372f 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -24,7 +24,7 @@ Concepts Let's show the sort of functionality that we are going to explore in this introductory tutorial by making use of the :command:`ls` command: -.. code-block:: sh +.. code-block:: shell-session $ ls cpython devguide prog.py pypy rm-unused-function.patch @@ -77,7 +77,7 @@ Let us start with a very simple example which does (almost) nothing:: Following is a result of running the code: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py $ python3 prog.py --help @@ -119,7 +119,7 @@ An example:: And running the code: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py usage: prog.py [-h] echo @@ -164,7 +164,7 @@ by reading the source code. So, let's make it a bit more useful:: And we get: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py -h usage: prog.py [-h] echo @@ -185,7 +185,7 @@ Now, how about doing something even more useful:: Following is a result of running the code: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 Traceback (most recent call last): @@ -206,7 +206,7 @@ give it as strings, unless we tell it otherwise. So, let's tell Following is a result of running the code: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 16 @@ -233,7 +233,7 @@ have a look on how to add optional ones:: And the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py --verbosity 1 verbosity turned on @@ -279,7 +279,7 @@ Let's modify the code accordingly:: And the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py --verbose verbosity turned on @@ -325,7 +325,7 @@ versions of the options. It's quite simple:: And here goes: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py -v verbosity turned on @@ -359,7 +359,7 @@ Our program keeps growing in complexity:: And now the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py usage: prog.py [-h] [-v] square @@ -395,7 +395,7 @@ multiple verbosity values, and actually get to use them:: And the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 16 @@ -429,7 +429,7 @@ Let's fix it by restricting the values the ``--verbosity`` option can accept:: And the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 -v 3 usage: prog.py [-h] [-v {0,1,2}] square @@ -470,7 +470,7 @@ verbosity argument (check the output of ``python --help``):: We have introduced another action, "count", to count the number of occurrences of a specific optional arguments: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 16 @@ -537,7 +537,7 @@ Let's fix:: And this is what it gives: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 -vvv the square of 4 equals 16 @@ -581,7 +581,7 @@ it gets the ``None`` value, and that cannot be compared to an int value And: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 16 @@ -614,7 +614,7 @@ not just squares:: Output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py usage: prog.py [-h] [-v] x y @@ -652,7 +652,7 @@ to display *more* text instead:: Output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 2 16 @@ -695,7 +695,7 @@ which will be the opposite of the ``--verbose`` one:: Our program is now simpler, and we've lost some functionality for the sake of demonstration. Anyways, here's the output: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py 4 2 4^2 == 16 @@ -739,7 +739,7 @@ Note that slight difference in the usage text. Note the ``[-v | -q]``, which tells us that we can either use ``-v`` or ``-q``, but not both at the same time: -.. code-block:: sh +.. code-block:: shell-session $ python3 prog.py --help usage: prog.py [-h] [-v | -q] x y diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index d3c7d668959e..788a0eee2ba1 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -267,12 +267,16 @@ Let's dive in! should get its own line. All the parameter lines should be indented from the function name and the docstring. - The general form of these parameter lines is as follows:: + The general form of these parameter lines is as follows: + + .. code-block:: none name_of_parameter: converter If the parameter has a default value, add that after the - converter:: + converter: + + .. code-block:: none name_of_parameter: converter = default_value @@ -925,13 +929,17 @@ Parameter default values ------------------------ Default values for parameters can be any of a number of values. -At their simplest, they can be string, int, or float literals:: +At their simplest, they can be string, int, or float literals: + +.. code-block:: none foo: str = "abc" bar: int = 123 bat: float = 45.6 -They can also use any of Python's built-in constants:: +They can also use any of Python's built-in constants: + +.. code-block:: none yep: bool = True nope: bool = False @@ -959,7 +967,9 @@ It can be an entire expression, using math operators and looking up attributes on objects. However, this support isn't exactly simple, because of some non-obvious semantics. -Consider the following example:: +Consider the following example: + +.. code-block:: none foo: Py_ssize_t = sys.maxsize - 1 @@ -970,7 +980,9 @@ runtime, when the user asks for the function's signature. What namespace is available when the expression is evaluated? It's evaluated in the context of the module the builtin came from. So, if your module has an -attribute called "``max_widgets``", you may simply use it:: +attribute called "``max_widgets``", you may simply use it: + +.. code-block:: none foo: Py_ssize_t = max_widgets @@ -982,7 +994,9 @@ it's best to restrict yourself to modules that are preloaded by Python itself.) Evaluating default values only at runtime means Argument Clinic can't compute the correct equivalent C default value. So you need to tell it explicitly. When you use an expression, you must also specify the equivalent expression -in C, using the ``c_default`` parameter to the converter:: +in C, using the ``c_default`` parameter to the converter: + +.. code-block:: none foo: Py_ssize_t(c_default="PY_SSIZE_T_MAX - 1") = sys.maxsize - 1 @@ -1359,7 +1373,9 @@ Let's start with defining some terminology: A field, in this context, is a subsection of Clinic's output. For example, the ``#define`` for the ``PyMethodDef`` structure is a field, called ``methoddef_define``. Clinic has seven - different fields it can output per function definition:: + different fields it can output per function definition: + + .. code-block:: none docstring_prototype docstring_definition @@ -1416,7 +1432,9 @@ Let's start with defining some terminology: Clinic defines five new directives that let you reconfigure its output. -The first new directive is ``dump``:: +The first new directive is ``dump``: + +.. code-block:: none dump @@ -1425,7 +1443,9 @@ the current block, and empties it. This only works with ``buffer`` and ``two-pass`` destinations. The second new directive is ``output``. The most basic form of ``output`` -is like this:: +is like this: + +.. code-block:: none output @@ -1433,7 +1453,9 @@ This tells Clinic to output *field* to *destination*. ``output`` also supports a special meta-destination, called ``everything``, which tells Clinic to output *all* fields to that *destination*. -``output`` has a number of other functions:: +``output`` has a number of other functions: + +.. code-block:: none output push output pop @@ -1508,7 +1530,9 @@ preset configurations, as follows: Suppresses the ``impl_prototype``, write the ``docstring_definition`` and ``parser_definition`` to ``buffer``, write everything else to ``block``. -The third new directive is ``destination``:: +The third new directive is ``destination``: + +.. code-block:: none destination [...] @@ -1516,7 +1540,9 @@ This performs an operation on the destination named ``name``. There are two defined subcommands: ``new`` and ``clear``. -The ``new`` subcommand works like this:: +The ``new`` subcommand works like this: + +.. code-block:: none destination new @@ -1564,7 +1590,9 @@ There are five destination types: A two-pass buffer, like the "two-pass" builtin destination above. -The ``clear`` subcommand works like this:: +The ``clear`` subcommand works like this: + +.. code-block:: none destination clear @@ -1572,7 +1600,9 @@ It removes all the accumulated text up to this point in the destination. (I don't know what you'd need this for, but I thought maybe it'd be useful while someone's experimenting.) -The fourth new directive is ``set``:: +The fourth new directive is ``set``: + +.. code-block:: none set line_prefix "string" set line_suffix "string" @@ -1590,7 +1620,9 @@ Both of these support two format strings: Turns into the string ``*/``, the end-comment text sequence for C files. The final new directive is one you shouldn't need to use directly, -called ``preserve``:: +called ``preserve``: + +.. code-block:: none preserve @@ -1638,7 +1670,9 @@ like so:: #endif /* HAVE_FUNCTIONNAME */ Then, remove those three lines from the ``PyMethodDef`` structure, -replacing them with the macro Argument Clinic generated:: +replacing them with the macro Argument Clinic generated: + +.. code-block:: none MODULE_FUNCTIONNAME_METHODDEF diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index b9c51a4a4538..b63c43c81f71 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -254,11 +254,15 @@ and the remainder indicates the call/return hierarchy as the script executes. For a `--enable-shared` build of CPython, the markers are contained within the libpython shared library, and the probe's dotted path needs to reflect this. For -example, this line from the above example:: +example, this line from the above example: + +.. code-block:: none probe process("python").mark("function__entry") { -should instead read:: +should instead read: + +.. code-block:: none probe process("python").library("libpython3.6dm.so.1.0").mark("function__entry") { diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 4d2d052d2917..fdf7874883ee 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -72,7 +72,9 @@ Here is the auxiliary module:: def some_function(): module_logger.info('received a call to "some_function"') -The output looks like this:: +The output looks like this: + +.. code-block:: none 2005-03-23 23:47:11,663 - spam_application - INFO - creating an instance of auxiliary_module.Auxiliary @@ -127,7 +129,9 @@ shows logging from the main (initial) thread and another thread:: if __name__ == '__main__': main() -When run, the script should print something like the following:: +When run, the script should print something like the following: + +.. code-block:: none 0 Thread-1 Hi from myfunc 3 MainThread Hello from main @@ -240,14 +244,18 @@ messages should not. Here's how you can achieve this:: logger2.warning('Jail zesty vixen who grabbed pay from quack.') logger2.error('The five boxing wizards jump quickly.') -When you run this, on the console you will see :: +When you run this, on the console you will see + +.. code-block:: none root : INFO Jackdaws love my big sphinx of quartz. myapp.area1 : INFO How quickly daft jumping zebras vex. myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. myapp.area2 : ERROR The five boxing wizards jump quickly. -and in the file you will see something like :: +and in the file you will see something like + +.. code-block:: none 10-22 22:19 root INFO Jackdaws love my big sphinx of quartz. 10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. @@ -515,7 +523,9 @@ module. Here is a basic working example:: main() First run the server, and then the client. On the client side, nothing is -printed on the console; on the server side, you should see something like:: +printed on the console; on the server side, you should see something like: + +.. code-block:: none About to start TCP server... 59 root INFO Jackdaws love my big sphinx of quartz. @@ -675,7 +685,9 @@ script:: lvlname = logging.getLevelName(lvl) a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') -which, when run, produces something like:: +which, when run, produces something like: + +.. code-block:: none 2010-09-06 22:38:15,292 a.b.c DEBUG IP: 123.231.231.123 User: fred A debug message 2010-09-06 22:38:15,300 a.b.c INFO IP: 192.168.0.1 User: sheila An info message with some parameters @@ -976,7 +988,9 @@ logging package provides a :class:`~handlers.RotatingFileHandler`:: print(filename) The result should be 6 separate files, each with part of the log history for the -application:: +application: + +.. code-block:: none logging_rotatingfile_example.out logging_rotatingfile_example.out.1 @@ -1706,7 +1720,9 @@ which uses JSON to serialise the event in a machine-parseable manner:: logging.basicConfig(level=logging.INFO, format='%(message)s') logging.info(_('message 1', foo='bar', bar='baz', num=123, fnum=123.456)) -If the above script is run, it prints:: +If the above script is run, it prints: + +.. code-block:: none message 1 >>> {"fnum": 123.456, "num": 123, "bar": "baz", "foo": "bar"} @@ -1753,7 +1769,9 @@ as in the following complete example:: if __name__ == '__main__': main() -When the above script is run, it prints:: +When the above script is run, it prints: + +.. code-block:: none message 1 >>> {"snowman": "\u2603", "set_value": [1, 2, 3]} @@ -2083,7 +2101,9 @@ most obvious, but you can provide any callable which returns a This example shows how you can pass configuration data to the callable which constructs the instance, in the form of keyword parameters. When run, the above -script will print:: +script will print: + +.. code-block:: none changed: hello @@ -2150,7 +2170,9 @@ class, as shown in the following example:: if __name__ == '__main__': main() -When run, this produces a file with exactly two lines:: +When run, this produces a file with exactly two lines: + +.. code-block:: none 28/01/2015 07:21:23|INFO|Sample message| 28/01/2015 07:21:23|ERROR|ZeroDivisionError: integer division or modulo by zero|'Traceback (most recent call last):\n File "logtest7.py", line 30, in main\n x = 1 / 0\nZeroDivisionError: integer division or modulo by zero'| @@ -2312,7 +2334,9 @@ Here's the script:: write_line('Calling decorated foo with True') assert decorated_foo(True) -When this script is run, the following output should be observed:: +When this script is run, the following output should be observed: + +.. code-block:: none Calling undecorated foo with False about to log at DEBUG ... @@ -2408,7 +2432,9 @@ the following complete example:: logging.config.dictConfig(LOGGING) logging.warning('The local time is %s', time.asctime()) -When this script is run, it should print something like:: +When this script is run, it should print something like: + +.. code-block:: none 2015-10-17 12:53:29,501 The local time is Sat Oct 17 13:53:29 2015 2015-10-17 13:53:29,501 The local time is Sat Oct 17 13:53:29 2015 diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 4ee68b4747eb..f8b78b618569 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -134,7 +134,9 @@ interpreter, and don't just continue from the session described above:: logging.warning('And this, too') And now if we open the file and look at what we have, we should find the log -messages:: +messages: + +.. code-block:: none DEBUG:root:This message should go to the log file INFO:root:So should this @@ -144,7 +146,9 @@ This example also shows how you can set the logging level which acts as the threshold for tracking. In this case, because we set the threshold to ``DEBUG``, all of the messages were printed. -If you want to set the logging level from a command-line option such as:: +If you want to set the logging level from a command-line option such as: + +.. code-block:: none --log=INFO @@ -208,7 +212,9 @@ could organize logging in it:: def do_something(): logging.info('Doing something') -If you run *myapp.py*, you should see this in *myapp.log*:: +If you run *myapp.py*, you should see this in *myapp.log*: + +.. code-block:: none INFO:root:Started INFO:root:Doing something @@ -258,7 +264,9 @@ specify the format you want to use:: logging.info('So should this') logging.warning('And this, too') -which would print:: +which would print: + +.. code-block:: none DEBUG:This message should appear on the console INFO:So should this @@ -282,7 +290,9 @@ your format string:: logging.basicConfig(format='%(asctime)s %(message)s') logging.warning('is when this event was logged.') -which should print something like this:: +which should print something like this: + +.. code-block:: none 2010-12-12 11:41:42,612 is when this event was logged. @@ -294,7 +304,9 @@ argument to ``basicConfig``, as in this example:: logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.warning('is when this event was logged.') -which would display something like this:: +which would display something like this: + +.. code-block:: none 12/12/2010 11:46:36 AM is when this event was logged. @@ -376,7 +388,9 @@ if no destination is set; and if one is not set, they will set a destination of the console (``sys.stderr``) and a default format for the displayed message before delegating to the root logger to do the actual message output. -The default format set by :func:`basicConfig` for messages is:: +The default format set by :func:`basicConfig` for messages is: + +.. code-block:: none severity:logger name:message @@ -522,7 +536,9 @@ indicator. .. method:: logging.Formatter.__init__(fmt=None, datefmt=None, style='%') If there is no message format string, the default is to use the -raw message. If there is no date format string, the default date format is:: +raw message. If there is no date format string, the default date format is: + +.. code-block:: none %Y-%m-%d %H:%M:%S @@ -628,7 +644,9 @@ the names of the objects:: logger.error('error message') logger.critical('critical message') -Here is the logging.conf file:: +Here is the logging.conf file: + +.. code-block:: ini [loggers] keys=root,simpleExample @@ -713,7 +731,9 @@ construct the dictionary in Python code, receive it in pickled form over a socket, or use whatever approach makes sense for your application. Here's an example of the same configuration as above, in YAML format for -the new dictionary-based approach:: +the new dictionary-based approach: + +.. code-block:: yaml version: 1 formatters: diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index bdf687ee4551..b09f748a9227 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -786,7 +786,9 @@ Frequently you need to obtain more information than just whether the RE matched or not. Regular expressions are often used to dissect strings by writing a RE divided into several subgroups which match different components of interest. For example, an RFC-822 header line is divided into a header name and a value, -separated by a ``':'``, like this:: +separated by a ``':'``, like this: + +.. code-block:: none From: author at example.com User-Agent: Thunderbird 1.5.0.9 (X11/20061227) diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst index 093f4454af1d..be1fefb35a71 100644 --- a/Doc/howto/unicode.rst +++ b/Doc/howto/unicode.rst @@ -30,7 +30,9 @@ spellings such as 'co?perate'.) For a while people just wrote programs that didn't display accents. In the mid-1980s an Apple II BASIC program written by a French speaker -might have lines like these:: +might have lines like these: + +.. code-block:: basic PRINT "MISE A JOUR TERMINEE" PRINT "PARAMETRES ENREGISTRES" diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index c1fd5cf0680d..204a05a61008 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -457,7 +457,9 @@ error code) requesting authentication. This specifies the authentication scheme and a 'realm'. The header looks like: ``WWW-Authenticate: SCHEME realm="REALM"``. -e.g. :: +e.g. + +.. code-block:: none WWW-Authenticate: Basic realm="cPanel Users" diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 0545b8f33d03..92cdf2f11443 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -283,7 +283,9 @@ Windows, choose :menuselection:`Start --> Programs --> Python X.Y --> Python (command line)`. Once the interpreter is started, you type Python code at the prompt. For example, on my Linux system, I type the three Python statements shown below, and get the output as shown, to find out my -:file:`{prefix}` and :file:`{exec-prefix}`:: +:file:`{prefix}` and :file:`{exec-prefix}`: + +.. code-block:: pycon Python 2.4 (#26, Aug 7 2004, 17:19:02) Type "help", "copyright", "credits" or "license" for more information. @@ -622,7 +624,9 @@ parsing your configuration file(s). Obviously, specifying the entire installation scheme every time you install a new module distribution would be very tedious. Thus, you can put these options -into your Distutils config file (see section :ref:`inst-config-files`):: +into your Distutils config file (see section :ref:`inst-config-files`): + +.. code-block:: ini [install] install-base=$HOME @@ -631,7 +635,9 @@ into your Distutils config file (see section :ref:`inst-config-files`):: install-scripts=python/scripts install-data=python/data -or, equivalently, :: +or, equivalently, + +.. code-block:: ini [install] install-base=$HOME/python @@ -718,7 +724,9 @@ A slightly less convenient way is to edit the :file:`site.py` file in Python's standard library, and modify ``sys.path``. :file:`site.py` is automatically imported when the Python interpreter is executed, unless the :option:`-S` switch is supplied to suppress this behaviour. So you could simply edit -:file:`site.py` and add two lines to it:: +:file:`site.py` and add two lines to it: + +.. code-block:: python import sys sys.path.append('/www/python/') @@ -839,7 +847,9 @@ plus a ``global`` section for global options that affect every command. Each section consists of one option per line, specified as ``option=value``. For example, the following is a complete config file that just forces all -commands to run quietly by default:: +commands to run quietly by default: + +.. code-block:: ini [global] verbose=0 @@ -853,7 +863,9 @@ distribution. You could override the default "build base" directory and make the :command:`build\*` commands always forcibly rebuild all files with the -following:: +following: + +.. code-block:: ini [build] build-base=blib diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst index d0c4cd07c571..94ebd87639c5 100644 --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -152,10 +152,10 @@ these functions again each time that the file is replaced. Example ------- -.. highlight:: sh - Example of a segmentation fault on Linux with and without enabling the fault -handler:: +handler: + +.. code-block:: shell-session $ python3 -c "import ctypes; ctypes.string_at(0)" Segmentation fault diff --git a/Doc/library/json.rst b/Doc/library/json.rst index bcad61aeca3b..85798fa2cf72 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -100,9 +100,9 @@ Extending :class:`JSONEncoder`:: ['[2.0', ', 1.0', ']'] -.. highlight:: bash +Using :mod:`json.tool` from the shell to validate and pretty-print: -Using :mod:`json.tool` from the shell to validate and pretty-print:: +.. code-block:: shell-session $ echo '{"json":"obj"}' | python -m json.tool { @@ -113,8 +113,6 @@ Using :mod:`json.tool` from the shell to validate and pretty-print:: See :ref:`json-commandline` for detailed documentation. -.. highlight:: python3 - .. note:: JSON is a subset of `YAML `_ 1.2. The JSON produced by @@ -647,8 +645,6 @@ when serializing Python :class:`int` values of extremely large magnitude, or when serializing instances of "exotic" numerical types such as :class:`decimal.Decimal`. -.. highlight:: bash - .. _json-commandline: Command Line Interface @@ -665,7 +661,9 @@ The :mod:`json.tool` module provides a simple command line interface to validate and pretty-print JSON objects. If the optional ``infile`` and ``outfile`` arguments are not -specified, :attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively:: +specified, :attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively: + +.. code-block:: shell-session $ echo '{"json": "obj"}' | python -m json.tool { @@ -684,7 +682,9 @@ Command line options .. cmdoption:: infile - The JSON file to be validated or pretty-printed:: + The JSON file to be validated or pretty-printed: + + .. code-block:: shell-session $ python -m json.tool mp_films.json [ diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 06378379c331..1f9d7c7f220b 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -538,7 +538,9 @@ target handler, and the system will resolve to the handler from the id. If, however, a user defines a ``my.package.MyHandler`` which has an ``alternate`` handler, the configuration system would not know that the ``alternate`` referred to a handler. To cater for this, a generic -resolution system allows the user to specify:: +resolution system allows the user to specify: + +.. code-block:: yaml handlers: file: @@ -552,7 +554,9 @@ The literal string ``'cfg://handlers.file'`` will be resolved in an analogous way to strings with the ``ext://`` prefix, but looking in the configuration itself rather than the import namespace. The mechanism allows access by dot or by index, in a similar way to -that provided by ``str.format``. Thus, given the following snippet:: +that provided by ``str.format``. Thus, given the following snippet: + +.. code-block:: yaml handlers: email: diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 88f804a074ec..f9eda173ad0d 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -179,7 +179,9 @@ is the module's name in the Python package namespace. You can specify *stack_info* independently of *exc_info*, e.g. to just show how you got to a certain point in your code, even when no exceptions were - raised. The stack frames are printed following a header line which says:: + raised. The stack frames are printed following a header line which says: + + .. code-block:: none Stack (most recent call last): @@ -198,7 +200,9 @@ is the module's name in the Python package namespace. logger = logging.getLogger('tcpserver') logger.warning('Protocol problem: %s', 'connection reset', extra=d) - would print something like :: + would print something like + + .. code-block:: none 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset @@ -939,7 +943,9 @@ functions. You can specify *stack_info* independently of *exc_info*, e.g. to just show how you got to a certain point in your code, even when no exceptions were - raised. The stack frames are printed following a header line which says:: + raised. The stack frames are printed following a header line which says: + + .. code-block:: none Stack (most recent call last): @@ -957,7 +963,9 @@ functions. d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logging.warning('Protocol problem: %s', 'connection reset', extra=d) - would print something like:: + would print something like: + + .. code-block:: none 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset diff --git a/Doc/library/site.rst b/Doc/library/site.rst index ae408133a7ce..0003a7cd8f17 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -222,7 +222,7 @@ Module contents The :mod:`site` module also provides a way to get the user directories from the command line: -.. code-block:: sh +.. code-block:: shell-session $ python3 -m site --user-site /home/user/.local/lib/python3.3/site-packages diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index 8bbadf11608b..d922fd6f32e2 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -25,7 +25,7 @@ Basic Examples The following example shows how the :ref:`timeit-command-line-interface` can be used to compare three different expressions: -.. code-block:: sh +.. code-block:: shell-session $ python3 -m timeit '"-".join(str(n) for n in range(100))' 10000 loops, best of 5: 30.2 usec per loop @@ -264,7 +264,7 @@ Examples It is possible to provide a setup statement that is executed only once at the beginning: -.. code-block:: sh +.. code-block:: shell-session $ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text' 5000000 loops, best of 5: 0.0877 usec per loop @@ -293,7 +293,7 @@ The following examples show how to time expressions that contain multiple lines. Here we compare the cost of using :func:`hasattr` vs. :keyword:`try`/:keyword:`except` to test for missing and present object attributes: -.. code-block:: sh +.. code-block:: shell-session $ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass' 20000 loops, best of 5: 15.7 usec per loop diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst index 02a0428f21bc..4c0a0ceef7dc 100644 --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -218,7 +218,7 @@ will be tokenized to the following output where the first column is the range of the line/column coordinates where the token is found, the second column is the name of the token, and the final column is the value of the token (if any) -.. code-block:: sh +.. code-block:: shell-session $ python -m tokenize hello.py 0,0-0,0: ENCODING 'utf-8' @@ -244,7 +244,7 @@ the name of the token, and the final column is the value of the token (if any) The exact token type names can be displayed using the :option:`-e` option: -.. code-block:: sh +.. code-block:: shell-session $ python -m tokenize -e hello.py 0,0-0,0: ENCODING 'utf-8' diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index a9a61c969c6f..26b0f19fdeb6 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -27,7 +27,7 @@ can be used to create an executable archive from a directory containing Python code. When run, the archive will execute the ``main`` function from the module ``myapp`` in the archive. -.. code-block:: sh +.. code-block:: shell-session $ python -m zipapp myapp -m "myapp:main" $ python myapp.pyz @@ -41,7 +41,7 @@ Command-Line Interface When called as a program from the command line, the following form is used: -.. code-block:: sh +.. code-block:: shell-session $ python -m zipapp source [options] @@ -189,7 +189,7 @@ Examples Pack up a directory into an archive, and run it. -.. code-block:: sh +.. code-block:: shell-session $ python -m zipapp myapp $ python myapp.pyz @@ -203,7 +203,7 @@ The same can be done using the :func:`create_archive` functon:: To make the application directly executable on POSIX, specify an interpreter to use. -.. code-block:: sh +.. code-block:: shell-session $ python -m zipapp myapp -p "/usr/bin/env python" $ ./myapp.pyz @@ -273,7 +273,7 @@ The steps to create a standalone archive are as follows: 2. Install all of your application's dependencies into the ``myapp`` directory, using pip: - .. code-block:: sh + .. code-block:: shell-session $ python -m pip install -r requirements.txt --target myapp @@ -288,7 +288,7 @@ The steps to create a standalone archive are as follows: 4. Package the application using: - .. code-block:: sh + .. code-block:: shell-session $ python -m zipapp -p "interpreter" myapp diff --git a/Doc/tutorial/appendix.rst b/Doc/tutorial/appendix.rst index ffd16aa97a15..241a81203746 100644 --- a/Doc/tutorial/appendix.rst +++ b/Doc/tutorial/appendix.rst @@ -52,7 +52,7 @@ comment in Python. The script can be given an executable mode, or permission, using the :program:`chmod` command. -.. code-block:: bash +.. code-block:: shell-session $ chmod +x myscript.py diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 21ba0b5cebc6..e72dea907580 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -178,11 +178,15 @@ Generic options .. cmdoption:: -V --version - Print the Python version number and exit. Example output could be:: + Print the Python version number and exit. Example output could be: + + .. code-block:: none Python 3.6.0b2+ - When given twice, print more information about the build, like:: + When given twice, print more information about the build, like: + + .. code-block:: none Python 3.6.0b2+ (3.6:84a3c5003510+, Oct 26 2016, 02:33:55) [GCC 6.2.0 20161005] @@ -355,7 +359,9 @@ Miscellaneous options Warning control. Python's warning machinery by default prints warning messages to :data:`sys.stderr`. A typical warning message has the following - form:: + form: + + .. code-block:: none file:line: category: message diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index ac99b699868f..8b392f8a56c4 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -118,7 +118,9 @@ Miscellaneous ============= To easily use Python scripts on Unix, you need to make them executable, -e.g. with :: +e.g. with + +.. code-block:: shell-session $ chmod +x script diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 47d423f42d6e..3bab6fe503ca 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -210,7 +210,9 @@ The options listed above can also be provided in a file named ``unattend.xml`` alongside the executable. This file specifies a list of options and values. When a value is provided as an attribute, it will be converted to a number if possible. Values provided as element text are always left as strings. This -example file sets the same options and the previous example:: +example file sets the same options and the previous example: + +.. code-block:: xml