Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Android/testbed/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ for ((i, prefix) in prefixes.withIndex()) {
val libDir = file("$prefix/lib")
val version = run {
for (filename in libDir.list()!!) {
"""python(\d+\.\d+)""".toRegex().matchEntire(filename)?.let {
"""python(\d+\.\d+[a-z]*)""".toRegex().matchEntire(filename)?.let {
return@run it.groupValues[1]
}
}
Expand All @@ -64,9 +64,10 @@ for ((i, prefix) in prefixes.withIndex()) {
val libPythonDir = file("$libDir/python$pythonVersion")
val triplet = run {
for (filename in libPythonDir.list()!!) {
"""_sysconfigdata__android_(.+).py""".toRegex().matchEntire(filename)?.let {
return@run it.groupValues[1]
}
"""_sysconfigdata_[a-z]*_android_(.+).py""".toRegex()
.matchEntire(filename)?.let {
return@run it.groupValues[1]
}
}
throw GradleException("Failed to find Python triplet in $libPythonDir")
}
Expand Down
16 changes: 15 additions & 1 deletion Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2243,7 +2243,7 @@ without the dedicated syntax, as documented below.
.. versionadded:: 3.10


.. class:: TypeAliasType(name, value, *, type_params=())
.. class:: TypeAliasType(name, value, *, type_params=(), qualname=None)

The type of type aliases created through the :keyword:`type` statement.

Expand All @@ -2267,6 +2267,20 @@ without the dedicated syntax, as documented below.
>>> Alias.__name__
'Alias'

.. attribute:: __qualname__

The :term:`qualified name` of the type alias:

.. doctest::

>>> class Class:
... type Alias = int
...
>>> Class.Alias.__qualname__
'Class.Alias'

.. versionadded:: 3.15

.. attribute:: __module__

The name of the module in which the type alias was defined::
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(ps1)
STRUCT_FOR_ID(ps2)
STRUCT_FOR_ID(qid)
STRUCT_FOR_ID(qualname)
STRUCT_FOR_ID(query)
STRUCT_FOR_ID(queuetype)
STRUCT_FOR_ID(quotetabs)
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""create and manipulate C data types in Python"""

import os as _os, sys as _sys
import os as _os
import sys as _sys
import sysconfig as _sysconfig
import types as _types

__version__ = "1.1.0"
Expand Down Expand Up @@ -550,10 +552,9 @@ def LoadLibrary(self, name):

if _os.name == "nt":
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
elif _sys.platform == "android":
pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2])
elif _sys.platform == "cygwin":
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
elif _sys.platform in ["android", "cygwin"]:
# These are Unix-like platforms which use a dynamically-linked libpython.
pythonapi = PyDLL(_sysconfig.get_config_var("LDLIBRARY"))
else:
pythonapi = PyDLL(None)

Expand Down
2 changes: 1 addition & 1 deletion Lib/importlib/metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def from_name(cls, name: str) -> Distribution:
try:
return next(iter(cls._prefer_valid(cls.discover(name=name))))
except StopIteration:
raise PackageNotFoundError(name)
raise PackageNotFoundError(name) from None

@classmethod
def discover(
Expand Down
82 changes: 69 additions & 13 deletions Lib/test/test_type_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args,
)

type GlobalTypeAlias = int

def get_type_alias():
type TypeAliasInFunc = str
return TypeAliasInFunc

class TypeParamsInvalidTest(unittest.TestCase):
def test_name_collisions(self):
Expand Down Expand Up @@ -70,6 +75,8 @@ def inner[B](self):


class TypeParamsAliasValueTest(unittest.TestCase):
type TypeAliasInClass = dict

def test_alias_value_01(self):
type TA1 = int

Expand Down Expand Up @@ -142,33 +149,67 @@ def test_subscripting(self):
self.assertIs(specialized2.__origin__, VeryGeneric)
self.assertEqual(specialized2.__args__, (int, str, float, [bool, range]))

def test___name__(self):
type TypeAliasLocal = GlobalTypeAlias

self.assertEqual(GlobalTypeAlias.__name__, 'GlobalTypeAlias')
self.assertEqual(get_type_alias().__name__, 'TypeAliasInFunc')
self.assertEqual(self.TypeAliasInClass.__name__, 'TypeAliasInClass')
self.assertEqual(TypeAliasLocal.__name__, 'TypeAliasLocal')

with self.assertRaisesRegex(
AttributeError,
"readonly attribute",
):
setattr(TypeAliasLocal, '__name__', 'TA')

def test___qualname__(self):
type TypeAliasLocal = GlobalTypeAlias

self.assertEqual(GlobalTypeAlias.__qualname__,
'GlobalTypeAlias')
self.assertEqual(get_type_alias().__qualname__,
'get_type_alias.<locals>.TypeAliasInFunc')
self.assertEqual(self.TypeAliasInClass.__qualname__,
'TypeParamsAliasValueTest.TypeAliasInClass')
self.assertEqual(TypeAliasLocal.__qualname__,
'TypeParamsAliasValueTest.test___qualname__.<locals>.TypeAliasLocal')

with self.assertRaisesRegex(
AttributeError,
"readonly attribute",
):
setattr(TypeAliasLocal, '__qualname__', 'TA')

def test_repr(self):
type Simple = int
type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
self.assertEqual(repr(Simple), Simple.__qualname__)

self.assertEqual(repr(Simple), "Simple")
self.assertEqual(repr(VeryGeneric), "VeryGeneric")
type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
self.assertEqual(repr(VeryGeneric), VeryGeneric.__qualname__)
fullname = f"{VeryGeneric.__module__}.{VeryGeneric.__qualname__}"
self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]),
"VeryGeneric[int, bytes, str, [float, object]]")
f"{fullname}[int, bytes, str, [float, object]]")
self.assertEqual(repr(VeryGeneric[int, []]),
"VeryGeneric[int, []]")
f"{fullname}[int, []]")
self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]),
"VeryGeneric[int, [VeryGeneric[int], list[str]]]")
f"{fullname}[int, [{fullname}[int], list[str]]]")

def test_recursive_repr(self):
type Recursive = Recursive
self.assertEqual(repr(Recursive), "Recursive")
self.assertEqual(repr(Recursive), Recursive.__qualname__)

type X = list[Y]
type Y = list[X]
self.assertEqual(repr(X), "X")
self.assertEqual(repr(Y), "Y")
self.assertEqual(repr(X), X.__qualname__)
self.assertEqual(repr(Y), Y.__qualname__)

type GenericRecursive[X] = list[X | GenericRecursive[X]]
self.assertEqual(repr(GenericRecursive), "GenericRecursive")
self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]")
self.assertEqual(repr(GenericRecursive), GenericRecursive.__qualname__)
fullname = f"{GenericRecursive.__module__}.{GenericRecursive.__qualname__}"
self.assertEqual(repr(GenericRecursive[int]), f"{fullname}[int]")
self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]),
"GenericRecursive[GenericRecursive[int]]")
f"{fullname}[{fullname}[int]]")

def test_raising(self):
type MissingName = list[_My_X]
Expand All @@ -193,15 +234,25 @@ class TypeAliasConstructorTest(unittest.TestCase):
def test_basic(self):
TA = TypeAliasType("TA", int)
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)

def test_with_qualname(self):
TA = TypeAliasType("TA", str, qualname="Class.TA")
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "Class.TA")
self.assertIs(TA.__value__, str)
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)

def test_attributes_with_exec(self):
ns = {}
exec("type TA = int", ns, ns)
TA = ns["TA"]
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
self.assertIs(TA.__module__, None)
Expand All @@ -210,6 +261,7 @@ def test_generic(self):
T = TypeVar("T")
TA = TypeAliasType("TA", list[T], type_params=(T,))
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[T])
self.assertEqual(TA.__type_params__, (T,))
self.assertEqual(TA.__module__, __name__)
Expand All @@ -218,6 +270,7 @@ def test_generic(self):
def test_not_generic(self):
TA = TypeAliasType("TA", list[int], type_params=())
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[int])
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)
Expand Down Expand Up @@ -268,8 +321,9 @@ def test_expects_type_like(self):
TypeAliasType("A", int, type_params=(T, 2))

def test_keywords(self):
TA = TypeAliasType(name="TA", value=int)
TA = TypeAliasType(name="TA", value=int, type_params=(), qualname=None)
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)
Expand All @@ -283,6 +337,8 @@ def test_errors(self):
TypeAliasType("TA", list, ())
with self.assertRaises(TypeError):
TypeAliasType("TA", list, type_params=42)
with self.assertRaises(TypeError):
TypeAliasType("TA", list, qualname=range(5))


class TypeAliasTypeTest(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Attribute ``__qualname__`` is added to :class:`typing.TypeAliasType`.
Patch by Mikhail Efimov.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The :py:class:`importlib.metadata.PackageNotFoundError` traceback raised when
``importlib.metadata.Distribution.from_name`` cannot discover a
distribution no longer includes a transient :exc:`StopIteration` exception trace.

Contributed by Bartosz Sławecki in :gh:`140142`.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix import of :mod:`ctypes` on Android and Cygwin when ABI flags are present.
25 changes: 16 additions & 9 deletions Objects/clinic/typevarobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading