diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index 7bcf63c0b45896..14f46efc1ec0fe 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -295,17 +295,21 @@ underline, reverse code, or in color. They'll be explained in more detail in the next subsection. -The :meth:`~curses.window.addstr` method takes a Python string or -bytestring as the value to be displayed. The contents of bytestrings -are sent to the terminal as-is. Strings are encoded to bytes using -the value of the window's :attr:`~window.encoding` attribute; this defaults to -the default system encoding as returned by :func:`locale.getencoding`. +The :meth:`~curses.window.addstr` method takes a Python string, bytestring +or :class:`~curses.complexstr` as the value to be displayed. The contents +of bytestrings are sent to the terminal as-is. +On a build without wide-character support strings are encoded +using the value of the window's :attr:`~window.encoding` attribute; +this defaults to the default system encoding +as returned by :func:`locale.getencoding`. The :meth:`~curses.window.addch` methods take a character, which can be -either a string of length 1, a bytestring of length 1, or an integer. +either a string of length 1, a bytestring of length 1, an integer, or a +:class:`~curses.complexchar`. -Constants are provided for extension characters; these constants are -integers greater than 255. For example, :const:`ACS_PLMINUS` is a +/- +Constants are provided for the characters of the terminal's alternate +character set. +For example, :const:`ACS_PLMINUS` is a +/- symbol, and :const:`ACS_ULCORNER` is the upper left corner of a box (handy for drawing borders). You can also use the appropriate Unicode character. @@ -319,11 +323,11 @@ won't be distracting; it can be confusing to have the cursor blinking at some apparently random location. If your application doesn't need a blinking cursor at all, you can -call ``curs_set(False)`` to make it invisible. For compatibility -with older curses versions, there's a ``leaveok(bool)`` function -that's a synonym for :func:`~curses.curs_set`. When *bool* is true, the -curses library will attempt to suppress the flashing cursor, and you -won't need to worry about leaving it in odd locations. +call ``curs_set(False)`` to make it invisible. +The window method :meth:`~curses.window.leaveok` does something different: +when its argument is true, +curses leaves the cursor wherever the last update put it, +instead of moving it back to the window's cursor position. Attributes and Color @@ -364,6 +368,14 @@ could code:: curses.A_REVERSE) stdscr.refresh() +A :class:`~curses.complexchar` carries its attributes and color pair +together with the text of one character cell, +and a :class:`~curses.complexstr` is a run of such cells. +They are what :meth:`~curses.window.in_wch` and +:meth:`~curses.window.in_wchstr` return, +so a part of the screen can be read and written back +with its appearance intact. + The curses library also supports color on those terminals that provide it. The most common such terminal is probably the Linux console, followed by color xterms. @@ -429,40 +441,48 @@ The C curses library offers only very simple input mechanisms. Python's :mod:`curses` module adds a basic text-input widget. (Other libraries such as :pypi:`Urwid` have more extensive collections of widgets.) -There are two methods for getting input from a window: +There are three methods for getting input from a window: -* :meth:`~curses.window.getch` refreshes the screen and then waits for +* :meth:`~curses.window.get_wch` refreshes the screen and then waits for the user to hit a key, displaying the key if :func:`~curses.echo` has been called earlier. You can optionally specify a coordinate to which the cursor should be moved before pausing. -* :meth:`~curses.window.getkey` does the same thing but converts the - integer to a string. Individual characters are returned as - 1-character strings, and special keys such as function keys return - longer strings containing a key name such as ``KEY_UP`` or ``^G``. +* :meth:`~curses.window.getch` does the same thing but returns the code of + the key instead of a character. + With ncurses this is a single byte of the key's encoding in the current + locale, so a character encoded with several bytes takes several calls, + one byte per call. + +* :meth:`~curses.window.getkey` does the same as :meth:`!getch` but returns + a string: + an ordinary key as a 1-character string, + and a special key as its name, such as ``KEY_UP``. It's possible to not wait for the user using the :meth:`~curses.window.nodelay` window method. After ``nodelay(True)``, -:meth:`!getch` and :meth:`!getkey` for the window become -non-blocking. To signal that no input is ready, :meth:`!getch` returns -``curses.ERR`` (a value of -1) and :meth:`!getkey` raises an exception. +the reads for the window become non-blocking. +To signal that no input is ready, +:meth:`!get_wch` and :meth:`!getkey` raise an exception, +and :meth:`!getch` returns ``-1``. There's also a :func:`~curses.halfdelay` function, which can be used to (in -effect) set a timer on each :meth:`!getch`; if no input becomes +effect) set a timer on each read; if no input becomes available within a specified delay (measured in tenths of a second), -curses raises an exception. +the read fails the same way. -The :meth:`!getch` method returns an integer; if it's between 0 and 255, it -represents the ASCII code of the key pressed. Values greater than 255 are -special keys such as Page Up, Home, or the cursor keys. You can compare the -value returned to constants such as :const:`curses.KEY_PPAGE`, +Special keys such as Page Up, Home, or the cursor keys are returned by all +three as one of the :ref:`KEY_* constants `, +all larger than 255. +You can compare the value returned to constants such as +:const:`curses.KEY_PPAGE`, :const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`. The main loop of your program may look something like this:: while True: - c = stdscr.getch() - if c == ord('p'): + c = stdscr.get_wch() + if c == 'p': PrintDocument() - elif c == ord('q'): + elif c == 'q': break # Exit the while loop elif c == curses.KEY_HOME: x = y = 0 @@ -474,16 +494,17 @@ conversion functions that take either integer or 1-character-string arguments and return the same type. For example, :func:`curses.ascii.ctrl` returns the control character corresponding to its argument. -There's also a method to retrieve an entire string, -:meth:`~curses.window.getstr`. It isn't used very often, because its +There's also a method to retrieve an entire line, +:meth:`~curses.window.get_wstr`. It isn't used very often, because its functionality is quite limited; the only editing keys available are -the backspace key and the Enter key, which terminates the string. It -can optionally be limited to a fixed number of characters. :: +the erase and kill characters, and the Enter key, which terminates the line. +It can optionally be limited to a fixed number of characters; +:meth:`~curses.window.getstr` returns a bytes object instead. :: curses.echo() # Enable echoing of characters - # Get a 15-character string, with the cursor on the top line - s = stdscr.getstr(0,0, 15) + # Get a line of at most 15 characters, with the cursor on the top line + s = stdscr.get_wstr(0,0, 15) The :mod:`curses.textpad` module supplies a text box that supports an Emacs-like set of keybindings. Various methods of the diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst index b5caf5502d0e1c..417611307577fd 100644 --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -6,59 +6,69 @@ -------------- -The :mod:`!atexit` module defines functions to register and unregister cleanup -functions. Functions thus registered are automatically executed upon normal -interpreter termination. :mod:`!atexit` runs these functions in the *reverse* -order in which they were registered; if you register ``A``, ``B``, and ``C``, -at interpreter termination time they will be run in the order ``C``, ``B``, -``A``. - -**Note:** The functions registered via this module are not called when the +The :mod:`!atexit` module defines functions to register and unregister +:dfn:`exit handlers`: functions that are automatically executed +"at exit", that is, upon normal program termination (for instance, +if :func:`sys.exit` is called or the main module's execution completes) +or, more generally, upon :term:`interpreter shutdown`. + +At exit, all registered exit handlers are called +in the *reverse* order in which they were registered. +If you register ``A``, ``B``, and ``C``, at interpreter shutdown time they +will be run in the order ``C``, ``B``, ``A``. +The assumption is that lower level modules will normally be imported before +higher level modules and thus must be cleaned up later. + +If an exception is raised during execution of an exit handler, a traceback is +printed (unless :exc:`SystemExit` is raised) and the exception information is +saved. After all exit handlers have had a chance to run, the last exception to +be raised is re-raised. + +In programs that use multiple interpreters, each interpreter has its own stack +of exit handlers, which are executed when the interpreter shuts down +(for example, with :meth:`concurrent.interpreters.Interpreter.close` or the +C API :c:func:`Py_EndInterpreter`). +Registration functions in this module only affect the interpreter they are +called from. + +**Note:** Exit handlers are not called when the program is killed by a signal not handled by Python, when a Python fatal internal error is detected, or when :func:`os._exit` is called. **Note:** The effect of registering or unregistering functions from within a cleanup function is undefined. -.. versionchanged:: 3.7 - When used with C-API subinterpreters, registered functions - are local to the interpreter they were registered in. +.. warning:: + When writing exit handlers, especially in C API extensions, keep in mind + that other exit handlers may still run arbitrary Python code after you + clean up. + Such code should succeed or fail with an exception, rather than crash. -.. function:: register(func, *args, **kwargs) +.. versionchanged:: 3.12 + Attempts to start a new thread or :func:`os.fork` a new process + in an exit handler now leads to :exc:`RuntimeError`. + Previously, this could cause race conditions between the main Python + runtime thread freeing thread states while internal :mod:`threading` + routines or the new process try to use that state, which could lead to + crashes rather than clean shutdown. - Register *func* as a function to be executed at termination. Any optional - arguments that are to be passed to *func* must be passed as arguments to - :func:`register`. It is possible to register the same function and arguments - more than once. +.. versionchanged:: 3.7 + When used with subinterpreters, registered functions + are local to the interpreter they were registered in. - At normal program termination (for instance, if :func:`sys.exit` is called or - the main module's execution completes), all functions registered are called in - last in, first out order. The assumption is that lower level modules will - normally be imported before higher level modules and thus must be cleaned up - later. +.. function:: register(func, *args, **kwargs) - If an exception is raised during execution of the exit handlers, a traceback is - printed (unless :exc:`SystemExit` is raised) and the exception information is - saved. After all exit handlers have had a chance to run, the last exception to - be raised is re-raised. + Register *func* as an exit handler. + Any optional arguments that are to be passed to *func* must be passed as + arguments to :func:`register`. + It is possible to register the same function and arguments more than once. This function returns *func*, which makes it possible to use it as a decorator. - .. warning:: - Starting new threads or calling :func:`os.fork` from a registered - function can lead to race condition between the main Python - runtime thread freeing thread states while internal :mod:`threading` - routines or the new process try to use that state. This can lead to - crashes rather than clean shutdown. - - .. versionchanged:: 3.12 - Attempts to start a new thread or :func:`os.fork` a new process - in a registered function now leads to :exc:`RuntimeError`. - .. function:: unregister(func) - Remove *func* from the list of functions to be run at interpreter shutdown. + Remove *func* from the list of exit handlers. :func:`unregister` silently does nothing if *func* was not previously registered. If *func* has been registered more than once, every occurrence of that function in the :mod:`!atexit` call stack will be removed. Equality diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 858371f927f4fa..bcf2ef47d48898 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -2002,7 +2002,8 @@ Other .. attribute:: window.encoding - Encoding used to encode method arguments (Unicode strings and characters). + Encoding used to encode the string arguments of the methods and to decode + their results on a build without wide-character support. The encoding attribute is inherited from the parent window when a subwindow is created, for example with :meth:`window.subwin`. By default, current locale encoding is used (see :func:`locale.getencoding`). diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 3ca63d1d026135..39caee4f89016b 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -485,6 +485,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is a Python generator function. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_GENERATOR` flag. + .. versionchanged:: 3.13 Functions wrapped in :func:`functools.partialmethod` now return ``True`` if the wrapped function is a Python generator function. @@ -507,6 +511,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is a :term:`coroutine function`. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_COROUTINE` flag. + .. versionchanged:: 3.12 Sync functions marked with :func:`markcoroutinefunction` now return ``True``. @@ -581,6 +589,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is an :term:`asynchronous generator` function. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_ASYNC_GENERATOR` flag. + .. versionchanged:: 3.13 Functions wrapped in :func:`functools.partialmethod` now return ``True`` if the wrapped function is a :term:`asynchronous generator` function. diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 7cc0c33fda353c..52fedb00a940c9 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -290,9 +290,10 @@ same issues as the :meth:`WeakKeyDictionary.keyrefs` method. from an object's :meth:`~object.__del__` method or a weak reference's callback. - When the program exits, each remaining live finalizer is called - unless its :attr:`atexit` attribute has been set to false. They - are called in reverse order of creation. + When the program exits (or more generally, at :term:`interpreter shutdown`), + each remaining live finalizer is called unless its :attr:`atexit` attribute + has been set to false. + They are called in reverse order of creation. A finalizer will never invoke its callback during the later part of the :term:`interpreter shutdown` when module globals are liable to have @@ -321,9 +322,9 @@ same issues as the :meth:`WeakKeyDictionary.keyrefs` method. .. attribute:: atexit - A writable boolean property which by default is true. When the - program exits, it calls all remaining live finalizers for which - :attr:`.atexit` is true. They are called in reverse order of + A writable boolean property which by default is true. At + :term:`interpreter shutdown`, all remaining live finalizers for which + :attr:`.atexit` is true are called in reverse order of creation. .. note:: diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index ec272a076c902b..7948b2ed78f4d0 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -15,7 +15,7 @@ for parsing and creating XML data. This module will use a fast implementation whenever available. .. deprecated:: 3.3 - The :mod:`!xml.etree.cElementTree` module is deprecated. + The :mod:`!xml.etree.cElementTree` alias of this module is deprecated. .. note:: diff --git a/Lib/inspect.py b/Lib/inspect.py index c52469e63861a2..3683f8c3fd5330 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -298,6 +298,8 @@ def _has_code_flag(f, flag): f = functools._unwrap_partial(f) if not (isfunction(f) or _signature_is_functionlike(f)): return False + # If it's a pure Python function, or an object that is duck type + # of a Python function (Cython and Mock functions, for instance), then: return bool(f.__code__.co_flags & flag) def isgeneratorfunction(obj): @@ -2338,7 +2340,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True, is_duck_function = True else: # If it's not a pure Python function, and not a duck type - # of pure function: + # of pure function (Cython and Mock functions, for instance), then: raise TypeError('{!r} is not a Python function'.format(func)) s = getattr(func, "__text_signature__", None) @@ -2531,7 +2533,7 @@ def _signature_from_callable(obj, *, if isfunction(obj) or _signature_is_functionlike(obj): # If it's a pure Python function, or an object that is duck type - # of a Python function (Cython functions, for instance), then: + # of a Python function (Cython and Mock functions, for instance), then: return _signature_from_function(sigcls, obj, skip_bound_arg=skip_bound_arg, globals=globals, locals=locals, eval_str=eval_str, diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index bb307191dffcc1..4cc9eea1f27214 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -84,6 +84,10 @@ def assertClose(self, x, y, eps=1e-9): # check that relative difference < eps self.assertTrue(abs(x-y)/abs(y) < eps) + def assertSameSign(self, x, y): + if copysign(1., x) != copysign(1., y): + self.fail(f'{x!r} and {y!r} have different signs') + def check_div(self, x, y): """Compute complex z=x*y, and check that z/x==y and z/y==x.""" z = x * y @@ -446,6 +450,63 @@ def test_pow_with_small_integer_exponents(self): self.assertEqual(str(float_pow), str(int_pow)) self.assertEqual(str(complex_pow), str(int_pow)) + # Check that complex numbers with special components + # are correctly handled. + values = [complex(x, y) + for x in [5, -5, +0.0, -0.0, INF, -INF, NAN] + for y in [12, -12, +0.0, -0.0, INF, -INF, NAN]] + for c in values: + with self.subTest(value=c): + self.assertComplexesAreIdentical(c**0, complex(1, +0.0)) + self.assertComplexesAreIdentical(c**1, c) + self.assertComplexesAreIdentical(c**2, c*c) + self.assertComplexesAreIdentical(c**3, c*(c*c)) + self.assertComplexesAreIdentical(c**3, (c*c)*c) + if not c: + continue + for n in range(1, 9): + with self.subTest(exponent=-n): + self.assertComplexesAreIdentical(c**-n, 1/(c**n)) + + # Special cases for complex division. + for x in [+2, -2]: + for y in [+0.0, -0.0]: + c = complex(x, y) + with self.subTest(value=c): + self.assertComplexesAreIdentical(c**-1, complex(1/x, -y)) + c = complex(y, x) + with self.subTest(value=c): + self.assertComplexesAreIdentical(c**-1, complex(y, -1/x)) + for x in [+INF, -INF]: + for y in [+1, -1]: + c = complex(x, y) + with self.subTest(value=c): + self.assertComplexesAreIdentical(c**-1, complex(1/x, -0.0*y)) + self.assertComplexesAreIdentical(c**-2, complex(0.0, -y/x)) + c = complex(y, x) + with self.subTest(value=c): + self.assertComplexesAreIdentical(c**-1, complex(+0.0*y, -1/x)) + self.assertComplexesAreIdentical(c**-2, complex(-0.0, -y/x)) + + # Test that zeroes has the same sign as small non-zero values. + eps = 1e-11 + pairs = [(complex(x, y), complex(x, copysign(0.0, y))) + for x in [+1, -1] for y in [+eps, -eps]] + pairs += [(complex(y, x), complex(copysign(0.0, y), x)) + for x in [+1, -1] for y in [+eps, -eps]] + for c1, c2 in pairs: + for n in exponents: + with self.subTest(value=c1, exponent=n): + r1 = c1**n + r2 = c2**n + self.assertClose(r1, r2) + self.assertSameSign(r1.real, r2.real) + self.assertSameSign(r1.imag, r2.imag) + self.assertNotEqual(r1.real, 0.0) + if n != 0: + self.assertNotEqual(r1.imag, 0.0) + self.assertTrue(r2.real == 0.0 or r2.imag == 0.0) + def test_boolcontext(self): for i in range(100): self.assertTrue(complex(random() + 1e-6, random() + 1e-6)) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-15-47-50.gh-issue-117999.Iq4jEG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-15-47-50.gh-issue-117999.Iq4jEG.rst new file mode 100644 index 00000000000000..7c3a9b38372cad --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-15-47-50.gh-issue-117999.Iq4jEG.rst @@ -0,0 +1,2 @@ +Fix calculation of powers of complex numbers. Small integer powers now produce correct sign of zero components. Negative powers of infinite numbers now evaluate to zero instead of NaN. +Powers of infinite numbers no longer raise OverflowError. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 18bbbb618c2b18..f6dedeed981c40 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -720,12 +720,17 @@ _elementtree.Element.append subelement: object(subclass_of='clinic_state()->Element_Type') / +Add *subelement* to the end of this element. + +The new element will appear in document order after the last +existing subelement (or directly after the text, if it's the first +subelement), but before the end tag for this element. [clinic start generated code]*/ static PyObject * _elementtree_Element_append_impl(ElementObject *self, PyTypeObject *cls, PyObject *subelement) -/*[clinic end generated code: output=d00923711ea317fc input=8baf92679f9717b8]*/ +/*[clinic end generated code: output=d00923711ea317fc input=a59ebce98937a372]*/ { elementtreestate *st = get_elementtree_state_by_cls(cls); if (element_add_subelement(st, self, subelement) < 0) @@ -737,11 +742,15 @@ _elementtree_Element_append_impl(ElementObject *self, PyTypeObject *cls, /*[clinic input] _elementtree.Element.clear +Reset element. + +This function removes all subelements, clears all attributes, and +sets the text and tail attributes to None. [clinic start generated code]*/ static PyObject * _elementtree_Element_clear_impl(ElementObject *self) -/*[clinic end generated code: output=8bcd7a51f94cfff6 input=3c719ff94bf45dd6]*/ +/*[clinic end generated code: output=8bcd7a51f94cfff6 input=135c2ab634d0fdf5]*/ { clear_extra(self); @@ -1250,12 +1259,15 @@ _elementtree.Element.extend elements: object / +Append subelements from a sequence. + +*elements* is a sequence with zero or more elements. [clinic start generated code]*/ static PyObject * _elementtree_Element_extend_impl(ElementObject *self, PyTypeObject *cls, PyObject *elements) -/*[clinic end generated code: output=3e86d37fac542216 input=6479b1b5379d09ae]*/ +/*[clinic end generated code: output=3e86d37fac542216 input=401ac1d07e13282b]*/ { PyObject* seq; Py_ssize_t i; @@ -1289,12 +1301,19 @@ _elementtree.Element.find path: object namespaces: object = None +Find first matching element by tag name or path. + +*path* is a string having either an element tag or an XPath, +*namespaces* is an optional mapping from namespace prefix to full +name. + +Return the first matching element, or None if no element was found. [clinic start generated code]*/ static PyObject * _elementtree_Element_find_impl(ElementObject *self, PyTypeObject *cls, PyObject *path, PyObject *namespaces) -/*[clinic end generated code: output=18f77d393c9fef1b input=94df8a83f956acc6]*/ +/*[clinic end generated code: output=18f77d393c9fef1b input=3aec422879a342e1]*/ { elementtreestate *st = get_elementtree_state_by_cls(cls); @@ -1332,13 +1351,23 @@ _elementtree.Element.findtext default: object = None namespaces: object = None +Find text for first matching element by tag name or path. + +*path* is a string having either an element tag or an XPath, +*default* is the value to return if the element was not found, +*namespaces* is an optional mapping from namespace prefix to full +name. + +Return text content of first matching element, or default value if +none was found. Note that if an element is found having no text +content, the empty string is returned. [clinic start generated code]*/ static PyObject * _elementtree_Element_findtext_impl(ElementObject *self, PyTypeObject *cls, PyObject *path, PyObject *default_value, PyObject *namespaces) -/*[clinic end generated code: output=6af7a2d96aac32cb input=32f252099f62a3d2]*/ +/*[clinic end generated code: output=6af7a2d96aac32cb input=64610701f762c4f5]*/ { elementtreestate *st = get_elementtree_state_by_cls(cls); @@ -1381,12 +1410,19 @@ _elementtree.Element.findall path: object namespaces: object = None +Find all matching subelements by tag name or path. + +*path* is a string having either an element tag or an XPath, +*namespaces* is an optional mapping from namespace prefix to full +name. + +Returns list containing all matching elements in document order. [clinic start generated code]*/ static PyObject * _elementtree_Element_findall_impl(ElementObject *self, PyTypeObject *cls, PyObject *path, PyObject *namespaces) -/*[clinic end generated code: output=65e39a1208f3b59e input=7aa0db45673fc9a5]*/ +/*[clinic end generated code: output=65e39a1208f3b59e input=2208ddeb5f1cc7c3]*/ { elementtreestate *st = get_elementtree_state_by_cls(cls); @@ -1427,12 +1463,19 @@ _elementtree.Element.iterfind path: object namespaces: object = None +Find all matching subelements by tag name or path. + +*path* is a string having either an element tag or an XPath, +*namespaces* is an optional mapping from namespace prefix to full +name. + +Return an iterable yielding all matching elements in document order. [clinic start generated code]*/ static PyObject * _elementtree_Element_iterfind_impl(ElementObject *self, PyTypeObject *cls, PyObject *path, PyObject *namespaces) -/*[clinic end generated code: output=be5c3f697a14e676 input=88766875a5c9a88b]*/ +/*[clinic end generated code: output=be5c3f697a14e676 input=00bea06334260582]*/ { PyObject* tag = path; elementtreestate *st = get_elementtree_state_by_cls(cls); @@ -1447,12 +1490,20 @@ _elementtree.Element.get key: object default: object = None +Get element attribute. + +Equivalent to attrib.get, but some implementations may handle this a +bit more efficiently. *key* is what attribute to look for, and +*default* is what to return if the attribute was not found. + +Returns a string containing the attribute value, or the default if +attribute was not found. [clinic start generated code]*/ static PyObject * _elementtree_Element_get_impl(ElementObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=523c614142595d75 input=ee153bbf8cdb246e]*/ +/*[clinic end generated code: output=523c614142595d75 input=332624526ef81a70]*/ { if (self->extra && self->extra->attrib) { PyObject *attrib = Py_NewRef(self->extra->attrib); @@ -1478,12 +1529,24 @@ _elementtree.Element.iter / tag: object = None +Create tree iterator. + +The iterator loops over the element and all subelements in document +order, returning all elements with a matching tag. + +If the tree structure is modified during iteration, new or removed +elements may or may not be included. To get a stable set, use the +list() function on the iterator, and loop over the resulting list. + +*tag* is what tags to look for (default is to return all elements) + +Return an iterator containing all the matching elements. [clinic start generated code]*/ static PyObject * _elementtree_Element_iter_impl(ElementObject *self, PyTypeObject *cls, PyObject *tag) -/*[clinic end generated code: output=bff29dc5d4566c68 input=f6944c48d3f84c58]*/ +/*[clinic end generated code: output=bff29dc5d4566c68 input=e4c542a12e6f9199]*/ { if (PyUnicode_Check(tag)) { if (PyUnicode_GET_LENGTH(tag) == 1 && PyUnicode_READ_CHAR(tag, 0) == '*') @@ -1505,11 +1568,15 @@ _elementtree.Element.itertext cls: defining_class / +Create text iterator. + +The iterator loops over the element and all subelements in document +order, returning all inner text. [clinic start generated code]*/ static PyObject * _elementtree_Element_itertext_impl(ElementObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=fdeb2a3bca0ae063 input=a1ef1f0fc872a586]*/ +/*[clinic end generated code: output=fdeb2a3bca0ae063 input=eaffe70224da7f02]*/ { elementtreestate *st = get_elementtree_state_by_cls(cls); return create_elementiter(st, self, Py_None, 1); @@ -1556,12 +1623,13 @@ _elementtree.Element.insert subelement: object(subclass_of='clinic_state()->Element_Type') / +Insert *subelement* at position *index*. [clinic start generated code]*/ static PyObject * _elementtree_Element_insert_impl(ElementObject *self, Py_ssize_t index, PyObject *subelement) -/*[clinic end generated code: output=990adfef4d424c0b input=9530f4905aa401ca]*/ +/*[clinic end generated code: output=990adfef4d424c0b input=2886a2266de15ed7]*/ { Py_ssize_t i; @@ -1594,11 +1662,14 @@ _elementtree_Element_insert_impl(ElementObject *self, Py_ssize_t index, /*[clinic input] _elementtree.Element.items +Get element attributes as (name, value) pairs. + +Equivalent to attrib.items(). [clinic start generated code]*/ static PyObject * _elementtree_Element_items_impl(ElementObject *self) -/*[clinic end generated code: output=6db2c778ce3f5a4d input=adbe09aaea474447]*/ +/*[clinic end generated code: output=6db2c778ce3f5a4d input=7b5adcd8f774d4e0]*/ { if (!self->extra || !self->extra->attrib) return PyList_New(0); @@ -1609,11 +1680,14 @@ _elementtree_Element_items_impl(ElementObject *self) /*[clinic input] _elementtree.Element.keys +Get attribute names. + +Equivalent to attrib.keys() [clinic start generated code]*/ static PyObject * _elementtree_Element_keys_impl(ElementObject *self) -/*[clinic end generated code: output=bc5bfabbf20eeb3c input=f02caf5b496b5b0b]*/ +/*[clinic end generated code: output=bc5bfabbf20eeb3c input=6d860fbdb565115d]*/ { if (!self->extra || !self->extra->attrib) return PyList_New(0); @@ -1639,12 +1713,19 @@ _elementtree.Element.makeelement attrib: object(subclass_of='&PyDict_Type') / +Create a new element with the same type. + +*tag* is a string containing the element name. *attrib* is a +dictionary containing the element attributes. + +Do not call this method, use the SubElement factory function +instead. [clinic start generated code]*/ static PyObject * _elementtree_Element_makeelement_impl(ElementObject *self, PyTypeObject *cls, PyObject *tag, PyObject *attrib) -/*[clinic end generated code: output=d50bb17a47077d47 input=589829dab92f26e8]*/ +/*[clinic end generated code: output=d50bb17a47077d47 input=02b62a503fa25ae7]*/ { PyObject* elem; @@ -1666,11 +1747,20 @@ _elementtree.Element.remove subelement: object(subclass_of='clinic_state()->Element_Type') / +Remove matching subelement. + +Unlike the find methods, this method compares elements based on +identity, NOT ON tag value or contents. To remove subelements by +other means, the easiest way is to use a list comprehension to +select what elements to keep, and then use slice assignment to +update the parent element. + +ValueError is raised if a matching element could not be found. [clinic start generated code]*/ static PyObject * _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement) -/*[clinic end generated code: output=38fe6c07d6d87d1f input=6133e1d05597d5ee]*/ +/*[clinic end generated code: output=38fe6c07d6d87d1f input=e035af9d920f785b]*/ { Py_ssize_t i; // When iterating over the list of children, we need to check that the @@ -1748,12 +1838,17 @@ _elementtree.Element.set value: object / +Set element attribute. + +Equivalent to attrib[key] = value, but some implementations may +handle this a bit more efficiently. *key* is what attribute to set, +and *value* is the attribute value to set it to. [clinic start generated code]*/ static PyObject * _elementtree_Element_set_impl(ElementObject *self, PyObject *key, PyObject *value) -/*[clinic end generated code: output=fb938806be3c5656 input=1efe90f7d82b3fe9]*/ +/*[clinic end generated code: output=fb938806be3c5656 input=bbaadd68b86636d7]*/ { PyObject* attrib; @@ -2470,6 +2565,24 @@ _elementtree.TreeBuilder.__init__ insert_comments: bool = False insert_pis: bool = False +Generic element structure builder. + +This builder converts a sequence of start, data, and end method +calls to a well-formed element structure. + +You can use this class to build an element structure using a custom +XML parser, or a parser for some other XML-like format. + +*element_factory* is an optional element factory which is called +to create new Element instances, as necessary. + +*comment_factory* is a factory to create comments to be used instead +of the standard factory. If *insert_comments* is false (the +default), comments will not be inserted into the tree. + +*pi_factory* is a factory to create processing instructions to be +used instead of the standard factory. If *insert_pis* is false (the +default), processing instructions will not be inserted into the tree. [clinic start generated code]*/ static int @@ -2478,7 +2591,7 @@ _elementtree_TreeBuilder___init___impl(TreeBuilderObject *self, PyObject *comment_factory, PyObject *pi_factory, int insert_comments, int insert_pis) -/*[clinic end generated code: output=8571d4dcadfdf952 input=ae98a94df20b5cc3]*/ +/*[clinic end generated code: output=8571d4dcadfdf952 input=24fb5a482d93f8e4]*/ { if (element_factory != Py_None) { Py_XSETREF(self->element_factory, Py_NewRef(element_factory)); @@ -3004,11 +3117,12 @@ _elementtree.TreeBuilder.data data: object / +Add text to current element. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_data_impl(TreeBuilderObject *self, PyObject *data) -/*[clinic end generated code: output=dfa02b68f732b8c0 input=a0540c532b284d29]*/ +/*[clinic end generated code: output=dfa02b68f732b8c0 input=679b26864cecbde8]*/ { return treebuilder_handle_data(self, data); } @@ -3019,11 +3133,14 @@ _elementtree.TreeBuilder.end tag: object / +Close and return current Element. + +*tag* is the element name. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_end_impl(TreeBuilderObject *self, PyObject *tag) -/*[clinic end generated code: output=84cb6ca9008ec740 input=22dc3674236f5745]*/ +/*[clinic end generated code: output=84cb6ca9008ec740 input=9d161338282e5fac]*/ { return treebuilder_handle_end(self, tag); } @@ -3034,12 +3151,15 @@ _elementtree.TreeBuilder.comment text: object / +Create a comment using the comment_factory. + +*text* is the text of the comment. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_comment_impl(TreeBuilderObject *self, PyObject *text) -/*[clinic end generated code: output=a555ef39027c3823 input=47e7ebc48ed01dfa]*/ +/*[clinic end generated code: output=a555ef39027c3823 input=b1579b62bb9277e4]*/ { return treebuilder_handle_comment(self, text); } @@ -3051,12 +3171,16 @@ _elementtree.TreeBuilder.pi text: object = None / +Create a processing instruction using the pi_factory. + +*target* is the target name of the processing instruction. *text* is +the data of the processing instruction, or ''. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_pi_impl(TreeBuilderObject *self, PyObject *target, PyObject *text) -/*[clinic end generated code: output=21eb95ec9d04d1d9 input=349342bd79c35570]*/ +/*[clinic end generated code: output=21eb95ec9d04d1d9 input=160b939cc17e4121]*/ { return treebuilder_handle_pi(self, target, text); } @@ -3079,11 +3203,12 @@ treebuilder_done(TreeBuilderObject* self) /*[clinic input] _elementtree.TreeBuilder.close +Flush builder buffers and return toplevel document Element. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_close_impl(TreeBuilderObject *self) -/*[clinic end generated code: output=b441fee3202f61ee input=f7c9c65dc718de14]*/ +/*[clinic end generated code: output=b441fee3202f61ee input=461e8391c6b73c5f]*/ { return treebuilder_done(self); } @@ -3095,12 +3220,16 @@ _elementtree.TreeBuilder.start attrs: object(subclass_of='&PyDict_Type') / +Open new element and return it. + +*tag* is the element name, *attrs* is a dict containing element +attributes. [clinic start generated code]*/ static PyObject * _elementtree_TreeBuilder_start_impl(TreeBuilderObject *self, PyObject *tag, PyObject *attrs) -/*[clinic end generated code: output=e7e9dc2861349411 input=7288e9e38e63b2b6]*/ +/*[clinic end generated code: output=e7e9dc2861349411 input=26cccb49c3b8b12f]*/ { return treebuilder_handle_start(self, tag, attrs); } @@ -3715,18 +3844,25 @@ ignore_attribute_error(PyObject *value) } /*[clinic input] +@permit_long_summary _elementtree.XMLParser.__init__ * target: object = None encoding: str(accept={str, NoneType}) = None +Element structure builder for XML source data based on the expat parser. + +*target* is an optional target object which defaults to an instance +of the standard TreeBuilder class, *encoding* is an optional encoding +string which if given, overrides the encoding specified in the XML +file: http://www.iana.org/assignments/character-sets [clinic start generated code]*/ static int _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, const char *encoding) -/*[clinic end generated code: output=3ae45ec6cdf344e4 input=7e716dd6e4f3e439]*/ +/*[clinic end generated code: output=3ae45ec6cdf344e4 input=43dcd316382c80a2]*/ { self->entity = PyDict_New(); if (!self->entity) @@ -3969,11 +4105,12 @@ expat_parse_large(elementtreestate *st, XMLParserObject *self, /*[clinic input] _elementtree.XMLParser.close +Finish feeding data to parser and return element structure. [clinic start generated code]*/ static PyObject * _elementtree_XMLParser_close_impl(XMLParserObject *self) -/*[clinic end generated code: output=d68d375dd23bc7fb input=ca7909ca78c3abfe]*/ +/*[clinic end generated code: output=d68d375dd23bc7fb input=177603f3353e644f]*/ { /* end feeding data to parser */ @@ -4040,11 +4177,12 @@ _elementtree.XMLParser.feed data: object / +Feed encoded data to parser. [clinic start generated code]*/ static PyObject * _elementtree_XMLParser_feed_impl(XMLParserObject *self, PyObject *data) -/*[clinic end generated code: output=503e6fbf1adf17ab input=fe231b6b8de3ce1f]*/ +/*[clinic end generated code: output=503e6fbf1adf17ab input=9432a189100bc488]*/ { /* feed data to parser */ @@ -4360,7 +4498,27 @@ static PyGetSetDef element_getsetlist[] = { {NULL}, }; +PyDoc_STRVAR(element_doc, +"Element(tag, attrib={}, **extra)\n" +"--\n" +"\n" +"An XML element.\n" +"\n" +"This class is the reference implementation of the Element interface.\n" +"\n" +"An element's length is its number of subelements. That means if you\n" +"want to check if an element is truly empty, you should check BOTH\n" +"its length AND its text attribute.\n" +"\n" +"*tag* is the element name. *attrib* is an optional dictionary\n" +"containing element attributes. *extra* are additional element\n" +"attributes given as keyword arguments.\n" +"\n" +"Example form:\n" +" text...tail"); + static PyType_Slot element_slots[] = { + {Py_tp_doc, (void *)element_doc}, {Py_tp_dealloc, element_dealloc}, {Py_tp_repr, element_repr}, {Py_tp_getattro, PyObject_GenericGetAttr}, @@ -4401,6 +4559,7 @@ static PyMethodDef treebuilder_methods[] = { }; static PyType_Slot treebuilder_slots[] = { + {Py_tp_doc, (void *)_elementtree_TreeBuilder___init____doc__}, {Py_tp_dealloc, treebuilder_dealloc}, {Py_tp_traverse, treebuilder_gc_traverse}, {Py_tp_clear, treebuilder_gc_clear}, @@ -4428,6 +4587,7 @@ static PyMethodDef xmlparser_methods[] = { }; static PyType_Slot xmlparser_slots[] = { + {Py_tp_doc, (void *)_elementtree_XMLParser___init____doc__}, {Py_tp_dealloc, xmlparser_dealloc}, {Py_tp_traverse, xmlparser_gc_traverse}, {Py_tp_clear, xmlparser_gc_clear}, diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h index c9e77a4c2b92d8..a39e738ec538b6 100644 --- a/Modules/clinic/_elementtree.c.h +++ b/Modules/clinic/_elementtree.c.h @@ -12,7 +12,12 @@ preserve PyDoc_STRVAR(_elementtree_Element_append__doc__, "append($self, subelement, /)\n" "--\n" -"\n"); +"\n" +"Add *subelement* to the end of this element.\n" +"\n" +"The new element will appear in document order after the last\n" +"existing subelement (or directly after the text, if it\'s the first\n" +"subelement), but before the end tag for this element."); #define _ELEMENTTREE_ELEMENT_APPEND_METHODDEF \ {"append", _PyCFunction_CAST(_elementtree_Element_append), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_append__doc__}, @@ -60,7 +65,11 @@ _elementtree_Element_append(PyObject *self, PyTypeObject *cls, PyObject *const * PyDoc_STRVAR(_elementtree_Element_clear__doc__, "clear($self, /)\n" "--\n" -"\n"); +"\n" +"Reset element.\n" +"\n" +"This function removes all subelements, clears all attributes, and\n" +"sets the text and tail attributes to None."); #define _ELEMENTTREE_ELEMENT_CLEAR_METHODDEF \ {"clear", (PyCFunction)_elementtree_Element_clear, METH_NOARGS, _elementtree_Element_clear__doc__}, @@ -214,7 +223,10 @@ _elementtree_Element___setstate__(PyObject *self, PyTypeObject *cls, PyObject *c PyDoc_STRVAR(_elementtree_Element_extend__doc__, "extend($self, elements, /)\n" "--\n" -"\n"); +"\n" +"Append subelements from a sequence.\n" +"\n" +"*elements* is a sequence with zero or more elements."); #define _ELEMENTTREE_ELEMENT_EXTEND_METHODDEF \ {"extend", _PyCFunction_CAST(_elementtree_Element_extend), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_extend__doc__}, @@ -258,7 +270,14 @@ _elementtree_Element_extend(PyObject *self, PyTypeObject *cls, PyObject *const * PyDoc_STRVAR(_elementtree_Element_find__doc__, "find($self, /, path, namespaces=None)\n" "--\n" -"\n"); +"\n" +"Find first matching element by tag name or path.\n" +"\n" +"*path* is a string having either an element tag or an XPath,\n" +"*namespaces* is an optional mapping from namespace prefix to full\n" +"name.\n" +"\n" +"Return the first matching element, or None if no element was found."); #define _ELEMENTTREE_ELEMENT_FIND_METHODDEF \ {"find", _PyCFunction_CAST(_elementtree_Element_find), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_find__doc__}, @@ -323,7 +342,17 @@ _elementtree_Element_find(PyObject *self, PyTypeObject *cls, PyObject *const *ar PyDoc_STRVAR(_elementtree_Element_findtext__doc__, "findtext($self, /, path, default=None, namespaces=None)\n" "--\n" -"\n"); +"\n" +"Find text for first matching element by tag name or path.\n" +"\n" +"*path* is a string having either an element tag or an XPath,\n" +"*default* is the value to return if the element was not found,\n" +"*namespaces* is an optional mapping from namespace prefix to full\n" +"name.\n" +"\n" +"Return text content of first matching element, or default value if\n" +"none was found. Note that if an element is found having no text\n" +"content, the empty string is returned."); #define _ELEMENTTREE_ELEMENT_FINDTEXT_METHODDEF \ {"findtext", _PyCFunction_CAST(_elementtree_Element_findtext), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_findtext__doc__}, @@ -396,7 +425,14 @@ _elementtree_Element_findtext(PyObject *self, PyTypeObject *cls, PyObject *const PyDoc_STRVAR(_elementtree_Element_findall__doc__, "findall($self, /, path, namespaces=None)\n" "--\n" -"\n"); +"\n" +"Find all matching subelements by tag name or path.\n" +"\n" +"*path* is a string having either an element tag or an XPath,\n" +"*namespaces* is an optional mapping from namespace prefix to full\n" +"name.\n" +"\n" +"Returns list containing all matching elements in document order."); #define _ELEMENTTREE_ELEMENT_FINDALL_METHODDEF \ {"findall", _PyCFunction_CAST(_elementtree_Element_findall), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_findall__doc__}, @@ -461,7 +497,14 @@ _elementtree_Element_findall(PyObject *self, PyTypeObject *cls, PyObject *const PyDoc_STRVAR(_elementtree_Element_iterfind__doc__, "iterfind($self, /, path, namespaces=None)\n" "--\n" -"\n"); +"\n" +"Find all matching subelements by tag name or path.\n" +"\n" +"*path* is a string having either an element tag or an XPath,\n" +"*namespaces* is an optional mapping from namespace prefix to full\n" +"name.\n" +"\n" +"Return an iterable yielding all matching elements in document order."); #define _ELEMENTTREE_ELEMENT_ITERFIND_METHODDEF \ {"iterfind", _PyCFunction_CAST(_elementtree_Element_iterfind), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_iterfind__doc__}, @@ -526,7 +569,15 @@ _elementtree_Element_iterfind(PyObject *self, PyTypeObject *cls, PyObject *const PyDoc_STRVAR(_elementtree_Element_get__doc__, "get($self, /, key, default=None)\n" "--\n" -"\n"); +"\n" +"Get element attribute.\n" +"\n" +"Equivalent to attrib.get, but some implementations may handle this a\n" +"bit more efficiently. *key* is what attribute to look for, and\n" +"*default* is what to return if the attribute was not found.\n" +"\n" +"Returns a string containing the attribute value, or the default if\n" +"attribute was not found."); #define _ELEMENTTREE_ELEMENT_GET_METHODDEF \ {"get", _PyCFunction_CAST(_elementtree_Element_get), METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_get__doc__}, @@ -591,7 +642,19 @@ _elementtree_Element_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs PyDoc_STRVAR(_elementtree_Element_iter__doc__, "iter($self, /, tag=None)\n" "--\n" -"\n"); +"\n" +"Create tree iterator.\n" +"\n" +"The iterator loops over the element and all subelements in document\n" +"order, returning all elements with a matching tag.\n" +"\n" +"If the tree structure is modified during iteration, new or removed\n" +"elements may or may not be included. To get a stable set, use the\n" +"list() function on the iterator, and loop over the resulting list.\n" +"\n" +"*tag* is what tags to look for (default is to return all elements)\n" +"\n" +"Return an iterator containing all the matching elements."); #define _ELEMENTTREE_ELEMENT_ITER_METHODDEF \ {"iter", _PyCFunction_CAST(_elementtree_Element_iter), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_iter__doc__}, @@ -654,7 +717,11 @@ _elementtree_Element_iter(PyObject *self, PyTypeObject *cls, PyObject *const *ar PyDoc_STRVAR(_elementtree_Element_itertext__doc__, "itertext($self, /)\n" "--\n" -"\n"); +"\n" +"Create text iterator.\n" +"\n" +"The iterator loops over the element and all subelements in document\n" +"order, returning all inner text."); #define _ELEMENTTREE_ELEMENT_ITERTEXT_METHODDEF \ {"itertext", _PyCFunction_CAST(_elementtree_Element_itertext), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_itertext__doc__}, @@ -675,7 +742,8 @@ _elementtree_Element_itertext(PyObject *self, PyTypeObject *cls, PyObject *const PyDoc_STRVAR(_elementtree_Element_insert__doc__, "insert($self, index, subelement, /)\n" "--\n" -"\n"); +"\n" +"Insert *subelement* at position *index*."); #define _ELEMENTTREE_ELEMENT_INSERT_METHODDEF \ {"insert", _PyCFunction_CAST(_elementtree_Element_insert), METH_FASTCALL, _elementtree_Element_insert__doc__}, @@ -720,7 +788,10 @@ _elementtree_Element_insert(PyObject *self, PyObject *const *args, Py_ssize_t na PyDoc_STRVAR(_elementtree_Element_items__doc__, "items($self, /)\n" "--\n" -"\n"); +"\n" +"Get element attributes as (name, value) pairs.\n" +"\n" +"Equivalent to attrib.items()."); #define _ELEMENTTREE_ELEMENT_ITEMS_METHODDEF \ {"items", (PyCFunction)_elementtree_Element_items, METH_NOARGS, _elementtree_Element_items__doc__}, @@ -737,7 +808,10 @@ _elementtree_Element_items(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_elementtree_Element_keys__doc__, "keys($self, /)\n" "--\n" -"\n"); +"\n" +"Get attribute names.\n" +"\n" +"Equivalent to attrib.keys()"); #define _ELEMENTTREE_ELEMENT_KEYS_METHODDEF \ {"keys", (PyCFunction)_elementtree_Element_keys, METH_NOARGS, _elementtree_Element_keys__doc__}, @@ -754,7 +828,14 @@ _elementtree_Element_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_elementtree_Element_makeelement__doc__, "makeelement($self, tag, attrib, /)\n" "--\n" -"\n"); +"\n" +"Create a new element with the same type.\n" +"\n" +"*tag* is a string containing the element name. *attrib* is a\n" +"dictionary containing the element attributes.\n" +"\n" +"Do not call this method, use the SubElement factory function\n" +"instead."); #define _ELEMENTTREE_ELEMENT_MAKEELEMENT_METHODDEF \ {"makeelement", _PyCFunction_CAST(_elementtree_Element_makeelement), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _elementtree_Element_makeelement__doc__}, @@ -804,7 +885,16 @@ _elementtree_Element_makeelement(PyObject *self, PyTypeObject *cls, PyObject *co PyDoc_STRVAR(_elementtree_Element_remove__doc__, "remove($self, subelement, /)\n" "--\n" -"\n"); +"\n" +"Remove matching subelement.\n" +"\n" +"Unlike the find methods, this method compares elements based on\n" +"identity, NOT ON tag value or contents. To remove subelements by\n" +"other means, the easiest way is to use a list comprehension to\n" +"select what elements to keep, and then use slice assignment to\n" +"update the parent element.\n" +"\n" +"ValueError is raised if a matching element could not be found."); #define _ELEMENTTREE_ELEMENT_REMOVE_METHODDEF \ {"remove", (PyCFunction)_elementtree_Element_remove, METH_O, _elementtree_Element_remove__doc__}, @@ -832,7 +922,12 @@ _elementtree_Element_remove(PyObject *self, PyObject *arg) PyDoc_STRVAR(_elementtree_Element_set__doc__, "set($self, key, value, /)\n" "--\n" -"\n"); +"\n" +"Set element attribute.\n" +"\n" +"Equivalent to attrib[key] = value, but some implementations may\n" +"handle this a bit more efficiently. *key* is what attribute to set,\n" +"and *value* is the attribute value to set it to."); #define _ELEMENTTREE_ELEMENT_SET_METHODDEF \ {"set", _PyCFunction_CAST(_elementtree_Element_set), METH_FASTCALL, _elementtree_Element_set__doc__}, @@ -859,6 +954,30 @@ _elementtree_Element_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs return return_value; } +PyDoc_STRVAR(_elementtree_TreeBuilder___init____doc__, +"TreeBuilder(element_factory=None, *, comment_factory=None,\n" +" pi_factory=None, insert_comments=False, insert_pis=False)\n" +"--\n" +"\n" +"Generic element structure builder.\n" +"\n" +"This builder converts a sequence of start, data, and end method\n" +"calls to a well-formed element structure.\n" +"\n" +"You can use this class to build an element structure using a custom\n" +"XML parser, or a parser for some other XML-like format.\n" +"\n" +"*element_factory* is an optional element factory which is called\n" +"to create new Element instances, as necessary.\n" +"\n" +"*comment_factory* is a factory to create comments to be used instead\n" +"of the standard factory. If *insert_comments* is false (the\n" +"default), comments will not be inserted into the tree.\n" +"\n" +"*pi_factory* is a factory to create processing instructions to be\n" +"used instead of the standard factory. If *insert_pis* is false (the\n" +"default), processing instructions will not be inserted into the tree."); + static int _elementtree_TreeBuilder___init___impl(TreeBuilderObject *self, PyObject *element_factory, @@ -993,7 +1112,8 @@ _elementtree__set_factories(PyObject *module, PyObject *const *args, Py_ssize_t PyDoc_STRVAR(_elementtree_TreeBuilder_data__doc__, "data($self, data, /)\n" "--\n" -"\n"); +"\n" +"Add text to current element."); #define _ELEMENTTREE_TREEBUILDER_DATA_METHODDEF \ {"data", (PyCFunction)_elementtree_TreeBuilder_data, METH_O, _elementtree_TreeBuilder_data__doc__}, @@ -1014,7 +1134,10 @@ _elementtree_TreeBuilder_data(PyObject *self, PyObject *data) PyDoc_STRVAR(_elementtree_TreeBuilder_end__doc__, "end($self, tag, /)\n" "--\n" -"\n"); +"\n" +"Close and return current Element.\n" +"\n" +"*tag* is the element name."); #define _ELEMENTTREE_TREEBUILDER_END_METHODDEF \ {"end", (PyCFunction)_elementtree_TreeBuilder_end, METH_O, _elementtree_TreeBuilder_end__doc__}, @@ -1035,7 +1158,10 @@ _elementtree_TreeBuilder_end(PyObject *self, PyObject *tag) PyDoc_STRVAR(_elementtree_TreeBuilder_comment__doc__, "comment($self, text, /)\n" "--\n" -"\n"); +"\n" +"Create a comment using the comment_factory.\n" +"\n" +"*text* is the text of the comment."); #define _ELEMENTTREE_TREEBUILDER_COMMENT_METHODDEF \ {"comment", (PyCFunction)_elementtree_TreeBuilder_comment, METH_O, _elementtree_TreeBuilder_comment__doc__}, @@ -1057,7 +1183,11 @@ _elementtree_TreeBuilder_comment(PyObject *self, PyObject *text) PyDoc_STRVAR(_elementtree_TreeBuilder_pi__doc__, "pi($self, target, text=None, /)\n" "--\n" -"\n"); +"\n" +"Create a processing instruction using the pi_factory.\n" +"\n" +"*target* is the target name of the processing instruction. *text* is\n" +"the data of the processing instruction, or \'\'."); #define _ELEMENTTREE_TREEBUILDER_PI_METHODDEF \ {"pi", _PyCFunction_CAST(_elementtree_TreeBuilder_pi), METH_FASTCALL, _elementtree_TreeBuilder_pi__doc__}, @@ -1091,7 +1221,8 @@ _elementtree_TreeBuilder_pi(PyObject *self, PyObject *const *args, Py_ssize_t na PyDoc_STRVAR(_elementtree_TreeBuilder_close__doc__, "close($self, /)\n" "--\n" -"\n"); +"\n" +"Flush builder buffers and return toplevel document Element."); #define _ELEMENTTREE_TREEBUILDER_CLOSE_METHODDEF \ {"close", (PyCFunction)_elementtree_TreeBuilder_close, METH_NOARGS, _elementtree_TreeBuilder_close__doc__}, @@ -1108,7 +1239,11 @@ _elementtree_TreeBuilder_close(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_elementtree_TreeBuilder_start__doc__, "start($self, tag, attrs, /)\n" "--\n" -"\n"); +"\n" +"Open new element and return it.\n" +"\n" +"*tag* is the element name, *attrs* is a dict containing element\n" +"attributes."); #define _ELEMENTTREE_TREEBUILDER_START_METHODDEF \ {"start", _PyCFunction_CAST(_elementtree_TreeBuilder_start), METH_FASTCALL, _elementtree_TreeBuilder_start__doc__}, @@ -1139,6 +1274,17 @@ _elementtree_TreeBuilder_start(PyObject *self, PyObject *const *args, Py_ssize_t return return_value; } +PyDoc_STRVAR(_elementtree_XMLParser___init____doc__, +"XMLParser(*, target=None, encoding=None)\n" +"--\n" +"\n" +"Element structure builder for XML source data based on the expat parser.\n" +"\n" +"*target* is an optional target object which defaults to an instance\n" +"of the standard TreeBuilder class, *encoding* is an optional encoding\n" +"string which if given, overrides the encoding specified in the XML\n" +"file: http://www.iana.org/assignments/character-sets"); + static int _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, const char *encoding); @@ -1223,7 +1369,8 @@ _elementtree_XMLParser___init__(PyObject *self, PyObject *args, PyObject *kwargs PyDoc_STRVAR(_elementtree_XMLParser_close__doc__, "close($self, /)\n" "--\n" -"\n"); +"\n" +"Finish feeding data to parser and return element structure."); #define _ELEMENTTREE_XMLPARSER_CLOSE_METHODDEF \ {"close", (PyCFunction)_elementtree_XMLParser_close, METH_NOARGS, _elementtree_XMLParser_close__doc__}, @@ -1257,7 +1404,8 @@ _elementtree_XMLParser_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_elementtree_XMLParser_feed__doc__, "feed($self, data, /)\n" "--\n" -"\n"); +"\n" +"Feed encoded data to parser."); #define _ELEMENTTREE_XMLPARSER_FEED_METHODDEF \ {"feed", (PyCFunction)_elementtree_XMLParser_feed, METH_O, _elementtree_XMLParser_feed__doc__}, @@ -1331,4 +1479,4 @@ _elementtree_XMLParser__setevents(PyObject *self, PyObject *const *args, Py_ssiz exit: return return_value; } -/*[clinic end generated code: output=c863ce16d8566291 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e2e9cf288c4400f6 input=a9049054013a1b77]*/ diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 3612c2699a557d..5f7acdeb7cfd8d 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -26,8 +26,6 @@ class complex "PyComplexObject *" "&PyComplex_Type" /* elementary operations on complex numbers */ -static Py_complex c_1 = {1., 0.}; - Py_complex _Py_c_sum(Py_complex a, Py_complex b) { @@ -333,23 +331,33 @@ _Py_c_pow(Py_complex a, Py_complex b) r.real = len*cos(phase); r.imag = len*sin(phase); - _Py_ADJUST_ERANGE2(r.real, r.imag); + if (isfinite(a.real) && isfinite(a.imag) + && isfinite(b.real) && isfinite(b.imag)) + { + _Py_ADJUST_ERANGE2(r.real, r.imag); + } } return r; } +#define INT_EXP_CUTOFF 100 + static Py_complex c_powu(Py_complex x, long n) { - Py_complex r, p; - long mask = 1; - r = c_1; - p = x; - while (mask > 0 && n >= mask) { - if (n & mask) - r = _Py_c_prod(r,p); - mask <<= 1; - p = _Py_c_prod(p,p); + assert(0 < n && n <= INT_EXP_CUTOFF); + while ((n & 1) == 0) { + x = _Py_c_prod(x, x); + n >>= 1; + } + Py_complex r = x; + n >>= 1; + while (n) { + x = _Py_c_prod(x, x); + if (n & 1) { + r = _Py_c_prod(r, x); + } + n >>= 1; } return r; } @@ -358,10 +366,11 @@ static Py_complex c_powi(Py_complex x, long n) { if (n > 0) - return c_powu(x,n); + return c_powu(x, n); + else if (n < 0) + return _Py_rc_quot(1.0, c_powu(x, -n)); else - return _Py_c_quot(c_1, c_powu(x,-n)); - + return (Py_complex){1., 0.}; } double @@ -751,9 +760,13 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z) errno = 0; // Check whether the exponent has a small integer value, and if so use // a faster and more accurate algorithm. - if (b.imag == 0.0 && b.real == floor(b.real) && fabs(b.real) <= 100.0) { + if (b.imag == 0.0 && b.real == floor(b.real) + && fabs(b.real) <= INT_EXP_CUTOFF) + { p = c_powi(a, (long)b.real); - _Py_ADJUST_ERANGE2(p.real, p.imag); + if (isfinite(a.real) && isfinite(a.imag)) { + _Py_ADJUST_ERANGE2(p.real, p.imag); + } } else { p = _Py_c_pow(a, b);