f()
-* Use :func:`locals` or :func:`eval` to resolve the function name::
+* Use :func:`locals` to resolve the function name::
def myFunc():
print("hello")
f = locals()[fname]
f()
- f = eval(fname)
- f()
-
- Note: Using :func:`eval` is slow and dangerous. If you don't have absolute
- control over the contents of the string, someone could pass a string that
- resulted in an arbitrary function being executed.
Is there an equivalent to Perl's chomp() for removing trailing newlines from strings?
-------------------------------------------------------------------------------------
into a list.
+How do you remove multiple items from a list
+--------------------------------------------
+
+As with removing duplicates, explicitly iterating in reverse with a
+delete condition is one possibility. However, it is easier and faster
+to use slice replacement with an implicit or explicit forward iteration.
+Here are three variations.::
+
+ mylist[:] = filter(keep_function, mylist)
+ mylist[:] = (x for x in mylist if keep_condition)
+ mylist[:] = [x for x in mylist if keep_condition]
+
+The list comprehension may be fastest.
+
+
How do you make an array in Python?
-----------------------------------
['else', 'sort', 'to', 'something']
-An alternative for the last step is::
-
- >>> result = []
- >>> for p in pairs: result.append(p[1])
-
-If you find this more legible, you might prefer to use this instead of the final
-list comprehension. However, it is almost twice as slow for long lists. Why?
-First, the ``append()`` operation has to reallocate memory, and while it uses
-some tricks to avoid doing that each time, it still has to do it occasionally,
-and that costs quite a bit. Second, the expression "result.append" requires an
-extra attribute lookup, and third, there's a speed reduction from having to make
-all those function calls.
-
-
Objects
=======
Calltips
^^^^^^^^
-A calltip is shown when one types :kbd:`(` after the name of an *accessible*
-function. A name expression may include dots and subscripts. A calltip
-remains until it is clicked, the cursor is moved out of the argument area,
-or :kbd:`)` is typed. When the cursor is in the argument part of a definition,
-the menu or shortcut display a calltip.
-
-A calltip consists of the function signature and the first line of the
-docstring. For builtins without an accessible signature, the calltip
-consists of all lines up the fifth line or the first blank line. These
-details may change.
-
-The set of *accessible* functions depends on what modules have been imported
-into the user process, including those imported by Idle itself,
-and what definitions have been run, all since the last restart.
+A calltip is shown automatically when one types :kbd:`(` after the name
+of an *accessible* function. A function name expression may include
+dots and subscripts. A calltip remains until it is clicked, the cursor
+is moved out of the argument area, or :kbd:`)` is typed. Whenever the
+cursor is in the argument part of a definition, select Edit and "Show
+Call Tip" on the menu or enter its shortcut to display a calltip.
+
+The calltip consists of the function's signature and docstring up to
+the latter's first blank line or the fifth non-blank line. (Some builtin
+functions lack an accessible signature.) A '/' or '*' in the signature
+indicates that the preceding or following arguments are passed by
+position or name (keyword) only. Details are subject to change.
+
+In Shell, the accessible functions depends on what modules have been
+imported into the user process, including those imported by Idle itself,
+and which definitions have been run, all since the last restart.
For example, restart the Shell and enter ``itertools.count(``. A calltip
-appears because Idle imports itertools into the user process for its own use.
-(This could change.) Enter ``turtle.write(`` and nothing appears. Idle does
-not import turtle. The menu or shortcut do nothing either. Enter
-``import turtle`` and then ``turtle.write(`` will work.
-
-In an editor, import statements have no effect until one runs the file. One
-might want to run a file after writing the import statements at the top,
-or immediately run an existing file before editing.
+appears because Idle imports itertools into the user process for its own
+use. (This could change.) Enter ``turtle.write(`` and nothing appears.
+Idle does not itself import turtle. The menu entry and shortcut also do
+nothing. Enter ``import turtle``. Thereafter, ``turtle.write(``
+will display a calltip.
+
+In an editor, import statements have no effect until one runs the file.
+One might want to run a file after writing import statements, after
+adding function definitions, or after opening an existing file.
.. _code-context:
Return the greatest common divisor of the specified integer arguments.
If any of the arguments is nonzero, then the returned value is the largest
- positive integer that is a divisor af all arguments. If all arguments
+ positive integer that is a divisor of all arguments. If all arguments
are zero, then the returned value is ``0``. ``gcd()`` without arguments
returns ``0``.
order so that the sample is reproducible.
+.. _real-valued-distributions:
+
Real-valued distributions
-------------------------
.. _random-examples:
-Examples and Recipes
---------------------
+Examples
+--------
Basic examples::
a tutorial by `Peter Norvig <http://norvig.com/bio.html>`_ covering
the basics of probability theory, how to write simulations, and
how to perform data analysis using Python.
+
+
+Recipes
+-------
+
+The default :func:`.random` returns multiples of 2⁻⁵³ in the range
+*0.0 ≤ x < 1.0*. All such numbers are evenly spaced and are exactly
+representable as Python floats. However, many other representable
+floats in that interval are not possible selections. For example,
+``0.05954861408025609`` isn't an integer multiple of 2⁻⁵³.
+
+The following recipe takes a different approach. All floats in the
+interval are possible selections. The mantissa comes from a uniform
+distribution of integers in the range *2⁵² ≤ mantissa < 2⁵³*. The
+exponent comes from a geometric distribution where exponents smaller
+than *-53* occur half as often as the next larger exponent.
+
+::
+
+ from random import Random
+ from math import ldexp
+
+ class FullRandom(Random):
+
+ def random(self):
+ mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
+ exponent = -53
+ x = 0
+ while not x:
+ x = self.getrandbits(32)
+ exponent += x.bit_length() - 32
+ return ldexp(mantissa, exponent)
+
+All :ref:`real valued distributions <real-valued-distributions>`
+in the class will use the new method::
+
+ >>> fr = FullRandom()
+ >>> fr.random()
+ 0.05954861408025609
+ >>> fr.expovariate(0.25)
+ 8.87925541791544
+
+The recipe is conceptually equivalent to an algorithm that chooses from
+all the multiples of 2⁻¹⁰⁷⁴ in the range *0.0 ≤ x < 1.0*. All such
+numbers are evenly spaced, but most have to be rounded down to the
+nearest representable Python float. (The value 2⁻¹⁰⁷⁴ is the smallest
+positive unnormalized float and is equal to ``math.ulp(0.0)``.)
+
+
+.. seealso::
+
+ `Generating Pseudo-random Floating-Point Values
+ <https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
+ paper by Allen B. Downey describing ways to generate more
+ fine-grained floats than normally generated by :func:`.random`.
will be created in or as *dst* and *src* will be removed.
If *copy_function* is given, it must be a callable that takes two arguments
- *src* and *dst*, and will be used to copy *src* to *dest* if
+ *src* and *dst*, and will be used to copy *src* to *dst* if
:func:`os.rename` cannot be used. If the source is a directory,
:func:`copytree` is called, passing it the :func:`copy_function`. The
default *copy_function* is :func:`copy2`. Using :func:`~shutil.copy` as the
Return the path of the user-specific site-packages directory,
:data:`USER_SITE`. If it is not initialized yet, this function will also set
- it, respecting :envvar:`PYTHONNOUSERSITE` and :data:`USER_BASE`.
+ it, respecting :data:`USER_BASE`. To determine if the user-specific
+ site-packages was added to ``sys.path`` :data:`ENABLE_USER_SITE` should be
+ used.
.. versionadded:: 3.2
.. versionadded:: 3.6.0
.. deprecated:: 3.9
- :class:`collections.contextlib.AbstractContextManager` now supports ``[]``. See :pep:`585`.
+ :class:`contextlib.AbstractContextManager` now supports ``[]``. See :pep:`585`.
.. class:: AsyncContextManager(Generic[T_co])
.. versionadded:: 3.6.2
.. deprecated:: 3.9
- :class:`collections.contextlib.AbstractAsyncContextManager` now supports ``[]``. See :pep:`585`.
+ :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See :pep:`585`.
Protocols
---------
If ``from __future__ import annotations`` is used in Python 3.7 or later,
annotations are not evaluated at function definition time.
- Instead, the are stored as strings in ``__annotations__``,
+ Instead, they are stored as strings in ``__annotations__``,
This makes it unnecessary to use quotes around the annotation.
(see :pep:`563`).
If given, *logger* should be a :class:`logging.Logger` object or a
:class:`str` giving the name of a logger. The default is the root
- logger, which will catch all messages.
+ logger, which will catch all messages that were not blocked by a
+ non-propagating descendent logger.
If given, *level* should be either a numeric logging level or
its string equivalent (for example either ``"ERROR"`` or
remove all countries with a rank higher than 50::
>>> for country in root.findall('country'):
+ ... # using root.findall() to avoid removal during traversal
... rank = int(country.find('rank').text)
... if rank > 50:
... root.remove(country)
...
>>> tree.write('output.xml')
+Note that concurrent modification while iterating can lead to problems,
+just like when iterating and modifying Python lists or dicts.
+Therefore, the example first collects all matching elements with
+``root.findall()``, and only then iterates over the list of matches.
+
Our XML now looks like this:
.. code-block:: xml
.. note::
- If the right operand's type is a subclass of the left operand's type and that
- subclass provides the reflected method for the operation, this method will be
- called before the left operand's non-reflected method. This behavior allows
- subclasses to override their ancestors' operations.
+ If the right operand's type is a subclass of the left operand's type and
+ that subclass provides a different implementation of the reflected method
+ for the operation, this method will be called before the left operand's
+ non-reflected method. This behavior allows subclasses to override their
+ ancestors' operations.
.. method:: object.__iadd__(self, other)
method—that will instead have the opposite effect of explicitly
*blocking* such fallback.
-.. [#] For operands of the same type, it is assumed that if the non-reflected method
- (such as :meth:`__add__`) fails the operation is not supported, which is why the
- reflected method is not called.
+.. [#] For operands of the same type, it is assumed that if the non-reflected
+ method -- such as :meth:`__add__` -- fails then the overall operation is not
+ supported, which is why the reflected method is not called.
from sphinx.util.nodes import split_explicit_title
from sphinx.writers.text import TextWriter, TextTranslator
from sphinx.writers.latex import LaTeXTranslator
-from sphinx.domains.python import PyModulelevel, PyClassmember
+
+try:
+ from sphinx.domains.python import PyFunction, PyMethod
+except ImportError:
+ from sphinx.domains.python import PyClassmember as PyMethod
+ from sphinx.domains.python import PyModulelevel as PyFunction
# Support for checking for suspicious markup
return False
-class PyDecoratorFunction(PyDecoratorMixin, PyModulelevel):
+class PyDecoratorFunction(PyDecoratorMixin, PyFunction):
def run(self):
# a decorator function is a function after all
self.name = 'py:function'
- return PyModulelevel.run(self)
+ return PyFunction.run(self)
-class PyDecoratorMethod(PyDecoratorMixin, PyClassmember):
+# TODO: Use sphinx.domains.python.PyDecoratorMethod when possible
+class PyDecoratorMethod(PyDecoratorMixin, PyMethod):
def run(self):
self.name = 'py:method'
- return PyClassmember.run(self)
+ return PyMethod.run(self)
class PyCoroutineMixin(object):
return ret
-class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel):
+class PyCoroutineFunction(PyCoroutineMixin, PyFunction):
def run(self):
self.name = 'py:function'
- return PyModulelevel.run(self)
+ return PyFunction.run(self)
-class PyCoroutineMethod(PyCoroutineMixin, PyClassmember):
+class PyCoroutineMethod(PyCoroutineMixin, PyMethod):
def run(self):
self.name = 'py:method'
- return PyClassmember.run(self)
+ return PyMethod.run(self)
-class PyAwaitableFunction(PyAwaitableMixin, PyClassmember):
+class PyAwaitableFunction(PyAwaitableMixin, PyFunction):
def run(self):
self.name = 'py:function'
- return PyClassmember.run(self)
+ return PyFunction.run(self)
-class PyAwaitableMethod(PyAwaitableMixin, PyClassmember):
+class PyAwaitableMethod(PyAwaitableMixin, PyMethod):
def run(self):
self.name = 'py:method'
- return PyClassmember.run(self)
+ return PyMethod.run(self)
-class PyAbstractMethod(PyClassmember):
+class PyAbstractMethod(PyMethod):
def handle_signature(self, sig, signode):
ret = super(PyAbstractMethod, self).handle_signature(sig, signode)
def run(self):
self.name = 'py:method'
- return PyClassmember.run(self)
+ return PyMethod.run(self)
# Support for documenting version of removal in deprecations
(Many people worked on this for eight years but the problem was finally
solved by Serhiy Storchaka in :issue:`13153`.)
+New in 3.8.1:
+
+Add option to toggle cursor blink off. (Contributed by Zackery Spytz
+in :issue:`4603`.)
+
+Escape key now closes IDLE completion windows. (Contributed by Johnny
+Najera in :issue:`38944`.)
+
The changes above have been backported to 3.7 maintenance releases.
+Add keywords to module name completion list. (Contributed by Terry J.
+Reedy in :issue:`37765`.)
inspect
-------
-------------- --- --- --- --- --- ---
Variable and attribute read access:
- read_local 7.1 7.1 5.4 5.1 3.9 4.0
- read_nonlocal 7.1 8.1 5.8 5.4 4.4 4.8
- read_global 15.5 19.0 14.3 13.6 7.6 7.7
- read_builtin 21.1 21.6 18.5 19.0 7.5 7.7
- read_classvar_from_class 25.6 26.5 20.7 19.5 18.4 18.6
- read_classvar_from_instance 22.8 23.5 18.8 17.1 16.4 20.1
- read_instancevar 32.4 33.1 28.0 26.3 25.4 27.7
- read_instancevar_slots 27.8 31.3 20.8 20.8 20.2 24.5
- read_namedtuple 73.8 57.5 45.0 46.8 18.4 23.2
- read_boundmethod 37.6 37.9 29.6 26.9 27.7 45.9
+ read_local 7.1 7.1 5.4 5.1 3.9 3.9
+ read_nonlocal 7.1 8.1 5.8 5.4 4.4 4.5
+ read_global 15.5 19.0 14.3 13.6 7.6 7.8
+ read_builtin 21.1 21.6 18.5 19.0 7.5 7.8
+ read_classvar_from_class 25.6 26.5 20.7 19.5 18.4 17.9
+ read_classvar_from_instance 22.8 23.5 18.8 17.1 16.4 16.9
+ read_instancevar 32.4 33.1 28.0 26.3 25.4 25.3
+ read_instancevar_slots 27.8 31.3 20.8 20.8 20.2 20.5
+ read_namedtuple 73.8 57.5 45.0 46.8 18.4 18.7
+ read_boundmethod 37.6 37.9 29.6 26.9 27.7 41.1
Variable and attribute write access:
- write_local 8.7 9.3 5.5 5.3 4.3 4.2
- write_nonlocal 10.5 11.1 5.6 5.5 4.7 4.9
- write_global 19.7 21.2 18.0 18.0 15.8 17.2
- write_classvar 92.9 96.0 104.6 102.1 39.2 43.2
- write_instancevar 44.6 45.8 40.0 38.9 35.5 40.7
- write_instancevar_slots 35.6 36.1 27.3 26.6 25.7 27.7
+ write_local 8.7 9.3 5.5 5.3 4.3 4.3
+ write_nonlocal 10.5 11.1 5.6 5.5 4.7 4.8
+ write_global 19.7 21.2 18.0 18.0 15.8 16.7
+ write_classvar 92.9 96.0 104.6 102.1 39.2 39.8
+ write_instancevar 44.6 45.8 40.0 38.9 35.5 37.4
+ write_instancevar_slots 35.6 36.1 27.3 26.6 25.7 25.8
Data structure read access:
- read_list 24.2 24.5 20.8 20.8 19.0 21.1
- read_deque 24.7 25.5 20.2 20.6 19.8 21.6
- read_dict 24.3 25.7 22.3 23.0 21.0 22.5
- read_strdict 22.6 24.3 19.5 21.2 18.9 21.6
+ read_list 24.2 24.5 20.8 20.8 19.0 19.5
+ read_deque 24.7 25.5 20.2 20.6 19.8 20.2
+ read_dict 24.3 25.7 22.3 23.0 21.0 22.4
+ read_strdict 22.6 24.3 19.5 21.2 18.9 21.5
Data structure write access:
- write_list 27.1 28.5 22.5 21.6 20.0 21.6
- write_deque 28.7 30.1 22.7 21.8 23.5 23.2
- write_dict 31.4 33.3 29.3 29.2 24.7 27.8
- write_strdict 28.4 29.9 27.5 25.2 23.1 29.8
+ write_list 27.1 28.5 22.5 21.6 20.0 20.0
+ write_deque 28.7 30.1 22.7 21.8 23.5 21.7
+ write_dict 31.4 33.3 29.3 29.2 24.7 25.4
+ write_strdict 28.4 29.9 27.5 25.2 23.1 24.5
Stack (or queue) operations:
- list_append_pop 93.4 112.7 75.4 74.2 50.8 53.9
- deque_append_pop 43.5 57.0 49.4 49.2 42.5 45.5
- deque_append_popleft 43.7 57.3 49.7 49.7 42.8 45.5
+ list_append_pop 93.4 112.7 75.4 74.2 50.8 50.6
+ deque_append_pop 43.5 57.0 49.4 49.2 42.5 44.2
+ deque_append_popleft 43.7 57.3 49.7 49.7 42.8 46.4
Timing loop:
loop_overhead 0.5 0.6 0.4 0.3 0.3 0.3
and will be removed in future Python versions. ``value`` itself should be
used instead of ``Index(value)``. ``Tuple(slices, Load())`` should be
used instead of ``ExtSlice(slices)``.
- (Contributed by Serhiy Storchaka in :issue:`32892`.)
+ (Contributed by Serhiy Storchaka in :issue:`34822`.)
* :mod:`ast` classes ``Suite``, ``Param``, ``AugLoad`` and ``AugStore``
are considered deprecated and will be removed in future Python versions.
| ASYNC 'with' a=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
CHECK_VERSION(5, "Async with statements are", _Py_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
with_item[withitem_ty]:
- | e=expression 'as' t=target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
+ | e=expression 'as' t=star_target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
| invalid_with_item
| e=expression { _Py_withitem(e, NULL, p->arena) }
PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
-PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
-#endif
-
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
-PyAPI_DATA(int) Py_UTF8Mode;
-#endif
-
/* The std printer acts as a preliminary sys.stderr until the new io
infrastructure is in place. */
PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
If non-NULL, this is different than the default encoding for strings
*/
PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
+PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
+#endif
PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding;
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
+PyAPI_DATA(int) Py_UTF8Mode;
+#endif
+
/* A routine to check if a file descriptor can be select()-ed. */
#ifdef _MSC_VER
/* On Windows, any socket fd can be select()-ed, no matter how high */
#define PY_RELEASE_SERIAL 0
/* Version as a string */
-#define PY_VERSION "3.9.0"
+#define PY_VERSION "3.9.0+"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
(options, args) = parser.parse_args()
sys.argv[:] = args
+ # The script that we're profiling may chdir, so capture the absolute path
+ # to the output file at startup.
+ if options.outfile is not None:
+ options.outfile = os.path.abspath(options.outfile)
+
if len(args) > 0:
if options.module:
code = "run_module(modname, run_name='__main__')"
import unittest
+import unittest.mock
import os.path
import sys
import test.support
@unittest.skipUnless(sys.platform.startswith('linux'),
'Test only valid for Linux')
-class LibPathFindTest(unittest.TestCase):
+class FindLibraryLinux(unittest.TestCase):
def test_find_on_libpath(self):
import subprocess
import tempfile
# LD_LIBRARY_PATH)
self.assertEqual(find_library(libname), 'lib%s.so' % libname)
+ def test_find_library_with_gcc(self):
+ with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
+ self.assertNotEqual(find_library('c'), None)
+
+ def test_find_library_with_ld(self):
+ with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
+ unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
+ self.assertNotEqual(find_library('c'), None)
+
if __name__ == "__main__":
unittest.main()
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile
+ def _is_elf(filename):
+ "Return True if the given file is an ELF file"
+ elf_header = b'\x7fELF'
+ with open(filename, 'br') as thefile:
+ return thefile.read(4) == elf_header
+
def _findLib_gcc(name):
# Run GCC's linker with the -t (aka --trace) option and examine the
# library name it prints out. The GCC command will fail because we
# Raised if the file was already removed, which is the normal
# behaviour of GCC if linking fails
pass
- res = re.search(expr, trace)
+ res = re.findall(expr, trace)
if not res:
return None
- return os.fsdecode(res.group(0))
+
+ for file in res:
+ # Check if the given file is an elf file: gcc can report
+ # some files that are linker scripts and not actual
+ # shared objects. See bpo-41976 for more details
+ if not _is_elf(file):
+ continue
+ return os.fsdecode(file)
if sys.platform == "sunos5":
stderr=subprocess.PIPE,
universal_newlines=True)
out, _ = p.communicate()
- res = re.search(expr, os.fsdecode(out))
- if res:
- result = res.group(0)
+ res = re.findall(expr, os.fsdecode(out))
+ for file in res:
+ # Check if the given file is an elf file: gcc can report
+ # some files that are linker scripts and not actual
+ # shared objects. See bpo-41976 for more details
+ if not _is_elf(file):
+ continue
+ return os.fsdecode(file)
except Exception:
pass # result will be None
return result
def find_library(name):
# See issue #9998
return _findSoname_ldconfig(name) or \
- _get_soname(_findLib_gcc(name) or _findLib_ld(name))
+ _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
################################################################
# test code
self._tzinfo = tzinfo
def __reduce_ex__(self, protocol):
- return (time, self._getstate(protocol))
+ return (self.__class__, self._getstate(protocol))
def __reduce__(self):
return self.__reduce_ex__(2)
class CycleError(ValueError):
- """Subclass of ValueError raised by TopologicalSorterif cycles exist in the graph
+ """Subclass of ValueError raised by TopologicalSorter.prepare if cycles
+ exist in the working graph.
If multiple cycles exist, only one undefined choice among them will be reported
and included in the exception. The detected cycle can be accessed via the second
return result
def is_active(self):
- """Return True if more progress can be made and ``False`` otherwise.
+ """Return ``True`` if more progress can be made and ``False`` otherwise.
Progress can be made if cycles do not block the resolution and either there
are still nodes ready that haven't yet been returned by "get_ready" or the
"""Marks a set of nodes returned by "get_ready" as processed.
This method unblocks any successor of each node in *nodes* for being returned
- in the future by a a call to "get_ready"
+ in the future by a call to "get_ready".
Raises :exec:`ValueError` if any node in *nodes* has already been marked as
processed by a previous call to this method, if a node was not added to the
+What's New in IDLE 3.9.1
+Released on 2020-12-07?
+======================================
+
+
+bpo-41775: Make 'IDLE Shell' the shell title.
+
+bpo-35764: Rewrite the Calltips doc section.
+
+bpo-40181: In calltips, stop reminding that '/' marks the end of
+positional-only arguments.
+
+
What's New in IDLE 3.9.0 (since 3.8.0)
Released on 2020-10-05?
======================================
-
bpo-41468: Improve IDLE run crash error message (which users should
never see).
_first_param = re.compile(r'(?<=\()\w*\,?\s*')
_default_callable_argspec = "See source or doc"
_invalid_method = "invalid method signature"
-_argument_positional = " # '/' marks preceding args as positional-only."
def get_argspec(ob):
'''Return a string describing the signature of a callable object, or ''.
else:
argspec = ''
- if '/' in argspec and len(argspec) < _MAX_COLS - len(_argument_positional):
- # Add explanation TODO remove after 3.7, before 3.9.
- argspec += _argument_positional
if isinstance(fob, type) and argspec == '()':
# If fob has no argument, use default callable argspec.
argspec = _default_callable_argspec
</div>
<div class="section" id="calltips">
<span id="id4"></span><h3>Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
-<p>A calltip is shown when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name of an <em>accessible</em>
-function. A name expression may include dots and subscripts. A calltip
-remains until it is clicked, the cursor is moved out of the argument area,
-or <kbd class="kbd docutils literal notranslate">)</kbd> is typed. When the cursor is in the argument part of a definition,
-the menu or shortcut display a calltip.</p>
-<p>A calltip consists of the function signature and the first line of the
-docstring. For builtins without an accessible signature, the calltip
-consists of all lines up the fifth line or the first blank line. These
-details may change.</p>
-<p>The set of <em>accessible</em> functions depends on what modules have been imported
-into the user process, including those imported by Idle itself,
-and what definitions have been run, all since the last restart.</p>
+<p>A calltip is shown automatically when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name
+of an <em>accessible</em> function. A function name expression may include
+dots and subscripts. A calltip remains until it is clicked, the cursor
+is moved out of the argument area, or <kbd class="kbd docutils literal notranslate">)</kbd> is typed. Whenever the
+cursor is in the argument part of a definition, select Edit and “Show
+Call Tip” on the menu or enter its shortcut to display a calltip.</p>
+<p>The calltip consists of the function’s signature and docstring up to
+the latter’s first blank line or the fifth non-blank line. (Some builtin
+functions lack an accessible signature.) A ‘/’ or ‘*’ in the signature
+indicates that the preceding or following arguments are passed by
+position or name (keyword) only. Details are subject to change.</p>
+<p>In Shell, the accessible functions depends on what modules have been
+imported into the user process, including those imported by Idle itself,
+and which definitions have been run, all since the last restart.</p>
<p>For example, restart the Shell and enter <code class="docutils literal notranslate"><span class="pre">itertools.count(</span></code>. A calltip
-appears because Idle imports itertools into the user process for its own use.
-(This could change.) Enter <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> and nothing appears. Idle does
-not import turtle. The menu or shortcut do nothing either. Enter
-<code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">turtle</span></code> and then <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> will work.</p>
-<p>In an editor, import statements have no effect until one runs the file. One
-might want to run a file after writing the import statements at the top,
-or immediately run an existing file before editing.</p>
+appears because Idle imports itertools into the user process for its own
+use. (This could change.) Enter <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> and nothing appears.
+Idle does not itself import turtle. The menu entry and shortcut also do
+nothing. Enter <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">turtle</span></code>. Thereafter, <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code>
+will display a calltip.</p>
+<p>In an editor, import statements have no effect until one runs the file.
+One might want to run a file after writing import statements, after
+adding function definitions, or after opening an existing file.</p>
</div>
<div class="section" id="code-context">
<span id="id5"></span><h3>Code Context<a class="headerlink" href="#code-context" title="Permalink to this headline">¶</a></h3>
<br />
<br />
- Last updated on Sep 09, 2020.
+ Last updated on Sep 22, 2020.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
if List.__doc__ is not None:
tiptest(List,
- f'(iterable=(), /){calltip._argument_positional}'
+ f'(iterable=(), /)'
f'\n{List.__doc__}')
tiptest(list.__new__,
'(*args, **kwargs)\n'
'Create and return a new object. '
'See help(type) for accurate signature.')
tiptest(list.__init__,
- '(self, /, *args, **kwargs)'
- + calltip._argument_positional + '\n' +
+ '(self, /, *args, **kwargs)\n'
'Initialize self. See help(type(self)) for accurate signature.')
- append_doc = (calltip._argument_positional
- + "\nAppend object to the end of the list.")
+ append_doc = "\nAppend object to the end of the list."
tiptest(list.append, '(self, object, /)' + append_doc)
tiptest(List.append, '(self, object, /)' + append_doc)
tiptest([].append, '(object, /)' + append_doc)
class PyShell(OutputWindow):
- shell_title = "Python " + python_version() + " Shell"
+ shell_title = "IDLE Shell " + python_version()
# Override classes
ColorDelegator = ModifiedColorDelegator
responsible for converting a LogRecord to (usually) a string which can
be interpreted by either a human or an external system. The base Formatter
allows a formatting string to be specified. If none is supplied, the
- the style-dependent default value, "%(message)s", "{message}", or
+ style-dependent default value, "%(message)s", "{message}", or
"${message}", is used.
The Formatter can be initialized with a format string which makes use of
"""
Determine if the specified record is to be logged.
- Is the specified record to be logged? Returns 0 for no, nonzero for
- yes. If deemed appropriate, the record may be modified in-place.
+ Returns True if the record should be logged, or False otherwise.
+ If deemed appropriate, the record may be modified in-place.
"""
if self.nlen == 0:
return True
(options, args) = parser.parse_args()
sys.argv[:] = args
+ # The script that we're profiling may chdir, so capture the absolute path
+ # to the output file at startup.
+ if options.outfile is not None:
+ options.outfile = os.path.abspath(options.outfile)
+
if len(args) > 0:
if options.module:
import runpy
TIME = 'time', 'tottime'
def __new__(cls, *values):
- obj = str.__new__(cls)
-
- obj._value_ = values[0]
+ value = values[0]
+ obj = str.__new__(cls, value)
+ obj._value_ = value
for other_value in values[1:]:
cls._value2member_map_[other_value] = obj
obj._all_values = values
_newSymbolTable = SymbolTableFactory()
-class SymbolTable(object):
+class SymbolTable:
def __init__(self, raw_table, filename):
self._table = raw_table
else:
kind = "%s " % self.__class__.__name__
- if self._table.name == "global":
+ if self._table.name == "top":
return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
else:
return "<{0}SymbolTable for {1} in {2}>".format(kind,
if sym is None:
flags = self._table.symbols[name]
namespaces = self.__check_children(name)
- sym = self._symbols[name] = Symbol(name, flags, namespaces)
+ module_scope = (self._table.name == "top")
+ sym = self._symbols[name] = Symbol(name, flags, namespaces,
+ module_scope=module_scope)
return sym
def get_symbols(self):
return self.__methods
-class Symbol(object):
+class Symbol:
- def __init__(self, name, flags, namespaces=None):
+ def __init__(self, name, flags, namespaces=None, *, module_scope=False):
self.__name = name
self.__flags = flags
self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
self.__namespaces = namespaces or ()
+ self.__module_scope = module_scope
def __repr__(self):
return "<symbol {0!r}>".format(self.__name)
return bool(self.__flags & DEF_PARAM)
def is_global(self):
- return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
+ """Return *True* if the sysmbol is global.
+ """
+ return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
+ or (self.__module_scope and self.__flags & DEF_BOUND))
def is_nonlocal(self):
return bool(self.__flags & DEF_NONLOCAL)
return bool(self.__scope == GLOBAL_EXPLICIT)
def is_local(self):
- return bool(self.__scope in (LOCAL, CELL))
+ """Return *True* if the symbol is local.
+ """
+ return bool(self.__scope in (LOCAL, CELL)
+ or (self.__module_scope and self.__flags & DEF_BOUND))
def is_annotated(self):
return bool(self.__flags & DEF_ANNOT)
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ self.assertTrue(isinstance(derived, SubclassDate))
def test_backdoor_resistance(self):
# For fast unpickling, the constructor accepts a pickle byte string.
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ self.assertTrue(isinstance(derived, SubclassDatetime))
def test_compat_unpickle(self):
tests = [
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ self.assertTrue(isinstance(derived, SubclassTime))
def test_compat_unpickle(self):
tests = [
self._test_mapping_file_plain()
def _test_mapping_file_plain(self):
- unichrs = lambda s: ''.join(map(chr, map(eval, s.split('+'))))
+ def unichrs(s):
+ return ''.join(chr(int(x, 16)) for x in s.split('+'))
+
urt_wa = {}
with self.open_mapping_file() as f:
for line in f:
if not line:
break
- data = line.split('#')[0].strip().split()
+ data = line.split('#')[0].split()
if len(data) != 2:
continue
- csetval = eval(data[0])
- if csetval <= 0x7F:
- csetch = bytes([csetval & 0xff])
- elif csetval >= 0x1000000:
- csetch = bytes([(csetval >> 24), ((csetval >> 16) & 0xff),
- ((csetval >> 8) & 0xff), (csetval & 0xff)])
- elif csetval >= 0x10000:
- csetch = bytes([(csetval >> 16), ((csetval >> 8) & 0xff),
- (csetval & 0xff)])
- elif csetval >= 0x100:
- csetch = bytes([(csetval >> 8), (csetval & 0xff)])
- else:
+ if data[0][:2] != '0x':
+ self.fail(f"Invalid line: {line!r}")
+ csetch = bytes.fromhex(data[0][2:])
+ if len(csetch) == 1 and 0x80 <= csetch[0]:
continue
unich = unichrs(data[1])
("", len(allbytes))
)
+ self.assertRaisesRegex(TypeError,
+ "character mapping must be in range\\(0x110000\\)",
+ codecs.charmap_decode,
+ b"\x00\x01\x02", "strict", {0: "A", 1: 'Bb', 2: -2}
+ )
+
+ self.assertRaisesRegex(TypeError,
+ "character mapping must be in range\\(0x110000\\)",
+ codecs.charmap_decode,
+ b"\x00\x01\x02", "strict", {0: "A", 1: 'Bb', 2: 999999999}
+ )
+
def test_decode_with_int2int_map(self):
a = ord('a')
b = ord('b')
raise TypeError('requires _testcapi.with_tp_del')
return C
+try:
+ from _testcapi import without_gc
+except ImportError:
+ def without_gc(cls):
+ class C:
+ def __new__(cls, *args, **kwargs):
+ raise TypeError('requires _testcapi.without_gc')
+ return C
+
from test import support
assert self.id_ == id(self)
+@without_gc
class NonGC(NonGCSimpleBase):
__slots__ = ()
+@without_gc
class NonGCResurrector(NonGCSimpleBase):
__slots__ = ()
class Simple(SimpleBase):
pass
-class SimpleResurrector(NonGCResurrector, SimpleBase):
- pass
+# Can't inherit from NonGCResurrector, in case importing without_gc fails.
+class SimpleResurrector(SimpleBase):
+
+ def side_effect(self):
+ """
+ Resurrect self by storing self in a class-wide list.
+ """
+ self.survivors.append(self)
class TestBase:
self.assert_survivors([])
self.assertIs(wr(), None)
+ @support.cpython_only
def test_non_gc(self):
with SimpleBase.test():
s = NonGC()
self.assert_del_calls(ids)
self.assert_survivors([])
+ @support.cpython_only
def test_non_gc_resurrect(self):
with SimpleBase.test():
s = NonGCResurrector()
self.assertTrue(gc.is_tracked(UserInt()))
self.assertTrue(gc.is_tracked([]))
self.assertTrue(gc.is_tracked(set()))
- self.assertFalse(gc.is_tracked(UserClassSlots()))
- self.assertFalse(gc.is_tracked(UserFloatSlots()))
- self.assertFalse(gc.is_tracked(UserIntSlots()))
+ self.assertTrue(gc.is_tracked(UserClassSlots()))
+ self.assertTrue(gc.is_tracked(UserFloatSlots()))
+ self.assertTrue(gc.is_tracked(UserIntSlots()))
def test_is_finalized(self):
# Objects not tracked by the always gc return false
except ImportError:
# multiprocessing.shared_memory is not available on e.g. Android
ShareableList = None
-from multiprocessing.queues import SimpleQueue
+from multiprocessing.queues import SimpleQueue as MPSimpleQueue
from os import DirEntry
from re import Pattern, Match
from types import GenericAlias, MappingProxyType, AsyncGeneratorType
SplitResult, ParseResult,
ValueProxy, ApplyResult,
WeakSet, ReferenceType, ref,
- ShareableList, SimpleQueue,
+ ShareableList, MPSimpleQueue,
Future, _WorkItem,
Morsel,
):
self.assertEqual(True, issubclass(B(), int))
+ def test_infinite_recursion_in_bases(self):
+ class X:
+ @property
+ def __bases__(self):
+ return self.__bases__
+
+ self.assertRaises(RecursionError, issubclass, X(), int)
+ self.assertRaises(RecursionError, issubclass, int, X())
+ self.assertRaises(RecursionError, isinstance, 1, X())
+
def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its
import unittest
-from test.support import check_warnings
+from test.support import check_warnings, import_fresh_module
with check_warnings(("", PendingDeprecationWarning)):
- from lib2to3.tests import load_tests
+ load_tests = import_fresh_module('lib2to3.tests', fresh=['lib2to3']).load_tests
if __name__ == '__main__':
unittest.main()
class MockRaceConditionHandler:
def __init__(self, mem_hdlr):
self.mem_hdlr = mem_hdlr
+ self.threads = []
def removeTarget(self):
self.mem_hdlr.setTarget(None)
def handle(self, msg):
- t = threading.Thread(target=self.removeTarget)
- t.daemon = True
- t.start()
+ thread = threading.Thread(target=self.removeTarget)
+ self.threads.append(thread)
+ thread.start()
target = MockRaceConditionHandler(self.mem_hdlr)
- self.mem_hdlr.setTarget(target)
+ try:
+ self.mem_hdlr.setTarget(target)
- for _ in range(10):
- time.sleep(0.005)
- self.mem_logger.info("not flushed")
- self.mem_logger.warning("flushed")
+ for _ in range(10):
+ time.sleep(0.005)
+ self.mem_logger.info("not flushed")
+ self.mem_logger.warning("flushed")
+ finally:
+ for thread in target.threads:
+ support.join_thread(thread)
class ExceptionFormatter(logging.Formatter):
import os
from difflib import unified_diff
from io import StringIO
-from test.support import TESTFN, run_unittest, unlink
+from test.support import TESTFN, run_unittest, unlink, temp_dir, change_cwd
from contextlib import contextmanager
import profile
assert_python_ok('-m', self.profilermodule.__name__,
'-m', 'timeit', '-n', '1')
+ def test_output_file_when_changing_directory(self):
+ with temp_dir() as tmpdir, change_cwd(tmpdir):
+ os.mkdir('dest')
+ with open('demo.py', 'w') as f:
+ f.write('import os; os.chdir("dest")')
+
+ assert_python_ok(
+ '-m', self.profilermodule.__name__,
+ '-o', 'out.pstats',
+ 'demo.py',
+ )
+
+ self.assertTrue(os.path.exists('out.pstats'))
+
def regenerate_expected_output(filename, cls):
filename = filename.rstrip('co')
self.assertIn('pass2', funcs_called)
self.assertIn('pass3', funcs_called)
+ def test_SortKey_enum(self):
+ self.assertEqual(SortKey.FILENAME, 'filename')
+ self.assertNotEqual(SortKey.FILENAME, SortKey.CALLS)
+
if __name__ == "__main__":
unittest.main()
@test.support.requires_resource('network')
@test.support.system_must_validate_cert
- @unittest.skipUnless(sys.version_info[3] == 'final',
- 'only for released versions')
@unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"),
'need SSL support to download license')
def test_license_exists_at_url(self):
# string displayed by license in the absence of a LICENSE file.
url = license._Printer__data.split()[1]
req = urllib.request.Request(url, method='HEAD')
+ # Reset global urllib.request._opener
+ self.addCleanup(urllib.request.urlcleanup)
try:
with socket_helper.transient_internet(url):
with urllib.request.urlopen(req) as data:
glob = 42
some_var = 12
+some_non_assigned_global_var = 11
+some_assigned_global_var = 11
class Mine:
instance_var = 24
def spam(a, b, *var, **kw):
global bar
+ global some_assigned_global_var
+ some_assigned_global_var = 12
bar = 47
some_var = 10
x = 23
def test_lineno(self):
self.assertEqual(self.top.get_lineno(), 0)
- self.assertEqual(self.spam.get_lineno(), 12)
+ self.assertEqual(self.spam.get_lineno(), 14)
def test_function_info(self):
func = self.spam
self.assertEqual(sorted(func.get_parameters()), ["a", "b", "kw", "var"])
expected = ['a', 'b', 'internal', 'kw', 'other_internal', 'some_var', 'var', 'x']
self.assertEqual(sorted(func.get_locals()), expected)
- self.assertEqual(sorted(func.get_globals()), ["bar", "glob"])
+ self.assertEqual(sorted(func.get_globals()), ["bar", "glob", "some_assigned_global_var"])
self.assertEqual(self.internal.get_frees(), ("x",))
def test_globals(self):
self.assertFalse(self.internal.lookup("x").is_global())
self.assertFalse(self.Mine.lookup("instance_var").is_global())
self.assertTrue(self.spam.lookup("bar").is_global())
+ # Module-scope globals are both global and local
+ self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_global())
+ self.assertTrue(self.top.lookup("some_assigned_global_var").is_global())
def test_nonlocal(self):
self.assertFalse(self.spam.lookup("some_var").is_nonlocal())
def test_local(self):
self.assertTrue(self.spam.lookup("x").is_local())
self.assertFalse(self.spam.lookup("bar").is_local())
+ # Module-scope globals are both global and local
+ self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_local())
+ self.assertTrue(self.top.lookup("some_assigned_global_var").is_local())
def test_free(self):
self.assertTrue(self.internal.lookup("x").is_free())
top = symtable.symtable(code, "?", "exec")
self.assertIsNotNone(find_block(top, "\u017d"))
+ def test_symtable_repr(self):
+ self.assertEqual(str(self.top), "<SymbolTable for module ?>")
+ self.assertEqual(str(self.spam), "<Function SymbolTable for spam in ?>")
+
if __name__ == '__main__':
unittest.main()
import sys
import unittest
from collections import deque
-from contextlib import _GeneratorContextManager, contextmanager
+from contextlib import _GeneratorContextManager, contextmanager, nullcontext
class MockContextManager(_GeneratorContextManager):
self.assertEqual(blah.two, 2)
self.assertEqual(blah.three, 3)
+ def testWithExtendedTargets(self):
+ with nullcontext(range(1, 5)) as (a, *b, c):
+ self.assertEqual(a, 1)
+ self.assertEqual(b, [2, 3])
+ self.assertEqual(c, 4)
+
class ExitSwallowsExceptionTestCase(unittest.TestCase):
#self.assertEqual(c14n_roundtrip("<doc xmlns:x='http://example.com/x' xmlns='http://example.com/default'><b y:a1='1' xmlns='http://example.com/default' a3='3' xmlns:y='http://example.com/y' y:a2='2'/></doc>"),
#'<doc xmlns:x="http://example.com/x"><b xmlns:y="http://example.com/y" a3="3" y:a1="1" y:a2="2"></b></doc>')
+ # Namespace issues
+ xml = '<X xmlns="http://nps/a"><Y targets="abc,xyz"></Y></X>'
+ self.assertEqual(c14n_roundtrip(xml), xml)
+ xml = '<X xmlns="http://nps/a"><Y xmlns="http://nsp/b" targets="abc,xyz"></Y></X>'
+ self.assertEqual(c14n_roundtrip(xml), xml)
+ xml = '<X xmlns="http://nps/a"><Y xmlns:b="http://nsp/b" b:targets="abc,xyz"></Y></X>'
+ self.assertEqual(c14n_roundtrip(xml), xml)
+
def test_c14n_exclusion(self):
xml = textwrap.dedent("""\
<root xmlns:x="http://example.com/x">
self.assertEqual(zipf.comment, b"an updated comment")
# check that comments are correctly shortened in append mode
+ # and the file is indeed truncated
with zipfile.ZipFile(TESTFN,mode="w") as zipf:
zipf.comment = b"original comment that's longer"
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+ original_zip_size = os.path.getsize(TESTFN)
with zipfile.ZipFile(TESTFN,mode="a") as zipf:
zipf.comment = b"shorter comment"
+ self.assertTrue(original_zip_size > os.path.getsize(TESTFN))
with zipfile.ZipFile(TESTFN,mode="r") as zipf:
self.assertEqual(zipf.comment, b"shorter comment")
import importlib.metadata
import io
import json
-import lzma
import os
import pathlib
import pickle
from . import _support as test_support
from ._support import OS_ENV_LOCK, TZPATH_TEST_LOCK, ZoneInfoTestBase
+from test.support import import_module
+lzma = import_module('lzma')
py_zoneinfo, c_zoneinfo = test_support.get_modules()
try:
class EventType(str, enum.Enum):
KeyPress = '2'
- Key = KeyPress,
+ Key = KeyPress
KeyRelease = '3'
ButtonPress = '4'
- Button = ButtonPress,
+ Button = ButtonPress
ButtonRelease = '5'
Motion = '6'
Enter = '7'
Colormap = '32'
ClientMessage = '33' # undocumented
Mapping = '34' # undocumented
- VirtualEvent = '35', # undocumented
- Activate = '36',
- Deactivate = '37',
- MouseWheel = '38',
+ VirtualEvent = '35' # undocumented
+ Activate = '36'
+ Deactivate = '37'
+ MouseWheel = '38'
- def __str__(self):
- return self.name
+ __str__ = str.__str__
class Event:
'num', 'delta', 'focus',
'x', 'y', 'width', 'height')
return '<%s event%s>' % (
- self.type,
+ getattr(self.type, 'name', self.type),
''.join(' %s=%s' % (k, attrs[k]) for k in keys if k in attrs)
)
with self.assertRaises(tkinter.TclError):
root.clipboard_get()
+ def test_event_repr_defaults(self):
+ e = tkinter.Event()
+ e.serial = 12345
+ e.num = '??'
+ e.height = '??'
+ e.keycode = '??'
+ e.state = 0
+ e.time = 123456789
+ e.width = '??'
+ e.x = '??'
+ e.y = '??'
+ e.char = ''
+ e.keysym = '??'
+ e.keysym_num = '??'
+ e.type = '100'
+ e.widget = '??'
+ e.x_root = '??'
+ e.y_root = '??'
+ e.delta = 0
+ self.assertEqual(repr(e), '<100 event>')
+
+ def test_event_repr(self):
+ e = tkinter.Event()
+ e.serial = 12345
+ e.num = 3
+ e.focus = True
+ e.height = 200
+ e.keycode = 65
+ e.state = 0x30405
+ e.time = 123456789
+ e.width = 300
+ e.x = 10
+ e.y = 20
+ e.char = 'A'
+ e.send_event = True
+ e.keysym = 'Key-A'
+ e.keysym_num = ord('A')
+ e.type = tkinter.EventType.Configure
+ e.widget = '.text'
+ e.x_root = 1010
+ e.y_root = 1020
+ e.delta = -1
+ self.assertEqual(repr(e),
+ "<Configure event send_event=True"
+ " state=Shift|Control|Button3|0x30000"
+ " keysym=Key-A keycode=65 char='A'"
+ " num=3 delta=-1 focus=True"
+ " x=10 y=20 width=300 height=200>")
tests_gui = (MiscTest, )
def test_from(self):
widget = self.create()
- self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=float_round)
+ conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
+ self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
def test_label(self):
widget = self.create()
self._declared_ns_stack[-1].append((uri, prefix))
return f'{prefix}:{tag}' if prefix else tag, tag, uri
+ if not uri:
+ # As soon as a default namespace is defined,
+ # anything that has no namespace (and thus, no prefix) goes there.
+ return tag, tag, uri
+
raise ValueError(f'Namespace "{uri}" is not declared in scope')
def data(self, data):
centDirSize, centDirOffset, len(self._comment))
self.fp.write(endrec)
self.fp.write(self._comment)
+ if self.mode == "a":
+ self.fp.truncate()
self.fp.flush()
def _fpclose(self, fp):
),
),
dict(
- name="SQLite 3.32.3",
- url="https://sqlite.org/2020/sqlite-autoconf-3320300.tar.gz",
- checksum='2e3911a3c15e85c2f2d040154bbe5ce3',
+ name="SQLite 3.33.0",
+ url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz",
+ checksum='842a8a100d7b01b09e543deb2b7951dd',
extra_cflags=('-Os '
'-DSQLITE_ENABLE_FTS5 '
'-DSQLITE_ENABLE_FTS4 '
Peter Ingebretson
Tony Ingraldi
John Interrante
+Dean Inwood
Bob Ippolito
Roger Irwin
Atsuo Ishimoto
return obj;
}
+static PyObject *
+without_gc(PyObject *Py_UNUSED(self), PyObject *obj)
+{
+ PyTypeObject *tp = (PyTypeObject*)obj;
+ if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
+ return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj);
+ }
+ if (PyType_IS_GC(tp)) {
+ // Don't try this at home, kids:
+ tp->tp_flags -= Py_TPFLAGS_HAVE_GC;
+ tp->tp_free = PyObject_Del;
+ tp->tp_traverse = NULL;
+ tp->tp_clear = NULL;
+ }
+ assert(!PyType_IS_GC(tp));
+ Py_INCREF(obj);
+ return obj;
+}
+
static PyMethodDef ml;
static PyObject *
{"meth_fastcall", (PyCFunction)(void(*)(void))meth_fastcall, METH_FASTCALL},
{"meth_fastcall_keywords", (PyCFunction)(void(*)(void))meth_fastcall_keywords, METH_FASTCALL|METH_KEYWORDS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
+ {"without_gc", without_gc, METH_O},
{NULL, NULL} /* sentinel */
};
trace_t *trace = (trace_t *)value;
trace_t *trace2 = raw_malloc(sizeof(trace_t));
- if (traces2 == NULL) {
+ if (trace2 == NULL) {
return -1;
}
*trace2 = *trace;
_Py_IDENTIFIER(__bases__);
PyObject *bases;
- Py_ALLOW_RECURSION
(void)_PyObject_LookupAttrId(cls, &PyId___bases__, &bases);
- Py_END_ALLOW_RECURSION
if (bases != NULL && !PyTuple_Check(bases)) {
Py_DECREF(bases);
return NULL;
.tp_name = "types.GenericAlias",
.tp_doc = "Represent a PEP 585 generic type\n"
"\n"
- "E.g. for t = list[int], t.origin is list and t.args is (int,).",
+ "E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).",
.tp_basicsize = sizeof(gaobject),
.tp_dealloc = ga_dealloc,
.tp_repr = ga_repr,
if (m->m_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*) m);
}
+ // Dereference class before m_self: PyCFunction_GET_CLASS accesses
+ // PyMethodDef m_ml, which could be kept alive by m_self
+ Py_XDECREF(PyCFunction_GET_CLASS(m));
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
- Py_XDECREF(PyCFunction_GET_CLASS(m));
PyObject_GC_Del(m);
}
static int
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
{
+ Py_VISIT(PyCFunction_GET_CLASS(m));
Py_VISIT(m->m_self);
Py_VISIT(m->m_module);
- Py_VISIT(PyCFunction_GET_CLASS(m));
return 0;
}
slots = NULL;
/* Initialize tp_flags */
+ // All heap types need GC, since we can create a reference cycle by storing
+ // an instance on one of its parents:
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
- Py_TPFLAGS_BASETYPE;
- if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
- type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC;
/* Initialize essential fields */
type->tp_as_async = &et->as_async;
}
type->tp_dealloc = subtype_dealloc;
- /* Enable GC unless this class is not adding new instance variables and
- the base class did not use GC. */
- if ((base->tp_flags & Py_TPFLAGS_HAVE_GC) ||
- type->tp_basicsize > base->tp_basicsize)
- type->tp_flags |= Py_TPFLAGS_HAVE_GC;
-
/* Always override allocation strategy to use regular heap */
type->tp_alloc = PyType_GenericAlloc;
- if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
- type->tp_free = PyObject_GC_Del;
- type->tp_traverse = subtype_traverse;
- type->tp_clear = subtype_clear;
- }
- else
- type->tp_free = PyObject_Del;
+ type->tp_free = PyObject_GC_Del;
+ type->tp_traverse = subtype_traverse;
+ type->tp_clear = subtype_clear;
/* store type in class' cell if one is supplied */
cell = _PyDict_GetItemIdWithError(dict, &PyId___classcell__);
goto Undefined;
if (value < 0 || value > MAX_UNICODE) {
PyErr_Format(PyExc_TypeError,
- "character mapping must be in range(0x%lx)",
+ "character mapping must be in range(0x%x)",
(unsigned long)MAX_UNICODE + 1);
goto onError;
}
}
PyObject *t;
- Py_ALLOW_RECURSION
t = PyDict_SetDefault(interned, s, s);
- Py_END_ALLOW_RECURSION
if (t == NULL) {
PyErr_Clear();
return _res;
}
-// with_item: expression 'as' target &(',' | ')' | ':') | invalid_with_item | expression
+// with_item:
+// | expression 'as' star_target &(',' | ')' | ':')
+// | invalid_with_item
+// | expression
static withitem_ty
with_item_rule(Parser *p)
{
}
withitem_ty _res = NULL;
int _mark = p->mark;
- { // expression 'as' target &(',' | ')' | ':')
+ { // expression 'as' star_target &(',' | ')' | ':')
if (p->error_indicator) {
D(p->level--);
return NULL;
}
- D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+ D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
Token * _keyword;
expr_ty e;
expr_ty t;
&&
(_keyword = _PyPegen_expect_token(p, 520)) // token='as'
&&
- (t = target_rule(p)) // target
+ (t = star_target_rule(p)) // star_target
&&
_PyPegen_lookahead(1, _tmp_47_rule, p)
)
{
- D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+ D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
_res = _Py_withitem ( e , t , p -> arena );
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s with_item[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
}
{ // invalid_with_item
if (p->error_indicator) {
ERRBUF_APPEND(message[i]);
ERRBUF_APPEND("\n");
}
- errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */
- pathname_ob = PyUnicode_FromString(pathname);
- errbuf_ob = PyUnicode_FromString(errbuf);
- PyErr_SetImportError(errbuf_ob, NULL, pathname);
+ /* Subtract 1 from the length to trim off trailing newline */
+ errbuf_ob = PyUnicode_DecodeLocaleAndSize(errbuf, strlen(errbuf)-1, "surrogateescape");
+ if (errbuf_ob == NULL)
+ return;
+ pathname_ob = PyUnicode_DecodeFSDefault(pathname);
+ if (pathname_ob == NULL) {
+ Py_DECREF(errbuf_ob);
+ return;
+ }
+ PyErr_SetImportError(errbuf_ob, NULL, pathname_ob);
Py_DECREF(pathname_ob);
Py_DECREF(errbuf_ob);
return;
char buf[256];
PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s",
pathname);
- PyObject *buf_ob = PyUnicode_FromString(buf);
+ PyObject *buf_ob = PyUnicode_DecodeFSDefault(buf);
+ if (buf_ob == NULL)
+ return NULL;
PyObject *shortname_ob = PyUnicode_FromString(shortname);
- PyObject *pathname_ob = PyUnicode_FromString(pathname);
+ if (shortname_ob == NULL) {
+ Py_DECREF(buf_ob);
+ return NULL;
+ }
+ PyObject *pathname_ob = PyUnicode_DecodeFSDefault(pathname);
+ if (pathname_ob == NULL) {
+ Py_DECREF(buf_ob);
+ Py_DECREF(shortname_ob);
+ return NULL;
+ }
PyErr_SetImportError(buf_ob, shortname_ob, pathname_ob);
Py_DECREF(buf_ob);
Py_DECREF(shortname_ob);
const char *error = dlerror();
if (error == NULL)
error = "unknown dlopen() error";
- error_ob = PyUnicode_FromString(error);
+ error_ob = PyUnicode_DecodeLocale(error, "surrogateescape");
if (error_ob == NULL)
return NULL;
mod_name = PyUnicode_FromString(shortname);
Py_DECREF(error_ob);
return NULL;
}
- path = PyUnicode_FromString(pathname);
+ path = PyUnicode_DecodeFSDefault(pathname);
if (path == NULL) {
Py_DECREF(error_ob);
Py_DECREF(mod_name);
}
-/* Remove name from sys.modules, if it's there. */
+/* Remove name from sys.modules, if it's there.
+ * Can be called with an exception raised.
+ * If fail to remove name a new exception will be chained with the old
+ * exception, otherwise the old exception is preserved.
+ */
static void
remove_module(PyThreadState *tstate, PyObject *name)
{
_PyErr_Fetch(tstate, &type, &value, &traceback);
PyObject *modules = tstate->interp->modules;
- if (!PyMapping_HasKey(modules, name)) {
- goto out;
+ if (PyDict_CheckExact(modules)) {
+ PyObject *mod = _PyDict_Pop(modules, name, Py_None);
+ Py_XDECREF(mod);
}
- if (PyMapping_DelItem(modules, name) < 0) {
- _PyErr_SetString(tstate, PyExc_RuntimeError,
- "deleting key in sys.modules failed");
- _PyErr_ChainExceptions(type, value, traceback);
- return;
+ else if (PyMapping_DelItem(modules, name) < 0) {
+ if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
+ _PyErr_Clear(tstate);
+ }
}
-out:
- _PyErr_Restore(tstate, type, value, traceback);
+ _PyErr_ChainExceptions(type, value, traceback);
}
def iter_files(root, suffix=None, relparent=None, *,
- get_files=os.walk,
+ get_files=None,
_glob=glob_tree,
_walk=walk_tree,
):
if "relparent" is provided then it is used to resolve each
filename as a relative path.
"""
+ if get_files is None:
+ get_files = os.walk
if not isinstance(root, str):
roots = root
for root in roots:
# you want to build and link with a framework build of Tcl and Tk
# that is not in /Library/Frameworks, say, in your private
# $HOME/Library/Frameworks directory or elsewhere. It turns
- # out to be difficult to make that work automtically here
+ # out to be difficult to make that work automatically here
# without bringing into play more tools and magic. That case
- # can be hamdled using a recipe with the right arguments
+ # can be handled using a recipe with the right arguments
# to detect_tkinter_explicitly().
#
# Note also that the fallback case here is to try to use the
# be forewarned that they are deprecated by Apple and typically
# out-of-date and buggy; their use should be avoided if at
# all possible by installing a newer version of Tcl and Tk in
- # /Library/Frameworks before bwfore building Python without
+ # /Library/Frameworks before building Python without
# an explicit SDK or by configuring build arguments explicitly.
from os.path import join, exists
else:
# Use case #1: no explicit SDK selected.
# Search the local system-wide /Library/Frameworks,
- # not the one in the default SDK, othewise fall back to
+ # not the one in the default SDK, otherwise fall back to
# /System/Library/Frameworks whose header files may be in
# the default SDK or, on older systems, actually installed.
framework_dirs = [
if not exists(join(F, fw + '.framework')):
break
else:
- # ok, F is now directory with both frameworks. Continure
+ # ok, F is now directory with both frameworks. Continue
# building
break
else: