From 8a691475cfee9d66c4833aff9359bfea79298b02 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 26 Jan 2022 08:27:48 +0900 Subject: [PATCH] Imported Upstream version 3.9.6 --- Doc/c-api/complex.rst | 4 +- Doc/c-api/concrete.rst | 1 + Doc/c-api/gcsupport.rst | 12 + Doc/c-api/import.rst | 6 +- Doc/c-api/init_config.rst | 9 +- Doc/c-api/object.rst | 4 +- Doc/c-api/type.rst | 9 + Doc/c-api/typehints.rst | 46 + Doc/faq/design.rst | 9 + Doc/faq/gui.rst | 2 +- Doc/faq/programming.rst | 17 +- Doc/faq/windows.rst | 5 +- Doc/includes/sqlite3/countcursors.py | 17 - Doc/includes/sqlite3/createdb.py | 28 - Doc/includes/sqlite3/ctx_manager.py | 8 +- Doc/includes/sqlite3/execsql_fetchonerow.py | 19 - Doc/includes/sqlite3/execsql_printall_1.py | 15 - Doc/includes/sqlite3/execute_1.py | 13 +- Doc/includes/sqlite3/insert_more_people.py | 18 - Doc/includes/sqlite3/parse_colnames.py | 10 - Doc/includes/sqlite3/shared_cache.py | 6 - Doc/includes/sqlite3/shortcut_methods.py | 16 +- Doc/includes/sqlite3/simple_tableprinter.py | 28 - Doc/library/ast.rst | 9 +- Doc/library/asyncio-eventloop.rst | 4 +- Doc/library/asyncio-protocol.rst | 2 +- Doc/library/asyncio-task.rst | 23 +- Doc/library/atexit.rst | 15 +- Doc/library/cgi.rst | 8 +- Doc/library/collections.rst | 4 +- Doc/library/compileall.rst | 10 +- Doc/library/configparser.rst | 7 + Doc/library/contextlib.rst | 16 +- Doc/library/dataclasses.rst | 35 +- Doc/library/exceptions.rst | 11 +- Doc/library/ftplib.rst | 2 + Doc/library/functions.rst | 16 +- Doc/library/http.server.rst | 16 +- Doc/library/importlib.metadata.rst | 5 + Doc/library/importlib.rst | 4 +- Doc/library/inspect.rst | 8 +- Doc/library/numbers.rst | 11 +- Doc/library/os.rst | 10 +- Doc/library/resource.rst | 4 +- Doc/library/sqlite3.rst | 6 +- Doc/library/stdtypes.rst | 15 +- Doc/library/string.rst | 6 +- Doc/library/subprocess.rst | 8 +- Doc/library/threading.rst | 9 +- Doc/library/timeit.rst | 4 +- Doc/library/types.rst | 4 +- Doc/library/typing.rst | 16 +- Doc/library/unittest.mock.rst | 4 +- Doc/library/unittest.rst | 5 +- Doc/license.rst | 2 +- Doc/reference/expressions.rst | 2 + Doc/reference/simple_stmts.rst | 2 +- Doc/tools/susp-ignored.csv | 3 +- Doc/tools/templates/customsourcelink.html | 2 +- Doc/tutorial/controlflow.rst | 23 +- Doc/tutorial/errors.rst | 6 +- Doc/tutorial/inputoutput.rst | 3 +- Doc/tutorial/introduction.rst | 2 +- Doc/whatsnew/3.9.rst | 16 +- Grammar/python.gram | 13 +- Include/Python.h | 11 +- Include/internal/pycore_fileutils.h | 12 + Include/patchlevel.h | 4 +- Lib/_aix_support.py | 26 +- Lib/_strptime.py | 2 +- Lib/abc.py | 27 +- Lib/ast.py | 4 +- Lib/bdb.py | 2 +- Lib/bz2.py | 16 +- Lib/configparser.py | 5 +- Lib/dataclasses.py | 2 +- Lib/distutils/command/upload.py | 3 +- Lib/distutils/spawn.py | 14 +- Lib/distutils/tests/test_upload.py | 2 +- Lib/email/message.py | 4 +- Lib/ensurepip/__init__.py | 2 +- ...ne-any.whl => pip-21.1.3-py3-none-any.whl} | Bin 1547644 -> 1548027 bytes Lib/enum.py | 38 +- Lib/getpass.py | 2 +- Lib/glob.py | 9 +- Lib/gzip.py | 2 +- Lib/http/client.py | 38 +- Lib/http/server.py | 1 + Lib/idlelib/autocomplete_w.py | 58 +- Lib/idlelib/configdialog.py | 928 +++-- Lib/idlelib/help.html | 22 +- Lib/idlelib/idle_test/test_configdialog.py | 272 +- Lib/importlib/_bootstrap_external.py | 10 +- Lib/lzma.py | 16 +- Lib/numbers.py | 8 +- Lib/pathlib.py | 12 +- Lib/pdb.py | 38 +- Lib/pkgutil.py | 1 + Lib/pydoc_data/topics.py | 38 +- Lib/random.py | 3 +- Lib/shutil.py | 16 +- Lib/sqlite3/test/hooks.py | 2 +- Lib/subprocess.py | 2 +- Lib/test/datetimetester.py | 1 + Lib/test/support/__init__.py | 10 + Lib/test/test_abc.py | 18 + Lib/test/test_ast.py | 16 + Lib/test/test_asyncio/test_subprocess.py | 2 + Lib/test/test_asyncio/test_windows_utils.py | 3 +- Lib/test/test_bz2.py | 9 + Lib/test/test_capi.py | 4 +- Lib/test/test_codeop.py | 30 +- Lib/test/test_coroutines.py | 18 +- Lib/test/test_csv.py | 2 +- Lib/test/test_deque.py | 7 +- Lib/test/test_email/test_message.py | 7 + Lib/test/test_embed.py | 18 +- Lib/test/test_enum.py | 83 + Lib/test/test_exceptions.py | 1 + Lib/test/test_float.py | 8 +- Lib/test/test_heapq.py | 4 +- Lib/test/test_httplib.py | 15 +- Lib/test/test_httpservers.py | 1 + Lib/test/test_import/__init__.py | 4 +- Lib/test/test_importlib/test_spec.py | 4 +- Lib/test/test_linecache.py | 42 + Lib/test/test_lzma.py | 9 + Lib/test/test_pdb.py | 95 + Lib/test/test_pkgutil.py | 46 + Lib/test/test_random.py | 5 + Lib/test/test_set.py | 4 +- Lib/test/test_site.py | 6 +- Lib/test/test_socket.py | 3 +- Lib/test/test_ssl.py | 11 +- Lib/test/test_subprocess.py | 40 +- Lib/test/test_syntax.py | 41 +- Lib/test/test_threading.py | 27 +- Lib/test/test_unicode.py | 7 +- Lib/test/test_urlparse.py | 24 +- Lib/threading.py | 32 +- Lib/turtledemo/__main__.py | 44 +- Lib/typing.py | 7 + Lib/urllib/parse.py | 8 +- Makefile.pre.in | 2 +- Misc/ACKS | 2 + Misc/NEWS | 228 +- Modules/_collectionsmodule.c | 2 +- Modules/_decimal/_decimal.c | 3 +- Modules/_hashopenssl.c | 6 +- Modules/_sha3/sha3module.c | 5 + Modules/_testcapimodule.c | 34 + Modules/_threadmodule.c | 5 +- Modules/_tkinter.c | 17 +- Modules/expat/xmltok_ns.c | 2 +- Modules/getpath.c | 1 + Objects/dictobject.c | 12 +- Objects/longobject.c | 1 + Objects/structseq.c | 17 +- Objects/unicodeobject.c | 40 + PCbuild/pyproject.props | 4 +- Parser/asdl_c.py | 19 +- Parser/pegen/parse.c | 1512 +++---- Parser/pegen/pegen.c | 1 + Programs/_testembed.c | 58 +- Python/Python-ast.c | 700 ++++ Python/fileutils.c | 106 + Python/formatter_unicode.c | 10 +- Python/import.c | 3 + Python/importlib_external.h | 3659 +++++++++-------- Python/thread_nt.h | 14 +- README.rst | 8 +- Tools/scripts/patchcheck.py | 33 +- Tools/unittestgui/unittestgui.py | 1 - configure | 25 +- configure.ac | 25 +- pyconfig.h.in | 4 + 176 files changed, 5574 insertions(+), 4026 deletions(-) create mode 100644 Doc/c-api/typehints.rst delete mode 100644 Doc/includes/sqlite3/countcursors.py delete mode 100644 Doc/includes/sqlite3/createdb.py delete mode 100644 Doc/includes/sqlite3/execsql_fetchonerow.py delete mode 100644 Doc/includes/sqlite3/execsql_printall_1.py delete mode 100644 Doc/includes/sqlite3/insert_more_people.py delete mode 100644 Doc/includes/sqlite3/parse_colnames.py delete mode 100644 Doc/includes/sqlite3/shared_cache.py delete mode 100644 Doc/includes/sqlite3/simple_tableprinter.py rename Lib/ensurepip/_bundled/{pip-21.1.1-py3-none-any.whl => pip-21.1.3-py3-none-any.whl} (92%) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index e2ea766b..c2589468 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -46,9 +46,9 @@ pointers. This is consistent throughout the API. :c:type:`Py_complex` representation. -.. c:function:: Py_complex _Py_c_neg(Py_complex complex) +.. c:function:: Py_complex _Py_c_neg(Py_complex num) - Return the negation of the complex number *complex*, using the C + Return the negation of the complex number *num*, using the C :c:type:`Py_complex` representation. diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index c1d9fa1b..84224dcc 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -115,3 +115,4 @@ Other Objects coro.rst contextvars.rst datetime.rst + typehints.rst diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index eee114c1..f821b450 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -33,6 +33,18 @@ Constructors for container types must conform to two rules: #. Once all the fields which may contain references to other containers are initialized, it must call :c:func:`PyObject_GC_Track`. + .. warning:: + If a type adds the Py_TPFLAGS_HAVE_GC, then it *must* implement at least + a :c:member:`~PyTypeObject.tp_traverse` handler or explicitly use one + from its subclass or subclasses. + + When calling :c:func:`PyType_Ready` or some of the APIs that indirectly + call it like :c:func:`PyType_FromSpecWithBases` or + :c:func:`PyType_FromSpec` the interpreter will automatically populate the + :c:member:`~PyTypeObject.tp_flags`, :c:member:`~PyTypeObject.tp_traverse` + and :c:member:`~PyTypeObject.tp_clear` fields if the type inherits from a + class that implements the garbage collector protocol and the child class + does *not* include the :const:`Py_TPFLAGS_HAVE_GC` flag. .. c:function:: TYPE* PyObject_GC_New(TYPE, PyTypeObject *type) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index c6fc3307..d2ae6b6d 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -299,4 +299,8 @@ Importing Modules field; failure to provide the sentinel value can result in a memory fault. Returns ``0`` on success or ``-1`` if insufficient memory could be allocated to extend the internal table. In the event of failure, no modules are added to the - internal table. This should be called before :c:func:`Py_Initialize`. + internal table. This must be called before :c:func:`Py_Initialize`. + + If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or + :c:func:`PyImport_ExtendInittab` must be called before each Python + initialization. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index f2b82a0c..23009e41 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -730,9 +730,12 @@ Function to initialize Python: The caller is responsible to handle exceptions (error or exit) using :c:func:`PyStatus_Exception` and :c:func:`Py_ExitStatusException`. -If ``PyImport_FrozenModules``, ``PyImport_AppendInittab()`` or -``PyImport_ExtendInittab()`` are used, they must be set or called after Python -preinitialization and before the Python initialization. +If :c:func:`PyImport_FrozenModules`, :c:func:`PyImport_AppendInittab` or +:c:func:`PyImport_ExtendInittab` are used, they must be set or called after +Python preinitialization and before the Python initialization. If Python is +initialized multiple times, :c:func:`PyImport_AppendInittab` or +:c:func:`PyImport_ExtendInittab` must be called before each Python +initialization. Example setting the program name:: diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index a387b4a2..05faa723 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -311,12 +311,12 @@ Object Protocol returned. This is the equivalent to the Python expression ``len(o)``. -.. c:function:: Py_ssize_t PyObject_LengthHint(PyObject *o, Py_ssize_t default) +.. c:function:: Py_ssize_t PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) Return an estimated length for the object *o*. First try to return its actual length, then an estimate using :meth:`~object.__length_hint__`, and finally return the default value. On error return ``-1``. This is the - equivalent to the Python expression ``operator.length_hint(o, default)``. + equivalent to the Python expression ``operator.length_hint(o, defaultvalue)``. .. versionadded:: 3.4 diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index ee76f522..d7f4bd67 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -97,6 +97,15 @@ Type Objects from a type's base class. Return ``0`` on success, or return ``-1`` and sets an exception on error. + .. note:: + If some of the base classes implements the GC protocol and the provided + type does not include the :const:`Py_TPFLAGS_HAVE_GC` in its flags, then + the GC protocol will be automatically implemented from its parents. On + the contrary, if the type being created does include + :const:`Py_TPFLAGS_HAVE_GC` in its flags then it **must** implement the + GC protocol itself by at least implementing the + :c:member:`~PyTypeObject.tp_traverse` handle. + .. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot) Return the function pointer stored in the given slot. If the diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst new file mode 100644 index 00000000..2d1175f4 --- /dev/null +++ b/Doc/c-api/typehints.rst @@ -0,0 +1,46 @@ +.. highlight:: c + +.. _typehintobjects: + +Objects for Type Hinting +------------------------ + +Various built-in types for type hinting are provided. +Only :ref:`GenericAlias ` is exposed to C. + +.. c:function:: PyObject* Py_GenericAlias(PyObject *origin, PyObject *args) + + Create a :ref:`GenericAlias ` object. + Equivalent to calling the Python class + :class:`types.GenericAlias`. The *origin* and *args* arguments set the + ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. + *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a + :c:type:`PyTupleObject*` or any ``PyObject*``. If *args* passed is + not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set + to ``(args,)``. + Minimal checking is done for the arguments, so the function will succeed even + if *origin* is not a type. + The ``GenericAlias``\ 's ``__parameters__`` attribute is constructed lazily + from ``__args__``. On failure, an exception is raised and ``NULL`` is + returned. + + Here's an example of how to make an extension type generic:: + + ... + static PyMethodDef my_obj_methods[] = { + // Other methods. + ... + {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS, "See PEP 585"} + ... + } + + .. seealso:: The data model method :meth:`__class_getitem__`. + + .. versionadded:: 3.9 + +.. c:var:: PyTypeObject Py_GenericAliasType + + The C type of the object returned by :c:func:`Py_GenericAlias`. Equivalent to + :class:`types.GenericAlias` in Python. + + .. versionadded:: 3.9 diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 5c59fccc..d2b868eb 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -709,6 +709,15 @@ bindings are resolved at run-time in Python, and the second version only needs to perform the resolution once. +Why don't generators support the with statement? +------------------------------------------------ + +For technical reasons, a generator used directly as a context manager +would not work correctly. When, as is most common, a generator is used as +an iterator run to completion, no closing is needed. When it is, wrap +it as "contextlib.closing(generator)" in the 'with' statment. + + Why are colons required for the if/while/def/class statements? -------------------------------------------------------------- diff --git a/Doc/faq/gui.rst b/Doc/faq/gui.rst index 781da467..a322fa23 100644 --- a/Doc/faq/gui.rst +++ b/Doc/faq/gui.rst @@ -92,7 +92,7 @@ FLTK Python bindings for `the FLTK toolkit `_, a simple yet powerful and mature cross-platform windowing system, are available from `the -PyFLTK project `_. +PyFLTK project `_. OpenGL ------ diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index f0784f07..ad51bb6e 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -66,6 +66,8 @@ Static type checkers such as `Mypy `_, source code. +.. _faq-create-standalone-binary: + How can I create a stand-alone binary from a Python script? ----------------------------------------------------------- @@ -89,14 +91,15 @@ only contains those built-in modules which are actually used in the program. It then compiles the generated C code and links it with the rest of the Python interpreter to form a self-contained binary which acts exactly like your script. -Obviously, freeze requires a C compiler. There are several other utilities -which don't: - -* `py2exe `_ for Windows binaries -* `py2app `_ for Mac OS X binaries -* `cx_Freeze `_ for cross-platform - binaries +The following packages can help with the creation of console and GUI +executables: +* `Nuitka `_ (Cross-platform) +* `PyInstaller `_ (Cross-platform) +* `PyOxidizer `_ (Cross-platform) +* `cx_Freeze `_ (Cross-platform) +* `py2app `_ (macOS only) +* `py2exe `_ (Windows only) Are there coding standards or a style guide for Python programs? ---------------------------------------------------------------- diff --git a/Doc/faq/windows.rst b/Doc/faq/windows.rst index 186dac2e..0153a4f3 100644 --- a/Doc/faq/windows.rst +++ b/Doc/faq/windows.rst @@ -140,9 +140,8 @@ offender. How do I make an executable from a Python script? ------------------------------------------------- -See `cx_Freeze `_ and -`py2exe `_, both are distutils extensions -that allow you to create console and GUI executables from Python code. +See :ref:`faq-create-standalone-binary` for a list of tools that can be used to +make executables. Is a ``*.pyd`` file the same as a DLL? diff --git a/Doc/includes/sqlite3/countcursors.py b/Doc/includes/sqlite3/countcursors.py deleted file mode 100644 index 112f4770..00000000 --- a/Doc/includes/sqlite3/countcursors.py +++ /dev/null @@ -1,17 +0,0 @@ -import sqlite3 - -class CountCursorsConnection(sqlite3.Connection): - def __init__(self, *args, **kwargs): - sqlite3.Connection.__init__(self, *args, **kwargs) - self.numcursors = 0 - - def cursor(self, *args, **kwargs): - self.numcursors += 1 - return sqlite3.Connection.cursor(self, *args, **kwargs) - -con = sqlite3.connect(":memory:", factory=CountCursorsConnection) -cur1 = con.cursor() -cur2 = con.cursor() -print(con.numcursors) - -con.close() diff --git a/Doc/includes/sqlite3/createdb.py b/Doc/includes/sqlite3/createdb.py deleted file mode 100644 index ee2950bd..00000000 --- a/Doc/includes/sqlite3/createdb.py +++ /dev/null @@ -1,28 +0,0 @@ -# Not referenced from the documentation, but builds the database file the other -# code snippets expect. - -import sqlite3 -import os - -DB_FILE = "mydb" - -if os.path.exists(DB_FILE): - os.remove(DB_FILE) - -con = sqlite3.connect(DB_FILE) -cur = con.cursor() -cur.execute(""" - create table people - ( - name_last varchar(20), - age integer - ) - """) - -cur.execute("insert into people (name_last, age) values ('Yeltsin', 72)") -cur.execute("insert into people (name_last, age) values ('Putin', 51)") - -con.commit() - -cur.close() -con.close() diff --git a/Doc/includes/sqlite3/ctx_manager.py b/Doc/includes/sqlite3/ctx_manager.py index 6db77d45..2e1175ef 100644 --- a/Doc/includes/sqlite3/ctx_manager.py +++ b/Doc/includes/sqlite3/ctx_manager.py @@ -1,19 +1,19 @@ import sqlite3 con = sqlite3.connect(":memory:") -con.execute("create table person (id integer primary key, firstname varchar unique)") +con.execute("create table lang (id integer primary key, name varchar unique)") # Successful, con.commit() is called automatically afterwards with con: - con.execute("insert into person(firstname) values (?)", ("Joe",)) + con.execute("insert into lang(name) values (?)", ("Python",)) # con.rollback() is called after the with block finishes with an exception, the # exception is still raised and must be caught try: with con: - con.execute("insert into person(firstname) values (?)", ("Joe",)) + con.execute("insert into lang(name) values (?)", ("Python",)) except sqlite3.IntegrityError: - print("couldn't add Joe twice") + print("couldn't add Python twice") # Connection object used as context manager only commits or rollbacks transactions, # so the connection object should be closed manually diff --git a/Doc/includes/sqlite3/execsql_fetchonerow.py b/Doc/includes/sqlite3/execsql_fetchonerow.py deleted file mode 100644 index 115bcb50..00000000 --- a/Doc/includes/sqlite3/execsql_fetchonerow.py +++ /dev/null @@ -1,19 +0,0 @@ -import sqlite3 - -con = sqlite3.connect("mydb") - -cur = con.cursor() -SELECT = "select name_last, age from people order by age, name_last" - -# 1. Iterate over the rows available from the cursor, unpacking the -# resulting sequences to yield their elements (name_last, age): -cur.execute(SELECT) -for (name_last, age) in cur: - print('%s is %d years old.' % (name_last, age)) - -# 2. Equivalently: -cur.execute(SELECT) -for row in cur: - print('%s is %d years old.' % (row[0], row[1])) - -con.close() diff --git a/Doc/includes/sqlite3/execsql_printall_1.py b/Doc/includes/sqlite3/execsql_printall_1.py deleted file mode 100644 index 19306e6e..00000000 --- a/Doc/includes/sqlite3/execsql_printall_1.py +++ /dev/null @@ -1,15 +0,0 @@ -import sqlite3 - -# Create a connection to the database file "mydb": -con = sqlite3.connect("mydb") - -# Get a Cursor object that operates in the context of Connection con: -cur = con.cursor() - -# Execute the SELECT statement: -cur.execute("select * from people order by age") - -# Retrieve all rows as a sequence and print that sequence: -print(cur.fetchall()) - -con.close() diff --git a/Doc/includes/sqlite3/execute_1.py b/Doc/includes/sqlite3/execute_1.py index 42aad4d5..ee0000e2 100644 --- a/Doc/includes/sqlite3/execute_1.py +++ b/Doc/includes/sqlite3/execute_1.py @@ -2,22 +2,21 @@ import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() -cur.execute("create table lang (lang_name, lang_age)") +cur.execute("create table lang (name, first_appeared)") # This is the qmark style: -cur.execute("insert into lang values (?, ?)", ("C", 49)) +cur.execute("insert into lang values (?, ?)", ("C", 1972)) # The qmark style used with executemany(): lang_list = [ - ("Fortran", 64), - ("Python", 30), - ("Go", 11), + ("Fortran", 1957), + ("Python", 1991), + ("Go", 2009), ] cur.executemany("insert into lang values (?, ?)", lang_list) # And this is the named style: -cur.execute("select * from lang where lang_name=:name and lang_age=:age", - {"name": "C", "age": 49}) +cur.execute("select * from lang where first_appeared=:year", {"year": 1972}) print(cur.fetchall()) con.close() diff --git a/Doc/includes/sqlite3/insert_more_people.py b/Doc/includes/sqlite3/insert_more_people.py deleted file mode 100644 index 10cf9372..00000000 --- a/Doc/includes/sqlite3/insert_more_people.py +++ /dev/null @@ -1,18 +0,0 @@ -import sqlite3 - -con = sqlite3.connect("mydb") - -cur = con.cursor() - -newPeople = ( - ('Lebed' , 53), - ('Zhirinovsky' , 57), - ) - -for person in newPeople: - cur.execute("insert into people (name_last, age) values (?, ?)", person) - -# The changes will not be saved unless the transaction is committed explicitly: -con.commit() - -con.close() diff --git a/Doc/includes/sqlite3/parse_colnames.py b/Doc/includes/sqlite3/parse_colnames.py deleted file mode 100644 index 5f01dbfe..00000000 --- a/Doc/includes/sqlite3/parse_colnames.py +++ /dev/null @@ -1,10 +0,0 @@ -import sqlite3 -import datetime - -con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES) -cur = con.cursor() -cur.execute('select ? as "x [timestamp]"', (datetime.datetime.now(),)) -dt = cur.fetchone()[0] -print(dt, type(dt)) - -con.close() diff --git a/Doc/includes/sqlite3/shared_cache.py b/Doc/includes/sqlite3/shared_cache.py deleted file mode 100644 index 30e71c93..00000000 --- a/Doc/includes/sqlite3/shared_cache.py +++ /dev/null @@ -1,6 +0,0 @@ -import sqlite3 - -# The shared cache is only available in SQLite versions 3.3.3 or later -# See the SQLite documentation for details. - -sqlite3.enable_shared_cache(True) diff --git a/Doc/includes/sqlite3/shortcut_methods.py b/Doc/includes/sqlite3/shortcut_methods.py index 98a39411..48ea6fad 100644 --- a/Doc/includes/sqlite3/shortcut_methods.py +++ b/Doc/includes/sqlite3/shortcut_methods.py @@ -1,23 +1,23 @@ import sqlite3 -persons = [ - ("Hugo", "Boss"), - ("Calvin", "Klein") - ] +langs = [ + ("C++", 1985), + ("Objective-C", 1984), +] con = sqlite3.connect(":memory:") # Create the table -con.execute("create table person(firstname, lastname)") +con.execute("create table lang(name, first_appeared)") # Fill the table -con.executemany("insert into person(firstname, lastname) values (?, ?)", persons) +con.executemany("insert into lang(name, first_appeared) values (?, ?)", langs) # Print the table contents -for row in con.execute("select firstname, lastname from person"): +for row in con.execute("select name, first_appeared from lang"): print(row) -print("I just deleted", con.execute("delete from person").rowcount, "rows") +print("I just deleted", con.execute("delete from lang").rowcount, "rows") # close is not a shortcut method and it's not called automatically, # so the connection object should be closed manually diff --git a/Doc/includes/sqlite3/simple_tableprinter.py b/Doc/includes/sqlite3/simple_tableprinter.py deleted file mode 100644 index 148a1707..00000000 --- a/Doc/includes/sqlite3/simple_tableprinter.py +++ /dev/null @@ -1,28 +0,0 @@ -import sqlite3 - -FIELD_MAX_WIDTH = 20 -TABLE_NAME = 'people' -SELECT = 'select * from %s order by age, name_last' % TABLE_NAME - -con = sqlite3.connect("mydb") - -cur = con.cursor() -cur.execute(SELECT) - -# Print a header. -for fieldDesc in cur.description: - print(fieldDesc[0].ljust(FIELD_MAX_WIDTH), end=' ') -print() # Finish the header with a newline. -print('-' * 78) - -# For each row, print the value of each field left-justified within -# the maximum possible width of that field. -fieldIndices = range(len(cur.description)) -for row in cur: - for fieldIndex in fieldIndices: - fieldValue = str(row[fieldIndex]) - print(fieldValue.ljust(FIELD_MAX_WIDTH), end=' ') - - print() # Finish the row with a newline. - -con.close() diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index d13c7ef6..9328faf5 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -80,10 +80,11 @@ Node classes end_col_offset Instances of :class:`ast.expr` and :class:`ast.stmt` subclasses have - :attr:`lineno`, :attr:`col_offset`, :attr:`lineno`, and :attr:`col_offset` - attributes. The :attr:`lineno` and :attr:`end_lineno` are the first and - last line numbers of source text span (1-indexed so the first line is line 1) - and the :attr:`col_offset` and :attr:`end_col_offset` are the corresponding + :attr:`lineno`, :attr:`col_offset`, :attr:`end_lineno`, and + :attr:`end_col_offset` attributes. The :attr:`lineno` and + :attr:`end_lineno` are the first and last line numbers of the source + text span (1-indexed so the first line is line 1), and the + :attr:`col_offset` and :attr:`end_col_offset` are the corresponding UTF-8 byte offsets of the first and last tokens that generated the node. The UTF-8 offset is recorded because the parser uses UTF-8 internally. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index be43ca4a..66eb3fae 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -440,7 +440,7 @@ Opening network connections and *local_addr* should be specified. * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used - to bind the socket to locally. The *local_host* and *local_port* + to bind the socket locally. The *local_host* and *local_port* are looked up using ``getaddrinfo()``, similarly to *host* and *port*. * *ssl_handshake_timeout* is (for a TLS connection) the time in seconds @@ -518,7 +518,7 @@ Opening network connections Other arguments: * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used - to bind the socket to locally. The *local_host* and *local_port* + to bind the socket locally. The *local_host* and *local_port* are looked up using :meth:`getaddrinfo`. * *remote_addr*, if given, is a ``(remote_host, remote_port)`` tuple used diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 9dbd3ab4..8b67f4b8 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -683,7 +683,7 @@ factories passed to the :meth:`loop.create_datagram_endpoint` method. Subprocess Protocols -------------------- -Datagram Protocol instances should be constructed by protocol +Subprocess Protocol instances should be constructed by protocol factories passed to the :meth:`loop.subprocess_exec` and :meth:`loop.subprocess_shell` methods. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 201678b0..ca6e525e 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -293,6 +293,10 @@ Sleeping ``sleep()`` always suspends the current task, allowing other tasks to run. + Setting the delay to 0 provides an optimized path to allow other + tasks to run. This can be used by long-running functions to avoid + blocking the event loop for the full duration of the function call. + .. deprecated-removed:: 3.8 3.10 The *loop* parameter. @@ -360,32 +364,35 @@ Running Tasks Concurrently async def factorial(name, number): f = 1 for i in range(2, number + 1): - print(f"Task {name}: Compute factorial({i})...") + print(f"Task {name}: Compute factorial({number}), currently i={i}...") await asyncio.sleep(1) f *= i print(f"Task {name}: factorial({number}) = {f}") + return f async def main(): # Schedule three calls *concurrently*: - await asyncio.gather( + L = await asyncio.gather( factorial("A", 2), factorial("B", 3), factorial("C", 4), ) + print(L) asyncio.run(main()) # Expected output: # - # Task A: Compute factorial(2)... - # Task B: Compute factorial(2)... - # Task C: Compute factorial(2)... + # Task A: Compute factorial(2), currently i=2... + # Task B: Compute factorial(3), currently i=2... + # Task C: Compute factorial(4), currently i=2... # Task A: factorial(2) = 2 - # Task B: Compute factorial(3)... - # Task C: Compute factorial(3)... + # Task B: Compute factorial(3), currently i=3... + # Task C: Compute factorial(4), currently i=3... # Task B: factorial(3) = 6 - # Task C: Compute factorial(4)... + # Task C: Compute factorial(4), currently i=4... # Task C: factorial(4) = 24 + # [2, 6, 24] .. note:: If *return_exceptions* is False, cancelling gather() after it diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst index c2c058e4..e6fa33ac 100644 --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -39,7 +39,7 @@ internal error is detected, or when :func:`os._exit` is called. 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 + saved. After all exit handlers have had a chance to run, the last exception to be raised is re-raised. This function returns *func*, which makes it possible to use it as a @@ -73,7 +73,7 @@ automatically when the program terminates without relying on the application making an explicit call into this module at termination. :: try: - with open("counterfile") as infile: + with open('counterfile') as infile: _count = int(infile.read()) except FileNotFoundError: _count = 0 @@ -83,21 +83,22 @@ making an explicit call into this module at termination. :: _count = _count + n def savecounter(): - with open("counterfile", "w") as outfile: - outfile.write("%d" % _count) + with open('counterfile', 'w') as outfile: + outfile.write('%d' % _count) import atexit + atexit.register(savecounter) Positional and keyword arguments may also be passed to :func:`register` to be passed along to the registered function when it is called:: def goodbye(name, adjective): - print('Goodbye, %s, it was %s to meet you.' % (name, adjective)) + print('Goodbye %s, it was %s to meet you.' % (name, adjective)) import atexit - atexit.register(goodbye, 'Donny', 'nice') + atexit.register(goodbye, 'Donny', 'nice') # or: atexit.register(goodbye, adjective='nice', name='Donny') @@ -107,6 +108,6 @@ Usage as a :term:`decorator`:: @atexit.register def goodbye(): - print("You are now leaving the Python sector.") + print('You are now leaving the Python sector.') This only works with functions that can be called without arguments. diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst index e60a3f13..0c985c07 100644 --- a/Doc/library/cgi.rst +++ b/Doc/library/cgi.rst @@ -316,7 +316,7 @@ algorithms implemented in this module in other circumstances. .. function:: test() Robust test CGI script, usable as main program. Writes minimal HTTP headers and - formats all information provided to the script in HTML form. + formats all information provided to the script in HTML format. .. function:: print_environ() @@ -346,8 +346,8 @@ Caring about security .. index:: pair: CGI; security -There's one important rule: if you invoke an external program (via the -:func:`os.system` or :func:`os.popen` functions. or others with similar +There's one important rule: if you invoke an external program (via +:func:`os.system`, :func:`os.popen` or other functions with similar functionality), make very sure you don't pass arbitrary strings received from the client to the shell. This is a well-known security hole whereby clever hackers anywhere on the Web can exploit a gullible CGI script to invoke @@ -424,7 +424,7 @@ above on installing your CGI script carefully can save you a lot of time. If you wonder whether you have understood the installation procedure correctly, try installing a copy of this module file (:file:`cgi.py`) as a CGI script. When invoked as a script, the file will dump its environment and the contents of the -form in HTML form. Give it the right mode etc, and send it a request. If it's +form in HTML format. Give it the right mode etc., and send it a request. If it's installed in the standard :file:`cgi-bin` directory, it should be possible to send it a request by entering a URL into your browser of the form: diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 4dc1b9fc..5189a2e8 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -685,9 +685,9 @@ stack manipulations such as ``dup``, ``drop``, ``swap``, ``over``, ``pick``, :class:`defaultdict` objects ---------------------------- -.. class:: defaultdict([default_factory[, ...]]) +.. class:: defaultdict(default_factory=None, /, [...]) - Returns a new dictionary-like object. :class:`defaultdict` is a subclass of the + Return a new dictionary-like object. :class:`defaultdict` is a subclass of the built-in :class:`dict` class. It overrides one method and adds one writable instance variable. The remaining functionality is the same as for the :class:`dict` class and is not documented here. diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index 5c6e68f9..de34664a 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -166,9 +166,10 @@ Public functions If *force* is true, modules are re-compiled even if the timestamps are up to date. - If *rx* is given, its search method is called on the complete path to each + If *rx* is given, its ``search`` method is called on the complete path to each file considered for compilation, and if it returns a true value, the file - is skipped. + is skipped. This can be used to exclude files matching a regular expression, + given as a :ref:`re.Pattern ` object. If *quiet* is ``False`` or ``0`` (the default), the filenames and other information are printed to standard out. Set to ``1``, only errors are @@ -242,9 +243,10 @@ Public functions cases where the source file does not exist at the time the byte-code file is executed. - If *rx* is given, its search method is passed the full path name to the + If *rx* is given, its ``search`` method is passed the full path name to the file being compiled, and if it returns a true value, the file is not - compiled and ``True`` is returned. + compiled and ``True`` is returned. This can be used to exclude files matching + a regular expression, given as a :ref:`re.Pattern ` object. If *quiet* is ``False`` or ``0`` (the default), the filenames and other information are printed to standard out. Set to ``1``, only errors are diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 2e22a549..730d1df9 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1129,6 +1129,13 @@ ConfigParser Objects *space_around_delimiters* is true, delimiters between keys and values are surrounded by spaces. + .. note:: + + Comments in the original configuration file are not preserved when + writing the configuration back. + What is considered a comment, depends on the given values for + *comment_prefix* and *inline_comment_prefix*. + .. method:: remove_option(section, option) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 4c6c5207..f87ee210 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -191,8 +191,9 @@ Functions and classes provided: .. function:: suppress(*exceptions) Return a context manager that suppresses any of the specified exceptions - if they occur in the body of a with statement and then resumes execution - with the first statement following the end of the with statement. + if they occur in the body of a :keyword:`!with` statement and then + resumes execution with the first statement following the end of the + :keyword:`!with` statement. As with any other mechanism that completely suppresses exceptions, this context manager should be used only to cover very specific errors where @@ -236,10 +237,11 @@ Functions and classes provided: For example, the output of :func:`help` normally is sent to *sys.stdout*. You can capture that output in a string by redirecting the output to an - :class:`io.StringIO` object:: + :class:`io.StringIO` object. The replacement stream is returned from the + ``__enter__`` method and so is available as the target of the + :keyword:`with` statement:: - f = io.StringIO() - with redirect_stdout(f): + with redirect_stdout(io.StringIO()) as f: help(pow) s = f.getvalue() @@ -463,7 +465,7 @@ Functions and classes provided: The :meth:`close` method is not implemented, :meth:`aclose` must be used instead. - .. method:: enter_async_context(cm) + .. coroutinemethod:: enter_async_context(cm) Similar to :meth:`enter_context` but expects an asynchronous context manager. @@ -477,7 +479,7 @@ Functions and classes provided: Similar to :meth:`callback` but expects a coroutine function. - .. method:: aclose() + .. coroutinemethod:: aclose() Similar to :meth:`close` but properly handles awaitables. diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 87111915..b226cda4 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -17,7 +17,7 @@ adding generated :term:`special method`\s such as :meth:`__init__` and in :pep:`557`. The member variables to use in these generated methods are defined -using :pep:`526` type annotations. For example this code:: +using :pep:`526` type annotations. For example, this code:: from dataclasses import dataclass @@ -31,7 +31,7 @@ using :pep:`526` type annotations. For example this code:: def total_cost(self) -> float: return self.unit_price * self.quantity_on_hand -Will add, among other things, a :meth:`__init__` that looks like:: +will add, among other things, a :meth:`__init__` that looks like:: def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0): self.name = name @@ -52,7 +52,7 @@ Module-level decorators, classes, and functions :term:`special method`\s to classes, as described below. The :func:`dataclass` decorator examines the class to find - ``field``\s. A ``field`` is defined as class variable that has a + ``field``\s. A ``field`` is defined as a class variable that has a :term:`type annotation `. With two exceptions described below, nothing in :func:`dataclass` examines the type specified in the variable annotation. @@ -62,8 +62,8 @@ Module-level decorators, classes, and functions The :func:`dataclass` decorator will add various "dunder" methods to the class, described below. If any of the added methods already - exist on the class, the behavior depends on the parameter, as documented - below. The decorator returns the same class that is called on; no new + exist in the class, the behavior depends on the parameter, as documented + below. The decorator returns the same class that it is called on; no new class is created. If :func:`dataclass` is used just as a simple decorator with no parameters, @@ -175,7 +175,7 @@ Module-level decorators, classes, and functions def __init__(self, a: int, b: int = 0): :exc:`TypeError` will be raised if a field without a default value - follows a field with a default value. This is true either when this + follows a field with a default value. This is true whether this occurs in a single class, or as a result of class inheritance. .. function:: field(*, default=MISSING, default_factory=MISSING, repr=True, hash=None, init=True, compare=True, metadata=None) @@ -361,7 +361,7 @@ Module-level decorators, classes, and functions .. function:: replace(instance, /, **changes) - Creates a new object of the same type of ``instance``, replacing + Creates a new object of the same type as ``instance``, replacing fields with values from ``changes``. If ``instance`` is not a Data Class, raises :exc:`TypeError`. If values in ``changes`` do not specify fields, raises :exc:`TypeError`. @@ -422,6 +422,27 @@ depend on one or more other fields. For example:: def __post_init__(self): self.c = self.a + self.b +The :meth:`__init__` method generated by :func:`dataclass` does not call base +class :meth:`__init__` methods. If the base class has an :meth:`__init__` method +that has to be called, it is common to call this method in a +:meth:`__post_init__` method:: + + @dataclass + class Rectangle: + height: float + width: float + + @dataclass + class Square(Rectangle): + side: float + + def __post_init__(self): + super().__init__(self.side, self.side) + +Note, however, that in general the dataclass-generated :meth:`__init__` methods +don't need to be called, since the derived dataclass will take care of +initializing all fields of any base class that is a dataclass itself. + See the section below on init-only variables for ways to pass parameters to :meth:`__post_init__`. Also see the warning about how :func:`replace` handles ``init=False`` fields. diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 7170b2c2..6bed5c70 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -390,14 +390,16 @@ The following exceptions are the exceptions that are usually raised. .. versionadded:: 3.5 -.. exception:: SyntaxError +.. exception:: SyntaxError(message, details) Raised when the parser encounters a syntax error. This may occur in an - :keyword:`import` statement, in a call to the built-in functions :func:`exec` + :keyword:`import` statement, in a call to the built-in functions + :func:`compile`, :func:`exec`, or :func:`eval`, or when reading the initial script or standard input (also interactively). The :func:`str` of the exception instance returns only the error message. + Details is a tuple whose members are also available as separate attributes. .. attribute:: filename @@ -417,6 +419,11 @@ The following exceptions are the exceptions that are usually raised. The source code text involved in the error. + For errors in f-string fields, the message is prefixed by "f-string: " + and the offsets are offsets in a text constructed from the replacement + expression. For example, compiling f'Bad {a b} field' results in this + args attribute: ('f-string: ...', ('', 1, 4, '(a b)\n')). + .. exception:: IndentationError diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index f4d4cdf9..3a9165ac 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -28,6 +28,7 @@ Here's a sample session using the :mod:`ftplib` module:: >>> ftp.login() # user anonymous, passwd anonymous@ '230 Login successful.' >>> ftp.cwd('debian') # change into "debian" directory + '250 Directory successfully changed.' >>> ftp.retrlines('LIST') # list directory contents -rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18 README ... @@ -39,6 +40,7 @@ Here's a sample session using the :mod:`ftplib` module:: >>> ftp.retrbinary('RETR README', fp.write) '226 Transfer complete.' >>> ftp.quit() + '221 Goodbye.' The module defines the following items: diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 3a222b1e..784bb62e 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -676,6 +676,13 @@ are always available. They are listed here in alphabetical order. ``x.foobar``. If the named attribute does not exist, *default* is returned if provided, otherwise :exc:`AttributeError` is raised. + .. note:: + + Since :ref:`private name mangling ` happens at + compilation time, one must manually mangle a private attribute's + (attributes with two leading underscores) name in order to retrieve it with + :func:`getattr`. + .. function:: globals() @@ -957,7 +964,7 @@ are always available. They are listed here in alphabetical order. .. _func-memoryview: -.. class:: memoryview(obj) +.. class:: memoryview(object) :noindex: Return a "memory view" object created from the given argument. See @@ -1495,6 +1502,13 @@ are always available. They are listed here in alphabetical order. object allows it. For example, ``setattr(x, 'foobar', 123)`` is equivalent to ``x.foobar = 123``. + .. note:: + + Since :ref:`private name mangling ` happens at + compilation time, one must manually mangle a private attribute's + (attributes with two leading underscores) name in order to set it with + :func:`setattr`. + .. class:: slice(stop) slice(start, stop[, step]) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 729d7e37..029e9ec5 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -320,9 +320,16 @@ provides three different variants: .. class:: SimpleHTTPRequestHandler(request, client_address, server, directory=None) - This class serves files from the current directory and below, directly + This class serves files from the directory *directory* and below, + or the current directory if *directory* is not provided, directly mapping the directory structure to HTTP requests. + .. versionadded:: 3.7 + The *directory* parameter. + + .. versionchanged:: 3.9 + The *directory* parameter accepts a :term:`path-like object`. + A lot of the work, such as parsing the request, is done by the base class :class:`BaseHTTPRequestHandler`. This class implements the :func:`do_GET` and :func:`do_HEAD` functions. @@ -345,13 +352,6 @@ provides three different variants: This dictionary is no longer filled with the default system mappings, but only contains overrides. - .. attribute:: directory - - If not specified, the directory to serve is the current working directory. - - .. versionchanged:: 3.9 - Accepts a :term:`path-like object`. - The :class:`SimpleHTTPRequestHandler` class defines the following methods: .. method:: do_HEAD() diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 2c8d7f81..9bf34047 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -4,6 +4,11 @@ Using :mod:`!importlib.metadata` ================================= +.. module:: importlib.metadata + :synopsis: The implementation of the importlib metadata. + +**Source code:** :source:`Lib/importlib/metadata.py` + .. versionadded:: 3.8 .. note:: diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 61a81e02..736c43d9 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -481,7 +481,7 @@ ABC hierarchy:: .. class:: ResourceReader - *Superseded by TraversableReader* + *Superseded by TraversableResources* An :term:`abstract base class` to provide the ability to read *resources*. @@ -806,7 +806,7 @@ ABC hierarchy:: .. versionadded:: 3.9 -.. class:: TraversableReader +.. class:: TraversableResources An abstract base class for resource readers capable of serving the ``files`` interface. Subclasses ResourceReader and provides diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index b53a9421..d1e4a9b5 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -809,10 +809,10 @@ function. >>> str(param.replace(default=Parameter.empty, annotation='spam')) "foo:'spam'" - .. versionchanged:: 3.4 - In Python 3.3 Parameter objects were allowed to have ``name`` set - to ``None`` if their ``kind`` was set to ``POSITIONAL_ONLY``. - This is no longer permitted. + .. versionchanged:: 3.4 + In Python 3.3 Parameter objects were allowed to have ``name`` set + to ``None`` if their ``kind`` was set to ``POSITIONAL_ONLY``. + This is no longer permitted. .. class:: BoundArguments diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst index 1b594952..b77845ed 100644 --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -10,7 +10,7 @@ The :mod:`numbers` module (:pep:`3141`) defines a hierarchy of numeric :term:`abstract base classes ` which progressively define -more operations. None of the types defined in this module can be instantiated. +more operations. None of the types defined in this module are intended to be instantiated. .. class:: Number @@ -27,8 +27,8 @@ The numeric tower Subclasses of this type describe complex numbers and include the operations that work on the built-in :class:`complex` type. These are: conversions to :class:`complex` and :class:`bool`, :attr:`.real`, :attr:`.imag`, ``+``, - ``-``, ``*``, ``/``, :func:`abs`, :meth:`conjugate`, ``==``, and ``!=``. All - except ``-`` and ``!=`` are abstract. + ``-``, ``*``, ``/``, ``**``, :func:`abs`, :meth:`conjugate`, ``==``, and + ``!=``. All except ``-`` and ``!=`` are abstract. .. attribute:: real @@ -76,8 +76,9 @@ The numeric tower Subtypes :class:`Rational` and adds a conversion to :class:`int`. Provides defaults for :func:`float`, :attr:`~Rational.numerator`, and - :attr:`~Rational.denominator`. Adds abstract methods for ``**`` and - bit-string operations: ``<<``, ``>>``, ``&``, ``^``, ``|``, ``~``. + :attr:`~Rational.denominator`. Adds abstract methods for :func:`pow` with + modulus and bit-string operations: ``<<``, ``>>``, ``&``, ``^``, ``|``, + ``~``. Notes for type implementors diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 1198c4af..2295ffc8 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3965,12 +3965,12 @@ written in Python, such as a mail server's external command delivery program. the Standard C function :c:func:`system`, and has the same limitations. Changes to :data:`sys.stdin`, etc. are not reflected in the environment of the executed command. If *command* generates any output, it will be sent to - the interpreter standard output stream. + the interpreter standard output stream. The C standard does not + specify the meaning of the return value of the C function, so the return + value of the Python function is system-dependent. On Unix, the return value is the exit status of the process encoded in the - format specified for :func:`wait`. Note that POSIX does not specify the - meaning of the return value of the C :c:func:`system` function, so the return - value of the Python function is system-dependent. + format specified for :func:`wait`. On Windows, the return value is that returned by the system shell after running *command*. The shell is given by the Windows environment variable @@ -4389,7 +4389,7 @@ operating system. .. function:: sched_setparam(pid, param) - Set a scheduling parameters for the process with PID *pid*. A *pid* of 0 means + Set the scheduling parameters for the process with PID *pid*. A *pid* of 0 means the calling process. *param* is a :class:`sched_param` instance. diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index e4eac436..c8c1348b 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -241,7 +241,9 @@ platform. The maximum size (in bytes) of the swap space that may be reserved or used by all of this user id's processes. This limit is enforced only if bit 1 of the vm.overcommit sysctl is set. - Please see :manpage:`tuning(7)` for a complete description of this sysctl. + Please see + `tuning(7) `__ + for a complete description of this sysctl. .. availability:: FreeBSD 9 or later. diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index a82ba3a5..4ae4b4dc 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -635,7 +635,8 @@ Cursor Objects This is a nonstandard convenience method for executing multiple SQL statements at once. It issues a ``COMMIT`` statement first, then executes the SQL script it - gets as a parameter. + gets as a parameter. This method disregards :attr:`isolation_level`; any + transation control must be added to *sql_script*. *sql_script* can be an instance of :class:`str`. @@ -1038,6 +1039,9 @@ setting :attr:`isolation_level` to ``None``. This will leave the underlying control the transaction state by explicitly issuing ``BEGIN``, ``ROLLBACK``, ``SAVEPOINT``, and ``RELEASE`` statements in your code. +Note that :meth:`~Cursor.executescript` disregards +:attr:`isolation_level`; any transaction control must be added explicitly. + .. versionchanged:: 3.6 :mod:`sqlite3` used to implicitly commit an open transaction before DDL statements. This is no longer the case. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 8a03b73b..acaf99b7 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -3609,17 +3609,16 @@ Memory Views of an object that supports the :ref:`buffer protocol ` without copying. -.. class:: memoryview(obj) +.. class:: memoryview(object) - Create a :class:`memoryview` that references *obj*. *obj* must support the - buffer protocol. Built-in objects that support the buffer protocol include - :class:`bytes` and :class:`bytearray`. + Create a :class:`memoryview` that references *object*. *object* must + support the buffer protocol. Built-in objects that support the buffer + protocol include :class:`bytes` and :class:`bytearray`. A :class:`memoryview` has the notion of an *element*, which is the - atomic memory unit handled by the originating object *obj*. For many - simple types such as :class:`bytes` and :class:`bytearray`, an element - is a single byte, but other types such as :class:`array.array` may have - bigger elements. + atomic memory unit handled by the originating *object*. For many simple + types such as :class:`bytes` and :class:`bytearray`, an element is a single + byte, but other types such as :class:`array.array` may have bigger elements. ``len(view)`` is equal to the length of :class:`~memoryview.tolist`. If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length diff --git a/Doc/library/string.rst b/Doc/library/string.rst index e55884d2..d1bdf434 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -386,8 +386,8 @@ The ``'#'`` option causes the "alternate form" to be used for the conversion. The alternate form is defined differently for different types. This option is only valid for integer, float and complex types. For integers, when binary, octal, or hexadecimal output -is used, this option adds the prefix respective ``'0b'``, ``'0o'``, or -``'0x'`` to the output value. For float and complex the +is used, this option adds the respective prefix ``'0b'``, ``'0o'``, +``'0x'``, or ``'0X'`` to the output value. For float and complex the alternate form causes the result of the conversion to always contain a decimal-point character, even if no digits follow it. Normally, a decimal-point character appears in the result of these conversions @@ -463,6 +463,8 @@ The available integer presentation types are: +---------+----------------------------------------------------------+ | ``'X'`` | Hex format. Outputs the number in base 16, using | | | upper-case letters for the digits above 9. | + | | In case ``'#'`` is specified, the prefix ``'0x'`` will | + | | be upper-cased to ``'0X'`` as well. | +---------+----------------------------------------------------------+ | ``'n'`` | Number. This is the same as ``'d'``, except that it uses | | | the current locale setting to insert the appropriate | diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 3150aa60..762da9b1 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -1268,11 +1268,17 @@ Replacing :func:`os.system` sts = os.system("mycmd" + " myarg") # becomes - sts = call("mycmd" + " myarg", shell=True) + retcode = call("mycmd" + " myarg", shell=True) Notes: * Calling the program through the shell is usually not required. +* The :func:`call` return value is encoded differently to that of + :func:`os.system`. + +* The :func:`os.system` function ignores SIGINT and SIGQUIT signals while + the command is running, but the caller must do this separately when + using the :mod:`subprocess` module. A more realistic example would look like this:: diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 2a42018b..894bbb11 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -110,10 +110,11 @@ This module defines the following functions: .. function:: enumerate() - Return a list of all :class:`Thread` objects currently alive. The list - includes daemonic threads, dummy thread objects created by - :func:`current_thread`, and the main thread. It excludes terminated threads - and threads that have not yet been started. + Return a list of all :class:`Thread` objects currently active. The list + includes daemonic threads and dummy thread objects created by + :func:`current_thread`. It excludes terminated threads and threads + that have not yet been started. However, the main thread is always part + of the result, even when terminated. .. function:: main_thread() diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index 668fcb86..d4e8b749 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -15,8 +15,8 @@ This module provides a simple way to time small bits of Python code. It has both a :ref:`timeit-command-line-interface` as well as a :ref:`callable ` one. It avoids a number of common traps for measuring execution times. -See also Tim Peters' introduction to the "Algorithms" chapter in the *Python -Cookbook*, published by O'Reilly. +See also Tim Peters' introduction to the "Algorithms" chapter in the second +edition of *Python Cookbook*, published by O'Reilly. Basic Examples diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 83e2cb4c..81a2b7b9 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -264,8 +264,8 @@ Standard names are defined for the following types: .. attribute:: __spec__ - A record of the the module's import-system-related state. Expected to be - an instance of :class:`importlib.machinery.ModuleSpec`. + A record of the module's import-system-related state. Expected to be an + instance of :class:`importlib.machinery.ModuleSpec`. .. versionadded:: 3.4 diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index b136da00..78ab760d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -656,10 +656,10 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.8 .. versionchanged:: 3.9.1 - ``Literal`` now de-duplicates parameters. Equality comparison of + ``Literal`` now de-duplicates parameters. Equality comparisons of ``Literal`` objects are no longer order dependent. ``Literal`` objects will now raise a :exc:`TypeError` exception during equality comparisons - if one of their parameters are not :term:`immutable`. + if one of their parameters are not :term:`hashable`. .. data:: ClassVar @@ -1179,7 +1179,11 @@ Other concrete types Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` and ``BinaryIO(IO[bytes])`` represent the types of I/O streams such as returned by - :func:`open`. These types are also in the ``typing.io`` namespace. + :func:`open`. + + .. deprecated-removed:: 3.8 3.12 + These types are also in the ``typing.io`` namespace, which was + never supported by type checkers and will be removed. .. class:: Pattern Match @@ -1189,7 +1193,11 @@ Other concrete types :func:`re.match`. These types (and the corresponding functions) are generic in ``AnyStr`` and can be made specific by writing ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or - ``Match[bytes]``. These types are also in the ``typing.re`` namespace. + ``Match[bytes]``. + + .. deprecated-removed:: 3.8 3.12 + These types are also in the ``typing.re`` namespace, which was + never supported by type checkers and will be removed. .. deprecated:: 3.9 Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 9e73ec32..b3e71705 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -327,8 +327,8 @@ the *new_callable* argument to :func:`patch`. .. method:: assert_called_once_with(*args, **kwargs) - Assert that the mock was called exactly once and that that call was - with the specified arguments. + Assert that the mock was called exactly once and that call was with the + specified arguments. >>> mock = Mock(return_value=None) >>> mock('foo', bar='baz') diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 9541997e..392cd247 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -597,8 +597,9 @@ The following decorators and exception implement test skipping and expected fail .. decorator:: expectedFailure Mark the test as an expected failure or error. If the test fails or errors - it will be considered a success. If the test passes, it will be considered - a failure. + in the test function itself (rather than in one of the :dfn:`test fixture` + methods) then it will be considered a success. If the test passes, it will + be considered a failure. .. exception:: SkipTest(reason) diff --git a/Doc/license.rst b/Doc/license.rst index f487d98b..d459ff66 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -955,7 +955,7 @@ W3C C14N test suite The C14N 2.0 test suite in the :mod:`test` package (``Lib/test/xmltestdata/c14n-20/``) was retrieved from the W3C website at https://www.w3.org/TR/xml-c14n2-testcases/ and is distributed under the -3-clause BSD license: +3-clause BSD license:: Copyright (c) 2013 W3C(R) (MIT, ERCIM, Keio, Beihang), All Rights Reserved. diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 8fead33e..51fa750d 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -77,6 +77,8 @@ When the name is bound to an object, evaluation of the atom yields that object. When a name is not bound, an attempt to evaluate it raises a :exc:`NameError` exception. +.. _private-name-mangling: + .. index:: pair: name; mangling pair: private; names diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 8691cbd0..fcca12dc 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -734,7 +734,7 @@ The :keyword:`!import` statement : ("," `identifier` ["as" `identifier`])* : | "from" `relative_module` "import" "(" `identifier` ["as" `identifier`] : ("," `identifier` ["as" `identifier`])* [","] ")" - : | "from" `module` "import" "*" + : | "from" `relative_module` "import" "*" module: (`identifier` ".")* `identifier` relative_module: "."* `module` | "."+ diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 95277c44..ad5f55e8 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -211,8 +211,7 @@ library/smtplib,,:port,method must support that as well as a regular host:port library/socket,,::,'5aef:2b::8' library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" library/socket,,:len,fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) -library/sqlite3,,:name,"cur.execute(""select * from lang where lang_name=:name and lang_age=:age""," -library/sqlite3,,:age,"cur.execute(""select * from lang where lang_name=:name and lang_age=:age""," +library/sqlite3,,:year,"cur.execute(""select * from lang where first_appeared=:year"", {""year"": 1972})" library/sqlite3,,:memory, library/sqlite3,,:path,"db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)" library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" diff --git a/Doc/tools/templates/customsourcelink.html b/Doc/tools/templates/customsourcelink.html index fca44e91..21af621e 100644 --- a/Doc/tools/templates/customsourcelink.html +++ b/Doc/tools/templates/customsourcelink.html @@ -4,7 +4,7 @@
  • {% trans %}Report a Bug{% endtrans %}
  • - {{ _('Show Source') }}
  • diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 284b68c0..129ab21c 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -104,14 +104,14 @@ The given end point is never part of the generated sequence; ``range(10)`` gener is possible to let the range start at another number, or to specify a different increment (even negative; sometimes this is called the 'step'):: - range(5, 10) - 5, 6, 7, 8, 9 + >>> list(range(5, 10)) + [5, 6, 7, 8, 9] - range(0, 10, 3) - 0, 3, 6, 9 + >>> list(range(0, 10, 3)) + [0, 3, 6, 9] - range(-10, -100, -30) - -10, -40, -70 + >>> list(range(-10, -100, -30)) + [-10, -40, -70] To iterate over the indices of a sequence, you can combine :func:`range` and :func:`len` as follows:: @@ -131,7 +131,7 @@ function, see :ref:`tut-loopidioms`. A strange thing happens if you just print a range:: - >>> print(range(10)) + >>> range(10) range(0, 10) In many ways the object returned by :func:`range` behaves as if it is a list, @@ -149,13 +149,7 @@ that takes an iterable is :func:`sum`:: 6 Later we will see more functions that return iterables and take iterables as -arguments. Lastly, maybe you are curious about how to get a list from a range. -Here is the solution:: - - >>> list(range(4)) - [0, 1, 2, 3] - -In chapter :ref:`tut-structures`, we will discuss in more detail about +arguments. In chapter :ref:`tut-structures`, we will discuss in more detail about :func:`list`. .. _tut-break: @@ -208,6 +202,7 @@ iteration of the loop:: ... print("Found an even number", num) ... continue ... print("Found an odd number", num) + ... Found an even number 2 Found an odd number 3 Found an even number 4 diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index f72da5c3..516c925b 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -305,7 +305,7 @@ disabled by using ``from None`` idiom: >>> try: ... open('database.sqlite') - ... except IOError: + ... except OSError: ... raise RuntimeError from None ... Traceback (most recent call last): @@ -405,6 +405,10 @@ points discuss more complex cases when an exception occurs: or :keyword:`!else` clause. Again, the exception is re-raised after the :keyword:`!finally` clause has been executed. +* If the :keyword:`!finally` clause executes a :keyword:`break`, + :keyword:`continue` or :keyword:`return` statement, exceptions are not + re-raised. + * If the :keyword:`!try` statement reaches a :keyword:`break`, :keyword:`continue` or :keyword:`return` statement, the :keyword:`!finally` clause will execute just prior to the diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 4e27cff8..7f83c4d4 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -480,7 +480,8 @@ If you have an object ``x``, you can view its JSON string representation with a simple line of code:: >>> import json - >>> json.dumps([1, 'simple', 'list']) + >>> x = [1, 'simple', 'list'] + >>> json.dumps(x) '[1, "simple", "list"]' Another variant of the :func:`~json.dumps` function, called :func:`~json.dump`, diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 2a166612..4613cf76 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -73,7 +73,7 @@ operator; to calculate the remainder you can use ``%``:: 5 >>> 17 % 3 # the % operator returns the remainder of the division 2 - >>> 5 * 3 + 2 # result * divisor + remainder + >>> 5 * 3 + 2 # floored quotient * divisor + remainder 17 With Python, it is possible to use the ``**`` operator to calculate powers [#]_:: diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index cb492e45..c29715d1 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1493,7 +1493,7 @@ and to match the behavior of static type checkers specified in the PEP. now ``False``. To support this change, the internally used type cache now supports differentiating types. 4. ``Literal`` objects will now raise a :exc:`TypeError` exception during - equality comparisons if one of their parameters are not :term:`immutable`. + equality comparisons if any of their parameters are not :term:`hashable`. Note that declaring ``Literal`` with mutable parameters will not throw an error:: @@ -1560,3 +1560,17 @@ IPv4 address sent from the remote server when setting up a passive data channel. We reuse the ftp server IP address instead. For unusual code requiring the old behavior, set a ``trust_server_pasv_ipv4_address`` attribute on your FTP instance to ``True``. (See :issue:`43285`) + +Notable changes in Python 3.9.5 +=============================== + +urllib.parse +------------ + +The presence of newline or tab characters in parts of a URL allows for some +forms of attacks. Following the WHATWG specification that updates :rfc:`3986`, +ASCII newline ``\n``, ``\r`` and tab ``\t`` characters are stripped from the +URL by the parser in :mod:`urllib.parse` preventing such attacks. The removal +characters are controlled by a new module level variable +``urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE``. (See :issue:`43882`) + diff --git a/Grammar/python.gram b/Grammar/python.gram index 64e205e7..544b4f79 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -600,11 +600,6 @@ del_t_atom[expr_ty]: | '(' a=[del_targets] ')' { _Py_Tuple(a, Del, EXTRA) } | '[' a=[del_targets] ']' { _Py_List(a, Del, EXTRA) } -targets[asdl_seq*]: a=','.target+ [','] { a } -target[expr_ty] (memo): - | a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Store, EXTRA) } - | a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) } - | t_atom t_primary[expr_ty]: | a=t_primary '.' b=NAME &t_lookahead { _Py_Attribute(a, b->v.Name.id, Load, EXTRA) } | a=t_primary '[' b=slices ']' &t_lookahead { _Py_Subscript(a, b, Load, EXTRA) } @@ -616,12 +611,6 @@ t_primary[expr_ty]: EXTRA) } | a=atom &t_lookahead { a } t_lookahead: '(' | '[' | '.' -t_atom[expr_ty]: - | a=NAME { _PyPegen_set_expr_context(p, a, Store) } - | '(' a=target ')' { _PyPegen_set_expr_context(p, a, Store) } - | '(' b=[targets] ')' { _Py_Tuple(b, Store, EXTRA) } - | '[' b=[targets] ']' { _Py_List(b, Store, EXTRA) } - # From here on, there are rules for invalid syntax with specialised error messages invalid_arguments: @@ -633,7 +622,7 @@ invalid_arguments: RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "Generator expression must be parenthesized") } | a=args ',' args { _PyPegen_arguments_parsing_error(p, a) } invalid_kwarg: - | a=expression '=' { + | !(NAME '=') a=expression b='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION( a, "expression cannot contain assignment, perhaps you meant \"==\"?") } invalid_named_expression: diff --git a/Include/Python.h b/Include/Python.h index dcd0a57a..acee38c4 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -63,13 +63,22 @@ #include "pyport.h" #include "pymacro.h" -/* A convenient way for code to know if clang's memory sanitizer is enabled. */ +/* A convenient way for code to know if sanitizers are enabled. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) # if !defined(_Py_MEMORY_SANITIZER) # define _Py_MEMORY_SANITIZER # endif # endif +# if __has_feature(address_sanitizer) +# if !defined(_Py_ADDRESS_SANITIZER) +# define _Py_ADDRESS_SANITIZER +# endif +# endif +#elif defined(__GNUC__) +# if defined(__SANITIZE_ADDRESS__) +# define _Py_ADDRESS_SANITIZER +# endif #endif /* Debug-mode build with pymalloc implies PYMALLOC_DEBUG. diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index bbee5861..8cf137bb 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -48,6 +48,18 @@ PyAPI_FUNC(int) _Py_GetLocaleconvNumeric( PyObject **decimal_point, PyObject **thousands_sep); +#ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION +extern int _Py_LocaleUsesNonUnicodeWchar(void); + +extern wchar_t* _Py_DecodeNonUnicodeWchar( + const wchar_t* native, + Py_ssize_t size); + +extern int _Py_EncodeNonUnicodeWchar_InPlace( + wchar_t* unicode, + Py_ssize_t size); +#endif + #ifdef __cplusplus } #endif diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 32ce1165..19e2aaea 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 5 +#define PY_MICRO_VERSION 6 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.5" +#define PY_VERSION "3.9.6" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/_aix_support.py b/Lib/_aix_support.py index 45504934..d27a1e87 100644 --- a/Lib/_aix_support.py +++ b/Lib/_aix_support.py @@ -15,8 +15,9 @@ def _aix_tag(vrtl, bd): # type: (List[int], int) -> str # Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) _sz = 32 if sys.maxsize == (2**31-1) else 64 + _bd = bd if bd != 0 else 9988 # vrtl[version, release, technology_level] - return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, _sz) + return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], _bd, _sz) # extract version, release and technology level from a VRMF string @@ -26,19 +27,20 @@ def _aix_vrtl(vrmf): return [int(v[-1]), int(r), int(tl)] -def _aix_bosmp64(): +def _aix_bos_rte(): # type: () -> Tuple[str, int] """ Return a Tuple[str, int] e.g., ['7.1.4.34', 1806] - The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate - reflect the current ABI levels of the runtime environment. + The fileset bos.rte represents the current AIX run-time level. It's VRMF and + builddate reflect the current ABI levels of the runtime environment. + If no builddate is found give a value that will satisfy pep425 related queries """ - # We expect all AIX systems to have lslpp installed in this location - out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) + # All AIX systems to have lslpp installed in this location + out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.rte"]) out = out.decode("utf-8") out = out.strip().split(":") # type: ignore - # Use str() and int() to help mypy see types - return (str(out[2]), int(out[-1])) + _bd = int(out[-1]) if out[-1] != '' else 9988 + return (str(out[2]), _bd) def aix_platform(): @@ -47,11 +49,11 @@ def aix_platform(): AIX filesets are identified by four decimal values: V.R.M.F. V (version) and R (release) can be retreived using ``uname`` Since 2007, starting with AIX 5.3 TL7, the M value has been - included with the fileset bos.mp64 and represents the Technology + included with the fileset bos.rte and represents the Technology Level (TL) of AIX. The F (Fix) value also increases, but is not relevant for comparing releases and binary compatibility. For binary compatibility the so-called builddate is needed. - Again, the builddate of an AIX release is associated with bos.mp64. + Again, the builddate of an AIX release is associated with bos.rte. AIX ABI compatibility is described as guaranteed at: https://www.ibm.com/\ support/knowledgecenter/en/ssw_aix_72/install/binary_compatability.html @@ -60,7 +62,7 @@ def aix_platform(): e.g., "aix-6107-1415-32" for AIX 6.1 TL7 bd 1415, 32-bit and, "aix-6107-1415-64" for AIX 6.1 TL7 bd 1415, 64-bit """ - vrmf, bd = _aix_bosmp64() + vrmf, bd = _aix_bos_rte() return _aix_tag(_aix_vrtl(vrmf), bd) @@ -79,7 +81,7 @@ def aix_buildtag(): Return the platform_tag of the system Python was built on. """ # AIX_BUILDDATE is defined by configure with: - # lslpp -Lcq bos.mp64 | awk -F: '{ print $NF }' + # lslpp -Lcq bos.rte | awk -F: '{ print $NF }' build_date = sysconfig.get_config_var("AIX_BUILDDATE") try: build_date = int(build_date) diff --git a/Lib/_strptime.py b/Lib/_strptime.py index 5df37f5f..b97dfcce 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -201,7 +201,7 @@ class TimeRE(dict): #XXX: Does 'Y' need to worry about having less or more than # 4 digits? 'Y': r"(?P\d\d\d\d)", - 'z': r"(?P[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|Z)", + 'z': r"(?P[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|(?-i:Z))", 'A': self.__seqToRE(self.locale_time.f_weekday, 'A'), 'a': self.__seqToRE(self.locale_time.a_weekday, 'a'), 'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'), diff --git a/Lib/abc.py b/Lib/abc.py index 431b6404..9de128e2 100644 --- a/Lib/abc.py +++ b/Lib/abc.py @@ -28,7 +28,14 @@ def abstractmethod(funcobj): class abstractclassmethod(classmethod): """A decorator indicating abstract classmethods. - Deprecated, use 'classmethod' with 'abstractmethod' instead. + Deprecated, use 'classmethod' with 'abstractmethod' instead: + + class C(ABC): + @classmethod + @abstractmethod + def my_abstract_classmethod(cls, ...): + ... + """ __isabstractmethod__ = True @@ -41,7 +48,14 @@ class abstractclassmethod(classmethod): class abstractstaticmethod(staticmethod): """A decorator indicating abstract staticmethods. - Deprecated, use 'staticmethod' with 'abstractmethod' instead. + Deprecated, use 'staticmethod' with 'abstractmethod' instead: + + class C(ABC): + @staticmethod + @abstractmethod + def my_abstract_staticmethod(...): + ... + """ __isabstractmethod__ = True @@ -54,7 +68,14 @@ class abstractstaticmethod(staticmethod): class abstractproperty(property): """A decorator indicating abstract properties. - Deprecated, use 'property' with 'abstractmethod' instead. + Deprecated, use 'property' with 'abstractmethod' instead: + + class C(ABC): + @property + @abstractmethod + def my_abstract_property(self): + ... + """ __isabstractmethod__ = True diff --git a/Lib/ast.py b/Lib/ast.py index 5d326218..396eea18 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1448,9 +1448,9 @@ class _Unparser(NodeVisitor): def visit_Subscript(self, node): def is_simple_tuple(slice_value): - # when unparsing a non-empty tuple, the parantheses can be safely + # when unparsing a non-empty tuple, the parentheses can be safely # omitted if there aren't any elements that explicitly requires - # parantheses (such as starred expressions). + # parentheses (such as starred expressions). return ( isinstance(slice_value, Tuple) and slice_value.elts diff --git a/Lib/bdb.py b/Lib/bdb.py index b18a0612..384a272a 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -117,7 +117,7 @@ class Bdb: """Invoke user function and return trace function for call event. If the debugger stops on this function call, invoke - self.user_call(). Raise BbdQuit if self.quitting is set. + self.user_call(). Raise BdbQuit if self.quitting is set. Return self.trace_dispatch to continue tracing in this scope. """ # XXX 'arg' is no longer used diff --git a/Lib/bz2.py b/Lib/bz2.py index ce07ebeb..7447d12f 100644 --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -226,15 +226,23 @@ class BZ2File(_compression.BaseStream): """Write a byte string to the file. Returns the number of uncompressed bytes written, which is - always len(data). Note that due to buffering, the file on disk - may not reflect the data written until close() is called. + always the length of data in bytes. Note that due to buffering, + the file on disk may not reflect the data written until close() + is called. """ with self._lock: self._check_can_write() + if isinstance(data, (bytes, bytearray)): + length = len(data) + else: + # accept any data that supports the buffer protocol + data = memoryview(data) + length = data.nbytes + compressed = self._compressor.compress(data) self._fp.write(compressed) - self._pos += len(data) - return len(data) + self._pos += length + return length def writelines(self, seq): """Write a sequence of byte strings to the file. diff --git a/Lib/configparser.py b/Lib/configparser.py index 924cc56a..8dd5c13b 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -907,6 +907,9 @@ class RawConfigParser(MutableMapping): If `space_around_delimiters' is True (the default), delimiters between keys and values are surrounded by spaces. + + Please note that comments in the original configuration file are not + preserved when writing the configuration back. """ if space_around_delimiters: d = " {} ".format(self._delimiters[0]) @@ -1005,7 +1008,7 @@ class RawConfigParser(MutableMapping): Configuration files may include comments, prefixed by specific characters (`#' and `;' by default). Comments may appear on their own in an otherwise empty line or may be entered in lines holding values or - section names. + section names. Please note that comments get stripped off when reading configuration files. """ elements_added = set() cursect = None # None, or a dictionary diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index da7cb743..c98e74d4 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -944,7 +944,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): _set_new_attribute(cls, '__repr__', _repr_fn(flds, globals)) if eq: - # Create _eq__ method. There's no need for a __ne__ method, + # Create __eq__ method. There's no need for a __ne__ method, # since python will call __eq__ and negate it. flds = [f for f in field_list if f.compare] self_tuple = _tuple_str('self', flds) diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 95e9fda1..e0ecb655 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -9,7 +9,8 @@ import os import io import hashlib from base64 import standard_b64encode -from urllib.request import urlopen, Request, HTTPError +from urllib.error import HTTPError +from urllib.request import urlopen, Request from urllib.parse import urlparse from distutils.errors import DistutilsError, DistutilsOptionError from distutils.core import PyPIRCCommand diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index 0d1bd039..31df3f7f 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -59,13 +59,17 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0): if _cfg_target: _cfg_target_split = [int(x) for x in _cfg_target.split('.')] if _cfg_target: - # ensure that the deployment target of build process is not less - # than that used when the interpreter was built. This ensures - # extension modules are built with correct compatibility values + # Ensure that the deployment target of the build process is not + # less than 10.3 if the interpreter was built for 10.3 or later. + # This ensures extension modules are built with correct + # compatibility values, specifically LDSHARED which can use + # '-undefined dynamic_lookup' which only works on >= 10.3. cur_target = os.environ.get('MACOSX_DEPLOYMENT_TARGET', _cfg_target) - if _cfg_target_split > [int(x) for x in cur_target.split('.')]: + cur_target_split = [int(x) for x in cur_target.split('.')] + if _cfg_target_split[:2] >= [10, 3] and cur_target_split[:2] < [10, 3]: my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: ' - 'now "%s" but "%s" during configure' + 'now "%s" but "%s" during configure;' + 'must use 10.3 or later' % (cur_target, _cfg_target)) raise DistutilsPlatformError(my_msg) env = dict(os.environ, diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py index bca5516d..74f0bc0a 100644 --- a/Lib/distutils/tests/test_upload.py +++ b/Lib/distutils/tests/test_upload.py @@ -2,7 +2,7 @@ import os import unittest import unittest.mock as mock -from urllib.request import HTTPError +from urllib.error import HTTPError from test.support import run_unittest diff --git a/Lib/email/message.py b/Lib/email/message.py index 3701b305..db30d9a1 100644 --- a/Lib/email/message.py +++ b/Lib/email/message.py @@ -948,7 +948,7 @@ class MIMEPart(Message): if policy is None: from email.policy import default policy = default - Message.__init__(self, policy) + super().__init__(policy) def as_string(self, unixfrom=False, maxheaderlen=None, policy=None): @@ -965,7 +965,7 @@ class MIMEPart(Message): policy = self.policy if policy is None else policy if maxheaderlen is None: maxheaderlen = policy.max_line_length - return super().as_string(maxheaderlen=maxheaderlen, policy=policy) + return super().as_string(unixfrom, maxheaderlen, policy) def __str__(self): return self.as_string(policy=self.policy.clone(utf8=True)) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 57e576d1..14a39037 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -15,7 +15,7 @@ __all__ = ["version", "bootstrap"] _SETUPTOOLS_VERSION = "56.0.0" -_PIP_VERSION = "21.1.1" +_PIP_VERSION = "21.1.3" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-21.1.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-21.1.3-py3-none-any.whl similarity index 92% rename from Lib/ensurepip/_bundled/pip-21.1.1-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-21.1.3-py3-none-any.whl index 291cc296fa7b4811f1c8d361cfe58266b9eb7d6d..d96a40a9291fb27e32d569b3d542456b2dbf09e3 100644 GIT binary patch delta 66811 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

    VMI6qA(@}>$f-uqrY*TB9y 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 f&7-8m`` 1: raise TypeError('%r: too many data types: %r' % (class_name, data_types)) elif data_types: - return data_types[0] + return data_types.pop() else: return None diff --git a/Lib/getpass.py b/Lib/getpass.py index 6911f41d..6970d8ad 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -95,7 +95,7 @@ def unix_getpass(prompt='Password: ', stream=None): def win_getpass(prompt='Password: ', stream=None): - """Prompt for password with echo off, using Windows getch().""" + """Prompt for password with echo off, using Windows getwch().""" if sys.stdin is not sys.__stdin__: return fallback_getpass(prompt, stream) diff --git a/Lib/glob.py b/Lib/glob.py index 0dd2f8be..12370611 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -1,5 +1,6 @@ """Filename globbing utility.""" +import contextlib import os import re import fnmatch @@ -79,7 +80,7 @@ def _iglob(pathname, recursive, dironly): # takes a literal basename (so it only has to check for its existence). def _glob1(dirname, pattern, dironly): - names = list(_iterdir(dirname, dironly)) + names = _listdir(dirname, dironly) if not _ishidden(pattern): names = (x for x in names if not _ishidden(x)) return fnmatch.filter(names, pattern) @@ -130,9 +131,13 @@ def _iterdir(dirname, dironly): except OSError: return +def _listdir(dirname, dironly): + with contextlib.closing(_iterdir(dirname, dironly)) as it: + return list(it) + # Recursively yields relative pathnames inside a literal directory. def _rlistdir(dirname, dironly): - names = list(_iterdir(dirname, dironly)) + names = _listdir(dirname, dironly) for x in names: if not _ishidden(x): yield x diff --git a/Lib/gzip.py b/Lib/gzip.py index ee0cbed8..11a5f41d 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -516,7 +516,7 @@ class _GzipReader(_compression.DecompressReader): def _read_eof(self): # We've read to the end of the file - # We check the that the computed CRC and size of the + # We check that the computed CRC and size of the # uncompressed data matches the stored values. Note that the size # stored is the true file size mod 2**32. crc32, isize = struct.unpack(" _MAXLINE: - raise LineTooLong("header line") - skip = skip.strip() - if not skip: - break - if self.debuglevel > 0: - print("header:", skip) + skipped_headers = _read_headers(self.fp) + if self.debuglevel > 0: + print("headers:", skipped_headers) + del skipped_headers self.code = self.status = status self.reason = reason.strip() diff --git a/Lib/http/server.py b/Lib/http/server.py index def05f46..d7cce204 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -689,6 +689,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): parts[3], parts[4]) new_url = urllib.parse.urlunsplit(new_parts) self.send_header("Location", new_url) + self.send_header("Content-Length", "0") self.end_headers() return None for index in "index.html", "index.htm": diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index fe7a6be8..21b8a247 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -203,6 +203,7 @@ class AutoCompleteWindow: scrollbar.config(command=listbox.yview) scrollbar.pack(side=RIGHT, fill=Y) listbox.pack(side=LEFT, fill=BOTH, expand=True) + acw.update_idletasks() # Need for tk8.6.8 on macOS: #40128. acw.lift() # work around bug in Tk 8.5.18+ (issue #24570) # Initialize the listbox selection @@ -239,31 +240,46 @@ class AutoCompleteWindow: self.is_configuring = True if not self.is_active(): return - # Position the completion list window - text = self.widget - text.see(self.startindex) - x, y, cx, cy = text.bbox(self.startindex) - acw = self.autocompletewindow - acw.update() - acw_width, acw_height = acw.winfo_width(), acw.winfo_height() - text_width, text_height = text.winfo_width(), text.winfo_height() - new_x = text.winfo_rootx() + min(x, max(0, text_width - acw_width)) - new_y = text.winfo_rooty() + y - if (text_height - (y + cy) >= acw_height # enough height below - or y < acw_height): # not enough height above - # place acw below current line - new_y += cy - else: - # place acw above current line - new_y -= acw_height - acw.wm_geometry("+%d+%d" % (new_x, new_y)) - acw.update_idletasks() + + # Since the event may occur after the completion window is gone, + # catch potential TclError exceptions when accessing acw. See: bpo-41611. + try: + # Position the completion list window + text = self.widget + text.see(self.startindex) + x, y, cx, cy = text.bbox(self.startindex) + acw = self.autocompletewindow + if platform.system().startswith('Windows'): + # On Windows an update() call is needed for the completion + # list window to be created, so that we can fetch its width + # and height. However, this is not needed on other platforms + # (tested on Ubuntu and macOS) but at one point began + # causing freezes on macOS. See issues 37849 and 41611. + acw.update() + acw_width, acw_height = acw.winfo_width(), acw.winfo_height() + text_width, text_height = text.winfo_width(), text.winfo_height() + new_x = text.winfo_rootx() + min(x, max(0, text_width - acw_width)) + new_y = text.winfo_rooty() + y + if (text_height - (y + cy) >= acw_height # enough height below + or y < acw_height): # not enough height above + # place acw below current line + new_y += cy + else: + # place acw above current line + new_y -= acw_height + acw.wm_geometry("+%d+%d" % (new_x, new_y)) + acw.update_idletasks() + except TclError: + pass if platform.system().startswith('Windows'): - # See issue 15786. When on Windows platform, Tk will misbehave + # See issue 15786. When on Windows platform, Tk will misbehave # to call winconfig_event multiple times, we need to prevent this, # otherwise mouse button double click will not be able to used. - acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid) + try: + acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid) + except TclError: + pass self.winconfigid = None self.is_configuring = False diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index c52a04b5..6d089368 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -15,9 +15,10 @@ from tkinter import (Toplevel, Listbox, Scale, Canvas, StringVar, BooleanVar, IntVar, TRUE, FALSE, TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW, - HORIZONTAL, VERTICAL, ANCHOR, ACTIVE, END) + HORIZONTAL, VERTICAL, ANCHOR, ACTIVE, END, TclError) from tkinter.ttk import (Frame, LabelFrame, Button, Checkbutton, Entry, Label, - OptionMenu, Notebook, Radiobutton, Scrollbar, Style) + OptionMenu, Notebook, Radiobutton, Scrollbar, Style, + Spinbox, Combobox) from tkinter import colorchooser import tkinter.font as tkfont from tkinter import messagebox @@ -101,8 +102,9 @@ class ConfigDialog(Toplevel): highpage: HighPage fontpage: FontPage keyspage: KeysPage - genpage: GenPage - extpage: self.create_page_extensions + winpage: WinPage + shedpage: ShedPage + extpage: ExtPage Methods: create_action_buttons @@ -112,15 +114,18 @@ class ConfigDialog(Toplevel): self.frame = frame = Frame(self, padding="5px") self.frame.grid(sticky="nwes") self.note = note = Notebook(frame) - self.highpage = HighPage(note) + self.extpage = ExtPage(note) + self.highpage = HighPage(note, self.extpage) self.fontpage = FontPage(note, self.highpage) - self.keyspage = KeysPage(note) - self.genpage = GenPage(note) - self.extpage = self.create_page_extensions() + self.keyspage = KeysPage(note, self.extpage) + self.winpage = WinPage(note) + self.shedpage = ShedPage(note) + note.add(self.fontpage, text='Fonts/Tabs') note.add(self.highpage, text='Highlights') note.add(self.keyspage, text=' Keys ') - note.add(self.genpage, text=' General ') + note.add(self.winpage, text=' Windows ') + note.add(self.shedpage, text=' Shell/Ed ') note.add(self.extpage, text='Extensions') note.enable_traversal() note.pack(side=TOP, expand=TRUE, fill=BOTH) @@ -167,26 +172,15 @@ class ConfigDialog(Toplevel): return outer def ok(self): - """Apply config changes, then dismiss dialog. - - Methods: - apply - destroy: inherited - """ + """Apply config changes, then dismiss dialog.""" self.apply() self.destroy() def apply(self): - """Apply config changes and leave dialog open. - - Methods: - deactivate_current_config - save_all_changed_extensions - activate_config_changes - """ + """Apply config changes and leave dialog open.""" self.deactivate_current_config() changes.save_all() - self.save_all_changed_extensions() + self.extpage.save_all_changed_extensions() self.activate_config_changes() def cancel(self): @@ -244,190 +238,6 @@ class ConfigDialog(Toplevel): for klass in reloadables: klass.reload() - def create_page_extensions(self): - """Part of the config dialog used for configuring IDLE extensions. - - This code is generic - it works for any and all IDLE extensions. - - IDLE extensions save their configuration options using idleConf. - This code reads the current configuration using idleConf, supplies a - GUI interface to change the configuration values, and saves the - changes using idleConf. - - Not all changes take effect immediately - some may require restarting IDLE. - This depends on each extension's implementation. - - All values are treated as text, and it is up to the user to supply - reasonable values. The only exception to this are the 'enable*' options, - which are boolean, and can be toggled with a True/False button. - - Methods: - load_extensions: - extension_selected: Handle selection from list. - create_extension_frame: Hold widgets for one extension. - set_extension_value: Set in userCfg['extensions']. - save_all_changed_extensions: Call extension page Save(). - """ - parent = self.parent - frame = Frame(self.note) - self.ext_defaultCfg = idleConf.defaultCfg['extensions'] - self.ext_userCfg = idleConf.userCfg['extensions'] - self.is_int = self.register(is_int) - self.load_extensions() - # Create widgets - a listbox shows all available extensions, with the - # controls for the extension selected in the listbox to the right. - self.extension_names = StringVar(self) - frame.rowconfigure(0, weight=1) - frame.columnconfigure(2, weight=1) - self.extension_list = Listbox(frame, listvariable=self.extension_names, - selectmode='browse') - self.extension_list.bind('<>', self.extension_selected) - scroll = Scrollbar(frame, command=self.extension_list.yview) - self.extension_list.yscrollcommand=scroll.set - self.details_frame = LabelFrame(frame, width=250, height=250) - self.extension_list.grid(column=0, row=0, sticky='nws') - scroll.grid(column=1, row=0, sticky='ns') - self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0]) - frame.configure(padding=10) - self.config_frame = {} - self.current_extension = None - - self.outerframe = self # TEMPORARY - self.tabbed_page_set = self.extension_list # TEMPORARY - - # Create the frame holding controls for each extension. - ext_names = '' - for ext_name in sorted(self.extensions): - self.create_extension_frame(ext_name) - ext_names = ext_names + '{' + ext_name + '} ' - self.extension_names.set(ext_names) - self.extension_list.selection_set(0) - self.extension_selected(None) - - return frame - - def load_extensions(self): - "Fill self.extensions with data from the default and user configs." - self.extensions = {} - for ext_name in idleConf.GetExtensions(active_only=False): - # Former built-in extensions are already filtered out. - self.extensions[ext_name] = [] - - for ext_name in self.extensions: - opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name)) - - # Bring 'enable' options to the beginning of the list. - enables = [opt_name for opt_name in opt_list - if opt_name.startswith('enable')] - for opt_name in enables: - opt_list.remove(opt_name) - opt_list = enables + opt_list - - for opt_name in opt_list: - def_str = self.ext_defaultCfg.Get( - ext_name, opt_name, raw=True) - try: - def_obj = {'True':True, 'False':False}[def_str] - opt_type = 'bool' - except KeyError: - try: - def_obj = int(def_str) - opt_type = 'int' - except ValueError: - def_obj = def_str - opt_type = None - try: - value = self.ext_userCfg.Get( - ext_name, opt_name, type=opt_type, raw=True, - default=def_obj) - except ValueError: # Need this until .Get fixed. - value = def_obj # Bad values overwritten by entry. - var = StringVar(self) - var.set(str(value)) - - self.extensions[ext_name].append({'name': opt_name, - 'type': opt_type, - 'default': def_str, - 'value': value, - 'var': var, - }) - - def extension_selected(self, event): - "Handle selection of an extension from the list." - newsel = self.extension_list.curselection() - if newsel: - newsel = self.extension_list.get(newsel) - if newsel is None or newsel != self.current_extension: - if self.current_extension: - self.details_frame.config(text='') - self.config_frame[self.current_extension].grid_forget() - self.current_extension = None - if newsel: - self.details_frame.config(text=newsel) - self.config_frame[newsel].grid(column=0, row=0, sticky='nsew') - self.current_extension = newsel - - def create_extension_frame(self, ext_name): - """Create a frame holding the widgets to configure one extension""" - f = VerticalScrolledFrame(self.details_frame, height=250, width=250) - self.config_frame[ext_name] = f - entry_area = f.interior - # Create an entry for each configuration option. - for row, opt in enumerate(self.extensions[ext_name]): - # Create a row with a label and entry/checkbutton. - label = Label(entry_area, text=opt['name']) - label.grid(row=row, column=0, sticky=NW) - var = opt['var'] - if opt['type'] == 'bool': - Checkbutton(entry_area, variable=var, - onvalue='True', offvalue='False', width=8 - ).grid(row=row, column=1, sticky=W, padx=7) - elif opt['type'] == 'int': - Entry(entry_area, textvariable=var, validate='key', - validatecommand=(self.is_int, '%P'), width=10 - ).grid(row=row, column=1, sticky=NSEW, padx=7) - - else: # type == 'str' - # Limit size to fit non-expanding space with larger font. - Entry(entry_area, textvariable=var, width=15 - ).grid(row=row, column=1, sticky=NSEW, padx=7) - return - - def set_extension_value(self, section, opt): - """Return True if the configuration was added or changed. - - If the value is the same as the default, then remove it - from user config file. - """ - name = opt['name'] - default = opt['default'] - value = opt['var'].get().strip() or default - opt['var'].set(value) - # if self.defaultCfg.has_section(section): - # Currently, always true; if not, indent to return. - if (value == default): - return self.ext_userCfg.RemoveOption(section, name) - # Set the option. - return self.ext_userCfg.SetOption(section, name, value) - - def save_all_changed_extensions(self): - """Save configuration changes to the user config file. - - Attributes accessed: - extensions - - Methods: - set_extension_value - """ - has_changes = False - for ext_name in self.extensions: - options = self.extensions[ext_name] - for opt in options: - if self.set_extension_value(ext_name, opt): - has_changes = True - if has_changes: - self.ext_userCfg.Save() - # class TabPage(Frame): # A template for Page classes. # def __init__(self, master): @@ -480,12 +290,11 @@ class FontPage(Frame): def __init__(self, master, highpage): super().__init__(master) self.highlight_sample = highpage.highlight_sample - self.create_page_font_tab() + self.create_page_font() self.load_font_cfg() - self.load_tab_cfg() - def create_page_font_tab(self): - """Return frame of widgets for Font/Tabs tab. + def create_page_font(self): + """Return frame of widgets for Font tab. Fonts: Enable users to provisionally change font face, size, or boldness and to see the consequence of proposed choices. Each @@ -509,11 +318,6 @@ class FontPage(Frame): Set_samples applies a new font constructed from the font vars to font_sample and to highlight_sample on the highlight page. - Tabs: Enable users to change spaces entered for indent tabs. - Changing indent_scale value with the mouse sets Var space_num, - which invokes the default callback to add an entry to - changes. Load_tab_cfg initializes space_num to default. - Widgets for FontPage(Frame): (*) widgets bound to self frame_font: LabelFrame frame_font_name: Frame @@ -526,23 +330,16 @@ class FontPage(Frame): (*)bold_toggle: Checkbutton - font_bold frame_sample: LabelFrame (*)font_sample: Label - frame_indent: LabelFrame - indent_title: Label - (*)indent_scale: Scale - space_num """ self.font_name = tracers.add(StringVar(self), self.var_changed_font) self.font_size = tracers.add(StringVar(self), self.var_changed_font) self.font_bold = tracers.add(BooleanVar(self), self.var_changed_font) - self.space_num = tracers.add(IntVar(self), ('main', 'Indent', 'num-spaces')) # Define frames and widgets. - frame_font = LabelFrame( - self, borderwidth=2, relief=GROOVE, text=' Shell/Editor Font ') - frame_sample = LabelFrame( - self, borderwidth=2, relief=GROOVE, - text=' Font Sample (Editable) ') - frame_indent = LabelFrame( - self, borderwidth=2, relief=GROOVE, text=' Indentation Width ') + frame_font = LabelFrame(self, borderwidth=2, relief=GROOVE, + text=' Shell/Editor Font ') + frame_sample = LabelFrame(self, borderwidth=2, relief=GROOVE, + text=' Font Sample (Editable) ') # frame_font. frame_font_name = Frame(frame_font) frame_font_param = Frame(frame_font) @@ -566,13 +363,6 @@ class FontPage(Frame): self.font_sample = font_sample_frame.text self.font_sample.config(wrap=NONE, width=1, height=1) self.font_sample.insert(END, font_sample_text) - # frame_indent. - indent_title = Label( - frame_indent, justify=LEFT, - text='Python Standard: 4 Spaces!') - self.indent_scale = Scale( - frame_indent, variable=self.space_num, - orient='horizontal', tickinterval=2, from_=2, to=16) # Grid and pack widgets: self.columnconfigure(1, weight=1) @@ -580,7 +370,6 @@ class FontPage(Frame): frame_font.grid(row=0, column=0, padx=5, pady=5) frame_sample.grid(row=0, column=1, rowspan=3, padx=5, pady=5, sticky='nsew') - frame_indent.grid(row=1, column=0, padx=5, pady=5, sticky='ew') # frame_font. frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X) frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X) @@ -592,9 +381,6 @@ class FontPage(Frame): self.bold_toggle.pack(side=LEFT, anchor=W, padx=20) # frame_sample. font_sample_frame.pack(expand=TRUE, fill=BOTH) - # frame_indent. - indent_title.pack(side=TOP, anchor=W, padx=5) - self.indent_scale.pack(side=TOP, padx=5, fill=X) def load_font_cfg(self): """Load current configuration settings for the font options. @@ -668,34 +454,19 @@ class FontPage(Frame): self.font_sample['font'] = new_font self.highlight_sample['font'] = new_font - def load_tab_cfg(self): - """Load current configuration settings for the tab options. - - Attributes updated: - space_num: Set to value from idleConf. - """ - # Set indent sizes. - space_num = idleConf.GetOption( - 'main', 'Indent', 'num-spaces', default=4, type='int') - self.space_num.set(space_num) - - def var_changed_space_num(self, *params): - "Store change to indentation size." - value = self.space_num.get() - changes.add_option('main', 'Indent', 'num-spaces', value) - class HighPage(Frame): - def __init__(self, master): + def __init__(self, master, extpage): super().__init__(master) + self.extpage = extpage self.cd = master.winfo_toplevel() self.style = Style(master) self.create_page_highlight() self.load_theme_cfg() def create_page_highlight(self): - """Return frame of widgets for Highlighting tab. + """Return frame of widgets for Highlights tab. Enable users to provisionally change foreground and background colors applied to textual tags. Color mappings are stored in @@ -1339,15 +1110,16 @@ class HighPage(Frame): self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) # User can't back out of these changes, they must be applied now. changes.save_all() - self.cd.save_all_changed_extensions() + self.extpage.save_all_changed_extensions() self.cd.activate_config_changes() self.set_theme_type() class KeysPage(Frame): - def __init__(self, master): + def __init__(self, master, extpage): super().__init__(master) + self.extpage = extpage self.cd = master.winfo_toplevel() self.create_page_keys() self.load_key_cfg() @@ -1771,19 +1543,19 @@ class KeysPage(Frame): or idleConf.default_keys()) # User can't back out of these changes, they must be applied now. changes.save_all() - self.cd.save_all_changed_extensions() + self.extpage.save_all_changed_extensions() self.cd.activate_config_changes() self.set_keys_type() -class GenPage(Frame): +class WinPage(Frame): def __init__(self, master): super().__init__(master) self.init_validators() - self.create_page_general() - self.load_general_cfg() + self.create_page_windows() + self.load_windows_cfg() def init_validators(self): digits_or_empty_re = re.compile(r'[0-9]*') @@ -1792,76 +1564,45 @@ class GenPage(Frame): return digits_or_empty_re.fullmatch(s) is not None self.digits_only = (self.register(is_digits_or_empty), '%P',) - def create_page_general(self): - """Return frame of widgets for General tab. - - Enable users to provisionally change general options. Function - load_general_cfg initializes tk variables and helplist using - idleConf. Radiobuttons startup_shell_on and startup_editor_on - set var startup_edit. Radiobuttons save_ask_on and save_auto_on - set var autosave. Entry boxes win_width_int and win_height_int - set var win_width and win_height. Setting var_name invokes the - default callback that adds option to changes. + def create_page_windows(self): + """Return frame of widgets for Windows tab. - Helplist: load_general_cfg loads list user_helplist with - name, position pairs and copies names to listbox helplist. - Clicking a name invokes help_source selected. Clicking - button_helplist_name invokes helplist_item_name, which also - changes user_helplist. These functions all call - set_add_delete_state. All but load call update_help_changes to - rewrite changes['main']['HelpFiles']. + Enable users to provisionally change general window options. + Function load_windows_cfg initializes tk variable idleConf. + Radiobuttons startup_shell_on and startup_editor_on set var + startup_edit. Entry boxes win_width_int and win_height_int set var + win_width and win_height. Setting var_name invokes the default + callback that adds option to changes. - Widgets for GenPage(Frame): (*) widgets bound to self + Widgets for WinPage(Frame): > vars, bound to self frame_window: LabelFrame frame_run: Frame startup_title: Label - (*)startup_editor_on: Radiobutton - startup_edit - (*)startup_shell_on: Radiobutton - startup_edit + startup_editor_on: Radiobutton > startup_edit + startup_shell_on: Radiobutton > startup_edit frame_win_size: Frame win_size_title: Label win_width_title: Label - (*)win_width_int: Entry - win_width + win_width_int: Entry > win_width win_height_title: Label - (*)win_height_int: Entry - win_height - frame_cursor_blink: Frame - cursor_blink_title: Label - (*)cursor_blink_bool: Checkbutton - cursor_blink + win_height_int: Entry > win_height + frame_cursor: Frame + indent_title: Label + indent_chooser: Spinbox (Combobox < 8.5.9) > indent_spaces + blink_on: Checkbutton > cursor_blink frame_autocomplete: Frame auto_wait_title: Label - (*)auto_wait_int: Entry - autocomplete_wait + auto_wait_int: Entry > autocomplete_wait frame_paren1: Frame paren_style_title: Label - (*)paren_style_type: OptionMenu - paren_style + paren_style_type: OptionMenu > paren_style frame_paren2: Frame paren_time_title: Label - (*)paren_flash_time: Entry - flash_delay - (*)bell_on: Checkbutton - paren_bell - frame_editor: LabelFrame - frame_save: Frame - run_save_title: Label - (*)save_ask_on: Radiobutton - autosave - (*)save_auto_on: Radiobutton - autosave + paren_flash_time: Entry > flash_delay + bell_on: Checkbutton > paren_bell frame_format: Frame format_width_title: Label - (*)format_width_int: Entry - format_width - frame_line_numbers_default: Frame - line_numbers_default_title: Label - (*)line_numbers_default_bool: Checkbutton - line_numbers_default - frame_context: Frame - context_title: Label - (*)context_int: Entry - context_lines - frame_shell: LabelFrame - frame_auto_squeeze_min_lines: Frame - auto_squeeze_min_lines_title: Label - (*)auto_squeeze_min_lines_int: Entry - auto_squeeze_min_lines - frame_help: LabelFrame - frame_helplist: Frame - frame_helplist_buttons: Frame - (*)button_helplist_edit - (*)button_helplist_add - (*)button_helplist_remove - (*)helplist: ListBox - scroll_helplist: Scrollbar + format_width_int: Entry > format_width """ # Integer values need StringVar because int('') raises. self.startup_edit = tracers.add( @@ -1870,6 +1611,8 @@ class GenPage(Frame): StringVar(self), ('main', 'EditorWindow', 'width')) self.win_height = tracers.add( StringVar(self), ('main', 'EditorWindow', 'height')) + self.indent_spaces = tracers.add( + StringVar(self), ('main', 'Indent', 'num-spaces')) self.cursor_blink = tracers.add( BooleanVar(self), ('main', 'EditorWindow', 'cursor-blink')) self.autocomplete_wait = tracers.add( @@ -1880,31 +1623,13 @@ class GenPage(Frame): StringVar(self), ('extensions', 'ParenMatch', 'flash-delay')) self.paren_bell = tracers.add( BooleanVar(self), ('extensions', 'ParenMatch', 'bell')) - - self.auto_squeeze_min_lines = tracers.add( - StringVar(self), ('main', 'PyShell', 'auto-squeeze-min-lines')) - - self.autosave = tracers.add( - IntVar(self), ('main', 'General', 'autosave')) self.format_width = tracers.add( StringVar(self), ('extensions', 'FormatParagraph', 'max-width')) - self.line_numbers_default = tracers.add( - BooleanVar(self), - ('main', 'EditorWindow', 'line-numbers-default')) - self.context_lines = tracers.add( - StringVar(self), ('extensions', 'CodeContext', 'maxlines')) # Create widgets: - # Section frames. frame_window = LabelFrame(self, borderwidth=2, relief=GROOVE, text=' Window Preferences') - frame_editor = LabelFrame(self, borderwidth=2, relief=GROOVE, - text=' Editor Preferences') - frame_shell = LabelFrame(self, borderwidth=2, relief=GROOVE, - text=' Shell Preferences') - frame_help = LabelFrame(self, borderwidth=2, relief=GROOVE, - text=' Additional Help Sources ') - # Frame_window. + frame_run = Frame(frame_window, borderwidth=0) startup_title = Label(frame_run, text='At Startup') self.startup_editor_on = Radiobutton( @@ -1928,19 +1653,28 @@ class GenPage(Frame): validatecommand=self.digits_only, validate='key', ) - frame_cursor_blink = Frame(frame_window, borderwidth=0) - cursor_blink_title = Label(frame_cursor_blink, text='Cursor Blink') - self.cursor_blink_bool = Checkbutton(frame_cursor_blink, - variable=self.cursor_blink, width=1) + frame_cursor = Frame(frame_window, borderwidth=0) + indent_title = Label(frame_cursor, + text='Indent spaces (4 is standard)') + try: + self.indent_chooser = Spinbox( + frame_cursor, textvariable=self.indent_spaces, + from_=1, to=10, width=2, + validatecommand=self.digits_only, validate='key') + except TclError: + self.indent_chooser = Combobox( + frame_cursor, textvariable=self.indent_spaces, + state="readonly", values=list(range(1,11)), width=3) + cursor_blink_title = Label(frame_cursor, text='Cursor Blink') + self.cursor_blink_bool = Checkbutton(frame_cursor, text="Cursor blink", + variable=self.cursor_blink) frame_autocomplete = Frame(frame_window, borderwidth=0,) auto_wait_title = Label(frame_autocomplete, - text='Completions Popup Wait (milliseconds)') - self.auto_wait_int = Entry(frame_autocomplete, width=6, - textvariable=self.autocomplete_wait, - validatecommand=self.digits_only, - validate='key', - ) + text='Completions Popup Wait (milliseconds)') + self.auto_wait_int = Entry( + frame_autocomplete, textvariable=self.autocomplete_wait, + width=6, validatecommand=self.digits_only, validate='key') frame_paren1 = Frame(frame_window, borderwidth=0) paren_style_title = Label(frame_paren1, text='Paren Match Style') @@ -1952,79 +1686,20 @@ class GenPage(Frame): frame_paren2, text='Time Match Displayed (milliseconds)\n' '(0 is until next input)') self.paren_flash_time = Entry( - frame_paren2, textvariable=self.flash_delay, width=6) + frame_paren2, textvariable=self.flash_delay, width=6, + validatecommand=self.digits_only, validate='key') self.bell_on = Checkbutton( frame_paren2, text="Bell on Mismatch", variable=self.paren_bell) - - # Frame_editor. - frame_save = Frame(frame_editor, borderwidth=0) - run_save_title = Label(frame_save, text='At Start of Run (F5) ') - self.save_ask_on = Radiobutton( - frame_save, variable=self.autosave, value=0, - text="Prompt to Save") - self.save_auto_on = Radiobutton( - frame_save, variable=self.autosave, value=1, - text='No Prompt') - - frame_format = Frame(frame_editor, borderwidth=0) + frame_format = Frame(frame_window, borderwidth=0) format_width_title = Label(frame_format, text='Format Paragraph Max Width') self.format_width_int = Entry( frame_format, textvariable=self.format_width, width=4, validatecommand=self.digits_only, validate='key', - ) - - frame_line_numbers_default = Frame(frame_editor, borderwidth=0) - line_numbers_default_title = Label( - frame_line_numbers_default, text='Show line numbers in new windows') - self.line_numbers_default_bool = Checkbutton( - frame_line_numbers_default, - variable=self.line_numbers_default, - width=1) - - frame_context = Frame(frame_editor, borderwidth=0) - context_title = Label(frame_context, text='Max Context Lines :') - self.context_int = Entry( - frame_context, textvariable=self.context_lines, width=3, - validatecommand=self.digits_only, validate='key', - ) - - # Frame_shell. - frame_auto_squeeze_min_lines = Frame(frame_shell, borderwidth=0) - auto_squeeze_min_lines_title = Label(frame_auto_squeeze_min_lines, - text='Auto-Squeeze Min. Lines:') - self.auto_squeeze_min_lines_int = Entry( - frame_auto_squeeze_min_lines, width=4, - textvariable=self.auto_squeeze_min_lines, - validatecommand=self.digits_only, validate='key', - ) - - # frame_help. - frame_helplist = Frame(frame_help) - frame_helplist_buttons = Frame(frame_helplist) - self.helplist = Listbox( - frame_helplist, height=5, takefocus=True, - exportselection=FALSE) - scroll_helplist = Scrollbar(frame_helplist) - scroll_helplist['command'] = self.helplist.yview - self.helplist['yscrollcommand'] = scroll_helplist.set - self.helplist.bind('', self.help_source_selected) - self.button_helplist_edit = Button( - frame_helplist_buttons, text='Edit', state='disabled', - width=8, command=self.helplist_item_edit) - self.button_helplist_add = Button( - frame_helplist_buttons, text='Add', - width=8, command=self.helplist_item_add) - self.button_helplist_remove = Button( - frame_helplist_buttons, text='Remove', state='disabled', - width=8, command=self.helplist_item_remove) + ) # Pack widgets: - # Body. frame_window.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - frame_editor.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - frame_shell.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) # frame_run. frame_run.pack(side=TOP, padx=5, pady=0, fill=X) startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5) @@ -2037,10 +1712,11 @@ class GenPage(Frame): win_height_title.pack(side=RIGHT, anchor=E, pady=5) self.win_width_int.pack(side=RIGHT, anchor=E, padx=10, pady=5) win_width_title.pack(side=RIGHT, anchor=E, pady=5) - # frame_cursor_blink. - frame_cursor_blink.pack(side=TOP, padx=5, pady=0, fill=X) - cursor_blink_title.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.cursor_blink_bool.pack(side=LEFT, padx=5, pady=5) + # frame_cursor. + frame_cursor.pack(side=TOP, padx=5, pady=0, fill=X) + indent_title.pack(side=LEFT, anchor=W, padx=5) + self.indent_chooser.pack(side=LEFT, anchor=W, padx=10) + self.cursor_blink_bool.pack(side=RIGHT, anchor=E, padx=15, pady=5) # frame_autocomplete. frame_autocomplete.pack(side=TOP, padx=5, pady=0, fill=X) auto_wait_title.pack(side=LEFT, anchor=W, padx=5, pady=5) @@ -2053,41 +1729,12 @@ class GenPage(Frame): paren_time_title.pack(side=LEFT, anchor=W, padx=5) self.bell_on.pack(side=RIGHT, anchor=E, padx=15, pady=5) self.paren_flash_time.pack(side=TOP, anchor=W, padx=15, pady=5) - - # frame_save. - frame_save.pack(side=TOP, padx=5, pady=0, fill=X) - run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.save_auto_on.pack(side=RIGHT, anchor=W, padx=5, pady=5) - self.save_ask_on.pack(side=RIGHT, anchor=W, padx=5, pady=5) # frame_format. frame_format.pack(side=TOP, padx=5, pady=0, fill=X) format_width_title.pack(side=LEFT, anchor=W, padx=5, pady=5) self.format_width_int.pack(side=TOP, padx=10, pady=5) - # frame_line_numbers_default. - frame_line_numbers_default.pack(side=TOP, padx=5, pady=0, fill=X) - line_numbers_default_title.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.line_numbers_default_bool.pack(side=LEFT, padx=5, pady=5) - # frame_context. - frame_context.pack(side=TOP, padx=5, pady=0, fill=X) - context_title.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.context_int.pack(side=TOP, padx=5, pady=5) - # frame_auto_squeeze_min_lines - frame_auto_squeeze_min_lines.pack(side=TOP, padx=5, pady=0, fill=X) - auto_squeeze_min_lines_title.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.auto_squeeze_min_lines_int.pack(side=TOP, padx=5, pady=5) - - # frame_help. - frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y) - frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y) - self.helplist.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH) - self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5) - self.button_helplist_add.pack(side=TOP, anchor=W) - self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5) - - def load_general_cfg(self): - "Load current configuration settings for the general options." + def load_windows_cfg(self): # Set variables for all windows. self.startup_edit.set(idleConf.GetOption( 'main', 'General', 'editor-on-startup', type='bool')) @@ -2095,6 +1742,8 @@ class GenPage(Frame): 'main', 'EditorWindow', 'width', type='int')) self.win_height.set(idleConf.GetOption( 'main', 'EditorWindow', 'height', type='int')) + self.indent_spaces.set(idleConf.GetOption( + 'main', 'Indent', 'num-spaces', type='int')) self.cursor_blink.set(idleConf.GetOption( 'main', 'EditorWindow', 'cursor-blink', type='bool')) self.autocomplete_wait.set(idleConf.GetOption( @@ -2105,27 +1754,394 @@ class GenPage(Frame): 'extensions', 'ParenMatch', 'flash-delay', type='int')) self.paren_bell.set(idleConf.GetOption( 'extensions', 'ParenMatch', 'bell')) + self.format_width.set(idleConf.GetOption( + 'extensions', 'FormatParagraph', 'max-width', type='int')) + + +class ShedPage(Frame): + + def __init__(self, master): + super().__init__(master) + + self.init_validators() + self.create_page_shed() + self.load_shelled_cfg() + + def init_validators(self): + digits_or_empty_re = re.compile(r'[0-9]*') + def is_digits_or_empty(s): + "Return 's is blank or contains only digits'" + return digits_or_empty_re.fullmatch(s) is not None + self.digits_only = (self.register(is_digits_or_empty), '%P',) + + def create_page_shed(self): + """Return frame of widgets for Shell/Ed tab. + + Enable users to provisionally change shell and editor options. + Function load_shed_cfg initializes tk variables using idleConf. + Entry box auto_squeeze_min_lines_int sets + auto_squeeze_min_lines_int. Setting var_name invokes the + default callback that adds option to changes. + + Widgets for ShedPage(Frame): (*) widgets bound to self + frame_shell: LabelFrame + frame_auto_squeeze_min_lines: Frame + auto_squeeze_min_lines_title: Label + (*)auto_squeeze_min_lines_int: Entry - + auto_squeeze_min_lines + frame_editor: LabelFrame + frame_save: Frame + run_save_title: Label + (*)save_ask_on: Radiobutton - autosave + (*)save_auto_on: Radiobutton - autosave + frame_format: Frame + format_width_title: Label + (*)format_width_int: Entry - format_width + frame_line_numbers_default: Frame + line_numbers_default_title: Label + (*)line_numbers_default_bool: Checkbutton - line_numbers_default + frame_context: Frame + context_title: Label + (*)context_int: Entry - context_lines + """ + # Integer values need StringVar because int('') raises. + self.auto_squeeze_min_lines = tracers.add( + StringVar(self), ('main', 'PyShell', 'auto-squeeze-min-lines')) + + self.autosave = tracers.add( + IntVar(self), ('main', 'General', 'autosave')) + self.line_numbers_default = tracers.add( + BooleanVar(self), + ('main', 'EditorWindow', 'line-numbers-default')) + self.context_lines = tracers.add( + StringVar(self), ('extensions', 'CodeContext', 'maxlines')) + # Create widgets: + frame_shell = LabelFrame(self, borderwidth=2, relief=GROOVE, + text=' Shell Preferences') + frame_editor = LabelFrame(self, borderwidth=2, relief=GROOVE, + text=' Editor Preferences') + # Frame_shell. + frame_auto_squeeze_min_lines = Frame(frame_shell, borderwidth=0) + auto_squeeze_min_lines_title = Label(frame_auto_squeeze_min_lines, + text='Auto-Squeeze Min. Lines:') + self.auto_squeeze_min_lines_int = Entry( + frame_auto_squeeze_min_lines, width=4, + textvariable=self.auto_squeeze_min_lines, + validatecommand=self.digits_only, validate='key', + ) + # Frame_editor. + frame_save = Frame(frame_editor, borderwidth=0) + run_save_title = Label(frame_save, text='At Start of Run (F5) ') + + self.save_ask_on = Radiobutton( + frame_save, variable=self.autosave, value=0, + text="Prompt to Save") + self.save_auto_on = Radiobutton( + frame_save, variable=self.autosave, value=1, + text='No Prompt') + + frame_line_numbers_default = Frame(frame_editor, borderwidth=0) + line_numbers_default_title = Label( + frame_line_numbers_default, text='Show line numbers in new windows') + self.line_numbers_default_bool = Checkbutton( + frame_line_numbers_default, + variable=self.line_numbers_default, + width=1) + + frame_context = Frame(frame_editor, borderwidth=0) + context_title = Label(frame_context, text='Max Context Lines :') + self.context_int = Entry( + frame_context, textvariable=self.context_lines, width=3, + validatecommand=self.digits_only, validate='key', + ) + + # Pack widgets: + frame_shell.pack(side=TOP, padx=5, pady=5, fill=BOTH) + Label(self).pack() # Spacer -- better solution? + frame_editor.pack(side=TOP, padx=5, pady=5, fill=BOTH) + # frame_auto_squeeze_min_lines + frame_auto_squeeze_min_lines.pack(side=TOP, padx=5, pady=0, fill=X) + auto_squeeze_min_lines_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.auto_squeeze_min_lines_int.pack(side=TOP, padx=5, pady=5) + # frame_save. + frame_save.pack(side=TOP, padx=5, pady=0, fill=X) + run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.save_auto_on.pack(side=RIGHT, anchor=W, padx=5, pady=5) + self.save_ask_on.pack(side=RIGHT, anchor=W, padx=5, pady=5) + # frame_line_numbers_default. + frame_line_numbers_default.pack(side=TOP, padx=5, pady=0, fill=X) + line_numbers_default_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.line_numbers_default_bool.pack(side=LEFT, padx=5, pady=5) + # frame_context. + frame_context.pack(side=TOP, padx=5, pady=0, fill=X) + context_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.context_int.pack(side=TOP, padx=5, pady=5) + + def load_shelled_cfg(self): + # Set variables for shell windows. + self.auto_squeeze_min_lines.set(idleConf.GetOption( + 'main', 'PyShell', 'auto-squeeze-min-lines', type='int')) # Set variables for editor windows. self.autosave.set(idleConf.GetOption( 'main', 'General', 'autosave', default=0, type='bool')) - self.format_width.set(idleConf.GetOption( - 'extensions', 'FormatParagraph', 'max-width', type='int')) self.line_numbers_default.set(idleConf.GetOption( 'main', 'EditorWindow', 'line-numbers-default', type='bool')) self.context_lines.set(idleConf.GetOption( 'extensions', 'CodeContext', 'maxlines', type='int')) - # Set variables for shell windows. - self.auto_squeeze_min_lines.set(idleConf.GetOption( - 'main', 'PyShell', 'auto-squeeze-min-lines', type='int')) - # Set additional help sources. - self.user_helplist = idleConf.GetAllExtraHelpSourcesList() - self.helplist.delete(0, 'end') - for help_item in self.user_helplist: - self.helplist.insert(END, help_item[0]) - self.set_add_delete_state() +class ExtPage(Frame): + def __init__(self, master): + super().__init__(master) + self.ext_defaultCfg = idleConf.defaultCfg['extensions'] + self.ext_userCfg = idleConf.userCfg['extensions'] + self.is_int = self.register(is_int) + self.load_extensions() + self.create_page_extensions() # Requires extension names. + + def create_page_extensions(self): + """Configure IDLE feature extensions and help menu extensions. + + List the feature extensions and a configuration box for the + selected extension. Help menu extensions are in a HelpFrame. + + This code reads the current configuration using idleConf, + supplies a GUI interface to change the configuration values, + and saves the changes using idleConf. + + Some changes may require restarting IDLE. This depends on each + extension's implementation. + + All values are treated as text, and it is up to the user to + supply reasonable values. The only exception to this are the + 'enable*' options, which are boolean, and can be toggled with a + True/False button. + + Methods: + extension_selected: Handle selection from list. + create_extension_frame: Hold widgets for one extension. + set_extension_value: Set in userCfg['extensions']. + save_all_changed_extensions: Call extension page Save(). + """ + self.extension_names = StringVar(self) + + frame_ext = LabelFrame(self, borderwidth=2, relief=GROOVE, + text=' Feature Extensions ') + self.frame_help = HelpFrame(self, borderwidth=2, relief=GROOVE, + text=' Help Menu Extensions ') + + frame_ext.rowconfigure(0, weight=1) + frame_ext.columnconfigure(2, weight=1) + self.extension_list = Listbox(frame_ext, listvariable=self.extension_names, + selectmode='browse') + self.extension_list.bind('<>', self.extension_selected) + scroll = Scrollbar(frame_ext, command=self.extension_list.yview) + self.extension_list.yscrollcommand=scroll.set + self.details_frame = LabelFrame(frame_ext, width=250, height=250) + self.extension_list.grid(column=0, row=0, sticky='nws') + scroll.grid(column=1, row=0, sticky='ns') + self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0]) + frame_ext.configure(padding=10) + self.config_frame = {} + self.current_extension = None + + self.outerframe = self # TEMPORARY + self.tabbed_page_set = self.extension_list # TEMPORARY + + # Create the frame holding controls for each extension. + ext_names = '' + for ext_name in sorted(self.extensions): + self.create_extension_frame(ext_name) + ext_names = ext_names + '{' + ext_name + '} ' + self.extension_names.set(ext_names) + self.extension_list.selection_set(0) + self.extension_selected(None) + + + frame_ext.grid(row=0, column=0, sticky='nsew') + Label(self).grid(row=1, column=0) # Spacer. Replace with config? + self.frame_help.grid(row=2, column=0, sticky='sew') + + def load_extensions(self): + "Fill self.extensions with data from the default and user configs." + self.extensions = {} + for ext_name in idleConf.GetExtensions(active_only=False): + # Former built-in extensions are already filtered out. + self.extensions[ext_name] = [] + + for ext_name in self.extensions: + opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name)) + + # Bring 'enable' options to the beginning of the list. + enables = [opt_name for opt_name in opt_list + if opt_name.startswith('enable')] + for opt_name in enables: + opt_list.remove(opt_name) + opt_list = enables + opt_list + + for opt_name in opt_list: + def_str = self.ext_defaultCfg.Get( + ext_name, opt_name, raw=True) + try: + def_obj = {'True':True, 'False':False}[def_str] + opt_type = 'bool' + except KeyError: + try: + def_obj = int(def_str) + opt_type = 'int' + except ValueError: + def_obj = def_str + opt_type = None + try: + value = self.ext_userCfg.Get( + ext_name, opt_name, type=opt_type, raw=True, + default=def_obj) + except ValueError: # Need this until .Get fixed. + value = def_obj # Bad values overwritten by entry. + var = StringVar(self) + var.set(str(value)) + + self.extensions[ext_name].append({'name': opt_name, + 'type': opt_type, + 'default': def_str, + 'value': value, + 'var': var, + }) + + def extension_selected(self, event): + "Handle selection of an extension from the list." + newsel = self.extension_list.curselection() + if newsel: + newsel = self.extension_list.get(newsel) + if newsel is None or newsel != self.current_extension: + if self.current_extension: + self.details_frame.config(text='') + self.config_frame[self.current_extension].grid_forget() + self.current_extension = None + if newsel: + self.details_frame.config(text=newsel) + self.config_frame[newsel].grid(column=0, row=0, sticky='nsew') + self.current_extension = newsel + + def create_extension_frame(self, ext_name): + """Create a frame holding the widgets to configure one extension""" + f = VerticalScrolledFrame(self.details_frame, height=250, width=250) + self.config_frame[ext_name] = f + entry_area = f.interior + # Create an entry for each configuration option. + for row, opt in enumerate(self.extensions[ext_name]): + # Create a row with a label and entry/checkbutton. + label = Label(entry_area, text=opt['name']) + label.grid(row=row, column=0, sticky=NW) + var = opt['var'] + if opt['type'] == 'bool': + Checkbutton(entry_area, variable=var, + onvalue='True', offvalue='False', width=8 + ).grid(row=row, column=1, sticky=W, padx=7) + elif opt['type'] == 'int': + Entry(entry_area, textvariable=var, validate='key', + validatecommand=(self.is_int, '%P'), width=10 + ).grid(row=row, column=1, sticky=NSEW, padx=7) + + else: # type == 'str' + # Limit size to fit non-expanding space with larger font. + Entry(entry_area, textvariable=var, width=15 + ).grid(row=row, column=1, sticky=NSEW, padx=7) + return + + def set_extension_value(self, section, opt): + """Return True if the configuration was added or changed. + + If the value is the same as the default, then remove it + from user config file. + """ + name = opt['name'] + default = opt['default'] + value = opt['var'].get().strip() or default + opt['var'].set(value) + # if self.defaultCfg.has_section(section): + # Currently, always true; if not, indent to return. + if (value == default): + return self.ext_userCfg.RemoveOption(section, name) + # Set the option. + return self.ext_userCfg.SetOption(section, name, value) + + def save_all_changed_extensions(self): + """Save configuration changes to the user config file. + + Attributes accessed: + extensions + + Methods: + set_extension_value + """ + has_changes = False + for ext_name in self.extensions: + options = self.extensions[ext_name] + for opt in options: + if self.set_extension_value(ext_name, opt): + has_changes = True + if has_changes: + self.ext_userCfg.Save() + + +class HelpFrame(LabelFrame): + + def __init__(self, master, **cfg): + super().__init__(master, **cfg) + self.create_frame_help() + self.load_helplist() + + def create_frame_help(self): + """Create LabelFrame for additional help menu sources. + + load_helplist loads list user_helplist with + name, position pairs and copies names to listbox helplist. + Clicking a name invokes help_source selected. Clicking + button_helplist_name invokes helplist_item_name, which also + changes user_helplist. These functions all call + set_add_delete_state. All but load call update_help_changes to + rewrite changes['main']['HelpFiles']. + + Widgets for HelpFrame(LabelFrame): (*) widgets bound to self + frame_helplist: Frame + (*)helplist: ListBox + scroll_helplist: Scrollbar + frame_buttons: Frame + (*)button_helplist_edit + (*)button_helplist_add + (*)button_helplist_remove + """ + # self = frame_help in dialog (until ExtPage class). + frame_helplist = Frame(self) + self.helplist = Listbox( + frame_helplist, height=5, takefocus=True, + exportselection=FALSE) + scroll_helplist = Scrollbar(frame_helplist) + scroll_helplist['command'] = self.helplist.yview + self.helplist['yscrollcommand'] = scroll_helplist.set + self.helplist.bind('', self.help_source_selected) + + frame_buttons = Frame(self) + self.button_helplist_edit = Button( + frame_buttons, text='Edit', state='disabled', + width=8, command=self.helplist_item_edit) + self.button_helplist_add = Button( + frame_buttons, text='Add', + width=8, command=self.helplist_item_add) + self.button_helplist_remove = Button( + frame_buttons, text='Remove', state='disabled', + width=8, command=self.helplist_item_remove) + + # Pack frame_help. + frame_helplist.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) + self.helplist.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH) + scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y) + frame_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y) + self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5) + self.button_helplist_add.pack(side=TOP, anchor=W) + self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5) def help_source_selected(self, event): "Handle event for selecting additional help." @@ -2195,6 +2211,14 @@ class GenPage(Frame): 'main', 'HelpFiles', str(num), ';'.join(self.user_helplist[num-1][:2])) + def load_helplist(self): + # Set additional help sources. + self.user_helplist = idleConf.GetAllExtraHelpSourcesList() + self.helplist.delete(0, 'end') + for help_item in self.user_helplist: + self.helplist.insert(END, help_item[0]) + self.set_add_delete_state() + class VarTrace: """Maintain Tk variables trace state.""" diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index e80384b7..3f87e89f 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -5,7 +5,7 @@ - IDLE — Python 3.10.0a6 documentation + IDLE — Python 3.11.0a0 documentation @@ -18,7 +18,7 @@ @@ -71,7 +71,7 @@

  • - 3.10.0a6 Documentation » + 3.11.0a0 Documentation »
  • @@ -102,7 +102,7 @@

    IDLE¶

    -

    Source code: Lib/idlelib/

    +

    Source code: Lib/idlelib/


    IDLE is Python’s Integrated Development and Learning Environment.

    IDLE has the following features:

    @@ -685,7 +685,7 @@ intended to be the same as executing the same code by the default method, directly with Python in a text-mode system console or terminal window. However, the different interface and operation occasionally affect visible results. For instance, sys.modules starts with more entries, -and threading.activeCount() returns 2 instead of 1.

    +and threading.active_count() returns 2 instead of 1.

    By default, IDLE runs user code in a separate OS process rather than in the user interface process that runs the shell and editor. In the execution process, it replaces sys.stdin, sys.stdout, and sys.stderr @@ -939,7 +939,7 @@ also used for testing.

    • Report a Bug
    • - Show Source
    • @@ -971,7 +971,7 @@ also used for testing.

    • - 3.10.0a6 Documentation » + 3.11.0a0 Documentation »
    • @@ -997,13 +997,19 @@ also used for testing.