Skip to content

Commit

Permalink
Merge branch 'main' into ios-configure-targets
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Feb 25, 2024
2 parents 6247052 + f745586 commit ee41015
Show file tree
Hide file tree
Showing 42 changed files with 877 additions and 355 deletions.
449 changes: 449 additions & 0 deletions Doc/howto/gdb_helpers.rst

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Doc/howto/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Currently, the HOWTOs are:
cporting.rst
curses.rst
descriptor.rst
gdb_helpers.rst
enum.rst
functional.rst
logging.rst
Expand Down
1 change: 0 additions & 1 deletion Doc/library/array.rst
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,3 @@ Examples::

`NumPy <https://numpy.org/>`_
The NumPy package defines another array type.

6 changes: 3 additions & 3 deletions Doc/library/ctypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ calls).
Python objects that can directly be used as parameters in these function calls.
``None`` is passed as a C ``NULL`` pointer, bytes objects and strings are passed
as pointer to the memory block that contains their data (:c:expr:`char *` or
:c:expr:`wchar_t *`). Python integers are passed as the platforms default C
:c:expr:`wchar_t *`). Python integers are passed as the platform's default C
:c:expr:`int` type, their value is masked to fit into the C type.

Before we move on calling functions with other parameter types, we have to learn
Expand Down Expand Up @@ -1445,7 +1445,7 @@ function exported by these libraries, and reacquired afterwards.
All these classes can be instantiated by calling them with at least one
argument, the pathname of the shared library. If you have an existing handle to
an already loaded shared library, it can be passed as the ``handle`` named
parameter, otherwise the underlying platforms :c:func:`!dlopen` or
parameter, otherwise the underlying platform's :c:func:`!dlopen` or
:c:func:`!LoadLibrary` function is used to load the library into
the process, and to get a handle to it.

Expand All @@ -1456,7 +1456,7 @@ configurable.

The *use_errno* parameter, when set to true, enables a ctypes mechanism that
allows accessing the system :data:`errno` error number in a safe way.
:mod:`ctypes` maintains a thread-local copy of the systems :data:`errno`
:mod:`ctypes` maintains a thread-local copy of the system's :data:`errno`
variable; if you call foreign functions created with ``use_errno=True`` then the
:data:`errno` value before the function call is swapped with the ctypes private
copy, the same happens immediately after the function call.
Expand Down
8 changes: 6 additions & 2 deletions Doc/library/pyexpat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ XMLParser Objects
:meth:`CharacterDataHandler` callback whenever possible. This can improve
performance substantially since Expat normally breaks character data into chunks
at every line ending. This attribute is false by default, and may be changed at
any time.
any time. Note that when it is false, data that does not contain newlines
may be chunked too.


.. attribute:: xmlparser.buffer_used
Expand Down Expand Up @@ -372,7 +373,10 @@ otherwise stated.
marked content, and ignorable whitespace. Applications which must distinguish
these cases can use the :attr:`StartCdataSectionHandler`,
:attr:`EndCdataSectionHandler`, and :attr:`ElementDeclHandler` callbacks to
collect the required information.
collect the required information. Note that the character data may be
chunked even if it is short and so you may receive more than one call to
:meth:`CharacterDataHandler`. Set the :attr:`buffer_text` instance attribute
to ``True`` to avoid that.


.. method:: xmlparser.UnparsedEntityDeclHandler(entityName, base, systemId, publicId, notationName)
Expand Down
8 changes: 4 additions & 4 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ represented by objects.)
Every object has an identity, a type and a value. An object's *identity* never
changes once it has been created; you may think of it as the object's address in
memory. The ':keyword:`is`' operator compares the identity of two objects; the
memory. The :keyword:`is` operator compares the identity of two objects; the
:func:`id` function returns an integer representing its identity.

.. impl-detail::
Expand Down Expand Up @@ -81,16 +81,16 @@ are still reachable.

Note that the use of the implementation's tracing or debugging facilities may
keep objects alive that would normally be collectable. Also note that catching
an exception with a ':keyword:`try`...\ :keyword:`except`' statement may keep
an exception with a :keyword:`try`...\ :keyword:`except` statement may keep
objects alive.

Some objects contain references to "external" resources such as open files or
windows. It is understood that these resources are freed when the object is
garbage-collected, but since garbage collection is not guaranteed to happen,
such objects also provide an explicit way to release the external resource,
usually a :meth:`!close` method. Programs are strongly recommended to explicitly
close such objects. The ':keyword:`try`...\ :keyword:`finally`' statement
and the ':keyword:`with`' statement provide convenient ways to do this.
close such objects. The :keyword:`try`...\ :keyword:`finally` statement
and the :keyword:`with` statement provide convenient ways to do this.

.. index:: single: container

Expand Down
2 changes: 1 addition & 1 deletion Doc/using/windows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ know about when using Python on Microsoft Windows.

Unlike most Unix systems and services, Windows does not include a system
supported installation of Python. To make Python available, the CPython team
has compiled Windows installers (MSI packages) with every `release
has compiled Windows installers with every `release
<https://www.python.org/downloads/>`_ for many years. These installers
are primarily intended to add a per-user installation of Python, with the
core interpreter and library being used by a single user. The installer is also
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ ipaddress
* Add the :attr:`ipaddress.IPv4Address.ipv6_mapped` property, which returns the IPv4-mapped IPv6 address.
(Contributed by Charles Machalow in :gh:`109466`.)

itertools
---------

* Added a ``strict`` option to :func:`itertools.batched`.
This raises a :exc:`ValueError` if the final batch is shorter
than the specified batch size.
(Contributed by Raymond Hettinger in :gh:`113202`.)

marshal
-------

Expand Down
81 changes: 51 additions & 30 deletions Lib/importlib/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import _imp
import sys
import threading
import types


Expand Down Expand Up @@ -171,36 +172,54 @@ class _LazyModule(types.ModuleType):

def __getattribute__(self, attr):
"""Trigger the load of the module and return the attribute."""
# All module metadata must be garnered from __spec__ in order to avoid
# using mutated values.
# Stop triggering this method.
self.__class__ = types.ModuleType
# Get the original name to make sure no object substitution occurred
# in sys.modules.
original_name = self.__spec__.name
# Figure out exactly what attributes were mutated between the creation
# of the module and now.
attrs_then = self.__spec__.loader_state['__dict__']
attrs_now = self.__dict__
attrs_updated = {}
for key, value in attrs_now.items():
# Code that set the attribute may have kept a reference to the
# assigned object, making identity more important than equality.
if key not in attrs_then:
attrs_updated[key] = value
elif id(attrs_now[key]) != id(attrs_then[key]):
attrs_updated[key] = value
self.__spec__.loader.exec_module(self)
# If exec_module() was used directly there is no guarantee the module
# object was put into sys.modules.
if original_name in sys.modules:
if id(self) != id(sys.modules[original_name]):
raise ValueError(f"module object for {original_name!r} "
"substituted in sys.modules during a lazy "
"load")
# Update after loading since that's what would happen in an eager
# loading situation.
self.__dict__.update(attrs_updated)
__spec__ = object.__getattribute__(self, '__spec__')
loader_state = __spec__.loader_state
with loader_state['lock']:
# Only the first thread to get the lock should trigger the load
# and reset the module's class. The rest can now getattr().
if object.__getattribute__(self, '__class__') is _LazyModule:
# The first thread comes here multiple times as it descends the
# call stack. The first time, it sets is_loading and triggers
# exec_module(), which will access module.__dict__, module.__name__,
# and/or module.__spec__, reentering this method. These accesses
# need to be allowed to proceed without triggering the load again.
if loader_state['is_loading'] and attr.startswith('__') and attr.endswith('__'):
return object.__getattribute__(self, attr)
loader_state['is_loading'] = True

__dict__ = object.__getattribute__(self, '__dict__')

# All module metadata must be gathered from __spec__ in order to avoid
# using mutated values.
# Get the original name to make sure no object substitution occurred
# in sys.modules.
original_name = __spec__.name
# Figure out exactly what attributes were mutated between the creation
# of the module and now.
attrs_then = loader_state['__dict__']
attrs_now = __dict__
attrs_updated = {}
for key, value in attrs_now.items():
# Code that set an attribute may have kept a reference to the
# assigned object, making identity more important than equality.
if key not in attrs_then:
attrs_updated[key] = value
elif id(attrs_now[key]) != id(attrs_then[key]):
attrs_updated[key] = value
__spec__.loader.exec_module(self)
# If exec_module() was used directly there is no guarantee the module
# object was put into sys.modules.
if original_name in sys.modules:
if id(self) != id(sys.modules[original_name]):
raise ValueError(f"module object for {original_name!r} "
"substituted in sys.modules during a lazy "
"load")
# Update after loading since that's what would happen in an eager
# loading situation.
__dict__.update(attrs_updated)
# Finally, stop triggering this method.
self.__class__ = types.ModuleType

return getattr(self, attr)

def __delattr__(self, attr):
Expand Down Expand Up @@ -244,5 +263,7 @@ def exec_module(self, module):
loader_state = {}
loader_state['__dict__'] = module.__dict__.copy()
loader_state['__class__'] = module.__class__
loader_state['lock'] = threading.RLock()
loader_state['is_loading'] = False
module.__spec__.loader_state = loader_state
module.__class__ = _LazyModule
10 changes: 9 additions & 1 deletion Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,14 @@ def with_name(self, name):

def with_stem(self, stem):
"""Return a new path with the stem changed."""
return self.with_name(stem + self.suffix)
suffix = self.suffix
if not suffix:
return self.with_name(stem)
elif not stem:
# If the suffix is non-empty, we can't make the stem empty.
raise ValueError(f"{self!r} has a non-empty suffix")
else:
return self.with_name(stem + suffix)

def with_suffix(self, suffix):
"""Return a new path with the file suffix changed. If the path
Expand All @@ -324,6 +331,7 @@ def with_suffix(self, suffix):
if not suffix:
return self.with_name(stem)
elif not stem:
# If the stem is empty, we can't make the suffix non-empty.
raise ValueError(f"{self!r} has an empty name")
elif suffix.startswith('.') and len(suffix) > 1:
return self.with_name(stem + suffix)
Expand Down
7 changes: 7 additions & 0 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,13 @@ def test_extend(self):
a = bytearray(b'')
a.extend([Indexable(ord('a'))])
self.assertEqual(a, b'a')
a = bytearray(b'abc')
self.assertRaisesRegex(TypeError, # Override for string.
"expected iterable of integers; got: 'str'",
a.extend, 'def')
self.assertRaisesRegex(TypeError, # But not for others.
"can't extend bytearray with float",
a.extend, 1.0)

def test_remove(self):
b = bytearray(b'hello')
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import textwrap
import unittest
import gc
import os

import _testinternalcapi

Expand Down Expand Up @@ -568,6 +569,8 @@ def testfunc(n):
count = ops.count("_GUARD_IS_TRUE_POP") + ops.count("_GUARD_IS_FALSE_POP")
self.assertLessEqual(count, 2)


@unittest.skipIf(os.getenv("PYTHONUOPSOPTIMIZE", default=0) == 0, "Needs uop optimizer to run.")
class TestUopsOptimization(unittest.TestCase):

def _run_with_optimizer(self, testfunc, arg):
Expand Down
54 changes: 39 additions & 15 deletions Lib/test/test_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,11 @@ def test_write_lineterminator(self):
writer = csv.writer(sio, lineterminator=lineterminator)
writer.writerow(['a', 'b'])
writer.writerow([1, 2])
writer.writerow(['\r', '\n'])
self.assertEqual(sio.getvalue(),
f'a,b{lineterminator}'
f'1,2{lineterminator}')
f'1,2{lineterminator}'
f'"\r","\n"{lineterminator}')

def test_write_iterable(self):
self._write_test(iter(['a', 1, 'p,q']), 'a,1,"p,q"')
Expand Down Expand Up @@ -507,22 +509,44 @@ def test_read_linenum(self):
self.assertEqual(r.line_num, 3)

def test_roundtrip_quoteed_newlines(self):
with TemporaryFile("w+", encoding="utf-8", newline='') as fileobj:
writer = csv.writer(fileobj)
rows = [['a\nb','b'],['c','x\r\nd']]
writer.writerows(rows)
fileobj.seek(0)
for i, row in enumerate(csv.reader(fileobj)):
self.assertEqual(row, rows[i])
rows = [
['\na', 'b\nc', 'd\n'],
['\re', 'f\rg', 'h\r'],
['\r\ni', 'j\r\nk', 'l\r\n'],
['\n\rm', 'n\n\ro', 'p\n\r'],
['\r\rq', 'r\r\rs', 't\r\r'],
['\n\nu', 'v\n\nw', 'x\n\n'],
]
for lineterminator in '\r\n', '\n', '\r':
with self.subTest(lineterminator=lineterminator):
with TemporaryFile("w+", encoding="utf-8", newline='') as fileobj:
writer = csv.writer(fileobj, lineterminator=lineterminator)
writer.writerows(rows)
fileobj.seek(0)
for i, row in enumerate(csv.reader(fileobj)):
self.assertEqual(row, rows[i])

def test_roundtrip_escaped_unquoted_newlines(self):
with TemporaryFile("w+", encoding="utf-8", newline='') as fileobj:
writer = csv.writer(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")
rows = [['a\nb','b'],['c','x\r\nd']]
writer.writerows(rows)
fileobj.seek(0)
for i, row in enumerate(csv.reader(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")):
self.assertEqual(row,rows[i])
rows = [
['\na', 'b\nc', 'd\n'],
['\re', 'f\rg', 'h\r'],
['\r\ni', 'j\r\nk', 'l\r\n'],
['\n\rm', 'n\n\ro', 'p\n\r'],
['\r\rq', 'r\r\rs', 't\r\r'],
['\n\nu', 'v\n\nw', 'x\n\n'],
]
for lineterminator in '\r\n', '\n', '\r':
with self.subTest(lineterminator=lineterminator):
with TemporaryFile("w+", encoding="utf-8", newline='') as fileobj:
writer = csv.writer(fileobj, lineterminator=lineterminator,
quoting=csv.QUOTE_NONE, escapechar="\\")
writer.writerows(rows)
fileobj.seek(0)
for i, row in enumerate(csv.reader(fileobj,
quoting=csv.QUOTE_NONE,
escapechar="\\")):
self.assertEqual(row, rows[i])


class TestDialectRegistry(unittest.TestCase):
def test_registry_badargs(self):
Expand Down
Loading

0 comments on commit ee41015

Please sign in to comment.