Skip to content
Merged
39 changes: 27 additions & 12 deletions Android/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
ANDROID_DIR.name == "Android" and (PYTHON_DIR / "pyconfig.h.in").exists()
)

ENV_SCRIPT = ANDROID_DIR / "android-env.sh"
TESTBED_DIR = ANDROID_DIR / "testbed"
CROSS_BUILD_DIR = PYTHON_DIR / "cross-build"

Expand Down Expand Up @@ -129,12 +130,11 @@ def android_env(host):
sysconfig_filename = next(sysconfig_files).name
host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1]

env_script = ANDROID_DIR / "android-env.sh"
env_output = subprocess.run(
f"set -eu; "
f"HOST={host}; "
f"PREFIX={prefix}; "
f". {env_script}; "
f". {ENV_SCRIPT}; "
f"export",
check=True, shell=True, capture_output=True, encoding='utf-8',
).stdout
Expand All @@ -151,7 +151,7 @@ def android_env(host):
env[key] = value

if not env:
raise ValueError(f"Found no variables in {env_script.name} output:\n"
raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n"
+ env_output)
return env

Expand Down Expand Up @@ -281,15 +281,30 @@ def clean_all(context):


def setup_ci():
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
if "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux":
run(
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
text=True,
)
run(["sudo", "udevadm", "control", "--reload-rules"])
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
if "GITHUB_ACTIONS" in os.environ:
# Enable emulator hardware acceleration
# (https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
if platform.system() == "Linux":
run(
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
text=True,
)
run(["sudo", "udevadm", "control", "--reload-rules"])
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])

# Free up disk space by deleting unused versions of the NDK
# (https://github.com/freakboy3742/pyspamsum/pull/108).
for line in ENV_SCRIPT.read_text().splitlines():
if match := re.fullmatch(r"ndk_version=(.+)", line):
ndk_version = match[1]
break
else:
raise ValueError(f"Failed to find NDK version in {ENV_SCRIPT.name}")

for item in (android_home / "ndk").iterdir():
if item.name[0].isdigit() and item.name != ndk_version:
delete_glob(item)


def setup_sdk():
Expand Down
4 changes: 2 additions & 2 deletions Android/testbed/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ android {
val androidEnvFile = file("../../android-env.sh").absoluteFile

namespace = "org.python.testbed"
compileSdk = 34
compileSdk = 35

defaultConfig {
applicationId = "org.python.testbed"
Expand All @@ -92,7 +92,7 @@ android {
}
throw GradleException("Failed to find API level in $androidEnvFile")
}
targetSdk = 34
targetSdk = 35

versionCode = 1
versionName = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/set.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.

Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an
error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~frozenset.discard`
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard`
method, this function does not automatically convert unhashable sets into
temporary frozensets. Raise :exc:`SystemError` if *set* is not an
instance of :class:`set` or its subtype.
Expand Down
9 changes: 9 additions & 0 deletions Doc/library/readline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ Startup hooks
if Python was compiled for a version of the library that supports it.


.. function:: get_pre_input_hook()

Get the current pre-input hook function, or ``None`` if no pre-input hook
function has been set. This function only exists if Python was compiled
for a version of the library that supports it.

.. versionadded:: next


.. _readline-completion:

Completion
Expand Down
210 changes: 109 additions & 101 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4826,7 +4826,7 @@ other sequence-like behavior.

There are currently two built-in set types, :class:`set` and :class:`frozenset`.
The :class:`set` type is mutable --- the contents can be changed using methods
like :meth:`add <frozenset.add>` and :meth:`remove <frozenset.add>`.
like :meth:`~set.add` and :meth:`~set.remove`.
Since it is mutable, it has no hash value and cannot be used as
either a dictionary key or as an element of another set.
The :class:`frozenset` type is immutable and :term:`hashable` ---
Expand All @@ -4848,164 +4848,172 @@ The constructors for both classes work the same:
objects. If *iterable* is not specified, a new empty set is
returned.

Sets can be created by several means:
Sets can be created by several means:

* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``
* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``

Instances of :class:`set` and :class:`frozenset` provide the following
operations:
Instances of :class:`set` and :class:`frozenset` provide the following
operations:

.. describe:: len(s)
.. describe:: len(s)

Return the number of elements in set *s* (cardinality of *s*).
Return the number of elements in set *s* (cardinality of *s*).

.. describe:: x in s
.. describe:: x in s

Test *x* for membership in *s*.
Test *x* for membership in *s*.

.. describe:: x not in s
.. describe:: x not in s

Test *x* for non-membership in *s*.
Test *x* for non-membership in *s*.

.. method:: isdisjoint(other, /)
.. method:: frozenset.isdisjoint(other, /)
set.isdisjoint(other, /)

Return ``True`` if the set has no elements in common with *other*. Sets are
disjoint if and only if their intersection is the empty set.
Return ``True`` if the set has no elements in common with *other*. Sets are
disjoint if and only if their intersection is the empty set.

.. method:: issubset(other, /)
set <= other
.. method:: frozenset.issubset(other, /)
set.issubset(other, /)
.. describe:: set <= other

Test whether every element in the set is in *other*.
Test whether every element in the set is in *other*.

.. method:: set < other
.. describe:: set < other

Test whether the set is a proper subset of *other*, that is,
``set <= other and set != other``.
Test whether the set is a proper subset of *other*, that is,
``set <= other and set != other``.

.. method:: issuperset(other, /)
set >= other
.. method:: frozenset.issuperset(other, /)
set.issuperset(other, /)
.. describe:: set >= other

Test whether every element in *other* is in the set.
Test whether every element in *other* is in the set.

.. method:: set > other
.. describe:: set > other

Test whether the set is a proper superset of *other*, that is, ``set >=
other and set != other``.
Test whether the set is a proper superset of *other*, that is, ``set >=
other and set != other``.

.. method:: union(*others)
set | other | ...
.. method:: frozenset.union(*others)
set.union(*others)
.. describe:: set | other | ...

Return a new set with elements from the set and all others.
Return a new set with elements from the set and all others.

.. method:: intersection(*others)
set & other & ...
.. method:: frozenset.intersection(*others)
set.intersection(*others)
.. describe:: set & other & ...

Return a new set with elements common to the set and all others.
Return a new set with elements common to the set and all others.

.. method:: difference(*others)
set - other - ...
.. method:: frozenset.difference(*others)
set.difference(*others)
.. describe:: set - other - ...

Return a new set with elements in the set that are not in the others.
Return a new set with elements in the set that are not in the others.

.. method:: symmetric_difference(other, /)
set ^ other
.. method:: frozenset.symmetric_difference(other, /)
set.symmetric_difference(other, /)
.. describe:: set ^ other

Return a new set with elements in either the set or *other* but not both.
Return a new set with elements in either the set or *other* but not both.

.. method:: copy()
.. method:: frozenset.copy()
set.copy()

Return a shallow copy of the set.
Return a shallow copy of the set.


Note, the non-operator versions of :meth:`union`, :meth:`intersection`,
:meth:`difference`, :meth:`symmetric_difference`, :meth:`issubset`, and
:meth:`issuperset` methods will accept any iterable as an argument. In
contrast, their operator based counterparts require their arguments to be
sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
in favor of the more readable ``set('abc').intersection('cbs')``.
Note, the non-operator versions of :meth:`~frozenset.union`,
:meth:`~frozenset.intersection`, :meth:`~frozenset.difference`, :meth:`~frozenset.symmetric_difference`, :meth:`~frozenset.issubset`, and
:meth:`~frozenset.issuperset` methods will accept any iterable as an argument. In
contrast, their operator based counterparts require their arguments to be
sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
in favor of the more readable ``set('abc').intersection('cbs')``.

Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
sets are equal if and only if every element of each set is contained in the
other (each is a subset of the other). A set is less than another set if and
only if the first set is a proper subset of the second set (is a subset, but
is not equal). A set is greater than another set if and only if the first set
is a proper superset of the second set (is a superset, but is not equal).
Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
sets are equal if and only if every element of each set is contained in the
other (each is a subset of the other). A set is less than another set if and
only if the first set is a proper subset of the second set (is a subset, but
is not equal). A set is greater than another set if and only if the first set
is a proper superset of the second set (is a superset, but is not equal).

Instances of :class:`set` are compared to instances of :class:`frozenset`
based on their members. For example, ``set('abc') == frozenset('abc')``
returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.
Instances of :class:`set` are compared to instances of :class:`frozenset`
based on their members. For example, ``set('abc') == frozenset('abc')``
returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.

The subset and equality comparisons do not generalize to a total ordering
function. For example, any two nonempty disjoint sets are not equal and are not
subsets of each other, so *all* of the following return ``False``: ``a<b``,
``a==b``, or ``a>b``.
The subset and equality comparisons do not generalize to a total ordering
function. For example, any two nonempty disjoint sets are not equal and are not
subsets of each other, so *all* of the following return ``False``: ``a<b``,
``a==b``, or ``a>b``.

Since sets only define partial ordering (subset relationships), the output of
the :meth:`list.sort` method is undefined for lists of sets.
Since sets only define partial ordering (subset relationships), the output of
the :meth:`list.sort` method is undefined for lists of sets.

Set elements, like dictionary keys, must be :term:`hashable`.
Set elements, like dictionary keys, must be :term:`hashable`.

Binary operations that mix :class:`set` instances with :class:`frozenset`
return the type of the first operand. For example: ``frozenset('ab') |
set('bc')`` returns an instance of :class:`frozenset`.
Binary operations that mix :class:`set` instances with :class:`frozenset`
return the type of the first operand. For example: ``frozenset('ab') |
set('bc')`` returns an instance of :class:`frozenset`.

The following table lists operations available for :class:`set` that do not
apply to immutable instances of :class:`frozenset`:
The following table lists operations available for :class:`set` that do not
apply to immutable instances of :class:`frozenset`:

.. method:: update(*others)
set |= other | ...
.. method:: set.update(*others)
.. describe:: set |= other | ...

Update the set, adding elements from all others.
Update the set, adding elements from all others.

.. method:: intersection_update(*others)
set &= other & ...
.. method:: set.intersection_update(*others)
.. describe:: set &= other & ...

Update the set, keeping only elements found in it and all others.
Update the set, keeping only elements found in it and all others.

.. method:: difference_update(*others)
set -= other | ...
.. method:: set.difference_update(*others)
.. describe:: set -= other | ...

Update the set, removing elements found in others.
Update the set, removing elements found in others.

.. method:: symmetric_difference_update(other, /)
set ^= other
.. method:: set.symmetric_difference_update(other, /)
.. describe:: set ^= other

Update the set, keeping only elements found in either set, but not in both.
Update the set, keeping only elements found in either set, but not in both.

.. method:: add(elem, /)
.. method:: set.add(elem, /)

Add element *elem* to the set.
Add element *elem* to the set.

.. method:: remove(elem, /)
.. method:: set.remove(elem, /)

Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
not contained in the set.
Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
not contained in the set.

.. method:: discard(elem, /)
.. method:: set.discard(elem, /)

Remove element *elem* from the set if it is present.
Remove element *elem* from the set if it is present.

.. method:: pop()
.. method:: set.pop()

Remove and return an arbitrary element from the set. Raises
:exc:`KeyError` if the set is empty.
Remove and return an arbitrary element from the set. Raises
:exc:`KeyError` if the set is empty.

.. method:: clear()
.. method:: set.clear()

Remove all elements from the set.
Remove all elements from the set.


Note, the non-operator versions of the :meth:`update`,
:meth:`intersection_update`, :meth:`difference_update`, and
:meth:`symmetric_difference_update` methods will accept any iterable as an
argument.
Note, the non-operator versions of the :meth:`~set.update`,
:meth:`~set.intersection_update`, :meth:`~set.difference_update`, and
:meth:`~set.symmetric_difference_update` methods will accept any iterable as an
argument.

Note, the *elem* argument to the :meth:`~object.__contains__`,
:meth:`remove`, and
:meth:`discard` methods may be a set. To support searching for an equivalent
frozenset, a temporary one is created from *elem*.
Note, the *elem* argument to the :meth:`~object.__contains__`,
:meth:`~set.remove`, and
:meth:`~set.discard` methods may be a set. To support searching for an equivalent
frozenset, a temporary one is created from *elem*.


.. _typesmapping:
Expand Down
Loading
Loading