Skip to content

Commit e78d425

Browse files
committed
Merge branch 'main' into pep750-october-updates
2 parents 2611119 + 85f165e commit e78d425

File tree

14 files changed

+1680
-512
lines changed

14 files changed

+1680
-512
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ peps/pep-0690.rst @warsaw
574574
peps/pep-0691.rst @dstufft
575575
peps/pep-0692.rst @jellezijlstra
576576
peps/pep-0693.rst @Yhg1s
577-
peps/pep-0694.rst @dstufft
577+
peps/pep-0694.rst @dstufft @warsaw
578578
peps/pep-0695.rst @gvanrossum
579579
peps/pep-0696.rst @jellezijlstra
580580
peps/pep-0697.rst @encukou
@@ -646,6 +646,8 @@ peps/pep-0765.rst @iritkatriel @ncoghlan
646646
peps/pep-0766.rst @warsaw
647647
peps/pep-0767.rst @carljm
648648
peps/pep-0768.rst @pablogsal
649+
peps/pep-0769.rst @facundobatista
650+
peps/pep-0770.rst @sethmlarson @brettcannon
649651
# ...
650652
peps/pep-0777.rst @warsaw
651653
# ...

.github/workflows/render.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
matrix:
2424
python-version:
2525
- "3.x"
26-
- "3.13-dev"
26+
- "3.14-dev"
2727

2828
steps:
2929
- name: Checkout

.github/workflows/test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ jobs:
6262
uvx --with tox-uv tox -e py -- -v --cov-report term
6363
6464
- name: Upload coverage
65-
uses: codecov/codecov-action@v4
65+
uses: codecov/codecov-action@v5
6666
with:
6767
flags: ${{ matrix.os }}
6868
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
69+
token: ${{ secrets.CODECOV_ORG_TOKEN }}

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ htmllive: _ensure-sphinx-autobuild html
4040
.PHONY: dirhtml
4141
dirhtml: BUILDER = dirhtml
4242
dirhtml: html
43+
mv $(BUILDDIR)/404/index.html $(BUILDDIR)/404.html
4344

4445
## linkcheck to check validity of links within PEP sources
4546
.PHONY: linkcheck

pep_sphinx_extensions/pep_theme/templates/page.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ <h1>Python Enhancement Proposals</h1>
4949
<article>
5050
{{ body }}
5151
</article>
52-
{%- if not pagename == "numerical" %}
52+
{%- if not pagename.startswith(("404", "numerical")) %}
5353
<nav id="pep-sidebar">
5454
<h2>Contents</h2>
5555
{{ toc }}
5656
<br>
57-
{%- if not pagename.startswith(("numerical", "pep-0000", "topic")) %}
57+
{%- if not pagename.startswith(("pep-0000", "topic")) %}
5858
<a id="source" href="https://github.com/python/peps/blob/main/peps/{{pagename}}.rst">Page Source (GitHub)</a>
5959
{%- endif %}
6060
</nav>

peps/conf.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
# Add any Sphinx extension module names here, as strings.
2121
extensions = [
22+
"notfound.extension",
2223
"pep_sphinx_extensions",
2324
"sphinx.ext.extlinks",
2425
"sphinx.ext.intersphinx",
@@ -85,6 +86,10 @@
8586
"pypi": ("https://pypi.org/project/%s/", "%s"),
8687
}
8788

89+
# sphinx-notfound-page
90+
# https://sphinx-notfound-page.readthedocs.io/en/latest/faq.html#does-this-extension-work-with-github-pages
91+
notfound_urls_prefix = None
92+
8893
# -- Options for HTML output -------------------------------------------------
8994

9095
_PSE_PATH = _ROOT / "pep_sphinx_extensions"

peps/pep-0694.rst

Lines changed: 769 additions & 456 deletions
Large diffs are not rendered by default.

peps/pep-0728.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ If ``closed`` is not provided, the behavior is inherited from the superclass.
258258
If the superclass is TypedDict itself or the superclass does not have ``closed=True``
259259
or the ``extra_items`` parameter, the previous TypedDict behavior is preserved:
260260
arbitrary extra items are allowed. If the superclass has ``closed=True``, the
261-
child class is also closed.
261+
child class is also closed::
262262

263263
class BaseMovie(TypedDict, closed=True):
264264
name: str

peps/pep-0747.rst

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,9 @@ extract components of some type form objects.
410410
::
411411

412412
import typing
413+
from typing import TypeForm, cast
413414

414-
def strip_annotated_metadata(typx: TypeForm[T]) -> TypeForm[T]:
415+
def strip_annotated_metadata[T](typx: TypeForm[T]) -> TypeForm[T]:
415416
if typing.get_origin(typx) is typing.Annotated:
416417
typx = cast(TypeForm[T], typing.get_args(typx)[0])
417418
return typx
@@ -423,15 +424,16 @@ kinds of type form objects:
423424

424425
import types
425426
import typing
427+
from typing import TypeForm, cast
426428

427429
def split_union(typx: TypeForm) -> tuple[TypeForm, ...]:
428-
if isinstance(typ, types.UnionType): # X | Y
429-
return cast(tuple[TypeForm, ...], typing.get_args(typ))
430-
if typing.get_origin(typ) is typing.Union: # Union[X, Y]
431-
return cast(tuple[TypeForm, ...], typing.get_args(typ))
432-
if typ in (typing.Never, typing.NoReturn,):
430+
if isinstance(typx, types.UnionType): # X | Y
431+
return cast(tuple[TypeForm, ...], typing.get_args(typx))
432+
if typing.get_origin(typx) is typing.Union: # Union[X, Y]
433+
return cast(tuple[TypeForm, ...], typing.get_args(typx))
434+
if typx in (typing.Never, typing.NoReturn,):
433435
return ()
434-
return (typ,)
436+
return (typx,)
435437

436438

437439
Combining with a type variable
@@ -443,7 +445,7 @@ within the same function definition:
443445
::
444446

445447
def as_instance[T](typx: TypeForm[T]) -> T | None:
446-
return typ() if isinstance(typ, type) else None
448+
return typx() if isinstance(typx, type) else None
447449

448450

449451
Combining with ``type``
@@ -455,7 +457,7 @@ variable within the same function definition:
455457
::
456458

457459
def as_type[T](typx: TypeForm[T]) -> type[T] | None:
458-
return typ if isinstance(typ, type) else None
460+
return typx if isinstance(typx, type) else None
459461

460462

461463
Combining with ``TypeIs`` and ``TypeGuard``

peps/pep-0767.rst

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ Today, there are three major ways of achieving read-only attributes, honored by
9898
Protocols
9999
---------
100100

101-
A read-only attribute ``name: T`` on a :class:`~typing.Protocol` in principle
102-
defines two requirements:
101+
Suppose a :class:`~typing.Protocol` member ``name: T`` defining two requirements:
103102

104103
1. ``hasattr(obj, "name")``
105104
2. ``isinstance(obj.name, T)``
@@ -251,7 +250,12 @@ Initialization
251250

252251
Assignment to a read-only attribute can only occur in the class declaring the attribute.
253252
There is no restriction to how many times the attribute can be assigned to.
254-
The assignment must be allowed in the following contexts:
253+
Depending on the kind of the attribute, they can be assigned to at different sites:
254+
255+
Instance Attributes
256+
'''''''''''''''''''
257+
258+
Assignment to an instance attribute must be allowed in the following contexts:
255259

256260
* In ``__init__``, on the instance received as the first parameter (likely, ``self``).
257261
* In ``__new__``, on instances of the declaring class created via a call
@@ -267,9 +271,6 @@ Additionally, a type checker may choose to allow the assignment:
267271
* In ``@classmethod``\ s, on instances of the declaring class created via
268272
a call to the class' or super-class' ``__new__`` method.
269273

270-
Note that a child class cannot assign to any read-only attributes of a parent class
271-
in any of the aforementioned contexts, unless the attribute is redeclared.
272-
273274
.. code-block:: python
274275
275276
from collections import abc
@@ -332,6 +333,25 @@ in any of the aforementioned contexts, unless the attribute is redeclared.
332333
self.numerator, self.denominator = f.as_integer_ratio()
333334
return self
334335
336+
Class Attributes
337+
''''''''''''''''
338+
339+
Read-only class attributes are attributes annotated as both ``ReadOnly`` and ``ClassVar``.
340+
Assignment to such attributes must be allowed in the following contexts:
341+
342+
* At declaration in the body of the class.
343+
* In ``__init_subclass__``, on the class object received as the first parameter (likely, ``cls``).
344+
345+
.. code-block:: python
346+
347+
class URI:
348+
protocol: ReadOnly[ClassVar[str]] = ""
349+
350+
def __init_subclass__(cls, protocol: str = "") -> None:
351+
cls.protocol = protocol
352+
353+
class File(URI, protocol="file"): ...
354+
335355
When a class-level declaration has an initializing value, it can serve as a `flyweight <https://en.wikipedia.org/wiki/Flyweight_pattern>`_
336356
default for instances:
337357

@@ -367,8 +387,8 @@ protocols or ABCs)::
367387
Subtyping
368388
---------
369389

370-
Read-only attributes are covariant. This has a few subtyping implications.
371-
Borrowing from :pep:`705#inheritance`:
390+
The inability to reassign read-only attributes makes them covariant.
391+
This has a few subtyping implications. Borrowing from :pep:`705#inheritance`:
372392

373393
* Read-only attributes can be redeclared as writable attributes, descriptors
374394
or class variables::
@@ -493,9 +513,6 @@ Interaction with Other Type Qualifiers
493513
This is consistent with the interaction of ``ReadOnly`` and :class:`typing.TypedDict`
494514
defined in :pep:`705`.
495515

496-
An attribute annotated as both ``ReadOnly`` and ``ClassVar`` can only be assigned to
497-
at declaration in the class body.
498-
499516
An attribute cannot be annotated as both ``ReadOnly`` and ``Final``, as the two
500517
qualifiers differ in semantics, and ``Final`` is generally more restrictive.
501518
``Final`` remains allowed as an annotation of attributes that are only implied
@@ -604,23 +621,6 @@ to allow initialization in. This however could easily result in users mistakenly
604621
or purposefully breaking the aforementioned invariants. It is also a fairly
605622
big ask for a relatively niche feature.
606623

607-
``ReadOnly[ClassVar[...]]`` and ``__init_subclass__``
608-
-----------------------------------------------------
609-
610-
Should read-only class variables be assignable to within the declaring class'
611-
``__init_subclass__``?
612-
613-
.. code-block:: python
614-
615-
class URI:
616-
protocol: ReadOnly[ClassVar[str]] = ""
617-
618-
def __init_subclass__(cls, protocol: str = "") -> None:
619-
cls.foo = protocol
620-
621-
class File(URI, protocol="file"): ...
622-
623-
624624
Footnotes
625625
=========
626626

0 commit comments

Comments
 (0)