From c4be7f4b389ac5317446d55760f4801e901c7032 Mon Sep 17 00:00:00 2001 From: Ofek Lev Date: Fri, 25 Aug 2023 00:06:43 -0400 Subject: [PATCH 001/173] PEP 723: Remove ``run.version`` (#3307) --- pep-0723.rst | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/pep-0723.rst b/pep-0723.rst index fa77dd595..90170af41 100644 --- a/pep-0723.rst +++ b/pep-0723.rst @@ -147,8 +147,6 @@ The ``[run]`` table MAY include the following optional fields: * ``requires-python``: A string that specifies the Python version(s) with which the script is compatible. The value of this field MUST be a valid :pep:`version specifier <440#version-specifiers>`. -* ``version``: A string that specifies the version of the script. The value of - this field MUST be a valid :pep:`440` version. Any future PEPs that define additional fields for the ``[run]`` table when used in a ``pyproject.toml`` file MUST include the aforementioned fields exactly as @@ -307,7 +305,6 @@ is TOML and resembles a ``pyproject.toml`` file. # "rich", # ] # requires-python = ">=3.11" - # version = "0.1.0" # /// The two allowed tables are ``[run]`` and ``[tool]``. The ``[run]`` table may @@ -332,11 +329,6 @@ contain the following fields: - Tools might error if no version of Python that satisfies the constraint can be executed. - * - ``version`` - - A string that specifies the version of the script. - The value of this field must be a valid :pep:`440` version. - - Tools may use this however they wish, if defined. - It is up to individual tools whether or not their behavior is altered based on the embedded metadata. For example, every script runner may not be able to provide an environment for specific Python versions as defined by the @@ -539,19 +531,10 @@ There are two significant problems with this proposal: Why not limit to specific metadata fields? ------------------------------------------ -By limiting the metadata to a specific set of fields, for example just -``dependencies``, we would prevent legitimate known use cases: - -* ``requires-python``: For tools that support managing Python installations, - this allows users to target specific versions of Python for new syntax - or standard library functionality. -* ``version``: It is quite common to version scripts for persistence even when - using a VCS like Git. When not using a VCS it is even more common to version, - for example the author has been in multiple time sensitive debugging sessions - with customers where due to the airgapped nature of the environment, the only - way to transfer the script was via email or copying and pasting it into a - chat window. In these cases, versioning is invaluable to ensure that the - customer is using the latest (or a specific) version of the script. +By limiting the metadata to just ``dependencies``, we would prevent the known +use case of tools that support managing Python installations, which would +allows users to target specific versions of Python for new syntax or standard +library functionality. .. _723-tool-configuration: From bd6016df127a81ff082f329f441aec57af6ef72b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 25 Aug 2023 04:16:01 -0600 Subject: [PATCH 002/173] PEP 569, 596, 619, 664: Add 2023-08-24 releases (#3306) --- pep-0569.rst | 1 + pep-0596.rst | 1 + pep-0619.rst | 8 +++++++- pep-0664.rst | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pep-0569.rst b/pep-0569.rst index c4cfc6247..caa9593e2 100644 --- a/pep-0569.rst +++ b/pep-0569.rst @@ -96,6 +96,7 @@ Provided irregularly on an "as-needed" basis until October 2024. - 3.8.15: Tuesday, 2022-10-11 - 3.8.16: Tuesday, 2022-12-06 - 3.8.17: Tuesday, 2023-06-06 +- 3.8.18: Thursday, 2023-08-24 Features for 3.8 diff --git a/pep-0596.rst b/pep-0596.rst index 1196233e0..62b4d10d1 100644 --- a/pep-0596.rst +++ b/pep-0596.rst @@ -93,6 +93,7 @@ Provided irregularly on an "as-needed" basis until October 2025. - 3.9.15: Tuesday, 2022-10-11 - 3.9.16: Tuesday, 2022-12-06 - 3.9.17: Tuesday, 2023-06-06 +- 3.9.18: Thursday, 2023-08-24 3.9 Lifespan diff --git a/pep-0619.rst b/pep-0619.rst index 71b70ae0b..e60052486 100644 --- a/pep-0619.rst +++ b/pep-0619.rst @@ -74,8 +74,14 @@ Actual: - 3.10.10: Wednesday, 2023-02-08 - 3.10.11: Wednesday, 2023-04-05 (final regular bugfix release with binary installers) -- 3.10.12: Tuesday, 2023-06-06 +Source-only security fix releases +--------------------------------- + +Provided irregularly on an "as-needed" basis until October 2026. + +- 3.10.12: Tuesday, 2023-06-06 +- 3.10.13: Thursday, 2023-08-24 3.10 Lifespan ------------- diff --git a/pep-0664.rst b/pep-0664.rst index 27ab755b8..6530677bc 100644 --- a/pep-0664.rst +++ b/pep-0664.rst @@ -70,10 +70,10 @@ Actual: - 3.11.2: Wednesday, 2023-02-08 - 3.11.3: Wednesday, 2023-04-05 - 3.11.4: Tuesday, 2023-06-06 +- 3.11.5: Thursday, 2023-08-24 Expected: -- 3.11.5: Monday, 2023-08-07 - 3.11.6: Monday, 2023-10-02 - 3.11.7: Monday, 2023-12-04 - 3.11.8: Monday, 2024-02-05 From e41aba6009d975da3572a08a5840a26f5f6acf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 28 Aug 2023 21:39:50 +0200 Subject: [PATCH 003/173] PEP 1: Add a missing word in "Submitting a PEP" (#3311) --- pep-0001.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0001.txt b/pep-0001.txt index 82ff18ea0..5aa9b5394 100644 --- a/pep-0001.txt +++ b/pep-0001.txt @@ -207,7 +207,7 @@ The standard PEP workflow is: It also provides a complete introduction to reST markup that is used in PEPs. Approval criteria are: - * It sound and complete. The ideas must make technical sense. The + * It is sound and complete. The ideas must make technical sense. The editors do not consider whether they seem likely to be accepted. * The title accurately describes the content. * The PEP's language (spelling, grammar, sentence structure, etc.) From c8e245dedc0275dd2d58a34b837d346f24ecffa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 28 Aug 2023 21:58:03 +0200 Subject: [PATCH 004/173] PEP 727: Documentation Metadata in Typing (#3310) --- .github/CODEOWNERS | 1 + pep-0727.rst | 516 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 517 insertions(+) create mode 100644 pep-0727.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 53755f393..72f2bcd2c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -602,6 +602,7 @@ pep-0721.rst @encukou pep-0722.rst @pfmoore pep-0723.rst @AA-Turner pep-0725.rst @pradyunsg +pep-0727.rst @JelleZijlstra # ... # pep-0754.txt # ... diff --git a/pep-0727.rst b/pep-0727.rst new file mode 100644 index 000000000..494f31082 --- /dev/null +++ b/pep-0727.rst @@ -0,0 +1,516 @@ +PEP: 727 +Title: Documentation Metadata in Typing +Author: Sebastián Ramírez +Sponsor: Jelle Zijlstra +Discussions-To: +Status: Draft +Type: Standards Track +Topic: Typing +Content-Type: text/x-rst +Created: 28-Aug-2023 +Python-Version: 3.13 +Post-History: + + +Abstract +======== + +This document proposes a way to complement docstrings to add additional documentation +to Python symbols using type annotations with ``Annotated`` (in class attributes, +function and method parameters, return values, and variables). + + +Motivation +========== + +The current standard method of documenting code APIs in Python is using docstrings. +But there's no standard way to document parameters in docstrings. + +There are several pseudo-standards for the format in these docstrings, and new +pseudo-standards can appear easily: numpy, Google, Keras, reST, etc. + +All these formats are some specific syntax inside a string. Because of this, when +editing those docstrings, editors can't easily provide support for autocompletion, +inline errors for broken syntax, etc. + +Editors don't have a way to support all the possible micro languages in the docstrings +and show nice user interfaces when developers use libraries with those different +formats. They could even add support for some of the syntaxes, but probably not all, +or not completely. + +Because the docstring is in a different place in the code than the actual parameters +and it requires duplication of information (the parameter name) the information about +a parameter is easily in a place in the code quite far away from the declaration of +the actual parameter. This means it's easy to refactor a function, remove a parameter, +and forget to remove its docs. The same happens when adding a new parameter: it's easy +to forget to add the docstring for it. + +Editors can't check or ensure the consistency of the parameters and their docs. + +It's not possible to programatically test these docstrings, for example to ensure +documentation consistency for the parameters across several similar functions, at +least not without implementing a custom syntax parser. + +Some of these previous formats tried to account for the lack of type annotations +in older Python versions by including typing information in the docstrings, +but now that information doesn't need to be in docstrings as there is now an official +syntax for type annotations. + + +Rationale +========= + +This proposal intends to address these shortcomings by extending and complementing the +information in docstrings, keeping backwards compatibility with existing docstrings, +and doing it in a way that leverages the Python language and structure, via type +annotations with ``Annotated``, and a new function in ``typing``. + +The reason why this would belong in the standard Python library instead of an +external package is because although the implementation would be quite trivial, +the actual power and benefit from it would come from being a standard, so that +editors and other tools could implement support for it. + +This doesn't deprecate current usage of docstrings, it's transparent to common +developers (library users), and it's only opt-in for library authors that would +like to adopt it. + + +Specification +============= + + +``typing.doc`` +-------------- + +The main proposal is to have a new function ``doc()`` in the ``typing`` module. +Even though this is not strictly related to the type annotations, it's expected +to go in ``Annotated`` type annotations, and to interact with type annotations. + +There's also the particular benefit that it could be implemented in the +``typing_extensions`` package to have support for older versions of Python and +early adopters of this proposal. + +This ``doc()`` function would receive one single parameter ``documentation`` with +a documentation string. + +This string could be a multi-line string, in which case, when extracted by tools, +should be interpreted cleaning up indentation as if using ``inspect.cleandoc()``, +the same procedure used for docstrings. + +This string could probably contain markup, like Markdown or reST. As that could +be highly debated, that decision is left for a future proposal, to focus here +on the main functionality. + +This specification targets static analysis tools and editors, and as such, the +value passed to ``doc()`` should allow static evaluation and analysis. If a +developer passes as the value something that requires runtime execution +(e.g. a function call) the behavior of static analysis tools is unspecified +and they could omit it from their process and results. For static analysis +tools to be conformant with this specification they need only to support +statically accessible values. + +An example documenting the attributes of a class, or in this case, the keys +of a ``TypedDict``, could look like this: + +.. code-block:: + + from typing import Annotated, TypedDict, NotRequired, doc + + + class User(TypedDict): + firstname: Annotated[str, doc("The user's first name")] + lastname: Annotated[str, doc("The user's last name")] + + +An example documenting the parameters of a function could look like this: + +.. code-block:: + + from typing import Annotated, doc + + + def create_user( + lastname: Annotated[str, doc("The **last name** of the newly created user")], + firstname: Annotated[str | None, doc("The user's **first name**")] = None, + ) -> Annotated[User, doc("The created user after saving in the database")]: + """ + Create a new user in the system, it needs the database connection to be already + initialized. + """ + pass + + +The return of the ``doc()`` function is an instance of a class that can be checked +and used at runtime, defined similar to: + +.. code-block:: + + class DocInfo: + def __init__(self, documentation: str): + self.documentation = documentation + +...where the attribute ``documentation`` contains the same value string passed to +the function ``doc()``. + + +Additional Scenarios +-------------------- + +The main scenarios that this proposal intends to cover are described above, and +for implementers to be conformant to this specification, they only need to support +those scenarios described above. + +Here are some additional edge case scenarios with their respective considerations, +but implementers are not required to support them. + + +Type Alias +---------- + +When creating a type alias, like: + +.. code-block:: + + Username = Annotated[str, doc("The name of a user in the system")] + + +...the documentation would be considered to be carried by the parameter annotated +with ``Username``. + +So, in a function like: + +.. code-block:: + + def hi( + to: Username, + ) -> None: ... + + +...it would be equivalent to: + +.. code-block:: + + def hi( + to: Annotated[str, doc("The name of a user in the system")], + ) -> None: ... + +Nevertheless, implementers would not be required to support type aliases outside +of the final type annotation to be conformant with this specification, as it +could require more complex dereferencing logic. + + +Annotating Type Parameters +-------------------------- + +When annotating type parameters, as in: + +.. code-block:: + + def hi( + to: list[Annotated[str, doc("The name of a user in a list")]], + ) -> None: ... + +...the documentation in ``doc()`` would refer to what it is annotating, in this +case, each item in the list, not the list itself. + +There are currently no practical use cases for documenting type parameters, +so implementers are not required to support this scenario to be considered +conformant, but it's included for completeness. + + +Annotating Unions +----------------- + +If used in one of the parameters of a union, as in: + +.. code-block:: + + def hi( + to: str | Annotated[list[str], doc("List of user names")], + ) -> None: ... + +...again, the documentation in ``doc()`` would refer to what it is annotating, +in this case, this documents the list itself, not its items. + +In particular, the documentation would not refer to a single string passed as a +parameter, only to a list. + +There are currently no practical use cases for documenting unions, so implementers +are not required to support this scenario to be considered conformant, but it's +included for completeness. + + +Nested ``Annotated`` +-------------------- + +Continuing with the same idea above, if ``Annotated`` was used nested and used +multiple times in the same parameter, ``doc()`` would refer to the type it +is annotating. + +So, in an example like: + +.. code-block:: + + def hi( + to: Annotated[ + Annotated[str, doc("A user name")] | Annotated[list, doc("A list of user names")], + doc("Who to say hi to"), + ], + ) -> None: ... + + +The documentation for the whole parameter ``to`` would be considered to be +"``Who to say hi to``". + +The documentation for the case where that parameter ``to`` is specifically a ``str`` +would be considered to be "``A user name``". + +The documentation for the case where that parameter ``to`` is specifically a +``list`` would be considered to be "``A list of user names``". + +Implementers would only be required to support the top level use case, where the +documentation for ``to`` is considered to be "``Who to say hi to``". +They could optionally support having conditional documentation for when the type +of the parameter passed is of one type or another, but they are not required to do so. + + +Duplication +----------- + +If ``doc()`` is used multiple times in a single ``Annotated``, it would be +considered invalid usage from the developer, for example: + +.. code-block:: + + def hi( + to: Annotated[str, doc("A user name"), doc("The current user name")], + ) -> None: ... + + +Implementers can consider this invalid and are not required to support this to be +considered conformant. + +Nevertheless, as it might be difficult to enforce it on developers, implementers +can opt to support one of the ``doc()`` declarations. + +In that case, the suggestion would be to support the last one, just because +this would support overriding, for example, in: + +.. code-block:: + + User = Annotated[str, doc("A user name")] + + CurrentUser = Annotated[User, doc("The current user name")] + + +Internally, in Python, ``CurrentUser`` here is equivalent to: + +.. code-block:: + + CurrentUser = Annotated[str, doc("A user name"), doc("The current user name")] + + +For an implementation that supports the last ``doc()`` appearance, the above +example would be equivalent to: + +.. code-block:: + + def hi( + to: Annotated[str, doc("The current user name")], + ) -> None: ... + + +Early Adopters and Older Python Versions +======================================== + +For older versions of Python and early adopters of this proposal, ``doc()`` and +``DocInfo`` can be imported from the ``typing_extensions`` package. + +.. code-block:: + + from typing import Annotated + + from typing_extensions import doc + + + def hi( + to: Annotated[str, doc("The current user name")], + ) -> None: ... + + +Rejected Ideas +============== + + +Standardize Current Docstrings +------------------------------ + +A possible alternative would be to support and try to push as a standard one of the +existing docstring formats. But that would only solve the standardization. + +It wouldn't solve any of the other problems, like getting editor support +(syntax checks) for library authors, the distance and duplication of information +between a parameter definition and its documentation in the docstring, etc. + + +Extra Metadata and Decorator +---------------------------- + +An earlier version of this proposal included several parameters to indicate whether +an object is discouraged from use, what exceptions it may raise, etc. +To allow also deprecating functions and classes, it was also expected +that ``doc()`` could be used as a decorator. But this functionality is covered +by ``typing.deprecated()`` in :pep:`702`, so it was dropped from this proposal. + +A way to declare additional information could still be useful in the future, +but taking early feedback on this document, all that was postponed to future +proposals. + +This also shifts the focus from an all-encompasing function ``doc()`` +with multiple parameters to multiple composable functions, having ``doc()`` +handle one single use case: additional documentation in ``Annotated``. + +This design change also allows better interoperability with other proposals +like ``typing.deprecated()``, as in the future it could be considered to +allow having ``typing.deprecated()`` also in ``Annotated`` to deprecate +individual parameters, coexisting with ``doc()``. + + +Open Issues +=========== + + +Verbosity +--------- + +The main argument against this would be the increased verbosity. + +Nevertheless, this verbosity would not affect end users as they would not see the +internal code using ``typing.doc()``. + +And the cost of dealing with the additional verbosity would only be carried +by those library maintainers that decide to opt-in into this feature. + +Any authors that decide not to adopt it, are free to continue using docstrings +with any particular format they decide, no docstrings at all, etc. + +This argument could be analogous to the argument against type annotations +in general, as they do indeed increase verbosity, in exchange for their +features. But again, as with type annotations, this would be optional and only +to be used by those that are willing to take the extra verbosity in exchange +for the benefits. + + +Doc is not Typing +----------------- + +It could also be argued that documentation is not really part of typing, or that +it should live in a different module. Or that this information should not be part +of the signature but live in another place (like the docstring). + +Nevertheless, type annotations in Python could already be considered, by default, +mainly documentation: they carry additional information about variables, +parameters, return types, and by default they don't have any runtime behavior. + +It could be argued that this proposal extends the type of information that +type annotations carry, the same way as :pep:`702` extends them to include +deprecation information. + +And as described above, including this in ``typing_extensions`` to support older +versions of Python would have a very simple and practical benefit. + + +Multiple Standards +------------------ + +Another argument against this would be that it would create another standard, +and that there are already several pseudo-standards for docstrings. It could +seem better to formalize one of the currently existing standards. + +Nevertheless, as stated above, none of those standards cover the general +drawbacks of a doctsring-based approach that this proposal solves naturally. + +None of the editors have full docstring editing support (even when they have +rendering support). Again, this is solved by this proposal just by using +standard Python syntax and structures instead of a docstring microsyntax. + +The effort required to implement support for this proposal by tools would +be minimal compared to that required for alternative docstring-based +pseudo-standards, as for this proposal, editors would only need to +access an already existing value in their ASTs, instead of writing a parser +for a new string microsyntax. + +In the same way, it can be seen that, in many cases, a new standard that +takes advantage of new features and solves several problems from previous +methods can be worth having. As is the case with the new ``pyproject.toml``, +``dataclass_transform``, the new typing pipe/union (``|``) operator, and other cases. + + +Adoption +-------- + +As this is a new standard proposal, it would only make sense if it had +interest from the community. + +Fortunately there's already interest from several mainstream libraries +from several developers and teams, including FastAPI, Typer, SQLModel, +Asyncer (from the author of this proposal), Pydantic, Strawberry, and others, +from other teams. + +There's also interest and support from documentation tools, like +`mkdocstrings `__, which added +support even for an earlier version of this proposal. + +All the CPython core developers contacted for early feedback (at least 4) have +shown interest and support for this proposal. + +Editor developers (VS Code and PyCharm) have shown some interest, while showing +concerns about the verbosity of the proposal, although not about the +implementation (which is what would affect them the most). And they have shown +they would consider adding support for this if it were to become an +official standard. In that case, they would only need to add support for +rendering, as support for editing, which is normally non-existing for +other standards, is already there, as they already support editing standard +Python syntax. + + +Bike Shedding +------------- + +I think ``doc()`` is a good name for the main function. But it might make sense +to consider changing the names for the other parts. + +The returned class containing info currently named ``DocInfo`` could instead +be named just ``Doc``. Although it could make verbal conversations more +confusing as it's the same word as the name of the function. + +The parameter received by ``doc()`` currently named ``documentation`` could +instead be named also ``doc``, but it would make it more ambiguous in +discussions to distinguish when talking about the function and the parameter, +although it would simplify the amount of terms, but as these terms refer to +different things closely related, it could make sense to have different names. + +The parameter received by ``doc()`` currently named ``documentation`` could +instead be named ``value``, but the word "documentation" might convey +the meaning better. + +The parameter received by ``doc()`` currently named ``documentation`` could be a +position-only parameter, in which case the name wouldn't matter much. But then +there wouldn't be a way to make it match with the ``DocInfo`` attribute. + +The ``DocInfo`` class has a single attribute ``documentation``, this name matches +the parameter passed to ``doc()``. It could be named something different, +like ``doc``, but this would mean a mismatch between the ``doc()`` parameter +``documentation`` and the equivalent attribute ``doc``, and it would mean that in +one case (in the function), the term ``doc`` refers to a function, and in the +other case (the resulting class) the term ``doc`` refers to a string value. + +This shows the logic to select the current terms, but it could all be +discussed further. + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From fb2279258a2c1e25c509eda306f0a9e81c0f327c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 30 Aug 2023 00:33:48 +0200 Subject: [PATCH 005/173] PEP 727: Rewordings and clarifications (#3315) --- pep-0727.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/pep-0727.rst b/pep-0727.rst index 494f31082..fd220f65f 100644 --- a/pep-0727.rst +++ b/pep-0727.rst @@ -2,14 +2,14 @@ PEP: 727 Title: Documentation Metadata in Typing Author: Sebastián Ramírez Sponsor: Jelle Zijlstra -Discussions-To: +Discussions-To: https://discuss.python.org/t/pep-727-documentation-metadata-in-typing/32566 Status: Draft Type: Standards Track Topic: Typing Content-Type: text/x-rst Created: 28-Aug-2023 Python-Version: 3.13 -Post-History: +Post-History: `30-Aug-2023 `__ Abstract @@ -45,11 +45,17 @@ the actual parameter. This means it's easy to refactor a function, remove a para and forget to remove its docs. The same happens when adding a new parameter: it's easy to forget to add the docstring for it. -Editors can't check or ensure the consistency of the parameters and their docs. +And because of this same duplication of information (the parameter name) editors and +other tools would need to have complex custom logic to check or ensure the +consistency of the parameters in the signature and in their docstring, or they +would simply not be able to support that. -It's not possible to programatically test these docstrings, for example to ensure -documentation consistency for the parameters across several similar functions, at -least not without implementing a custom syntax parser. +Additionally, it would be difficult to robustly parse varying existing docstring +conventions to programatically get the documentation for each individual parameter +or variable at runtime. This would be useful, for example, +for testing the contents of each parameter's documentation, to ensure consistency +across several similar functions, or to extract and expose that same parameter +documentation in some other way (e.g. an API, a CLI, etc). Some of these previous formats tried to account for the lack of type annotations in older Python versions by including typing information in the docstrings, From 946fa15e8bfc4876b265f49e401b05d5a49455a8 Mon Sep 17 00:00:00 2001 From: xzmeng Date: Thu, 31 Aug 2023 11:16:35 +0800 Subject: [PATCH 006/173] PEP 649, 652, 653, 665, 684, 690, 713, 727: Correct spelling (#3313) --- pep-0649.rst | 4 ++-- pep-0652.rst | 2 +- pep-0653.rst | 4 ++-- pep-0665.rst | 2 +- pep-0684.rst | 2 +- pep-0690.rst | 2 +- pep-0713.rst | 2 +- pep-0727.rst | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pep-0649.rst b/pep-0649.rst index ad6c64afb..e91eb99ff 100644 --- a/pep-0649.rst +++ b/pep-0649.rst @@ -932,7 +932,7 @@ will also require constructing a matching "fake locals" dictionary, which for ``FORWARDREF`` format will be pre-populated with the relevant locals dict. The "fake globals" environment will also have to create -a fake "closure", a tuple of ``FowardRef`` objects +a fake "closure", a tuple of ``ForwardRef`` objects pre-created with the names of the free variables referenced by the ``__annotate__`` method. @@ -1330,7 +1330,7 @@ These codebases examined the annotation strings *without evaluating them,* instead relying on identity checks or simple lexical analysis on the strings. -This PEP supports these technqiues too. But users will need +This PEP supports these techniques too. But users will need to port their code to it. First, user code will need to use ``inspect.get_annotations`` or ``typing.get_type_hints`` to access the annotations; they won't be able to simply get the diff --git a/pep-0652.rst b/pep-0652.rst index 720f41e15..19bdff979 100644 --- a/pep-0652.rst +++ b/pep-0652.rst @@ -210,7 +210,7 @@ The following will be generated from the ABI manifest: * Source for the Windows shared library, ``PC/python3dll.c``. * Input for documentation (see below). -* Test case that checks the runtime availablility of symbols (see below). +* Test case that checks the runtime availability of symbols (see below). The following will be checked against the Stable ABI manifest as part of continuous integration: diff --git a/pep-0653.rst b/pep-0653.rst index 7e81a306b..bfb251122 100644 --- a/pep-0653.rst +++ b/pep-0653.rst @@ -156,7 +156,7 @@ Semantics of the matching process In the following, all variables of the form ``$var`` are temporary variables and are not visible to the Python program. They may be visible via introspection, but that is an implementation detail and should not be relied on. -The psuedo-statement ``FAIL`` is used to signify that matching failed for this pattern and that matching should move to the next pattern. +The pseudo-statement ``FAIL`` is used to signify that matching failed for this pattern and that matching should move to the next pattern. If control reaches the end of the translation without reaching a ``FAIL``, then it has matched, and following patterns are ignored. Variables of the form ``$ALL_CAPS`` are meta-variables holding a syntactic element, they are not normal variables. @@ -165,7 +165,7 @@ but an unpacking of ``$items`` into the variables that ``$VARS`` holds. For example, with the abstract syntax ``case [$VARS]:``, and the concrete syntax ``case[a, b]:`` then ``$VARS`` would hold the variables ``(a, b)``, not the values of those variables. -The psuedo-function ``QUOTE`` takes a variable and returns the name of that variable. +The pseudo-function ``QUOTE`` takes a variable and returns the name of that variable. For example, if the meta-variable ``$VAR`` held the variable ``foo`` then ``QUOTE($VAR) == "foo"``. All additional code listed below that is not present in the original source will not trigger line events, conforming to :pep:`626`. diff --git a/pep-0665.rst b/pep-0665.rst index ec999f54f..923dc83d9 100644 --- a/pep-0665.rst +++ b/pep-0665.rst @@ -740,7 +740,7 @@ Second, consumers of requirements files like cloud providers would also accept lock files. At this point the PEP would have permeated out far enough to be on -par with requirements files in terms of general accpetance and +par with requirements files in terms of general acceptance and potentially more if projects had dropped their own lock files for this PEP. diff --git a/pep-0684.rst b/pep-0684.rst index c8964309c..65c9e5fa1 100644 --- a/pep-0684.rst +++ b/pep-0684.rst @@ -682,7 +682,7 @@ Open Issues (isolation) but doesn't work under a per-interpreter GIL? (See `Extension Module Thread Safety`_.) * If it is likely enough, what can we do to help extension maintainers - mitigate the problem and enjoy use under a per-intepreter GIL? + mitigate the problem and enjoy use under a per-interpreter GIL? * What would be a better (scarier-sounding) name for ``allow_all_extensions``? diff --git a/pep-0690.rst b/pep-0690.rst index 3df31c961..593f117cd 100644 --- a/pep-0690.rst +++ b/pep-0690.rst @@ -507,7 +507,7 @@ For authors of C extension modules, the proposed public C API is as follows: * ``PyDict_NextWithError()``, works the same way as ``PyDict_Next()``, with the exception it propagates any errors to the caller by returning ``0`` and - setting an exception. The caller should use ``PyErr_Ocurred()`` to check for any + setting an exception. The caller should use ``PyErr_Occurred()`` to check for any errors. diff --git a/pep-0713.rst b/pep-0713.rst index eff1c283c..5e704c910 100644 --- a/pep-0713.rst +++ b/pep-0713.rst @@ -61,7 +61,7 @@ without further hooks from the author, even with ``from module import member``. It also results in a "module" object that is missing all of the special module attributes, including ``__doc__``, ``__package__``, ``__path__``, etc. -Alteratively, a module author can choose to override the module's ``__class__`` +Alternatively, a module author can choose to override the module's ``__class__`` property with a custom type that provides a callable interface:: # fancy.py diff --git a/pep-0727.rst b/pep-0727.rst index fd220f65f..da9b018e2 100644 --- a/pep-0727.rst +++ b/pep-0727.rst @@ -372,7 +372,7 @@ A way to declare additional information could still be useful in the future, but taking early feedback on this document, all that was postponed to future proposals. -This also shifts the focus from an all-encompasing function ``doc()`` +This also shifts the focus from an all-encompassing function ``doc()`` with multiple parameters to multiple composable functions, having ``doc()`` handle one single use case: additional documentation in ``Annotated``. From 44fa89d2aea0fc348e7d95296d97036d5d7e181d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 31 Aug 2023 04:39:48 +0100 Subject: [PATCH 007/173] PEP 376: Remove fragment from Post-History entry (#3318) --- pep-0376.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0376.txt b/pep-0376.txt index 5cc2bfc8f..60119c69e 100644 --- a/pep-0376.txt +++ b/pep-0376.txt @@ -7,7 +7,7 @@ Topic: Packaging Content-Type: text/x-rst Created: 22-Feb-2009 Python-Version: 2.7, 3.2 -Post-History: `22-Jun-2009 `__ +Post-History: `22-Jun-2009 `__ .. canonical-pypa-spec:: :ref:`packaging:core-metadata` From aa9ff1bd7a5e72fd0e3e06a8fff5f0814749a2f5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 31 Aug 2023 04:40:00 +0100 Subject: [PATCH 008/173] PEP 11: Remove fragment from Post-History entry (#3317) --- pep-0011.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0011.txt b/pep-0011.txt index ffbd2e766..63131c3a2 100644 --- a/pep-0011.txt +++ b/pep-0011.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 07-Jul-2002 Post-History: `18-Aug-2007 `__, `14-May-2014 `__, - `20-Feb-2015 `__, + `20-Feb-2015 `__, `10-Mar-2022 `__, From f70b3ba7dbf6cd461139dca4581fc72b11faadaa Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 31 Aug 2023 04:40:14 +0100 Subject: [PATCH 009/173] PEP 623: Remove fragment from Resolution (#3319) --- pep-0623.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0623.rst b/pep-0623.rst index ce0227d55..0d182add1 100644 --- a/pep-0623.rst +++ b/pep-0623.rst @@ -8,7 +8,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 25-Jun-2020 Python-Version: 3.10 -Resolution: https://mail.python.org/archives/list/python-dev@python.org/thread/VQKDIZLZ6HF2MLTNCUFURK2IFTXVQEYA/#VQKDIZLZ6HF2MLTNCUFURK2IFTXVQEYA +Resolution: https://mail.python.org/archives/list/python-dev@python.org/thread/VQKDIZLZ6HF2MLTNCUFURK2IFTXVQEYA/ Abstract From 43a28ef8b49f4fec4b6a46aad5e7eb20df88dd76 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 31 Aug 2023 06:42:33 +0300 Subject: [PATCH 010/173] PEP 726: Module __setattr__ and __delattr__ (#3301) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- .github/CODEOWNERS | 1 + pep-0726.rst | 188 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 pep-0726.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 72f2bcd2c..4602dbe7b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -602,6 +602,7 @@ pep-0721.rst @encukou pep-0722.rst @pfmoore pep-0723.rst @AA-Turner pep-0725.rst @pradyunsg +pep-0726.rst @AA-Turner pep-0727.rst @JelleZijlstra # ... # pep-0754.txt diff --git a/pep-0726.rst b/pep-0726.rst new file mode 100644 index 000000000..20b821ad3 --- /dev/null +++ b/pep-0726.rst @@ -0,0 +1,188 @@ +PEP: 726 +Title: Module ``__setattr__`` and ``__delattr__`` +Author: Sergey B Kirpichev +Sponsor: Adam Turner +Discussions-To: https://discuss.python.org/t/32640/ +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 24-Aug-2023 +Python-Version: 3.13 +Post-History: `06-Apr-2023 `__, + `31-Aug-2023 `__, + + +Abstract +======== + +This PEP proposes supporting user-defined ``__setattr__`` +and ``__delattr__`` methods on modules to extend customization +of module attribute access beyond :pep:`562`. + +Motivation +========== + +There are several potential uses of a module ``__setattr__``: + +1. To prevent setting an attribute at all (i.e. make it read-only) +2. To validate the value to be assigned +3. To intercept setting an attribute and update some other state + +Proper support for read-only attributes would also require adding the +``__delattr__`` function to prevent their deletion. + +A typical workaround is assigning the ``__class__`` of a module object to a +custom subclass of :py:class:`python:types.ModuleType` (see [1]_). +Unfortunately, this also brings a noticeable speed regression +(~2-3x) for attribute *access*. It would be convenient to directly +support such customization, by recognizing ``__setattr__`` and ``__delattr__`` +methods defined in a module that would act like normal +:py:meth:`python:object.__setattr__` and :py:meth:`python:object.__delattr__` +methods, except that they will be defined on module *instances*. + +For example + +.. code:: python + + # mplib.py + + CONSTANT = 3.14 + prec = 53 + dps = 15 + + def dps_to_prec(n): + """Return the number of bits required to represent n decimals accurately.""" + return max(1, int(round((int(n)+1)*3.3219280948873626))) + + def prec_to_dps(n): + """Return the number of accurate decimals that can be represented with n bits.""" + return max(1, int(round(int(n)/3.3219280948873626)-1)) + + def validate(n): + n = int(n) + if n <= 0: + raise ValueError('non-negative integer expected') + return n + + def __setattr__(name, value): + if name == 'CONSTANT': + raise AttributeError('Read-only attribute!') + if name == 'dps': + value = validate(value) + globals()['dps'] = value + globals()['prec'] = dps_to_prec(value) + return + if name == 'prec': + value = validate(value) + globals()['prec'] = value + globals()['dps'] = prec_to_dps(value) + return + globals()[name] = value + + def __delattr__(name): + if name in ('CONSTANT', 'dps', 'prec'): + raise AttributeError('Read-only attribute!') + del globals()[name] + +.. code:: pycon + + >>> import mplib + >>> mplib.foo = 'spam' + >>> mplib.CONSTANT = 42 + Traceback (most recent call last): + ... + AttributeError: Read-only attribute! + >>> del mplib.foo + >>> del mplib.CONSTANT + Traceback (most recent call last): + ... + AttributeError: Read-only attribute! + >>> mplib.prec + 53 + >>> mplib.dps + 15 + >>> mplib.dps = 5 + >>> mplib.prec + 20 + >>> mplib.dps = 0 + Traceback (most recent call last): + ... + ValueError: non-negative integer expected + + +Specification +============= + +The ``__setattr__`` function at the module level should accept two +arguments, the name of an attribute and the value to be assigned, +and return :py:obj:`None` or raise an :exc:`AttributeError`. + +.. code:: python + + def __setattr__(name: str, value: typing.Any, /) -> None: ... + +The ``__delattr__`` function should accept one argument, +the name of an attribute, and return :py:obj:`None` or raise an +:py:exc:`AttributeError`: + +.. code:: python + + def __delattr__(name: str, /) -> None: ... + +The ``__setattr__`` and ``__delattr__`` functions are looked up in the +module ``__dict__``. If present, the appropriate function is called to +customize setting the attribute or its deletion, else the normal +mechanism (storing/deleting the value in the module dictionary) will work. + +Defining ``__setattr__`` or ``__delattr__`` only affect lookups made +using the attribute access syntax---directly accessing the module +globals is unaffected, e.g. ``sys.modules[__name__].some_global = 'spam'``. + + +How to Teach This +================= + +The "Customizing module attribute access" [1]_ section of the documentation +will be expanded to include new functions. + + +Reference Implementation +======================== + +The reference implementation for this PEP can be found in `CPython PR #108261 +`__. + + +Backwards compatibility +======================= + +This PEP may break code that uses module level (global) names +``__setattr__`` and ``__delattr__``, but the language reference +explicitly reserves *all* undocumented dunder names, and allows +"breakage without warning" [2]_. + +The performance implications of this PEP are small, since additional +dictionary lookup is much cheaper than storing/deleting the value in +the dictionary. Also it is hard to imagine a module that expects the +user to set (and/or delete) attributes enough times to be a +performance concern. On another hand, proposed mechanism allows to +override setting/deleting of attributes without affecting speed of +attribute access, which is much more likely scenario to get a +performance penalty. + + +Footnotes +========= + +.. [1] Customizing module attribute access + (https://docs.python.org/3.11/reference/datamodel.html#customizing-module-attribute-access) + +.. [2] Reserved classes of identifiers + (https://docs.python.org/3.11/reference/lexical_analysis.html#reserved-classes-of-identifiers) + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From dbe0dd8c4f8c68f8fa43043b72f19fe3afd5840e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 05:57:00 +0100 Subject: [PATCH 011/173] Ensure the ``:pep:`` role works properly with the dirhtml builder (#3322) --- pep_sphinx_extensions/__init__.py | 2 +- pep_sphinx_extensions/pep_zero_generator/writer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep_sphinx_extensions/__init__.py b/pep_sphinx_extensions/__init__.py index 672a6a452..8538b838a 100644 --- a/pep_sphinx_extensions/__init__.py +++ b/pep_sphinx_extensions/__init__.py @@ -28,7 +28,7 @@ def _update_config_for_builder(app: Sphinx) -> None: app.env.document_ids = {} # For PEPReferenceRoleTitleText app.env.settings["builder"] = app.builder.name if app.builder.name == "dirhtml": - app.env.settings["pep_url"] = "pep-{:0>4}" + app.env.settings["pep_url"] = "pep-{:0>4}/" app.connect("build-finished", _post_build) # Post-build tasks diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index b6171f731..cfb8e864e 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -149,7 +149,7 @@ class PEPZeroWriter: target = ( f"topic/{subindex}.html" if builder == "html" - else f"../topic/{subindex}" + else f"../topic/{subindex}/" ) self.emit_text(f"* `{subindex.title()} PEPs <{target}>`_") self.emit_newline() From a16d9f9f9b3dd2e61c6eac5c7352950ca3fc4325 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:02:27 +0100 Subject: [PATCH 012/173] PEP 703: Remove blank ``Resolution`` header (#3323) --- pep-0703.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/pep-0703.rst b/pep-0703.rst index b7a0d6cf3..1eb697caf 100644 --- a/pep-0703.rst +++ b/pep-0703.rst @@ -10,7 +10,6 @@ Created: 09-Jan-2023 Python-Version: 3.13 Post-History: `09-Jan-2023 `__, `04-May-2023 `__ -Resolution: Abstract From d90efc2f9923699cc23c7bb5c5fbdf338e5c5684 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:03:16 +0100 Subject: [PATCH 013/173] PEP 720: Remove blank ``Resolution`` header (#3324) --- pep-0720.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/pep-0720.rst b/pep-0720.rst index 87c00ae7c..14e0708c7 100644 --- a/pep-0720.rst +++ b/pep-0720.rst @@ -7,7 +7,6 @@ Type: Informational Content-Type: text/x-rst Created: 01-Jul-2023 Python-Version: 3.12 -Resolution: Abstract From 513dc168afc2457bcf514eeac65f91a9819b227d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 1 Sep 2023 08:11:23 +0300 Subject: [PATCH 014/173] PEP 726: Correct and expand specification (#3320) Co-authored-by: Oscar Benjamin Co-authored-by: Jelle Zijlstra Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- pep-0726.rst | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/pep-0726.rst b/pep-0726.rst index 20b821ad3..44cd3d9fa 100644 --- a/pep-0726.rst +++ b/pep-0726.rst @@ -134,9 +134,47 @@ module ``__dict__``. If present, the appropriate function is called to customize setting the attribute or its deletion, else the normal mechanism (storing/deleting the value in the module dictionary) will work. -Defining ``__setattr__`` or ``__delattr__`` only affect lookups made -using the attribute access syntax---directly accessing the module -globals is unaffected, e.g. ``sys.modules[__name__].some_global = 'spam'``. +Defining module ``__setattr__`` or ``__delattr__`` only affects lookups made +using the attribute access syntax---directly accessing the module globals +(whether by ``globals()`` within the module, or via a reference to the module's +globals dictionary) is unaffected. For example: + +.. code:: pycon + + >>> import mod + >>> mod.__dict__['foo'] = 'spam' # bypasses __setattr__, defined in mod.py + +or + +.. code:: python + + # mod.py + + def __setattr__(name, value): + ... + + foo = 'spam' # bypasses __setattr__ + globals()['bar'] = 'spam' # here too + + def f(): + global x + x = 123 + + f() # and here + +To use a module global and trigger ``__setattr__`` (or ``__delattr__``), +one can access it via ``sys.modules[__name__]`` within the module's code: + +.. code:: python + + # mod.py + + sys.modules[__name__].foo = 'spam' # bypasses __setattr__ + + def __setattr__(name, value): + ... + + sys.modules[__name__].bar = 'spam' # triggers __setattr__ How to Teach This From 8ba873d2b449537945cbdb0e293fd61356c5cecf Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:35:46 +0100 Subject: [PATCH 015/173] PEP 418: Standardise authors (#3327) --- pep-0418.txt | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt index bcf698ec8..b728a3fb3 100644 --- a/pep-0418.txt +++ b/pep-0418.txt @@ -1,8 +1,9 @@ PEP: 418 Title: Add monotonic time, performance counter, and process time functions -Version: $Revision$ -Last-Modified: $Date$ -Author: Cameron Simpson , Jim Jewett , Stephen J. Turnbull , Victor Stinner +Author: Cameron Simpson , + Jim J. Jewett , + Stephen J. Turnbull , + Victor Stinner Status: Final Type: Standards Track Content-Type: text/x-rst @@ -1640,14 +1641,3 @@ Copyright ========= This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 2044cd779811f315c383818c29a4e4ef4eb05745 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:37:07 +0100 Subject: [PATCH 016/173] PEP 284: Standardise authors (#3328) --- pep-0284.txt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/pep-0284.txt b/pep-0284.txt index 48c476f23..08fedf5ab 100644 --- a/pep-0284.txt +++ b/pep-0284.txt @@ -1,9 +1,7 @@ PEP: 284 Title: Integer for-loops -Version: $Revision$ -Last-Modified: $Date$ Author: David Eppstein , - Greg Ewing + Gregory Ewing Status: Rejected Type: Standards Track Content-Type: text/x-rst @@ -264,12 +262,3 @@ Copyright ========= This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - fill-column: 70 - End: From 53892a7c6cd60cbf9897d2805706eefe1c6b2d73 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:39:22 +0100 Subject: [PATCH 017/173] PEP 402: Standardise authors (#3329) --- pep-0402.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0402.txt b/pep-0402.txt index 0d8a95440..2581eaf08 100644 --- a/pep-0402.txt +++ b/pep-0402.txt @@ -1,8 +1,6 @@ PEP: 402 Title: Simplified Package Layout and Partitioning -Version: $Revision$ -Last-Modified: $Date$ -Author: P.J. Eby +Author: Phillip J. Eby Status: Rejected Type: Standards Track Topic: Packaging @@ -664,13 +662,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From f5eb3053ca9c848bd894fc6c8c5ee215ef9fa95f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:40:29 +0100 Subject: [PATCH 018/173] PEP 3333: Standardise authors (#3330) --- pep-3333.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-3333.txt b/pep-3333.txt index d6d3dfa74..35e097936 100644 --- a/pep-3333.txt +++ b/pep-3333.txt @@ -1,8 +1,6 @@ PEP: 3333 Title: Python Web Server Gateway Interface v1.0.1 -Version: $Revision$ -Last-Modified: $Date$ -Author: P.J. Eby +Author: Phillip J. Eby Discussions-To: web-sig@python.org Status: Final Type: Informational @@ -1780,13 +1778,3 @@ Copyright ========= This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - End: From f710aaab09ba9a0a2af6e3da70f4bfb9e354aad9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:42:24 +0100 Subject: [PATCH 019/173] PEP 516: Standardise authors (#3331) --- pep-0516.txt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pep-0516.txt b/pep-0516.txt index de209ada0..241683f23 100644 --- a/pep-0516.txt +++ b/pep-0516.txt @@ -1,9 +1,7 @@ PEP: 516 Title: Build system abstraction for pip/conda etc -Version: $Revision$ -Last-Modified: $Date$ Author: Robert Collins , - Nathaniel Smith + Nathaniel J. Smith BDFL-Delegate: Nick Coghlan Discussions-To: distutils-sig@python.org Status: Rejected @@ -473,14 +471,3 @@ Copyright ========= This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 3e5f30d86a2a688fa0dada7e1ee25c8f9ca08ab4 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:43:24 +0100 Subject: [PATCH 020/173] PEP 518: Standardise authors (#3332) --- pep-0518.txt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pep-0518.txt b/pep-0518.txt index 744a56657..a2ce91924 100644 --- a/pep-0518.txt +++ b/pep-0518.txt @@ -1,9 +1,7 @@ PEP: 518 Title: Specifying Minimum Build System Requirements for Python Projects -Version: $Revision$ -Last-Modified: $Date$ Author: Brett Cannon , - Nathaniel Smith , + Nathaniel J. Smith , Donald Stufft BDFL-Delegate: Nick Coghlan Discussions-To: distutils-sig@python.org @@ -559,14 +557,3 @@ Copyright ========= This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 7221c620bab2072f3805824fc737432122f24894 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:46:38 +0100 Subject: [PATCH 021/173] PEP 381: Standardise authors (#3333) --- pep-0381.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0381.txt b/pep-0381.txt index 2bfad7c1e..8f2952b20 100644 --- a/pep-0381.txt +++ b/pep-0381.txt @@ -1,8 +1,6 @@ PEP: 381 Title: Mirroring infrastructure for PyPI -Version: $Revision$ -Last-Modified: $Date$ -Author: Tarek Ziadé , Martin v. Löwis +Author: Tarek Ziadé , Martin von Löwis Status: Withdrawn Type: Standards Track Topic: Packaging @@ -376,13 +374,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 7a54537f90c9a5c60926b3e76a76f258fc2e90a9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:47:46 +0100 Subject: [PATCH 022/173] PEP 382: Standardise authors (#3334) --- pep-0382.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0382.txt b/pep-0382.txt index 520c33c01..ecbbaeacc 100644 --- a/pep-0382.txt +++ b/pep-0382.txt @@ -1,8 +1,6 @@ PEP: 382 Title: Namespace Packages -Version: $Revision$ -Last-Modified: $Date$ -Author: Martin v. Löwis +Author: Martin von Löwis Status: Rejected Type: Standards Track Content-Type: text/x-rst @@ -215,13 +213,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 780dbfac1b8ff5a5dff5820aeff87e9d3ef27c72 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:48:59 +0100 Subject: [PATCH 023/173] PEP 383: Standardise authors (#3335) --- pep-0383.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0383.txt b/pep-0383.txt index e13c7b953..cce198367 100644 --- a/pep-0383.txt +++ b/pep-0383.txt @@ -1,6 +1,6 @@ PEP: 383 Title: Non-decodable Bytes in System Character Interfaces -Author: Martin v. Löwis +Author: Martin von Löwis Status: Final Type: Standards Track Content-Type: text/x-rst From 4d59688c371864f317f78236b1c8db6839be4192 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:50:31 +0100 Subject: [PATCH 024/173] PEP 384: Standardise authors (#3336) --- pep-0384.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0384.txt b/pep-0384.txt index 7c7b4e495..867173da9 100644 --- a/pep-0384.txt +++ b/pep-0384.txt @@ -1,8 +1,6 @@ PEP: 384 Title: Defining a Stable ABI -Version: $Revision$ -Last-Modified: $Date$ -Author: Martin v. Löwis +Author: Martin von Löwis Status: Final Type: Standards Track Content-Type: text/x-rst @@ -375,13 +373,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From bb6e5c9ad2d7e0dde3c53a4e1dd187b0df05a3d5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:51:45 +0100 Subject: [PATCH 025/173] PEP 393: Standardise authors (#3337) --- pep-0393.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0393.txt b/pep-0393.txt index 2bd4d83db..bee0319fd 100644 --- a/pep-0393.txt +++ b/pep-0393.txt @@ -1,8 +1,6 @@ PEP: 393 Title: Flexible String Representation -Version: $Revision$ -Last-Modified: $Date$ -Author: Martin v. Löwis +Author: Martin von Löwis Status: Final Type: Standards Track Content-Type: text/x-rst @@ -463,13 +461,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 3c5f6973cf6d4395a2c8672b13838331a58ee8b8 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:53:06 +0100 Subject: [PATCH 026/173] PEP 397: Standardise authors (#3338) --- pep-0397.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0397.txt b/pep-0397.txt index b0b170a56..bec6ac504 100644 --- a/pep-0397.txt +++ b/pep-0397.txt @@ -1,9 +1,7 @@ PEP: 397 Title: Python launcher for Windows -Version: $Revision: a57419aee37d $ -Last-Modified: $Date: 2012/06/19 15:13:49 $ Author: Mark Hammond , - Martin v. Löwis + Martin von Löwis Status: Final Type: Standards Track Content-Type: text/x-rst @@ -420,13 +418,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 32a92bd50b9fcce44189ac1083017804506f0347 Mon Sep 17 00:00:00 2001 From: Josh Cannon Date: Fri, 1 Sep 2023 10:11:33 -0500 Subject: [PATCH 027/173] PEP 0: Use authors' full names over surnames (#3295) Co-authored-by: Hugo van Kemenade Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- AUTHOR_OVERRIDES.csv | 13 --- .../pep_zero_generator/author.py | 89 ------------------- .../pep_zero_generator/parser.py | 47 ++++------ .../pep_zero_generator/writer.py | 16 ++-- .../tests/pep_zero_generator/test_author.py | 69 -------------- .../tests/pep_zero_generator/test_parser.py | 29 ++++-- .../tests/pep_zero_generator/test_writer.py | 6 +- pep_sphinx_extensions/tests/utils.py | 6 -- 8 files changed, 50 insertions(+), 225 deletions(-) delete mode 100644 AUTHOR_OVERRIDES.csv delete mode 100644 pep_sphinx_extensions/pep_zero_generator/author.py delete mode 100644 pep_sphinx_extensions/tests/pep_zero_generator/test_author.py delete mode 100644 pep_sphinx_extensions/tests/utils.py diff --git a/AUTHOR_OVERRIDES.csv b/AUTHOR_OVERRIDES.csv deleted file mode 100644 index ba4e681a2..000000000 --- a/AUTHOR_OVERRIDES.csv +++ /dev/null @@ -1,13 +0,0 @@ -Overridden Name,Surname First,Name Reference -The Python core team and community,"The Python core team and community",python-dev -Erik De Bonte,"De Bonte, Erik",De Bonte -Greg Ewing,"Ewing, Gregory",Ewing -Guido van Rossum,"van Rossum, Guido (GvR)",GvR -Inada Naoki,"Inada, Naoki",Inada -Jim Jewett,"Jewett, Jim J.",Jewett -Just van Rossum,"van Rossum, Just (JvR)",JvR -Martin v. Löwis,"von Löwis, Martin",von Löwis -Nathaniel Smith,"Smith, Nathaniel J.",Smith -P.J. Eby,"Eby, Phillip J.",Eby -Germán Méndez Bravo,"Méndez Bravo, Germán",Méndez Bravo -Amethyst Reese,"Reese, Amethyst",Amethyst diff --git a/pep_sphinx_extensions/pep_zero_generator/author.py b/pep_sphinx_extensions/pep_zero_generator/author.py deleted file mode 100644 index 4425c6b3c..000000000 --- a/pep_sphinx_extensions/pep_zero_generator/author.py +++ /dev/null @@ -1,89 +0,0 @@ -from __future__ import annotations - -from typing import NamedTuple - - -class _Name(NamedTuple): - mononym: str = None - forename: str = None - surname: str = None - suffix: str = None - - -class Author(NamedTuple): - """Represent PEP authors.""" - last_first: str # The author's name in Surname, Forename, Suffix order. - nick: str # Author's nickname for PEP tables. Defaults to surname. - email: str # The author's email address. - - -def parse_author_email(author_email_tuple: tuple[str, str], authors_overrides: dict[str, dict[str, str]]) -> Author: - """Parse the name and email address of an author.""" - name, email = author_email_tuple - _first_last = name.strip() - email = email.lower() - - if _first_last in authors_overrides: - name_dict = authors_overrides[_first_last] - last_first = name_dict["Surname First"] - nick = name_dict["Name Reference"] - return Author(last_first, nick, email) - - name_parts = _parse_name(_first_last) - if name_parts.mononym is not None: - return Author(name_parts.mononym, name_parts.mononym, email) - - if name_parts.suffix: - last_first = f"{name_parts.surname}, {name_parts.forename}, {name_parts.suffix}" - return Author(last_first, name_parts.surname, email) - - last_first = f"{name_parts.surname}, {name_parts.forename}" - return Author(last_first, name_parts.surname, email) - - -def _parse_name(full_name: str) -> _Name: - """Decompose a full name into parts. - - If a mononym (e.g, 'Aahz') then return the full name. If there are - suffixes in the name (e.g. ', Jr.' or 'II'), then find and extract - them. If there is a middle initial followed by a full stop, then - combine the following words into a surname (e.g. N. Vander Weele). If - there is a leading, lowercase portion to the last name (e.g. 'van' or - 'von') then include it in the surname. - - """ - possible_suffixes = {"Jr", "Jr.", "II", "III"} - - pre_suffix, _, raw_suffix = full_name.partition(",") - name_parts = pre_suffix.strip().split(" ") - num_parts = len(name_parts) - suffix = raw_suffix.strip() - - if name_parts == [""]: - raise ValueError("Name is empty!") - elif num_parts == 1: - return _Name(mononym=name_parts[0], suffix=suffix) - elif num_parts == 2: - return _Name(forename=name_parts[0].strip(), surname=name_parts[1], suffix=suffix) - - # handles rogue uncaught suffixes - if name_parts[-1] in possible_suffixes: - suffix = f"{name_parts.pop(-1)} {suffix}".strip() - - # handles von, van, v. etc. - if name_parts[-2].islower(): - forename = " ".join(name_parts[:-2]).strip() - surname = " ".join(name_parts[-2:]) - return _Name(forename=forename, surname=surname, suffix=suffix) - - # handles double surnames after a middle initial (e.g. N. Vander Weele) - elif any(s.endswith(".") for s in name_parts): - split_position = [i for i, x in enumerate(name_parts) if x.endswith(".")][-1] + 1 - forename = " ".join(name_parts[:split_position]).strip() - surname = " ".join(name_parts[split_position:]) - return _Name(forename=forename, surname=surname, suffix=suffix) - - # default to using the last item as the surname - else: - forename = " ".join(name_parts[:-1]).strip() - return _Name(forename=forename, surname=name_parts[-1], suffix=suffix) diff --git a/pep_sphinx_extensions/pep_zero_generator/parser.py b/pep_sphinx_extensions/pep_zero_generator/parser.py index 220ef308c..2ce802a13 100644 --- a/pep_sphinx_extensions/pep_zero_generator/parser.py +++ b/pep_sphinx_extensions/pep_zero_generator/parser.py @@ -2,13 +2,10 @@ from __future__ import annotations -import csv from email.parser import HeaderParser from pathlib import Path import re -from typing import TYPE_CHECKING -from pep_sphinx_extensions.pep_zero_generator.author import parse_author_email from pep_sphinx_extensions.pep_zero_generator.constants import ACTIVE_ALLOWED from pep_sphinx_extensions.pep_zero_generator.constants import HIDE_STATUS from pep_sphinx_extensions.pep_zero_generator.constants import SPECIAL_STATUSES @@ -19,17 +16,6 @@ from pep_sphinx_extensions.pep_zero_generator.constants import TYPE_STANDARDS from pep_sphinx_extensions.pep_zero_generator.constants import TYPE_VALUES from pep_sphinx_extensions.pep_zero_generator.errors import PEPError -if TYPE_CHECKING: - from pep_sphinx_extensions.pep_zero_generator.author import Author - - -# AUTHOR_OVERRIDES.csv is an exception file for PEP 0 name parsing -AUTHOR_OVERRIDES: dict[str, dict[str, str]] = {} -with open("AUTHOR_OVERRIDES.csv", "r", encoding="utf-8") as f: - for line in csv.DictReader(f): - full_name = line.pop("Overridden Name") - AUTHOR_OVERRIDES[full_name] = line - class PEP: """Representation of PEPs. @@ -97,7 +83,7 @@ class PEP: self.status: str = status # Parse PEP authors - self.authors: list[Author] = _parse_authors(self, metadata["Author"], AUTHOR_OVERRIDES) + self.authors: dict[str, str] = _parse_authors(self, metadata["Author"]) # Topic (for sub-indices) _topic = metadata.get("Topic", "").lower().split(",") @@ -144,7 +130,7 @@ class PEP: # a tooltip representing the type and status "shorthand": self.shorthand, # the author list as a comma-separated with only last names - "authors": ", ".join(author.nick for author in self.authors), + "authors": ", ".join(self.authors), } @property @@ -153,7 +139,7 @@ class PEP: return { "number": self.number, "title": self.title, - "authors": ", ".join(author.nick for author in self.authors), + "authors": ", ".join(self.authors), "discussions_to": self.discussions_to, "status": self.status, "type": self.pep_type, @@ -175,12 +161,12 @@ def _raise_pep_error(pep: PEP, msg: str, pep_num: bool = False) -> None: raise PEPError(msg, pep.filename) -def _parse_authors(pep: PEP, author_header: str, authors_overrides: dict) -> list[Author]: +def _parse_authors(pep: PEP, author_header: str) -> dict[str, str]: """Parse Author header line""" - authors_and_emails = _parse_author(author_header) - if not authors_and_emails: + authors_to_emails = _parse_author(author_header) + if not authors_to_emails: raise _raise_pep_error(pep, "no authors found", pep_num=True) - return [parse_author_email(author_tuple, authors_overrides) for author_tuple in authors_and_emails] + return authors_to_emails author_angled = re.compile(r"(?P.+?) <(?P.+?)>(,\s*)?") @@ -188,10 +174,10 @@ author_paren = re.compile(r"(?P.+?) \((?P.+?)\)(,\s*)?") author_simple = re.compile(r"(?P[^,]+)(,\s*)?") -def _parse_author(data: str) -> list[tuple[str, str]]: - """Return a list of author names and emails.""" +def _parse_author(data: str) -> dict[str, str]: + """Return a mapping of author names to emails.""" - author_list = [] + author_items = [] for regex in (author_angled, author_paren, author_simple): for match in regex.finditer(data): # Watch out for suffixes like 'Jr.' when they are comma-separated @@ -200,16 +186,21 @@ def _parse_author(data: str) -> list[tuple[str, str]]: match_dict = match.groupdict() author = match_dict["author"] if not author.partition(" ")[1] and author.endswith("."): - prev_author = author_list.pop() + prev_author = author_items.pop() author = ", ".join([prev_author, author]) if "email" not in match_dict: email = "" else: email = match_dict["email"] - author_list.append((author, email)) + + author = author.strip() + if not author: + raise ValueError("Name is empty!") + + author_items.append((author, email.lower().strip())) # If authors were found then stop searching as only expect one # style of author citation. - if author_list: + if author_items: break - return author_list + return dict(author_items) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index cfb8e864e..043337a77 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -295,24 +295,24 @@ def _classify_peps(peps: list[PEP]) -> tuple[list[PEP], ...]: def _verify_email_addresses(peps: list[PEP]) -> dict[str, str]: authors_dict: dict[str, set[str]] = {} for pep in peps: - for author in pep.authors: + for author, email in pep.authors.items(): # If this is the first time we have come across an author, add them. - if author.last_first not in authors_dict: - authors_dict[author.last_first] = set() + if author not in authors_dict: + authors_dict[author] = set() # If the new email is an empty string, move on. - if not author.email: + if not email: continue # If the email has not been seen, add it to the list. - authors_dict[author.last_first].add(author.email) + authors_dict[author].add(email) valid_authors_dict: dict[str, str] = {} too_many_emails: list[tuple[str, set[str]]] = [] - for last_first, emails in authors_dict.items(): + for name, emails in authors_dict.items(): if len(emails) > 1: - too_many_emails.append((last_first, emails)) + too_many_emails.append((name, emails)) else: - valid_authors_dict[last_first] = next(iter(emails), "") + valid_authors_dict[name] = next(iter(emails), "") if too_many_emails: err_output = [] for author, emails in too_many_emails: diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py deleted file mode 100644 index 8334b1c5f..000000000 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py +++ /dev/null @@ -1,69 +0,0 @@ -import pytest - -from pep_sphinx_extensions.pep_zero_generator import author -from pep_sphinx_extensions.tests.utils import AUTHORS_OVERRIDES - - -@pytest.mark.parametrize( - "test_input, expected", - [ - ( - ("First Last", "first@example.com"), - author.Author( - last_first="Last, First", nick="Last", email="first@example.com" - ), - ), - ( - ("Guido van Rossum", "guido@example.com"), - author.Author( - last_first="van Rossum, Guido (GvR)", - nick="GvR", - email="guido@example.com", - ), - ), - ( - ("Hugo van Kemenade", "hugo@example.com"), - author.Author( - last_first="van Kemenade, Hugo", - nick="van Kemenade", - email="hugo@example.com", - ), - ), - ( - ("Eric N. Vander Weele", "eric@example.com"), - author.Author( - last_first="Vander Weele, Eric N.", - nick="Vander Weele", - email="eric@example.com", - ), - ), - ( - ("Mariatta", "mariatta@example.com"), - author.Author( - last_first="Mariatta", nick="Mariatta", email="mariatta@example.com" - ), - ), - ( - ("First Last Jr.", "first@example.com"), - author.Author( - last_first="Last, First, Jr.", nick="Last", email="first@example.com" - ), - ), - pytest.param( - ("First Last", "first at example.com"), - author.Author( - last_first="Last, First", nick="Last", email="first@example.com" - ), - marks=pytest.mark.xfail, - ), - ], -) -def test_parse_author_email(test_input, expected): - out = author.parse_author_email(test_input, AUTHORS_OVERRIDES) - - assert out == expected - - -def test_parse_author_email_empty_name(): - with pytest.raises(ValueError, match="Name is empty!"): - author.parse_author_email(("", "user@example.com"), AUTHORS_OVERRIDES) diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index d5ebab143..4950acbb1 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -3,7 +3,6 @@ from pathlib import Path import pytest from pep_sphinx_extensions.pep_zero_generator import parser -from pep_sphinx_extensions.pep_zero_generator.author import Author from pep_sphinx_extensions.pep_zero_generator.constants import ( STATUS_ACCEPTED, STATUS_ACTIVE, @@ -19,7 +18,6 @@ from pep_sphinx_extensions.pep_zero_generator.constants import ( TYPE_STANDARDS, ) from pep_sphinx_extensions.pep_zero_generator.errors import PEPError -from pep_sphinx_extensions.tests.utils import AUTHORS_OVERRIDES def test_pep_repr(): @@ -46,7 +44,7 @@ def test_pep_details(monkeypatch): pep8 = parser.PEP(Path("pep-0008.txt")) assert pep8.details == { - "authors": "GvR, Warsaw, Coghlan", + "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", "number": 8, "shorthand": ":abbr:`PA (Process, Active)`", "title": "Style Guide for Python Code", @@ -58,21 +56,34 @@ def test_pep_details(monkeypatch): [ ( "First Last ", - [Author(last_first="Last, First", nick="Last", email="user@example.com")], + {"First Last": "user@example.com"}, + ), + ( + "First Last < user@example.com >", + {"First Last": "user@example.com"}, ), ( "First Last", - [Author(last_first="Last, First", nick="Last", email="")], + {"First Last": ""}, ), ( "user@example.com (First Last)", - [Author(last_first="Last, First", nick="Last", email="user@example.com")], + {"First Last": "user@example.com"}, + ), + ( + "user@example.com ( First Last )", + {"First Last": "user@example.com"}, ), pytest.param( "First Last ", - [Author(last_first="Last, First", nick="Last", email="user@example.com")], + {"First Last": "user@example.com"}, marks=pytest.mark.xfail, ), + pytest.param( + " , First Last,", + {"First Last": ""}, + marks=pytest.mark.xfail(raises=ValueError), + ), ], ) def test_parse_authors(test_input, expected): @@ -80,7 +91,7 @@ def test_parse_authors(test_input, expected): dummy_object = parser.PEP(Path("pep-0160.txt")) # Act - out = parser._parse_authors(dummy_object, test_input, AUTHORS_OVERRIDES) + out = parser._parse_authors(dummy_object, test_input) # Assert assert out == expected @@ -90,7 +101,7 @@ def test_parse_authors_invalid(): pep = parser.PEP(Path("pep-0008.txt")) with pytest.raises(PEPError, match="no authors found"): - parser._parse_authors(pep, "", AUTHORS_OVERRIDES) + parser._parse_authors(pep, "") @pytest.mark.parametrize( diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py index 19eeca2d9..150a317bb 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -35,13 +35,13 @@ def test_pep_zero_writer_emit_title(): ( "pep-9000.rst", { - "Fussyreverend, Francis": "one@example.com", - "Soulfulcommodore, Javier": "two@example.com", + "Francis Fussyreverend": "one@example.com", + "Javier Soulfulcommodore": "two@example.com", }, ), ( "pep-9001.rst", - {"Fussyreverend, Francis": "", "Soulfulcommodore, Javier": ""}, + {"Francis Fussyreverend": "", "Javier Soulfulcommodore": ""}, ), ], ) diff --git a/pep_sphinx_extensions/tests/utils.py b/pep_sphinx_extensions/tests/utils.py deleted file mode 100644 index 19167d552..000000000 --- a/pep_sphinx_extensions/tests/utils.py +++ /dev/null @@ -1,6 +0,0 @@ -AUTHORS_OVERRIDES = { - "Guido van Rossum": { - "Surname First": "van Rossum, Guido (GvR)", - "Name Reference": "GvR", - }, -} From 3550731898aa878bb0016258cdd4ccc3f1da51f7 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:19:19 +0100 Subject: [PATCH 028/173] PEP 0: Refactoring (#3340) --- .../pep_zero_generator/parser.py | 73 ++++++++----------- .../pep_zero_generator/writer.py | 24 +++--- .../tests/pep_zero_generator/test_parser.py | 31 ++------ 3 files changed, 50 insertions(+), 78 deletions(-) diff --git a/pep_sphinx_extensions/pep_zero_generator/parser.py b/pep_sphinx_extensions/pep_zero_generator/parser.py index 2ce802a13..96b4e9aba 100644 --- a/pep_sphinx_extensions/pep_zero_generator/parser.py +++ b/pep_sphinx_extensions/pep_zero_generator/parser.py @@ -2,6 +2,7 @@ from __future__ import annotations +import dataclasses from email.parser import HeaderParser from pathlib import Path import re @@ -17,6 +18,13 @@ from pep_sphinx_extensions.pep_zero_generator.constants import TYPE_VALUES from pep_sphinx_extensions.pep_zero_generator.errors import PEPError +@dataclasses.dataclass(order=True, frozen=True) +class _Author: + """Represent PEP authors.""" + full_name: str # The author's name. + email: str # The author's email address. + + class PEP: """Representation of PEPs. @@ -83,7 +91,9 @@ class PEP: self.status: str = status # Parse PEP authors - self.authors: dict[str, str] = _parse_authors(self, metadata["Author"]) + self.authors: list[_Author] = _parse_author(metadata["Author"]) + if not self.authors: + raise _raise_pep_error(self, "no authors found", pep_num=True) # Topic (for sub-indices) _topic = metadata.get("Topic", "").lower().split(",") @@ -130,7 +140,7 @@ class PEP: # a tooltip representing the type and status "shorthand": self.shorthand, # the author list as a comma-separated with only last names - "authors": ", ".join(self.authors), + "authors": ", ".join(author.full_name for author in self.authors), } @property @@ -139,7 +149,7 @@ class PEP: return { "number": self.number, "title": self.title, - "authors": ", ".join(self.authors), + "authors": ", ".join(author.full_name for author in self.authors), "discussions_to": self.discussions_to, "status": self.status, "type": self.pep_type, @@ -161,46 +171,27 @@ def _raise_pep_error(pep: PEP, msg: str, pep_num: bool = False) -> None: raise PEPError(msg, pep.filename) -def _parse_authors(pep: PEP, author_header: str) -> dict[str, str]: - """Parse Author header line""" - authors_to_emails = _parse_author(author_header) - if not authors_to_emails: - raise _raise_pep_error(pep, "no authors found", pep_num=True) - return authors_to_emails +jr_placeholder = ",Jr" -author_angled = re.compile(r"(?P.+?) <(?P.+?)>(,\s*)?") -author_paren = re.compile(r"(?P.+?) \((?P.+?)\)(,\s*)?") -author_simple = re.compile(r"(?P[^,]+)(,\s*)?") +def _parse_author(data: str) -> list[_Author]: + """Return a list of author names and emails.""" + author_list = [] + data = (data.replace("\n", " ") + .replace(", Jr", jr_placeholder) + .rstrip().removesuffix(",")) + for author_email in data.split(", "): + if ' <' in author_email: + author, email = author_email.removesuffix(">").split(" <") + else: + author, email = author_email, "" -def _parse_author(data: str) -> dict[str, str]: - """Return a mapping of author names to emails.""" + author = author.strip() + if author == "": + raise ValueError("Name is empty!") - author_items = [] - for regex in (author_angled, author_paren, author_simple): - for match in regex.finditer(data): - # Watch out for suffixes like 'Jr.' when they are comma-separated - # from the name and thus cause issues when *all* names are only - # separated by commas. - match_dict = match.groupdict() - author = match_dict["author"] - if not author.partition(" ")[1] and author.endswith("."): - prev_author = author_items.pop() - author = ", ".join([prev_author, author]) - if "email" not in match_dict: - email = "" - else: - email = match_dict["email"] - - author = author.strip() - if not author: - raise ValueError("Name is empty!") - - author_items.append((author, email.lower().strip())) - - # If authors were found then stop searching as only expect one - # style of author citation. - if author_items: - break - return dict(author_items) + author = author.replace(jr_placeholder, ", Jr") + email = email.lower() + author_list.append(_Author(author, email)) + return author_list diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 043337a77..02af0c8bd 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -2,7 +2,6 @@ from __future__ import annotations -import datetime as dt from typing import TYPE_CHECKING import unicodedata @@ -29,11 +28,10 @@ from pep_sphinx_extensions.pep_zero_generator.errors import PEPError if TYPE_CHECKING: from pep_sphinx_extensions.pep_zero_generator.parser import PEP -HEADER = f"""\ +HEADER = """\ PEP: 0 Title: Index of Python Enhancement Proposals (PEPs) -Last-Modified: {dt.date.today()} -Author: python-dev +Author: The PEP Editors Status: Active Type: Informational Content-Type: text/x-rst @@ -241,7 +239,7 @@ class PEPZeroWriter: self.emit_newline() self.emit_newline() - pep0_string = "\n".join([str(s) for s in self.output]) + pep0_string = "\n".join(map(str, self.output)) return pep0_string @@ -295,24 +293,24 @@ def _classify_peps(peps: list[PEP]) -> tuple[list[PEP], ...]: def _verify_email_addresses(peps: list[PEP]) -> dict[str, str]: authors_dict: dict[str, set[str]] = {} for pep in peps: - for author, email in pep.authors.items(): + for author in pep.authors: # If this is the first time we have come across an author, add them. - if author not in authors_dict: - authors_dict[author] = set() + if author.full_name not in authors_dict: + authors_dict[author.full_name] = set() # If the new email is an empty string, move on. - if not email: + if not author.email: continue # If the email has not been seen, add it to the list. - authors_dict[author].add(email) + authors_dict[author.full_name].add(author.email) valid_authors_dict: dict[str, str] = {} too_many_emails: list[tuple[str, set[str]]] = [] - for name, emails in authors_dict.items(): + for full_name, emails in authors_dict.items(): if len(emails) > 1: - too_many_emails.append((name, emails)) + too_many_emails.append((full_name, emails)) else: - valid_authors_dict[name] = next(iter(emails), "") + valid_authors_dict[full_name] = next(iter(emails), "") if too_many_emails: err_output = [] for author, emails in too_many_emails: diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index 4950acbb1..2cba74df1 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -17,7 +17,7 @@ from pep_sphinx_extensions.pep_zero_generator.constants import ( TYPE_PROCESS, TYPE_STANDARDS, ) -from pep_sphinx_extensions.pep_zero_generator.errors import PEPError +from pep_sphinx_extensions.pep_zero_generator.parser import _Author def test_pep_repr(): @@ -56,27 +56,15 @@ def test_pep_details(monkeypatch): [ ( "First Last ", - {"First Last": "user@example.com"}, - ), - ( - "First Last < user@example.com >", - {"First Last": "user@example.com"}, + [_Author(full_name="First Last", email="user@example.com")], ), ( "First Last", - {"First Last": ""}, - ), - ( - "user@example.com (First Last)", - {"First Last": "user@example.com"}, - ), - ( - "user@example.com ( First Last )", - {"First Last": "user@example.com"}, + [_Author(full_name="First Last", email="")], ), pytest.param( "First Last ", - {"First Last": "user@example.com"}, + [_Author(full_name="First Last", email="user@example.com")], marks=pytest.mark.xfail, ), pytest.param( @@ -87,21 +75,16 @@ def test_pep_details(monkeypatch): ], ) def test_parse_authors(test_input, expected): - # Arrange - dummy_object = parser.PEP(Path("pep-0160.txt")) - # Act - out = parser._parse_authors(dummy_object, test_input) + out = parser._parse_author(test_input) # Assert assert out == expected def test_parse_authors_invalid(): - pep = parser.PEP(Path("pep-0008.txt")) - - with pytest.raises(PEPError, match="no authors found"): - parser._parse_authors(pep, "") + with pytest.raises(ValueError, match="Name is empty!"): + assert parser._parse_author("") @pytest.mark.parametrize( From 52b311ff8b3a8a4a21607f151c858e52d7bdbaad Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:26:09 +0100 Subject: [PATCH 029/173] PEP 0: Remove unneeded import (#3341) --- pep_sphinx_extensions/pep_zero_generator/parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pep_sphinx_extensions/pep_zero_generator/parser.py b/pep_sphinx_extensions/pep_zero_generator/parser.py index 96b4e9aba..193186c74 100644 --- a/pep_sphinx_extensions/pep_zero_generator/parser.py +++ b/pep_sphinx_extensions/pep_zero_generator/parser.py @@ -5,7 +5,6 @@ from __future__ import annotations import dataclasses from email.parser import HeaderParser from pathlib import Path -import re from pep_sphinx_extensions.pep_zero_generator.constants import ACTIVE_ALLOWED from pep_sphinx_extensions.pep_zero_generator.constants import HIDE_STATUS From e906b6a1bbb1b89fd48a6b7f87a15ec29f1d448e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:51:46 +0100 Subject: [PATCH 030/173] PEP 0: Set consistent table column widths (#3339) --- pep_sphinx_extensions/pep_theme/static/style.css | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css index f3c7cb16d..70e1cbf08 100644 --- a/pep_sphinx_extensions/pep_theme/static/style.css +++ b/pep_sphinx_extensions/pep_theme/static/style.css @@ -230,6 +230,22 @@ table th + th, table td + td { border-left: 1px solid var(--colour-background-accent-strong); } +/* Common column widths for PEP status tables */ +table.pep-zero-table tr td:nth-child(1) { + width: 5.5%; +} +table.pep-zero-table tr td:nth-child(2) { + width: 6.5%; +} +table.pep-zero-table tr td:nth-child(3), +table.pep-zero-table tr td:nth-child(4){ + width: 44%; +} +/* Authors & Sponsors table */ +#authors-owners table td, +#authors-owners table th { + width: 50%; +} /* Breadcrumbs rules */ section#pep-page-section > header { From e6412ac9657c84ac35a8e61ef6c8ad76ea34eb3d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:37:19 +0100 Subject: [PATCH 031/173] PEP 201: Resolve dangling hyphens (#3342) --- pep-0201.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0201.txt b/pep-0201.txt index 71454d9ae..7b1c77af3 100644 --- a/pep-0201.txt +++ b/pep-0201.txt @@ -46,8 +46,8 @@ Lockstep For-Loops Lockstep for-loops are non-nested iterations over two or more sequences, such that at each pass through the loop, one element from each sequence is taken to compose the target. This behavior can -already be accomplished in Python through the use of the map() built- -in function:: +already be accomplished in Python through the use of the map() built-in +function:: >>> a = (1, 2, 3) >>> b = (4, 5, 6) From aaac2aff262f8d29d3b9055c84454114427805d2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:38:24 +0100 Subject: [PATCH 032/173] PEP 205: Resolve dangling hyphens (#3343) --- pep-0205.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0205.txt b/pep-0205.txt index d746d7b02..e16c2d3dc 100644 --- a/pep-0205.txt +++ b/pep-0205.txt @@ -185,8 +185,8 @@ Implementation Strategy ======================= The implementation of weak references will include a list of -reference containers that must be cleared for each weakly- -referencable object. If the reference is from a weak dictionary, +reference containers that must be cleared for each weakly-referencable +object. If the reference is from a weak dictionary, the dictionary entry is cleared first. Then, any associated callback is called with the object passed as a parameter. Once all callbacks have been called, the object is finalized and From e8715f849dd4b2d582583378255f253b8bc788d6 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:38:53 +0100 Subject: [PATCH 033/173] PEP 209: Resolve dangling hyphens (#3344) --- pep-0209.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pep-0209.txt b/pep-0209.txt index f3ffd2f93..c91a15f0a 100644 --- a/pep-0209.txt +++ b/pep-0209.txt @@ -12,9 +12,9 @@ Post-History: Abstract ======== -This PEP proposes a redesign and re-implementation of the multi- -dimensional array module, Numeric, to make it easier to add new -features and functionality to the module. Aspects of Numeric 2 +This PEP proposes a redesign and re-implementation of the +multi-dimensional array module, Numeric, to make it easier to add +new features and functionality to the module. Aspects of Numeric 2 that will receive special attention are efficient access to arrays exceeding a gigabyte in size and composed of inhomogeneous data structures or records. The proposed design uses four Python @@ -128,8 +128,8 @@ Some planned features are: automatically handle alignment and representational issues when data is accessed or operated on. There are two approaches to implementing records; as either a derived array - class or a special array type, depending on your point-of- - view. We defer this discussion to the Open Issues section. + class or a special array type, depending on your point-of-view. + We defer this discussion to the Open Issues section. 2. Additional array types @@ -265,8 +265,8 @@ The design of Numeric 2 has four primary classes: _ufunc.compute(slice, data, func, swap, conv) The 'func' argument is a CFuncObject, while the 'swap' and 'conv' - arguments are lists of CFuncObjects for those arrays needing pre- - or post-processing, otherwise None is used. The data argument is + arguments are lists of CFuncObjects for those arrays needing pre- or + post-processing, otherwise None is used. The data argument is a list of buffer objects, and the slice argument gives the number of iterations for each dimension along with the buffer offset and step size for each array and each dimension. From 97df1d203943dbf13857c9681406f5c3fbe4c1eb Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:39:22 +0100 Subject: [PATCH 034/173] PEP 235: Resolve dangling hyphens (#3345) --- pep-0235.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0235.txt b/pep-0235.txt index f152caa9c..d5a374afa 100644 --- a/pep-0235.txt +++ b/pep-0235.txt @@ -125,8 +125,8 @@ A. If the ``PYTHONCASEOK`` environment variable exists, same as B. Else search ``sys.path`` for the first case-sensitive match; raise ``ImportError`` if none found. -#B is the same rule as is used on Unix, so this will improve cross- -platform portability. That's good. #B is also the rule the Mac +#B is the same rule as is used on Unix, so this will improve +cross-platform portability. That's good. #B is also the rule the Mac and Cygwin folks want (and wanted enough to implement themselves, multiple times, which is a powerful argument in PythonLand). It can't cause any existing non-exceptional Windows import to fail, From b72f81ff4a246089c50d92bf79cb11c05966a162 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:39:51 +0100 Subject: [PATCH 035/173] PEP 249: Resolve dangling hyphens (#3346) --- pep-0249.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0249.txt b/pep-0249.txt index 629a8ba89..d8a409cc5 100644 --- a/pep-0249.txt +++ b/pep-0249.txt @@ -938,8 +938,8 @@ Cursor\ `.lastrowid`_ Connection\ `.autocommit`_ Attribute to query and set the autocommit mode of the connection. - Return ``True`` if the connection is operating in autocommit (non- - transactional) mode. Return ``False`` if the connection is + Return ``True`` if the connection is operating in autocommit + (non-transactional) mode. Return ``False`` if the connection is operating in manual commit (transactional) mode. Setting the attribute to ``True`` or ``False`` adjusts the From 8b7a3464da8b3feddb46bcc1cbd322024d951024 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:40:09 +0100 Subject: [PATCH 036/173] PEP 333: Resolve dangling hyphens (#3347) --- pep-0333.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0333.txt b/pep-0333.txt index d0c6e8377..e57f89254 100644 --- a/pep-0333.txt +++ b/pep-0333.txt @@ -596,9 +596,9 @@ Variable Value ``wsgi.input`` An input stream (file-like object) from which the HTTP request body can be read. (The server or gateway may perform reads on-demand as - requested by the application, or it may pre- - read the client's request body and buffer it - in-memory or on disk, or use any other + requested by the application, or it may + pre-read the client's request body and buffer + it in-memory or on disk, or use any other technique for providing such an input stream, according to its preference.) @@ -1341,8 +1341,8 @@ use only language features available in the target version, use Optional Platform-Specific File Handling ---------------------------------------- -Some operating environments provide special high-performance file- -transmission facilities, such as the Unix ``sendfile()`` call. +Some operating environments provide special high-performance +file-transmission facilities, such as the Unix ``sendfile()`` call. Servers and gateways **may** expose this functionality via an optional ``wsgi.file_wrapper`` key in the ``environ``. An application **may** use this "file wrapper" to convert a file or file-like object From 043306b1f70ce50340bc165d8ef66712b2bed5f1 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:40:48 +0100 Subject: [PATCH 037/173] PEP 344: Resolve dangling hyphens (#3348) --- pep-0344.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0344.txt b/pep-0344.txt index c2c4f0efb..de5fc298d 100644 --- a/pep-0344.txt +++ b/pep-0344.txt @@ -85,8 +85,8 @@ exception, the exception must be retained implicitly. To support intentional translation of an exception, there must be a way to chain exceptions explicitly. This PEP addresses both. -Several attribute names for chained exceptions have been suggested on Python- -Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``, +Several attribute names for chained exceptions have been suggested on +Python-Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``, ``chain``, ``chainedexc``, ``xc_chain``, ``excprev``, ``previous`` and ``precursor``. For an explicitly chained exception, this PEP suggests ``__cause__`` because of its specific meaning. For an implicitly chained From 3bbf470f3f86e585d680c7f049ad7111f5cd33fd Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:41:38 +0100 Subject: [PATCH 038/173] PEP 367: Resolve dangling hyphens (#3349) --- pep-0367.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pep-0367.txt b/pep-0367.txt index 89ca58778..168db7a1e 100644 --- a/pep-0367.txt +++ b/pep-0367.txt @@ -122,10 +122,10 @@ Should ``super`` actually become a keyword? With this proposal, ``super`` would become a keyword to the same extent that ``None`` is a keyword. It is possible that further restricting the ``super`` -name may simplify implementation, however some are against the actual keyword- -ization of super. The simplest solution is often the correct solution and the -simplest solution may well not be adding additional keywords to the language -when they are not needed. Still, it may solve other open issues. +name may simplify implementation, however some are against the actual +keyword-ization of super. The simplest solution is often the correct solution +and the simplest solution may well not be adding additional keywords to the +language when they are not needed. Still, it may solve other open issues. Closed Issues @@ -513,10 +513,10 @@ super(self, \*args) or __super__(self, \*args) This solution only solves the problem of the type indication, does not handle differently named super methods, and is explicit about the name of the instance. It is less flexible without being able to enacted on other method -names, in cases where that is needed. One use case this fails is where a base- -class has a factory classmethod and a subclass has two factory classmethods, -both of which needing to properly make super calls to the one in the base- -class. +names, in cases where that is needed. One use case this fails is where a +base-class has a factory classmethod and a subclass has two factory +classmethods, both of which needing to properly make super calls to the one +in the base-class. super.foo(self, \*args) ----------------------- From 938f17e4cd43a1c36d02c2ea844206335d4dfb19 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:41:52 +0100 Subject: [PATCH 039/173] PEP 374: Resolve dangling hyphens (#3350) --- pep-0374.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0374.txt b/pep-0374.txt index f6228d857..49c944e8f 100644 --- a/pep-0374.txt +++ b/pep-0374.txt @@ -274,8 +274,8 @@ This identity may be associated with a full name. All of the DVCSs will query the system to get some approximation to this information, but that may not be what you want. They also -support setting this information on a per-user basis, and on a per- -project basis. Convenience commands to set these attributes vary, +support setting this information on a per-user basis, and on a +per-project basis. Convenience commands to set these attributes vary, but all allow direct editing of configuration files. Some VCSs support end-of-line (EOL) conversions on checkout/checkin. From 7dd8829bcfce80b0ce7a1ad9b20a2de03909ef91 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:42:17 +0100 Subject: [PATCH 040/173] PEP 451: Resolve dangling hyphens (#3352) --- pep-0451.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0451.txt b/pep-0451.txt index f4373b3e7..6e673e92a 100644 --- a/pep-0451.txt +++ b/pep-0451.txt @@ -678,9 +678,9 @@ Other than adding ``__spec__``, none of the import-related module attributes will be changed or deprecated, though some of them could be; any such deprecation can wait until Python 4. -A module's spec will not be kept in sync with the corresponding import- -related attributes. Though they may differ, in practice they will -typically be the same. +A module's spec will not be kept in sync with the corresponding +import-related attributes. Though they may differ, in practice they +will typically be the same. One notable exception is that case where a module is run as a script by using the ``-m`` flag. In that case ``module.__spec__.name`` will @@ -716,8 +716,8 @@ Adding yet another similar method to loaders is a case of practicality. find_module() could be changed to return specs instead of loaders. This is tempting because the import APIs have suffered enough, especially considering PathEntryFinder.find_loader() was just -added in Python 3.3. However, the extra complexity and a less-than- -explicit method name aren't worth it. +added in Python 3.3. However, the extra complexity and a +less-than-explicit method name aren't worth it. The "target" parameter of find_spec() ------------------------------------- From 0516a43ea29ffbd722dc960a86b647fb3f926f98 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:42:35 +0100 Subject: [PATCH 041/173] PEP 439: Resolve dangling hyphens (#3351) --- pep-0439.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0439.txt b/pep-0439.txt index d354c3da4..b07a72043 100644 --- a/pep-0439.txt +++ b/pep-0439.txt @@ -189,8 +189,8 @@ Implementation ============== The changes to pip required by this PEP are being tracked in that project's -issue tracker [2]_. Most notably, the addition of --bootstrap and --bootstrap- -to-system to the pip command-line. +issue tracker [2]_. Most notably, the addition of --bootstrap and +--bootstrap-to-system to the pip command-line. It would be preferable that the pip and setuptools projects distribute a wheel format download. From 5b5d47732f0f564d1c8d76c4f495202a5ca74e6d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:42:53 +0100 Subject: [PATCH 042/173] PEP 465: Resolve dangling hyphens (#3353) --- pep-0465.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0465.txt b/pep-0465.txt index 5b38dd3c3..79f3ec705 100644 --- a/pep-0465.txt +++ b/pep-0465.txt @@ -388,8 +388,8 @@ real-world code (i.e., all the code on Github). We checked for imports of several popular stdlib modules, a variety of numerically oriented modules, and various other extremely high-profile modules like django and lxml (the latter of which is the #1 most downloaded -package on PyPI). Starred lines indicate packages which export array- -or matrix-like objects which will adopt ``@`` if this PEP is +package on PyPI). Starred lines indicate packages which export +array- or matrix-like objects which will adopt ``@`` if this PEP is approved:: Count of Python source files on Github matching given search terms From 471d9096c6f122899dafa25814d60cf08635ba0c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:43:33 +0100 Subject: [PATCH 043/173] PEP 471: Resolve dangling hyphens (#3354) --- pep-0471.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0471.txt b/pep-0471.txt index e48961f49..3a02fda57 100644 --- a/pep-0471.txt +++ b/pep-0471.txt @@ -46,8 +46,8 @@ better than this.) In practice, removing all those extra system calls makes ``os.walk()`` about **8-9 times as fast on Windows**, and about **2-3 times as fast -on POSIX systems**. So we're not talking about micro- -optimizations. See more `benchmarks here`_. +on POSIX systems**. So we're not talking about +micro-optimizations. See more `benchmarks here`_. .. _`benchmarks here`: https://github.com/benhoyt/scandir#benchmarks From 1e6221e7fe6b0235a243e5420310ee6c905b2b49 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:43:45 +0100 Subject: [PATCH 044/173] PEP 479: Resolve dangling hyphens (#3355) --- pep-0479.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt index 44f4d75ae..e5cbe823e 100644 --- a/pep-0479.txt +++ b/pep-0479.txt @@ -57,9 +57,9 @@ problem.) This is particularly pernicious in combination with the ``yield from`` construct of :pep:`380`, as it breaks the abstraction that a subgenerator may be factored out of a generator. That PEP notes this -limitation, but notes that "use cases for these [are] rare to non- -existent". Unfortunately while intentional use is rare, it is easy to -stumble on these cases by accident:: +limitation, but notes that "use cases for these [are] rare to +non-existent". Unfortunately while intentional use is rare, it is +easy to stumble on these cases by accident:: import contextlib From 20b605caf2bc279bb1765e9017ec84095847957b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:44:08 +0100 Subject: [PATCH 045/173] PEP 492: Resolve dangling hyphens (#3356) --- pep-0492.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pep-0492.txt b/pep-0492.txt index 2905a2576..2bab371de 100644 --- a/pep-0492.txt +++ b/pep-0492.txt @@ -173,8 +173,8 @@ in asyncio and *native coroutines* introduced by this PEP:: data = yield from read_data(db) ... -The function applies ``CO_ITERABLE_COROUTINE`` flag to generator- -function's code object, making it return a *coroutine* object. +The function applies ``CO_ITERABLE_COROUTINE`` flag to +generator-function's code object, making it return a *coroutine* object. If ``fn`` is not a *generator function*, it is wrapped. If it returns a *generator*, it will be wrapped in an *awaitable* proxy object @@ -996,8 +996,8 @@ Differences from this proposal: coroutines with ``yield`` or ``async yield`` expressions -- we wouldn't need a ``cocall`` keyword to call them. So we'll end up having ``__cocall__`` and no ``__call__`` for regular coroutines, - and having ``__call__`` and no ``__cocall__`` for coroutine- - generators. + and having ``__call__`` and no ``__cocall__`` for + coroutine-generators. 6. Requiring parentheses grammatically also introduces a whole lot of new problems. @@ -1316,8 +1316,8 @@ List of high-level changes and new protocols associated protocol with ``__aenter__`` and ``__aexit__`` methods. 4. New syntax for asynchronous iteration: ``async for``. And - associated protocol with ``__aiter__``, ``__aexit__`` and new built- - in exception ``StopAsyncIteration``. New ``tp_as_async.am_aiter`` + associated protocol with ``__aiter__``, ``__aexit__`` and new built-in + exception ``StopAsyncIteration``. New ``tp_as_async.am_aiter`` and ``tp_as_async.am_anext`` slots in ``PyTypeObject``. 5. New AST nodes: ``AsyncFunctionDef``, ``AsyncFor``, ``AsyncWith``, From ee2f31e163ce2250a579e84b4af5060f1824213f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:44:27 +0100 Subject: [PATCH 046/173] PEP 512: Resolve dangling hyphens (#3357) --- pep-0512.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0512.txt b/pep-0512.txt index e5c5917f2..ad6ffdce3 100644 --- a/pep-0512.txt +++ b/pep-0512.txt @@ -262,8 +262,8 @@ Requirements for the cpython Repository Obviously the most active and important repository currently hosted at hg.python.org [#h.p.o]_ is the cpython -repository [#cpython-repo]_. Because of its importance and high- -frequency use, it requires more tooling before being moved to GitHub +repository [#cpython-repo]_. Because of its importance and +high-frequency use, it requires more tooling before being moved to GitHub compared to the other repositories mentioned in this PEP. From eaa4742315610d974be497d12121ab00826f618d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:44:48 +0100 Subject: [PATCH 047/173] PEP 520: Resolve dangling hyphens (#3358) --- pep-0520.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pep-0520.txt b/pep-0520.txt index d3090f0ef..978456b90 100644 --- a/pep-0520.txt +++ b/pep-0520.txt @@ -37,8 +37,8 @@ This allows introspection of the original definition order, e.g. by class decorators. Additionally, this PEP requires that the default class definition -namespace be ordered (e.g. ``OrderedDict``) by default. The long- -lived class namespace (``__dict__``) will remain a ``dict``. +namespace be ordered (e.g. ``OrderedDict``) by default. The +long-lived class namespace (``__dict__``) will remain a ``dict``. Motivation @@ -185,10 +185,10 @@ the well-worn precedent found in Python. Per Guido:: Also, note that a writeable ``__definition_order__`` allows dynamically created classes (e.g. by Cython) to still have ``__definition_order__`` -properly set. That could certainly be handled through specific class- -creation tools, such as ``type()`` or the C-API, without the need to -lose the semantics of a read-only attribute. However, with a writeable -attribute it's a moot point. +properly set. That could certainly be handled through specific +class-creation tools, such as ``type()`` or the C-API, without the need +to lose the semantics of a read-only attribute. However, with a +writeable attribute it's a moot point. Why not "__attribute_order__"? From f5b8e92ae881e0570a72f0b3a0ff226d399bbc5f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:45:31 +0100 Subject: [PATCH 048/173] PEP 3101: Resolve dangling hyphens (#3360) --- pep-3101.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-3101.txt b/pep-3101.txt index 6b4fcc90e..9267d17cb 100644 --- a/pep-3101.txt +++ b/pep-3101.txt @@ -310,10 +310,10 @@ The available integer presentation types are:: Unicode character before printing. 'd' - Decimal Integer. Outputs the number in base 10. 'o' - Octal format. Outputs the number in base 8. - 'x' - Hex format. Outputs the number in base 16, using lower- - case letters for the digits above 9. - 'X' - Hex format. Outputs the number in base 16, using upper- - case letters for the digits above 9. + 'x' - Hex format. Outputs the number in base 16, using + lower-case letters for the digits above 9. + 'X' - Hex format. Outputs the number in base 16, using + upper-case letters for the digits above 9. 'n' - Number. This is the same as 'd', except that it uses the current locale setting to insert the appropriate number separator characters. From be43f82d93c0e93f16fbe6505d730e491b378264 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:46:09 +0100 Subject: [PATCH 049/173] PEP 3115: Resolve dangling hyphens (#3361) --- pep-3115.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-3115.txt b/pep-3115.txt index 57d5e64f4..a8c2560dc 100644 --- a/pep-3115.txt +++ b/pep-3115.txt @@ -137,8 +137,8 @@ an arbitrary length list of base classes. After the base classes, there may be one or more keyword arguments, one of which can be *metaclass*. Note that the *metaclass* argument is not included in *kwargs*, since it is filtered out by the normal parameter -assignment algorithm. (Note also that *metaclass* is a keyword- -only argument as per :pep:`3102`.) +assignment algorithm. (Note also that *metaclass* is a +keyword-only argument as per :pep:`3102`.) Even though ``__prepare__`` is not required, the default metaclass ('type') implements it, for the convenience of subclasses calling From 16c5f92aba2a0205191094e2d206c0ca971a1ae3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:46:41 +0100 Subject: [PATCH 050/173] PEP 3124: Resolve dangling hyphens (#3362) --- pep-3124.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-3124.txt b/pep-3124.txt index a3500ba5c..e755609a2 100644 --- a/pep-3124.txt +++ b/pep-3124.txt @@ -959,8 +959,8 @@ about. As a result, the vast majority of overloads can be found adjacent to either the function being overloaded, or to a newly-defined type for -which the overload is adding support. Thus, overloads are highly- -discoverable in the common case, as you are either looking at the +which the overload is adding support. Thus, overloads are +highly-discoverable in the common case, as you are either looking at the function or the type, or both. It is only in rather infrequent cases that one will have overloads in a From 59ad1216c0558edd028fdf1989f2fba99de62302 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:47:23 +0100 Subject: [PATCH 051/173] PEP 3135: Resolve dangling hyphens (#3363) --- pep-3135.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-3135.txt b/pep-3135.txt index da66891b1..cbd13aa8b 100644 --- a/pep-3135.txt +++ b/pep-3135.txt @@ -165,10 +165,10 @@ super(self, \*args) or __super__(self, \*args) This solution only solves the problem of the type indication, does not handle differently named super methods, and is explicit about the name of the instance. It is less flexible without being able to enacted on other method -names, in cases where that is needed. One use case this fails is where a base- -class has a factory classmethod and a subclass has two factory classmethods, -both of which needing to properly make super calls to the one in the base- -class. +names, in cases where that is needed. One use case this fails is where a +base-class has a factory classmethod and a subclass has two factory +classmethods,both of which needing to properly make super calls to the one +in the base-class. super.foo(self, \*args) ----------------------- From f4fbfad07d7ebb0f71a76eeb13e2d46ee4841239 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:47:26 +0100 Subject: [PATCH 052/173] PEP 3333: Resolve dangling hyphens (#3364) --- pep-3333.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-3333.txt b/pep-3333.txt index 35e097936..4ec70d84f 100644 --- a/pep-3333.txt +++ b/pep-3333.txt @@ -674,9 +674,9 @@ Variable Value ``wsgi.input`` An input stream (file-like object) from which the HTTP request body bytes can be read. (The server or gateway may perform reads on-demand as - requested by the application, or it may pre- - read the client's request body and buffer it - in-memory or on disk, or use any other + requested by the application, or it may + pre-read the client's request body and buffer + it in-memory or on disk, or use any other technique for providing such an input stream, according to its preference.) @@ -1455,8 +1455,8 @@ use only language features available in the target version, use Optional Platform-Specific File Handling ---------------------------------------- -Some operating environments provide special high-performance file- -transmission facilities, such as the Unix ``sendfile()`` call. +Some operating environments provide special high-performance +file-transmission facilities, such as the Unix ``sendfile()`` call. Servers and gateways **may** expose this functionality via an optional ``wsgi.file_wrapper`` key in the ``environ``. An application **may** use this "file wrapper" to convert a file or file-like object From 961483467820d60c1ccfbfd22444f1c76691d72e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 19:47:40 +0100 Subject: [PATCH 053/173] PEP 3001: Resolve dangling hyphens (#3359) --- pep-3001.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-3001.txt b/pep-3001.txt index d4fb893c5..08df2138f 100644 --- a/pep-3001.txt +++ b/pep-3001.txt @@ -29,8 +29,8 @@ but are too widely used to be deprecated or removed. Python 3000 is the big occasion to get rid of them. There will have to be a document listing all removed modules, together -with information on possible substitutes or alternatives. This infor- -mation will also have to be provided by the python3warn.py porting +with information on possible substitutes or alternatives. This +information will also have to be provided by the python3warn.py porting helper script mentioned in PEP XXX. From 34022280b9e22c46efb5948f9074c57b86d8ad52 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:17:26 +0100 Subject: [PATCH 054/173] PEP 1: Resolve uses of the default role (#3366) --- pep-0001.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0001.txt b/pep-0001.txt index 5aa9b5394..66da707dc 100644 --- a/pep-0001.txt +++ b/pep-0001.txt @@ -296,7 +296,7 @@ pointing to this new thread. If it is not chosen as the discussion venue, a brief announcement post should be made to the `PEPs category`_ -with at least a link to the rendered PEP and the `Discussions-To` thread +with at least a link to the rendered PEP and the ``Discussions-To`` thread when the draft PEP is committed to the repository and if a major-enough change is made to trigger a new thread. From 10f48f67d855f1dc7fb8bbe89eca29d7ebe56a5b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:18:36 +0100 Subject: [PATCH 055/173] PEP 101: Resolve uses of the default role (#3368) --- pep-0101.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt index b2bbfde93..e877f8958 100644 --- a/pep-0101.txt +++ b/pep-0101.txt @@ -212,7 +212,7 @@ to perform some manual editing steps. within it (called the "release clone" from now on). You can use the same GitHub fork you use for cpython development. Using the standard setup recommended in the Python Developer's Guide, your fork would be referred - to as `origin` and the standard cpython repo as `upstream`. You will + to as ``origin`` and the standard cpython repo as ``upstream``. You will use the branch on your fork to do the release engineering work, including tagging the release, and you will use it to share with the other experts for making the binaries. @@ -302,7 +302,7 @@ to perform some manual editing steps. $ .../release-tools/release.py --tag X.Y.ZaN - This executes a `git tag` command with the `-s` option so that the + This executes a ``git tag`` command with the ``-s`` option so that the release tag in the repo is signed with your gpg key. When prompted choose the private key you use for signing release tarballs etc. @@ -538,7 +538,7 @@ the main repo. do some post-merge cleanup. Check the top-level ``README.rst`` and ``include/patchlevel.h`` files to ensure they now reflect the desired post-release values for on-going development. - The patchlevel should be the release tag with a `+`. + The patchlevel should be the release tag with a ``+``. Also, if you cherry-picked changes from the standard release branch into the release engineering branch for this release, you will now need to manual remove each blurb entry from @@ -546,8 +546,8 @@ the main repo. into the release you are working on since that blurb entry is now captured in the merged x.y.z.rst file for the new release. Otherwise, the blurb entry will appear twice in - the `changelog.html` file, once under `Python next` and again - under `x.y.z`. + the ``changelog.html`` file, once under ``Python next`` and again + under ``x.y.z``. - Review and commit these changes:: @@ -712,19 +712,19 @@ with RevSys.) - If this is a **final** release: - Add the new version to the *Python Documentation by Version* - page `https://www.python.org/doc/versions/` and + page ``https://www.python.org/doc/versions/`` and remove the current version from any 'in development' section. - For X.Y.Z, edit all the previous X.Y releases' page(s) to point to the new release. This includes the content field of the - `Downloads -> Releases` entry for the release:: + ``Downloads -> Releases`` entry for the release:: Note: Python x.y.m has been superseded by `Python x.y.n `_. And, for those releases having separate release page entries (phasing these out?), update those pages as well, - e.g. `download/releases/x.y.z`:: + e.g. ``download/releases/x.y.z``:: Note: Python x.y.m has been superseded by `Python x.y.n `_. @@ -908,8 +908,8 @@ else does them. Some of those tasks include: - Remove the release from the list of "Active Python Releases" on the Downloads page. To do this, log in to the admin page for python.org, navigate to Boxes, - and edit the `downloads-active-releases` entry. Simply strip out the relevant - paragraph of HTML for your release. (You'll probably have to do the `curl -X PURGE` + and edit the ``downloads-active-releases`` entry. Simply strip out the relevant + paragraph of HTML for your release. (You'll probably have to do the ``curl -X PURGE`` trick to purge the cache if you want to confirm you made the change correctly.) - Add retired notice to each release page on python.org for the retired branch. From c946ae0bbb77f13e6c2a00acc2aad1142f16c345 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:18:50 +0100 Subject: [PATCH 056/173] PEP 310: Resolve uses of the default role (#3370) --- pep-0310.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0310.txt b/pep-0310.txt index 09a389711..a327def99 100644 --- a/pep-0310.txt +++ b/pep-0310.txt @@ -238,7 +238,7 @@ could be mentioned here. https://mail.python.org/pipermail/python-dev/2003-August/037795.html .. [3] Thread on python-dev with subject - `[Python-Dev] pre-PEP: Resource-Release Support for Generators` + ``[Python-Dev] pre-PEP: Resource-Release Support for Generators`` starting at https://mail.python.org/pipermail/python-dev/2003-August/037803.html From 0737e8b5cd923b667bd2dd30e25f6856073b813e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:00 +0100 Subject: [PATCH 057/173] PEP 329: Resolve uses of the default role (#3372) --- pep-0329.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pep-0329.txt b/pep-0329.txt index 7b9f99b3c..b59e9c588 100644 --- a/pep-0329.txt +++ b/pep-0329.txt @@ -49,14 +49,14 @@ of performance. There are currently over a hundred instances of ``while 1`` in the library. They were not replaced with the more readable ``while True`` because of performance reasons (the compiler cannot eliminate the test -because `True` is not known to always be a constant). Conversion of +because ``True`` is not known to always be a constant). Conversion of True to a constant will clarify the code while retaining performance. Many other basic Python operations run much slower because of global lookups. In try/except statements, the trapped exceptions are dynamically looked up before testing whether they match. Similarly, simple identity tests such as ``while x is not None`` -require the `None` variable to be re-looked up on every pass. +require the ``None`` variable to be re-looked up on every pass. Builtin lookups are especially egregious because the enclosing global scope must be checked first. These lookup chains devour cache space that is best used elsewhere. @@ -69,7 +69,7 @@ Proposal ======== Add a module called codetweaks.py which contains two functions, -`bind_constants()` and `bind_all()`. The first function performs +``bind_constants()`` and ``bind_all()``. The first function performs constant binding and the second recursively applies it to every function and class in a target module. @@ -80,7 +80,7 @@ the end of the script:: codetweaks.bind_all(sys.modules[__name__]) In addition to binding builtins, there are some modules (like -`sre_compile`) where it also makes sense to bind module variables +``sre_compile``) where it also makes sense to bind module variables as well as builtins into constants. @@ -97,17 +97,17 @@ Questions and Answers Every function has attributes with its bytecodes (the language of the Python virtual machine) and a table of constants. The bind - function scans the bytecodes for a `LOAD_GLOBAL` instruction and + function scans the bytecodes for a ``LOAD_GLOBAL`` instruction and checks to see whether the value is already known. If so, it adds that value to the constants table and replaces the opcode with - `LOAD_CONSTANT`. + ``LOAD_CONSTANT``. 3. When does it work? When a module is imported for the first time, python compiles the bytecode and runs the binding optimization. Subsequent imports just re-use the previous work. Each session repeats this process - (the results are not saved in `pyc` files). + (the results are not saved in ``pyc`` files). 4. How do you know this works? @@ -117,7 +117,7 @@ Questions and Answers 5. What if the module defines a variable shadowing a builtin? This does happen. For instance, True can be redefined at the module - level as `True = (1==1)`. The sample implementation below detects the + level as ``True = (1==1)``. The sample implementation below detects the shadowing and leaves the global lookup unchanged. 6. Are you the first person to recognize that most global lookups are for @@ -130,22 +130,22 @@ Questions and Answers implementations? Either do this before importing a module, or just reload the - module, or disable `codetweaks.py` (it will have a disable flag). + module, or disable ``codetweaks.py`` (it will have a disable flag). 8. How susceptible is this module to changes in Python's byte coding? - It imports `opcode.py` to protect against renumbering. Also, it - uses `LOAD_CONST` and `LOAD_GLOBAL` which are fundamental and have + It imports ``opcode.py`` to protect against renumbering. Also, it + uses ``LOAD_CONST`` and ``LOAD_GLOBAL`` which are fundamental and have been around forever. That notwithstanding, the coding scheme could change and this implementation would have to change along with - modules like `dis` which also rely on the current coding scheme. + modules like ``dis`` which also rely on the current coding scheme. 9. What is the effect on startup time? I could not measure a difference. None of the startup modules are bound except for warnings.py. Also, the binding function is very fast, making just a single pass over the code string in search of - the `LOAD_GLOBAL` opcode. + the ``LOAD_GLOBAL`` opcode. Sample Implementation From 0426040703ca01fdff38ef064ae094c2eb291dd3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:13 +0100 Subject: [PATCH 058/173] PEP 345: Resolve uses of the default role (#3374) --- pep-0345.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0345.txt b/pep-0345.txt index 876f5c0f2..a9a9f359b 100644 --- a/pep-0345.txt +++ b/pep-0345.txt @@ -32,7 +32,7 @@ These fields are "Requires-Python", "Requires-External", "Requires-Dist", "Platform" field. Three new fields were also added: "Maintainer", "Maintainer-email" and "Project-URL". -Last, this new version also adds `environment markers`. +Last, this new version also adds ``environment markers``. Fields ====== @@ -137,7 +137,7 @@ parser. Example:: Description: This project provides powerful math functions - |For example, you can use `sum()` to sum numbers: + |For example, you can use ``sum()`` to sum numbers: | |Example:: | From 2ea7e87926e13756413f5fd28762aaca2e147d04 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:15 +0100 Subject: [PATCH 059/173] PEP 326: Resolve uses of the default role (#3371) --- pep-0326.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0326.txt b/pep-0326.txt index bf5959a8f..20ddc6f12 100644 --- a/pep-0326.txt +++ b/pep-0326.txt @@ -268,7 +268,7 @@ following problem [5]_: and ``B``. Such an algorithm is a 7 line modification to the `DijkstraSP_table`_ -algorithm given above (modified lines prefixed with `*`):: +algorithm given above (modified lines prefixed with ``*``):: def DijkstraSP_table(graph, S, T): table = {} #3 From ea13fde5129e80ad5b363f0bda566d2713bf40b5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:20 +0100 Subject: [PATCH 060/173] PEP 381: Resolve uses of the default role (#3375) --- pep-0381.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pep-0381.txt b/pep-0381.txt index 8f2952b20..6aac3a78c 100644 --- a/pep-0381.txt +++ b/pep-0381.txt @@ -37,8 +37,8 @@ Rationale ========= PyPI is hosting over 6000 projects and is used on a daily basis -by people to build applications. Especially systems like `easy_install` -and `zc.buildout` make intensive usage of PyPI. +by people to build applications. Especially systems like ``easy_install`` +and ``zc.buildout`` make intensive usage of PyPI. For people making intensive use of PyPI, it can act as a single point of failure. People have started to set up some mirrors, both private @@ -74,19 +74,19 @@ last host name. Mirror operators should use a static address, and report planned changes to that address in advance to distutils-sig. -The new mirror also appears at `http://pypi.python.org/mirrors` +The new mirror also appears at ``http://pypi.python.org/mirrors`` which is a human-readable page that gives the list of mirrors. This page also explains how to register a new mirror. Statistics page ::::::::::::::: -PyPI provides statistics on downloads at `/stats`. This page is +PyPI provides statistics on downloads at ``/stats``. This page is calculated daily by PyPI, by reading all mirrors' local stats and summing them. -The stats are presented in daily or monthly files, under `/stats/days` -and `/stats/months`. Each file is a `bzip2` file with these formats: +The stats are presented in daily or monthly files, under ``/stats/days`` +and ``/stats/months``. Each file is a ``bzip2`` file with these formats: - YYYY-MM-DD.bz2 for daily files - YYYY-MM.bz2 for monthly files @@ -180,7 +180,7 @@ that represents the last synchronisation date the mirror maintains. The date is provided in GMT time, using the ISO 8601 format [#iso8601]_. Each mirror will be responsible to maintain its last modified date. -This page must be located at : `/last-modified` and must be a +This page must be located at : ``/last-modified`` and must be a text/plain page. Local statistics @@ -192,7 +192,7 @@ display the grand total. These statistics are in CSV-like form, with a header in the first line. It needs to obey :pep:`305`. Basically, it should be -readable by Python's `csv` module. +readable by Python's ``csv`` module. The fields in this file are: @@ -209,26 +209,26 @@ The content will look like this:: ... The counting starts the day the mirror is launched, and there is one -file per day, compressed using the `bzip2` format. Each file is named -like the day. For example, `2008-11-06.bz2` is the file for the 6th of +file per day, compressed using the ``bzip2`` format. Each file is named +like the day. For example, ``2008-11-06.bz2`` is the file for the 6th of November 2008. -They are then provided in a folder called `days`. For example: +They are then provided in a folder called ``days``. For example: - /local-stats/days/2008-11-06.bz2 - /local-stats/days/2008-11-07.bz2 - /local-stats/days/2008-11-08.bz2 -This page must be located at `/local-stats`. +This page must be located at ``/local-stats``. How a mirror should synchronize with PyPI ========================================= -A mirroring protocol called `Simple Index` was described and +A mirroring protocol called ``Simple Index`` was described and implemented by Martin v. Loewis and Jim Fulton, based on how -`easy_install` works. This section synthesizes it and gives a few -relevant links, plus a small part about `User-Agent`. +``easy_install`` works. This section synthesizes it and gives a few +relevant links, plus a small part about ``User-Agent``. The mirroring protocol :::::::::::::::::::::: @@ -267,7 +267,7 @@ How a client can use PyPI and its mirrors ::::::::::::::::::::::::::::::::::::::::: Clients that are browsing PyPI should be able to use alternative -mirrors, by getting the list of the mirrors using `last.pypi.python.org`. +mirrors, by getting the list of the mirrors using ``last.pypi.python.org``. Code example:: @@ -309,7 +309,7 @@ runs their own server where people might get the project package. However, it is strongly encouraged that a public package index follows PyPI and Distutils protocols. -In other words, the `register` and `upload` command should be +In other words, the ``register`` and ``upload`` command should be compatible with any package index server out there. Software that are compatible with PyPI and Distutils so far: From eb75dbcb15efc0183a10e5de99453af1ee6418dc Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:28 +0100 Subject: [PATCH 061/173] PEP 386: Resolve uses of the default role (#3376) --- pep-0386.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pep-0386.txt b/pep-0386.txt index aa7f964cb..6197dbc8a 100644 --- a/pep-0386.txt +++ b/pep-0386.txt @@ -25,9 +25,9 @@ Motivation In Python there are no real restrictions yet on how a project should manage its versions, and how they should be incremented. -Distutils provides a `version` distribution meta-data field but it is freeform and +Distutils provides a ``version`` distribution meta-data field but it is freeform and current users, such as PyPI usually consider the latest version pushed as the -`latest` one, regardless of the expected semantics. +``latest`` one, regardless of the expected semantics. Distutils will soon extend its capabilities to allow distributions to express a dependency on other distributions through the ``Requires-Dist`` metadata field @@ -271,8 +271,8 @@ a particular package was using and to provide tools on top of PyPI. Distutils classes are not really used in Python projects, but the Setuptools function is quite widespread because it's used by tools like -`easy_install` [#ezinstall]_, `pip` [#pip]_ or `zc.buildout` [#zc.buildout]_ -to install dependencies of a given project. +``easy_install`` [#ezinstall]_, ``pip`` [#pip]_ or ``zc.buildout`` +[#zc.buildout]_ to install dependencies of a given project. While Setuptools *does* provide a mechanism for comparing/sorting versions, it is much preferable if the versioning spec is such that a human can make a @@ -292,7 +292,7 @@ The new versioning algorithm During Pycon, members of the Python, Ubuntu and Fedora community worked on a version standard that would be acceptable for everyone. -It's currently called `verlib` and a prototype lives at [#prototype]_. +It's currently called ``verlib`` and a prototype lives at [#prototype]_. The pseudo-format supported is:: @@ -362,9 +362,9 @@ Note that ``c`` is the preferred marker for third party projects. NormalizedVersion ----------------- -The `NormalizedVersion` class is used to hold a version and to compare it with -others. It takes a string as an argument, that contains the representation of -the version:: +The ``NormalizedVersion`` class is used to hold a version and to compare it +with others. It takes a string as an argument, that contains the representation +of the version:: >>> from verlib import NormalizedVersion >>> version = NormalizedVersion('1.0') From ba1a43836f49fb1c109a0018afc6eaad339daf96 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:36 +0100 Subject: [PATCH 062/173] PEP 523: Resolve uses of the default role (#3377) --- pep-0523.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0523.txt b/pep-0523.txt index 2afecd3f0..4ba6fb4b8 100644 --- a/pep-0523.txt +++ b/pep-0523.txt @@ -323,7 +323,7 @@ mutable. The thinking seemed to be that having a field that was mutated after the creation of the code object made the object seem mutable, even though no other aspect of code objects changed. -The view of this PEP is that the `co_extra` field doesn't change the +The view of this PEP is that the ``co_extra`` field doesn't change the fact that code objects are immutable. The field is specified in this PEP to not contain information required to make the code object usable, making it more of a caching field. It could be viewed as From 1b262f6056289a8725b8a98747c2c40eb7c14563 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:39 +0100 Subject: [PATCH 063/173] PEP 542: Resolve uses of the default role (#3380) --- pep-0542.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0542.txt b/pep-0542.txt index b7a7216a3..3359e8e45 100644 --- a/pep-0542.txt +++ b/pep-0542.txt @@ -134,7 +134,7 @@ Similar to how decorators are syntastic sugar:: Implementation ============== -The `__name__` would follow the principles of a normal function:: +The ``__name__`` would follow the principles of a normal function:: class MyClass: def my_function1(self): @@ -146,7 +146,7 @@ The `__name__` would follow the principles of a normal function:: assert my_function1.__name__ == 'my_function1' assert my_function2.__name__ == 'my_function2' -The grammar would use `dotted_name` to support chaining of attributes:: +The grammar would use ``dotted_name`` to support chaining of attributes:: def Person.name.fset(self, value): self._name = value From af6e2eded10f939c99462649c363d3bc8518019c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:49 +0100 Subject: [PATCH 064/173] PEP 545: Resolve uses of the default role (#3381) --- pep-0545.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0545.txt b/pep-0545.txt index e1890acb2..d5b475436 100644 --- a/pep-0545.txt +++ b/pep-0545.txt @@ -134,9 +134,9 @@ sometimes almost impossible when already registered, this solution should be avoided. Using subdomains like "es.docs.python.org" or "docs.es.python.org" is -possible but confusing ("is it `es.docs.python.org` or -`docs.es.python.org`?"). Hyphens in subdomains like -`pt-br.doc.python.org` is uncommon and SEOMoz [23]_ correlated the +possible but confusing ("is it ``es.docs.python.org`` or +``docs.es.python.org``?"). Hyphens in subdomains like +``pt-br.doc.python.org`` is uncommon and SEOMoz [23]_ correlated the presence of hyphens as a negative factor. Usage of underscores in subdomain is prohibited by the :rfc:`1123`, section 2.1. Finally, using subdomains means creating TLS certificates for each From 7fdc166f8211abff17404dfcba17d0e300976f5c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:19:56 +0100 Subject: [PATCH 065/173] PEP 534: Resolve uses of the default role (#3379) --- pep-0534.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0534.txt b/pep-0534.txt index 4959943d5..a572180fd 100644 --- a/pep-0534.txt +++ b/pep-0534.txt @@ -326,7 +326,7 @@ a proper, distro-specific way to install missing standard library modules upon encountering a `ModuleNotFoundError`_. Some downstream distributors are already using this method of patching -`sys.excepthook` to integrate with platform crash reporting mechanisms. +``sys.excepthook`` to integrate with platform crash reporting mechanisms. .. _`site.py`: https://docs.python.org/3.7/library/site.html .. _`sitecustomize.py`: `site.py`_ From 461e931fb56ce49000cf3004f1748ce5c1197b75 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:20:07 +0100 Subject: [PATCH 066/173] PEP 531: Resolve uses of the default role (#3378) --- pep-0531.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0531.txt b/pep-0531.txt index 0f8c76cd6..13be86600 100644 --- a/pep-0531.txt +++ b/pep-0531.txt @@ -572,7 +572,7 @@ protocol definition significantly more complex, both to define and to use: a singleton tuple containing a reference to the object to be used as the result of the existence check * at the C layer, ``tp_exists`` implementations would return NULL to indicate - non-existence, and otherwise return a `PyObject *` pointer as the + non-existence, and otherwise return a ``PyObject *`` pointer as the result of the existence check Given that change, the sentinel object idiom could be rewritten as:: From cc78d2150d2a7ec857373407c80c4b2ecdd1fa54 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:20:20 +0100 Subject: [PATCH 067/173] PEP 3143: Resolve uses of the default role (#3383) --- pep-3143.txt | 174 +++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/pep-3143.txt b/pep-3143.txt index fa0858d25..a360aa374 100644 --- a/pep-3143.txt +++ b/pep-3143.txt @@ -38,7 +38,7 @@ Specification Example usage ============= -Simple example of direct `DaemonContext` usage:: +Simple example of direct ``DaemonContext`` usage:: import daemon @@ -90,24 +90,24 @@ More complex example usage:: Interface ========= -A new package, `daemon`, is added to the standard library. +A new package, ``daemon``, is added to the standard library. -A class, `DaemonContext`, is defined to represent the settings and +A class, ``DaemonContext``, is defined to represent the settings and process context for the program running as a daemon process. ``DaemonContext`` objects ========================= -A `DaemonContext` instance represents the behaviour settings and +A ``DaemonContext`` instance represents the behaviour settings and process context for the program when it becomes a daemon. The behaviour and environment is customised by setting options on the -instance, before calling the `open` method. +instance, before calling the ``open`` method. -Each option can be passed as a keyword argument to the `DaemonContext` +Each option can be passed as a keyword argument to the ``DaemonContext`` constructor, or subsequently altered by assigning to an attribute on -the instance at any time prior to calling `open`. That is, for -options named `wibble` and `wubble`, the following invocation:: +the instance at any time prior to calling ``open``. That is, for +options named ``wibble`` and ``wubble``, the following invocation:: foo = daemon.DaemonContext(wibble=bar, wubble=baz) foo.open() @@ -121,24 +121,24 @@ is equivalent to:: The following options are defined. -`files_preserve` +``files_preserve`` :Default: ``None`` List of files that should *not* be closed when starting the daemon. If ``None``, all open file descriptors will be closed. Elements of the list are file descriptors (as returned by a file - object's `fileno()` method) or Python `file` objects. Each + object's ``fileno()`` method) or Python ``file`` objects. Each specifies a file that is not to be closed during daemon start. -`chroot_directory` +``chroot_directory`` :Default: ``None`` Full path to a directory to set as the effective root directory of the process. If ``None``, specifies that the root directory is not to be changed. -`working_directory` +``working_directory`` :Default: ``'/'`` Full path of the working directory to which the process should @@ -149,7 +149,7 @@ The following options are defined. be left at default or set to a directory that is a sensible “home directory” for the daemon while it is running. -`umask` +``umask`` :Default: ``0`` File access creation mask (“umask”) to set for the process on @@ -159,13 +159,13 @@ The following options are defined. starting the daemon will reset the umask to this value so that files are created by the daemon with access modes as it expects. -`pidfile` +``pidfile`` :Default: ``None`` Context manager for a PID lock file. When the daemon context opens - and closes, it enters and exits the `pidfile` context manager. + and closes, it enters and exits the ``pidfile`` context manager. -`detach_process` +``detach_process`` :Default: ``None`` If ``True``, detach the process context when opening the daemon @@ -174,10 +174,10 @@ The following options are defined. If unspecified (``None``) during initialisation of the instance, this will be set to ``True`` by default, and ``False`` only if detaching the process is determined to be redundant; for example, - in the case when the process was started by `init`, by `initd`, or - by `inetd`. + in the case when the process was started by ``init``, by ``initd``, or + by ``inetd``. -`signal_map` +``signal_map`` :Default: system-dependent Mapping from operating system signals to callback actions. @@ -215,10 +215,10 @@ The following options are defined. on how to determine what circumstances dictate the need for signal handlers. -`uid` +``uid`` :Default: ``os.getuid()`` -`gid` +``gid`` :Default: ``os.getgid()`` The user ID (“UID”) value and group ID (“GID”) value to switch @@ -228,122 +228,122 @@ The following options are defined. relinquish any effective privilege elevation inherited by the process. -`prevent_core` +``prevent_core`` :Default: ``True`` If true, prevents the generation of core files, in order to avoid - leaking sensitive information from daemons run as `root`. + leaking sensitive information from daemons run as ``root``. -`stdin` +``stdin`` :Default: ``None`` -`stdout` +``stdout`` :Default: ``None`` -`stderr` +``stderr`` :Default: ``None`` - Each of `stdin`, `stdout`, and `stderr` is a file-like object + Each of ``stdin``, ``stdout``, and ``stderr`` is a file-like object which will be used as the new file for the standard I/O stream - `sys.stdin`, `sys.stdout`, and `sys.stderr` respectively. The file + ``sys.stdin``, ``sys.stdout``, and ``sys.stderr`` respectively. The file should therefore be open, with a minimum of mode 'r' in the case - of `stdin`, and mode 'w+' in the case of `stdout` and `stderr`. + of ``stdin``, and mode 'w+' in the case of ``stdout`` and ``stderr``. - If the object has a `fileno()` method that returns a file + If the object has a ``fileno()`` method that returns a file descriptor, the corresponding file will be excluded from being closed during daemon start (that is, it will be treated as though - it were listed in `files_preserve`). + it were listed in ``files_preserve``). If ``None``, the corresponding system stream is re-bound to the - file named by `os.devnull`. + file named by ``os.devnull``. The following methods are defined. -`open()` +``open()`` :Return: ``None`` Open the daemon context, turning the current program into a daemon process. This performs the following steps: - * If this instance's `is_open` property is true, return - immediately. This makes it safe to call `open` multiple times on + * If this instance's ``is_open`` property is true, return + immediately. This makes it safe to call ``open`` multiple times on an instance. - * If the `prevent_core` attribute is true, set the resource limits + * If the ``prevent_core`` attribute is true, set the resource limits for the process to prevent any core dump from the process. - * If the `chroot_directory` attribute is not ``None``, set the + * If the ``chroot_directory`` attribute is not ``None``, set the effective root directory of the process to that directory (via - `os.chroot`). + ``os.chroot``). This allows running the daemon process inside a “chroot gaol” as a means of limiting the system's exposure to rogue behaviour by the process. Note that the specified directory needs to already be set up for this purpose. - * Set the process UID and GID to the `uid` and `gid` attribute + * Set the process UID and GID to the ``uid`` and ``gid`` attribute values. * Close all open file descriptors. This excludes those listed in - the `files_preserve` attribute, and those that correspond to the - `stdin`, `stdout`, or `stderr` attributes. + the ``files_preserve`` attribute, and those that correspond to the + ``stdin``, ``stdout``, or ``stderr`` attributes. * Change current working directory to the path specified by the - `working_directory` attribute. + ``working_directory`` attribute. * Reset the file access creation mask to the value specified by - the `umask` attribute. + the ``umask`` attribute. - * If the `detach_process` option is true, detach the current + * If the ``detach_process`` option is true, detach the current process into its own process group, and disassociate from any controlling terminal. - * Set signal handlers as specified by the `signal_map` attribute. + * Set signal handlers as specified by the ``signal_map`` attribute. - * If any of the attributes `stdin`, `stdout`, `stderr` are not - ``None``, bind the system streams `sys.stdin`, `sys.stdout`, - and/or `sys.stderr` to the files represented by the + * If any of the attributes ``stdin``, ``stdout``, ``stderr`` are not + ``None``, bind the system streams ``sys.stdin``, ``sys.stdout``, + and/or ``sys.stderr`` to the files represented by the corresponding attributes. Where the attribute has a file descriptor, the descriptor is duplicated (instead of re-binding the name). - * If the `pidfile` attribute is not ``None``, enter its context + * If the ``pidfile`` attribute is not ``None``, enter its context manager. - * Mark this instance as open (for the purpose of future `open` and - `close` calls). + * Mark this instance as open (for the purpose of future ``open`` and + ``close`` calls). - * Register the `close` method to be called during Python's exit + * Register the ``close`` method to be called during Python's exit processing. When the function returns, the running program is a daemon process. -`close()` +``close()`` :Return: ``None`` Close the daemon context. This performs the following steps: - * If this instance's `is_open` property is false, return - immediately. This makes it safe to call `close` multiple times + * If this instance's ``is_open`` property is false, return + immediately. This makes it safe to call ``close`` multiple times on an instance. - * If the `pidfile` attribute is not ``None``, exit its context + * If the ``pidfile`` attribute is not ``None``, exit its context manager. - * Mark this instance as closed (for the purpose of future `open` - and `close` calls). + * Mark this instance as closed (for the purpose of future ``open`` + and ``close`` calls). -`is_open` +``is_open`` :Return: ``True`` if the instance is open, ``False`` otherwise. This property exposes the state indicating whether the instance is - currently open. It is ``True`` if the instance's `open` method has - been called and the `close` method has not subsequently been + currently open. It is ``True`` if the instance's ``open`` method has + been called and the ``close`` method has not subsequently been called. -`terminate(signal_number, stack_frame)` +``terminate(signal_number, stack_frame)`` :Return: ``None`` Signal handler for the ``signal.SIGTERM`` signal. Performs the @@ -354,16 +354,16 @@ The following methods are defined. The class also implements the context manager protocol via ``__enter__`` and ``__exit__`` methods. -`__enter__()` +``__enter__()`` :Return: The ``DaemonContext`` instance - Call the instance's `open()` method, then return the instance. + Call the instance's ``open()`` method, then return the instance. -`__exit__(exc_type, exc_value, exc_traceback)` +``__exit__(exc_type, exc_value, exc_traceback)`` :Return: ``True`` or ``False`` as defined by the context manager protocol - Call the instance's `close()` method, then return ``True`` if the + Call the instance's ``close()`` method, then return ``True`` if the exception was handled or ``False`` if it was not. @@ -409,13 +409,13 @@ following steps to become a Unix daemon process. * Correctly handle the following circumstances: - * Started by System V `init` process. + * Started by System V ``init`` process. * Daemon termination by ``SIGTERM`` signal. * Children generate ``SIGCLD`` signal. -The `daemon` tool [slack-daemon]_ lists (in its summary of features) +The ``daemon`` tool [slack-daemon]_ lists (in its summary of features) behaviour that should be performed when turning a program into a well-behaved Unix daemon process. It differs from this PEP's intent in that it invokes a *separate* program as a daemon process. The @@ -424,7 +424,7 @@ once the program is already running: * Sets up the correct process context for a daemon. -* Behaves sensibly when started by `initd(8)` or `inetd(8)`. +* Behaves sensibly when started by ``initd(8)`` or ``inetd(8)``. * Revokes any suid or sgid privileges to reduce security risks in case daemon is incorrectly installed with special privileges. @@ -468,7 +468,7 @@ a service. Reference Implementation ======================== -The `python-daemon` package [python-daemon]_. +The ``python-daemon`` package [python-daemon]_. Other daemon implementations ============================ @@ -482,23 +482,23 @@ following implementations: * Many good ideas were contributed by the community to Python cookbook recipes #66012 [cookbook-66012]_ and #278731 [cookbook-278731]_. -* The `bda.daemon` library [bda.daemon]_ is an implementation of +* The ``bda.daemon`` library [bda.daemon]_ is an implementation of [cookbook-66012]_. It is the predecessor of [python-daemon]_. Other Python daemon implementations that differ from this PEP: -* The `zdaemon` tool [zdaemon]_ was written for the Zope project. Like +* The ``zdaemon`` tool [zdaemon]_ was written for the Zope project. Like [slack-daemon]_, it differs from this specification because it is used to run another program as a daemon process. -* The Python library `daemon` [clapper-daemon]_ is (according to its +* The Python library ``daemon`` [clapper-daemon]_ is (according to its homepage) no longer maintained. As of version 1.0.1, it implements the basic steps from [stevens]_. -* The `daemonize` library [seutter-daemonize]_ also implements the +* The ``daemonize`` library [seutter-daemonize]_ also implements the basic steps from [stevens]_. -* Ray Burr's `daemon.py` module [burr-daemon]_ provides the [stevens]_ +* Ray Burr's ``daemon.py`` module [burr-daemon]_ provides the [stevens]_ procedure as well as PID file handling and redirection of output to syslog. @@ -507,8 +507,8 @@ Other Python daemon implementations that differ from this PEP: with the rest of the Twisted framework; it differs significantly from the API in this PEP. -* The Python `initd` library [dagitses-initd]_, which uses - [clapper-daemon]_, implements an equivalent of Unix `initd(8)` for +* The Python ``initd`` library [dagitses-initd]_, which uses + [clapper-daemon]_, implements an equivalent of Unix ``initd(8)`` for controlling a daemon process. @@ -518,17 +518,17 @@ References .. [stevens] - `Unix Network Programming`, W. Richard Stevens, 1994 Prentice + ``Unix Network Programming``, W. Richard Stevens, 1994 Prentice Hall. .. [slack-daemon] - The (non-Python) “libslack” implementation of a `daemon` tool + The (non-Python) “libslack” implementation of a ``daemon`` tool ``_ by “raf” . .. [python-daemon] - The `python-daemon` library + The ``python-daemon`` library ``_ by Ben Finney et al. @@ -544,39 +544,39 @@ References .. [bda.daemon] - The `bda.daemon` library + The ``bda.daemon`` library ``_ by Robert Niederreiter et al. .. [zdaemon] - The `zdaemon` tool ``_ by + The ``zdaemon`` tool ``_ by Guido van Rossum et al. .. [clapper-daemon] - The `daemon` library ``_ by + The ``daemon`` library ``_ by Brian Clapper. .. [seutter-daemonize] - The `daemonize` library ``_ by + The ``daemonize`` library ``_ by Jerry Seutter. .. [burr-daemon] - The `daemon.py` module + The ``daemon.py`` module ``_ by Ray Burr. .. [twisted] - The `Twisted` application framework + The ``Twisted`` application framework ``_ by Glyph Lefkowitz et al. .. [dagitses-initd] - The Python `initd` library ``_ + The Python ``initd`` library ``_ by Michael Andreas Dagitses. From e14830b96ab46d7d948052b588e604561b21b4f0 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:20:35 +0100 Subject: [PATCH 068/173] PEP 3103: Resolve uses of the default role (#3382) --- pep-3103.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-3103.txt b/pep-3103.txt index 1f4b9fe44..007b909a3 100644 --- a/pep-3103.txt +++ b/pep-3103.txt @@ -232,7 +232,7 @@ like this:: case [*]EXPR, [*]EXPR, ...: -The `*` notation is similar to the use of prefix `*` already in use for +The ``*`` notation is similar to the use of prefix ``*`` already in use for variable-length parameter lists and for passing computed argument lists, and often proposed for value-unpacking (e.g. ``a, b, *c = X`` as an alternative to ``(a, b), c = X[:2], X[2:]``). From 7cf696649b09b7985a1170ee02fc6df2e4fc0880 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:20:54 +0100 Subject: [PATCH 069/173] PEP 3148: Resolve uses of the default role (#3386) --- pep-3148.txt | 146 +++++++++++++++++++++++++-------------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/pep-3148.txt b/pep-3148.txt index 70c044f12..61c62616c 100644 --- a/pep-3148.txt +++ b/pep-3148.txt @@ -57,21 +57,21 @@ in that module, which work across thread and process boundaries. Interface --------- -The proposed package provides two core classes: `Executor` and -`Future`. An `Executor` receives asynchronous work requests (in terms -of a callable and its arguments) and returns a `Future` to represent +The proposed package provides two core classes: ``Executor`` and +``Future``. An ``Executor`` receives asynchronous work requests (in terms +of a callable and its arguments) and returns a ``Future`` to represent the execution of that work request. Executor '''''''' -`Executor` is an abstract class that provides methods to execute calls +``Executor`` is an abstract class that provides methods to execute calls asynchronously. ``submit(fn, *args, **kwargs)`` Schedules the callable to be executed as ``fn(*args, **kwargs)`` - and returns a `Future` instance representing the execution of the + and returns a ``Future`` instance representing the execution of the callable. This is an abstract method and must be implemented by Executor @@ -81,10 +81,10 @@ asynchronously. Equivalent to ``map(func, *iterables)`` but func is executed asynchronously and several calls to func may be made concurrently. - The returned iterator raises a `TimeoutError` if `__next__()` is + The returned iterator raises a ``TimeoutError`` if ``__next__()`` is called and the result isn't available after *timeout* seconds from - the original call to `map()`. If *timeout* is not specified or - `None` then there is no limit to the wait time. If a call raises + the original call to ``map()``. If *timeout* is not specified or + ``None`` then there is no limit to the wait time. If a call raises an exception then that exception will be raised when its value is retrieved from the iterator. @@ -92,12 +92,12 @@ asynchronously. Signal the executor that it should free any resources that it is using when the currently pending futures are done executing. - Calls to `Executor.submit` and `Executor.map` and made after - shutdown will raise `RuntimeError`. + Calls to ``Executor.submit`` and ``Executor.map`` and made after + shutdown will raise ``RuntimeError``. - If wait is `True` then this method will not return until all the + If wait is ``True`` then this method will not return until all the pending futures are done executing and the resources associated - with the executor have been freed. If wait is `False` then this + with the executor have been freed. If wait is ``False`` then this method will return immediately and the resources associated with the executor will be freed when all pending futures are done executing. Regardless of the value of wait, the entire Python @@ -107,21 +107,21 @@ asynchronously. | ``__enter__()`` | ``__exit__(exc_type, exc_val, exc_tb)`` - When using an executor as a context manager, `__exit__` will call + When using an executor as a context manager, ``__exit__`` will call ``Executor.shutdown(wait=True)``. ProcessPoolExecutor ''''''''''''''''''' -The `ProcessPoolExecutor` class is an `Executor` subclass that uses a +The ``ProcessPoolExecutor`` class is an ``Executor`` subclass that uses a pool of processes to execute calls asynchronously. The callable -objects and arguments passed to `ProcessPoolExecutor.submit` must be +objects and arguments passed to ``ProcessPoolExecutor.submit`` must be pickleable according to the same limitations as the multiprocessing module. -Calling `Executor` or `Future` methods from within a callable -submitted to a `ProcessPoolExecutor` will result in deadlock. +Calling ``Executor`` or ``Future`` methods from within a callable +submitted to a ``ProcessPoolExecutor`` will result in deadlock. ``__init__(max_workers)`` @@ -132,11 +132,11 @@ submitted to a `ProcessPoolExecutor` will result in deadlock. ThreadPoolExecutor '''''''''''''''''' -The `ThreadPoolExecutor` class is an `Executor` subclass that uses a +The ``ThreadPoolExecutor`` class is an ``Executor`` subclass that uses a pool of threads to execute calls asynchronously. -Deadlock can occur when the callable associated with a `Future` waits -on the results of another `Future`. For example:: +Deadlock can occur when the callable associated with a ``Future`` waits +on the results of another ``Future``. For example:: import time def wait_on_b(): @@ -173,28 +173,28 @@ And:: Future Objects '''''''''''''' -The `Future` class encapsulates the asynchronous execution of a -callable. `Future` instances are returned by `Executor.submit`. +The ``Future`` class encapsulates the asynchronous execution of a +callable. ``Future`` instances are returned by ``Executor.submit``. ``cancel()`` Attempt to cancel the call. If the call is currently being executed then it cannot be cancelled and the method will return - `False`, otherwise the call will be cancelled and the method will - return `True`. + ``False``, otherwise the call will be cancelled and the method will + return ``True``. ``cancelled()`` - Return `True` if the call was successfully cancelled. + Return ``True`` if the call was successfully cancelled. ``running()`` - Return `True` if the call is currently being executed and cannot + Return ``True`` if the call is currently being executed and cannot be cancelled. ``done()`` - Return `True` if the call was successfully cancelled or finished + Return ``True`` if the call was successfully cancelled or finished running. ``result(timeout=None)`` @@ -202,10 +202,10 @@ callable. `Future` instances are returned by `Executor.submit`. Return the value returned by the call. If the call hasn't yet completed then this method will wait up to *timeout* seconds. If the call hasn't completed in *timeout* seconds then a - `TimeoutError` will be raised. If *timeout* is not specified or - `None` then there is no limit to the wait time. + ``TimeoutError`` will be raised. If *timeout* is not specified or + ``None`` then there is no limit to the wait time. - If the future is cancelled before completing then `CancelledError` + If the future is cancelled before completing then ``CancelledError`` will be raised. If the call raised then this method will raise the same exception. @@ -215,13 +215,13 @@ callable. `Future` instances are returned by `Executor.submit`. Return the exception raised by the call. If the call hasn't yet completed then this method will wait up to *timeout* seconds. If the call hasn't completed in *timeout* seconds then a - `TimeoutError` will be raised. If *timeout* is not specified or + ``TimeoutError`` will be raised. If *timeout* is not specified or ``None`` then there is no limit to the wait time. - If the future is cancelled before completing then `CancelledError` + If the future is cancelled before completing then ``CancelledError`` will be raised. - If the call completed without raising then `None` is returned. + If the call completed without raising then ``None`` is returned. ``add_done_callback(fn)`` @@ -231,9 +231,9 @@ callable. `Future` instances are returned by `Executor.submit`. Added callables are called in the order that they were added and are always called in a thread belonging to the process that added - them. If the callable raises an `Exception` then it will be + them. If the callable raises an ``Exception`` then it will be logged and ignored. If the callable raises another - `BaseException` then behavior is not defined. + ``BaseException`` then behavior is not defined. If the future has already completed or been cancelled then *fn* will be called immediately. @@ -241,43 +241,43 @@ callable. `Future` instances are returned by `Executor.submit`. Internal Future Methods ^^^^^^^^^^^^^^^^^^^^^^^ -The following `Future` methods are meant for use in unit tests and -`Executor` implementations. +The following ``Future`` methods are meant for use in unit tests and +``Executor`` implementations. ``set_running_or_notify_cancel()`` - Should be called by `Executor` implementations before executing - the work associated with the `Future`. + Should be called by ``Executor`` implementations before executing + the work associated with the ``Future``. - If the method returns `False` then the `Future` was cancelled, - i.e. `Future.cancel` was called and returned `True`. Any threads - waiting on the `Future` completing (i.e. through `as_completed()` - or `wait()`) will be woken up. + If the method returns ``False`` then the ``Future`` was cancelled, + i.e. ``Future.cancel`` was called and returned ``True``. Any threads + waiting on the ``Future`` completing (i.e. through ``as_completed()`` + or ``wait()``) will be woken up. - If the method returns `True` then the `Future` was not cancelled + If the method returns ``True`` then the ``Future`` was not cancelled and has been put in the running state, i.e. calls to - `Future.running()` will return `True`. + ``Future.running()`` will return ``True``. This method can only be called once and cannot be called after - `Future.set_result()` or `Future.set_exception()` have been + ``Future.set_result()`` or ``Future.set_exception()`` have been called. ``set_result(result)`` - Sets the result of the work associated with the `Future`. + Sets the result of the work associated with the ``Future``. ``set_exception(exception)`` - Sets the result of the work associated with the `Future` to the - given `Exception`. + Sets the result of the work associated with the ``Future`` to the + given ``Exception``. Module Functions '''''''''''''''' ``wait(fs, timeout=None, return_when=ALL_COMPLETED)`` - Wait for the `Future` instances (possibly created by different - `Executor` instances) given by *fs* to complete. Returns a named + Wait for the ``Future`` instances (possibly created by different + ``Executor`` instances) given by *fs* to complete. Returns a named 2-tuple of sets. The first set, named "done", contains the futures that completed (finished or were cancelled) before the wait completed. The second set, named "not_done", contains @@ -293,27 +293,27 @@ Module Functions ============================= ================================================== Constant Description ============================= ================================================== - `FIRST_COMPLETED` The method will return when any future finishes or + ``FIRST_COMPLETED`` The method will return when any future finishes or is cancelled. - `FIRST_EXCEPTION` The method will return when any future finishes by + ``FIRST_EXCEPTION`` The method will return when any future finishes by raising an exception. If not future raises an exception then it is equivalent to ALL_COMPLETED. - `ALL_COMPLETED` The method will return when all calls finish. + ``ALL_COMPLETED`` The method will return when all calls finish. ============================= ================================================== ``as_completed(fs, timeout=None)`` - Returns an iterator over the `Future` instances given by *fs* that + Returns an iterator over the ``Future`` instances given by *fs* that yields futures as they complete (finished or were cancelled). Any - futures that completed before `as_completed()` was called will be - yielded first. The returned iterator raises a `TimeoutError` if - `__next__()` is called and the result isn't available after - *timeout* seconds from the original call to `as_completed()`. If - *timeout* is not specified or `None` then there is no limit to the + futures that completed before ``as_completed()`` was called will be + yielded first. The returned iterator raises a ``TimeoutError`` if + ``__next__()`` is called and the result isn't available after + *timeout* seconds from the original call to ``as_completed()``. If + *timeout* is not specified or ``None`` then there is no limit to the wait time. - The `Future` instances can have been created by different - `Executor` instances. + The ``Future`` instances can have been created by different + ``Executor`` instances. Check Prime Example ------------------- @@ -408,7 +408,7 @@ list [3]_. The proposed design is explicit, i.e. it requires that clients be aware that they are consuming Futures. It would be possible to design -a module that would return proxy objects (in the style of `weakref`) +a module that would return proxy objects (in the style of ``weakref``) that could be used transparently. It is possible to build a proxy implementation on top of the proposed explicit mechanism. @@ -425,13 +425,13 @@ the API has been discussed in some detail on stdlib-sig [6]_. The proposed design was discussed on the Python-Dev mailing list [7]_. Following those discussions, the following changes were made: -* The `Executor` class was made into an abstract base class -* The `Future.remove_done_callback` method was removed due to a lack +* The ``Executor`` class was made into an abstract base class +* The ``Future.remove_done_callback`` method was removed due to a lack of convincing use cases -* The `Future.add_done_callback` method was modified to allow the +* The ``Future.add_done_callback`` method was modified to allow the same callable to be added many times -* The `Future` class's mutation methods were better documented to - indicate that they are private to the `Executor` that created them +* The ``Future`` class's mutation methods were better documented to + indicate that they are private to the ``Executor`` that created them ======================== Reference Implementation @@ -445,7 +445,7 @@ References ========== .. [1] - `java.util.concurrent` package documentation + ``java.util.concurrent`` package documentation http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html .. [2] @@ -453,15 +453,15 @@ References http://code.activestate.com/recipes/84317/ .. [3] - `Python-3000` thread, "mechanism for handling asynchronous concurrency" + ``Python-3000`` thread, "mechanism for handling asynchronous concurrency" https://mail.python.org/pipermail/python-3000/2006-April/000960.html .. [4] - `Python 3000` thread, "Futures in Python 3000 (was Re: mechanism for handling asynchronous concurrency)" + ``Python 3000`` thread, "Futures in Python 3000 (was Re: mechanism for handling asynchronous concurrency)" https://mail.python.org/pipermail/python-3000/2006-April/000970.html .. [5] - A discussion of `stream`, a similar concept proposed by Anh Hai Trinh + A discussion of ``stream``, a similar concept proposed by Anh Hai Trinh http://www.mail-archive.com/stdlib-sig@python.org/msg00480.html .. [6] @@ -473,7 +473,7 @@ References https://mail.python.org/pipermail/python-dev/2010-March/098169.html .. [8] - Reference `futures` implementation + Reference ``futures`` implementation http://code.google.com/p/pythonfutures/source/browse/#svn/branches/feedback ========= From ac2c284aeaf4a7bcfabd18cbff078e473df7ef2a Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:21:05 +0100 Subject: [PATCH 070/173] PEP 3146: Resolve uses of the default role (#3384) --- pep-3146.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pep-3146.txt b/pep-3146.txt index afa39136a..dcbdbfe05 100644 --- a/pep-3146.txt +++ b/pep-3146.txt @@ -132,10 +132,10 @@ they are used. However, if by chance the historically-untaken branch is now taken, or some integer-optimized ``a + b`` snippet receives two strings, we must support this. We cannot change Python semantics. Each of these sections of optimized machine -code is preceded by a `guard`, which checks whether the simplifying assumptions -we made when optimizing still hold. If the assumptions are still valid, we run -the optimized machine code; if they are not, we revert back to the interpreter -and pick up where we left off. +code is preceded by a ``guard``, which checks whether the simplifying +assumptions we made when optimizing still hold. If the assumptions are still +valid, we run the optimized machine code; if they are not, we revert back to +the interpreter and pick up where we left off. We have chosen to reuse a set of existing compiler libraries called LLVM [#llvm]_ for code generation and code optimization. This has saved our small @@ -848,8 +848,8 @@ Unladen Swallow [#us-oprofile-change]_, other profiling tools should be easy as well, provided they support a similar JIT interface [#oprofile-jit-interface]_. We have documented the process for using oProfile to profile Unladen Swallow -[#oprofile-workflow]_. This document will be merged into CPython's `Doc/` tree -in the merge. +[#oprofile-workflow]_. This document will be merged into CPython's ``Doc/`` +tree in the merge. Addition of C++ to CPython From eecda12e5ae862e90bd629300f88730f64e2cfbe Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:21:21 +0100 Subject: [PATCH 071/173] PEP 3147: Resolve uses of the default role (#3385) --- pep-3147.txt | 178 +++++++++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/pep-3147.txt b/pep-3147.txt index 8b54d8a30..5f3e54fa6 100644 --- a/pep-3147.txt +++ b/pep-3147.txt @@ -30,7 +30,7 @@ CPython compiles its source code into "byte code", and for performance reasons, it caches this byte code on the file system whenever the source file has changes. This makes loading of Python modules much faster because the compilation phase can be bypassed. When your -source file is `foo.py`, CPython caches the byte code in a `foo.pyc` +source file is ``foo.py``, CPython caches the byte code in a ``foo.pyc`` file right next to the source. Byte code files contain two 32-bit big-endian numbers followed by the @@ -59,11 +59,11 @@ with Python 2.6 being the default. This causes a conflict for third party Python source files installed by the system, because you cannot compile a single Python source file -for more than one Python version at a time. When Python finds a `pyc` +for more than one Python version at a time. When Python finds a ``pyc`` file with a non-matching magic number, it falls back to the slower process of recompiling the source. Thus if your system installed a -`/usr/share/python/foo.py`, two different versions of Python would -fight over the `pyc` file and rewrite it each time the source is +``/usr/share/python/foo.py``, two different versions of Python would +fight over the ``pyc`` file and rewrite it each time the source is compiled. (The standard library is unaffected by this, since multiple versions of the stdlib *are* installed on such distributions..) @@ -99,7 +99,7 @@ Proposal Python's import machinery is extended to write and search for byte code cache files in a single directory inside every Python package -directory. This directory will be called `__pycache__`. +directory. This directory will be called ``__pycache__``. Further, pyc file names will contain a magic string (called a "tag") that differentiates the Python version they were compiled for. This @@ -107,36 +107,36 @@ allows multiple byte compiled cache files to co-exist for a single Python source file. The magic tag is implementation defined, but should contain the -implementation name and a version number shorthand, e.g. `cpython-32`. +implementation name and a version number shorthand, e.g. ``cpython-32``. It must be unique among all versions of Python, and whenever the magic -number is bumped, a new magic tag must be defined. An example `pyc` -file for Python 3.2 is thus `foo.cpython-32.pyc`. +number is bumped, a new magic tag must be defined. An example ``pyc`` +file for Python 3.2 is thus ``foo.cpython-32.pyc``. -The magic tag is available in the `imp` module via the `get_tag()` -function. This is parallel to the `imp.get_magic()` function. +The magic tag is available in the ``imp`` module via the ``get_tag()`` +function. This is parallel to the ``imp.get_magic()`` function. This scheme has the added benefit of reducing the clutter in a Python package directory. When a Python source file is imported for the first time, a -`__pycache__` directory will be created in the package directory, if +``__pycache__`` directory will be created in the package directory, if one does not already exist. The pyc file for the imported source will -be written to the `__pycache__` directory, using the magic-tag -formatted name. If either the creation of the `__pycache__` directory +be written to the ``__pycache__`` directory, using the magic-tag +formatted name. If either the creation of the ``__pycache__`` directory or the pyc file inside that fails, the import will still succeed, just as it does in a pre-:pep:`3147` world. -If the py source file is missing, the pyc file inside `__pycache__` +If the py source file is missing, the pyc file inside ``__pycache__`` will be ignored. This eliminates the problem of accidental stale pyc file imports. For backward compatibility, Python will still support pyc-only distributions, however it will only do so when the pyc file lives in the directory where the py file *would* have been, i.e. not in the -`__pycache__` directory. pyc file outside of `__pycache__` will only +``__pycache__`` directory. pyc file outside of ``__pycache__`` will only be imported if the py source file is missing. -Tools such as `py_compile` [15]_ and `compileall` [16]_ will be +Tools such as ``py_compile`` [15]_ and ``compileall`` [16]_ will be extended to create :pep:`3147` formatted layouts automatically, but will have an option to create pyc-only distribution layouts. @@ -146,8 +146,8 @@ Examples What would this look like in practice? -Let's say we have a Python package named `alpha` which contains a -sub-package name `beta`. The source directory layout before byte +Let's say we have a Python package named ``alpha`` which contains a +sub-package name ``beta``. The source directory layout before byte compilation might look like this:: alpha/ @@ -218,7 +218,7 @@ As you can see, as long as the Python version identifier string is unique, any number of pyc files can co-exist. These identifier strings are described in more detail below. -A nice property of this layout is that the `__pycache__` directories +A nice property of this layout is that the ``__pycache__`` directories can generally be ignored, such that a normal directory listing would show something like this:: @@ -239,50 +239,50 @@ This is much less cluttered than even today's Python. Python behavior =============== -When Python searches for a module to import (say `foo`), it may find +When Python searches for a module to import (say ``foo``), it may find one of several situations. As per current Python rules, the term "matching pyc" means that the magic number matches the current interpreter's magic number, and the source file's timestamp matches -the timestamp in the `pyc` file exactly. +the timestamp in the ``pyc`` file exactly. Case 0: The steady state ------------------------ -When Python is asked to import module `foo`, it searches for a -`foo.py` file (or `foo` package, but that's not important for this -discussion) along its `sys.path`. If found, Python looks to see if -there is a matching `__pycache__/foo..pyc` file, and if so, -that `pyc` file is loaded. +When Python is asked to import module ``foo``, it searches for a +``foo.py`` file (or ``foo`` package, but that's not important for this +discussion) along its ``sys.path``. If found, Python looks to see if +there is a matching ``__pycache__/foo..pyc`` file, and if so, +that ``pyc`` file is loaded. Case 1: The first import ------------------------ -When Python locates the `foo.py`, if the `__pycache__/foo..pyc` +When Python locates the ``foo.py``, if the ``__pycache__/foo..pyc`` file is missing, Python will create it, also creating the -`__pycache__` directory if necessary. Python will parse and byte -compile the `foo.py` file and save the byte code in -`__pycache__/foo..pyc`. +``__pycache__`` directory if necessary. Python will parse and byte +compile the ``foo.py`` file and save the byte code in +``__pycache__/foo..pyc``. Case 2: The second import ------------------------- -When Python is asked to import module `foo` a second time (in a -different process of course), it will again search for the `foo.py` -file along its `sys.path`. When Python locates the `foo.py` file, it -looks for a matching `__pycache__/foo..pyc` and finding this, +When Python is asked to import module ``foo`` a second time (in a +different process of course), it will again search for the ``foo.py`` +file along its ``sys.path``. When Python locates the ``foo.py`` file, it +looks for a matching ``__pycache__/foo..pyc`` and finding this, it reads the byte code and continues as usual. Case 3: __pycache__/foo..pyc with no source --------------------------------------------------- -It's possible that the `foo.py` file somehow got removed, while +It's possible that the ``foo.py`` file somehow got removed, while leaving the cached pyc file still on the file system. If the -`__pycache__/foo..pyc` file exists, but the `foo.py` file used -to create it does not, Python will raise an `ImportError` when asked +``__pycache__/foo..pyc`` file exists, but the ``foo.py`` file used +to create it does not, Python will raise an ``ImportError`` when asked to import foo. In other words, Python will not import a pyc file from the cache directory unless the source file exists. @@ -291,8 +291,8 @@ Case 4: legacy pyc files and source-less imports ------------------------------------------------ Python will ignore all legacy pyc files when a source file exists next -to it. In other words, if a `foo.pyc` file exists next to the -`foo.py` file, the pyc file will be ignored in all cases +to it. In other words, if a ``foo.pyc`` file exists next to the +``foo.py`` file, the pyc file will be ignored in all cases In order to continue to support source-less distributions though, if the source file is missing, Python will import a lone pyc file if it @@ -302,9 +302,9 @@ lives where the source file would have been. Case 5: read-only file systems ------------------------------ -When the source lives on a read-only file system, or the `__pycache__` +When the source lives on a read-only file system, or the ``__pycache__`` directory or pyc file cannot otherwise be written, all the same rules -apply. This is also the case when `__pycache__` happens to be written +apply. This is also the case when ``__pycache__`` happens to be written with permissions which do not allow for writing containing pyc files. @@ -324,9 +324,9 @@ Alternative Python implementations Alternative Python implementations such as Jython [11]_, IronPython [12]_, PyPy [13]_, Pynie [14]_, and Unladen Swallow can also use the -`__pycache__` directory to store whatever compilation artifacts make +``__pycache__`` directory to store whatever compilation artifacts make sense for their platforms. For example, Jython could store the class -file for the module in `__pycache__/foo.jython-32.class`. +file for the module in ``__pycache__/foo.jython-32.class``. Implementation strategy @@ -336,7 +336,7 @@ This feature is targeted for Python 3.2, solving the problem for those and all future versions. It may be back-ported to Python 2.7. Vendors are free to backport the changes to earlier distributions as they see fit. For backports of this feature to Python 2, when the -`-U` flag is used, a file such as `foo.cpython-27u.pyc` can be +``-U`` flag is used, a file such as ``foo.cpython-27u.pyc`` can be written. @@ -360,9 +360,9 @@ The easiest way to detect whether your version of Python provides PEP __file__ --------- -In Python 3, when you import a module, its `__file__` attribute points -to its source `py` file (in Python 2, it points to the `pyc` file). A -package's `__file__` points to the `py` file for its `__init__.py`. +In Python 3, when you import a module, its ``__file__`` attribute points +to its source ``py`` file (in Python 2, it points to the ``pyc`` file). A +package's ``__file__`` points to the ``py`` file for its ``__init__.py``. E.g.:: >>> import foo @@ -373,64 +373,64 @@ E.g.:: >>> baz.__file__ 'baz/__init__.py' -Nothing in this PEP would change the semantics of `__file__`. +Nothing in this PEP would change the semantics of ``__file__``. -This PEP proposes the addition of an `__cached__` attribute to -modules, which will always point to the actual `pyc` file that was +This PEP proposes the addition of an ``__cached__`` attribute to +modules, which will always point to the actual ``pyc`` file that was read or written. When the environment variable -`$PYTHONDONTWRITEBYTECODE` is set, or the `-B` option is given, or if -the source lives on a read-only filesystem, then the `__cached__` -attribute will point to the location that the `pyc` file *would* have +``$PYTHONDONTWRITEBYTECODE`` is set, or the ``-B`` option is given, or if +the source lives on a read-only filesystem, then the ``__cached__`` +attribute will point to the location that the ``pyc`` file *would* have been written to if it didn't exist. This location of course includes -the `__pycache__` subdirectory in its path. +the ``__pycache__`` subdirectory in its path. -For alternative Python implementations which do not support `pyc` -files, the `__cached__` attribute may point to whatever information -makes sense. E.g. on Jython, this might be the `.class` file for the -module: `__pycache__/foo.jython-32.class`. Some implementations may +For alternative Python implementations which do not support ``pyc`` +files, the ``__cached__`` attribute may point to whatever information +makes sense. E.g. on Jython, this might be the ``.class`` file for the +module: ``__pycache__/foo.jython-32.class``. Some implementations may use multiple compiled files to create the module, in which case -`__cached__` may be a tuple. The exact contents of `__cached__` are +``__cached__`` may be a tuple. The exact contents of ``__cached__`` are Python implementation specific. It is recommended that when nothing sensible can be calculated, -implementations should set the `__cached__` attribute to `None`. +implementations should set the ``__cached__`` attribute to ``None``. py_compile and compileall ------------------------- -Python comes with two modules, `py_compile` [15]_ and `compileall` +Python comes with two modules, ``py_compile`` [15]_ and ``compileall`` [16]_ which support compiling Python modules external to the built-in -import machinery. `py_compile` in particular has intimate knowledge +import machinery. ``py_compile`` in particular has intimate knowledge of byte compilation, so these will be updated to understand the new -layout. The `-b` flag is added to `compileall` for writing legacy -`.pyc` byte-compiled file path names. +layout. The ``-b`` flag is added to ``compileall`` for writing legacy +``.pyc`` byte-compiled file path names. bdist_wininst and the Windows installer --------------------------------------- These tools also compile modules explicitly on installation. If they -do not use `py_compile` and `compileall`, then they would also have to +do not use ``py_compile`` and ``compileall``, then they would also have to be modified to understand the new layout. File extension checks --------------------- -There exists some code which checks for files ending in `.pyc` and -simply chops off the last character to find the matching `.py` file. +There exists some code which checks for files ending in ``.pyc`` and +simply chops off the last character to find the matching ``.py`` file. This code will obviously fail once this PEP is implemented. -To support this use case, we'll add two new methods to the `imp` +To support this use case, we'll add two new methods to the ``imp`` package [17]_: -* `imp.cache_from_source(py_path)` -> `pyc_path` -* `imp.source_from_cache(pyc_path)` -> `py_path` +* ``imp.cache_from_source(py_path)`` -> ``pyc_path`` +* ``imp.source_from_cache(pyc_path)`` -> ``py_path`` Alternative implementations are free to override these functions to return reasonable values based on their own support for this PEP. -These methods are allowed to return `None` when the implementation (or +These methods are allowed to return ``None`` when the implementation (or :pep:`302` loader in effect) for whatever reason cannot calculate the appropriate file name. They should not raise exceptions. @@ -443,15 +443,15 @@ possible to backport this PEP. However, in Python 3.2 (and possibly 2.7), this behavior will be turned on by default, and in fact, it will replace the old behavior. Backports will need to support the old layout by default. We suggest supporting :pep:`3147` through the use of -an environment variable called `$PYTHONENABLECACHEDIR` or the command -line switch `-Xenablecachedir` to enable the feature. +an environment variable called ``$PYTHONENABLECACHEDIR`` or the command +line switch ``-Xenablecachedir`` to enable the feature. Makefiles and other dependency tools ------------------------------------ -Makefiles and other tools which calculate dependencies on `.pyc` files -(e.g. to byte-compile the source if the `.pyc` is missing) will have +Makefiles and other tools which calculate dependencies on ``.pyc`` files +(e.g. to byte-compile the source if the ``.pyc`` is missing) will have to be updated to check the new paths. @@ -465,7 +465,7 @@ were considered and rejected during the PEP's development. Hexadecimal magic tags ---------------------- -pyc files inside of the `__pycache__` directories contain a magic tag +pyc files inside of the ``__pycache__`` directories contain a magic tag in their file names. These are mnemonic tags for the actual magic numbers used by the importer. We could have used the hexadecimal representation [10]_ of the binary magic number as a unique @@ -485,15 +485,15 @@ PEP 304 There is some overlap between the goals of this PEP and :pep:`304`, which has been withdrawn. However :pep:`304` would allow a user to -create a shadow file system hierarchy in which to store `pyc` files. -This concept of a shadow hierarchy for `pyc` files could be used to +create a shadow file system hierarchy in which to store ``pyc`` files. +This concept of a shadow hierarchy for ``pyc`` files could be used to satisfy the aims of this PEP. Although the :pep:`304` does not indicate why it was withdrawn, shadow directories have a number of problems. -The location of the shadow `pyc` files would not be easily discovered +The location of the shadow ``pyc`` files would not be easily discovered and would depend on the proper and consistent use of the -`$PYTHONBYTECODE` environment variable both by the system and by end +``$PYTHONBYTECODE`` environment variable both by the system and by end users. There are also global implications, meaning that while the -system might want to shadow `pyc` files, users might not want to, but +system might want to shadow ``pyc`` files, users might not want to, but the PEP defines only an all-or-nothing approach. As an example of the problem, a common (though fragile) Python idiom @@ -503,9 +503,9 @@ for locating data files is to do something like this:: import foo.bar data_file = join(dirname(foo.bar.__file__), 'my.dat') -This would be problematic since `foo.bar.__file__` will give the -location of the `pyc` file in the shadow directory, and it may not be -possible to find the `my.dat` file relative to the source directory +This would be problematic since ``foo.bar.__file__`` will give the +location of the ``pyc`` file in the shadow directory, and it may not be +possible to find the ``my.dat`` file relative to the source directory from there. @@ -513,11 +513,11 @@ Fat byte compilation files -------------------------- An earlier version of this PEP described "fat" Python byte code files. -These files would contain the equivalent of multiple `pyc` files in a -single `pyf` file, with a lookup table keyed off the appropriate magic +These files would contain the equivalent of multiple ``pyc`` files in a +single ``pyf`` file, with a lookup table keyed off the appropriate magic number. This was an extensible file format so that the first 5 parallel Python implementations could be supported fairly efficiently, -but with extension lookup tables available to scale `pyf` byte code +but with extension lookup tables available to scale ``pyf`` byte code objects as large as necessary. The fat byte compilation files were fairly complex, and inherently @@ -541,7 +541,7 @@ tools that are dependent on the file extension. .pyc ---- -A proposal was floated to call the `__pycache__` directory `.pyc` or +A proposal was floated to call the ``__pycache__`` directory ``.pyc`` or some other dot-file name. This would have the effect on \*nix systems of hiding the directory. There are many reasons why this was rejected by the BDFL [20]_ including the fact that dot-files are only @@ -616,7 +616,7 @@ ACKNOWLEDGMENTS Barry Warsaw's original idea was for fat Python byte code files. Martin von Loewis reviewed an early draft of the PEP and suggested the -simplification to store traditional `pyc` and `pyo` files in a +simplification to store traditional ``pyc`` and ``pyo`` files in a directory. Many other people reviewed early versions of this PEP and provided useful feedback including but not limited to: From 90bf48eb4cc3c721af6537d51cef550a41dc4ac9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:25:38 +0100 Subject: [PATCH 072/173] PEP 390: Resolve uses of the default role (#3387) --- pep-0390.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0390.txt b/pep-0390.txt index f10d4fd53..502e43a4f 100644 --- a/pep-0390.txt +++ b/pep-0390.txt @@ -166,8 +166,8 @@ Impact on PKG-INFO generation and PEP 314 ========================================= When ``PKG-INFO`` is generated by Distutils, every field that relies on a -condition will have that condition written at the end of the line, after a `;` -separator:: +condition will have that condition written at the end of the line, after a +``;`` separator:: Metadata-Version: 1.2 Name: distribute From 72cafd185951c2cf74e3df618a7aeb14a9f2c566 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:25:59 +0100 Subject: [PATCH 073/173] PEP 394: Resolve uses of the default role (#3389) --- pep-0394.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0394.txt b/pep-0394.txt index 7e6110112..c3438657f 100644 --- a/pep-0394.txt +++ b/pep-0394.txt @@ -361,7 +361,7 @@ References .. [6] PEP 394 - Clarification of what "python" command should invoke (https://mail.python.org/pipermail/python-dev/2014-September/136374.html) -.. [7] PEP 394: Allow the `python` command to not be installed, and other +.. [7] PEP 394: Allow the ``python`` command to not be installed, and other minor edits (https://github.com/python/peps/pull/630) From 3bc3ad8f39d833c062f9c0b00a557b8133394f79 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:13 +0100 Subject: [PATCH 074/173] PEP 399: Resolve uses of the default role (#3390) --- pep-0399.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0399.txt b/pep-0399.txt index 3fe730c98..a87ee2a10 100644 --- a/pep-0399.txt +++ b/pep-0399.txt @@ -161,9 +161,9 @@ could be added. To also help with compatibility, C code should use abstract APIs on objects to prevent accidental dependence on specific types. For instance, if a function accepts a sequence then the C code should -default to using `PyObject_GetItem()` instead of something like -`PyList_GetItem()`. C code is allowed to have a fast path if the -proper `PyList_CheckExact()` is used, but otherwise APIs should work +default to using ``PyObject_GetItem()`` instead of something like +``PyList_GetItem()``. C code is allowed to have a fast path if the +proper ``PyList_CheckExact()`` is used, but otherwise APIs should work with any object that duck types to the proper interface instead of a specific type. From bff9f540a2730616660950faa2f625fb3284db94 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:24 +0100 Subject: [PATCH 075/173] PEP 402: Resolve uses of the default role (#3391) --- pep-0402.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0402.txt b/pep-0402.txt index 2581eaf08..318726599 100644 --- a/pep-0402.txt +++ b/pep-0402.txt @@ -532,7 +532,7 @@ Specifically the proposed changes and additions to ``pkgutil`` are: The implementation of this function does a simple top-down traversal of ``sys.virtual_package_paths``, and performs any necessary ``get_subpath()`` calls to identify what path entries need to be - added to the virtual path for that package, given that `path_entry` + added to the virtual path for that package, given that ``path_entry`` has been added to ``sys.path``. (Or, in the case of sub-packages, adding a derived subpath entry, based on their parent package's virtual path.) @@ -545,7 +545,7 @@ Specifically the proposed changes and additions to ``pkgutil`` are: * A new ``iter_virtual_packages(parent='')`` function to allow top-down traversal of virtual packages from ``sys.virtual_package_paths``, by yielding the child virtual - packages of `parent`. For example, calling + packages of ``parent``. For example, calling ``iter_virtual_packages("zope")`` might yield ``zope.app`` and ``zope.products`` (if they are virtual packages listed in ``sys.virtual_package_paths``), but **not** ``zope.foo.bar``. From e9448dbb41a3368b8b6c750007918d1465fcad73 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:38 +0100 Subject: [PATCH 076/173] PEP 391: Resolve uses of the default role (#3388) --- pep-0391.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pep-0391.txt b/pep-0391.txt index d6050e30f..407ecb4b4 100644 --- a/pep-0391.txt +++ b/pep-0391.txt @@ -383,7 +383,7 @@ Dictionary Schema - Detail The dictionary passed to ``dictConfig()`` must contain the following keys: -* `version` - to be set to an integer value representing the schema +* ``version`` - to be set to an integer value representing the schema version. The only valid value at present is 1, but having this key allows the schema to evolve while still preserving backwards compatibility. @@ -395,7 +395,7 @@ custom instantiation is required. If so, the mechanism described above is used to instantiate; otherwise, the context is used to determine how to instantiate. -* `formatters` - the corresponding value will be a dict in which each +* ``formatters`` - the corresponding value will be a dict in which each key is a formatter id and each value is a dict describing how to configure the corresponding Formatter instance. @@ -403,7 +403,7 @@ determine how to instantiate. (with defaults of ``None``) and these are used to construct a ``logging.Formatter`` instance. -* `filters` - the corresponding value will be a dict in which each key +* ``filters`` - the corresponding value will be a dict in which each key is a filter id and each value is a dict describing how to configure the corresponding Filter instance. @@ -411,7 +411,7 @@ determine how to instantiate. empty string) and this is used to construct a ``logging.Filter`` instance. -* `handlers` - the corresponding value will be a dict in which each +* ``handlers`` - the corresponding value will be a dict in which each key is a handler id and each value is a dict describing how to configure the corresponding Handler instance. @@ -451,7 +451,7 @@ determine how to instantiate. ``logging.handlers.RotatingFileHandler`` with the keyword arguments ``filename='logconfig.log', maxBytes=1024, backupCount=3``. -* `loggers` - the corresponding value will be a dict in which each key +* ``loggers`` - the corresponding value will be a dict in which each key is a logger name and each value is a dict describing how to configure the corresponding Logger instance. @@ -470,11 +470,11 @@ determine how to instantiate. The specified loggers will be configured according to the level, propagation, filters and handlers specified. -* `root` - this will be the configuration for the root logger. +* ``root`` - this will be the configuration for the root logger. Processing of the configuration will be as for any logger, except that the ``propagate`` setting will not be applicable. -* `incremental` - whether the configuration is to be interpreted as +* ``incremental`` - whether the configuration is to be interpreted as incremental to the existing configuration. This value defaults to ``False``, which means that the specified configuration replaces the existing configuration with the same semantics as used by the @@ -483,10 +483,10 @@ determine how to instantiate. If the specified value is ``True``, the configuration is processed as described in the section on `Incremental Configuration`_, below. -* `disable_existing_loggers` - whether any existing loggers are to be +* ``disable_existing_loggers`` - whether any existing loggers are to be disabled. This setting mirrors the parameter of the same name in ``fileConfig()``. If absent, this parameter defaults to ``True``. - This value is ignored if `incremental` is ``True``. + This value is ignored if ``incremental`` is ``True``. A Working Example ----------------- From 3ea21da044379568ec0698643f634b3616375612 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:41 +0100 Subject: [PATCH 077/173] PEP 431: Resolve uses of the default role (#3394) --- pep-0431.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0431.txt b/pep-0431.txt index 070e41eda..1b313bd14 100644 --- a/pep-0431.txt +++ b/pep-0431.txt @@ -188,13 +188,13 @@ This function takes a name string that must be a string specifying a valid zoneinfo time zone, i.e. "US/Eastern", "Europe/Warsaw" or "Etc/GMT". If not given, the local time zone will be looked up. If an invalid zone name is given, or the local time zone can not be retrieved, the function raises -`UnknownTimeZoneError`. +``UnknownTimeZoneError``. The function also takes an optional path to the location of the zoneinfo database which should be used. If not specified, the function will look for databases in the following order: -1. Check if the `tzdata-update` module is installed, and then use that +1. Check if the ``tzdata-update`` module is installed, and then use that database. 2. Use the database in ``/usr/share/zoneinfo``, if it exists. From a1a1346fb8b49fdf0e73262b0639dca34b0dde61 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:52 +0100 Subject: [PATCH 078/173] PEP 423: Resolve uses of the default role (#3392) --- pep-0423.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0423.txt b/pep-0423.txt index 094fef505..0eba9486c 100644 --- a/pep-0423.txt +++ b/pep-0423.txt @@ -631,7 +631,7 @@ already been registered: * in the `Python Standard Library`_. -* inside projects at `PyPI`. There is currently no helper for that. +* inside projects at ``PyPI``. There is currently no helper for that. Notice that the more projects follow the `use a single name`_ rule, the easier is the verification. From 5fcb01a22c637ea064095fcba17ac196ff1f8526 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:07 +0100 Subject: [PATCH 079/173] PEP 512: Resolve uses of the default role (#3399) --- pep-0512.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-0512.txt b/pep-0512.txt index ad6ffdce3..4284f089c 100644 --- a/pep-0512.txt +++ b/pep-0512.txt @@ -44,7 +44,7 @@ the basic steps were: Rietveld code review tool [#rietveld]_. 6. Download the patch to make sure it still applies cleanly. 7. Run the test suite manually. -8. Update the `NEWS`, `ACKS`, and "What's New" document as necessary +8. Update the ``NEWS``, ``ACKS``, and "What's New" document as necessary 9. Pull changes to avoid a merge race. 10. Commit the change manually. 11. If the change was for a bugfix release, merge into the @@ -240,7 +240,7 @@ in the Knights Who Say Ni project [#ni]_. Make old repository read-only ''''''''''''''''''''''''''''' -Updating `.hg/hgrc` in the now-old Mercurial repository in the `[hooks]` +Updating ``.hg/hgrc`` in the now-old Mercurial repository in the ``[hooks]`` section with:: pretxnchangegroup.reject = echo " * This repo has been migrated to github.com/python/peps and does not accept new commits in Mercurial!" 2>&1; exit 1 @@ -435,7 +435,7 @@ http://docs.openstack.org/developer/reno/. Discussions at the Sep 2016 Python core-dev sprints led to this decision compared to the rejected approaches outlined in the -`Rejected Ideas` section of this PEP. The separate files approach +``Rejected Ideas`` section of this PEP. The separate files approach seems to have the right balance of flexibility and potential tooling out of the various options while solving the motivating problem. @@ -772,7 +772,7 @@ Optional features: - `Link web content back to files that it is generated from`_ - `Handling Misc/NEWS`_ - `Bot to generate cherry-pick pull requests`_ - - Write `.github/CONTRIBUTING.md` + - Write ``.github/CONTRIBUTING.md`` (to prevent PRs that are inappropriate from even showing up and pointing to the devguide) From 27e9d905007fbd0e3bc6363c441666dd1e17ff6e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:20 +0100 Subject: [PATCH 080/173] PEP 447: Resolve uses of the default role (#3396) --- pep-0447.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0447.txt b/pep-0447.txt index ba04ecb31..626a54816 100644 --- a/pep-0447.txt +++ b/pep-0447.txt @@ -297,7 +297,7 @@ to ``tp_flags`` to indicate that new slot must be used. Use of this hook by the interpreter ----------------------------------- -The new method is required for metatypes and as such is defined on `type_`. +The new method is required for metatypes and as such is defined on ``type_``. Both ``super.__getattribute__`` and ``object.__getattribute__``/`PyObject_GenericGetAttr`_ (through ``_PyType_Lookup``) use the this ``__getdescriptor__`` method when From 47b79e09fe3eeb97d22c89dd9ee56cf13a8c4e71 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:29 +0100 Subject: [PATCH 081/173] PEP 499: Resolve uses of the default role (#3397) --- pep-0499.txt | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pep-0499.txt b/pep-0499.txt index 9cbf6f8c3..57568897f 100644 --- a/pep-0499.txt +++ b/pep-0499.txt @@ -182,29 +182,30 @@ Pickle compatibility If no changes are made to the pickle module, then pickles that were previously being written with the correct module name (due to a dual import) may start -being written with `__main__` as their module name instead, and hence fail to be -loaded correctly by other projects. +being written with ``__main__`` as their module name instead, and hence fail +to be loaded correctly by other projects. Scenarios to be checked: -* `python script.py` writing, `python -m script` reading -* `python -m script` writing, `python script.py` reading -* `python -m script` writing, `python some_other_app.py` reading -* `old_python -m script` writing, `new_python -m script` reading -* `new_python -m script` writing, `old_python -m script` reading +* ``python script.py`` writing, ``python -m script`` reading +* ``python -m script`` writing, ``python script.py`` reading +* ``python -m script`` writing, ``python some_other_app.py`` reading +* ``old_python -m script`` writing, ``new_python -m script`` reading +* ``new_python -m script`` writing, ``old_python -m script`` reading -Projects that special-case `__main__` -------------------------------------- +Projects that special-case ``__main__`` +--------------------------------------- In order to get the regression test suite to pass, the current reference -implementation had to patch `pdb` to avoid destroying its own global namespace. +implementation had to patch ``pdb`` to avoid destroying its own global +namespace. This suggests there may be a broader compatibility issue where some scripts are relying on direct execution and import giving different namespaces (just as -package execution keeps the two separate by executing the `__main__` submodule -in the `__main__` namespace, while the package name references the `__init__` -file as usual. +package execution keeps the two separate by executing the ``__main__`` +submodule in the ``__main__`` namespace, while the package name references +the ``__init__`` file as usual. Background @@ -219,7 +220,7 @@ module instance, not the running module instance. However, the problem has been around as long as the ``-m`` command line option and is encountered regularly, if infrequently, by others. -In addition to `issue 19702`_, the discrepancy around `__main__` +In addition to `issue 19702`_, the discrepancy around ``__main__`` is alluded to in :pep:`451` and a similar proposal (predating :pep:`451`) is described in :pep:`395` under :pep:`Fixing dual imports of the main module <395#fixing-dual-imports-of-the-main-module>`. From 96480c49e4f643fb0f0e82ac8f620994220cf7d5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:36 +0100 Subject: [PATCH 082/173] PEP 510: Resolve uses of the default role (#3398) --- pep-0510.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0510.txt b/pep-0510.txt index 70746c9ef..e96ba19e3 100644 --- a/pep-0510.txt +++ b/pep-0510.txt @@ -125,11 +125,11 @@ Hypothetical myoptimizer module Examples in this PEP uses a hypothetical ``myoptimizer`` module which provides the following functions and types: -* ``specialize(func, code, guards)``: add the specialized code `code` - with guards `guards` to the function `func` +* ``specialize(func, code, guards)``: add the specialized code ``code`` + with guards ``guards`` to the function ``func`` * ``get_specialized(func)``: get the list of specialized codes as a list - of ``(code, guards)`` tuples where `code` is a callable or code object - and `guards` is a list of a guards + of ``(code, guards)`` tuples where ``code`` is a callable or code object + and ``guards`` is a list of a guards * ``GuardBuiltins(name)``: guard watching for ``builtins.__dict__[name]`` and ``globals()[name]``. The guard fails if ``builtins.__dict__[name]`` is replaced, or if ``globals()[name]`` @@ -323,7 +323,7 @@ The ``check()`` function checks a guard: *stack* is an array of arguments: indexed arguments followed by (*key*, *value*) pairs of keyword arguments. *na* is the number of indexed arguments. *nk* is the number of keyword arguments: the number of (*key*, -*value*) pairs. `stack` contains ``na + nk * 2`` objects. +*value*) pairs. ``stack`` contains ``na + nk * 2`` objects. Specialized code From 76159afb05c3ef7045bb1101fc00ecc7942ed5c2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:45 +0100 Subject: [PATCH 083/173] PEP 3149: Resolve uses of the default role (#3401) --- pep-3149.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pep-3149.txt b/pep-3149.txt index a7d64707c..9d0f3a2ad 100644 --- a/pep-3149.txt +++ b/pep-3149.txt @@ -30,8 +30,8 @@ Background :pep:`3147` defined the file system layout for a pure-Python package, where multiple versions of Python are available on the system. For -example, where the `alpha` package containing source modules `one.py` -and `two.py` exist on a system with Python 3.2 and 3.3, the post-byte +example, where the ``alpha`` package containing source modules ``one.py`` +and ``two.py`` exist on a system with Python 3.2 and 3.3, the post-byte compilation file system layout would be:: alpha/ @@ -69,18 +69,18 @@ with Python 2.6 being the default. In order to share as much as possible between the available Python versions, these distributions install third party package modules -(``.pyc`` and ``.so`` files) into `/usr/share/pyshared` and symlink to -them from `/usr/lib/pythonX.Y/dist-packages`. The symlinks exist -because in a pre-:pep:`3147` world (i.e < Python 3.2), the `.pyc` files +(``.pyc`` and ``.so`` files) into ``/usr/share/pyshared`` and symlink to +them from ``/usr/lib/pythonX.Y/dist-packages``. The symlinks exist +because in a pre-:pep:`3147` world (i.e < Python 3.2), the ``.pyc`` files resulting from byte compilation by the various installed Pythons will name collide with each other. For Python versions >= 3.2, all -pure-Python packages can be shared, because the `.pyc` files will no +pure-Python packages can be shared, because the ``.pyc`` files will no longer cause file system naming conflicts. Eliminating these symlinks makes for a simpler, more robust Python distribution. A similar situation arises with shared library extensions. Because -extension modules are typically named `foo.so` for a `foo` extension -module, these would also name collide if `foo` was provided for more +extension modules are typically named ``foo.so`` for a ``foo`` extension +module, these would also name collide if ``foo`` was provided for more than one Python version. In addition, because different configuration/compilation options for @@ -93,7 +93,7 @@ module files. PyPy [5]_ can also benefit from this PEP, allowing it to avoid name collisions in extension modules built for its API, but with a -different `.so` tag. +different ``.so`` tag. Proposal @@ -139,7 +139,7 @@ Note that ``$SOABI`` contains just the tag, while ``$EXT_SUFFIX`` includes the platform extension for shared library files, and is the exact suffix added to the extension module name. -For an arbitrary package `foo`, you might see these files when the +For an arbitrary package ``foo``, you might see these files when the distribution package was installed:: /usr/lib/python/foo.cpython-32m.so @@ -159,7 +159,7 @@ This shared library tag would be used globally for all distutils-based extension modules, regardless of where on the file system they are built. Extension modules built by means other than distutils would either have to calculate the tag manually, or fallback to the -non-tagged `.so` file name. +non-tagged ``.so`` file name. Proven approach @@ -170,7 +170,7 @@ and Ubuntu system where different extensions are used for debug builds of Python and extension modules. Debug builds on Windows also already use a different file extension for dynamic libraries, and in fact encoded (in a different way than proposed in this PEP) the Python -major and minor version in the `.dll` file name. +major and minor version in the ``.dll`` file name. Windows @@ -207,7 +207,7 @@ its name. The prefix ``abi`` is reserved for Python's use. Thus, an initial implementation of :pep:`384`, when Python is configured with the default set of flags, would search for the following file -names when extension module `foo` is imported (in this order):: +names when extension module ``foo`` is imported (in this order):: foo.cpython-XYm.so foo.abi3.so @@ -271,7 +271,7 @@ If a pure-Python package is shared in one version, should it suddenly be not-shared if the next release adds an extension module for speed? Also, even though all extension shared libraries will be compiled and distributed once for every supported Python, there's a big difference -between duplicating the `.so` files and duplicating all `.py` files. +between duplicating the ``.so`` files and duplicating all ``.py`` files. The extra size increases the download time for such packages, and more immediately, increases the space pressures on already constrained distribution CD-ROMs. From 87d13e41698b610d397b6f07b002f66c7ce3081c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:51 +0100 Subject: [PATCH 084/173] PEP 516: Resolve uses of the default role (#3400) --- pep-0516.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pep-0516.txt b/pep-0516.txt index 241683f23..1f66518e1 100644 --- a/pep-0516.txt +++ b/pep-0516.txt @@ -216,9 +216,10 @@ develop [--prefix PREFIX] flit develop --root /tmp/ --prefix /usr/local - Should install scripts within `/tmp/usr/local/bin`, even if the Python - environment in use reports that the sys.prefix is `/usr/` which would lead - to using `/tmp/usr/bin/`. Similar logic applies for package files etc. + Should install scripts within ``/tmp/usr/local/bin``, even if the Python + environment in use reports that the sys.prefix is ``/usr/`` which would + lead to using ``/tmp/usr/bin/``. + Similar logic applies for package files etc. The build environment --------------------- @@ -307,15 +308,15 @@ When 'pip' reads this it would prepare an environment with flit in it before trying to use flit. Because flit doesn't have setup-requires support today, -`flit build_requires` would just output a constant string:: +``flit build_requires`` would just output a constant string:: {"build_requires": []} -`flit metadata` would interrogate `flit.ini` and marshal the metadata into +``flit metadata`` would interrogate ``flit.ini`` and marshal the metadata into a wheel METADATA file and output that on stdout. -`flit wheel` would need to accept a `-d` parameter that tells it where to output the -wheel (pip needs this). +``flit wheel`` would need to accept a ``-d`` parameter that tells it where to +output the wheel (pip needs this). Backwards Compatibility ======================= @@ -349,7 +350,7 @@ run by pip, and that will try and fail to install A. As such we recommend that tools which are currently used as setup-requires either ensure that they keep a `setuptools shim`_ or find their consumers and -get them all to upgrade to the use of a `pypa.json` in advance of moving +get them all to upgrade to the use of a ``pypa.json`` in advance of moving themselves. Pragmatically that is impossible, so the advice is to keep a setuptools shim indefinitely - both for projects like pbr, setuptools_scm and also projects like numpy. From 09e6c75fd891a4f6f15cbebb1dae0d509b93970f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:27:57 +0100 Subject: [PATCH 085/173] PEP 3151: Resolve uses of the default role (#3402) --- pep-3151.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-3151.txt b/pep-3151.txt index 21af2cd5f..e1ba710e2 100644 --- a/pep-3151.txt +++ b/pep-3151.txt @@ -695,7 +695,7 @@ Handling of PYTHONSTARTUP raises IOError (but the error gets discarded):: IOError: [Errno 2] No such file or directory: 'foox' ``PyObject_Print()`` raises IOError when ferror() signals an error on the -`FILE *` parameter (which, in the source tree, is always either stdout or +``FILE *`` parameter (which, in the source tree, is always either stdout or stderr). Unicode encoding and decoding using the ``mbcs`` encoding can raise From 8a318a54004c74dd52d2f194856ec2d1c1b722ee Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:28:04 +0100 Subject: [PATCH 086/173] PEP 440: Resolve uses of the default role (#3395) --- pep-0440.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pep-0440.txt b/pep-0440.txt index 05ef4df20..86a82ea1e 100644 --- a/pep-0440.txt +++ b/pep-0440.txt @@ -93,10 +93,10 @@ this scheme but MUST also include the normalizations specified below. Installation tools MAY warn the user when non-compliant or ambiguous versions are detected. -See also `Appendix B : Parsing version strings with regular expressions` which -provides a regular expression to check strict conformance with the canonical -format, as well as a more permissive regular expression accepting inputs that -may require subsequent normalization. +See also ``Appendix B : Parsing version strings with regular expressions`` +which provides a regular expression to check strict conformance with the +canonical format, as well as a more permissive regular expression accepting +inputs that may require subsequent normalization. Public version identifiers are separated into up to five segments: @@ -650,10 +650,10 @@ are permitted and MUST be ordered as shown:: .devN, aN, bN, rcN, , .postN -Note that `c` is considered to be semantically equivalent to `rc` and must be -sorted as if it were `rc`. Tools MAY reject the case of having the same ``N`` -for both a ``c`` and a ``rc`` in the same release segment as ambiguous and -remain in compliance with the PEP. +Note that ``c`` is considered to be semantically equivalent to ``rc`` and must +be sorted as if it were ``rc``. Tools MAY reject the case of having the same +``N`` for both a ``c`` and a ``rc`` in the same release segment as ambiguous +and remain in compliance with the PEP. Within an alpha (``1.0a1``), beta (``1.0b1``), or release candidate (``1.0rc1``, ``1.0c1``), the following suffixes are permitted and MUST be @@ -1296,7 +1296,7 @@ trailing ``\n`` character were found on PyPI. Various other normalisation rules were also added as described in the separate section on version normalisation below. -`Appendix A` shows detailed results of an analysis of PyPI distribution +``Appendix A`` shows detailed results of an analysis of PyPI distribution version information, as collected on 8th August, 2014. This analysis compares the behavior of the explicitly ordered version scheme defined in this PEP with the de facto standard defined by the behavior of setuptools. @@ -1599,7 +1599,7 @@ Metadata v2.0 guidelines versus setuptools:: Appendix B : Parsing version strings with regular expressions ============================================================= -As noted earlier in the `Public version identifiers` section, published +As noted earlier in the ``Public version identifiers`` section, published version identifiers SHOULD use the canonical format. This section provides regular expressions that can be used to test whether a version is already in that form, and if it's not, extract the various components for subsequent From cf42856db102a154190f2641513766bd289d7fcf Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:29:38 +0100 Subject: [PATCH 087/173] PEP 448: Resolve uses of the default role (#3403) --- pep-0448.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt index cd17a1a73..38721e8a3 100644 --- a/pep-0448.txt +++ b/pep-0448.txt @@ -198,7 +198,7 @@ are already valid. These could be extended to:: f(**x for x in it) == f({**x for x in it}) However, it wasn't clear if this was the best behaviour or if it should -unpack into the arguments of the call to `f`. Since this is likely to be +unpack into the arguments of the call to ``f``. Since this is likely to be confusing and is of only very marginal utility, it is not included in this PEP. Instead, these will throw a ``SyntaxError`` and comprehensions with explicit brackets should be used instead. @@ -224,7 +224,7 @@ References .. [1] PEP accepted, "PEP 448 review", Guido van Rossum (https://mail.python.org/pipermail/python-dev/2015-February/138564.html) -.. [2] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters +.. [2] Issue 2292, "Missing ``*``-unpacking generalizations", Thomas Wouters (https://github.com/python/cpython/issues/46545) [3] Discussion on Python-ideas list, From 2e3497b4bb5be2ca58017e9f82bbf78006b37f37 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:14 +0100 Subject: [PATCH 088/173] PEP 457: Resolve uses of the default role (#3404) --- pep-0457.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0457.txt b/pep-0457.txt index 7ce06c782..bc9730ec8 100644 --- a/pep-0457.txt +++ b/pep-0457.txt @@ -22,7 +22,7 @@ their position. This PEP is an Informational PEP describing the notation for use when describing APIs that use positional-only parameters (e.g. in Argument -Clinic, or in the string representation of `inspect.Signature` +Clinic, or in the string representation of ``inspect.Signature`` objects). A separate PEP, :pep:`570`, proposes elevation of this notation to full Python syntax. From e1e1a298020d8004bb3d7c53f4122ef0c5f742f7 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:24 +0100 Subject: [PATCH 089/173] PEP 459: Resolve uses of the default role (#3406) --- pep-0459.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0459.txt b/pep-0459.txt index 98399fa9d..74920f90d 100644 --- a/pep-0459.txt +++ b/pep-0459.txt @@ -22,7 +22,7 @@ PEP Withdrawal section in that PEP for details. In the meantime, metadata extensions will continue to be handled as they have been for past examples like ``entry_points.txt``: as additional files -installed into metadata directories alongside the main `METADATA` file. +installed into metadata directories alongside the main ``METADATA`` file. Abstract From 0e6087cfff30ee42740aaa4bfa418e4f7f929791 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:35 +0100 Subject: [PATCH 090/173] PEP 6: Resolve uses of the default role (#3367) --- pep-0006.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0006.txt b/pep-0006.txt index ca6a6e74c..fd5389929 100644 --- a/pep-0006.txt +++ b/pep-0006.txt @@ -45,7 +45,7 @@ Prohibitions Bug fix releases are required to adhere to the following restrictions: -1. There must be zero syntax changes. All `.pyc` and `.pyo` files must +1. There must be zero syntax changes. All ``.pyc`` and ``.pyo`` files must work (no regeneration needed) with all bugfix releases forked off from a major release. From 303c618638eb86b2aa1c7c007d93d4a904719cca Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:43 +0100 Subject: [PATCH 091/173] PEP 302: Resolve uses of the default role (#3369) --- pep-0302.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0302.txt b/pep-0302.txt index bdea0a363..29f9f799d 100644 --- a/pep-0302.txt +++ b/pep-0302.txt @@ -428,7 +428,7 @@ built-in import mechanism". They simply won't invoke any import hooks. A new if loader is not None: loader.load_module(fullname) -In the case of a "basic" import, one the `imp.find_module()` function would +In the case of a "basic" import, one the ``imp.find_module()`` function would handle, the loader object would be a wrapper for the current output of ``imp.find_module()``, and ``loader.load_module()`` would call ``imp.load_module()`` with that output. From 49abbcea975b8039390a957eb314821810764bc0 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:52 +0100 Subject: [PATCH 092/173] PEP 339: Resolve uses of the default role (#3373) --- pep-0339.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0339.txt b/pep-0339.txt index 18e97d023..434a159c4 100644 --- a/pep-0339.txt +++ b/pep-0339.txt @@ -550,7 +550,7 @@ References ---------- .. [Aho86] Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman. - `Compilers: Principles, Techniques, and Tools`, + ``Compilers: Principles, Techniques, and Tools``, http://www.amazon.com/exec/obidos/tg/detail/-/0201100886/104-0162389-6419108 .. [Wang97] Daniel C. Wang, Andrew W. Appel, Jeff L. Korn, and Chris From 2e87059c8eb47949d0376e486b2364976c3742b8 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:04 +0100 Subject: [PATCH 093/173] PEP 477: Resolve uses of the default role (#3409) --- pep-0477.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0477.txt b/pep-0477.txt index 4e8d81747..721bae141 100644 --- a/pep-0477.txt +++ b/pep-0477.txt @@ -105,7 +105,7 @@ module it is explicitly allowed for downstream distributors to patch the If a downstream distributor wishes to disable ``ensurepip`` completely in Python 2.7, they should still at least provide the module and allow -`python -m ensurepip` style invocation. However it should raise errors or +``python -m ensurepip`` style invocation. However it should raise errors or otherwise exit with a non-zero exit code and print out an error on stderr directing users to what they can/should use instead of ``ensurepip``. From dfc21e60622d933d315208eb78d5dacc6cba52b8 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:06 +0100 Subject: [PATCH 094/173] PEP 461: Resolve uses of the default role (#3407) --- pep-0461.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0461.txt b/pep-0461.txt index 5f4f4a1c9..09036768d 100644 --- a/pep-0461.txt +++ b/pep-0461.txt @@ -60,7 +60,7 @@ synonym for b). For the numeric codes, the only difference between ``str`` and ``bytes`` (or ``bytearray``) interpolation is that the results from these codes will be ASCII-encoded text, not unicode. In other words, for any numeric formatting -code `%x`:: +code ``%x``:: b"%x" % val From 3f39a801a15938216cfa24da13efbc625fee2a25 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:14 +0100 Subject: [PATCH 095/173] PEP 468: Resolve uses of the default role (#3408) --- pep-0468.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0468.txt b/pep-0468.txt index ea74c98d6..fec816e7f 100644 --- a/pep-0468.txt +++ b/pep-0468.txt @@ -201,7 +201,7 @@ idea regardless. (There is a reason those discussions were brief.) Relationship to inspect.Signature --------------------------------- -Signature objects should need no changes. The `kwargs` parameter of +Signature objects should need no changes. The ``kwargs`` parameter of inspect.BoundArguments (returned by Signature.bind() and Signature.bind_partial()) will change from a dict to an OrderedDict. @@ -321,7 +321,7 @@ application-level use of annotations. dict.__order__ -------------- -dict objects would have a new attribute, `__order__` that would default +dict objects would have a new attribute, ``__order__`` that would default to None and that in the kwargs case the interpreter would use in the same way as described above for __kworder__. @@ -329,13 +329,13 @@ Prognosis: It would mean zero impact on kwargs performance but the change would be pretty intrusive (Python uses dict a lot). Also, for the wrapper case -the interpreter would have to be careful to preserve `__order__`. +the interpreter would have to be careful to preserve ``__order__``. KWArgsDict.__order__ -------------------- -This is the same as the `dict.__order__` idea, but kwargs would be an -instance of a new minimal dict subclass that provides the `__order__` +This is the same as the ``dict.__order__`` idea, but kwargs would be an +instance of a new minimal dict subclass that provides the ``__order__`` attribute. dict would instead be unchanged. Prognosis: From ea57cc320cf9bd7e0c2c484f61c2a92690691465 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:21 +0100 Subject: [PATCH 096/173] PEP 485: Resolve uses of the default role (#3410) --- pep-0485.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0485.txt b/pep-0485.txt index 44caf0438..dd2bc3451 100644 --- a/pep-0485.txt +++ b/pep-0485.txt @@ -590,7 +590,7 @@ No absolute tolerance Given the issues with comparing to zero, another possibility would have been to only provide a relative tolerance, and let comparison to zero fail. In this case, the user would need to do a simple absolute -test: `abs(val) < zero_tol` in the case where the comparison involved +test: ``abs(val) < zero_tol`` in the case where the comparison involved zero. However, this would not allow the same call to be used for a sequence From 65191051cddfe31be054053d08bc174e74e5a0e2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:27 +0100 Subject: [PATCH 097/173] PEP 488: Resolve uses of the default role (#3411) --- pep-0488.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0488.txt b/pep-0488.txt index 4e5b876b7..4015d6721 100644 --- a/pep-0488.txt +++ b/pep-0488.txt @@ -48,7 +48,7 @@ of reading PYO files, this can lead to an interpreter using a mixture of optimization levels with its code if the user was not careful to make sure all PYO files were generated using the same optimization level (typically done by blindly deleting all PYO files and then -using the `compileall` module to compile all-new PYO files [1]_). +using the ``compileall`` module to compile all-new PYO files [1]_). This issue is only compounded when people optimize Python code beyond what the interpreter natively supports, e.g., using the astoptimizer project [2]_. @@ -76,7 +76,7 @@ To eliminate the ambiguity that PYO files present, this PEP proposes eliminating the concept of PYO files and their accompanying ``.pyo`` file extension. To allow for the optimization level to be unambiguous as well as to avoid having to regenerate optimized bytecode files -needlessly in the `__pycache__` directory, the optimization level +needlessly in the ``__pycache__`` directory, the optimization level used to generate the bytecode file will be incorporated into the bytecode file name. When no optimization level is specified, the pre-PEP ``.pyc`` file name will be used (i.e., no optimization level From c8346db3e62e729cb2327ebf080b609579419f27 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:32 +0100 Subject: [PATCH 098/173] PEP 493: Resolve uses of the default role (#3412) --- pep-0493.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0493.txt b/pep-0493.txt index a286091fa..0cf4c5341 100644 --- a/pep-0493.txt +++ b/pep-0493.txt @@ -52,7 +52,7 @@ offer options to switch off certificate checking entirely (by way of ``curl --insecure`` and ``wget --no-check-certificate``, respectively). At a different layer of the technology stack, Linux security modules like -`SELinux` and `AppArmor`, while enabled by default by distribution vendors, +``SELinux`` and ``AppArmor``, while enabled by default by distribution vendors, offer relatively straightforward mechanisms for turning them off. At the moment, no such convenient mechanisms exist to disable Python's @@ -121,8 +121,8 @@ or absence of the feature to be determined using the following technique:: python -c "import ssl; ssl.<_relevant_attribute>" -This will fail with `AttributeError` (and hence a non-zero return code) if the -relevant capability is not available. +This will fail with ``AttributeError`` (and hence a non-zero return code) if +the relevant capability is not available. The feature detection attributes defined by this PEP are: From fba94ce6c9a555a7b7de6ad6b8fca8c5e439886e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:31:42 +0100 Subject: [PATCH 099/173] PEP 425: Resolve uses of the default role (#3393) --- pep-0425.txt | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pep-0425.txt b/pep-0425.txt index e627d5c98..5037b576a 100644 --- a/pep-0425.txt +++ b/pep-0425.txt @@ -71,7 +71,7 @@ For example, the tag py27-none-any indicates compatible with Python 2.7 Use === -The `wheel` built package format includes these tags in its filenames, +The ``wheel`` built package format includes these tags in its filenames, of the form ``{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl``. Other package formats may have their own conventions. @@ -91,31 +91,31 @@ a distribution. Major implementations have abbreviated codes, initially: * pp: PyPy * jy: Jython -Other Python implementations should use `sys.implementation.name`. +Other Python implementations should use ``sys.implementation.name``. -The version is `py_version_nodot`. CPython gets away with no dot, -but if one is needed the underscore `_` is used instead. PyPy should -probably use its own versions here `pp18`, `pp19`. +The version is ``py_version_nodot``. CPython gets away with no dot, +but if one is needed the underscore ``_`` is used instead. PyPy should +probably use its own versions here ``pp18``, ``pp19``. -The version can be just the major version `2` or `3` `py2`, `py3` for +The version can be just the major version ``2`` or ``3`` ``py2``, ``py3`` for many pure-Python distributions. -Importantly, major-version-only tags like `py2` and `py3` are not -shorthand for `py20` and `py30`. Instead, these tags mean the packager +Importantly, major-version-only tags like ``py2`` and ``py3`` are not +shorthand for ``py20`` and ``py30``. Instead, these tags mean the packager intentionally released a cross-version-compatible distribution. A single-source Python 2/3 compatible distribution can use the compound -tag `py2.py3`. See `Compressed Tag Sets`, below. +tag ``py2.py3``. See ``Compressed Tag Sets``, below. ABI Tag ------- The ABI tag indicates which Python ABI is required by any included extension modules. For implementation-specific ABIs, the implementation -is abbreviated in the same way as the Python Tag, e.g. `cp33d` would be +is abbreviated in the same way as the Python Tag, e.g. ``cp33d`` would be the CPython 3.3 ABI with debugging. -The CPython stable ABI is `abi3` as in the shared library suffix. +The CPython stable ABI is ``abi3`` as in the shared library suffix. Implementations with a very unstable ABI may use the first 6 bytes (as 8 base64-encoded characters) of the SHA-256 hash of their source code @@ -126,8 +126,8 @@ decide how to best use the ABI tag. Platform Tag ------------ -The platform tag is simply `distutils.util.get_platform()` with all -hyphens `-` and periods `.` replaced with underscore `_`. +The platform tag is simply ``distutils.util.get_platform()`` with all +hyphens ``-`` and periods ``.`` replaced with underscore ``_``. * win32 * linux_i386 @@ -139,7 +139,7 @@ Use The tags are used by installers to decide which built distribution (if any) to download from a list of potential built distributions. The installer maintains a list of (pyver, abi, arch) tuples that it -will support. If the built distribution's tag is `in` the list, then +will support. If the built distribution's tag is ``in`` the list, then it can be installed. It is recommended that installers try to choose the most feature complete @@ -147,7 +147,7 @@ built distribution available (the one most specific to the installation environment) by default before falling back to pure Python versions published for older Python releases. Installers are also recommended to provide a way to configure and re-order the list of allowed compatibility -tags; for example, a user might accept only the `*-none-any` tags to only +tags; for example, a user might accept only the ``*-none-any`` tags to only download built packages that advertise themselves as being pure Python. Another desirable installer feature might be to include "re-compile from @@ -181,8 +181,8 @@ older version of Python): Sometimes there will be more than one supported built distribution for a particular version of a package. For example, a packager could release -a package tagged `cp33-abi3-linux_x86_64` that contains an optional C -extension and the same distribution tagged `py3-none-any` that does not. +a package tagged ``cp33-abi3-linux_x86_64`` that contains an optional C +extension and the same distribution tagged ``py3-none-any`` that does not. The index of the tag in the supported tags list breaks the tie, and the package with the C extension is installed in preference to the package without because that tag appears first in the list. @@ -194,7 +194,7 @@ To allow for compact filenames of bdists that work with more than one compatibility tag triple, each tag in a filename can instead be a '.'-separated, sorted, set of tags. For example, pip, a pure-Python package that is written to run under Python 2 and 3 with the same source -code, could distribute a bdist with the tag `py2.py3-none-any`. +code, could distribute a bdist with the tag ``py2.py3-none-any``. The full list of simple tags is:: for x in pytag.split('.'): @@ -212,8 +212,8 @@ FAQ What tags are used by default? Tools should use the most-preferred architecture dependent tag - e.g. `cp33-cp33m-win32` or the most-preferred pure python tag - e.g. `py33-none-any` by default. If the packager overrides the + e.g. ``cp33-cp33m-win32`` or the most-preferred pure python tag + e.g. ``py33-none-any`` by default. If the packager overrides the default it indicates that they intended to provide cross-Python compatibility. @@ -227,7 +227,7 @@ What tag do I use if my distribution uses a feature exclusive to the newest vers older release ``beaglevote-1.1.0`` that does not use the new feature, to get a compatible build. -Why isn't there a `.` in the Python version number? +Why isn't there a ``.`` in the Python version number? CPython has lasted 20+ years without a 3-digit major release. This should continue for some time. Other implementations may use _ as a delimiter, since both - and . delimit the surrounding filename. From 12326a933774e77187829d1fe93c77f0b4365165 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:32:10 +0100 Subject: [PATCH 100/173] PEP 458: Resolve uses of the default role (#3405) --- pep-0458.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0458.txt b/pep-0458.txt index b15d6a5aa..f16faab27 100644 --- a/pep-0458.txt +++ b/pep-0458.txt @@ -339,7 +339,7 @@ of pip going forward SHOULD use TUF by default to download and verify distributi from PyPI before installing them. However, there may be unforeseen issues that might prevent users from installing or updating distributions, including pip itself, via TUF. Therefore, pip SHOULD provide an option e.g., -`--unsafely-disable-package-verification`, in order to work around such issues +``--unsafely-disable-package-verification``, in order to work around such issues until they are resolved. Note, the proposed option name is purposefully long, because a user must be helped to understand that the action is unsafe and not generally recommended. @@ -722,9 +722,9 @@ overhead for returning and new users would be around 50-54% and 114% respectively, assuming that the number of bins stay fixed. If the number of bins is increased, then the cost for all users would effectively be the cost for new users, because their cost would be dominated by the (once-in-a-while) -cost of downloading the large number of delegations in the `bins` metadata. +cost of downloading the large number of delegations in the ``bins`` metadata. If the cost for new users should prove to be too much, primarily due to the -overhead of downloading the `bins` metadata, then this subject SHOULD be +overhead of downloading the ``bins`` metadata, then this subject SHOULD be revisited before that happens. Note that changes to the number of bins on the server are transparent to the From b0ef0274276348629a8fbc7d534fb8c64e6003e9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:32:22 +0100 Subject: [PATCH 101/173] PEP 495: Resolve uses of the default role (#3413) --- pep-0495.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0495.txt b/pep-0495.txt index d096cee35..dc88ca603 100644 --- a/pep-0495.txt +++ b/pep-0495.txt @@ -689,7 +689,7 @@ The following alternative names have also been considered: the original time is invalid. **which** - The `original`_ placeholder name for the `localtime` function + The `original`_ placeholder name for the ``localtime`` function branch index was `independently proposed`_ for the name of the disambiguation attribute and received `some support`_. From d285b1ae1d031eaf2dc367aa18e117529b6ce7fa Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:37:23 +0100 Subject: [PATCH 102/173] PEP 497: Resolve uses of the default role (#3414) --- pep-0497.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0497.txt b/pep-0497.txt index cfb857d41..18d352eb7 100644 --- a/pep-0497.txt +++ b/pep-0497.txt @@ -12,7 +12,7 @@ Created: 04-Aug-2015 Rejection Notice ================ -The steering council decided that the `__past__` aspect of this proposal +The steering council decided that the ``__past__`` aspect of this proposal was too complicated for the potential benefit. The other aspect of stronger requirements for backwards-compatibility should be addressed by :pep:`387`. From 678bc9b8d311cacc31ff3c388705c5ad1564d519 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:41:07 +0100 Subject: [PATCH 103/173] Lint: Enable pre-commit default role checks (#3415) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f03d60e0..df7e3625f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -79,15 +79,15 @@ repos: hooks: - id: rst-backticks name: "Check RST: No single backticks" - files: '^pep-\d\.txt|\.rst$' + files: '^pep-\d+\.(rst|txt)$' types: [text] - id: rst-inline-touching-normal name: "Check RST: No backticks touching text" - files: '^pep-\d+\.txt|\.rst$' + files: '^pep-\d+\.(rst|txt)$' types: [text] - id: rst-directive-colons name: "Check RST: 2 colons after directives" - files: '^pep-\d+\.txt|\.rst$' + files: '^pep-\d+\.(rst|txt)$' types: [text] # Manual codespell check From e7314c978bc852a99759cef7a58d91c825db0682 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Fri, 1 Sep 2023 21:54:33 +0100 Subject: [PATCH 104/173] PEP 725: Fix example using `project.optional-dependencies` (#3416) Correct the syntax used to specify optional runtime Python dependencies. --- pep-0725.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0725.rst b/pep-0725.rst index b031efd94..172afbd86 100644 --- a/pep-0725.rst +++ b/pep-0725.rst @@ -391,8 +391,8 @@ NAVis 1.4.0: .. code:: toml - [project] - optional-dependencies = ["rpy2"] + [project.optional-dependencies] + r = ["rpy2"] [external] build-requires = [ From 2d4c98dca777fceb88393c2635dca44d49cf7380 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 3 Sep 2023 04:55:19 +0100 Subject: [PATCH 105/173] Infra: Prepare for moving PEPs to a subfolder (#3417) --- .github/CODEOWNERS | 1 - conf.py | 10 +++-- .../parsing/pep_banner_directive.py | 1 - .../pep_processor/transforms/pep_footer.py | 40 ++++++++++--------- .../pep_theme/templates/page.html | 2 +- .../pep_zero_generator/pep_index_generator.py | 21 ++++++---- .../pep_zero_generator/subindices.py | 7 +++- .../pep_zero_generator/writer.py | 6 +-- pep_sphinx_extensions/tests/conftest.py | 3 ++ .../transform/test_pep_footer.py | 12 +++--- .../tests/pep_zero_generator/test_parser.py | 18 ++++----- .../test_pep_index_generator.py | 6 +-- 12 files changed, 71 insertions(+), 56 deletions(-) create mode 100644 pep_sphinx_extensions/tests/conftest.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4602dbe7b..5b02ed791 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,7 +12,6 @@ requirements.txt @AA-Turner infra/ @ewdurbin pep_sphinx_extensions/ @AA-Turner -AUTHOR_OVERRIDES.csv @AA-Turner build.py @AA-Turner conf.py @AA-Turner contents.rst @AA-Turner diff --git a/conf.py b/conf.py index 95a1debd4..b795aa874 100644 --- a/conf.py +++ b/conf.py @@ -3,10 +3,12 @@ """Configuration for building PEPs using Sphinx.""" +import os from pathlib import Path import sys -sys.path.append(str(Path(".").absolute())) +_ROOT = Path(__file__).resolve().parent +sys.path.append(os.fspath(_ROOT)) # -- Project information ----------------------------------------------------- @@ -60,11 +62,13 @@ intersphinx_disabled_reftypes = [] # -- Options for HTML output ------------------------------------------------- +_PSE_PATH = _ROOT / "pep_sphinx_extensions" + # HTML output settings html_math_renderer = "maths_to_html" # Maths rendering # Theme settings -html_theme_path = ["pep_sphinx_extensions"] +html_theme_path = [os.fspath(_PSE_PATH)] html_theme = "pep_theme" # The actual theme directory (child of html_theme_path) html_use_index = False # Disable index (we use PEP 0) html_style = "" # must be defined here or in theme.conf, but is unused @@ -72,4 +76,4 @@ html_permalinks = False # handled in the PEPContents transform html_baseurl = "https://peps.python.org" # to create the CNAME file gettext_auto_build = False # speed-ups -templates_path = ["pep_sphinx_extensions/pep_theme/templates"] # Theme template relative paths from `confdir` +templates_path = [os.fspath(_PSE_PATH / "pep_theme" / "templates")] # Theme template relative paths from `confdir` diff --git a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py index f3a55270c..d0f1cbee2 100644 --- a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py +++ b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py @@ -5,7 +5,6 @@ from __future__ import annotations from docutils import nodes from docutils.parsers import rst - PYPA_SPEC_BASE_URL = "https://packaging.python.org/en/latest/specifications/" diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py index 7b9c29d51..efd94ca36 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py @@ -1,4 +1,4 @@ -import datetime as dt +import time from pathlib import Path import subprocess @@ -23,7 +23,7 @@ class PEPFooter(transforms.Transform): def apply(self) -> None: pep_source_path = Path(self.document["source"]) - if not pep_source_path.match("pep-*"): + if not pep_source_path.match("pep-????.???"): return # not a PEP file, exit early # Iterate through sections from the end of the document @@ -62,12 +62,10 @@ def _add_source_link(pep_source_path: Path) -> nodes.paragraph: def _add_commit_history_info(pep_source_path: Path) -> nodes.paragraph: """Use local git history to find last modified date.""" try: - since_epoch = LAST_MODIFIED_TIMES[pep_source_path.name] + iso_time = _LAST_MODIFIED_TIMES[pep_source_path.stem] except KeyError: return nodes.paragraph() - epoch_dt = dt.datetime.fromtimestamp(since_epoch, dt.timezone.utc) - iso_time = epoch_dt.isoformat(sep=" ") commit_link = f"https://github.com/python/peps/commits/main/{pep_source_path.name}" link_node = nodes.reference("", f"{iso_time} GMT", refuri=commit_link) return nodes.paragraph("", "Last modified: ", link_node) @@ -75,29 +73,33 @@ def _add_commit_history_info(pep_source_path: Path) -> nodes.paragraph: def _get_last_modified_timestamps(): # get timestamps and changed files from all commits (without paging results) - args = ["git", "--no-pager", "log", "--format=#%at", "--name-only"] - with subprocess.Popen(args, stdout=subprocess.PIPE) as process: - all_modified = process.stdout.read().decode("utf-8") - process.stdout.close() - if process.wait(): # non-zero return code - return {} + args = ("git", "--no-pager", "log", "--format=#%at", "--name-only") + ret = subprocess.run(args, stdout=subprocess.PIPE, text=True, encoding="utf-8") + if ret.returncode: # non-zero return code + return {} + all_modified = ret.stdout # set up the dictionary with the *current* files - last_modified = {path.name: 0 for path in Path().glob("pep-*") if path.suffix in {".txt", ".rst"}} + peps_dir = Path(__file__, "..", "..", "..", "..").resolve() + last_modified = {path.stem: "" for path in peps_dir.glob("pep-????.???") if path.suffix in {".txt", ".rst"}} # iterate through newest to oldest, updating per file timestamps change_sets = all_modified.removeprefix("#").split("#") for change_set in change_sets: timestamp, files = change_set.split("\n", 1) for file in files.strip().split("\n"): - if file.startswith("pep-") and file[-3:] in {"txt", "rst"}: - if last_modified.get(file) == 0: - try: - last_modified[file] = float(timestamp) - except ValueError: - pass # if float conversion fails + if not file.startswith("pep-") or not file.endswith((".rst", ".txt")): + continue # not a PEP + file = file[:-4] + if last_modified.get(file) != "": + continue # most recent modified date already found + try: + y, m, d, hh, mm, ss, *_ = time.gmtime(float(timestamp)) + except ValueError: + continue # if float conversion fails + last_modified[file] = f"{y:04}-{m:02}-{d:02} {hh:02}:{mm:02}:{ss:02}" return last_modified -LAST_MODIFIED_TIMES = _get_last_modified_timestamps() +_LAST_MODIFIED_TIMES = _get_last_modified_timestamps() diff --git a/pep_sphinx_extensions/pep_theme/templates/page.html b/pep_sphinx_extensions/pep_theme/templates/page.html index 2831fce0c..8bd879c0f 100644 --- a/pep_sphinx_extensions/pep_theme/templates/page.html +++ b/pep_sphinx_extensions/pep_theme/templates/page.html @@ -43,7 +43,7 @@

Contents

{{ toc }}
- {%- if not (sourcename.startswith("pep-0000") or sourcename.startswith("topic")) %} + {%- if not sourcename.startswith(("pep-0000", "topic")) %} Page Source (GitHub) {%- endif %} diff --git a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py index e2c1a7963..0804b4aa6 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -18,22 +18,22 @@ to allow it to be processed as normal. from __future__ import annotations import json +import os from pathlib import Path from typing import TYPE_CHECKING -from pep_sphinx_extensions.pep_zero_generator.constants import SUBINDICES_BY_TOPIC from pep_sphinx_extensions.pep_zero_generator import parser from pep_sphinx_extensions.pep_zero_generator import subindices from pep_sphinx_extensions.pep_zero_generator import writer +from pep_sphinx_extensions.pep_zero_generator.constants import SUBINDICES_BY_TOPIC if TYPE_CHECKING: from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment -def _parse_peps() -> list[parser.PEP]: +def _parse_peps(path: Path) -> list[parser.PEP]: # Read from root directory - path = Path(".") peps: list[parser.PEP] = [] for file_path in path.iterdir(): @@ -52,8 +52,16 @@ def create_pep_json(peps: list[parser.PEP]) -> str: return json.dumps({pep.number: pep.full_details for pep in peps}, indent=1) +def write_peps_json(peps: list[parser.PEP], path: Path) -> None: + # Create peps.json + json_peps = create_pep_json(peps) + Path(path, "peps.json").write_text(json_peps, encoding="utf-8") + os.makedirs(os.path.join(path, "api"), exist_ok=True) + Path(path, "api", "peps.json").write_text(json_peps, encoding="utf-8") + + def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> None: - peps = _parse_peps() + peps = _parse_peps(Path(app.srcdir)) pep0_text = writer.PEPZeroWriter().write_pep0(peps, builder=env.settings["builder"]) pep0_path = subindices.update_sphinx("pep-0000", pep0_text, docnames, env) @@ -61,7 +69,4 @@ def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> subindices.generate_subindices(SUBINDICES_BY_TOPIC, peps, docnames, env) - # Create peps.json - json_path = Path(app.outdir, "api", "peps.json").resolve() - json_path.parent.mkdir(exist_ok=True) - json_path.write_text(create_pep_json(peps), encoding="utf-8") + write_peps_json(peps, Path(app.outdir)) diff --git a/pep_sphinx_extensions/pep_zero_generator/subindices.py b/pep_sphinx_extensions/pep_zero_generator/subindices.py index 455a49dd8..3f61b3dd4 100644 --- a/pep_sphinx_extensions/pep_zero_generator/subindices.py +++ b/pep_sphinx_extensions/pep_zero_generator/subindices.py @@ -2,6 +2,7 @@ from __future__ import annotations +import os from pathlib import Path from typing import TYPE_CHECKING @@ -14,8 +15,7 @@ if TYPE_CHECKING: def update_sphinx(filename: str, text: str, docnames: list[str], env: BuildEnvironment) -> Path: - file_path = Path(f"{filename}.rst").resolve() - file_path.parent.mkdir(parents=True, exist_ok=True) + file_path = Path(env.srcdir, f"{filename}.rst") file_path.write_text(text, encoding="utf-8") # Add to files for builder @@ -32,6 +32,9 @@ def generate_subindices( docnames: list[str], env: BuildEnvironment, ) -> None: + # create topic directory + os.makedirs(os.path.join(env.srcdir, "topic"), exist_ok=True) + # Create sub index page generate_topic_contents(docnames, env) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 02af0c8bd..69a5fe4bc 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -5,10 +5,8 @@ from __future__ import annotations from typing import TYPE_CHECKING import unicodedata -from pep_sphinx_extensions.pep_processor.transforms.pep_headers import ( - ABBREVIATED_STATUSES, - ABBREVIATED_TYPES, -) +from pep_sphinx_extensions.pep_processor.transforms.pep_headers import ABBREVIATED_STATUSES +from pep_sphinx_extensions.pep_processor.transforms.pep_headers import ABBREVIATED_TYPES from pep_sphinx_extensions.pep_zero_generator.constants import DEAD_STATUSES from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACCEPTED from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACTIVE diff --git a/pep_sphinx_extensions/tests/conftest.py b/pep_sphinx_extensions/tests/conftest.py new file mode 100644 index 000000000..e1417e08e --- /dev/null +++ b/pep_sphinx_extensions/tests/conftest.py @@ -0,0 +1,3 @@ +from pathlib import Path + +PEP_ROOT = Path(__file__, "..", "..", "..").resolve() diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py index ad8cf2782..6bd0cdca9 100644 --- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py +++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py @@ -1,16 +1,18 @@ -from pathlib import Path +import datetime as dt from pep_sphinx_extensions.pep_processor.transforms import pep_footer +from ...conftest import PEP_ROOT + def test_add_source_link(): - out = pep_footer._add_source_link(Path("pep-0008.txt")) + out = pep_footer._add_source_link(PEP_ROOT / "pep-0008.txt") assert "https://github.com/python/peps/blob/main/pep-0008.txt" in str(out) def test_add_commit_history_info(): - out = pep_footer._add_commit_history_info(Path("pep-0008.txt")) + out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-0008.txt") assert str(out).startswith( "Last modified: " @@ -21,7 +23,7 @@ def test_add_commit_history_info(): def test_add_commit_history_info_invalid(): - out = pep_footer._add_commit_history_info(Path("pep-not-found.txt")) + out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-not-found.rst") assert str(out) == "" @@ -31,4 +33,4 @@ def test_get_last_modified_timestamps(): assert len(out) >= 585 # Should be a Unix timestamp and at least this - assert out["pep-0008.txt"] >= 1643124055 + assert dt.datetime.fromisoformat(out["pep-0008"]).timestamp() >= 1643124055 diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index 2cba74df1..cea1d61ab 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -1,5 +1,3 @@ -from pathlib import Path - import pytest from pep_sphinx_extensions.pep_zero_generator import parser @@ -19,29 +17,31 @@ from pep_sphinx_extensions.pep_zero_generator.constants import ( ) from pep_sphinx_extensions.pep_zero_generator.parser import _Author +from ..conftest import PEP_ROOT + def test_pep_repr(): - pep8 = parser.PEP(Path("pep-0008.txt")) + pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") assert repr(pep8) == "" def test_pep_less_than(): - pep8 = parser.PEP(Path("pep-0008.txt")) - pep3333 = parser.PEP(Path("pep-3333.txt")) + pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep3333 = parser.PEP(PEP_ROOT / "pep-3333.txt") assert pep8 < pep3333 def test_pep_equal(): - pep_a = parser.PEP(Path("pep-0008.txt")) - pep_b = parser.PEP(Path("pep-0008.txt")) + pep_a = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep_b = parser.PEP(PEP_ROOT / "pep-0008.txt") assert pep_a == pep_b def test_pep_details(monkeypatch): - pep8 = parser.PEP(Path("pep-0008.txt")) + pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") assert pep8.details == { "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", @@ -106,7 +106,7 @@ def test_parse_authors_invalid(): ) def test_abbreviate_type_status(test_type, test_status, expected): # set up dummy PEP object and monkeypatch attributes - pep = parser.PEP(Path("pep-0008.txt")) + pep = parser.PEP(PEP_ROOT / "pep-0008.txt") pep.pep_type = test_type pep.status = test_status diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py index c2e15844f..e920d9773 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py @@ -1,10 +1,10 @@ -from pathlib import Path - from pep_sphinx_extensions.pep_zero_generator import parser, pep_index_generator +from ..conftest import PEP_ROOT + def test_create_pep_json(): - peps = [parser.PEP(Path("pep-0008.txt"))] + peps = [parser.PEP(PEP_ROOT / "pep-0008.txt")] out = pep_index_generator.create_pep_json(peps) From 497250afe0734181ae732218b8c24396bf55bd97 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 3 Sep 2023 22:08:42 +0100 Subject: [PATCH 106/173] Infra: Update documentation and ``build.py`` (#3420) - Always fail on warnings, remove the related flag - Nitpicky is now enabled in ``conf.py``, remove the related flag - Use direct links to PEPs rather than Sphinx-only ``:doc:`` roles - Remove references to ``AUTHOR_OVERRIDES.csv``, which is no longer used - Fix indentation for an enumerated list --- build.py | 34 ++++++++-------------------------- docs/build.rst | 38 ++++++-------------------------------- docs/rendering_system.rst | 22 ++++++++++------------ 3 files changed, 24 insertions(+), 70 deletions(-) diff --git a/build.py b/build.py index 8f0ead024..ebc3cf4aa 100755 --- a/build.py +++ b/build.py @@ -5,6 +5,7 @@ """Build script for Sphinx documentation""" import argparse +import os from pathlib import Path from sphinx.application import Sphinx @@ -27,15 +28,6 @@ def create_parser(): help='Render PEPs to "index.html" files within "pep-NNNN" directories. ' 'Cannot be used with "-f" or "-l".') - # flags / options - parser.add_argument("-w", "--fail-on-warning", action="store_true", - help="Fail the Sphinx build on any warning.") - parser.add_argument("-n", "--nitpicky", action="store_true", - help="Run Sphinx in 'nitpicky' mode, " - "warning on every missing reference target.") - parser.add_argument("-j", "--jobs", type=int, default=1, - help="How many parallel jobs to run (if supported). " - "Integer, default 1.") parser.add_argument( "-o", "--output-dir", @@ -61,33 +53,23 @@ def create_index_file(html_root: Path, builder: str) -> None: if __name__ == "__main__": args = create_parser() - root_directory = Path(".").absolute() + root_directory = Path(__file__).resolve().parent source_directory = root_directory build_directory = root_directory / args.output_dir - doctree_directory = build_directory / ".doctrees" # builder configuration - if args.builder is not None: - sphinx_builder = args.builder - else: - # default builder - sphinx_builder = "html" - - # other configuration - config_overrides = {} - if args.nitpicky: - config_overrides["nitpicky"] = True + sphinx_builder = args.builder or "html" app = Sphinx( source_directory, confdir=source_directory, - outdir=build_directory, - doctreedir=doctree_directory, + outdir=build_directory / sphinx_builder, + doctreedir=build_directory / "doctrees", buildername=sphinx_builder, - confoverrides=config_overrides, - warningiserror=args.fail_on_warning, - parallel=args.jobs, + warningiserror=True, + parallel=os.cpu_count() or 1, tags=["internal_builder"], + keep_going=True, ) app.build() diff --git a/docs/build.rst b/docs/build.rst index ae4ac1848..d59b2f804 100644 --- a/docs/build.rst +++ b/docs/build.rst @@ -1,5 +1,4 @@ -.. - Author: Adam Turner +:author: Adam Turner Building PEPs Locally @@ -10,8 +9,8 @@ This can also be used to check that the PEP is valid reStructuredText before submission to the PEP editors. The rest of this document assumes you are working from a local clone of the -`PEPs repository `__, with -**Python 3.9 or later** installed. +`PEPs repository `__, +with **Python 3.9 or later** installed. Render PEPs locally @@ -51,11 +50,6 @@ Render PEPs locally (venv) PS> python build.py - .. note:: - - There may be a series of warnings about unreferenced citations or labels. - Whilst these are valid warnings, they do not impact the build process. - 4. Navigate to the ``build`` directory of your PEPs repo to find the HTML pages. PEP 0 provides a formatted index, and may be a useful reference. @@ -87,28 +81,8 @@ Check the validity of links within PEP sources (runs the `Sphinx linkchecker .. code-block:: shell - python build.py --check-links - make check-links - - -Stricter rendering -'''''''''''''''''' - -Run in `nit-picky `__ -mode. -This generates warnings for all missing references. - -.. code-block:: shell - - python build.py --nitpicky - -Fail the build on any warning. -As of January 2022, there are around 250 warnings when building the PEPs. - -.. code-block:: shell - - python build.py --fail-on-warning - make fail-warning + python build.py --check-links + make check-links ``build.py`` usage @@ -118,4 +92,4 @@ For details on the command-line options to the ``build.py`` script, run: .. code-block:: shell - python build.py --help + python build.py --help diff --git a/docs/rendering_system.rst b/docs/rendering_system.rst index 9a298e0e8..83c077e7a 100644 --- a/docs/rendering_system.rst +++ b/docs/rendering_system.rst @@ -1,6 +1,6 @@ -.. - Author: Adam Turner +:author: Adam Turner +.. We can't use :pep:`N` references in this document, as they use links relative to the current file, which doesn't work in a subdirectory like this one. @@ -9,7 +9,7 @@ An Overview of the PEP Rendering System ======================================= This document provides an overview of the PEP rendering system, as a companion -to :doc:`PEP 676 <../pep-0676>`. +to `PEP 676 `__. 1. Configuration @@ -18,7 +18,7 @@ to :doc:`PEP 676 <../pep-0676>`. Configuration is stored in three files: - ``conf.py`` contains the majority of the Sphinx configuration -- ``contents.rst`` creates the Sphinx-mandated table of contents directive +- ``contents.rst`` contains the compulsory table of contents directive - ``pep_sphinx_extensions/pep_theme/theme.conf`` sets the Pygments themes The configuration: @@ -110,7 +110,8 @@ This overrides the built-in ``:pep:`` role to return the correct URL. 3.4.2 ``PEPHeaders`` transform ****************************** -PEPs start with a set of :rfc:`2822` headers, per :doc:`PEP 1 <../pep-0001>`. +PEPs start with a set of :rfc:`2822` headers, +per `PEP 1 `__. This transform validates that the required headers are present and of the correct data type, and removes headers not for display. It must run before the ``PEPTitle`` transform. @@ -122,7 +123,7 @@ It must run before the ``PEPTitle`` transform. We generate the title node from the parsed title in the PEP headers, and make all nodes in the document children of the new title node. This transform must also handle parsing reStructuredText markup within PEP -titles, such as :doc:`PEP 604 <../pep-0604>`. +titles, such as `PEP 604 `__. 3.4.4 ``PEPContents`` transform @@ -216,12 +217,9 @@ parse and validate that metadata. After collecting and validating all the PEP data, the index itself is created in three steps: - 1. Output the header text - 2. Output the category and numerical indices - 3. Output the author index - -The ``AUTHOR_OVERRIDES.csv`` file can be used to override an author's name in -the PEP 0 output. +1. Output the header text +2. Output the category and numerical indices +3. Output the author index We then add the newly created PEP 0 file to two Sphinx variables so that it will be processed as a normal source document. From fe3993d64a1288a57fd801591c0870f4ffc4441a Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 5 Sep 2023 03:40:47 +0100 Subject: [PATCH 107/173] PEP 499: Shorten the title (#3325) --- pep-0499.txt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/pep-0499.txt b/pep-0499.txt index 57568897f..8a4862af7 100644 --- a/pep-0499.txt +++ b/pep-0499.txt @@ -1,7 +1,5 @@ PEP: 499 -Title: ``python -m foo`` should bind ``sys.modules['foo']`` in addition to ``sys.modules['__main__']`` -Version: $Revision$ -Last-Modified: $Date$ +Title: ``python -m foo`` should also bind ``'foo'`` in ``sys.modules`` Author: Cameron Simpson , Chris Angelico , Joseph Jevnik BDFL-Delegate: Nick Coghlan Status: Deferred @@ -238,13 +236,3 @@ Copyright ========= This document has been placed in the public domain. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: From 814ceede975056cc56a019bbed62b29a6a875830 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 5 Sep 2023 04:44:46 +0100 Subject: [PATCH 108/173] Lint: Add ``check-peps.py`` (#3275) ``check-peps`` codifies the rules in PEP 1 and PEP 12 into a single place containing all of the PEP-specific checks. These are primarily header and metadata validation, and ensuring that direct links to RFCs and PEPs aren't used. Reviewed-by: Hugo van Kemenade Reviewed-by: C.A.M. Gerlach --- .github/CODEOWNERS | 1 + .github/workflows/lint.yml | 14 + .pre-commit-config.yaml | 8 + check-peps.py | 605 ++++++++++++++++++ pep_sphinx_extensions/generate_rss.py | 3 - pep_sphinx_extensions/tests/conftest.py | 11 +- .../tests/pep_lint/__init__.py | 0 .../tests/pep_lint/test_date.py | 105 +++ .../tests/pep_lint/test_direct_links.py | 30 + .../tests/pep_lint/test_email.py | 238 +++++++ .../tests/pep_lint/test_headers.py | 408 ++++++++++++ .../tests/pep_lint/test_pep_lint.py | 48 ++ .../tests/pep_lint/test_pep_number.py | 108 ++++ .../tests/pep_lint/test_post_url.py | 309 +++++++++ pep_sphinx_extensions/tests/peps/pep-9002.rst | 23 + pytest.ini | 10 +- 16 files changed, 1916 insertions(+), 5 deletions(-) create mode 100755 check-peps.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/__init__.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_date.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_direct_links.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_email.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_headers.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_pep_number.py create mode 100644 pep_sphinx_extensions/tests/pep_lint/test_post_url.py create mode 100644 pep_sphinx_extensions/tests/peps/pep-9002.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5b02ed791..cecf3d623 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,6 +20,7 @@ contents.rst @AA-Turner .codespell/ @CAM-Gerlach @hugovk .codespellrc @CAM-Gerlach @hugovk .pre-commit-config.yaml @CAM-Gerlach @hugovk +check-peps.py @AA-Turner @CAM-Gerlach @hugovk # Git infrastructure .gitattributes @CAM-Gerlach diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f5afc0740..37ccaee03 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -35,3 +35,17 @@ jobs: uses: pre-commit/action@v3.0.0 with: extra_args: --all-files --hook-stage manual codespell || true + + check-peps: + name: Run check-peps + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3 + uses: actions/setup-python@v4 + with: + python-version: "3" + + - name: Run check-peps + run: python check-peps.py --detailed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index df7e3625f..8775917c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -101,6 +101,14 @@ repos: # Local checks for PEP headers and more - repo: local hooks: +# # Hook to run "check-peps.py" +# - id: "check-peps" +# name: "Check PEPs for metadata and content enforcement" +# entry: "python check-peps.py" +# language: "system" +# files: "^pep-\d{4}\.(rst|txt)$" +# require_serial: true + - id: check-no-tabs name: "Check tabs not used in PEPs" language: pygrep diff --git a/check-peps.py b/check-peps.py new file mode 100755 index 000000000..623bdc040 --- /dev/null +++ b/check-peps.py @@ -0,0 +1,605 @@ +#!/usr/bin/env python3 + +# This file is placed in the public domain or under the +# CC0-1.0-Universal license, whichever is more permissive. + +"""check-peps: Check PEPs for common mistakes. + +Usage: check-peps [-d | --detailed] + +Only the PEPs specified are checked. +If none are specified, all PEPs are checked. + +Use "--detailed" to show the contents of lines where errors were found. +""" + +from __future__ import annotations + +import datetime as dt +import itertools +import re +import sys +from pathlib import Path + +TYPE_CHECKING = False +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator, KeysView, Sequence + from typing import TypeAlias + + # (line number, warning message) + Message: TypeAlias = tuple[int, str] + MessageIterator: TypeAlias = Iterator[Message] + + +# get the directory with the PEP sources +PEP_ROOT = Path(__file__).resolve().parent + +# See PEP 12 for the order +# Note we retain "BDFL-Delegate" +ALL_HEADERS = ( + "PEP", + "Title", + "Version", + "Last-Modified", + "Author", + "Sponsor", + "BDFL-Delegate", "PEP-Delegate", + "Discussions-To", + "Status", + "Type", + "Topic", + "Content-Type", + "Requires", + "Created", + "Python-Version", + "Post-History", + "Replaces", + "Superseded-By", + "Resolution", +) +REQUIRED_HEADERS = frozenset({"PEP", "Title", "Author", "Status", "Type", "Created"}) + +# See PEP 1 for the full list +ALL_STATUSES = frozenset({ + "Accepted", + "Active", + "April Fool!", + "Deferred", + "Draft", + "Final", + "Provisional", + "Rejected", + "Superseded", + "Withdrawn", +}) + +# PEPs that are allowed to link directly to PEPs +SKIP_DIRECT_PEP_LINK_CHECK = frozenset({"0009", "0287", "0676", "0684", "8001"}) + +DEFAULT_FLAGS = re.ASCII | re.IGNORECASE # Insensitive latin + +# any sequence of letters or '-', followed by a single ':' and a space or end of line +HEADER_PATTERN = re.compile(r"^([a-z\-]+):(?: |$)", DEFAULT_FLAGS) +# any sequence of unicode letters or legal special characters +NAME_PATTERN = re.compile(r"(?:[^\W\d_]|[ ',\-.])+(?: |$)") +# any sequence of ASCII letters, digits, or legal special characters +EMAIL_LOCAL_PART_PATTERN = re.compile(r"[\w!#$%&'*+\-/=?^{|}~.]+", DEFAULT_FLAGS) + +DISCOURSE_THREAD_PATTERN = re.compile(r"([\w\-]+/)?\d+", DEFAULT_FLAGS) +DISCOURSE_POST_PATTERN = re.compile(r"([\w\-]+/)?\d+(/\d+)?", DEFAULT_FLAGS) + +MAILMAN_2_PATTERN = re.compile(r"[\w\-]+/\d{4}-[a-z]+/\d+\.html", DEFAULT_FLAGS) +MAILMAN_3_THREAD_PATTERN = re.compile(r"[\w\-]+@python\.org/thread/[a-z0-9]+/?", DEFAULT_FLAGS) +MAILMAN_3_MESSAGE_PATTERN = re.compile(r"[\w\-]+@python\.org/message/[a-z0-9]+/?(#[a-z0-9]+)?", DEFAULT_FLAGS) + +# Controlled by the "--detailed" flag +DETAILED_ERRORS = False + + +def check(filenames: Sequence[str] = (), /) -> int: + """The main entry-point.""" + if filenames: + filenames = map(Path, filenames) + else: + filenames = itertools.chain(PEP_ROOT.glob("pep-????.txt"), PEP_ROOT.glob("pep-????.rst")) + if (count := sum(map(check_file, filenames))) > 0: + s = "s" * (count != 1) + print(f"check-peps failed: {count} error{s}", file=sys.stderr) + return 1 + return 0 + + +def check_file(filename: Path, /) -> int: + filename = filename.resolve() + try: + content = filename.read_text(encoding="utf-8") + except FileNotFoundError: + return _output_error(filename, [""], [(0, "Could not read PEP!")]) + else: + lines = content.splitlines() + return _output_error(filename, lines, check_peps(filename, lines)) + + +def check_peps(filename: Path, lines: Sequence[str], /) -> MessageIterator: + yield from check_headers(lines) + for line_num, line in enumerate(lines, start=1): + if filename.stem.removeprefix("pep-") in SKIP_DIRECT_PEP_LINK_CHECK: + continue + yield from check_direct_links(line_num, line.lstrip()) + + +def check_headers(lines: Sequence[str], /) -> MessageIterator: + yield from _validate_pep_number(next(iter(lines), "")) + + found_headers = {} + line_num = 0 + for line_num, line in enumerate(lines, start=1): + if line.strip() == "": + headers_end_line_num = line_num + break + if match := HEADER_PATTERN.match(line): + header = match[1] + if header in ALL_HEADERS: + if header not in found_headers: + found_headers[match[1]] = line_num + else: + yield line_num, f"Must not have duplicate header: {header} " + else: + yield line_num, f"Must not have invalid header: {header}" + else: + headers_end_line_num = line_num + + yield from _validate_required_headers(found_headers.keys()) + + shifted_line_nums = list(found_headers.values())[1:] + for i, (header, line_num) in enumerate(found_headers.items()): + start = line_num - 1 + end = headers_end_line_num - 1 + if i < len(found_headers) - 1: + end = shifted_line_nums[i] - 1 + remainder = "\n".join(lines[start:end]).removeprefix(f"{header}:") + if remainder != "": + if remainder[0] not in {" ", "\n"}: + yield line_num, f"Headers must have a space after the colon: {header}" + remainder = remainder.lstrip() + yield from _validate_header(header, line_num, remainder) + + +def _validate_header(header: str, line_num: int, content: str) -> MessageIterator: + if header == "Title": + yield from _validate_title(line_num, content) + elif header == "Author": + yield from _validate_author(line_num, content) + elif header == "Sponsor": + yield from _validate_sponsor(line_num, content) + elif header in {"BDFL-Delegate", "PEP-Delegate"}: + yield from _validate_delegate(line_num, content) + elif header == "Discussions-To": + yield from _validate_discussions_to(line_num, content) + elif header == "Status": + yield from _validate_status(line_num, content) + elif header == "Type": + yield from _validate_type(line_num, content) + elif header == "Topic": + yield from _validate_topic(line_num, content) + elif header == "Content-Type": + yield from _validate_content_type(line_num, content) + elif header in {"Requires", "Replaces", "Superseded-By"}: + yield from _validate_pep_references(line_num, content) + elif header == "Created": + yield from _validate_created(line_num, content) + elif header == "Python-Version": + yield from _validate_python_version(line_num, content) + elif header == "Post-History": + yield from _validate_post_history(line_num, content) + elif header == "Resolution": + yield from _validate_resolution(line_num, content) + + +def check_direct_links(line_num: int, line: str) -> MessageIterator: + """Check that PEPs and RFCs aren't linked directly""" + + line = line.lower() + if "dev/peps/pep-" in line or "peps.python.org/pep-" in line: + yield line_num, "Use the :pep:`NNN` role to refer to PEPs" + if "rfc-editor.org/rfc/" in line or "ietf.org/doc/html/rfc" in line: + yield line_num, "Use the :rfc:`NNN` role to refer to RFCs" + + +def _output_error(filename: Path, lines: Sequence[str], errors: Iterable[Message]) -> int: + relative_filename = filename.relative_to(PEP_ROOT) + err_count = 0 + for line_num, msg in errors: + err_count += 1 + + print(f"{relative_filename}:{line_num}: {msg}") + if not DETAILED_ERRORS: + continue + + line = lines[line_num - 1] + print(" |") + print(f"{line_num: >4} | '{line}'") + print(" |") + + return err_count + + +########################### +# PEP Header Validators # +########################### + + +def _validate_required_headers(found_headers: KeysView[str]) -> MessageIterator: + """PEPs must have all required headers, in the PEP 12 order""" + + if missing := REQUIRED_HEADERS.difference(found_headers): + for missing_header in sorted(missing, key=ALL_HEADERS.index): + yield 1, f"Must have required header: {missing_header}" + + ordered_headers = sorted(found_headers, key=ALL_HEADERS.index) + if list(found_headers) != ordered_headers: + order_str = ", ".join(ordered_headers) + yield 1, "Headers must be in PEP 12 order. Correct order: " + order_str + + +def _validate_pep_number(line: str) -> MessageIterator: + """'PEP' header must be a number 1-9999""" + + if not line.startswith("PEP: "): + yield 1, "PEP must begin with the 'PEP:' header" + return + + pep_number = line.removeprefix("PEP: ").lstrip() + yield from _pep_num(1, pep_number, "'PEP:' header") + + +def _validate_title(line_num: int, line: str) -> MessageIterator: + """'Title' must be 1-79 characters""" + + if len(line) == 0: + yield line_num, "PEP must have a title" + elif len(line) > 79: + yield line_num, "PEP title must be less than 80 characters" + + +def _validate_author(line_num: int, body: str) -> MessageIterator: + """'Author' must be list of 'Name , …'""" + + lines = body.split("\n") + for offset, line in enumerate(lines): + if offset >= 1 and line[:9].isspace(): + # Checks for: + # Author: Alice + # Bob + # ^^^^ + # Note that len("Author: ") == 8 + yield line_num + offset, "Author line must not be over-indented" + if offset < len(lines) - 1: + if not line.endswith(","): + yield line_num + offset, "Author continuation lines must end with a comma" + for part in line.removesuffix(",").split(", "): + yield from _email(line_num + offset, part, "Author") + + +def _validate_sponsor(line_num: int, line: str) -> MessageIterator: + """'Sponsor' must have format 'Name '""" + + yield from _email(line_num, line, "Sponsor") + + +def _validate_delegate(line_num: int, line: str) -> MessageIterator: + """'Delegate' must have format 'Name '""" + + if line == "": + return + + # PEP 451 + if ", " in line: + for part in line.removesuffix(",").split(", "): + yield from _email(line_num, part, "Delegate") + return + + yield from _email(line_num, line, "Delegate") + + +def _validate_discussions_to(line_num: int, line: str) -> MessageIterator: + """'Discussions-To' must be a thread URL""" + + yield from _thread(line_num, line, "Discussions-To", discussions_to=True) + if line.startswith("https://"): + return + for suffix in "@python.org", "@googlegroups.com": + if line.endswith(suffix): + remainder = line.removesuffix(suffix) + if re.fullmatch(r"[\w\-]+", remainder) is None: + yield line_num, "Discussions-To must be a valid mailing list" + return + yield line_num, "Discussions-To must be a valid thread URL or mailing list" + + +def _validate_status(line_num: int, line: str) -> MessageIterator: + """'Status' must be a valid PEP status""" + + if line not in ALL_STATUSES: + yield line_num, "Status must be a valid PEP status" + + +def _validate_type(line_num: int, line: str) -> MessageIterator: + """'Type' must be a valid PEP type""" + + if line not in {"Standards Track", "Informational", "Process"}: + yield line_num, "Type must be a valid PEP type" + + +def _validate_topic(line_num: int, line: str) -> MessageIterator: + """'Topic' must be for a valid sub-index""" + + topics = line.split(", ") + unique_topics = set(topics) + if len(topics) > len(unique_topics): + yield line_num, "Topic must not contain duplicates" + + if unique_topics - {"Governance", "Packaging", "Typing", "Release"}: + if not all(map(str.istitle, unique_topics)): + yield line_num, "Topic must be properly capitalised (Title Case)" + if unique_topics - {"governance", "packaging", "typing", "release"}: + yield line_num, "Topic must be for a valid sub-index" + if sorted(topics) != topics: + yield line_num, "Topic must be sorted lexicographically" + + +def _validate_content_type(line_num: int, line: str) -> MessageIterator: + """'Content-Type' must be 'text/x-rst'""" + + if line != "text/x-rst": + yield line_num, "Content-Type must be 'text/x-rst'" + + +def _validate_pep_references(line_num: int, line: str) -> MessageIterator: + """`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs""" + + line = line.removesuffix(",").rstrip() + if line.count(", ") != line.count(","): + yield line_num, "PEP references must be separated by comma-spaces (', ')" + return + + references = line.split(", ") + for reference in references: + yield from _pep_num(line_num, reference, "PEP reference") + + +def _validate_created(line_num: int, line: str) -> MessageIterator: + """'Created' must be a 'DD-mmm-YYYY' date""" + + yield from _date(line_num, line, "Created") + + +def _validate_python_version(line_num: int, line: str) -> MessageIterator: + """'Python-Version' must be an ``X.Y[.Z]`` version""" + + versions = line.split(", ") + for version in versions: + if version.count(".") not in {1, 2}: + yield line_num, f"Python-Version must have two or three segments: {version}" + continue + + try: + major, minor, micro = version.split(".", 2) + except ValueError: + major, minor = version.split(".", 1) + micro = "" + + if major not in "123": + yield line_num, f"Python-Version major part must be 1, 2, or 3: {version}" + if not _is_digits(minor) and minor != "x": + yield line_num, f"Python-Version minor part must be numeric: {version}" + elif minor != "0" and minor[0] == "0": + yield line_num, f"Python-Version minor part must not have leading zeros: {version}" + + if micro == "": + return + if minor == "x": + yield line_num, f"Python-Version micro part must be empty if minor part is 'x': {version}" + elif micro[0] == "0": + yield line_num, f"Python-Version micro part must not have leading zeros: {version}" + elif not _is_digits(micro): + yield line_num, f"Python-Version micro part must be numeric: {version}" + + +def _validate_post_history(line_num: int, body: str) -> MessageIterator: + """'Post-History' must be '`DD-mmm-YYYY `__, …'""" + + if body == "": + return + + for offset, line in enumerate(body.removesuffix(",").split("\n"), start=line_num): + for post in line.removesuffix(",").strip().split(", "): + if not post.startswith("`") and not post.endswith(">`__"): + yield from _date(offset, post, "Post-History") + else: + post_date, post_url = post[1:-4].split(" <") + yield from _date(offset, post_date, "Post-History") + yield from _thread(offset, post_url, "Post-History") + + +def _validate_resolution(line_num: int, line: str) -> MessageIterator: + """'Resolution' must be a direct thread/message URL""" + + yield from _thread(line_num, line, "Resolution", allow_message=True) + + +######################## +# Validation Helpers # +######################## + +def _pep_num(line_num: int, pep_number: str, prefix: str) -> MessageIterator: + if pep_number == "": + yield line_num, f"{prefix} must not be blank: {pep_number!r}" + return + if pep_number.startswith("0") and pep_number != "0": + yield line_num, f"{prefix} must not contain leading zeros: {pep_number!r}" + if not _is_digits(pep_number): + yield line_num, f"{prefix} must be numeric: {pep_number!r}" + elif not 0 <= int(pep_number) <= 9999: + yield line_num, f"{prefix} must be between 0 and 9999: {pep_number!r}" + + +def _is_digits(string: str) -> bool: + """Match a string of ASCII digits ([0-9]+).""" + return string.isascii() and string.isdigit() + + +def _email(line_num: int, author_email: str, prefix: str) -> MessageIterator: + author_email = author_email.strip() + + if author_email.count("<") > 1: + msg = f"{prefix} entries must not contain multiple '<': {author_email!r}" + yield line_num, msg + if author_email.count(">") > 1: + msg = f"{prefix} entries must not contain multiple '>': {author_email!r}" + yield line_num, msg + if author_email.count("@") > 1: + msg = f"{prefix} entries must not contain multiple '@': {author_email!r}" + yield line_num, msg + + author = author_email.split("<", 1)[0].rstrip() + if NAME_PATTERN.fullmatch(author) is None: + msg = f"{prefix} entries must begin with a valid 'Name': {author_email!r}" + yield line_num, msg + return + + email_text = author_email.removeprefix(author) + if not email_text: + # Does not have the optional email part + return + + if not email_text.startswith(" <") or not email_text.endswith(">"): + msg = f"{prefix} entries must be formatted as 'Name ': {author_email!r}" + yield line_num, msg + email_text = email_text.removeprefix(" <").removesuffix(">") + + if "@" in email_text: + local, domain = email_text.rsplit("@", 1) + elif " at " in email_text: + local, domain = email_text.rsplit(" at ", 1) + else: + yield line_num, f"{prefix} entries must contain a valid email address: {author_email!r}" + return + if EMAIL_LOCAL_PART_PATTERN.fullmatch(local) is None or _invalid_domain(domain): + yield line_num, f"{prefix} entries must contain a valid email address: {author_email!r}" + + +def _invalid_domain(domain_part: str) -> bool: + *labels, root = domain_part.split(".") + for label in labels: + if not label.replace("-", "").isalnum(): + return True + return not root.isalnum() or not root.isascii() + + +def _thread(line_num: int, url: str, prefix: str, *, allow_message: bool = False, discussions_to: bool = False) -> MessageIterator: + if allow_message and discussions_to: + msg = "allow_message and discussions_to cannot both be True" + raise ValueError(msg) + + msg = f"{prefix} must be a valid thread URL" + + if not url.startswith("https://"): + if not discussions_to: + yield line_num, msg + return + + if url.startswith("https://discuss.python.org/t/"): + remainder = url.removeprefix("https://discuss.python.org/t/").removesuffix("/") + + # Discussions-To links must be the thread itself, not a post + if discussions_to: + # The equivalent pattern is similar to '([\w\-]+/)?\d+', + # but the topic name must contain a non-numeric character + + # We use ``str.rpartition`` as the topic name is optional + topic_name, _, topic_id = remainder.rpartition("/") + if topic_name == '' and _is_digits(topic_id): + return + topic_name = topic_name.replace("-", "0").replace("_", "0") + # the topic name must not be entirely numeric + valid_topic_name = not _is_digits(topic_name) and topic_name.isalnum() + if valid_topic_name and _is_digits(topic_id): + return + else: + # The equivalent pattern is similar to '([\w\-]+/)?\d+(/\d+)?', + # but the topic name must contain a non-numeric character + if remainder.count("/") == 2: + # When there are three parts, the URL must be "topic-name/topic-id/post-id". + topic_name, topic_id, post_id = remainder.rsplit("/", 2) + topic_name = topic_name.replace("-", "0").replace("_", "0") + valid_topic_name = not _is_digits(topic_name) and topic_name.isalnum() + if valid_topic_name and _is_digits(topic_id) and _is_digits(post_id): + # the topic name must not be entirely numeric + return + elif remainder.count("/") == 1: + # When there are only two parts, there's an ambiguity between + # "topic-name/topic-id" and "topic-id/post-id". + # We disambiguate by checking if the LHS is a valid name and + # the RHS is a valid topic ID (for the former), + # and then if both the LHS and RHS are valid IDs (for the latter). + left, right = remainder.rsplit("/") + left = left.replace("-", "0").replace("_", "0") + # the topic name must not be entirely numeric + left_is_name = not _is_digits(left) and left.isalnum() + if left_is_name and _is_digits(right): + return + elif _is_digits(left) and _is_digits(right): + return + else: + # When there's only one part, it must be a valid topic ID. + if _is_digits(remainder): + return + + if url.startswith("https://mail.python.org/pipermail/"): + remainder = url.removeprefix("https://mail.python.org/pipermail/") + if MAILMAN_2_PATTERN.fullmatch(remainder) is not None: + return + + if url.startswith("https://mail.python.org/archives/list/"): + remainder = url.removeprefix("https://mail.python.org/archives/list/") + if allow_message and MAILMAN_3_MESSAGE_PATTERN.fullmatch(remainder) is not None: + return + if MAILMAN_3_THREAD_PATTERN.fullmatch(remainder) is not None: + return + + yield line_num, msg + + +def _date(line_num: int, date_str: str, prefix: str) -> MessageIterator: + try: + parsed_date = dt.datetime.strptime(date_str, "%d-%b-%Y") + except ValueError: + yield line_num, f"{prefix} must be a 'DD-mmm-YYYY' date: {date_str!r}" + return + else: + if date_str[1] == "-": # Date must be zero-padded + yield line_num, f"{prefix} must be a 'DD-mmm-YYYY' date: {date_str!r}" + return + + if parsed_date.year < 1990: + yield line_num, f"{prefix} must not be before Python was invented: {date_str!r}" + if parsed_date > (dt.datetime.now() + dt.timedelta(days=14)): + yield line_num, f"{prefix} must not be in the future: {date_str!r}" + + +if __name__ == "__main__": + if {"-h", "--help", "-?"}.intersection(sys.argv[1:]): + print(__doc__, file=sys.stderr) + raise SystemExit(0) + + files = {} + for arg in sys.argv[1:]: + if not arg.startswith("-"): + files[arg] = None + elif arg in {"-d", "--detailed"}: + DETAILED_ERRORS = True + else: + print(f"Unknown option: {arg!r}", file=sys.stderr) + raise SystemExit(1) + raise SystemExit(check(files)) diff --git a/pep_sphinx_extensions/generate_rss.py b/pep_sphinx_extensions/generate_rss.py index a7120c9d6..5e5e0b8bc 100644 --- a/pep_sphinx_extensions/generate_rss.py +++ b/pep_sphinx_extensions/generate_rss.py @@ -17,9 +17,6 @@ RSS_DESCRIPTION = ( "and some meta-information like release procedure and schedules." ) -# get the directory with the PEP sources -PEP_ROOT = Path(__file__).parent - def _format_rfc_2822(datetime: dt.datetime) -> str: datetime = datetime.replace(tzinfo=dt.timezone.utc) diff --git a/pep_sphinx_extensions/tests/conftest.py b/pep_sphinx_extensions/tests/conftest.py index e1417e08e..2c207ebcd 100644 --- a/pep_sphinx_extensions/tests/conftest.py +++ b/pep_sphinx_extensions/tests/conftest.py @@ -1,3 +1,12 @@ +import importlib.util +import sys from pathlib import Path -PEP_ROOT = Path(__file__, "..", "..", "..").resolve() +_ROOT_PATH = Path(__file__, "..", "..", "..").resolve() +PEP_ROOT = _ROOT_PATH + +# Import "check-peps.py" as "check_peps" +CHECK_PEPS_PATH = _ROOT_PATH / "check-peps.py" +spec = importlib.util.spec_from_file_location("check_peps", CHECK_PEPS_PATH) +sys.modules["check_peps"] = check_peps = importlib.util.module_from_spec(spec) +spec.loader.exec_module(check_peps) diff --git a/pep_sphinx_extensions/tests/pep_lint/__init__.py b/pep_sphinx_extensions/tests/pep_lint/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pep_sphinx_extensions/tests/pep_lint/test_date.py b/pep_sphinx_extensions/tests/pep_lint/test_date.py new file mode 100644 index 000000000..3ce466610 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_date.py @@ -0,0 +1,105 @@ +import datetime as dt + +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + "line", + [ + # valid entries + "01-Jan-2000", + "29-Feb-2016", + "31-Dec-2000", + "01-Apr-2003", + "01-Apr-2007", + "01-Apr-2009", + "01-Jan-1990", + ], +) +def test_validate_created(line: str): + warnings = [warning for (_, warning) in check_peps._validate_created(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "date_str", + [ + # valid entries + "01-Jan-2000", + "29-Feb-2016", + "31-Dec-2000", + "01-Apr-2003", + "01-Apr-2007", + "01-Apr-2009", + "01-Jan-1990", + ], +) +def test_date_checker_valid(date_str: str): + warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "date_str", + [ + # malformed + "2000-01-01", + "01 January 2000", + "1 Jan 2000", + "1-Jan-2000", + "1-January-2000", + "Jan-1-2000", + "January 1 2000", + "January 01 2000", + "01/01/2000", + "01/Jan/2000", # 🇬🇧, 🇦🇺, 🇨🇦, 🇳🇿, 🇮🇪 , ... + "Jan/01/2000", # 🇺🇸 + "1st January 2000", + "The First day of January in the year of Our Lord Two Thousand", + "Jan, 1, 2000", + "2000-Jan-1", + "2000-Jan-01", + "2000-January-1", + "2000-January-01", + "00 Jan 2000", + "00-Jan-2000", + ], +) +def test_date_checker_malformed(date_str: str): + warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")] + expected = f" must be a 'DD-mmm-YYYY' date: {date_str!r}" + assert warnings == [expected], warnings + + +@pytest.mark.parametrize( + "date_str", + [ + # too early + "31-Dec-1989", + "01-Apr-1916", + "01-Jan-0020", + "01-Jan-0023", + ], +) +def test_date_checker_too_early(date_str: str): + warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")] + expected = f" must not be before Python was invented: {date_str!r}" + assert warnings == [expected], warnings + + +@pytest.mark.parametrize( + "date_str", + [ + # the future + "31-Dec-2999", + "01-Jan-2100", + "01-Jan-2100", + (dt.datetime.now() + dt.timedelta(days=15)).strftime("%d-%b-%Y"), + (dt.datetime.now() + dt.timedelta(days=100)).strftime("%d-%b-%Y"), + ], +) +def test_date_checker_too_late(date_str: str): + warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")] + expected = f" must not be in the future: {date_str!r}" + assert warnings == [expected], warnings diff --git a/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py b/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py new file mode 100644 index 000000000..66edc0552 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py @@ -0,0 +1,30 @@ +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + "line", + [ + "http://www.python.org/dev/peps/pep-0000/", + "https://www.python.org/dev/peps/pep-0000/", + "http://peps.python.org/pep-0000/", + "https://peps.python.org/pep-0000/", + ], +) +def test_check_direct_links_pep(line: str): + warnings = [warning for (_, warning) in check_peps.check_direct_links(1, line)] + assert warnings == ["Use the :pep:`NNN` role to refer to PEPs"], warnings + + +@pytest.mark.parametrize( + "line", + [ + "http://www.rfc-editor.org/rfc/rfc2324", + "https://www.rfc-editor.org/rfc/rfc2324", + "http://datatracker.ietf.org/doc/html/rfc2324", + "https://datatracker.ietf.org/doc/html/rfc2324", + ], +) +def test_check_direct_links_rfc(line: str): + warnings = [warning for (_, warning) in check_peps.check_direct_links(1, line)] + assert warnings == ["Use the :rfc:`NNN` role to refer to RFCs"], warnings diff --git a/pep_sphinx_extensions/tests/pep_lint/test_email.py b/pep_sphinx_extensions/tests/pep_lint/test_email.py new file mode 100644 index 000000000..2ff4ba61f --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_email.py @@ -0,0 +1,238 @@ +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + "line", + [ + "Alice", + "Alice,", + "Alice, Bob, Charlie", + "Alice,\nBob,\nCharlie", + "Alice,\n Bob,\n Charlie", + "Alice,\n Bob,\n Charlie", + "Cardinal Ximénez", + "Alice ", + "Cardinal Ximénez ", + ], + ids=repr, # the default calls str and renders newlines. +) +def test_validate_author(line: str): + warnings = [warning for (_, warning) in check_peps._validate_author(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "Alice,\n Bob,\n Charlie", + "Alice,\n Bob,\n Charlie", + "Alice,\n Bob,\n Charlie", + "Alice,\n Bob", + ], + ids=repr, # the default calls str and renders newlines. +) +def test_validate_author_over__indented(line: str): + warnings = [warning for (_, warning) in check_peps._validate_author(1, line)] + assert {*warnings} == {"Author line must not be over-indented"}, warnings + + +@pytest.mark.parametrize( + "line", + [ + "Cardinal Ximénez\nCardinal Biggles\nCardinal Fang", + "Cardinal Ximénez,\nCardinal Biggles\nCardinal Fang", + "Cardinal Ximénez\nCardinal Biggles,\nCardinal Fang", + ], + ids=repr, # the default calls str and renders newlines. +) +def test_validate_author_continuation(line: str): + warnings = [warning for (_, warning) in check_peps._validate_author(1, line)] + assert {*warnings} == {"Author continuation lines must end with a comma"}, warnings + + +@pytest.mark.parametrize( + "line", + [ + "Alice", + "Cardinal Ximénez", + "Alice ", + "Cardinal Ximénez ", + ], +) +def test_validate_sponsor(line: str): + warnings = [warning for (_, warning) in check_peps._validate_sponsor(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "", + "Alice, Bob, Charlie", + "Alice, Bob, Charlie,", + "Alice ", + "Cardinal Ximénez ", + ], +) +def test_validate_delegate(line: str): + warnings = [warning for (_, warning) in check_peps._validate_delegate(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + ("email", "expected_warnings"), + [ + # ... entries must not contain multiple '...' + ("Cardinal Ximénez <<", {"multiple <"}), + ("Cardinal Ximénez <<<", {"multiple <"}), + ("Cardinal Ximénez >>", {"multiple >"}), + ("Cardinal Ximénez >>>", {"multiple >"}), + ("Cardinal Ximénez <<<>>>", {"multiple <", "multiple >"}), + ("Cardinal Ximénez @@", {"multiple @"}), + ("Cardinal Ximénez <<@@@>", {"multiple <", "multiple @"}), + ("Cardinal Ximénez <@@@>>", {"multiple >", "multiple @"}), + ("Cardinal Ximénez <<@@>>", {"multiple <", "multiple >", "multiple @"}), + # valid names + ("Cardinal Ximénez", set()), + (" Cardinal Ximénez", set()), + ("\t\tCardinal Ximénez", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez\t\t", set()), + ("Cardinal O'Ximénez", set()), + ("Cardinal Ximénez, Inquisitor", set()), + ("Cardinal Ximénez-Biggles", set()), + ("Cardinal Ximénez-Biggles, Inquisitor", set()), + ("Cardinal T. S. I. Ximénez", set()), + # ... entries must have a valid 'Name' + ("Cardinal_Ximénez", {"valid name"}), + ("Cardinal Ximénez 3", {"valid name"}), + ("~ Cardinal Ximénez ~", {"valid name"}), + ("Cardinal Ximénez!", {"valid name"}), + ("@Cardinal Ximénez", {"valid name"}), + ("Cardinal_Ximénez <>", {"valid name"}), + ("Cardinal Ximénez 3 <>", {"valid name"}), + ("~ Cardinal Ximénez ~ <>", {"valid name"}), + ("Cardinal Ximénez! <>", {"valid name"}), + ("@Cardinal Ximénez <>", {"valid name"}), + # ... entries must be formatted as 'Name ' + ("Cardinal Ximénez<>", {"name "}), + ("Cardinal Ximénez<", {"name "}), + ("Cardinal Ximénez <", {"name "}), + ("Cardinal Ximénez <", {"name "}), + ("Cardinal Ximénez <>", {"name "}), + # ... entries must contain a valid email address (missing) + ("Cardinal Ximénez <>", {"valid email"}), + ("Cardinal Ximénez <> ", {"valid email"}), + ("Cardinal Ximénez <@> ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez < at > ", {"valid email"}), + # ... entries must contain a valid email address (local) + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez < Cardinal Ximenez @spanish.inquisition> ", {"valid email"}), + ("Cardinal Ximénez <(Cardinal.Ximenez)@spanish.inquisition>", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ( + "Cardinal Ximénez ", + {"multiple <", "multiple >", "valid email"}, + ), + ( + "Cardinal Ximénez ", + {"multiple @", "valid email"}, + ), + (r"Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez <[Cardinal.Ximenez]@spanish.inquisition>", {"valid email"}), + ('Cardinal Ximénez <"Cardinal"Ximenez"@spanish.inquisition>', {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + # ... entries must contain a valid email address (domain) + ( + "Cardinal Ximénez ", + {"valid email"}, + ), + ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximénez ", {"valid email"}), + ( + "Cardinal Ximénez ", + {"valid email"}, + ), + # valid name-emails + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez <{Cardinal.Ximenez}@spanish.inquisition>", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ("Cardinal Ximénez ", set()), + ], + # call str() on each parameterised value in the test ID. + ids=str, +) +def test_email_checker(email: str, expected_warnings: set): + warnings = [warning for (_, warning) in check_peps._email(1, email, "")] + + found_warnings = set() + email = email.strip() + + if "multiple <" in expected_warnings: + found_warnings.add("multiple <") + expected = f" entries must not contain multiple '<': {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "multiple >" in expected_warnings: + found_warnings.add("multiple >") + expected = f" entries must not contain multiple '>': {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "multiple @" in expected_warnings: + found_warnings.add("multiple @") + expected = f" entries must not contain multiple '@': {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "valid name" in expected_warnings: + found_warnings.add("valid name") + expected = f" entries must begin with a valid 'Name': {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "name " in expected_warnings: + found_warnings.add("name ") + expected = f" entries must be formatted as 'Name ': {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "valid email" in expected_warnings: + found_warnings.add("valid email") + expected = f" entries must contain a valid email address: {email!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if expected_warnings == set(): + assert warnings == [], warnings + + assert found_warnings == expected_warnings diff --git a/pep_sphinx_extensions/tests/pep_lint/test_headers.py b/pep_sphinx_extensions/tests/pep_lint/test_headers.py new file mode 100644 index 000000000..8246271e3 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_headers.py @@ -0,0 +1,408 @@ +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + ("test_input", "expected"), + [ + # capitalisation + ("Header:", "Header"), + ("header:", "header"), + ("hEADER:", "hEADER"), + ("hEaDeR:", "hEaDeR"), + # trailing spaces + ("Header: ", "Header"), + ("Header: ", "Header"), + ("Header: \t", "Header"), + # trailing content + ("Header: Text", "Header"), + ("Header: 123", "Header"), + ("Header: !", "Header"), + # separators + ("Hyphenated-Header:", "Hyphenated-Header"), + ], +) +def test_header_pattern(test_input, expected): + assert check_peps.HEADER_PATTERN.match(test_input)[1] == expected + + +@pytest.mark.parametrize( + "test_input", + [ + # trailing content + "Header:Text", + "Header:123", + "Header:!", + # colon position + "Header", + "Header : ", + "Header :", + "SemiColonHeader;", + # separators + "Underscored_Header:", + "Spaced Header:", + "Plus+Header:", + ], +) +def test_header_pattern_no_match(test_input): + assert check_peps.HEADER_PATTERN.match(test_input) is None + + +def test_validate_required_headers(): + found_headers = dict.fromkeys( + ("PEP", "Title", "Author", "Status", "Type", "Created") + ) + warnings = [ + warning for (_, warning) in check_peps._validate_required_headers(found_headers) + ] + assert warnings == [], warnings + + +def test_validate_required_headers_missing(): + found_headers = dict.fromkeys(("PEP", "Title", "Author", "Type")) + warnings = [ + warning for (_, warning) in check_peps._validate_required_headers(found_headers) + ] + assert warnings == [ + "Must have required header: Status", + "Must have required header: Created", + ], warnings + + +def test_validate_required_headers_order(): + found_headers = dict.fromkeys( + ("PEP", "Title", "Sponsor", "Author", "Type", "Status", "Replaces", "Created") + ) + warnings = [ + warning for (_, warning) in check_peps._validate_required_headers(found_headers) + ] + assert warnings == [ + "Headers must be in PEP 12 order. Correct order: PEP, Title, Author, Sponsor, Status, Type, Created, Replaces" + ], warnings + + +@pytest.mark.parametrize( + "line", + [ + "!", + "The Zen of Python", + "A title that is exactly 79 characters long, but shorter than 80 characters long", + ], +) +def test_validate_title(line: str): + warnings = [warning for (_, warning) in check_peps._validate_title(1, line)] + assert warnings == [], warnings + + +def test_validate_title_blank(): + warnings = [warning for (_, warning) in check_peps._validate_title(1, "-" * 80)] + assert warnings == ["PEP title must be less than 80 characters"], warnings + + +def test_validate_title_too_long(): + warnings = [warning for (_, warning) in check_peps._validate_title(1, "")] + assert warnings == ["PEP must have a title"], warnings + + +@pytest.mark.parametrize( + "line", + [ + "Accepted", + "Active", + "April Fool!", + "Deferred", + "Draft", + "Final", + "Provisional", + "Rejected", + "Superseded", + "Withdrawn", + ], +) +def test_validate_status_valid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_status(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "Standards Track", + "Informational", + "Process", + "accepted", + "active", + "april fool!", + "deferred", + "draft", + "final", + "provisional", + "rejected", + "superseded", + "withdrawn", + ], +) +def test_validate_status_invalid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_status(1, line)] + assert warnings == ["Status must be a valid PEP status"], warnings + + +@pytest.mark.parametrize( + "line", + [ + "Standards Track", + "Informational", + "Process", + ], +) +def test_validate_type_valid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_type(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "standards track", + "informational", + "process", + "Accepted", + "Active", + "April Fool!", + "Deferred", + "Draft", + "Final", + "Provisional", + "Rejected", + "Superseded", + "Withdrawn", + ], +) +def test_validate_type_invalid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_type(1, line)] + assert warnings == ["Type must be a valid PEP type"], warnings + + +@pytest.mark.parametrize( + ("line", "expected_warnings"), + [ + # valid entries + ("Governance", set()), + ("Packaging", set()), + ("Typing", set()), + ("Release", set()), + ("Governance, Packaging", set()), + ("Packaging, Typing", set()), + # duplicates + ("Governance, Governance", {"duplicates"}), + ("Release, Release", {"duplicates"}), + ("Release, Release", {"duplicates"}), + ("Spam, Spam", {"duplicates", "valid"}), + ("lobster, lobster", {"duplicates", "capitalisation", "valid"}), + ("governance, governance", {"duplicates", "capitalisation"}), + # capitalisation + ("governance", {"capitalisation"}), + ("packaging", {"capitalisation"}), + ("typing", {"capitalisation"}), + ("release", {"capitalisation"}), + ("Governance, release", {"capitalisation"}), + # validity + ("Spam", {"valid"}), + ("lobster", {"capitalisation", "valid"}), + # sorted + ("Packaging, Governance", {"sorted"}), + ("Typing, Release", {"sorted"}), + ("Release, Governance", {"sorted"}), + ("spam, packaging", {"capitalisation", "valid", "sorted"}), + ], + # call str() on each parameterised value in the test ID. + ids=str, +) +def test_validate_topic(line: str, expected_warnings: set): + warnings = [warning for (_, warning) in check_peps._validate_topic(1, line)] + + found_warnings = set() + + if "duplicates" in expected_warnings: + found_warnings.add("duplicates") + expected = "Topic must not contain duplicates" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "capitalisation" in expected_warnings: + found_warnings.add("capitalisation") + expected = "Topic must be properly capitalised (Title Case)" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "valid" in expected_warnings: + found_warnings.add("valid") + expected = "Topic must be for a valid sub-index" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "sorted" in expected_warnings: + found_warnings.add("sorted") + expected = "Topic must be sorted lexicographically" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if expected_warnings == set(): + assert warnings == [], warnings + + assert found_warnings == expected_warnings + + +def test_validate_content_type_valid(): + warnings = [ + warning for (_, warning) in check_peps._validate_content_type(1, "text/x-rst") + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "text/plain", + "text/markdown", + "text/csv", + "text/rtf", + "text/javascript", + "text/html", + "text/xml", + ], +) +def test_validate_content_type_invalid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_content_type(1, line)] + assert warnings == ["Content-Type must be 'text/x-rst'"], warnings + + +@pytest.mark.parametrize( + "line", + [ + "0, 1, 8, 12, 20,", + "101, 801,", + "3099, 9999", + ], +) +def test_validate_pep_references(line: str): + warnings = [ + warning for (_, warning) in check_peps._validate_pep_references(1, line) + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "0,1,8, 12, 20,", + "101,801,", + "3099, 9998,9999", + ], +) +def test_validate_pep_references_separators(line: str): + warnings = [ + warning for (_, warning) in check_peps._validate_pep_references(1, line) + ] + assert warnings == [ + "PEP references must be separated by comma-spaces (', ')" + ], warnings + + +@pytest.mark.parametrize( + ("line", "expected_warnings"), + [ + # valid entries + ("1.0, 2.4, 2.7, 2.8, 3.0, 3.1, 3.4, 3.7, 3.11, 3.14", set()), + ("2.x", set()), + ("3.x", set()), + ("3.0.1", set()), + # segments + ("", {"segments"}), + ("1", {"segments"}), + ("1.2.3.4", {"segments"}), + # major + ("0.0", {"major"}), + ("4.0", {"major"}), + ("9.0", {"major"}), + # minor number + ("3.a", {"minor numeric"}), + ("3.spam", {"minor numeric"}), + ("3.0+", {"minor numeric"}), + ("3.0-9", {"minor numeric"}), + ("9.Z", {"major", "minor numeric"}), + # minor leading zero + ("3.01", {"minor zero"}), + ("0.00", {"major", "minor zero"}), + # micro empty + ("3.x.1", {"micro empty"}), + ("9.x.1", {"major", "micro empty"}), + # micro leading zero + ("3.3.0", {"micro zero"}), + ("3.3.00", {"micro zero"}), + ("3.3.01", {"micro zero"}), + ("3.0.0", {"micro zero"}), + ("3.00.0", {"minor zero", "micro zero"}), + ("0.00.0", {"major", "minor zero", "micro zero"}), + # micro number + ("3.0.a", {"micro numeric"}), + ("0.3.a", {"major", "micro numeric"}), + ], + # call str() on each parameterised value in the test ID. + ids=str, +) +def test_validate_python_version(line: str, expected_warnings: set): + warnings = [ + warning for (_, warning) in check_peps._validate_python_version(1, line) + ] + + found_warnings = set() + + if "segments" in expected_warnings: + found_warnings.add("segments") + expected = f"Python-Version must have two or three segments: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "major" in expected_warnings: + found_warnings.add("major") + expected = f"Python-Version major part must be 1, 2, or 3: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "minor numeric" in expected_warnings: + found_warnings.add("minor numeric") + expected = f"Python-Version minor part must be numeric: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "minor zero" in expected_warnings: + found_warnings.add("minor zero") + expected = f"Python-Version minor part must not have leading zeros: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "micro empty" in expected_warnings: + found_warnings.add("micro empty") + expected = ( + f"Python-Version micro part must be empty if minor part is 'x': {line}" + ) + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "micro zero" in expected_warnings: + found_warnings.add("micro zero") + expected = f"Python-Version micro part must not have leading zeros: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "micro numeric" in expected_warnings: + found_warnings.add("micro numeric") + expected = f"Python-Version micro part must be numeric: {line}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if expected_warnings == set(): + assert warnings == [], warnings + + assert found_warnings == expected_warnings diff --git a/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py b/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py new file mode 100644 index 000000000..2c52fa397 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py @@ -0,0 +1,48 @@ +from pathlib import Path + +import check_peps # NoQA: inserted into sys.modules in conftest.py + +PEP_9002 = Path(__file__).parent.parent / "peps" / "pep-9002.rst" + + +def test_with_fake_pep(): + content = PEP_9002.read_text(encoding="utf-8").splitlines() + warnings = list(check_peps.check_peps(PEP_9002, content)) + assert warnings == [ + (1, "PEP must begin with the 'PEP:' header"), + (9, "Must not have duplicate header: Sponsor "), + (10, "Must not have invalid header: Horse-Guards"), + (1, "Must have required header: PEP"), + (1, "Must have required header: Type"), + ( + 1, + "Headers must be in PEP 12 order. Correct order: Title, Version, " + "Author, Sponsor, BDFL-Delegate, Discussions-To, Status, Topic, " + "Content-Type, Requires, Created, Python-Version, Post-History, " + "Resolution", + ), + (4, "Author continuation lines must end with a comma"), + (5, "Author line must not be over-indented"), + (7, "Python-Version major part must be 1, 2, or 3: 4.0"), + ( + 8, + "Sponsor entries must begin with a valid 'Name': " + r"'Sponsor:\nHorse-Guards: Parade'", + ), + (11, "Created must be a 'DD-mmm-YYYY' date: '1-Jan-1989'"), + (12, "Delegate entries must begin with a valid 'Name': 'Barry!'"), + (13, "Status must be a valid PEP status"), + (14, "Topic must not contain duplicates"), + (14, "Topic must be properly capitalised (Title Case)"), + (14, "Topic must be for a valid sub-index"), + (14, "Topic must be sorted lexicographically"), + (15, "Content-Type must be 'text/x-rst'"), + (16, "PEP references must be separated by comma-spaces (', ')"), + (17, "Discussions-To must be a valid thread URL or mailing list"), + (18, "Post-History must be a 'DD-mmm-YYYY' date: '2-Feb-2000'"), + (18, "Post-History must be a valid thread URL"), + (19, "Post-History must be a 'DD-mmm-YYYY' date: '3-Mar-2001'"), + (19, "Post-History must be a valid thread URL"), + (20, "Resolution must be a valid thread URL"), + (23, "Use the :pep:`NNN` role to refer to PEPs"), + ] diff --git a/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py b/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py new file mode 100644 index 000000000..3443f7144 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py @@ -0,0 +1,108 @@ +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + "line", + [ + "PEP: 0", + "PEP: 12", + ], +) +def test_validate_pep_number(line: str): + warnings = [warning for (_, warning) in check_peps._validate_pep_number(line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "0", + "PEP:12", + "PEP 0", + "PEP 12", + "PEP:0", + ], +) +def test_validate_pep_number_invalid_header(line: str): + warnings = [warning for (_, warning) in check_peps._validate_pep_number(line)] + assert warnings == ["PEP must begin with the 'PEP:' header"], warnings + + +@pytest.mark.parametrize( + ("pep_number", "expected_warnings"), + [ + # valid entries + ("0", set()), + ("1", set()), + ("12", set()), + ("20", set()), + ("101", set()), + ("801", set()), + ("3099", set()), + ("9999", set()), + # empty + ("", {"not blank"}), + # leading zeros + ("01", {"leading zeros"}), + ("001", {"leading zeros"}), + ("0001", {"leading zeros"}), + ("00001", {"leading zeros"}), + # non-numeric + ("a", {"non-numeric"}), + ("123abc", {"non-numeric"}), + ("0123A", {"leading zeros", "non-numeric"}), + ("0", {"non-numeric"}), + ("101", {"non-numeric"}), + ("9999", {"non-numeric"}), + ("𝟎", {"non-numeric"}), + ("𝟘", {"non-numeric"}), + ("𝟏𝟚", {"non-numeric"}), + ("𝟸𝟬", {"non-numeric"}), + ("-1", {"non-numeric"}), + ("+1", {"non-numeric"}), + # out of bounds + ("10000", {"range"}), + ("54321", {"range"}), + ("99999", {"range"}), + ("32768", {"range"}), + ], + # call str() on each parameterised value in the test ID. + ids=str, +) +def test_pep_num_checker(pep_number: str, expected_warnings: set): + warnings = [ + warning for (_, warning) in check_peps._pep_num(1, pep_number, "") + ] + + found_warnings = set() + pep_number = pep_number.strip() + + if "not blank" in expected_warnings: + found_warnings.add("not blank") + expected = f" must not be blank: {pep_number!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "leading zeros" in expected_warnings: + found_warnings.add("leading zeros") + expected = f" must not contain leading zeros: {pep_number!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "non-numeric" in expected_warnings: + found_warnings.add("non-numeric") + expected = f" must be numeric: {pep_number!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if "range" in expected_warnings: + found_warnings.add("range") + expected = f" must be between 0 and 9999: {pep_number!r}" + matching = [w for w in warnings if w == expected] + assert matching == [expected], warnings + + if expected_warnings == set(): + assert warnings == [], warnings + + assert found_warnings == expected_warnings diff --git a/pep_sphinx_extensions/tests/pep_lint/test_post_url.py b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py new file mode 100644 index 000000000..dd04b4c39 --- /dev/null +++ b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py @@ -0,0 +1,309 @@ +import check_peps # NoQA: inserted into sys.modules in conftest.py +import pytest + + +@pytest.mark.parametrize( + "line", + [ + "list-name@python.org", + "distutils-sig@python.org", + "csv@python.org", + "python-3000@python.org", + "ipaddr-py-dev@googlegroups.com", + "python-tulip@googlegroups.com", + "https://discuss.python.org/t/thread-name/123456", + "https://discuss.python.org/t/thread-name/123456/", + "https://discuss.python.org/t/thread_name/123456", + "https://discuss.python.org/t/thread_name/123456/", + "https://discuss.python.org/t/123456/", + "https://discuss.python.org/t/123456", + ], +) +def test_validate_discussions_to_valid(line: str): + warnings = [ + warning for (_, warning) in check_peps._validate_discussions_to(1, line) + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "$pecial+chars@python.org", + "a-discussions-to-list!@googlegroups.com", + ], +) +def test_validate_discussions_to_list_name(line: str): + warnings = [ + warning for (_, warning) in check_peps._validate_discussions_to(1, line) + ] + assert warnings == ["Discussions-To must be a valid mailing list"], warnings + + +@pytest.mark.parametrize( + "line", + [ + "list-name@python.org.uk", + "distutils-sig@mail-server.example", + ], +) +def test_validate_discussions_to_invalid_list_domain(line: str): + warnings = [ + warning for (_, warning) in check_peps._validate_discussions_to(1, line) + ] + assert warnings == [ + "Discussions-To must be a valid thread URL or mailing list" + ], warnings + + +@pytest.mark.parametrize( + "body", + [ + "", + ( + "01-Jan-2001, 02-Feb-2002,\n " + "03-Mar-2003, 04-Apr-2004,\n " + "05-May-2005," + ), + ( + "`01-Jan-2000 `__,\n " + "`11-Mar-2005 `__,\n " + "`21-May-2010 `__,\n " + "`31-Jul-2015 `__," + ), + "01-Jan-2001, `02-Feb-2002 `__,\n03-Mar-2003", + ], +) +def test_validate_post_history_valid(body: str): + warnings = [warning for (_, warning) in check_peps._validate_post_history(1, body)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor123", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor123", + ], +) +def test_validate_resolution_valid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_resolution(1, line)] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "line", + [ + "https://mail.python.org/archives/list/list-name@python.org/thread", + "https://mail.python.org/archives/list/list-name@python.org/message", + "https://mail.python.org/archives/list/list-name@python.org/thread/", + "https://mail.python.org/archives/list/list-name@python.org/message/", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/", + ], +) +def test_validate_resolution_invalid(line: str): + warnings = [warning for (_, warning) in check_peps._validate_resolution(1, line)] + assert warnings == ["Resolution must be a valid thread URL"], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "https://discuss.python.org/t/thread-name/123456", + "https://discuss.python.org/t/thread-name/123456/", + "https://discuss.python.org/t/thread_name/123456", + "https://discuss.python.org/t/thread_name/123456/", + "https://discuss.python.org/t/thread-name/123456/654321/", + "https://discuss.python.org/t/thread-name/123456/654321", + "https://discuss.python.org/t/123456", + "https://discuss.python.org/t/123456/", + "https://discuss.python.org/t/123456/654321/", + "https://discuss.python.org/t/123456/654321", + "https://discuss.python.org/t/1", + "https://discuss.python.org/t/1/", + "https://mail.python.org/pipermail/list-name/0000-Month/0123456.html", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/", + ], +) +def test_thread_checker_valid(thread_url: str): + warnings = [ + warning for (_, warning) in check_peps._thread(1, thread_url, "") + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "http://link.example", + "list-name@python.org", + "distutils-sig@python.org", + "csv@python.org", + "python-3000@python.org", + "ipaddr-py-dev@googlegroups.com", + "python-tulip@googlegroups.com", + "https://link.example", + "https://discuss.python.org", + "https://discuss.python.org/", + "https://discuss.python.org/c/category", + "https://discuss.python.org/t/thread_name/123456//", + "https://discuss.python.org/t/thread+name/123456", + "https://discuss.python.org/t/thread+name/123456#", + "https://discuss.python.org/t/thread+name/123456/#", + "https://discuss.python.org/t/thread+name/123456/#anchor", + "https://discuss.python.org/t/thread+name/", + "https://discuss.python.org/t/thread+name", + "https://discuss.python.org/t/thread-name/123abc", + "https://discuss.python.org/t/thread-name/123abc/", + "https://discuss.python.org/t/thread-name/123456/123abc", + "https://discuss.python.org/t/thread-name/123456/123abc/", + "https://discuss.python.org/t/123/456/789", + "https://discuss.python.org/t/123/456/789/", + "https://discuss.python.org/t/#/", + "https://discuss.python.org/t/#", + "https://mail.python.org/pipermail/list+name/0000-Month/0123456.html", + "https://mail.python.org/pipermail/list-name/YYYY-Month/0123456.html", + "https://mail.python.org/pipermail/list-name/0123456/0123456.html", + "https://mail.python.org/pipermail/list-name/0000-Month/0123456", + "https://mail.python.org/pipermail/list-name/0000-Month/0123456/", + "https://mail.python.org/pipermail/list-name/0000-Month/", + "https://mail.python.org/pipermail/list-name/0000-Month", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#anchor", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/", + ], +) +def test_thread_checker_invalid(thread_url: str): + warnings = [ + warning for (_, warning) in check_peps._thread(1, thread_url, "") + ] + assert warnings == [" must be a valid thread URL"], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor123", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor123", + ], +) +def test_thread_checker_valid_allow_message(thread_url: str): + warnings = [ + warning + for (_, warning) in check_peps._thread( + 1, thread_url, "", allow_message=True + ) + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "https://mail.python.org/archives/list/list-name@python.org/thread", + "https://mail.python.org/archives/list/list-name@python.org/message", + "https://mail.python.org/archives/list/list-name@python.org/thread/", + "https://mail.python.org/archives/list/list-name@python.org/message/", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor", + "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor", + "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", + "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123", + "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/", + ], +) +def test_thread_checker_invalid_allow_message(thread_url: str): + warnings = [ + warning + for (_, warning) in check_peps._thread( + 1, thread_url, "", allow_message=True + ) + ] + assert warnings == [" must be a valid thread URL"], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "list-name@python.org", + "distutils-sig@python.org", + "csv@python.org", + "python-3000@python.org", + "ipaddr-py-dev@googlegroups.com", + "python-tulip@googlegroups.com", + "https://discuss.python.org/t/thread-name/123456", + "https://discuss.python.org/t/thread-name/123456/", + "https://discuss.python.org/t/thread_name/123456", + "https://discuss.python.org/t/thread_name/123456/", + "https://discuss.python.org/t/123456/", + "https://discuss.python.org/t/123456", + ], +) +def test_thread_checker_valid_discussions_to(thread_url: str): + warnings = [ + warning + for (_, warning) in check_peps._thread( + 1, thread_url, "", discussions_to=True + ) + ] + assert warnings == [], warnings + + +@pytest.mark.parametrize( + "thread_url", + [ + "https://discuss.python.org/t/thread-name/123456/000", + "https://discuss.python.org/t/thread-name/123456/000/", + "https://discuss.python.org/t/thread_name/123456/000", + "https://discuss.python.org/t/thread_name/123456/000/", + "https://discuss.python.org/t/123456/000/", + "https://discuss.python.org/t/12345656/000", + "https://discuss.python.org/t/thread-name", + "https://discuss.python.org/t/thread_name", + "https://discuss.python.org/t/thread+name", + ], +) +def test_thread_checker_invalid_discussions_to(thread_url: str): + warnings = [ + warning + for (_, warning) in check_peps._thread( + 1, thread_url, "", discussions_to=True + ) + ] + assert warnings == [" must be a valid thread URL"], warnings + + +def test_thread_checker_allow_message_discussions_to(): + with pytest.raises(ValueError, match="cannot both be True"): + list( + check_peps._thread( + 1, "", "", allow_message=True, discussions_to=True + ) + ) diff --git a/pep_sphinx_extensions/tests/peps/pep-9002.rst b/pep_sphinx_extensions/tests/peps/pep-9002.rst new file mode 100644 index 000000000..208569e03 --- /dev/null +++ b/pep_sphinx_extensions/tests/peps/pep-9002.rst @@ -0,0 +1,23 @@ +PEP:9002 +Title: Nobody expects the example PEP! +Author: Cardinal Ximénez , + Cardinal Biggles + Cardinal Fang +Version: 4.0 +Python-Version: 4.0 +Sponsor: +Sponsor: +Horse-Guards: Parade +Created: 1-Jan-1989 +BDFL-Delegate: Barry! +Status: Draught +Topic: Inquisiting, Governance, Governance, packaging +Content-Type: video/quicktime +Requires: 0020,1,2,3, 7, 8 +Discussions-To: MR ALBERT SPIM, I,OOO,OO8 LONDON ROAD, OXFORD +Post-History: `2-Feb-2000 `__ + `3-Mar-2001 `__ +Resolution: + + +https://peps.python.org/pep-9002.html diff --git a/pytest.ini b/pytest.ini index b872465bf..10404cc0b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,8 +1,16 @@ [pytest] -addopts = -r a --strict-config --strict-markers --import-mode=importlib --cov pep_sphinx_extensions --cov-report html --cov-report xml +# https://docs.pytest.org/en/7.3.x/reference/reference.html#command-line-flags +addopts = + -r a + --strict-config + --strict-markers + --import-mode=importlib + --cov check_peps --cov pep_sphinx_extensions + --cov-report html --cov-report xml empty_parameter_set_mark = fail_at_collect filterwarnings = error minversion = 6.0 testpaths = pep_sphinx_extensions xfail_strict = True +disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True From 2afb609499fdfd77388bef7250cd7892bc2120c6 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 5 Sep 2023 05:08:14 +0100 Subject: [PATCH 109/173] Infra: Use actions/checkout version 4 (#3422) --- .github/workflows/lint.yml | 2 +- .github/workflows/render.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 37ccaee03..2d29bf2f5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3 uses: actions/setup-python@v4 with: diff --git a/.github/workflows/render.yml b/.github/workflows/render.yml index 01afd33f3..98dcbf730 100644 --- a/.github/workflows/render.yml +++ b/.github/workflows/render.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # fetch all history so that last modified date-times are accurate diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f80254024..e71847944 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,7 +40,7 @@ jobs: - "ubuntu-latest" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: From ffdff87dff50395c0656b191f707d66e73a848c6 Mon Sep 17 00:00:00 2001 From: "T. Wouters" Date: Wed, 6 Sep 2023 14:43:46 +0200 Subject: [PATCH 110/173] PEP 693: Update the Python 3.12.0rc2 release date. (#3426) --- pep-0693.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0693.rst b/pep-0693.rst index dba00cf3a..c5b11929c 100644 --- a/pep-0693.rst +++ b/pep-0693.rst @@ -56,10 +56,10 @@ Actual: - 3.12.0 beta 3: Monday, 2023-06-19 - 3.12.0 beta 4: Tuesday, 2023-07-11 - 3.12.0 candidate 1: Sunday, 2023-08-06 +- 3.12.0 candidate 2: Wednesday, 2023-09-06 Expected: -- 3.12.0 candidate 2: Monday, 2023-09-04 - 3.12.0 final: Monday, 2023-10-02 Subsequent bugfix releases every two months. From 5ce45eda6d65f1c6bf2a9e325a0ff0169d3ff179 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:44:00 +0100 Subject: [PATCH 111/173] PEP 713: Mark as Rejected (#3423) --- pep-0713.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pep-0713.rst b/pep-0713.rst index 5e704c910..65d117b1d 100644 --- a/pep-0713.rst +++ b/pep-0713.rst @@ -3,12 +3,23 @@ Title: Callable Modules Author: Amethyst Reese Sponsor: Łukasz Langa Discussions-To: https://discuss.python.org/t/pep-713-callable-modules/26127 -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 20-Apr-2023 Python-Version: 3.12 Post-History: `23-Apr-2023 `__ +Resolution: https://discuss.python.org/t/26127/86 + + +Rejection Notice +================ + +The Steering Council didn't feel that there was a compelling reason to +have this PEP, even though it clearly could be done from a consistency +point of view. +If this idea comes up again in the future, this is a useful prior +discussion to refer to. Abstract From 971a49b67ad36e84f77bb677a957c4f25883f184 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:48:58 +0100 Subject: [PATCH 112/173] PEP 727: Review (#3316) * Strip thread name * Link to Python docs * Reference PEP 484 * Fix heading levels * Add missing sections (as a comment) * Rename EAaOPV to Reference Implementation * Code block formatting * Remove leading elipses * Tighten usage criteria * Remove non-specification content * Rewrite the Specification * Simplify Examples and move DocInfo to the reference implementation * Improve the Reference Implementation * Syntax --- pep-0727.rst | 246 +++++++++++++++++++++++++-------------------------- 1 file changed, 121 insertions(+), 125 deletions(-) diff --git a/pep-0727.rst b/pep-0727.rst index da9b018e2..d8f900415 100644 --- a/pep-0727.rst +++ b/pep-0727.rst @@ -2,22 +2,22 @@ PEP: 727 Title: Documentation Metadata in Typing Author: Sebastián Ramírez Sponsor: Jelle Zijlstra -Discussions-To: https://discuss.python.org/t/pep-727-documentation-metadata-in-typing/32566 +Discussions-To: https://discuss.python.org/t/32566 Status: Draft Type: Standards Track Topic: Typing Content-Type: text/x-rst Created: 28-Aug-2023 Python-Version: 3.13 -Post-History: `30-Aug-2023 `__ +Post-History: `30-Aug-2023 `__ Abstract ======== This document proposes a way to complement docstrings to add additional documentation -to Python symbols using type annotations with ``Annotated`` (in class attributes, -function and method parameters, return values, and variables). +to Python symbols using type annotations with :py:class:`~typing.Annotated` +(in class attributes, function and method parameters, return values, and variables). Motivation @@ -60,7 +60,7 @@ documentation in some other way (e.g. an API, a CLI, etc). Some of these previous formats tried to account for the lack of type annotations in older Python versions by including typing information in the docstrings, but now that information doesn't need to be in docstrings as there is now an official -syntax for type annotations. +:pep:`syntax for type annotations <484>`. Rationale @@ -84,79 +84,56 @@ like to adopt it. Specification ============= +The main proposal is to introduce a new function, ``typing.doc()``, +to be used when documenting Python objects. +This function MUST only be used within :py:class:`~typing.Annotated` annotations. +The function takes a single string argument, ``documentation``, +and returns an instance of ``typing.DocInfo``, +which stores the input string unchanged. -``typing.doc`` --------------- +Any tool processing ``typing.DocInfo`` objects SHOULD interpret the string as +a docstring, and therefore SHOULD normalize whitespace +as if ``inspect.cleandoc()`` were used. -The main proposal is to have a new function ``doc()`` in the ``typing`` module. -Even though this is not strictly related to the type annotations, it's expected -to go in ``Annotated`` type annotations, and to interact with type annotations. +The string passed to ``typing.doc()`` SHOULD be of the form that would be a valid docstring. +This means that `f-strings`__ and string operations SHOULD NOT be used. +As this cannot be enforced by the Python runtime, +tools SHOULD NOT rely on this behaviour, +and SHOULD exit with an error if such a prohibited string is encountered. -There's also the particular benefit that it could be implemented in the -``typing_extensions`` package to have support for older versions of Python and -early adopters of this proposal. +__ https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -This ``doc()`` function would receive one single parameter ``documentation`` with -a documentation string. +Examples +-------- -This string could be a multi-line string, in which case, when extracted by tools, -should be interpreted cleaning up indentation as if using ``inspect.cleandoc()``, -the same procedure used for docstrings. +Class attributes may be documented: -This string could probably contain markup, like Markdown or reST. As that could -be highly debated, that decision is left for a future proposal, to focus here -on the main functionality. +.. code:: python -This specification targets static analysis tools and editors, and as such, the -value passed to ``doc()`` should allow static evaluation and analysis. If a -developer passes as the value something that requires runtime execution -(e.g. a function call) the behavior of static analysis tools is unspecified -and they could omit it from their process and results. For static analysis -tools to be conformant with this specification they need only to support -statically accessible values. + from typing import Annotated, doc -An example documenting the attributes of a class, or in this case, the keys -of a ``TypedDict``, could look like this: + class User: + first_name: Annotated[str, doc("The user's first name")] + last_name: Annotated[str, doc("The user's last name")] -.. code-block:: + ... - from typing import Annotated, TypedDict, NotRequired, doc +As can function or method parameters: +.. code:: python - class User(TypedDict): - firstname: Annotated[str, doc("The user's first name")] - lastname: Annotated[str, doc("The user's last name")] + from typing import Annotated, doc + def create_user( + first_name: Annotated[str, doc("The user's first name")], + last_name: Annotated[str, doc("The user's last name")], + cursor: DatabaseConnection | None = None, + ) -> Annotated[User, doc("The created user after saving in the database")]: + """Create a new user in the system. -An example documenting the parameters of a function could look like this: - -.. code-block:: - - from typing import Annotated, doc - - - def create_user( - lastname: Annotated[str, doc("The **last name** of the newly created user")], - firstname: Annotated[str | None, doc("The user's **first name**")] = None, - ) -> Annotated[User, doc("The created user after saving in the database")]: - """ - Create a new user in the system, it needs the database connection to be already - initialized. - """ - pass - - -The return of the ``doc()`` function is an instance of a class that can be checked -and used at runtime, defined similar to: - -.. code-block:: - - class DocInfo: - def __init__(self, documentation: str): - self.documentation = documentation - -...where the attribute ``documentation`` contains the same value string passed to -the function ``doc()``. + It needs the database connection to be already initialized. + """ + pass Additional Scenarios @@ -171,34 +148,30 @@ but implementers are not required to support them. Type Alias ----------- +'''''''''' When creating a type alias, like: -.. code-block:: +.. code:: python - Username = Annotated[str, doc("The name of a user in the system")] + Username = Annotated[str, doc("The name of a user in the system")] -...the documentation would be considered to be carried by the parameter annotated +The documentation would be considered to be carried by the parameter annotated with ``Username``. So, in a function like: -.. code-block:: +.. code:: python - def hi( - to: Username, - ) -> None: ... + def hi(to: Username) -> None: ... -...it would be equivalent to: +It would be equivalent to: -.. code-block:: +.. code:: python - def hi( - to: Annotated[str, doc("The name of a user in the system")], - ) -> None: ... + def hi(to: Annotated[str, doc("The name of a user in the system")]) -> None: ... Nevertheless, implementers would not be required to support type aliases outside of the final type annotation to be conformant with this specification, as it @@ -206,17 +179,17 @@ could require more complex dereferencing logic. Annotating Type Parameters --------------------------- +'''''''''''''''''''''''''' When annotating type parameters, as in: -.. code-block:: +.. code:: python - def hi( - to: list[Annotated[str, doc("The name of a user in a list")]], - ) -> None: ... + def hi( + to: list[Annotated[str, doc("The name of a user in a list")]], + ) -> None: ... -...the documentation in ``doc()`` would refer to what it is annotating, in this +The documentation in ``doc()`` would refer to what it is annotating, in this case, each item in the list, not the list itself. There are currently no practical use cases for documenting type parameters, @@ -225,17 +198,17 @@ conformant, but it's included for completeness. Annotating Unions ------------------ +''''''''''''''''' If used in one of the parameters of a union, as in: -.. code-block:: +.. code:: python - def hi( - to: str | Annotated[list[str], doc("List of user names")], - ) -> None: ... + def hi( + to: str | Annotated[list[str], doc("List of user names")], + ) -> None: ... -...again, the documentation in ``doc()`` would refer to what it is annotating, +Again, the documentation in ``doc()`` would refer to what it is annotating, in this case, this documents the list itself, not its items. In particular, the documentation would not refer to a single string passed as a @@ -247,7 +220,7 @@ included for completeness. Nested ``Annotated`` --------------------- +'''''''''''''''''''' Continuing with the same idea above, if ``Annotated`` was used nested and used multiple times in the same parameter, ``doc()`` would refer to the type it @@ -255,14 +228,15 @@ is annotating. So, in an example like: -.. code-block:: +.. code:: python - def hi( - to: Annotated[ - Annotated[str, doc("A user name")] | Annotated[list, doc("A list of user names")], - doc("Who to say hi to"), - ], - ) -> None: ... + def hi( + to: Annotated[ + Annotated[str, doc("A user name")] + | Annotated[list, doc("A list of user names")], + doc("Who to say hi to"), + ], + ) -> None: ... The documentation for the whole parameter ``to`` would be considered to be @@ -281,16 +255,16 @@ of the parameter passed is of one type or another, but they are not required to Duplication ------------ +''''''''''' If ``doc()`` is used multiple times in a single ``Annotated``, it would be considered invalid usage from the developer, for example: -.. code-block:: +.. code:: python - def hi( - to: Annotated[str, doc("A user name"), doc("The current user name")], - ) -> None: ... + def hi( + to: Annotated[str, doc("A user name"), doc("The current user name")], + ) -> None: ... Implementers can consider this invalid and are not required to support this to be @@ -302,46 +276,68 @@ can opt to support one of the ``doc()`` declarations. In that case, the suggestion would be to support the last one, just because this would support overriding, for example, in: -.. code-block:: +.. code:: python - User = Annotated[str, doc("A user name")] + User = Annotated[str, doc("A user name")] - CurrentUser = Annotated[User, doc("The current user name")] + CurrentUser = Annotated[User, doc("The current user name")] Internally, in Python, ``CurrentUser`` here is equivalent to: -.. code-block:: +.. code:: python - CurrentUser = Annotated[str, doc("A user name"), doc("The current user name")] + CurrentUser = Annotated[str, + doc("A user name"), + doc("The current user name")] For an implementation that supports the last ``doc()`` appearance, the above example would be equivalent to: -.. code-block:: +.. code:: python - def hi( - to: Annotated[str, doc("The current user name")], - ) -> None: ... + def hi(to: Annotated[str, doc("The current user name")]) -> None: ... -Early Adopters and Older Python Versions -======================================== +.. you need to fill these in: -For older versions of Python and early adopters of this proposal, ``doc()`` and -``DocInfo`` can be imported from the ``typing_extensions`` package. + Backwards Compatibility + ======================= -.. code-block:: - - from typing import Annotated - - from typing_extensions import doc + [Describe potential impact and severity on pre-existing code.] - def hi( - to: Annotated[str, doc("The current user name")], - ) -> None: ... + Security Implications + ===================== + + [How could a malicious user take advantage of this new feature?] + + + How to Teach This + ================= + + [How to teach users, new and experienced, how to apply the PEP to their work.] + + +Reference Implementation +======================== + +``typing.doc`` and ``typing.DocInfo`` are implemented as follows: + +.. code:: python + + def doc(documentation: str, /) -> DocInfo: + return DocInfo(documentation) + + class DocInfo: + def __init__(self, documentation: str, /): + self.documentation = documentation + + +These have been implemented in the `typing_extensions`__ package. + +__ https://pypi.org/project/typing-extensions/ Rejected Ideas @@ -407,8 +403,8 @@ to be used by those that are willing to take the extra verbosity in exchange for the benefits. -Doc is not Typing ------------------ +Documentation is not Typing +--------------------------- It could also be argued that documentation is not really part of typing, or that it should live in a different module. Or that this information should not be part From 0f2226896373c17d69d7ea7487c90a05f5dd3370 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 9 Sep 2023 17:33:52 +0100 Subject: [PATCH 113/173] Lint: Add Ruff (#3429) --- .github/CODEOWNERS | 1 + .pre-commit-config.yaml | 19 +++++++++++-------- .ruff.toml | 15 +++++++++++++++ .../tests/pep_lint/test_date.py | 2 +- .../tests/pep_lint/test_email.py | 2 +- .../tests/pep_lint/test_headers.py | 2 +- .../tests/pep_lint/test_post_url.py | 4 ---- .../transform/test_pep_headers.py | 12 ++++++------ .../pep_processor/transform/test_pep_zero.py | 2 +- .../tests/pep_zero_generator/test_parser.py | 4 ++-- .../tests/pep_zero_generator/test_writer.py | 2 +- 11 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 .ruff.toml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cecf3d623..a331e70cd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,6 +20,7 @@ contents.rst @AA-Turner .codespell/ @CAM-Gerlach @hugovk .codespellrc @CAM-Gerlach @hugovk .pre-commit-config.yaml @CAM-Gerlach @hugovk +.ruff.toml @AA-Turner @CAM-Gerlach @hugovk check-peps.py @AA-Turner @CAM-Gerlach @hugovk # Git infrastructure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8775917c8..8da57b575 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,6 +42,17 @@ repos: - id: check-yaml name: "Check YAML" + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.287 + hooks: + - id: ruff + name: "Lint with Ruff" + args: + - '--exit-non-zero-on-fix' + - '--diff' + - '--format=github' + files: '^pep_sphinx_extensions/tests/' + - repo: https://github.com/psf/black rev: 23.7.0 hooks: @@ -52,14 +63,6 @@ repos: - '--target-version=py310' files: 'pep_sphinx_extensions/tests/.*' - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - name: "Sort imports with isort" - args: ['--profile=black', '--atomic'] - files: 'pep_sphinx_extensions/tests/.*' - - repo: https://github.com/tox-dev/tox-ini-fmt rev: 1.3.1 hooks: diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 000000000..5ab2337f9 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,15 @@ +ignore = [ + "E501", # Line too long +] + +select = [ + "E", # pycodestyle errors + "F", # pyflakes + "I", # isort + "PT", # flake8-pytest-style + "W", # pycodestyle warnings +] + +show-source = true + +target-version = "py39" diff --git a/pep_sphinx_extensions/tests/pep_lint/test_date.py b/pep_sphinx_extensions/tests/pep_lint/test_date.py index 3ce466610..2218fc2a0 100644 --- a/pep_sphinx_extensions/tests/pep_lint/test_date.py +++ b/pep_sphinx_extensions/tests/pep_lint/test_date.py @@ -93,7 +93,7 @@ def test_date_checker_too_early(date_str: str): [ # the future "31-Dec-2999", - "01-Jan-2100", + "01-Jan-2042", "01-Jan-2100", (dt.datetime.now() + dt.timedelta(days=15)).strftime("%d-%b-%Y"), (dt.datetime.now() + dt.timedelta(days=100)).strftime("%d-%b-%Y"), diff --git a/pep_sphinx_extensions/tests/pep_lint/test_email.py b/pep_sphinx_extensions/tests/pep_lint/test_email.py index 2ff4ba61f..d9f19592d 100644 --- a/pep_sphinx_extensions/tests/pep_lint/test_email.py +++ b/pep_sphinx_extensions/tests/pep_lint/test_email.py @@ -149,7 +149,7 @@ def test_validate_delegate(line: str): (r"Cardinal Ximénez ", {"valid email"}), ("Cardinal Ximénez <[Cardinal.Ximenez]@spanish.inquisition>", {"valid email"}), ('Cardinal Ximénez <"Cardinal"Ximenez"@spanish.inquisition>', {"valid email"}), - ("Cardinal Ximénez ", {"valid email"}), + ("Cardinal Ximenez ", {"valid email"}), ("Cardinal Ximénez ", {"valid email"}), ("Cardinal Ximénez ", {"valid email"}), # ... entries must contain a valid email address (domain) diff --git a/pep_sphinx_extensions/tests/pep_lint/test_headers.py b/pep_sphinx_extensions/tests/pep_lint/test_headers.py index 8246271e3..227eb5397 100644 --- a/pep_sphinx_extensions/tests/pep_lint/test_headers.py +++ b/pep_sphinx_extensions/tests/pep_lint/test_headers.py @@ -196,7 +196,7 @@ def test_validate_type_invalid(line: str): # duplicates ("Governance, Governance", {"duplicates"}), ("Release, Release", {"duplicates"}), - ("Release, Release", {"duplicates"}), + ("Packaging, Packaging", {"duplicates"}), ("Spam, Spam", {"duplicates", "valid"}), ("lobster, lobster", {"duplicates", "capitalisation", "valid"}), ("governance, governance", {"duplicates", "capitalisation"}), diff --git a/pep_sphinx_extensions/tests/pep_lint/test_post_url.py b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py index dd04b4c39..982f4612e 100644 --- a/pep_sphinx_extensions/tests/pep_lint/test_post_url.py +++ b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py @@ -108,8 +108,6 @@ def test_validate_resolution_valid(line: str): "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor", "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123", "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/", - "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", - "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123", "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/", ], @@ -233,8 +231,6 @@ def test_thread_checker_valid_allow_message(thread_url: str): "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor", "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123", "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/", - "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", - "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/anchor/", "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123", "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/", ], diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py index 4cc45423e..772c24158 100644 --- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py +++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py @@ -18,7 +18,7 @@ from pep_sphinx_extensions.pep_zero_generator.constants import ( @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ("my-mailing-list@example.com", "my-mailing-list@example.com"), ("python-tulip@googlegroups.com", "https://groups.google.com/g/python-tulip"), @@ -37,7 +37,7 @@ def test_generate_list_url(test_input, expected): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( "https://mail.python.org/pipermail/python-3000/2006-November/004190.html", @@ -72,7 +72,7 @@ def test_process_pretty_url(test_input, expected): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( "https://example.com/", @@ -94,7 +94,7 @@ def test_process_pretty_url_invalid(test_input, expected): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( "https://mail.python.org/pipermail/python-3000/2006-November/004190.html", @@ -129,7 +129,7 @@ def test_make_link_pretty(test_input, expected): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ (STATUS_ACCEPTED, "Normative proposal accepted for implementation"), (STATUS_ACTIVE, "Currently valid informational guidance, or an in-use process"), @@ -155,7 +155,7 @@ def test_abbreviate_status_unknown(): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( TYPE_INFO, diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py index 09b2effea..e25d37fd2 100644 --- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py +++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py @@ -5,7 +5,7 @@ from pep_sphinx_extensions.pep_processor.transforms import pep_zero @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( nodes.reference( diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index cea1d61ab..0a1a108e1 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -52,7 +52,7 @@ def test_pep_details(monkeypatch): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( "First Last ", @@ -88,7 +88,7 @@ def test_parse_authors_invalid(): @pytest.mark.parametrize( - "test_type, test_status, expected", + ("test_type", "test_status", "expected"), [ (TYPE_INFO, STATUS_DRAFT, ":abbr:`I (Informational, Draft)`"), (TYPE_INFO, STATUS_ACTIVE, ":abbr:`IA (Informational, Active)`"), diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py index 150a317bb..1ccf8c418 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -30,7 +30,7 @@ def test_pep_zero_writer_emit_title(): @pytest.mark.parametrize( - "test_input, expected", + ("test_input", "expected"), [ ( "pep-9000.rst", From 08d688fdcafc1557bf7fc53573e5c84b31b78b5d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 9 Sep 2023 18:39:29 +0100 Subject: [PATCH 114/173] All PEPs: Move to ``peps/`` folder (#3418) --- .github/CODEOWNERS | 1310 ++++++++--------- .../PULL_REQUEST_TEMPLATE/Add a new PEP.md | 2 +- .gitignore | 28 +- .pre-commit-config.yaml | 80 +- Makefile | 2 +- build.py | 2 +- check-peps.py | 8 +- docs/rendering_system.rst | 8 +- .../pep_processor/html/pep_html_builder.py | 8 +- .../pep_processor/transforms/pep_footer.py | 9 +- .../pep_theme/templates/page.html | 4 +- .../pep_zero_generator/pep_index_generator.py | 2 +- pep_sphinx_extensions/tests/conftest.py | 2 +- .../transform/test_pep_footer.py | 8 +- .../tests/pep_zero_generator/test_parser.py | 14 +- .../test_pep_index_generator.py | 2 +- conf.py => peps/conf.py | 4 +- contents.rst => peps/contents.rst | 1 - pep-0001.txt => peps/pep-0001.rst | 0 {pep-0001 => peps/pep-0001}/process_flow.svg | 0 pep-0002.txt => peps/pep-0002.rst | 0 pep-0003.txt => peps/pep-0003.rst | 0 pep-0004.txt => peps/pep-0004.rst | 0 pep-0005.txt => peps/pep-0005.rst | 0 pep-0006.txt => peps/pep-0006.rst | 0 pep-0007.txt => peps/pep-0007.rst | 0 pep-0008.txt => peps/pep-0008.rst | 0 pep-0009.txt => peps/pep-0009.rst | 0 pep-0010.txt => peps/pep-0010.rst | 0 pep-0011.txt => peps/pep-0011.rst | 0 pep-0012.rst => peps/pep-0012.rst | 0 {pep-0012 => peps/pep-0012}/pep-NNNN.rst | 0 pep-0013.rst => peps/pep-0013.rst | 0 pep-0020.txt => peps/pep-0020.rst | 0 pep-0042.txt => peps/pep-0042.rst | 0 pep-0100.txt => peps/pep-0100.rst | 0 pep-0101.txt => peps/pep-0101.rst | 0 pep-0102.txt => peps/pep-0102.rst | 0 pep-0103.txt => peps/pep-0103.rst | 0 pep-0160.txt => peps/pep-0160.rst | 0 pep-0200.txt => peps/pep-0200.rst | 0 pep-0201.txt => peps/pep-0201.rst | 0 pep-0202.txt => peps/pep-0202.rst | 0 pep-0203.txt => peps/pep-0203.rst | 0 pep-0204.txt => peps/pep-0204.rst | 0 pep-0205.txt => peps/pep-0205.rst | 0 pep-0206.txt => peps/pep-0206.rst | 0 pep-0207.txt => peps/pep-0207.rst | 0 pep-0208.txt => peps/pep-0208.rst | 0 pep-0209.txt => peps/pep-0209.rst | 0 pep-0210.txt => peps/pep-0210.rst | 0 pep-0211.txt => peps/pep-0211.rst | 0 pep-0212.txt => peps/pep-0212.rst | 0 pep-0213.txt => peps/pep-0213.rst | 0 pep-0214.txt => peps/pep-0214.rst | 0 pep-0215.txt => peps/pep-0215.rst | 0 pep-0216.txt => peps/pep-0216.rst | 0 pep-0217.txt => peps/pep-0217.rst | 0 pep-0218.txt => peps/pep-0218.rst | 0 pep-0219.txt => peps/pep-0219.rst | 0 pep-0220.txt => peps/pep-0220.rst | 0 pep-0221.txt => peps/pep-0221.rst | 0 pep-0222.txt => peps/pep-0222.rst | 0 pep-0223.txt => peps/pep-0223.rst | 0 pep-0224.txt => peps/pep-0224.rst | 0 pep-0225.txt => peps/pep-0225.rst | 0 pep-0226.txt => peps/pep-0226.rst | 0 pep-0227.txt => peps/pep-0227.rst | 0 pep-0228.txt => peps/pep-0228.rst | 0 pep-0229.txt => peps/pep-0229.rst | 0 pep-0230.txt => peps/pep-0230.rst | 0 pep-0231.txt => peps/pep-0231.rst | 0 pep-0232.txt => peps/pep-0232.rst | 0 pep-0233.txt => peps/pep-0233.rst | 0 pep-0234.txt => peps/pep-0234.rst | 0 pep-0235.txt => peps/pep-0235.rst | 0 pep-0236.txt => peps/pep-0236.rst | 0 pep-0237.txt => peps/pep-0237.rst | 0 pep-0238.txt => peps/pep-0238.rst | 0 pep-0239.txt => peps/pep-0239.rst | 0 pep-0240.txt => peps/pep-0240.rst | 0 pep-0241.txt => peps/pep-0241.rst | 0 pep-0242.txt => peps/pep-0242.rst | 0 pep-0243.txt => peps/pep-0243.rst | 0 pep-0244.txt => peps/pep-0244.rst | 0 pep-0245.txt => peps/pep-0245.rst | 0 pep-0246.txt => peps/pep-0246.rst | 0 pep-0247.txt => peps/pep-0247.rst | 0 pep-0248.txt => peps/pep-0248.rst | 0 pep-0249.txt => peps/pep-0249.rst | 0 pep-0250.txt => peps/pep-0250.rst | 0 pep-0251.txt => peps/pep-0251.rst | 0 pep-0252.txt => peps/pep-0252.rst | 0 pep-0253.txt => peps/pep-0253.rst | 0 pep-0254.txt => peps/pep-0254.rst | 0 pep-0255.txt => peps/pep-0255.rst | 0 pep-0256.txt => peps/pep-0256.rst | 0 pep-0257.txt => peps/pep-0257.rst | 0 pep-0258.txt => peps/pep-0258.rst | 0 pep-0259.txt => peps/pep-0259.rst | 0 pep-0260.txt => peps/pep-0260.rst | 0 pep-0261.txt => peps/pep-0261.rst | 0 pep-0262.txt => peps/pep-0262.rst | 0 pep-0263.txt => peps/pep-0263.rst | 0 pep-0264.txt => peps/pep-0264.rst | 0 pep-0265.txt => peps/pep-0265.rst | 0 pep-0266.txt => peps/pep-0266.rst | 0 pep-0267.txt => peps/pep-0267.rst | 0 pep-0268.txt => peps/pep-0268.rst | 0 pep-0269.txt => peps/pep-0269.rst | 0 pep-0270.txt => peps/pep-0270.rst | 0 pep-0271.txt => peps/pep-0271.rst | 0 pep-0272.txt => peps/pep-0272.rst | 0 pep-0273.txt => peps/pep-0273.rst | 0 pep-0274.txt => peps/pep-0274.rst | 0 pep-0275.txt => peps/pep-0275.rst | 0 pep-0276.txt => peps/pep-0276.rst | 0 pep-0277.txt => peps/pep-0277.rst | 0 pep-0278.txt => peps/pep-0278.rst | 0 pep-0279.txt => peps/pep-0279.rst | 0 pep-0280.txt => peps/pep-0280.rst | 0 pep-0281.txt => peps/pep-0281.rst | 0 pep-0282.txt => peps/pep-0282.rst | 0 pep-0283.txt => peps/pep-0283.rst | 0 pep-0284.txt => peps/pep-0284.rst | 0 pep-0285.txt => peps/pep-0285.rst | 0 pep-0286.txt => peps/pep-0286.rst | 0 pep-0287.txt => peps/pep-0287.rst | 0 pep-0288.txt => peps/pep-0288.rst | 0 pep-0289.txt => peps/pep-0289.rst | 0 pep-0290.txt => peps/pep-0290.rst | 0 pep-0291.txt => peps/pep-0291.rst | 0 pep-0292.txt => peps/pep-0292.rst | 0 pep-0293.txt => peps/pep-0293.rst | 0 pep-0294.txt => peps/pep-0294.rst | 0 pep-0295.txt => peps/pep-0295.rst | 0 pep-0296.txt => peps/pep-0296.rst | 0 pep-0297.txt => peps/pep-0297.rst | 0 pep-0298.txt => peps/pep-0298.rst | 0 pep-0299.txt => peps/pep-0299.rst | 0 pep-0301.txt => peps/pep-0301.rst | 0 pep-0302.txt => peps/pep-0302.rst | 0 pep-0303.txt => peps/pep-0303.rst | 0 pep-0304.txt => peps/pep-0304.rst | 0 pep-0305.txt => peps/pep-0305.rst | 0 pep-0306.txt => peps/pep-0306.rst | 0 pep-0307.txt => peps/pep-0307.rst | 0 pep-0308.txt => peps/pep-0308.rst | 0 pep-0309.txt => peps/pep-0309.rst | 0 pep-0310.txt => peps/pep-0310.rst | 0 pep-0311.txt => peps/pep-0311.rst | 0 pep-0312.txt => peps/pep-0312.rst | 0 pep-0313.txt => peps/pep-0313.rst | 0 pep-0314.txt => peps/pep-0314.rst | 0 pep-0315.txt => peps/pep-0315.rst | 0 pep-0316.txt => peps/pep-0316.rst | 0 pep-0317.txt => peps/pep-0317.rst | 0 pep-0318.txt => peps/pep-0318.rst | 0 pep-0319.txt => peps/pep-0319.rst | 0 pep-0320.txt => peps/pep-0320.rst | 0 pep-0321.txt => peps/pep-0321.rst | 0 pep-0322.txt => peps/pep-0322.rst | 0 pep-0323.txt => peps/pep-0323.rst | 0 pep-0324.txt => peps/pep-0324.rst | 0 pep-0325.txt => peps/pep-0325.rst | 0 pep-0326.txt => peps/pep-0326.rst | 0 pep-0327.txt => peps/pep-0327.rst | 0 pep-0328.txt => peps/pep-0328.rst | 0 pep-0329.txt => peps/pep-0329.rst | 0 pep-0330.txt => peps/pep-0330.rst | 0 pep-0331.txt => peps/pep-0331.rst | 0 pep-0332.txt => peps/pep-0332.rst | 0 pep-0333.txt => peps/pep-0333.rst | 0 pep-0334.txt => peps/pep-0334.rst | 0 pep-0335.txt => peps/pep-0335.rst | 0 pep-0336.txt => peps/pep-0336.rst | 0 pep-0337.txt => peps/pep-0337.rst | 0 pep-0338.txt => peps/pep-0338.rst | 0 pep-0339.txt => peps/pep-0339.rst | 0 pep-0340.txt => peps/pep-0340.rst | 0 pep-0341.txt => peps/pep-0341.rst | 0 pep-0342.txt => peps/pep-0342.rst | 0 pep-0343.txt => peps/pep-0343.rst | 0 pep-0344.txt => peps/pep-0344.rst | 0 pep-0345.txt => peps/pep-0345.rst | 0 pep-0346.txt => peps/pep-0346.rst | 0 pep-0347.txt => peps/pep-0347.rst | 0 pep-0348.txt => peps/pep-0348.rst | 0 pep-0349.txt => peps/pep-0349.rst | 0 pep-0350.txt => peps/pep-0350.rst | 0 pep-0351.txt => peps/pep-0351.rst | 0 pep-0352.txt => peps/pep-0352.rst | 0 pep-0353.txt => peps/pep-0353.rst | 0 pep-0354.txt => peps/pep-0354.rst | 0 pep-0355.txt => peps/pep-0355.rst | 0 pep-0356.txt => peps/pep-0356.rst | 0 pep-0357.txt => peps/pep-0357.rst | 0 pep-0358.txt => peps/pep-0358.rst | 0 pep-0359.txt => peps/pep-0359.rst | 0 pep-0360.txt => peps/pep-0360.rst | 0 pep-0361.txt => peps/pep-0361.rst | 0 pep-0362.txt => peps/pep-0362.rst | 0 pep-0363.txt => peps/pep-0363.rst | 0 pep-0364.txt => peps/pep-0364.rst | 0 pep-0365.txt => peps/pep-0365.rst | 0 pep-0366.txt => peps/pep-0366.rst | 0 pep-0367.txt => peps/pep-0367.rst | 0 pep-0368.txt => peps/pep-0368.rst | 0 pep-0369.txt => peps/pep-0369.rst | 0 pep-0370.txt => peps/pep-0370.rst | 0 pep-0371.txt => peps/pep-0371.rst | 0 pep-0372.txt => peps/pep-0372.rst | 0 pep-0373.txt => peps/pep-0373.rst | 0 pep-0374.txt => peps/pep-0374.rst | 0 pep-0375.txt => peps/pep-0375.rst | 0 pep-0376.txt => peps/pep-0376.rst | 0 pep-0377.txt => peps/pep-0377.rst | 0 pep-0378.txt => peps/pep-0378.rst | 0 pep-0379.txt => peps/pep-0379.rst | 0 pep-0380.txt => peps/pep-0380.rst | 0 pep-0381.txt => peps/pep-0381.rst | 0 pep-0382.txt => peps/pep-0382.rst | 0 pep-0383.txt => peps/pep-0383.rst | 0 pep-0384.txt => peps/pep-0384.rst | 0 pep-0385.txt => peps/pep-0385.rst | 0 pep-0386.txt => peps/pep-0386.rst | 0 pep-0387.txt => peps/pep-0387.rst | 0 pep-0389.txt => peps/pep-0389.rst | 0 pep-0390.txt => peps/pep-0390.rst | 0 pep-0391.txt => peps/pep-0391.rst | 0 pep-0392.txt => peps/pep-0392.rst | 0 pep-0393.txt => peps/pep-0393.rst | 0 pep-0394.txt => peps/pep-0394.rst | 0 pep-0395.txt => peps/pep-0395.rst | 0 pep-0396.txt => peps/pep-0396.rst | 0 pep-0397.txt => peps/pep-0397.rst | 0 pep-0398.txt => peps/pep-0398.rst | 0 pep-0399.txt => peps/pep-0399.rst | 0 pep-0400.txt => peps/pep-0400.rst | 0 pep-0401.txt => peps/pep-0401.rst | 0 pep-0402.txt => peps/pep-0402.rst | 0 pep-0403.txt => peps/pep-0403.rst | 0 pep-0404.txt => peps/pep-0404.rst | 0 pep-0405.txt => peps/pep-0405.rst | 0 pep-0406.txt => peps/pep-0406.rst | 0 pep-0407.txt => peps/pep-0407.rst | 0 pep-0408.txt => peps/pep-0408.rst | 0 pep-0409.txt => peps/pep-0409.rst | 0 pep-0410.txt => peps/pep-0410.rst | 0 pep-0411.txt => peps/pep-0411.rst | 0 pep-0412.txt => peps/pep-0412.rst | 0 pep-0413.txt => peps/pep-0413.rst | 0 pep-0414.txt => peps/pep-0414.rst | 0 pep-0415.txt => peps/pep-0415.rst | 0 pep-0416.txt => peps/pep-0416.rst | 0 pep-0417.txt => peps/pep-0417.rst | 0 pep-0418.txt => peps/pep-0418.rst | 0 {pep-0418 => peps/pep-0418}/bench_time.c | 0 .../pep-0418}/clock_resolution.py | 0 {pep-0418 => peps/pep-0418}/clockutils.py | 0 pep-0419.txt => peps/pep-0419.rst | 0 pep-0420.txt => peps/pep-0420.rst | 0 pep-0421.txt => peps/pep-0421.rst | 0 pep-0422.txt => peps/pep-0422.rst | 0 pep-0423.txt => peps/pep-0423.rst | 0 pep-0424.txt => peps/pep-0424.rst | 0 pep-0425.txt => peps/pep-0425.rst | 0 pep-0426.txt => peps/pep-0426.rst | 0 {pep-0426 => peps/pep-0426}/pepsort.py | 0 .../pep-0426}/pydist-schema.json | 0 pep-0427.txt => peps/pep-0427.rst | 0 pep-0428.txt => peps/pep-0428.rst | 0 pep-0429.txt => peps/pep-0429.rst | 0 pep-0430.txt => peps/pep-0430.rst | 0 pep-0431.txt => peps/pep-0431.rst | 0 pep-0432.txt => peps/pep-0432.rst | 0 pep-0433.txt => peps/pep-0433.rst | 0 {pep-0433 => peps/pep-0433}/bench_cloexec.py | 0 {pep-0433 => peps/pep-0433}/openbsd_bug.py | 0 pep-0434.txt => peps/pep-0434.rst | 0 pep-0435.txt => peps/pep-0435.rst | 0 pep-0436.txt => peps/pep-0436.rst | 0 pep-0437.txt => peps/pep-0437.rst | 0 pep-0438.txt => peps/pep-0438.rst | 0 pep-0439.txt => peps/pep-0439.rst | 0 pep-0440.txt => peps/pep-0440.rst | 0 pep-0441.txt => peps/pep-0441.rst | 0 pep-0442.txt => peps/pep-0442.rst | 0 pep-0443.txt => peps/pep-0443.rst | 0 pep-0444.txt => peps/pep-0444.rst | 0 pep-0445.txt => peps/pep-0445.rst | 0 pep-0446.txt => peps/pep-0446.rst | 0 {pep-0446 => peps/pep-0446}/test_cloexec.py | 0 pep-0447.txt => peps/pep-0447.rst | 0 pep-0448.txt => peps/pep-0448.rst | 0 pep-0449.txt => peps/pep-0449.rst | 0 pep-0450.txt => peps/pep-0450.rst | 0 pep-0451.txt => peps/pep-0451.rst | 0 pep-0452.txt => peps/pep-0452.rst | 0 pep-0453.txt => peps/pep-0453.rst | 0 pep-0454.txt => peps/pep-0454.rst | 0 pep-0455.txt => peps/pep-0455.rst | 0 pep-0456.txt => peps/pep-0456.rst | 0 pep-0457.txt => peps/pep-0457.rst | 0 pep-0458-1.png => peps/pep-0458-1.png | Bin pep-0458.txt => peps/pep-0458.rst | 0 pep-0459.txt => peps/pep-0459.rst | 0 pep-0460.txt => peps/pep-0460.rst | 0 pep-0461.txt => peps/pep-0461.rst | 0 pep-0462.txt => peps/pep-0462.rst | 0 pep-0463.txt => peps/pep-0463.rst | 0 pep-0464.txt => peps/pep-0464.rst | 0 pep-0465.txt => peps/pep-0465.rst | 0 {pep-0465 => peps/pep-0465}/scan-ops.py | 0 pep-0466.txt => peps/pep-0466.rst | 0 pep-0467.txt => peps/pep-0467.rst | 0 pep-0468.txt => peps/pep-0468.rst | 0 pep-0469.txt => peps/pep-0469.rst | 0 pep-0470.txt => peps/pep-0470.rst | 0 pep-0471.txt => peps/pep-0471.rst | 0 pep-0472.txt => peps/pep-0472.rst | 0 pep-0473.txt => peps/pep-0473.rst | 0 pep-0474.txt => peps/pep-0474.rst | 0 pep-0475.txt => peps/pep-0475.rst | 0 pep-0476.txt => peps/pep-0476.rst | 0 pep-0477.txt => peps/pep-0477.rst | 0 pep-0478.txt => peps/pep-0478.rst | 0 pep-0479.txt => peps/pep-0479.rst | 0 pep-0480-1.png => peps/pep-0480-1.png | Bin pep-0480.txt => peps/pep-0480.rst | 0 pep-0481.txt => peps/pep-0481.rst | 0 pep-0482.txt => peps/pep-0482.rst | 0 pep-0483.txt => peps/pep-0483.rst | 0 pep-0484.txt => peps/pep-0484.rst | 0 pep-0485.txt => peps/pep-0485.rst | 0 pep-0486.txt => peps/pep-0486.rst | 0 pep-0487.txt => peps/pep-0487.rst | 0 pep-0488.txt => peps/pep-0488.rst | 0 pep-0489.txt => peps/pep-0489.rst | 0 pep-0490.txt => peps/pep-0490.rst | 0 pep-0491.txt => peps/pep-0491.rst | 0 pep-0492.txt => peps/pep-0492.rst | 0 pep-0493.txt => peps/pep-0493.rst | 0 pep-0494.txt => peps/pep-0494.rst | 0 .../pep-0495-daylightsavings.png | Bin pep-0495-fold.svg => peps/pep-0495-fold.svg | 0 pep-0495-gap.svg => peps/pep-0495-gap.svg | 0 pep-0495.txt => peps/pep-0495.rst | 0 pep-0496.txt => peps/pep-0496.rst | 0 pep-0497.txt => peps/pep-0497.rst | 0 pep-0498.txt => peps/pep-0498.rst | 0 pep-0499.txt => peps/pep-0499.rst | 0 pep-0500.txt => peps/pep-0500.rst | 0 pep-0501.txt => peps/pep-0501.rst | 0 pep-0502.txt => peps/pep-0502.rst | 0 pep-0503.txt => peps/pep-0503.rst | 0 pep-0504.txt => peps/pep-0504.rst | 0 pep-0505.rst => peps/pep-0505.rst | 0 {pep-0505 => peps/pep-0505}/find-pep505.out | 0 {pep-0505 => peps/pep-0505}/find-pep505.py | 0 {pep-0505 => peps/pep-0505}/test.py | 0 pep-0506.txt => peps/pep-0506.rst | 0 pep-0507.txt => peps/pep-0507.rst | 0 pep-0508.txt => peps/pep-0508.rst | 0 pep-0509.txt => peps/pep-0509.rst | 0 pep-0510.txt => peps/pep-0510.rst | 0 pep-0511.txt => peps/pep-0511.rst | 0 pep-0512.txt => peps/pep-0512.rst | 0 pep-0513.txt => peps/pep-0513.rst | 0 pep-0514.txt => peps/pep-0514.rst | 0 pep-0515.txt => peps/pep-0515.rst | 0 pep-0516.txt => peps/pep-0516.rst | 0 pep-0517.txt => peps/pep-0517.rst | 0 pep-0518.txt => peps/pep-0518.rst | 0 pep-0519.txt => peps/pep-0519.rst | 0 pep-0520.txt => peps/pep-0520.rst | 0 pep-0521.txt => peps/pep-0521.rst | 0 pep-0522.txt => peps/pep-0522.rst | 0 pep-0523.txt => peps/pep-0523.rst | 0 pep-0524.txt => peps/pep-0524.rst | 0 pep-0525-1.png => peps/pep-0525-1.png | Bin pep-0525.txt => peps/pep-0525.rst | 0 pep-0526.txt => peps/pep-0526.rst | 0 pep-0527.txt => peps/pep-0527.rst | 0 pep-0528.txt => peps/pep-0528.rst | 0 pep-0529.txt => peps/pep-0529.rst | 0 pep-0530.txt => peps/pep-0530.rst | 0 pep-0531.txt => peps/pep-0531.rst | 0 pep-0532.txt => peps/pep-0532.rst | 0 .../pep-0532}/circuit-breaking-protocol.svg | 0 pep-0533.txt => peps/pep-0533.rst | 0 pep-0534.txt => peps/pep-0534.rst | 0 pep-0535.txt => peps/pep-0535.rst | 0 pep-0536.txt => peps/pep-0536.rst | 0 pep-0537.txt => peps/pep-0537.rst | 0 pep-0538.txt => peps/pep-0538.rst | 0 pep-0539.txt => peps/pep-0539.rst | 0 pep-0540.txt => peps/pep-0540.rst | 0 pep-0541.txt => peps/pep-0541.rst | 0 pep-0542.txt => peps/pep-0542.rst | 0 pep-0543.rst => peps/pep-0543.rst | 0 pep-0544.txt => peps/pep-0544.rst | 0 pep-0545.txt => peps/pep-0545.rst | 0 pep-0546.txt => peps/pep-0546.rst | 0 pep-0547.rst => peps/pep-0547.rst | 0 pep-0548.rst => peps/pep-0548.rst | 0 pep-0549.rst => peps/pep-0549.rst | 0 .../pep-0550-hamt_vs_dict-v2.png | Bin .../pep-0550-hamt_vs_dict.png | Bin .../pep-0550-lookup_hamt.png | Bin pep-0550.rst => peps/pep-0550.rst | 0 pep-0551.rst => peps/pep-0551.rst | 0 pep-0552.rst => peps/pep-0552.rst | 0 pep-0553.rst => peps/pep-0553.rst | 0 pep-0554.rst => peps/pep-0554.rst | 0 pep-0555.rst => peps/pep-0555.rst | 0 pep-0556.rst => peps/pep-0556.rst | 0 pep-0557.rst => peps/pep-0557.rst | 0 pep-0558.rst => peps/pep-0558.rst | 0 pep-0559.rst => peps/pep-0559.rst | 0 pep-0560.rst => peps/pep-0560.rst | 0 pep-0561.rst => peps/pep-0561.rst | 0 pep-0562.rst => peps/pep-0562.rst | 0 pep-0563.rst => peps/pep-0563.rst | 0 pep-0564.rst => peps/pep-0564.rst | 0 pep-0565.rst => peps/pep-0565.rst | 0 pep-0566.rst => peps/pep-0566.rst | 0 pep-0567.rst => peps/pep-0567.rst | 0 pep-0568.rst => peps/pep-0568.rst | 0 pep-0569.rst => peps/pep-0569.rst | 0 pep-0570.rst => peps/pep-0570.rst | 0 pep-0571.rst => peps/pep-0571.rst | 0 pep-0572.rst => peps/pep-0572.rst | 0 pep-0573.rst => peps/pep-0573.rst | 0 pep-0574.rst => peps/pep-0574.rst | 0 pep-0575.rst => peps/pep-0575.rst | 0 pep-0576.rst => peps/pep-0576.rst | 0 pep-0577.rst => peps/pep-0577.rst | 0 pep-0578.rst => peps/pep-0578.rst | 0 pep-0579.rst => peps/pep-0579.rst | 0 pep-0580.rst => peps/pep-0580.rst | 0 pep-0581.rst => peps/pep-0581.rst | 0 pep-0582.rst => peps/pep-0582.rst | 0 pep-0583.rst => peps/pep-0583.rst | 0 pep-0584.rst => peps/pep-0584.rst | 0 pep-0585.rst => peps/pep-0585.rst | 0 pep-0586.rst => peps/pep-0586.rst | 0 pep-0587.rst => peps/pep-0587.rst | 0 pep-0588.rst => peps/pep-0588.rst | 0 pep-0589.rst => peps/pep-0589.rst | 0 pep-0590.rst => peps/pep-0590.rst | 0 pep-0591.rst => peps/pep-0591.rst | 0 pep-0592.rst => peps/pep-0592.rst | 0 pep-0593.rst => peps/pep-0593.rst | 0 pep-0594.rst => peps/pep-0594.rst | 0 pep-0595.rst => peps/pep-0595.rst | 0 pep-0596.rst => peps/pep-0596.rst | 0 pep-0597.rst => peps/pep-0597.rst | 0 pep-0598.rst => peps/pep-0598.rst | 0 pep-0599.rst => peps/pep-0599.rst | 0 pep-0600.rst => peps/pep-0600.rst | 0 pep-0601.txt => peps/pep-0601.rst | 0 .../pep-0602-example-release-calendar.png | Bin .../pep-0602-example-release-calendar.pptx | Bin .../pep-0602-overlapping-support-matrix.png | Bin .../pep-0602-overlapping-support-matrix.pptx | Bin pep-0602.rst => peps/pep-0602.rst | 0 .../pep-0603-hamt_vs_dict.png | Bin .../pep-0603-lookup_hamt.png | Bin pep-0603.rst => peps/pep-0603.rst | 0 pep-0604.rst => peps/pep-0604.rst | 0 .../pep-0605-example-release-calendar.png | Bin .../pep-0605-overlapping-support-matrix.png | Bin pep-0605.rst => peps/pep-0605.rst | 0 .../pep-0605}/example-release-calendar.odp | Bin .../pep-0605}/overlapping-support-matrix.odp | Bin pep-0606.rst => peps/pep-0606.rst | 0 pep-0607.rst => peps/pep-0607.rst | 0 pep-0608.rst => peps/pep-0608.rst | 0 pep-0609.rst => peps/pep-0609.rst | 0 pep-0610.rst => peps/pep-0610.rst | 0 pep-0611.rst => peps/pep-0611.rst | 0 pep-0612.rst => peps/pep-0612.rst | 0 pep-0613.rst => peps/pep-0613.rst | 0 pep-0614.rst => peps/pep-0614.rst | 0 pep-0615.rst => peps/pep-0615.rst | 0 pep-0616.rst => peps/pep-0616.rst | 0 pep-0617.rst => peps/pep-0617.rst | 0 pep-0618.rst => peps/pep-0618.rst | 0 pep-0619.rst => peps/pep-0619.rst | 0 pep-0620.rst => peps/pep-0620.rst | 0 pep-0621.rst => peps/pep-0621.rst | 0 pep-0622.rst => peps/pep-0622.rst | 0 pep-0623.rst => peps/pep-0623.rst | 0 pep-0624.rst => peps/pep-0624.rst | 0 pep-0625.rst => peps/pep-0625.rst | 0 pep-0626.rst => peps/pep-0626.rst | 0 pep-0627.rst => peps/pep-0627.rst | 0 pep-0628.txt => peps/pep-0628.rst | 0 pep-0629.rst => peps/pep-0629.rst | 0 pep-0630.rst => peps/pep-0630.rst | 0 pep-0631.rst => peps/pep-0631.rst | 0 pep-0632.rst => peps/pep-0632.rst | 0 pep-0633.rst => peps/pep-0633.rst | 0 pep-0634.rst => peps/pep-0634.rst | 0 pep-0635.rst => peps/pep-0635.rst | 0 pep-0636.rst => peps/pep-0636.rst | 0 pep-0637.rst => peps/pep-0637.rst | 0 pep-0638.rst => peps/pep-0638.rst | 0 pep-0639.rst => peps/pep-0639.rst | 0 pep-0640.rst => peps/pep-0640.rst | 0 pep-0641.rst => peps/pep-0641.rst | 0 pep-0642.rst => peps/pep-0642.rst | 0 pep-0643.rst => peps/pep-0643.rst | 0 pep-0644.rst => peps/pep-0644.rst | 0 pep-0645.rst => peps/pep-0645.rst | 0 pep-0646.rst => peps/pep-0646.rst | 0 pep-0647.rst => peps/pep-0647.rst | 0 pep-0648.rst => peps/pep-0648.rst | 0 pep-0649.rst => peps/pep-0649.rst | 0 pep-0650.rst => peps/pep-0650.rst | 0 pep-0651.rst => peps/pep-0651.rst | 0 pep-0652.rst => peps/pep-0652.rst | 0 pep-0653.rst => peps/pep-0653.rst | 0 pep-0654.rst => peps/pep-0654.rst | 0 pep-0655.rst => peps/pep-0655.rst | 0 pep-0656.rst => peps/pep-0656.rst | 0 pep-0657.rst => peps/pep-0657.rst | 0 pep-0658.rst => peps/pep-0658.rst | 0 pep-0659.rst => peps/pep-0659.rst | 0 pep-0660.rst => peps/pep-0660.rst | 0 pep-0661.rst => peps/pep-0661.rst | 0 pep-0662.rst => peps/pep-0662.rst | 0 .../pep-0662}/pep-0662-editable.json | 0 pep-0663.txt => peps/pep-0663.rst | 0 pep-0664.rst => peps/pep-0664.rst | 0 pep-0665.rst => peps/pep-0665.rst | 0 pep-0666.txt => peps/pep-0666.rst | 0 pep-0667.rst => peps/pep-0667.rst | 0 pep-0668.rst => peps/pep-0668.rst | 0 pep-0669.rst => peps/pep-0669.rst | 0 pep-0670.rst => peps/pep-0670.rst | 0 pep-0671.rst => peps/pep-0671.rst | 0 pep-0672.rst => peps/pep-0672.rst | 0 pep-0673.rst => peps/pep-0673.rst | 0 pep-0674.rst => peps/pep-0674.rst | 0 pep-0675.rst => peps/pep-0675.rst | 0 pep-0676.rst => peps/pep-0676.rst | 0 pep-0677.rst => peps/pep-0677.rst | 0 pep-0678.rst => peps/pep-0678.rst | 0 pep-0679.rst => peps/pep-0679.rst | 0 pep-0680.rst => peps/pep-0680.rst | 0 pep-0681.rst => peps/pep-0681.rst | 0 pep-0682.rst => peps/pep-0682.rst | 0 pep-0683.rst => peps/pep-0683.rst | 0 pep-0684.rst => peps/pep-0684.rst | 0 pep-0685.rst => peps/pep-0685.rst | 0 pep-0686.rst => peps/pep-0686.rst | 0 pep-0687.rst => peps/pep-0687.rst | 0 pep-0688.rst => peps/pep-0688.rst | 0 pep-0689.rst => peps/pep-0689.rst | 0 pep-0690.rst => peps/pep-0690.rst | 0 pep-0691.rst => peps/pep-0691.rst | 0 pep-0692.rst => peps/pep-0692.rst | 0 pep-0693.rst => peps/pep-0693.rst | 0 pep-0694.rst => peps/pep-0694.rst | 0 pep-0695.rst => peps/pep-0695.rst | 0 pep-0696.rst => peps/pep-0696.rst | 0 pep-0697.rst => peps/pep-0697.rst | 0 pep-0698.rst => peps/pep-0698.rst | 0 pep-0699.rst => peps/pep-0699.rst | 0 pep-0700.rst => peps/pep-0700.rst | 0 pep-0701.rst => peps/pep-0701.rst | 0 pep-0702.rst => peps/pep-0702.rst | 0 pep-0703.rst => peps/pep-0703.rst | 0 pep-0704.rst => peps/pep-0704.rst | 0 pep-0705.rst => peps/pep-0705.rst | 0 pep-0706.rst => peps/pep-0706.rst | 0 pep-0707.rst => peps/pep-0707.rst | 0 pep-0708.rst => peps/pep-0708.rst | 0 pep-0709.rst => peps/pep-0709.rst | 0 pep-0710.rst => peps/pep-0710.rst | 0 pep-0711.rst => peps/pep-0711.rst | 0 pep-0712.rst => peps/pep-0712.rst | 0 pep-0713.rst => peps/pep-0713.rst | 0 pep-0714.rst => peps/pep-0714.rst | 0 pep-0715.rst => peps/pep-0715.rst | 0 pep-0718.rst => peps/pep-0718.rst | 0 pep-0719.rst => peps/pep-0719.rst | 0 pep-0720.rst => peps/pep-0720.rst | 0 pep-0721.rst => peps/pep-0721.rst | 0 pep-0722.rst => peps/pep-0722.rst | 0 pep-0723.rst => peps/pep-0723.rst | 0 pep-0725.rst => peps/pep-0725.rst | 0 pep-0726.rst => peps/pep-0726.rst | 0 pep-0727.rst => peps/pep-0727.rst | 0 pep-0754.txt => peps/pep-0754.rst | 0 pep-0801.rst => peps/pep-0801.rst | 0 pep-3000.txt => peps/pep-3000.rst | 0 pep-3001.txt => peps/pep-3001.rst | 0 pep-3002.txt => peps/pep-3002.rst | 0 pep-3003.txt => peps/pep-3003.rst | 0 pep-3099.txt => peps/pep-3099.rst | 0 pep-3100.txt => peps/pep-3100.rst | 0 pep-3101.txt => peps/pep-3101.rst | 0 pep-3102.txt => peps/pep-3102.rst | 0 pep-3103.txt => peps/pep-3103.rst | 0 pep-3104.txt => peps/pep-3104.rst | 0 pep-3105.txt => peps/pep-3105.rst | 0 pep-3106.txt => peps/pep-3106.rst | 0 pep-3107.txt => peps/pep-3107.rst | 0 pep-3108.txt => peps/pep-3108.rst | 0 pep-3109.txt => peps/pep-3109.rst | 0 pep-3110.txt => peps/pep-3110.rst | 0 pep-3111.txt => peps/pep-3111.rst | 0 pep-3112.txt => peps/pep-3112.rst | 0 pep-3113.txt => peps/pep-3113.rst | 0 pep-3114.txt => peps/pep-3114.rst | 0 pep-3115.txt => peps/pep-3115.rst | 0 pep-3116.txt => peps/pep-3116.rst | 0 pep-3117.txt => peps/pep-3117.rst | 0 pep-3118.txt => peps/pep-3118.rst | 0 pep-3119.txt => peps/pep-3119.rst | 0 pep-3120.txt => peps/pep-3120.rst | 0 pep-3121.txt => peps/pep-3121.rst | 0 pep-3122.txt => peps/pep-3122.rst | 0 pep-3123.txt => peps/pep-3123.rst | 0 pep-3124.txt => peps/pep-3124.rst | 0 pep-3125.txt => peps/pep-3125.rst | 0 pep-3126.txt => peps/pep-3126.rst | 0 pep-3127.txt => peps/pep-3127.rst | 0 pep-3128.txt => peps/pep-3128.rst | 0 pep-3129.txt => peps/pep-3129.rst | 0 pep-3130.txt => peps/pep-3130.rst | 0 pep-3131.txt => peps/pep-3131.rst | 0 pep-3132.txt => peps/pep-3132.rst | 0 pep-3133.txt => peps/pep-3133.rst | 0 pep-3134.txt => peps/pep-3134.rst | 0 pep-3135.txt => peps/pep-3135.rst | 0 pep-3136.txt => peps/pep-3136.rst | 0 pep-3137.txt => peps/pep-3137.rst | 0 pep-3138.txt => peps/pep-3138.rst | 0 pep-3139.txt => peps/pep-3139.rst | 0 pep-3140.txt => peps/pep-3140.rst | 0 pep-3141.txt => peps/pep-3141.rst | 0 pep-3142.txt => peps/pep-3142.rst | 0 pep-3143.txt => peps/pep-3143.rst | 0 pep-3144.txt => peps/pep-3144.rst | 0 pep-3145.txt => peps/pep-3145.rst | 0 pep-3146.txt => peps/pep-3146.rst | 0 pep-3147-1.dia => peps/pep-3147-1.dia | Bin pep-3147-1.png => peps/pep-3147-1.png | Bin pep-3147.txt => peps/pep-3147.rst | 0 pep-3148.txt => peps/pep-3148.rst | 0 pep-3149.txt => peps/pep-3149.rst | 0 pep-3150.txt => peps/pep-3150.rst | 0 pep-3151.txt => peps/pep-3151.rst | 0 pep-3152.txt => peps/pep-3152.rst | 0 pep-3153.txt => peps/pep-3153.rst | 0 pep-3154.txt => peps/pep-3154.rst | 0 pep-3155.txt => peps/pep-3155.rst | 0 pep-3156.txt => peps/pep-3156.rst | 0 pep-3333.txt => peps/pep-3333.rst | 0 pep-8000.rst => peps/pep-8000.rst | 0 pep-8001.rst => peps/pep-8001.rst | 0 pep-8002.rst => peps/pep-8002.rst | 0 pep-8010.rst => peps/pep-8010.rst | 0 pep-8011.rst => peps/pep-8011.rst | 0 pep-8012.rst => peps/pep-8012.rst | 0 pep-8013.rst => peps/pep-8013.rst | 0 pep-8014.rst => peps/pep-8014.rst | 0 pep-8015.rst => peps/pep-8015.rst | 0 pep-8016.rst => peps/pep-8016.rst | 0 pep-8100.rst => peps/pep-8100.rst | 0 pep-8101.rst => peps/pep-8101.rst | 0 pep-8102.rst => peps/pep-8102.rst | 0 pep-8103.rst => peps/pep-8103.rst | 0 pep-8104.rst => peps/pep-8104.rst | 0 678 files changed, 732 insertions(+), 762 deletions(-) rename conf.py => peps/conf.py (96%) rename contents.rst => peps/contents.rst (97%) rename pep-0001.txt => peps/pep-0001.rst (100%) rename {pep-0001 => peps/pep-0001}/process_flow.svg (100%) rename pep-0002.txt => peps/pep-0002.rst (100%) rename pep-0003.txt => peps/pep-0003.rst (100%) rename pep-0004.txt => peps/pep-0004.rst (100%) rename pep-0005.txt => peps/pep-0005.rst (100%) rename pep-0006.txt => peps/pep-0006.rst (100%) rename pep-0007.txt => peps/pep-0007.rst (100%) rename pep-0008.txt => peps/pep-0008.rst (100%) rename pep-0009.txt => peps/pep-0009.rst (100%) rename pep-0010.txt => peps/pep-0010.rst (100%) rename pep-0011.txt => peps/pep-0011.rst (100%) rename pep-0012.rst => peps/pep-0012.rst (100%) rename {pep-0012 => peps/pep-0012}/pep-NNNN.rst (100%) rename pep-0013.rst => peps/pep-0013.rst (100%) rename pep-0020.txt => peps/pep-0020.rst (100%) rename pep-0042.txt => peps/pep-0042.rst (100%) rename pep-0100.txt => peps/pep-0100.rst (100%) rename pep-0101.txt => peps/pep-0101.rst (100%) rename pep-0102.txt => peps/pep-0102.rst (100%) rename pep-0103.txt => peps/pep-0103.rst (100%) rename pep-0160.txt => peps/pep-0160.rst (100%) rename pep-0200.txt => peps/pep-0200.rst (100%) rename pep-0201.txt => peps/pep-0201.rst (100%) rename pep-0202.txt => peps/pep-0202.rst (100%) rename pep-0203.txt => peps/pep-0203.rst (100%) rename pep-0204.txt => peps/pep-0204.rst (100%) rename pep-0205.txt => peps/pep-0205.rst (100%) rename pep-0206.txt => peps/pep-0206.rst (100%) rename pep-0207.txt => peps/pep-0207.rst (100%) rename pep-0208.txt => peps/pep-0208.rst (100%) rename pep-0209.txt => peps/pep-0209.rst (100%) rename pep-0210.txt => peps/pep-0210.rst (100%) rename pep-0211.txt => peps/pep-0211.rst (100%) rename pep-0212.txt => peps/pep-0212.rst (100%) rename pep-0213.txt => peps/pep-0213.rst (100%) rename pep-0214.txt => peps/pep-0214.rst (100%) rename pep-0215.txt => peps/pep-0215.rst (100%) rename pep-0216.txt => peps/pep-0216.rst (100%) rename pep-0217.txt => peps/pep-0217.rst (100%) rename pep-0218.txt => peps/pep-0218.rst (100%) rename pep-0219.txt => peps/pep-0219.rst (100%) rename pep-0220.txt => peps/pep-0220.rst (100%) rename pep-0221.txt => peps/pep-0221.rst (100%) rename pep-0222.txt => peps/pep-0222.rst (100%) rename pep-0223.txt => peps/pep-0223.rst (100%) rename pep-0224.txt => peps/pep-0224.rst (100%) rename pep-0225.txt => peps/pep-0225.rst (100%) rename pep-0226.txt => peps/pep-0226.rst (100%) rename pep-0227.txt => peps/pep-0227.rst (100%) rename pep-0228.txt => peps/pep-0228.rst (100%) rename pep-0229.txt => peps/pep-0229.rst (100%) rename pep-0230.txt => peps/pep-0230.rst (100%) rename pep-0231.txt => peps/pep-0231.rst (100%) rename pep-0232.txt => peps/pep-0232.rst (100%) rename pep-0233.txt => peps/pep-0233.rst (100%) rename pep-0234.txt => peps/pep-0234.rst (100%) rename pep-0235.txt => peps/pep-0235.rst (100%) rename pep-0236.txt => peps/pep-0236.rst (100%) rename pep-0237.txt => peps/pep-0237.rst (100%) rename pep-0238.txt => peps/pep-0238.rst (100%) rename pep-0239.txt => peps/pep-0239.rst (100%) rename pep-0240.txt => peps/pep-0240.rst (100%) rename pep-0241.txt => peps/pep-0241.rst (100%) rename pep-0242.txt => peps/pep-0242.rst (100%) rename pep-0243.txt => peps/pep-0243.rst (100%) rename pep-0244.txt => peps/pep-0244.rst (100%) rename pep-0245.txt => peps/pep-0245.rst (100%) rename pep-0246.txt => peps/pep-0246.rst (100%) rename pep-0247.txt => peps/pep-0247.rst (100%) rename pep-0248.txt => peps/pep-0248.rst (100%) rename pep-0249.txt => peps/pep-0249.rst (100%) rename pep-0250.txt => peps/pep-0250.rst (100%) rename pep-0251.txt => peps/pep-0251.rst (100%) rename pep-0252.txt => peps/pep-0252.rst (100%) rename pep-0253.txt => peps/pep-0253.rst (100%) rename pep-0254.txt => peps/pep-0254.rst (100%) rename pep-0255.txt => peps/pep-0255.rst (100%) rename pep-0256.txt => peps/pep-0256.rst (100%) rename pep-0257.txt => peps/pep-0257.rst (100%) rename pep-0258.txt => peps/pep-0258.rst (100%) rename pep-0259.txt => peps/pep-0259.rst (100%) rename pep-0260.txt => peps/pep-0260.rst (100%) rename pep-0261.txt => peps/pep-0261.rst (100%) rename pep-0262.txt => peps/pep-0262.rst (100%) rename pep-0263.txt => peps/pep-0263.rst (100%) rename pep-0264.txt => peps/pep-0264.rst (100%) rename pep-0265.txt => peps/pep-0265.rst (100%) rename pep-0266.txt => peps/pep-0266.rst (100%) rename pep-0267.txt => peps/pep-0267.rst (100%) rename pep-0268.txt => peps/pep-0268.rst (100%) rename pep-0269.txt => peps/pep-0269.rst (100%) rename pep-0270.txt => peps/pep-0270.rst (100%) rename pep-0271.txt => peps/pep-0271.rst (100%) rename pep-0272.txt => peps/pep-0272.rst (100%) rename pep-0273.txt => peps/pep-0273.rst (100%) rename pep-0274.txt => peps/pep-0274.rst (100%) rename pep-0275.txt => peps/pep-0275.rst (100%) rename pep-0276.txt => peps/pep-0276.rst (100%) rename pep-0277.txt => peps/pep-0277.rst (100%) rename pep-0278.txt => peps/pep-0278.rst (100%) rename pep-0279.txt => peps/pep-0279.rst (100%) rename pep-0280.txt => peps/pep-0280.rst (100%) rename pep-0281.txt => peps/pep-0281.rst (100%) rename pep-0282.txt => peps/pep-0282.rst (100%) rename pep-0283.txt => peps/pep-0283.rst (100%) rename pep-0284.txt => peps/pep-0284.rst (100%) rename pep-0285.txt => peps/pep-0285.rst (100%) rename pep-0286.txt => peps/pep-0286.rst (100%) rename pep-0287.txt => peps/pep-0287.rst (100%) rename pep-0288.txt => peps/pep-0288.rst (100%) rename pep-0289.txt => peps/pep-0289.rst (100%) rename pep-0290.txt => peps/pep-0290.rst (100%) rename pep-0291.txt => peps/pep-0291.rst (100%) rename pep-0292.txt => peps/pep-0292.rst (100%) rename pep-0293.txt => peps/pep-0293.rst (100%) rename pep-0294.txt => peps/pep-0294.rst (100%) rename pep-0295.txt => peps/pep-0295.rst (100%) rename pep-0296.txt => peps/pep-0296.rst (100%) rename pep-0297.txt => peps/pep-0297.rst (100%) rename pep-0298.txt => peps/pep-0298.rst (100%) rename pep-0299.txt => peps/pep-0299.rst (100%) rename pep-0301.txt => peps/pep-0301.rst (100%) rename pep-0302.txt => peps/pep-0302.rst (100%) rename pep-0303.txt => peps/pep-0303.rst (100%) rename pep-0304.txt => peps/pep-0304.rst (100%) rename pep-0305.txt => peps/pep-0305.rst (100%) rename pep-0306.txt => peps/pep-0306.rst (100%) rename pep-0307.txt => peps/pep-0307.rst (100%) rename pep-0308.txt => peps/pep-0308.rst (100%) rename pep-0309.txt => peps/pep-0309.rst (100%) rename pep-0310.txt => peps/pep-0310.rst (100%) rename pep-0311.txt => peps/pep-0311.rst (100%) rename pep-0312.txt => peps/pep-0312.rst (100%) rename pep-0313.txt => peps/pep-0313.rst (100%) rename pep-0314.txt => peps/pep-0314.rst (100%) rename pep-0315.txt => peps/pep-0315.rst (100%) rename pep-0316.txt => peps/pep-0316.rst (100%) rename pep-0317.txt => peps/pep-0317.rst (100%) rename pep-0318.txt => peps/pep-0318.rst (100%) rename pep-0319.txt => peps/pep-0319.rst (100%) rename pep-0320.txt => peps/pep-0320.rst (100%) rename pep-0321.txt => peps/pep-0321.rst (100%) rename pep-0322.txt => peps/pep-0322.rst (100%) rename pep-0323.txt => peps/pep-0323.rst (100%) rename pep-0324.txt => peps/pep-0324.rst (100%) rename pep-0325.txt => peps/pep-0325.rst (100%) rename pep-0326.txt => peps/pep-0326.rst (100%) rename pep-0327.txt => peps/pep-0327.rst (100%) rename pep-0328.txt => peps/pep-0328.rst (100%) rename pep-0329.txt => peps/pep-0329.rst (100%) rename pep-0330.txt => peps/pep-0330.rst (100%) rename pep-0331.txt => peps/pep-0331.rst (100%) rename pep-0332.txt => peps/pep-0332.rst (100%) rename pep-0333.txt => peps/pep-0333.rst (100%) rename pep-0334.txt => peps/pep-0334.rst (100%) rename pep-0335.txt => peps/pep-0335.rst (100%) rename pep-0336.txt => peps/pep-0336.rst (100%) rename pep-0337.txt => peps/pep-0337.rst (100%) rename pep-0338.txt => peps/pep-0338.rst (100%) rename pep-0339.txt => peps/pep-0339.rst (100%) rename pep-0340.txt => peps/pep-0340.rst (100%) rename pep-0341.txt => peps/pep-0341.rst (100%) rename pep-0342.txt => peps/pep-0342.rst (100%) rename pep-0343.txt => peps/pep-0343.rst (100%) rename pep-0344.txt => peps/pep-0344.rst (100%) rename pep-0345.txt => peps/pep-0345.rst (100%) rename pep-0346.txt => peps/pep-0346.rst (100%) rename pep-0347.txt => peps/pep-0347.rst (100%) rename pep-0348.txt => peps/pep-0348.rst (100%) rename pep-0349.txt => peps/pep-0349.rst (100%) rename pep-0350.txt => peps/pep-0350.rst (100%) rename pep-0351.txt => peps/pep-0351.rst (100%) rename pep-0352.txt => peps/pep-0352.rst (100%) rename pep-0353.txt => peps/pep-0353.rst (100%) rename pep-0354.txt => peps/pep-0354.rst (100%) rename pep-0355.txt => peps/pep-0355.rst (100%) rename pep-0356.txt => peps/pep-0356.rst (100%) rename pep-0357.txt => peps/pep-0357.rst (100%) rename pep-0358.txt => peps/pep-0358.rst (100%) rename pep-0359.txt => peps/pep-0359.rst (100%) rename pep-0360.txt => peps/pep-0360.rst (100%) rename pep-0361.txt => peps/pep-0361.rst (100%) rename pep-0362.txt => peps/pep-0362.rst (100%) rename pep-0363.txt => peps/pep-0363.rst (100%) rename pep-0364.txt => peps/pep-0364.rst (100%) rename pep-0365.txt => peps/pep-0365.rst (100%) rename pep-0366.txt => peps/pep-0366.rst (100%) rename pep-0367.txt => peps/pep-0367.rst (100%) rename pep-0368.txt => peps/pep-0368.rst (100%) rename pep-0369.txt => peps/pep-0369.rst (100%) rename pep-0370.txt => peps/pep-0370.rst (100%) rename pep-0371.txt => peps/pep-0371.rst (100%) rename pep-0372.txt => peps/pep-0372.rst (100%) rename pep-0373.txt => peps/pep-0373.rst (100%) rename pep-0374.txt => peps/pep-0374.rst (100%) rename pep-0375.txt => peps/pep-0375.rst (100%) rename pep-0376.txt => peps/pep-0376.rst (100%) rename pep-0377.txt => peps/pep-0377.rst (100%) rename pep-0378.txt => peps/pep-0378.rst (100%) rename pep-0379.txt => peps/pep-0379.rst (100%) rename pep-0380.txt => peps/pep-0380.rst (100%) rename pep-0381.txt => peps/pep-0381.rst (100%) rename pep-0382.txt => peps/pep-0382.rst (100%) rename pep-0383.txt => peps/pep-0383.rst (100%) rename pep-0384.txt => peps/pep-0384.rst (100%) rename pep-0385.txt => peps/pep-0385.rst (100%) rename pep-0386.txt => peps/pep-0386.rst (100%) rename pep-0387.txt => peps/pep-0387.rst (100%) rename pep-0389.txt => peps/pep-0389.rst (100%) rename pep-0390.txt => peps/pep-0390.rst (100%) rename pep-0391.txt => peps/pep-0391.rst (100%) rename pep-0392.txt => peps/pep-0392.rst (100%) rename pep-0393.txt => peps/pep-0393.rst (100%) rename pep-0394.txt => peps/pep-0394.rst (100%) rename pep-0395.txt => peps/pep-0395.rst (100%) rename pep-0396.txt => peps/pep-0396.rst (100%) rename pep-0397.txt => peps/pep-0397.rst (100%) rename pep-0398.txt => peps/pep-0398.rst (100%) rename pep-0399.txt => peps/pep-0399.rst (100%) rename pep-0400.txt => peps/pep-0400.rst (100%) rename pep-0401.txt => peps/pep-0401.rst (100%) rename pep-0402.txt => peps/pep-0402.rst (100%) rename pep-0403.txt => peps/pep-0403.rst (100%) rename pep-0404.txt => peps/pep-0404.rst (100%) rename pep-0405.txt => peps/pep-0405.rst (100%) rename pep-0406.txt => peps/pep-0406.rst (100%) rename pep-0407.txt => peps/pep-0407.rst (100%) rename pep-0408.txt => peps/pep-0408.rst (100%) rename pep-0409.txt => peps/pep-0409.rst (100%) rename pep-0410.txt => peps/pep-0410.rst (100%) rename pep-0411.txt => peps/pep-0411.rst (100%) rename pep-0412.txt => peps/pep-0412.rst (100%) rename pep-0413.txt => peps/pep-0413.rst (100%) rename pep-0414.txt => peps/pep-0414.rst (100%) rename pep-0415.txt => peps/pep-0415.rst (100%) rename pep-0416.txt => peps/pep-0416.rst (100%) rename pep-0417.txt => peps/pep-0417.rst (100%) rename pep-0418.txt => peps/pep-0418.rst (100%) rename {pep-0418 => peps/pep-0418}/bench_time.c (100%) rename {pep-0418 => peps/pep-0418}/clock_resolution.py (100%) rename {pep-0418 => peps/pep-0418}/clockutils.py (100%) rename pep-0419.txt => peps/pep-0419.rst (100%) rename pep-0420.txt => peps/pep-0420.rst (100%) rename pep-0421.txt => peps/pep-0421.rst (100%) rename pep-0422.txt => peps/pep-0422.rst (100%) rename pep-0423.txt => peps/pep-0423.rst (100%) rename pep-0424.txt => peps/pep-0424.rst (100%) rename pep-0425.txt => peps/pep-0425.rst (100%) rename pep-0426.txt => peps/pep-0426.rst (100%) rename {pep-0426 => peps/pep-0426}/pepsort.py (100%) rename {pep-0426 => peps/pep-0426}/pydist-schema.json (100%) rename pep-0427.txt => peps/pep-0427.rst (100%) rename pep-0428.txt => peps/pep-0428.rst (100%) rename pep-0429.txt => peps/pep-0429.rst (100%) rename pep-0430.txt => peps/pep-0430.rst (100%) rename pep-0431.txt => peps/pep-0431.rst (100%) rename pep-0432.txt => peps/pep-0432.rst (100%) rename pep-0433.txt => peps/pep-0433.rst (100%) rename {pep-0433 => peps/pep-0433}/bench_cloexec.py (100%) rename {pep-0433 => peps/pep-0433}/openbsd_bug.py (100%) rename pep-0434.txt => peps/pep-0434.rst (100%) rename pep-0435.txt => peps/pep-0435.rst (100%) rename pep-0436.txt => peps/pep-0436.rst (100%) rename pep-0437.txt => peps/pep-0437.rst (100%) rename pep-0438.txt => peps/pep-0438.rst (100%) rename pep-0439.txt => peps/pep-0439.rst (100%) rename pep-0440.txt => peps/pep-0440.rst (100%) rename pep-0441.txt => peps/pep-0441.rst (100%) rename pep-0442.txt => peps/pep-0442.rst (100%) rename pep-0443.txt => peps/pep-0443.rst (100%) rename pep-0444.txt => peps/pep-0444.rst (100%) rename pep-0445.txt => peps/pep-0445.rst (100%) rename pep-0446.txt => peps/pep-0446.rst (100%) rename {pep-0446 => peps/pep-0446}/test_cloexec.py (100%) rename pep-0447.txt => peps/pep-0447.rst (100%) rename pep-0448.txt => peps/pep-0448.rst (100%) rename pep-0449.txt => peps/pep-0449.rst (100%) rename pep-0450.txt => peps/pep-0450.rst (100%) rename pep-0451.txt => peps/pep-0451.rst (100%) rename pep-0452.txt => peps/pep-0452.rst (100%) rename pep-0453.txt => peps/pep-0453.rst (100%) rename pep-0454.txt => peps/pep-0454.rst (100%) rename pep-0455.txt => peps/pep-0455.rst (100%) rename pep-0456.txt => peps/pep-0456.rst (100%) rename pep-0457.txt => peps/pep-0457.rst (100%) rename pep-0458-1.png => peps/pep-0458-1.png (100%) rename pep-0458.txt => peps/pep-0458.rst (100%) rename pep-0459.txt => peps/pep-0459.rst (100%) rename pep-0460.txt => peps/pep-0460.rst (100%) rename pep-0461.txt => peps/pep-0461.rst (100%) rename pep-0462.txt => peps/pep-0462.rst (100%) rename pep-0463.txt => peps/pep-0463.rst (100%) rename pep-0464.txt => peps/pep-0464.rst (100%) rename pep-0465.txt => peps/pep-0465.rst (100%) rename {pep-0465 => peps/pep-0465}/scan-ops.py (100%) rename pep-0466.txt => peps/pep-0466.rst (100%) rename pep-0467.txt => peps/pep-0467.rst (100%) rename pep-0468.txt => peps/pep-0468.rst (100%) rename pep-0469.txt => peps/pep-0469.rst (100%) rename pep-0470.txt => peps/pep-0470.rst (100%) rename pep-0471.txt => peps/pep-0471.rst (100%) rename pep-0472.txt => peps/pep-0472.rst (100%) rename pep-0473.txt => peps/pep-0473.rst (100%) rename pep-0474.txt => peps/pep-0474.rst (100%) rename pep-0475.txt => peps/pep-0475.rst (100%) rename pep-0476.txt => peps/pep-0476.rst (100%) rename pep-0477.txt => peps/pep-0477.rst (100%) rename pep-0478.txt => peps/pep-0478.rst (100%) rename pep-0479.txt => peps/pep-0479.rst (100%) rename pep-0480-1.png => peps/pep-0480-1.png (100%) rename pep-0480.txt => peps/pep-0480.rst (100%) rename pep-0481.txt => peps/pep-0481.rst (100%) rename pep-0482.txt => peps/pep-0482.rst (100%) rename pep-0483.txt => peps/pep-0483.rst (100%) rename pep-0484.txt => peps/pep-0484.rst (100%) rename pep-0485.txt => peps/pep-0485.rst (100%) rename pep-0486.txt => peps/pep-0486.rst (100%) rename pep-0487.txt => peps/pep-0487.rst (100%) rename pep-0488.txt => peps/pep-0488.rst (100%) rename pep-0489.txt => peps/pep-0489.rst (100%) rename pep-0490.txt => peps/pep-0490.rst (100%) rename pep-0491.txt => peps/pep-0491.rst (100%) rename pep-0492.txt => peps/pep-0492.rst (100%) rename pep-0493.txt => peps/pep-0493.rst (100%) rename pep-0494.txt => peps/pep-0494.rst (100%) rename pep-0495-daylightsavings.png => peps/pep-0495-daylightsavings.png (100%) rename pep-0495-fold.svg => peps/pep-0495-fold.svg (100%) rename pep-0495-gap.svg => peps/pep-0495-gap.svg (100%) rename pep-0495.txt => peps/pep-0495.rst (100%) rename pep-0496.txt => peps/pep-0496.rst (100%) rename pep-0497.txt => peps/pep-0497.rst (100%) rename pep-0498.txt => peps/pep-0498.rst (100%) rename pep-0499.txt => peps/pep-0499.rst (100%) rename pep-0500.txt => peps/pep-0500.rst (100%) rename pep-0501.txt => peps/pep-0501.rst (100%) rename pep-0502.txt => peps/pep-0502.rst (100%) rename pep-0503.txt => peps/pep-0503.rst (100%) rename pep-0504.txt => peps/pep-0504.rst (100%) rename pep-0505.rst => peps/pep-0505.rst (100%) rename {pep-0505 => peps/pep-0505}/find-pep505.out (100%) rename {pep-0505 => peps/pep-0505}/find-pep505.py (100%) rename {pep-0505 => peps/pep-0505}/test.py (100%) rename pep-0506.txt => peps/pep-0506.rst (100%) rename pep-0507.txt => peps/pep-0507.rst (100%) rename pep-0508.txt => peps/pep-0508.rst (100%) rename pep-0509.txt => peps/pep-0509.rst (100%) rename pep-0510.txt => peps/pep-0510.rst (100%) rename pep-0511.txt => peps/pep-0511.rst (100%) rename pep-0512.txt => peps/pep-0512.rst (100%) rename pep-0513.txt => peps/pep-0513.rst (100%) rename pep-0514.txt => peps/pep-0514.rst (100%) rename pep-0515.txt => peps/pep-0515.rst (100%) rename pep-0516.txt => peps/pep-0516.rst (100%) rename pep-0517.txt => peps/pep-0517.rst (100%) rename pep-0518.txt => peps/pep-0518.rst (100%) rename pep-0519.txt => peps/pep-0519.rst (100%) rename pep-0520.txt => peps/pep-0520.rst (100%) rename pep-0521.txt => peps/pep-0521.rst (100%) rename pep-0522.txt => peps/pep-0522.rst (100%) rename pep-0523.txt => peps/pep-0523.rst (100%) rename pep-0524.txt => peps/pep-0524.rst (100%) rename pep-0525-1.png => peps/pep-0525-1.png (100%) rename pep-0525.txt => peps/pep-0525.rst (100%) rename pep-0526.txt => peps/pep-0526.rst (100%) rename pep-0527.txt => peps/pep-0527.rst (100%) rename pep-0528.txt => peps/pep-0528.rst (100%) rename pep-0529.txt => peps/pep-0529.rst (100%) rename pep-0530.txt => peps/pep-0530.rst (100%) rename pep-0531.txt => peps/pep-0531.rst (100%) rename pep-0532.txt => peps/pep-0532.rst (100%) rename {pep-0532 => peps/pep-0532}/circuit-breaking-protocol.svg (100%) rename pep-0533.txt => peps/pep-0533.rst (100%) rename pep-0534.txt => peps/pep-0534.rst (100%) rename pep-0535.txt => peps/pep-0535.rst (100%) rename pep-0536.txt => peps/pep-0536.rst (100%) rename pep-0537.txt => peps/pep-0537.rst (100%) rename pep-0538.txt => peps/pep-0538.rst (100%) rename pep-0539.txt => peps/pep-0539.rst (100%) rename pep-0540.txt => peps/pep-0540.rst (100%) rename pep-0541.txt => peps/pep-0541.rst (100%) rename pep-0542.txt => peps/pep-0542.rst (100%) rename pep-0543.rst => peps/pep-0543.rst (100%) rename pep-0544.txt => peps/pep-0544.rst (100%) rename pep-0545.txt => peps/pep-0545.rst (100%) rename pep-0546.txt => peps/pep-0546.rst (100%) rename pep-0547.rst => peps/pep-0547.rst (100%) rename pep-0548.rst => peps/pep-0548.rst (100%) rename pep-0549.rst => peps/pep-0549.rst (100%) rename pep-0550-hamt_vs_dict-v2.png => peps/pep-0550-hamt_vs_dict-v2.png (100%) rename pep-0550-hamt_vs_dict.png => peps/pep-0550-hamt_vs_dict.png (100%) rename pep-0550-lookup_hamt.png => peps/pep-0550-lookup_hamt.png (100%) rename pep-0550.rst => peps/pep-0550.rst (100%) rename pep-0551.rst => peps/pep-0551.rst (100%) rename pep-0552.rst => peps/pep-0552.rst (100%) rename pep-0553.rst => peps/pep-0553.rst (100%) rename pep-0554.rst => peps/pep-0554.rst (100%) rename pep-0555.rst => peps/pep-0555.rst (100%) rename pep-0556.rst => peps/pep-0556.rst (100%) rename pep-0557.rst => peps/pep-0557.rst (100%) rename pep-0558.rst => peps/pep-0558.rst (100%) rename pep-0559.rst => peps/pep-0559.rst (100%) rename pep-0560.rst => peps/pep-0560.rst (100%) rename pep-0561.rst => peps/pep-0561.rst (100%) rename pep-0562.rst => peps/pep-0562.rst (100%) rename pep-0563.rst => peps/pep-0563.rst (100%) rename pep-0564.rst => peps/pep-0564.rst (100%) rename pep-0565.rst => peps/pep-0565.rst (100%) rename pep-0566.rst => peps/pep-0566.rst (100%) rename pep-0567.rst => peps/pep-0567.rst (100%) rename pep-0568.rst => peps/pep-0568.rst (100%) rename pep-0569.rst => peps/pep-0569.rst (100%) rename pep-0570.rst => peps/pep-0570.rst (100%) rename pep-0571.rst => peps/pep-0571.rst (100%) rename pep-0572.rst => peps/pep-0572.rst (100%) rename pep-0573.rst => peps/pep-0573.rst (100%) rename pep-0574.rst => peps/pep-0574.rst (100%) rename pep-0575.rst => peps/pep-0575.rst (100%) rename pep-0576.rst => peps/pep-0576.rst (100%) rename pep-0577.rst => peps/pep-0577.rst (100%) rename pep-0578.rst => peps/pep-0578.rst (100%) rename pep-0579.rst => peps/pep-0579.rst (100%) rename pep-0580.rst => peps/pep-0580.rst (100%) rename pep-0581.rst => peps/pep-0581.rst (100%) rename pep-0582.rst => peps/pep-0582.rst (100%) rename pep-0583.rst => peps/pep-0583.rst (100%) rename pep-0584.rst => peps/pep-0584.rst (100%) rename pep-0585.rst => peps/pep-0585.rst (100%) rename pep-0586.rst => peps/pep-0586.rst (100%) rename pep-0587.rst => peps/pep-0587.rst (100%) rename pep-0588.rst => peps/pep-0588.rst (100%) rename pep-0589.rst => peps/pep-0589.rst (100%) rename pep-0590.rst => peps/pep-0590.rst (100%) rename pep-0591.rst => peps/pep-0591.rst (100%) rename pep-0592.rst => peps/pep-0592.rst (100%) rename pep-0593.rst => peps/pep-0593.rst (100%) rename pep-0594.rst => peps/pep-0594.rst (100%) rename pep-0595.rst => peps/pep-0595.rst (100%) rename pep-0596.rst => peps/pep-0596.rst (100%) rename pep-0597.rst => peps/pep-0597.rst (100%) rename pep-0598.rst => peps/pep-0598.rst (100%) rename pep-0599.rst => peps/pep-0599.rst (100%) rename pep-0600.rst => peps/pep-0600.rst (100%) rename pep-0601.txt => peps/pep-0601.rst (100%) rename pep-0602-example-release-calendar.png => peps/pep-0602-example-release-calendar.png (100%) rename pep-0602-example-release-calendar.pptx => peps/pep-0602-example-release-calendar.pptx (100%) rename pep-0602-overlapping-support-matrix.png => peps/pep-0602-overlapping-support-matrix.png (100%) rename pep-0602-overlapping-support-matrix.pptx => peps/pep-0602-overlapping-support-matrix.pptx (100%) rename pep-0602.rst => peps/pep-0602.rst (100%) rename pep-0603-hamt_vs_dict.png => peps/pep-0603-hamt_vs_dict.png (100%) rename pep-0603-lookup_hamt.png => peps/pep-0603-lookup_hamt.png (100%) rename pep-0603.rst => peps/pep-0603.rst (100%) rename pep-0604.rst => peps/pep-0604.rst (100%) rename pep-0605-example-release-calendar.png => peps/pep-0605-example-release-calendar.png (100%) rename pep-0605-overlapping-support-matrix.png => peps/pep-0605-overlapping-support-matrix.png (100%) rename pep-0605.rst => peps/pep-0605.rst (100%) rename {pep-0605 => peps/pep-0605}/example-release-calendar.odp (100%) rename {pep-0605 => peps/pep-0605}/overlapping-support-matrix.odp (100%) rename pep-0606.rst => peps/pep-0606.rst (100%) rename pep-0607.rst => peps/pep-0607.rst (100%) rename pep-0608.rst => peps/pep-0608.rst (100%) rename pep-0609.rst => peps/pep-0609.rst (100%) rename pep-0610.rst => peps/pep-0610.rst (100%) rename pep-0611.rst => peps/pep-0611.rst (100%) rename pep-0612.rst => peps/pep-0612.rst (100%) rename pep-0613.rst => peps/pep-0613.rst (100%) rename pep-0614.rst => peps/pep-0614.rst (100%) rename pep-0615.rst => peps/pep-0615.rst (100%) rename pep-0616.rst => peps/pep-0616.rst (100%) rename pep-0617.rst => peps/pep-0617.rst (100%) rename pep-0618.rst => peps/pep-0618.rst (100%) rename pep-0619.rst => peps/pep-0619.rst (100%) rename pep-0620.rst => peps/pep-0620.rst (100%) rename pep-0621.rst => peps/pep-0621.rst (100%) rename pep-0622.rst => peps/pep-0622.rst (100%) rename pep-0623.rst => peps/pep-0623.rst (100%) rename pep-0624.rst => peps/pep-0624.rst (100%) rename pep-0625.rst => peps/pep-0625.rst (100%) rename pep-0626.rst => peps/pep-0626.rst (100%) rename pep-0627.rst => peps/pep-0627.rst (100%) rename pep-0628.txt => peps/pep-0628.rst (100%) rename pep-0629.rst => peps/pep-0629.rst (100%) rename pep-0630.rst => peps/pep-0630.rst (100%) rename pep-0631.rst => peps/pep-0631.rst (100%) rename pep-0632.rst => peps/pep-0632.rst (100%) rename pep-0633.rst => peps/pep-0633.rst (100%) rename pep-0634.rst => peps/pep-0634.rst (100%) rename pep-0635.rst => peps/pep-0635.rst (100%) rename pep-0636.rst => peps/pep-0636.rst (100%) rename pep-0637.rst => peps/pep-0637.rst (100%) rename pep-0638.rst => peps/pep-0638.rst (100%) rename pep-0639.rst => peps/pep-0639.rst (100%) rename pep-0640.rst => peps/pep-0640.rst (100%) rename pep-0641.rst => peps/pep-0641.rst (100%) rename pep-0642.rst => peps/pep-0642.rst (100%) rename pep-0643.rst => peps/pep-0643.rst (100%) rename pep-0644.rst => peps/pep-0644.rst (100%) rename pep-0645.rst => peps/pep-0645.rst (100%) rename pep-0646.rst => peps/pep-0646.rst (100%) rename pep-0647.rst => peps/pep-0647.rst (100%) rename pep-0648.rst => peps/pep-0648.rst (100%) rename pep-0649.rst => peps/pep-0649.rst (100%) rename pep-0650.rst => peps/pep-0650.rst (100%) rename pep-0651.rst => peps/pep-0651.rst (100%) rename pep-0652.rst => peps/pep-0652.rst (100%) rename pep-0653.rst => peps/pep-0653.rst (100%) rename pep-0654.rst => peps/pep-0654.rst (100%) rename pep-0655.rst => peps/pep-0655.rst (100%) rename pep-0656.rst => peps/pep-0656.rst (100%) rename pep-0657.rst => peps/pep-0657.rst (100%) rename pep-0658.rst => peps/pep-0658.rst (100%) rename pep-0659.rst => peps/pep-0659.rst (100%) rename pep-0660.rst => peps/pep-0660.rst (100%) rename pep-0661.rst => peps/pep-0661.rst (100%) rename pep-0662.rst => peps/pep-0662.rst (100%) rename {pep-0662 => peps/pep-0662}/pep-0662-editable.json (100%) rename pep-0663.txt => peps/pep-0663.rst (100%) rename pep-0664.rst => peps/pep-0664.rst (100%) rename pep-0665.rst => peps/pep-0665.rst (100%) rename pep-0666.txt => peps/pep-0666.rst (100%) rename pep-0667.rst => peps/pep-0667.rst (100%) rename pep-0668.rst => peps/pep-0668.rst (100%) rename pep-0669.rst => peps/pep-0669.rst (100%) rename pep-0670.rst => peps/pep-0670.rst (100%) rename pep-0671.rst => peps/pep-0671.rst (100%) rename pep-0672.rst => peps/pep-0672.rst (100%) rename pep-0673.rst => peps/pep-0673.rst (100%) rename pep-0674.rst => peps/pep-0674.rst (100%) rename pep-0675.rst => peps/pep-0675.rst (100%) rename pep-0676.rst => peps/pep-0676.rst (100%) rename pep-0677.rst => peps/pep-0677.rst (100%) rename pep-0678.rst => peps/pep-0678.rst (100%) rename pep-0679.rst => peps/pep-0679.rst (100%) rename pep-0680.rst => peps/pep-0680.rst (100%) rename pep-0681.rst => peps/pep-0681.rst (100%) rename pep-0682.rst => peps/pep-0682.rst (100%) rename pep-0683.rst => peps/pep-0683.rst (100%) rename pep-0684.rst => peps/pep-0684.rst (100%) rename pep-0685.rst => peps/pep-0685.rst (100%) rename pep-0686.rst => peps/pep-0686.rst (100%) rename pep-0687.rst => peps/pep-0687.rst (100%) rename pep-0688.rst => peps/pep-0688.rst (100%) rename pep-0689.rst => peps/pep-0689.rst (100%) rename pep-0690.rst => peps/pep-0690.rst (100%) rename pep-0691.rst => peps/pep-0691.rst (100%) rename pep-0692.rst => peps/pep-0692.rst (100%) rename pep-0693.rst => peps/pep-0693.rst (100%) rename pep-0694.rst => peps/pep-0694.rst (100%) rename pep-0695.rst => peps/pep-0695.rst (100%) rename pep-0696.rst => peps/pep-0696.rst (100%) rename pep-0697.rst => peps/pep-0697.rst (100%) rename pep-0698.rst => peps/pep-0698.rst (100%) rename pep-0699.rst => peps/pep-0699.rst (100%) rename pep-0700.rst => peps/pep-0700.rst (100%) rename pep-0701.rst => peps/pep-0701.rst (100%) rename pep-0702.rst => peps/pep-0702.rst (100%) rename pep-0703.rst => peps/pep-0703.rst (100%) rename pep-0704.rst => peps/pep-0704.rst (100%) rename pep-0705.rst => peps/pep-0705.rst (100%) rename pep-0706.rst => peps/pep-0706.rst (100%) rename pep-0707.rst => peps/pep-0707.rst (100%) rename pep-0708.rst => peps/pep-0708.rst (100%) rename pep-0709.rst => peps/pep-0709.rst (100%) rename pep-0710.rst => peps/pep-0710.rst (100%) rename pep-0711.rst => peps/pep-0711.rst (100%) rename pep-0712.rst => peps/pep-0712.rst (100%) rename pep-0713.rst => peps/pep-0713.rst (100%) rename pep-0714.rst => peps/pep-0714.rst (100%) rename pep-0715.rst => peps/pep-0715.rst (100%) rename pep-0718.rst => peps/pep-0718.rst (100%) rename pep-0719.rst => peps/pep-0719.rst (100%) rename pep-0720.rst => peps/pep-0720.rst (100%) rename pep-0721.rst => peps/pep-0721.rst (100%) rename pep-0722.rst => peps/pep-0722.rst (100%) rename pep-0723.rst => peps/pep-0723.rst (100%) rename pep-0725.rst => peps/pep-0725.rst (100%) rename pep-0726.rst => peps/pep-0726.rst (100%) rename pep-0727.rst => peps/pep-0727.rst (100%) rename pep-0754.txt => peps/pep-0754.rst (100%) rename pep-0801.rst => peps/pep-0801.rst (100%) rename pep-3000.txt => peps/pep-3000.rst (100%) rename pep-3001.txt => peps/pep-3001.rst (100%) rename pep-3002.txt => peps/pep-3002.rst (100%) rename pep-3003.txt => peps/pep-3003.rst (100%) rename pep-3099.txt => peps/pep-3099.rst (100%) rename pep-3100.txt => peps/pep-3100.rst (100%) rename pep-3101.txt => peps/pep-3101.rst (100%) rename pep-3102.txt => peps/pep-3102.rst (100%) rename pep-3103.txt => peps/pep-3103.rst (100%) rename pep-3104.txt => peps/pep-3104.rst (100%) rename pep-3105.txt => peps/pep-3105.rst (100%) rename pep-3106.txt => peps/pep-3106.rst (100%) rename pep-3107.txt => peps/pep-3107.rst (100%) rename pep-3108.txt => peps/pep-3108.rst (100%) rename pep-3109.txt => peps/pep-3109.rst (100%) rename pep-3110.txt => peps/pep-3110.rst (100%) rename pep-3111.txt => peps/pep-3111.rst (100%) rename pep-3112.txt => peps/pep-3112.rst (100%) rename pep-3113.txt => peps/pep-3113.rst (100%) rename pep-3114.txt => peps/pep-3114.rst (100%) rename pep-3115.txt => peps/pep-3115.rst (100%) rename pep-3116.txt => peps/pep-3116.rst (100%) rename pep-3117.txt => peps/pep-3117.rst (100%) rename pep-3118.txt => peps/pep-3118.rst (100%) rename pep-3119.txt => peps/pep-3119.rst (100%) rename pep-3120.txt => peps/pep-3120.rst (100%) rename pep-3121.txt => peps/pep-3121.rst (100%) rename pep-3122.txt => peps/pep-3122.rst (100%) rename pep-3123.txt => peps/pep-3123.rst (100%) rename pep-3124.txt => peps/pep-3124.rst (100%) rename pep-3125.txt => peps/pep-3125.rst (100%) rename pep-3126.txt => peps/pep-3126.rst (100%) rename pep-3127.txt => peps/pep-3127.rst (100%) rename pep-3128.txt => peps/pep-3128.rst (100%) rename pep-3129.txt => peps/pep-3129.rst (100%) rename pep-3130.txt => peps/pep-3130.rst (100%) rename pep-3131.txt => peps/pep-3131.rst (100%) rename pep-3132.txt => peps/pep-3132.rst (100%) rename pep-3133.txt => peps/pep-3133.rst (100%) rename pep-3134.txt => peps/pep-3134.rst (100%) rename pep-3135.txt => peps/pep-3135.rst (100%) rename pep-3136.txt => peps/pep-3136.rst (100%) rename pep-3137.txt => peps/pep-3137.rst (100%) rename pep-3138.txt => peps/pep-3138.rst (100%) rename pep-3139.txt => peps/pep-3139.rst (100%) rename pep-3140.txt => peps/pep-3140.rst (100%) rename pep-3141.txt => peps/pep-3141.rst (100%) rename pep-3142.txt => peps/pep-3142.rst (100%) rename pep-3143.txt => peps/pep-3143.rst (100%) rename pep-3144.txt => peps/pep-3144.rst (100%) rename pep-3145.txt => peps/pep-3145.rst (100%) rename pep-3146.txt => peps/pep-3146.rst (100%) rename pep-3147-1.dia => peps/pep-3147-1.dia (100%) rename pep-3147-1.png => peps/pep-3147-1.png (100%) rename pep-3147.txt => peps/pep-3147.rst (100%) rename pep-3148.txt => peps/pep-3148.rst (100%) rename pep-3149.txt => peps/pep-3149.rst (100%) rename pep-3150.txt => peps/pep-3150.rst (100%) rename pep-3151.txt => peps/pep-3151.rst (100%) rename pep-3152.txt => peps/pep-3152.rst (100%) rename pep-3153.txt => peps/pep-3153.rst (100%) rename pep-3154.txt => peps/pep-3154.rst (100%) rename pep-3155.txt => peps/pep-3155.rst (100%) rename pep-3156.txt => peps/pep-3156.rst (100%) rename pep-3333.txt => peps/pep-3333.rst (100%) rename pep-8000.rst => peps/pep-8000.rst (100%) rename pep-8001.rst => peps/pep-8001.rst (100%) rename pep-8002.rst => peps/pep-8002.rst (100%) rename pep-8010.rst => peps/pep-8010.rst (100%) rename pep-8011.rst => peps/pep-8011.rst (100%) rename pep-8012.rst => peps/pep-8012.rst (100%) rename pep-8013.rst => peps/pep-8013.rst (100%) rename pep-8014.rst => peps/pep-8014.rst (100%) rename pep-8015.rst => peps/pep-8015.rst (100%) rename pep-8016.rst => peps/pep-8016.rst (100%) rename pep-8100.rst => peps/pep-8100.rst (100%) rename pep-8101.rst => peps/pep-8101.rst (100%) rename pep-8102.rst => peps/pep-8102.rst (100%) rename pep-8103.rst => peps/pep-8103.rst (100%) rename pep-8104.rst => peps/pep-8104.rst (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a331e70cd..242084ab2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,8 +13,8 @@ infra/ @ewdurbin pep_sphinx_extensions/ @AA-Turner build.py @AA-Turner -conf.py @AA-Turner -contents.rst @AA-Turner +peps/conf.py @AA-Turner +peps/contents.rst @AA-Turner # Linting infrastructure .codespell/ @CAM-Gerlach @hugovk @@ -27,668 +27,668 @@ check-peps.py @AA-Turner @CAM-Gerlach @hugovk .gitattributes @CAM-Gerlach .gitignore @CAM-Gerlach -pep-0001.txt @warsaw @ncoghlan -pep-0001-process_flow.png @warsaw @ncoghlan -pep-0001/ @warsaw @ncoghlan -# pep-0002.txt -pep-0003.txt @jeremyhylton -pep-0004.txt @brettcannon -# pep-0005.txt -# pep-0006.txt -pep-0007.txt @gvanrossum @warsaw -pep-0008.txt @gvanrossum @warsaw @ncoghlan -pep-0009.txt @warsaw -pep-0010.txt @warsaw -pep-0011.txt @brettcannon -pep-0012.rst @brettcannon @warsaw -pep-0012/ @brettcannon -# pep-0013.rst is owned by the entire core team. +peps/pep-0001.rst @warsaw @ncoghlan +peps/pep-0001-process_flow.png @warsaw @ncoghlan +peps/pep-0001/ @warsaw @ncoghlan +# peps/pep-0002.rst +peps/pep-0003.rst @jeremyhylton +peps/pep-0004.rst @brettcannon +# peps/pep-0005.rst +# peps/pep-0006.rst +peps/pep-0007.rst @gvanrossum @warsaw +peps/pep-0008.rst @gvanrossum @warsaw @ncoghlan +peps/pep-0009.rst @warsaw +peps/pep-0010.rst @warsaw +peps/pep-0011.rst @brettcannon +peps/pep-0012.rst @brettcannon @warsaw +peps/pep-0012/ @brettcannon +# peps/pep-0013.rst is owned by the entire core team. # ... -pep-0020.txt @tim-one +peps/pep-0020.rst @tim-one # ... -pep-0042.txt @jeremyhylton +peps/pep-0042.rst @jeremyhylton # ... -pep-0100.txt @malemburg -pep-0101.txt @Yhg1s @pablogsal @ambv @ned-deily -pep-0102.txt @warsaw @gvanrossum -# pep-0103.txt +peps/pep-0100.rst @malemburg +peps/pep-0101.rst @Yhg1s @pablogsal @ambv @ned-deily +peps/pep-0102.rst @warsaw @gvanrossum +# peps/pep-0103.rst # ... -pep-0160.txt @freddrake +peps/pep-0160.rst @freddrake # ... -pep-0200.txt @jeremyhylton -pep-0201.txt @warsaw -pep-0202.txt @warsaw -pep-0203.txt @Yhg1s -pep-0204.txt @Yhg1s -pep-0205.txt @freddrake -# pep-0206.txt -pep-0207.txt @gvanrossum -pep-0208.txt @nascheme @malemburg -# pep-0209.txt -# pep-0210.txt -# pep-0211.txt -# pep-0212.txt -# pep-0213.txt -pep-0214.txt @warsaw -# pep-0215.txt -# pep-0216.txt -# pep-0217.txt -pep-0218.txt @rhettinger -# pep-0219.txt -# pep-0220.txt -pep-0221.txt @Yhg1s -# pep-0222.txt -pep-0223.txt @tim-one -pep-0224.txt @malemburg -# pep-0225.txt -pep-0226.txt @jeremyhylton -pep-0227.txt @jeremyhylton -pep-0228.txt @gvanrossum -# pep-0229.txt -pep-0230.txt @gvanrossum -pep-0231.txt @warsaw -pep-0232.txt @warsaw -# pep-0233.txt -pep-0234.txt @gvanrossum -pep-0235.txt @tim-one -pep-0236.txt @tim-one -pep-0237.txt @gvanrossum -pep-0238.txt @gvanrossum -# pep-0239.txt -# pep-0240.txt -# pep-0241.txt -# pep-0242.txt -# pep-0243.txt -# pep-0244.txt -# pep-0245.txt -pep-0246.txt @aleaxit -# pep-0247.txt -pep-0248.txt @malemburg -pep-0249.txt @malemburg -pep-0250.txt @pfmoore -pep-0251.txt @warsaw @gvanrossum -pep-0252.txt @gvanrossum -pep-0253.txt @gvanrossum -pep-0254.txt @gvanrossum -pep-0255.txt @nascheme @tim-one -# pep-0256.txt -pep-0257.txt @gvanrossum -# pep-0258.txt -pep-0259.txt @gvanrossum -pep-0260.txt @gvanrossum -# pep-0261.txt -# pep-0262.txt -pep-0263.txt @malemburg -# pep-0264.txt -# pep-0265.txt -# pep-0266.txt -pep-0267.txt @jeremyhylton -# pep-0268.txt -# pep-0269.txt -# pep-0270.txt -# pep-0271.txt -# pep-0272.txt -# pep-0273.txt -pep-0274.txt @warsaw -pep-0275.txt @malemburg -# pep-0276.txt -# pep-0277.txt -pep-0278.txt @jackjansen -pep-0279.txt @rhettinger -pep-0280.txt @gvanrossum -# pep-0281.txt -pep-0282.txt @vsajip -pep-0283.txt @gvanrossum -# pep-0284.txt -pep-0285.txt @gvanrossum -# pep-0286.txt -# pep-0287.txt -pep-0288.txt @rhettinger -pep-0289.txt @rhettinger -pep-0290.txt @rhettinger -# pep-0291.txt -pep-0292.txt @warsaw -pep-0293.txt @doerwalter -# pep-0294.txt -# pep-0295.txt -# pep-0296.txt -pep-0297.txt @malemburg -pep-0298.txt @theller -# pep-0299.txt -# pep-0301.txt -pep-0302.txt @pfmoore -# pep-0303.txt -# pep-0304.txt -# pep-0305.txt -pep-0306.txt @jackdied @ncoghlan @benjaminp -pep-0307.txt @gvanrossum @tim-one -pep-0308.txt @gvanrossum @rhettinger -# pep-0309.txt -pep-0310.txt @pfmoore -pep-0311.txt @mhammond -pep-0312.txt @aleaxit -# pep-0313.txt -# pep-0314.txt -pep-0315.txt @rhettinger -# pep-0316.txt -# pep-0317.txt -# pep-0318.txt -# pep-0319.txt -pep-0320.txt @warsaw @rhettinger -# pep-0321.txt -pep-0322.txt @rhettinger -pep-0323.txt @aleaxit -# pep-0324.txt -# pep-0325.txt -pep-0326.txt @terryjreedy -pep-0327.txt @facundobatista -# pep-0328.txt -pep-0329.txt @rhettinger -# pep-0330.txt -# pep-0331.txt -# pep-0332.txt -# pep-0333.txt -# pep-0334.txt -# pep-0335.txt -# pep-0336.txt -# pep-0337.txt -pep-0338.txt @ncoghlan -pep-0339.txt @brettcannon -pep-0340.txt @gvanrossum -pep-0341.txt @birkenfeld -pep-0342.txt @gvanrossum -pep-0343.txt @gvanrossum @ncoghlan -# pep-0344.txt -# pep-0345.txt -pep-0346.txt @ncoghlan -# pep-0347.txt -pep-0348.txt @brettcannon -pep-0349.txt @nascheme -# pep-0350.txt -pep-0351.txt @warsaw -pep-0352.txt @brettcannon @gvanrossum -# pep-0353.txt -# pep-0354.txt -# pep-0355.txt -pep-0356.txt @gvanrossum -# pep-0357.txt -pep-0358.txt @nascheme @gvanrossum -# pep-0359.txt -pep-0360.txt @brettcannon -pep-0361.txt @warsaw -pep-0362.txt @brettcannon @1st1 @larryhastings -# pep-0363.txt -pep-0364.txt @warsaw -# pep-0365.txt -pep-0366.txt @ncoghlan -# pep-0367.txt -# pep-0368.txt -pep-0369.txt @tiran -pep-0370.txt @tiran -# pep-0371.txt -pep-0372.txt @mitsuhiko @rhettinger -pep-0373.txt @benjaminp -pep-0374.txt @brettcannon @avassalotti @warsaw -pep-0375.txt @benjaminp -# pep-0376.txt -pep-0377.txt @ncoghlan -pep-0378.txt @rhettinger -# pep-0379.txt -# pep-0380.txt -# pep-0381.txt -# pep-0382.txt -# pep-0383.txt -# pep-0384.txt -pep-0385.txt @pitrou @birkenfeld -# pep-0386.txt -pep-0387.txt @benjaminp @vstinner -# pep-0389.txt -# pep-0390.txt -pep-0391.txt @vsajip -pep-0392.txt @birkenfeld -# pep-0393.txt -pep-0394.txt @ncoghlan @warsaw @encukou @willingc -pep-0395.txt @ncoghlan -pep-0396.txt @warsaw -pep-0397.txt @mhammond -pep-0398.txt @birkenfeld -pep-0399.txt @brettcannon -pep-0400.txt @vstinner -pep-0401.txt @warsaw @brettcannon -# pep-0402.txt -pep-0403.txt @ncoghlan -pep-0404.txt @warsaw -# pep-0405.txt -pep-0406.txt @ncoghlan -pep-0407.txt @pitrou @birkenfeld @warsaw -pep-0408.txt @ncoghlan @eliben -pep-0409.txt @ethanfurman -pep-0410.txt @vstinner -pep-0411.txt @ncoghlan @eliben -pep-0412.txt @markshannon -pep-0413.txt @ncoghlan -pep-0414.txt @mitsuhiko @ncoghlan -pep-0415.txt @benjaminp -pep-0416.txt @vstinner -pep-0417.txt @voidspace -pep-0418.txt @vstinner -pep-0418/ @vstinner -# pep-0419.txt -pep-0420.txt @ericvsmith -pep-0421.txt @ericsnowcurrently -pep-0422.txt @ncoghlan -# pep-0423.txt -pep-0424.txt @alex -# pep-0425.txt -pep-0426.txt @ncoghlan @dstufft -pep-0426/ @ncoghlan @dstufft -# pep-0427.txt -pep-0428.txt @pitrou -pep-0429.txt @larryhastings -pep-0430.txt @ncoghlan -# pep-0431.txt -pep-0432.txt @ncoghlan @vstinner @ericsnowcurrently -pep-0433.txt @vstinner -pep-0433/ @vstinner -pep-0434.txt @terryjreedy -pep-0435.txt @warsaw @eliben @ethanfurman -pep-0436.txt @larryhastings -# pep-0437.txt -# pep-0438.txt -# pep-0439.txt -pep-0440.txt @ncoghlan @dstufft -pep-0441.txt @pfmoore -pep-0442.txt @pitrou -pep-0443.txt @ambv -pep-0444.txt @mitsuhiko -pep-0445.txt @vstinner -pep-0446.txt @vstinner -pep-0446/ @vstinner -pep-0447.txt @ronaldoussoren -# pep-0448.txt -pep-0449.txt @dstufft -# pep-0450.txt @stevendaprano -pep-0451.txt @ericsnowcurrently -pep-0452.txt @tiran -pep-0453.txt @dstufft @ncoghlan -pep-0454.txt @vstinner -pep-0455.txt @pitrou -pep-0456.txt @tiran -pep-0457.txt @larryhastings -# pep-0458.txt, pep-0458-1.png -pep-0459.txt @ncoghlan -pep-0460.txt @pitrou -pep-0461.txt @ethanfurman -pep-0462.txt @ncoghlan -# pep-0463.txt -pep-0464.txt @dstufft -pep-0465.txt @njsmith -pep-0465/ @njsmith -pep-0466.txt @ncoghlan -pep-0467.txt @ncoghlan @ethanfurman -pep-0468.txt @ericsnowcurrently -pep-0469.txt @ncoghlan -pep-0470.txt @dstufft -# pep-0471.txt -# pep-0472.txt -# pep-0473.txt -pep-0474.txt @ncoghlan -pep-0475.txt @vstinner -pep-0476.txt @alex -pep-0477.txt @dstufft @ncoghlan -pep-0478.txt @larryhastings -pep-0479.txt @gvanrossum -# pep-0480.txt, pep-0480-1.png -pep-0481.txt @dstufft -pep-0482.txt @ambv -pep-0483.txt @gvanrossum @ilevkivskyi -pep-0484.txt @gvanrossum @ambv -# pep-0485.txt -pep-0486.txt @pfmoore -# pep-0487.txt -pep-0488.txt @brettcannon -pep-0489.txt @encukou @scoder @ncoghlan -pep-0490.txt @vstinner -# pep-0491.txt -pep-0492.txt @1st1 -pep-0493.txt @ncoghlan @malemburg -pep-0494.txt @ned-deily -pep-0495.txt @abalkin @tim-one -pep-0495-gap.png @abalkin @tim-one -pep-0495-gap.svg @abalkin @tim-one -pep-0495-fold.svg @abalkin @tim-one -pep-0495-fold-2.png @abalkin @tim-one -pep-0495-daylightsavings.png @abalkin @tim-one -# pep-0496.txt -# pep-0497.txt -pep-0498.txt @ericvsmith -# pep-0499.txt -pep-0500.txt @abalkin @tim-one -pep-0501.txt @ncoghlan -# pep-0502.txt -pep-0503.txt @dstufft -pep-0504.txt @ncoghlan -pep-0505.rst @zooba -pep-0505/ @zooba -# pep-0506.txt @stevendaprano -pep-0507.txt @warsaw -pep-0508.txt @rbtcollins -pep-0509.txt @vstinner -pep-0510.txt @vstinner -pep-0511.txt @vstinner -pep-0512.txt @brettcannon -pep-0513.txt @njsmith -pep-0514.txt @zooba -pep-0515.txt @birkenfeld @serhiy-storchaka -pep-0516.txt @rbtcollins @njsmith -pep-0517.txt @njsmith -pep-0518.txt @brettcannon @njsmith @dstufft -pep-0519.txt @brettcannon -pep-0520.txt @ericsnowcurrently -pep-0521.txt @njsmith -pep-0522.txt @ncoghlan @njsmith -pep-0523.txt @brettcannon @DinoV -pep-0524.txt @vstinner -pep-0525.txt @1st1 -pep-0525-1.png @1st1 -pep-0526.txt @ilevkivskyi @lisroach @gvanrossum -pep-0527.txt @dstufft -pep-0528.txt @zooba -pep-0529.txt @zooba -pep-0530.txt @1st1 -pep-0531.txt @ncoghlan -pep-0532.txt @ncoghlan -pep-0532/ @ncoghlan -pep-0533.txt @njsmith -pep-0534.txt @encukou @ncoghlan -pep-0535.txt @ncoghlan -# pep-0536.txt -pep-0537.txt @ned-deily -pep-0538.txt @ncoghlan -# pep-0539.txt -pep-0540.txt @vstinner -pep-0541.txt @ambv -# pep-0542.txt -pep-0543.rst @tiran -pep-0544.txt @ilevkivskyi @ambv -pep-0545.txt @JulienPalard @methane @vstinner -pep-0546.txt @vstinner -pep-0547.rst @encukou -pep-0548.rst @bitdancer -pep-0549.rst @larryhastings -pep-0550.rst @1st1 -pep-0550-lookup_hamt.png @1st1 -pep-0550-hamt_vs_dict.png @1st1 -pep-0550-hamt_vs_dict-v2.png @1st1 -pep-0551.rst @zooba -pep-0552.rst @benjaminp -pep-0553.rst @warsaw -pep-0554.rst @ericsnowcurrently -# pep-0555.rst -pep-0556.rst @pitrou -pep-0557.rst @ericvsmith -pep-0558.rst @ncoghlan -pep-0559.rst @warsaw -pep-0560.rst @ilevkivskyi -# pep-0561.rst -pep-0562.rst @ilevkivskyi -pep-0563.rst @ambv -pep-0564.rst @vstinner -pep-0565.rst @ncoghlan -# pep-0566.rst -pep-0567.rst @1st1 -pep-0568.rst @njsmith -pep-0569.rst @ambv -pep-0570.rst @larryhastings @pablogsal -# pep-0571.rst -pep-0572.rst @tim-one @gvanrossum -pep-0573.rst @encukou @ncoghlan @ericsnowcurrently -pep-0574.rst @pitrou -# pep-0575.rst -pep-0576.rst @markshannon -pep-0577.rst @ncoghlan -pep-0578.rst @zooba -# pep-0579.rst -# pep-0580.rst -pep-0581.rst @Mariatta -pep-0582.rst @kushaldas @zooba @dstufft @ncoghlan -# pep-0583.rst -pep-0584.rst @brandtbucher # @stevendaprano -pep-0585.rst @ambv -pep-0586.rst @ilevkivskyi -pep-0587.rst @vstinner @ncoghlan -pep-0588.rst @Mariatta -pep-0589.rst @gvanrossum -pep-0590.rst @markshannon -pep-0591.rst @ilevkivskyi -pep-0592.rst @dstufft -pep-0593.rst @ilevkivskyi -pep-0594.rst @tiran @brettcannon -pep-0595.rst @ezio-melotti @berkerpeksag -pep-0596.rst @ambv -pep-0597.rst @methane -pep-0598.rst @ncoghlan -pep-0599.rst @pfmoore -pep-0600.rst @njsmith -pep-0601.txt @isidentical -pep-0602.rst @ambv -pep-0602-example-release-calendar.png @ambv -pep-0602-example-release-calendar.pptx @ambv -pep-0602-overlapping-support-matrix.png @ambv -pep-0602-overlapping-support-matrix.pptx @ambv -pep-0603.rst @1st1 -pep-0603-lookup_hamt.png @1st1 -pep-0603-hamt_vs_dict.png @1st1 -# pep-0604.rst -pep-0605.rst @zooba @ncoghlan -pep-0605-example-release-calendar.png @zooba @ncoghlan -pep-0605-overlapping-support-matrix.png @zooba @ncoghlan -pep-0605/ @zooba @ncoghlan -pep-0606.rst @vstinner -pep-0607.rst @ambv @zooba @ncoghlan -pep-0608.rst @vstinner -pep-0609.rst @pganssle -pep-0610.rst @cjerdonek -pep-0611.rst @markshannon -pep-0612.rst @gvanrossum -pep-0613.rst @gvanrossum -pep-0614.rst @brandtbucher -pep-0615.rst @pganssle -pep-0616.rst @ericvsmith -pep-0617.rst @gvanrossum @pablogsal @lysnikolaou -pep-0618.rst @brandtbucher -pep-0619.rst @pablogsal -pep-0620.rst @vstinner -pep-0621.rst @brettcannon @pganssle -pep-0622.rst @brandtbucher @ilevkivskyi @gvanrossum -pep-0623.rst @methane -pep-0624.rst @methane -pep-0625.rst @pfmoore -pep-0626.rst @markshannon -pep-0627.rst @encukou -pep-0628.txt @ncoghlan -pep-0629.rst @dstufft -pep-0630.rst @encukou -pep-0631.rst @pganssle -pep-0632.rst @zooba -pep-0633.rst @brettcannon -pep-0634.rst @brandtbucher @gvanrossum -pep-0635.rst @brandtbucher @gvanrossum -pep-0636.rst @brandtbucher @gvanrossum -# pep-0637.rst @stevendaprano -pep-0638.rst @markshannon -pep-0639.rst @CAM-Gerlach -pep-0640.rst @Yhg1s -pep-0641.rst @zooba @warsaw @brettcannon -pep-0642.rst @ncoghlan -pep-0643.rst @pfmoore -pep-0644.rst @tiran -pep-0645.rst @gvanrossum -pep-0646.rst @gvanrossum -pep-0647.rst @gvanrossum -pep-0648.rst @pablogsal -pep-0649.rst @larryhastings -pep-0650.rst @brettcannon -pep-0651.rst @markshannon -pep-0652.rst @encukou -pep-0653.rst @markshannon -pep-0654.rst @1st1 @gvanrossum @iritkatriel -pep-0655.rst @gvanrossum -pep-0656.rst @brettcannon -pep-0657.rst @pablogsal @isidentical @ammaraskar -pep-0658.rst @brettcannon -pep-0659.rst @markshannon -pep-0660.rst @pfmoore -pep-0661.rst @taleinat -pep-0662.rst @brettcannon -pep-0662/ @brettcannon -pep-0663.txt @ethanfurman -pep-0664.rst @pablogsal -pep-0665.rst @brettcannon -# pep-0666.txt -pep-0667.rst @markshannon -pep-0668.rst @dstufft -pep-0669.rst @markshannon -pep-0670.rst @vstinner @erlend-aasland -pep-0671.rst @rosuav -pep-0672.rst @encukou -pep-0673.rst @jellezijlstra -pep-0674.rst @vstinner -pep-0675.rst @jellezijlstra -pep-0676.rst @AA-Turner @Mariatta -pep-0677.rst @gvanrossum -pep-0678.rst @iritkatriel -pep-0679.rst @pablogsal -pep-0680.rst @encukou -pep-0681.rst @jellezijlstra -pep-0682.rst @mdickinson -pep-0683.rst @ericsnowcurrently -pep-0684.rst @ericsnowcurrently -# pep-0684.rst -pep-0685.rst @brettcannon -pep-0686.rst @methane -pep-0687.rst @encukou @erlend-aasland -pep-0688.rst @jellezijlstra -pep-0689.rst @encukou -pep-0690.rst @warsaw -pep-0691.rst @dstufft -pep-0692.rst @jellezijlstra -pep-0693.rst @Yhg1s -pep-0694.rst @dstufft -pep-0695.rst @gvanrossum -pep-0696.rst @jellezijlstra -pep-0697.rst @encukou -pep-0698.rst @jellezijlstra -pep-0699.rst @Fidget-Spinner -pep-0700.rst @pfmoore -pep-0701.rst @pablogsal @isidentical @lysnikolaou -pep-0702.rst @jellezijlstra -pep-0703.rst @ambv -pep-0704.rst @brettcannon @pradyunsg -pep-0705.rst @pablogsal -pep-0706.rst @encukou -pep-0707.rst @iritkatriel -pep-0708.rst @dstufft -pep-0709.rst @carljm -pep-0710.rst @dstufft -pep-0711.rst @njsmith -pep-0712.rst @ericvsmith -pep-0713.rst @ambv -pep-0714.rst @dstufft -pep-0715.rst @dstufft -pep-0718.rst @gvanrossum -pep-0719.rst @Yhg1s -pep-0720.rst @FFY00 -pep-0721.rst @encukou -pep-0722.rst @pfmoore -pep-0723.rst @AA-Turner -pep-0725.rst @pradyunsg -pep-0726.rst @AA-Turner -pep-0727.rst @JelleZijlstra +peps/pep-0200.rst @jeremyhylton +peps/pep-0201.rst @warsaw +peps/pep-0202.rst @warsaw +peps/pep-0203.rst @Yhg1s +peps/pep-0204.rst @Yhg1s +peps/pep-0205.rst @freddrake +# peps/pep-0206.rst +peps/pep-0207.rst @gvanrossum +peps/pep-0208.rst @nascheme @malemburg +# peps/pep-0209.rst +# peps/pep-0210.rst +# peps/pep-0211.rst +# peps/pep-0212.rst +# peps/pep-0213.rst +peps/pep-0214.rst @warsaw +# peps/pep-0215.rst +# peps/pep-0216.rst +# peps/pep-0217.rst +peps/pep-0218.rst @rhettinger +# peps/pep-0219.rst +# peps/pep-0220.rst +peps/pep-0221.rst @Yhg1s +# peps/pep-0222.rst +peps/pep-0223.rst @tim-one +peps/pep-0224.rst @malemburg +# peps/pep-0225.rst +peps/pep-0226.rst @jeremyhylton +peps/pep-0227.rst @jeremyhylton +peps/pep-0228.rst @gvanrossum +# peps/pep-0229.rst +peps/pep-0230.rst @gvanrossum +peps/pep-0231.rst @warsaw +peps/pep-0232.rst @warsaw +# peps/pep-0233.rst +peps/pep-0234.rst @gvanrossum +peps/pep-0235.rst @tim-one +peps/pep-0236.rst @tim-one +peps/pep-0237.rst @gvanrossum +peps/pep-0238.rst @gvanrossum +# peps/pep-0239.rst +# peps/pep-0240.rst +# peps/pep-0241.rst +# peps/pep-0242.rst +# peps/pep-0243.rst +# peps/pep-0244.rst +# peps/pep-0245.rst +peps/pep-0246.rst @aleaxit +# peps/pep-0247.rst +peps/pep-0248.rst @malemburg +peps/pep-0249.rst @malemburg +peps/pep-0250.rst @pfmoore +peps/pep-0251.rst @warsaw @gvanrossum +peps/pep-0252.rst @gvanrossum +peps/pep-0253.rst @gvanrossum +peps/pep-0254.rst @gvanrossum +peps/pep-0255.rst @nascheme @tim-one +# peps/pep-0256.rst +peps/pep-0257.rst @gvanrossum +# peps/pep-0258.rst +peps/pep-0259.rst @gvanrossum +peps/pep-0260.rst @gvanrossum +# peps/pep-0261.rst +# peps/pep-0262.rst +peps/pep-0263.rst @malemburg +# peps/pep-0264.rst +# peps/pep-0265.rst +# peps/pep-0266.rst +peps/pep-0267.rst @jeremyhylton +# peps/pep-0268.rst +# peps/pep-0269.rst +# peps/pep-0270.rst +# peps/pep-0271.rst +# peps/pep-0272.rst +# peps/pep-0273.rst +peps/pep-0274.rst @warsaw +peps/pep-0275.rst @malemburg +# peps/pep-0276.rst +# peps/pep-0277.rst +peps/pep-0278.rst @jackjansen +peps/pep-0279.rst @rhettinger +peps/pep-0280.rst @gvanrossum +# peps/pep-0281.rst +peps/pep-0282.rst @vsajip +peps/pep-0283.rst @gvanrossum +# peps/pep-0284.rst +peps/pep-0285.rst @gvanrossum +# peps/pep-0286.rst +# peps/pep-0287.rst +peps/pep-0288.rst @rhettinger +peps/pep-0289.rst @rhettinger +peps/pep-0290.rst @rhettinger +# peps/pep-0291.rst +peps/pep-0292.rst @warsaw +peps/pep-0293.rst @doerwalter +# peps/pep-0294.rst +# peps/pep-0295.rst +# peps/pep-0296.rst +peps/pep-0297.rst @malemburg +peps/pep-0298.rst @theller +# peps/pep-0299.rst +# peps/pep-0301.rst +peps/pep-0302.rst @pfmoore +# peps/pep-0303.rst +# peps/pep-0304.rst +# peps/pep-0305.rst +peps/pep-0306.rst @jackdied @ncoghlan @benjaminp +peps/pep-0307.rst @gvanrossum @tim-one +peps/pep-0308.rst @gvanrossum @rhettinger +# peps/pep-0309.rst +peps/pep-0310.rst @pfmoore +peps/pep-0311.rst @mhammond +peps/pep-0312.rst @aleaxit +# peps/pep-0313.rst +# peps/pep-0314.rst +peps/pep-0315.rst @rhettinger +# peps/pep-0316.rst +# peps/pep-0317.rst +# peps/pep-0318.rst +# peps/pep-0319.rst +peps/pep-0320.rst @warsaw @rhettinger +# peps/pep-0321.rst +peps/pep-0322.rst @rhettinger +peps/pep-0323.rst @aleaxit +# peps/pep-0324.rst +# peps/pep-0325.rst +peps/pep-0326.rst @terryjreedy +peps/pep-0327.rst @facundobatista +# peps/pep-0328.rst +peps/pep-0329.rst @rhettinger +# peps/pep-0330.rst +# peps/pep-0331.rst +# peps/pep-0332.rst +# peps/pep-0333.rst +# peps/pep-0334.rst +# peps/pep-0335.rst +# peps/pep-0336.rst +# peps/pep-0337.rst +peps/pep-0338.rst @ncoghlan +peps/pep-0339.rst @brettcannon +peps/pep-0340.rst @gvanrossum +peps/pep-0341.rst @birkenfeld +peps/pep-0342.rst @gvanrossum +peps/pep-0343.rst @gvanrossum @ncoghlan +# peps/pep-0344.rst +# peps/pep-0345.rst +peps/pep-0346.rst @ncoghlan +# peps/pep-0347.rst +peps/pep-0348.rst @brettcannon +peps/pep-0349.rst @nascheme +# peps/pep-0350.rst +peps/pep-0351.rst @warsaw +peps/pep-0352.rst @brettcannon @gvanrossum +# peps/pep-0353.rst +# peps/pep-0354.rst +# peps/pep-0355.rst +peps/pep-0356.rst @gvanrossum +# peps/pep-0357.rst +peps/pep-0358.rst @nascheme @gvanrossum +# peps/pep-0359.rst +peps/pep-0360.rst @brettcannon +peps/pep-0361.rst @warsaw +peps/pep-0362.rst @brettcannon @1st1 @larryhastings +# peps/pep-0363.rst +peps/pep-0364.rst @warsaw +# peps/pep-0365.rst +peps/pep-0366.rst @ncoghlan +# peps/pep-0367.rst +# peps/pep-0368.rst +peps/pep-0369.rst @tiran +peps/pep-0370.rst @tiran +# peps/pep-0371.rst +peps/pep-0372.rst @mitsuhiko @rhettinger +peps/pep-0373.rst @benjaminp +peps/pep-0374.rst @brettcannon @avassalotti @warsaw +peps/pep-0375.rst @benjaminp +# peps/pep-0376.rst +peps/pep-0377.rst @ncoghlan +peps/pep-0378.rst @rhettinger +# peps/pep-0379.rst +# peps/pep-0380.rst +# peps/pep-0381.rst +# peps/pep-0382.rst +# peps/pep-0383.rst +# peps/pep-0384.rst +peps/pep-0385.rst @pitrou @birkenfeld +# peps/pep-0386.rst +peps/pep-0387.rst @benjaminp @vstinner +# peps/pep-0389.rst +# peps/pep-0390.rst +peps/pep-0391.rst @vsajip +peps/pep-0392.rst @birkenfeld +# peps/pep-0393.rst +peps/pep-0394.rst @ncoghlan @warsaw @encukou @willingc +peps/pep-0395.rst @ncoghlan +peps/pep-0396.rst @warsaw +peps/pep-0397.rst @mhammond +peps/pep-0398.rst @birkenfeld +peps/pep-0399.rst @brettcannon +peps/pep-0400.rst @vstinner +peps/pep-0401.rst @warsaw @brettcannon +# peps/pep-0402.rst +peps/pep-0403.rst @ncoghlan +peps/pep-0404.rst @warsaw +# peps/pep-0405.rst +peps/pep-0406.rst @ncoghlan +peps/pep-0407.rst @pitrou @birkenfeld @warsaw +peps/pep-0408.rst @ncoghlan @eliben +peps/pep-0409.rst @ethanfurman +peps/pep-0410.rst @vstinner +peps/pep-0411.rst @ncoghlan @eliben +peps/pep-0412.rst @markshannon +peps/pep-0413.rst @ncoghlan +peps/pep-0414.rst @mitsuhiko @ncoghlan +peps/pep-0415.rst @benjaminp +peps/pep-0416.rst @vstinner +peps/pep-0417.rst @voidspace +peps/pep-0418.rst @vstinner +peps/pep-0418/ @vstinner +# peps/pep-0419.rst +peps/pep-0420.rst @ericvsmith +peps/pep-0421.rst @ericsnowcurrently +peps/pep-0422.rst @ncoghlan +# peps/pep-0423.rst +peps/pep-0424.rst @alex +# peps/pep-0425.rst +peps/pep-0426.rst @ncoghlan @dstufft +peps/pep-0426/ @ncoghlan @dstufft +# peps/pep-0427.rst +peps/pep-0428.rst @pitrou +peps/pep-0429.rst @larryhastings +peps/pep-0430.rst @ncoghlan +# peps/pep-0431.rst +peps/pep-0432.rst @ncoghlan @vstinner @ericsnowcurrently +peps/pep-0433.rst @vstinner +peps/pep-0433/ @vstinner +peps/pep-0434.rst @terryjreedy +peps/pep-0435.rst @warsaw @eliben @ethanfurman +peps/pep-0436.rst @larryhastings +# peps/pep-0437.rst +# peps/pep-0438.rst +# peps/pep-0439.rst +peps/pep-0440.rst @ncoghlan @dstufft +peps/pep-0441.rst @pfmoore +peps/pep-0442.rst @pitrou +peps/pep-0443.rst @ambv +peps/pep-0444.rst @mitsuhiko +peps/pep-0445.rst @vstinner +peps/pep-0446.rst @vstinner +peps/pep-0446/ @vstinner +peps/pep-0447.rst @ronaldoussoren +# peps/pep-0448.rst +peps/pep-0449.rst @dstufft +# peps/pep-0450.rst @stevendaprano +peps/pep-0451.rst @ericsnowcurrently +peps/pep-0452.rst @tiran +peps/pep-0453.rst @dstufft @ncoghlan +peps/pep-0454.rst @vstinner +peps/pep-0455.rst @pitrou +peps/pep-0456.rst @tiran +peps/pep-0457.rst @larryhastings +# peps/pep-0458.rst, peps/pep-0458-1.png +peps/pep-0459.rst @ncoghlan +peps/pep-0460.rst @pitrou +peps/pep-0461.rst @ethanfurman +peps/pep-0462.rst @ncoghlan +# peps/pep-0463.rst +peps/pep-0464.rst @dstufft +peps/pep-0465.rst @njsmith +peps/pep-0465/ @njsmith +peps/pep-0466.rst @ncoghlan +peps/pep-0467.rst @ncoghlan @ethanfurman +peps/pep-0468.rst @ericsnowcurrently +peps/pep-0469.rst @ncoghlan +peps/pep-0470.rst @dstufft +# peps/pep-0471.rst +# peps/pep-0472.rst +# peps/pep-0473.rst +peps/pep-0474.rst @ncoghlan +peps/pep-0475.rst @vstinner +peps/pep-0476.rst @alex +peps/pep-0477.rst @dstufft @ncoghlan +peps/pep-0478.rst @larryhastings +peps/pep-0479.rst @gvanrossum +# peps/pep-0480.rst, peps/pep-0480-1.png +peps/pep-0481.rst @dstufft +peps/pep-0482.rst @ambv +peps/pep-0483.rst @gvanrossum @ilevkivskyi +peps/pep-0484.rst @gvanrossum @ambv +# peps/pep-0485.rst +peps/pep-0486.rst @pfmoore +# peps/pep-0487.rst +peps/pep-0488.rst @brettcannon +peps/pep-0489.rst @encukou @scoder @ncoghlan +peps/pep-0490.rst @vstinner +# peps/pep-0491.rst +peps/pep-0492.rst @1st1 +peps/pep-0493.rst @ncoghlan @malemburg +peps/pep-0494.rst @ned-deily +peps/pep-0495.rst @abalkin @tim-one +peps/pep-0495-gap.png @abalkin @tim-one +peps/pep-0495-gap.svg @abalkin @tim-one +peps/pep-0495-fold.svg @abalkin @tim-one +peps/pep-0495-fold-2.png @abalkin @tim-one +peps/pep-0495-daylightsavings.png @abalkin @tim-one +# peps/pep-0496.rst +# peps/pep-0497.rst +peps/pep-0498.rst @ericvsmith +# peps/pep-0499.rst +peps/pep-0500.rst @abalkin @tim-one +peps/pep-0501.rst @ncoghlan +# peps/pep-0502.rst +peps/pep-0503.rst @dstufft +peps/pep-0504.rst @ncoghlan +peps/pep-0505.rst @zooba +peps/pep-0505/ @zooba +# peps/pep-0506.rst @stevendaprano +peps/pep-0507.rst @warsaw +peps/pep-0508.rst @rbtcollins +peps/pep-0509.rst @vstinner +peps/pep-0510.rst @vstinner +peps/pep-0511.rst @vstinner +peps/pep-0512.rst @brettcannon +peps/pep-0513.rst @njsmith +peps/pep-0514.rst @zooba +peps/pep-0515.rst @birkenfeld @serhiy-storchaka +peps/pep-0516.rst @rbtcollins @njsmith +peps/pep-0517.rst @njsmith +peps/pep-0518.rst @brettcannon @njsmith @dstufft +peps/pep-0519.rst @brettcannon +peps/pep-0520.rst @ericsnowcurrently +peps/pep-0521.rst @njsmith +peps/pep-0522.rst @ncoghlan @njsmith +peps/pep-0523.rst @brettcannon @DinoV +peps/pep-0524.rst @vstinner +peps/pep-0525.rst @1st1 +peps/pep-0525-1.png @1st1 +peps/pep-0526.rst @ilevkivskyi @lisroach @gvanrossum +peps/pep-0527.rst @dstufft +peps/pep-0528.rst @zooba +peps/pep-0529.rst @zooba +peps/pep-0530.rst @1st1 +peps/pep-0531.rst @ncoghlan +peps/pep-0532.rst @ncoghlan +peps/pep-0532/ @ncoghlan +peps/pep-0533.rst @njsmith +peps/pep-0534.rst @encukou @ncoghlan +peps/pep-0535.rst @ncoghlan +# peps/pep-0536.rst +peps/pep-0537.rst @ned-deily +peps/pep-0538.rst @ncoghlan +# peps/pep-0539.rst +peps/pep-0540.rst @vstinner +peps/pep-0541.rst @ambv +# peps/pep-0542.rst +peps/pep-0543.rst @tiran +peps/pep-0544.rst @ilevkivskyi @ambv +peps/pep-0545.rst @JulienPalard @methane @vstinner +peps/pep-0546.rst @vstinner +peps/pep-0547.rst @encukou +peps/pep-0548.rst @bitdancer +peps/pep-0549.rst @larryhastings +peps/pep-0550.rst @1st1 +peps/pep-0550-lookup_hamt.png @1st1 +peps/pep-0550-hamt_vs_dict.png @1st1 +peps/pep-0550-hamt_vs_dict-v2.png @1st1 +peps/pep-0551.rst @zooba +peps/pep-0552.rst @benjaminp +peps/pep-0553.rst @warsaw +peps/pep-0554.rst @ericsnowcurrently +# peps/pep-0555.rst +peps/pep-0556.rst @pitrou +peps/pep-0557.rst @ericvsmith +peps/pep-0558.rst @ncoghlan +peps/pep-0559.rst @warsaw +peps/pep-0560.rst @ilevkivskyi +# peps/pep-0561.rst +peps/pep-0562.rst @ilevkivskyi +peps/pep-0563.rst @ambv +peps/pep-0564.rst @vstinner +peps/pep-0565.rst @ncoghlan +# peps/pep-0566.rst +peps/pep-0567.rst @1st1 +peps/pep-0568.rst @njsmith +peps/pep-0569.rst @ambv +peps/pep-0570.rst @larryhastings @pablogsal +# peps/pep-0571.rst +peps/pep-0572.rst @tim-one @gvanrossum +peps/pep-0573.rst @encukou @ncoghlan @ericsnowcurrently +peps/pep-0574.rst @pitrou +# peps/pep-0575.rst +peps/pep-0576.rst @markshannon +peps/pep-0577.rst @ncoghlan +peps/pep-0578.rst @zooba +# peps/pep-0579.rst +# peps/pep-0580.rst +peps/pep-0581.rst @Mariatta +peps/pep-0582.rst @kushaldas @zooba @dstufft @ncoghlan +# peps/pep-0583.rst +peps/pep-0584.rst @brandtbucher # @stevendaprano +peps/pep-0585.rst @ambv +peps/pep-0586.rst @ilevkivskyi +peps/pep-0587.rst @vstinner @ncoghlan +peps/pep-0588.rst @Mariatta +peps/pep-0589.rst @gvanrossum +peps/pep-0590.rst @markshannon +peps/pep-0591.rst @ilevkivskyi +peps/pep-0592.rst @dstufft +peps/pep-0593.rst @ilevkivskyi +peps/pep-0594.rst @tiran @brettcannon +peps/pep-0595.rst @ezio-melotti @berkerpeksag +peps/pep-0596.rst @ambv +peps/pep-0597.rst @methane +peps/pep-0598.rst @ncoghlan +peps/pep-0599.rst @pfmoore +peps/pep-0600.rst @njsmith +peps/pep-0601.rst @isidentical +peps/pep-0602.rst @ambv +peps/pep-0602-example-release-calendar.png @ambv +peps/pep-0602-example-release-calendar.pptx @ambv +peps/pep-0602-overlapping-support-matrix.png @ambv +peps/pep-0602-overlapping-support-matrix.pptx @ambv +peps/pep-0603.rst @1st1 +peps/pep-0603-lookup_hamt.png @1st1 +peps/pep-0603-hamt_vs_dict.png @1st1 +# peps/pep-0604.rst +peps/pep-0605.rst @zooba @ncoghlan +peps/pep-0605-example-release-calendar.png @zooba @ncoghlan +peps/pep-0605-overlapping-support-matrix.png @zooba @ncoghlan +peps/pep-0605/ @zooba @ncoghlan +peps/pep-0606.rst @vstinner +peps/pep-0607.rst @ambv @zooba @ncoghlan +peps/pep-0608.rst @vstinner +peps/pep-0609.rst @pganssle +peps/pep-0610.rst @cjerdonek +peps/pep-0611.rst @markshannon +peps/pep-0612.rst @gvanrossum +peps/pep-0613.rst @gvanrossum +peps/pep-0614.rst @brandtbucher +peps/pep-0615.rst @pganssle +peps/pep-0616.rst @ericvsmith +peps/pep-0617.rst @gvanrossum @pablogsal @lysnikolaou +peps/pep-0618.rst @brandtbucher +peps/pep-0619.rst @pablogsal +peps/pep-0620.rst @vstinner +peps/pep-0621.rst @brettcannon @pganssle +peps/pep-0622.rst @brandtbucher @ilevkivskyi @gvanrossum +peps/pep-0623.rst @methane +peps/pep-0624.rst @methane +peps/pep-0625.rst @pfmoore +peps/pep-0626.rst @markshannon +peps/pep-0627.rst @encukou +peps/pep-0628.rst @ncoghlan +peps/pep-0629.rst @dstufft +peps/pep-0630.rst @encukou +peps/pep-0631.rst @pganssle +peps/pep-0632.rst @zooba +peps/pep-0633.rst @brettcannon +peps/pep-0634.rst @brandtbucher @gvanrossum +peps/pep-0635.rst @brandtbucher @gvanrossum +peps/pep-0636.rst @brandtbucher @gvanrossum +# peps/pep-0637.rst @stevendaprano +peps/pep-0638.rst @markshannon +peps/pep-0639.rst @CAM-Gerlach +peps/pep-0640.rst @Yhg1s +peps/pep-0641.rst @zooba @warsaw @brettcannon +peps/pep-0642.rst @ncoghlan +peps/pep-0643.rst @pfmoore +peps/pep-0644.rst @tiran +peps/pep-0645.rst @gvanrossum +peps/pep-0646.rst @gvanrossum +peps/pep-0647.rst @gvanrossum +peps/pep-0648.rst @pablogsal +peps/pep-0649.rst @larryhastings +peps/pep-0650.rst @brettcannon +peps/pep-0651.rst @markshannon +peps/pep-0652.rst @encukou +peps/pep-0653.rst @markshannon +peps/pep-0654.rst @1st1 @gvanrossum @iritkatriel +peps/pep-0655.rst @gvanrossum +peps/pep-0656.rst @brettcannon +peps/pep-0657.rst @pablogsal @isidentical @ammaraskar +peps/pep-0658.rst @brettcannon +peps/pep-0659.rst @markshannon +peps/pep-0660.rst @pfmoore +peps/pep-0661.rst @taleinat +peps/pep-0662.rst @brettcannon +peps/pep-0662/ @brettcannon +peps/pep-0663.rst @ethanfurman +peps/pep-0664.rst @pablogsal +peps/pep-0665.rst @brettcannon +# peps/pep-0666.rst +peps/pep-0667.rst @markshannon +peps/pep-0668.rst @dstufft +peps/pep-0669.rst @markshannon +peps/pep-0670.rst @vstinner @erlend-aasland +peps/pep-0671.rst @rosuav +peps/pep-0672.rst @encukou +peps/pep-0673.rst @jellezijlstra +peps/pep-0674.rst @vstinner +peps/pep-0675.rst @jellezijlstra +peps/pep-0676.rst @AA-Turner @Mariatta +peps/pep-0677.rst @gvanrossum +peps/pep-0678.rst @iritkatriel +peps/pep-0679.rst @pablogsal +peps/pep-0680.rst @encukou +peps/pep-0681.rst @jellezijlstra +peps/pep-0682.rst @mdickinson +peps/pep-0683.rst @ericsnowcurrently +peps/pep-0684.rst @ericsnowcurrently +# peps/pep-0684.rst +peps/pep-0685.rst @brettcannon +peps/pep-0686.rst @methane +peps/pep-0687.rst @encukou @erlend-aasland +peps/pep-0688.rst @jellezijlstra +peps/pep-0689.rst @encukou +peps/pep-0690.rst @warsaw +peps/pep-0691.rst @dstufft +peps/pep-0692.rst @jellezijlstra +peps/pep-0693.rst @Yhg1s +peps/pep-0694.rst @dstufft +peps/pep-0695.rst @gvanrossum +peps/pep-0696.rst @jellezijlstra +peps/pep-0697.rst @encukou +peps/pep-0698.rst @jellezijlstra +peps/pep-0699.rst @Fidget-Spinner +peps/pep-0700.rst @pfmoore +peps/pep-0701.rst @pablogsal @isidentical @lysnikolaou +peps/pep-0702.rst @jellezijlstra +peps/pep-0703.rst @ambv +peps/pep-0704.rst @brettcannon @pradyunsg +peps/pep-0705.rst @pablogsal +peps/pep-0706.rst @encukou +peps/pep-0707.rst @iritkatriel +peps/pep-0708.rst @dstufft +peps/pep-0709.rst @carljm +peps/pep-0710.rst @dstufft +peps/pep-0711.rst @njsmith +peps/pep-0712.rst @ericvsmith +peps/pep-0713.rst @ambv +peps/pep-0714.rst @dstufft +peps/pep-0715.rst @dstufft +peps/pep-0718.rst @gvanrossum +peps/pep-0719.rst @Yhg1s +peps/pep-0720.rst @FFY00 +peps/pep-0721.rst @encukou +peps/pep-0722.rst @pfmoore +peps/pep-0723.rst @AA-Turner +peps/pep-0725.rst @pradyunsg +peps/pep-0726.rst @AA-Turner +peps/pep-0727.rst @JelleZijlstra # ... -# pep-0754.txt +# peps/pep-0754.rst # ... -pep-0801.rst @warsaw +peps/pep-0801.rst @warsaw # ... -pep-3000.txt @gvanrossum -pep-3001.txt @birkenfeld -# pep-3002.txt -pep-3003.txt @brettcannon @gvanrossum +peps/pep-3000.rst @gvanrossum +peps/pep-3001.rst @birkenfeld +# peps/pep-3002.rst +peps/pep-3003.rst @brettcannon @gvanrossum # ... -pep-3099.txt @birkenfeld -pep-3100.txt @brettcannon -# pep-3101.txt -# pep-3102.txt -pep-3103.txt @gvanrossum -# pep-3104.txt -pep-3105.txt @birkenfeld -pep-3106.txt @gvanrossum -# pep-3107.txt -pep-3108.txt @brettcannon -# pep-3109.txt -# pep-3110.txt -# pep-3111.txt -# pep-3112.txt -pep-3113.txt @brettcannon -# pep-3114.txt -# pep-3115.txt -pep-3116.txt @gvanrossum -pep-3117.txt @birkenfeld -# pep-3118.txt -pep-3119.txt @gvanrossum -# pep-3120.txt -# pep-3121.txt -pep-3122.txt @brettcannon -# pep-3123.txt -# pep-3124.txt -# pep-3125.txt -pep-3126.txt @rhettinger -# pep-3127.txt -# pep-3128.txt -# pep-3129.txt -# pep-3130.txt -# pep-3131.txt -pep-3132.txt @birkenfeld -# pep-3133.txt -# pep-3134.txt -# pep-3135.txt -# pep-3136.txt -pep-3137.txt @gvanrossum -# pep-3138.txt -pep-3139.txt @benjaminp -# pep-3140.txt -# pep-3141.txt -# pep-3142.txt -# pep-3143.txt -# pep-3144.txt -# pep-3145.txt -# pep-3146.txt -pep-3147.txt @warsaw -pep-3147-1.dia @warsaw -pep-3147-1.png @warsaw -pep-3148.txt @brianquinlan -pep-3149.txt @warsaw -pep-3150.txt @ncoghlan -pep-3151.txt @pitrou -# pep-3152.txt -# pep-3153.txt -pep-3154.txt @pitrou -pep-3155.txt @pitrou -pep-3156.txt @gvanrossum +peps/pep-3099.rst @birkenfeld +peps/pep-3100.rst @brettcannon +# peps/pep-3101.rst +# peps/pep-3102.rst +peps/pep-3103.rst @gvanrossum +# peps/pep-3104.rst +peps/pep-3105.rst @birkenfeld +peps/pep-3106.rst @gvanrossum +# peps/pep-3107.rst +peps/pep-3108.rst @brettcannon +# peps/pep-3109.rst +# peps/pep-3110.rst +# peps/pep-3111.rst +# peps/pep-3112.rst +peps/pep-3113.rst @brettcannon +# peps/pep-3114.rst +# peps/pep-3115.rst +peps/pep-3116.rst @gvanrossum +peps/pep-3117.rst @birkenfeld +# peps/pep-3118.rst +peps/pep-3119.rst @gvanrossum +# peps/pep-3120.rst +# peps/pep-3121.rst +peps/pep-3122.rst @brettcannon +# peps/pep-3123.rst +# peps/pep-3124.rst +# peps/pep-3125.rst +peps/pep-3126.rst @rhettinger +# peps/pep-3127.rst +# peps/pep-3128.rst +# peps/pep-3129.rst +# peps/pep-3130.rst +# peps/pep-3131.rst +peps/pep-3132.rst @birkenfeld +# peps/pep-3133.rst +# peps/pep-3134.rst +# peps/pep-3135.rst +# peps/pep-3136.rst +peps/pep-3137.rst @gvanrossum +# peps/pep-3138.rst +peps/pep-3139.rst @benjaminp +# peps/pep-3140.rst +# peps/pep-3141.rst +# peps/pep-3142.rst +# peps/pep-3143.rst +# peps/pep-3144.rst +# peps/pep-3145.rst +# peps/pep-3146.rst +peps/pep-3147.rst @warsaw +peps/pep-3147-1.dia @warsaw +peps/pep-3147-1.png @warsaw +peps/pep-3148.rst @brianquinlan +peps/pep-3149.rst @warsaw +peps/pep-3150.rst @ncoghlan +peps/pep-3151.rst @pitrou +# peps/pep-3152.rst +# peps/pep-3153.rst +peps/pep-3154.rst @pitrou +peps/pep-3155.rst @pitrou +peps/pep-3156.rst @gvanrossum # ... -# pep-3333.txt +# peps/pep-3333.rst # ... -pep-8000.rst @warsaw -pep-8001.rst @brettcannon @tiran @dstufft @ericsnowcurrently @gpshead @ambv @Mariatta @njsmith @pablogsal @rhettinger @taleinat @tim-one @zware -pep-8002.rst @warsaw @ambv @pitrou @dhellmann @willingc -pep-8010.rst @warsaw -pep-8011.rst @Mariatta @warsaw -pep-8012.rst @ambv -pep-8013.rst @zooba -pep-8014.rst @jackjansen -pep-8015.rst @vstinner -pep-8016.rst @njsmith @dstufft +peps/pep-8000.rst @warsaw +peps/pep-8001.rst @brettcannon @tiran @dstufft @ericsnowcurrently @gpshead @ambv @Mariatta @njsmith @pablogsal @rhettinger @taleinat @tim-one @zware +peps/pep-8002.rst @warsaw @ambv @pitrou @dhellmann @willingc +peps/pep-8010.rst @warsaw +peps/pep-8011.rst @Mariatta @warsaw +peps/pep-8012.rst @ambv +peps/pep-8013.rst @zooba +peps/pep-8014.rst @jackjansen +peps/pep-8015.rst @vstinner +peps/pep-8016.rst @njsmith @dstufft # ... -pep-8100.rst @njsmith -# pep-8101.rst -# pep-8102.rst +peps/pep-8100.rst @njsmith +# peps/pep-8101.rst +# peps/pep-8102.rst diff --git a/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md b/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md index bcc29bf74..48aaa3072 100644 --- a/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md +++ b/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md @@ -10,7 +10,7 @@ If your PEP is not Standards Track, remove the corresponding section. ## Basic requirements (all PEP Types) * [ ] Read and followed [PEP 1](https://peps.python.org/1) & [PEP 12](https://peps.python.org/12) -* [ ] File created from the [latest PEP template](https://github.com/python/peps/blob/main/pep-0012/pep-NNNN.rst?plain=1) +* [ ] File created from the [latest PEP template](https://github.com/python/peps/blob/main/peps/pep-0012/pep-NNNN.rst?plain=1) * [ ] PEP has next available number, & set in filename (``pep-NNNN.rst``), PR title (``PEP 123: ``) and ``PEP`` header * [ ] Title clearly, accurately and concisely describes the content in 79 characters or less * [ ] Core dev/PEP editor listed as ``Author`` or ``Sponsor``, and formally confirmed their approval diff --git a/.gitignore b/.gitignore index ae1196cb1..6beae9d8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,24 @@ -coverage.xml -pep-0000.txt +# PEPs pep-0000.rst -pep-????.html peps.rss +topic +/build + +# Bytecode __pycache__ -*.pyc -*.pyo +*.py[co] + +# Editors *~ -*env -.coverage -.tox +.idea .vscode *.swp -/build -/package -/topic + +# Tests +coverage.xml +.coverage +.tox + +# Virtual environments +*env /venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8da57b575..81d21c8e4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,16 +82,12 @@ repos: hooks: - id: rst-backticks name: "Check RST: No single backticks" - files: '^pep-\d+\.(rst|txt)$' - types: [text] + - id: rst-inline-touching-normal name: "Check RST: No backticks touching text" - files: '^pep-\d+\.(rst|txt)$' - types: [text] + - id: rst-directive-colons name: "Check RST: 2 colons after directives" - files: '^pep-\d+\.(rst|txt)$' - types: [text] # Manual codespell check - repo: https://github.com/codespell-project/codespell @@ -112,152 +108,126 @@ repos: # files: "^pep-\d{4}\.(rst|txt)$" # require_serial: true - - id: check-no-tabs - name: "Check tabs not used in PEPs" - language: pygrep - entry: '\t' - files: '^pep-\d+\.(rst|txt)$' - types: [text] - - id: check-required-headers name: "PEPs must have all required headers" language: pygrep entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nContent-Type:)(?=[\s\S]*\nCreated:))' args: ['--negate', '--multiline'] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: check-header-order name: "PEP header order must follow PEP 12" language: pygrep entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?Content-Type:[^\n]+\n(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n' args: ['--negate', '--multiline'] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-pep-number name: "'PEP' header must be a number 1-9999" language: pygrep entry: '(?-m:^PEP:(?:(?! +(0|[1-9][0-9]{0,3})\n)))' args: ['--multiline'] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-title name: "'Title' must be 1-79 characters" language: pygrep entry: '(?<=\n)Title:(?:(?! +\S.{1,78}\n(?=[A-Z])))' args: ['--multiline'] - files: '^pep-\d+\.(rst|txt)$' - exclude: '^pep-(0499)\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' + exclude: '^peps/pep-(0499)\.rst$' - id: validate-author name: "'Author' must be list of 'Name <email@example.com>, ...'" language: pygrep entry: '(?<=\n)Author:(?:(?!((( +|\n {1,8})[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?)(,|(?=\n[^ ])))+\n(?=[A-Z])))' - args: [--multiline] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + args: ["--multiline"] + files: '^peps/pep-\d+\.rst$' - id: validate-sponsor name: "'Sponsor' must have format 'Name <email@example.com>'" language: pygrep entry: '^Sponsor:(?: (?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-delegate name: "'Delegate' must have format 'Name <email@example.com>'" language: pygrep entry: '^(PEP|BDFL)-Delegate: (?:(?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))' - files: '^pep-\d+\.(rst|txt)$' - exclude: '^pep-(0451)\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' + exclude: '^peps/pep-(0451)\.rst$' - id: validate-discussions-to name: "'Discussions-To' must be a thread URL" language: pygrep entry: '^Discussions-To: (?:(?!([\w\-]+@(python\.org|googlegroups\.com))|https://((discuss\.python\.org/t/([\w\-]+/)?\d+/?)|(mail\.python\.org/pipermail/[\w\-]+/\d{4}-[A-Za-z]+/[A-Za-z0-9]+\.html)|(mail\.python\.org/archives/list/[\w\-]+@python\.org/thread/[A-Za-z0-9]+/?))$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-status name: "'Status' must be a valid PEP status" language: pygrep entry: '^Status:(?:(?! +(Draft|Withdrawn|Rejected|Accepted|Final|Active|Provisional|Deferred|Superseded|April Fool!)$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-type name: "'Type' must be a valid PEP type" language: pygrep entry: '^Type:(?:(?! +(Standards Track|Informational|Process)$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-topic name: "'Topic' must be for a valid sub-index" language: pygrep entry: '^Topic:(?:(?! +(Governance|Packaging|Typing|Release)(, (Governance|Packaging|Typing|Release))*$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-content-type name: "'Content-Type' must be 'text/x-rst'" language: pygrep entry: '^Content-Type:(?:(?! +text/x-rst$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-pep-references name: "`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs" language: pygrep entry: '^(Requires|Replaces|Superseded-By):(?:(?! *( (0|[1-9][0-9]{0,3})(,|$))+$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-created name: "'Created' must be a 'DD-mmm-YYYY' date" language: pygrep entry: '^Created:(?:(?! +([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-python-version name: "'Python-Version' must be a 'X.Y[.Z]` version" language: pygrep entry: '^Python-Version:(?:(?! *( [1-9]\.([0-9][0-9]?|x)(\.[1-9][0-9]?)?(,|$))+$))' - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-post-history name: "'Post-History' must be '`DD-mmm-YYYY <Thread URL>`__, ...'" language: pygrep entry: '(?<=\n)Post-History:(?:(?! ?\n|((( +|\n {1,14})(([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])|`([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9]) <https://((discuss\.python\.org/t/([\w\-]+/)?\d+(?:/\d+/|/?))|(mail\.python\.org/pipermail/[\w\-]+/\d{4}-[A-Za-z]+/[A-Za-z0-9]+\.html)|(mail\.python\.org/archives/list/[\w\-]+@python\.org/thread/[A-Za-z0-9]+/?(#[A-Za-z0-9]+)?))>`__)(,|(?=\n[^ ])))+\n(?=[A-Z\n]))))' args: [--multiline] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: validate-resolution name: "'Resolution' must be a direct thread/message URL" language: pygrep entry: '(?<!\n\n)(?<=\n)Resolution: (?:(?!https://((discuss\.python\.org/t/([\w\-]+/)?\d+(/\d+)?/?)|(mail\.python\.org/pipermail/[\w\-]+/\d{4}-[A-Za-z]+/[A-Za-z0-9]+\.html)|(mail\.python\.org/archives/list/[\w\-]+@python\.org/(message|thread)/[A-Za-z0-9]+/?(#[A-Za-z0-9]+)?))\n))' args: ['--multiline'] - files: '^pep-\d+\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' - id: check-direct-pep-links name: "Check that PEPs aren't linked directly" language: pygrep entry: '(dev/peps|peps\.python\.org)/pep-\d+' - files: '^pep-\d+\.(rst|txt)$' - exclude: '^pep-(0009|0287|0676|0684|8001)\.(rst|txt)$' - types: [text] + files: '^peps/pep-\d+\.rst$' + exclude: '^peps/pep-(0009|0287|0676|0684|8001)\.rst$' - id: check-direct-rfc-links name: "Check that RFCs aren't linked directly" language: pygrep entry: '(rfc-editor\.org|ietf\.org)/[\.\-_\?\&\#\w/]*[Rr][Ff][Cc][\-_]?\d+' - files: '\.(rst|txt)$' - types: [text] + types: ['rst'] diff --git a/Makefile b/Makefile index dcbf43a19..8f973be2c 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ OUTPUT_DIR = build SPHINXERRORHANDLING = -W --keep-going -w sphinx-warnings.txt ALLSPHINXOPTS = -b $(BUILDER) -j $(JOBS) \ - $(SPHINXOPTS) $(SPHINXERRORHANDLING) . $(OUTPUT_DIR) $(SOURCES) + $(SPHINXOPTS) $(SPHINXERRORHANDLING) peps $(OUTPUT_DIR) $(SOURCES) ## html to render PEPs to "pep-NNNN.html" files .PHONY: html diff --git a/build.py b/build.py index ebc3cf4aa..04f0b5fdb 100755 --- a/build.py +++ b/build.py @@ -54,7 +54,7 @@ if __name__ == "__main__": args = create_parser() root_directory = Path(__file__).resolve().parent - source_directory = root_directory + source_directory = root_directory / "peps" build_directory = root_directory / args.output_dir # builder configuration diff --git a/check-peps.py b/check-peps.py index 623bdc040..ea45cd161 100755 --- a/check-peps.py +++ b/check-peps.py @@ -16,7 +16,6 @@ Use "--detailed" to show the contents of lines where errors were found. from __future__ import annotations import datetime as dt -import itertools import re import sys from pathlib import Path @@ -32,7 +31,8 @@ if TYPE_CHECKING: # get the directory with the PEP sources -PEP_ROOT = Path(__file__).resolve().parent +ROOT_DIR = Path(__file__).resolve().parent +PEP_ROOT = ROOT_DIR / "peps" # See PEP 12 for the order # Note we retain "BDFL-Delegate" @@ -101,7 +101,7 @@ def check(filenames: Sequence[str] = (), /) -> int: if filenames: filenames = map(Path, filenames) else: - filenames = itertools.chain(PEP_ROOT.glob("pep-????.txt"), PEP_ROOT.glob("pep-????.rst")) + filenames = PEP_ROOT.glob("pep-????.rst") if (count := sum(map(check_file, filenames))) > 0: s = "s" * (count != 1) print(f"check-peps failed: {count} error{s}", file=sys.stderr) @@ -207,7 +207,7 @@ def check_direct_links(line_num: int, line: str) -> MessageIterator: def _output_error(filename: Path, lines: Sequence[str], errors: Iterable[Message]) -> int: - relative_filename = filename.relative_to(PEP_ROOT) + relative_filename = filename.relative_to(ROOT_DIR) err_count = 0 for line_num, msg in errors: err_count += 1 diff --git a/docs/rendering_system.rst b/docs/rendering_system.rst index 83c077e7a..fc20d00df 100644 --- a/docs/rendering_system.rst +++ b/docs/rendering_system.rst @@ -17,14 +17,14 @@ to `PEP 676 <https://peps.python.org/pep-0676/>`__. Configuration is stored in three files: -- ``conf.py`` contains the majority of the Sphinx configuration -- ``contents.rst`` contains the compulsory table of contents directive +- ``peps/conf.py`` contains the majority of the Sphinx configuration +- ``peps/contents.rst`` contains the compulsory table of contents directive - ``pep_sphinx_extensions/pep_theme/theme.conf`` sets the Pygments themes The configuration: - registers the custom Sphinx extension -- sets both ``.txt`` and ``.rst`` suffixes to be parsed as PEPs +- sets the ``.rst`` suffix to be parsed as PEPs - tells Sphinx which source files to use - registers the PEP theme, maths renderer, and template - disables some default settings that are covered in the extension @@ -35,7 +35,7 @@ The configuration: ---------------- ``build.py`` manages the rendering process. -Usage is covered in :doc:`build`. +Usage is covered in `Building PEPs Locally <./build.rst>`_. 3. Extension diff --git a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py index a73bd2e9e..7349f712f 100644 --- a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py +++ b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py @@ -1,5 +1,3 @@ -from pathlib import Path - from docutils import nodes from docutils.frontend import OptionParser from sphinx.builders.html import StandaloneHTMLBuilder @@ -31,10 +29,6 @@ class FileBuilder(StandaloneHTMLBuilder): except KeyError: title = "" - # source filename - file_is_rst = Path(self.env.srcdir, docname + ".rst").exists() - source_name = f"{docname}.rst" if file_is_rst else f"{docname}.txt" - # local table of contents toc_tree = self.env.tocs[docname].deepcopy() if len(toc_tree) and len(toc_tree[0]) > 1: @@ -46,7 +40,7 @@ class FileBuilder(StandaloneHTMLBuilder): else: toc = "" # PEPs with no sections -- 9, 210 - return {"title": title, "sourcename": source_name, "toc": toc, "body": body} + return {"title": title, "toc": toc, "body": body} class DirectoryBuilder(FileBuilder): diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py index efd94ca36..c49355fd1 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py @@ -54,7 +54,7 @@ class PEPFooter(transforms.Transform): def _add_source_link(pep_source_path: Path) -> nodes.paragraph: """Add link to source text on VCS (GitHub)""" - source_link = f"https://github.com/python/peps/blob/main/{pep_source_path.name}" + source_link = f"https://github.com/python/peps/blob/main/peps/{pep_source_path.name}" link_node = nodes.reference("", source_link, refuri=source_link) return nodes.paragraph("", "Source: ", link_node) @@ -79,9 +79,12 @@ def _get_last_modified_timestamps(): return {} all_modified = ret.stdout + # remove "peps/" prefix from file names + all_modified = all_modified.replace("\npeps/", "\n") + # set up the dictionary with the *current* files - peps_dir = Path(__file__, "..", "..", "..", "..").resolve() - last_modified = {path.stem: "" for path in peps_dir.glob("pep-????.???") if path.suffix in {".txt", ".rst"}} + peps_dir = Path(__file__, "..", "..", "..", "..", "peps").resolve() + last_modified = {path.stem: "" for path in peps_dir.glob("pep-????.rst")} # iterate through newest to oldest, updating per file timestamps change_sets = all_modified.removeprefix("#").split("#") diff --git a/pep_sphinx_extensions/pep_theme/templates/page.html b/pep_sphinx_extensions/pep_theme/templates/page.html index 8bd879c0f..46be8c5bb 100644 --- a/pep_sphinx_extensions/pep_theme/templates/page.html +++ b/pep_sphinx_extensions/pep_theme/templates/page.html @@ -43,8 +43,8 @@ <h2>Contents</h2> {{ toc }} <br> - {%- if not sourcename.startswith(("pep-0000", "topic")) %} - <a id="source" href="https://github.com/python/peps/blob/main/{{sourcename}}">Page Source (GitHub)</a> + {%- if not pagename.startswith(("pep-0000", "topic")) %} + <a id="source" href="https://github.com/python/peps/blob/main/peps/{{pagename}}.rst">Page Source (GitHub)</a> {%- endif %} </nav> </section> diff --git a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py index 0804b4aa6..8fbf5cc7e 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -41,7 +41,7 @@ def _parse_peps(path: Path) -> list[parser.PEP]: continue # Skip directories etc. if file_path.match("pep-0000*"): continue # Skip pre-existing PEP 0 files - if file_path.match("pep-????.???") and file_path.suffix in {".txt", ".rst"}: + if file_path.match("pep-????.rst"): pep = parser.PEP(path.joinpath(file_path).absolute()) peps.append(pep) diff --git a/pep_sphinx_extensions/tests/conftest.py b/pep_sphinx_extensions/tests/conftest.py index 2c207ebcd..15f3c907b 100644 --- a/pep_sphinx_extensions/tests/conftest.py +++ b/pep_sphinx_extensions/tests/conftest.py @@ -3,7 +3,7 @@ import sys from pathlib import Path _ROOT_PATH = Path(__file__, "..", "..", "..").resolve() -PEP_ROOT = _ROOT_PATH +PEP_ROOT = _ROOT_PATH / "peps" # Import "check-peps.py" as "check_peps" CHECK_PEPS_PATH = _ROOT_PATH / "check-peps.py" diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py index 6bd0cdca9..9f040c5e1 100644 --- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py +++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py @@ -6,17 +6,17 @@ from ...conftest import PEP_ROOT def test_add_source_link(): - out = pep_footer._add_source_link(PEP_ROOT / "pep-0008.txt") + out = pep_footer._add_source_link(PEP_ROOT / "pep-0008.rst") - assert "https://github.com/python/peps/blob/main/pep-0008.txt" in str(out) + assert "https://github.com/python/peps/blob/main/peps/pep-0008.rst" in str(out) def test_add_commit_history_info(): - out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-0008.txt") + out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-0008.rst") assert str(out).startswith( "<paragraph>Last modified: " - '<reference refuri="https://github.com/python/peps/commits/main/pep-0008.txt">' + '<reference refuri="https://github.com/python/peps/commits/main/pep-0008.rst">' ) # A variable timestamp comes next, don't test that assert str(out).endswith("</reference></paragraph>") diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index 0a1a108e1..daeb77c70 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -21,27 +21,27 @@ from ..conftest import PEP_ROOT def test_pep_repr(): - pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst") assert repr(pep8) == "<PEP 0008 - Style Guide for Python Code>" def test_pep_less_than(): - pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") - pep3333 = parser.PEP(PEP_ROOT / "pep-3333.txt") + pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst") + pep3333 = parser.PEP(PEP_ROOT / "pep-3333.rst") assert pep8 < pep3333 def test_pep_equal(): - pep_a = parser.PEP(PEP_ROOT / "pep-0008.txt") - pep_b = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep_a = parser.PEP(PEP_ROOT / "pep-0008.rst") + pep_b = parser.PEP(PEP_ROOT / "pep-0008.rst") assert pep_a == pep_b def test_pep_details(monkeypatch): - pep8 = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst") assert pep8.details == { "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", @@ -106,7 +106,7 @@ def test_parse_authors_invalid(): ) def test_abbreviate_type_status(test_type, test_status, expected): # set up dummy PEP object and monkeypatch attributes - pep = parser.PEP(PEP_ROOT / "pep-0008.txt") + pep = parser.PEP(PEP_ROOT / "pep-0008.rst") pep.pep_type = test_type pep.status = test_status diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py index e920d9773..75c16f624 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py @@ -4,7 +4,7 @@ from ..conftest import PEP_ROOT def test_create_pep_json(): - peps = [parser.PEP(PEP_ROOT / "pep-0008.txt")] + peps = [parser.PEP(PEP_ROOT / "pep-0008.rst")] out = pep_index_generator.create_pep_json(peps) diff --git a/conf.py b/peps/conf.py similarity index 96% rename from conf.py rename to peps/conf.py index b795aa874..09b9b3ed3 100644 --- a/conf.py +++ b/peps/conf.py @@ -7,7 +7,7 @@ import os from pathlib import Path import sys -_ROOT = Path(__file__).resolve().parent +_ROOT = Path(__file__).resolve().parent.parent sys.path.append(os.fspath(_ROOT)) # -- Project information ----------------------------------------------------- @@ -27,7 +27,6 @@ extensions = [ # The file extensions of source files. Sphinx uses these suffixes as sources. source_suffix = { ".rst": "pep", - ".txt": "pep", } # List of patterns (relative to source dir) to ignore when looking for source files. @@ -36,7 +35,6 @@ include_patterns = [ "contents.rst", # PEP files "pep-????.rst", - "pep-????.txt", # PEP ancillary files "pep-????/*.rst", # Documentation diff --git a/contents.rst b/peps/contents.rst similarity index 97% rename from contents.rst rename to peps/contents.rst index 3aa0d788d..d791f08f8 100644 --- a/contents.rst +++ b/peps/contents.rst @@ -14,6 +14,5 @@ This is an internal Sphinx page; please go to the :doc:`PEP Index <pep-0000>`. :glob: :caption: PEP Table of Contents (needed for Sphinx): - docs/* pep-* topic/* diff --git a/pep-0001.txt b/peps/pep-0001.rst similarity index 100% rename from pep-0001.txt rename to peps/pep-0001.rst diff --git a/pep-0001/process_flow.svg b/peps/pep-0001/process_flow.svg similarity index 100% rename from pep-0001/process_flow.svg rename to peps/pep-0001/process_flow.svg diff --git a/pep-0002.txt b/peps/pep-0002.rst similarity index 100% rename from pep-0002.txt rename to peps/pep-0002.rst diff --git a/pep-0003.txt b/peps/pep-0003.rst similarity index 100% rename from pep-0003.txt rename to peps/pep-0003.rst diff --git a/pep-0004.txt b/peps/pep-0004.rst similarity index 100% rename from pep-0004.txt rename to peps/pep-0004.rst diff --git a/pep-0005.txt b/peps/pep-0005.rst similarity index 100% rename from pep-0005.txt rename to peps/pep-0005.rst diff --git a/pep-0006.txt b/peps/pep-0006.rst similarity index 100% rename from pep-0006.txt rename to peps/pep-0006.rst diff --git a/pep-0007.txt b/peps/pep-0007.rst similarity index 100% rename from pep-0007.txt rename to peps/pep-0007.rst diff --git a/pep-0008.txt b/peps/pep-0008.rst similarity index 100% rename from pep-0008.txt rename to peps/pep-0008.rst diff --git a/pep-0009.txt b/peps/pep-0009.rst similarity index 100% rename from pep-0009.txt rename to peps/pep-0009.rst diff --git a/pep-0010.txt b/peps/pep-0010.rst similarity index 100% rename from pep-0010.txt rename to peps/pep-0010.rst diff --git a/pep-0011.txt b/peps/pep-0011.rst similarity index 100% rename from pep-0011.txt rename to peps/pep-0011.rst diff --git a/pep-0012.rst b/peps/pep-0012.rst similarity index 100% rename from pep-0012.rst rename to peps/pep-0012.rst diff --git a/pep-0012/pep-NNNN.rst b/peps/pep-0012/pep-NNNN.rst similarity index 100% rename from pep-0012/pep-NNNN.rst rename to peps/pep-0012/pep-NNNN.rst diff --git a/pep-0013.rst b/peps/pep-0013.rst similarity index 100% rename from pep-0013.rst rename to peps/pep-0013.rst diff --git a/pep-0020.txt b/peps/pep-0020.rst similarity index 100% rename from pep-0020.txt rename to peps/pep-0020.rst diff --git a/pep-0042.txt b/peps/pep-0042.rst similarity index 100% rename from pep-0042.txt rename to peps/pep-0042.rst diff --git a/pep-0100.txt b/peps/pep-0100.rst similarity index 100% rename from pep-0100.txt rename to peps/pep-0100.rst diff --git a/pep-0101.txt b/peps/pep-0101.rst similarity index 100% rename from pep-0101.txt rename to peps/pep-0101.rst diff --git a/pep-0102.txt b/peps/pep-0102.rst similarity index 100% rename from pep-0102.txt rename to peps/pep-0102.rst diff --git a/pep-0103.txt b/peps/pep-0103.rst similarity index 100% rename from pep-0103.txt rename to peps/pep-0103.rst diff --git a/pep-0160.txt b/peps/pep-0160.rst similarity index 100% rename from pep-0160.txt rename to peps/pep-0160.rst diff --git a/pep-0200.txt b/peps/pep-0200.rst similarity index 100% rename from pep-0200.txt rename to peps/pep-0200.rst diff --git a/pep-0201.txt b/peps/pep-0201.rst similarity index 100% rename from pep-0201.txt rename to peps/pep-0201.rst diff --git a/pep-0202.txt b/peps/pep-0202.rst similarity index 100% rename from pep-0202.txt rename to peps/pep-0202.rst diff --git a/pep-0203.txt b/peps/pep-0203.rst similarity index 100% rename from pep-0203.txt rename to peps/pep-0203.rst diff --git a/pep-0204.txt b/peps/pep-0204.rst similarity index 100% rename from pep-0204.txt rename to peps/pep-0204.rst diff --git a/pep-0205.txt b/peps/pep-0205.rst similarity index 100% rename from pep-0205.txt rename to peps/pep-0205.rst diff --git a/pep-0206.txt b/peps/pep-0206.rst similarity index 100% rename from pep-0206.txt rename to peps/pep-0206.rst diff --git a/pep-0207.txt b/peps/pep-0207.rst similarity index 100% rename from pep-0207.txt rename to peps/pep-0207.rst diff --git a/pep-0208.txt b/peps/pep-0208.rst similarity index 100% rename from pep-0208.txt rename to peps/pep-0208.rst diff --git a/pep-0209.txt b/peps/pep-0209.rst similarity index 100% rename from pep-0209.txt rename to peps/pep-0209.rst diff --git a/pep-0210.txt b/peps/pep-0210.rst similarity index 100% rename from pep-0210.txt rename to peps/pep-0210.rst diff --git a/pep-0211.txt b/peps/pep-0211.rst similarity index 100% rename from pep-0211.txt rename to peps/pep-0211.rst diff --git a/pep-0212.txt b/peps/pep-0212.rst similarity index 100% rename from pep-0212.txt rename to peps/pep-0212.rst diff --git a/pep-0213.txt b/peps/pep-0213.rst similarity index 100% rename from pep-0213.txt rename to peps/pep-0213.rst diff --git a/pep-0214.txt b/peps/pep-0214.rst similarity index 100% rename from pep-0214.txt rename to peps/pep-0214.rst diff --git a/pep-0215.txt b/peps/pep-0215.rst similarity index 100% rename from pep-0215.txt rename to peps/pep-0215.rst diff --git a/pep-0216.txt b/peps/pep-0216.rst similarity index 100% rename from pep-0216.txt rename to peps/pep-0216.rst diff --git a/pep-0217.txt b/peps/pep-0217.rst similarity index 100% rename from pep-0217.txt rename to peps/pep-0217.rst diff --git a/pep-0218.txt b/peps/pep-0218.rst similarity index 100% rename from pep-0218.txt rename to peps/pep-0218.rst diff --git a/pep-0219.txt b/peps/pep-0219.rst similarity index 100% rename from pep-0219.txt rename to peps/pep-0219.rst diff --git a/pep-0220.txt b/peps/pep-0220.rst similarity index 100% rename from pep-0220.txt rename to peps/pep-0220.rst diff --git a/pep-0221.txt b/peps/pep-0221.rst similarity index 100% rename from pep-0221.txt rename to peps/pep-0221.rst diff --git a/pep-0222.txt b/peps/pep-0222.rst similarity index 100% rename from pep-0222.txt rename to peps/pep-0222.rst diff --git a/pep-0223.txt b/peps/pep-0223.rst similarity index 100% rename from pep-0223.txt rename to peps/pep-0223.rst diff --git a/pep-0224.txt b/peps/pep-0224.rst similarity index 100% rename from pep-0224.txt rename to peps/pep-0224.rst diff --git a/pep-0225.txt b/peps/pep-0225.rst similarity index 100% rename from pep-0225.txt rename to peps/pep-0225.rst diff --git a/pep-0226.txt b/peps/pep-0226.rst similarity index 100% rename from pep-0226.txt rename to peps/pep-0226.rst diff --git a/pep-0227.txt b/peps/pep-0227.rst similarity index 100% rename from pep-0227.txt rename to peps/pep-0227.rst diff --git a/pep-0228.txt b/peps/pep-0228.rst similarity index 100% rename from pep-0228.txt rename to peps/pep-0228.rst diff --git a/pep-0229.txt b/peps/pep-0229.rst similarity index 100% rename from pep-0229.txt rename to peps/pep-0229.rst diff --git a/pep-0230.txt b/peps/pep-0230.rst similarity index 100% rename from pep-0230.txt rename to peps/pep-0230.rst diff --git a/pep-0231.txt b/peps/pep-0231.rst similarity index 100% rename from pep-0231.txt rename to peps/pep-0231.rst diff --git a/pep-0232.txt b/peps/pep-0232.rst similarity index 100% rename from pep-0232.txt rename to peps/pep-0232.rst diff --git a/pep-0233.txt b/peps/pep-0233.rst similarity index 100% rename from pep-0233.txt rename to peps/pep-0233.rst diff --git a/pep-0234.txt b/peps/pep-0234.rst similarity index 100% rename from pep-0234.txt rename to peps/pep-0234.rst diff --git a/pep-0235.txt b/peps/pep-0235.rst similarity index 100% rename from pep-0235.txt rename to peps/pep-0235.rst diff --git a/pep-0236.txt b/peps/pep-0236.rst similarity index 100% rename from pep-0236.txt rename to peps/pep-0236.rst diff --git a/pep-0237.txt b/peps/pep-0237.rst similarity index 100% rename from pep-0237.txt rename to peps/pep-0237.rst diff --git a/pep-0238.txt b/peps/pep-0238.rst similarity index 100% rename from pep-0238.txt rename to peps/pep-0238.rst diff --git a/pep-0239.txt b/peps/pep-0239.rst similarity index 100% rename from pep-0239.txt rename to peps/pep-0239.rst diff --git a/pep-0240.txt b/peps/pep-0240.rst similarity index 100% rename from pep-0240.txt rename to peps/pep-0240.rst diff --git a/pep-0241.txt b/peps/pep-0241.rst similarity index 100% rename from pep-0241.txt rename to peps/pep-0241.rst diff --git a/pep-0242.txt b/peps/pep-0242.rst similarity index 100% rename from pep-0242.txt rename to peps/pep-0242.rst diff --git a/pep-0243.txt b/peps/pep-0243.rst similarity index 100% rename from pep-0243.txt rename to peps/pep-0243.rst diff --git a/pep-0244.txt b/peps/pep-0244.rst similarity index 100% rename from pep-0244.txt rename to peps/pep-0244.rst diff --git a/pep-0245.txt b/peps/pep-0245.rst similarity index 100% rename from pep-0245.txt rename to peps/pep-0245.rst diff --git a/pep-0246.txt b/peps/pep-0246.rst similarity index 100% rename from pep-0246.txt rename to peps/pep-0246.rst diff --git a/pep-0247.txt b/peps/pep-0247.rst similarity index 100% rename from pep-0247.txt rename to peps/pep-0247.rst diff --git a/pep-0248.txt b/peps/pep-0248.rst similarity index 100% rename from pep-0248.txt rename to peps/pep-0248.rst diff --git a/pep-0249.txt b/peps/pep-0249.rst similarity index 100% rename from pep-0249.txt rename to peps/pep-0249.rst diff --git a/pep-0250.txt b/peps/pep-0250.rst similarity index 100% rename from pep-0250.txt rename to peps/pep-0250.rst diff --git a/pep-0251.txt b/peps/pep-0251.rst similarity index 100% rename from pep-0251.txt rename to peps/pep-0251.rst diff --git a/pep-0252.txt b/peps/pep-0252.rst similarity index 100% rename from pep-0252.txt rename to peps/pep-0252.rst diff --git a/pep-0253.txt b/peps/pep-0253.rst similarity index 100% rename from pep-0253.txt rename to peps/pep-0253.rst diff --git a/pep-0254.txt b/peps/pep-0254.rst similarity index 100% rename from pep-0254.txt rename to peps/pep-0254.rst diff --git a/pep-0255.txt b/peps/pep-0255.rst similarity index 100% rename from pep-0255.txt rename to peps/pep-0255.rst diff --git a/pep-0256.txt b/peps/pep-0256.rst similarity index 100% rename from pep-0256.txt rename to peps/pep-0256.rst diff --git a/pep-0257.txt b/peps/pep-0257.rst similarity index 100% rename from pep-0257.txt rename to peps/pep-0257.rst diff --git a/pep-0258.txt b/peps/pep-0258.rst similarity index 100% rename from pep-0258.txt rename to peps/pep-0258.rst diff --git a/pep-0259.txt b/peps/pep-0259.rst similarity index 100% rename from pep-0259.txt rename to peps/pep-0259.rst diff --git a/pep-0260.txt b/peps/pep-0260.rst similarity index 100% rename from pep-0260.txt rename to peps/pep-0260.rst diff --git a/pep-0261.txt b/peps/pep-0261.rst similarity index 100% rename from pep-0261.txt rename to peps/pep-0261.rst diff --git a/pep-0262.txt b/peps/pep-0262.rst similarity index 100% rename from pep-0262.txt rename to peps/pep-0262.rst diff --git a/pep-0263.txt b/peps/pep-0263.rst similarity index 100% rename from pep-0263.txt rename to peps/pep-0263.rst diff --git a/pep-0264.txt b/peps/pep-0264.rst similarity index 100% rename from pep-0264.txt rename to peps/pep-0264.rst diff --git a/pep-0265.txt b/peps/pep-0265.rst similarity index 100% rename from pep-0265.txt rename to peps/pep-0265.rst diff --git a/pep-0266.txt b/peps/pep-0266.rst similarity index 100% rename from pep-0266.txt rename to peps/pep-0266.rst diff --git a/pep-0267.txt b/peps/pep-0267.rst similarity index 100% rename from pep-0267.txt rename to peps/pep-0267.rst diff --git a/pep-0268.txt b/peps/pep-0268.rst similarity index 100% rename from pep-0268.txt rename to peps/pep-0268.rst diff --git a/pep-0269.txt b/peps/pep-0269.rst similarity index 100% rename from pep-0269.txt rename to peps/pep-0269.rst diff --git a/pep-0270.txt b/peps/pep-0270.rst similarity index 100% rename from pep-0270.txt rename to peps/pep-0270.rst diff --git a/pep-0271.txt b/peps/pep-0271.rst similarity index 100% rename from pep-0271.txt rename to peps/pep-0271.rst diff --git a/pep-0272.txt b/peps/pep-0272.rst similarity index 100% rename from pep-0272.txt rename to peps/pep-0272.rst diff --git a/pep-0273.txt b/peps/pep-0273.rst similarity index 100% rename from pep-0273.txt rename to peps/pep-0273.rst diff --git a/pep-0274.txt b/peps/pep-0274.rst similarity index 100% rename from pep-0274.txt rename to peps/pep-0274.rst diff --git a/pep-0275.txt b/peps/pep-0275.rst similarity index 100% rename from pep-0275.txt rename to peps/pep-0275.rst diff --git a/pep-0276.txt b/peps/pep-0276.rst similarity index 100% rename from pep-0276.txt rename to peps/pep-0276.rst diff --git a/pep-0277.txt b/peps/pep-0277.rst similarity index 100% rename from pep-0277.txt rename to peps/pep-0277.rst diff --git a/pep-0278.txt b/peps/pep-0278.rst similarity index 100% rename from pep-0278.txt rename to peps/pep-0278.rst diff --git a/pep-0279.txt b/peps/pep-0279.rst similarity index 100% rename from pep-0279.txt rename to peps/pep-0279.rst diff --git a/pep-0280.txt b/peps/pep-0280.rst similarity index 100% rename from pep-0280.txt rename to peps/pep-0280.rst diff --git a/pep-0281.txt b/peps/pep-0281.rst similarity index 100% rename from pep-0281.txt rename to peps/pep-0281.rst diff --git a/pep-0282.txt b/peps/pep-0282.rst similarity index 100% rename from pep-0282.txt rename to peps/pep-0282.rst diff --git a/pep-0283.txt b/peps/pep-0283.rst similarity index 100% rename from pep-0283.txt rename to peps/pep-0283.rst diff --git a/pep-0284.txt b/peps/pep-0284.rst similarity index 100% rename from pep-0284.txt rename to peps/pep-0284.rst diff --git a/pep-0285.txt b/peps/pep-0285.rst similarity index 100% rename from pep-0285.txt rename to peps/pep-0285.rst diff --git a/pep-0286.txt b/peps/pep-0286.rst similarity index 100% rename from pep-0286.txt rename to peps/pep-0286.rst diff --git a/pep-0287.txt b/peps/pep-0287.rst similarity index 100% rename from pep-0287.txt rename to peps/pep-0287.rst diff --git a/pep-0288.txt b/peps/pep-0288.rst similarity index 100% rename from pep-0288.txt rename to peps/pep-0288.rst diff --git a/pep-0289.txt b/peps/pep-0289.rst similarity index 100% rename from pep-0289.txt rename to peps/pep-0289.rst diff --git a/pep-0290.txt b/peps/pep-0290.rst similarity index 100% rename from pep-0290.txt rename to peps/pep-0290.rst diff --git a/pep-0291.txt b/peps/pep-0291.rst similarity index 100% rename from pep-0291.txt rename to peps/pep-0291.rst diff --git a/pep-0292.txt b/peps/pep-0292.rst similarity index 100% rename from pep-0292.txt rename to peps/pep-0292.rst diff --git a/pep-0293.txt b/peps/pep-0293.rst similarity index 100% rename from pep-0293.txt rename to peps/pep-0293.rst diff --git a/pep-0294.txt b/peps/pep-0294.rst similarity index 100% rename from pep-0294.txt rename to peps/pep-0294.rst diff --git a/pep-0295.txt b/peps/pep-0295.rst similarity index 100% rename from pep-0295.txt rename to peps/pep-0295.rst diff --git a/pep-0296.txt b/peps/pep-0296.rst similarity index 100% rename from pep-0296.txt rename to peps/pep-0296.rst diff --git a/pep-0297.txt b/peps/pep-0297.rst similarity index 100% rename from pep-0297.txt rename to peps/pep-0297.rst diff --git a/pep-0298.txt b/peps/pep-0298.rst similarity index 100% rename from pep-0298.txt rename to peps/pep-0298.rst diff --git a/pep-0299.txt b/peps/pep-0299.rst similarity index 100% rename from pep-0299.txt rename to peps/pep-0299.rst diff --git a/pep-0301.txt b/peps/pep-0301.rst similarity index 100% rename from pep-0301.txt rename to peps/pep-0301.rst diff --git a/pep-0302.txt b/peps/pep-0302.rst similarity index 100% rename from pep-0302.txt rename to peps/pep-0302.rst diff --git a/pep-0303.txt b/peps/pep-0303.rst similarity index 100% rename from pep-0303.txt rename to peps/pep-0303.rst diff --git a/pep-0304.txt b/peps/pep-0304.rst similarity index 100% rename from pep-0304.txt rename to peps/pep-0304.rst diff --git a/pep-0305.txt b/peps/pep-0305.rst similarity index 100% rename from pep-0305.txt rename to peps/pep-0305.rst diff --git a/pep-0306.txt b/peps/pep-0306.rst similarity index 100% rename from pep-0306.txt rename to peps/pep-0306.rst diff --git a/pep-0307.txt b/peps/pep-0307.rst similarity index 100% rename from pep-0307.txt rename to peps/pep-0307.rst diff --git a/pep-0308.txt b/peps/pep-0308.rst similarity index 100% rename from pep-0308.txt rename to peps/pep-0308.rst diff --git a/pep-0309.txt b/peps/pep-0309.rst similarity index 100% rename from pep-0309.txt rename to peps/pep-0309.rst diff --git a/pep-0310.txt b/peps/pep-0310.rst similarity index 100% rename from pep-0310.txt rename to peps/pep-0310.rst diff --git a/pep-0311.txt b/peps/pep-0311.rst similarity index 100% rename from pep-0311.txt rename to peps/pep-0311.rst diff --git a/pep-0312.txt b/peps/pep-0312.rst similarity index 100% rename from pep-0312.txt rename to peps/pep-0312.rst diff --git a/pep-0313.txt b/peps/pep-0313.rst similarity index 100% rename from pep-0313.txt rename to peps/pep-0313.rst diff --git a/pep-0314.txt b/peps/pep-0314.rst similarity index 100% rename from pep-0314.txt rename to peps/pep-0314.rst diff --git a/pep-0315.txt b/peps/pep-0315.rst similarity index 100% rename from pep-0315.txt rename to peps/pep-0315.rst diff --git a/pep-0316.txt b/peps/pep-0316.rst similarity index 100% rename from pep-0316.txt rename to peps/pep-0316.rst diff --git a/pep-0317.txt b/peps/pep-0317.rst similarity index 100% rename from pep-0317.txt rename to peps/pep-0317.rst diff --git a/pep-0318.txt b/peps/pep-0318.rst similarity index 100% rename from pep-0318.txt rename to peps/pep-0318.rst diff --git a/pep-0319.txt b/peps/pep-0319.rst similarity index 100% rename from pep-0319.txt rename to peps/pep-0319.rst diff --git a/pep-0320.txt b/peps/pep-0320.rst similarity index 100% rename from pep-0320.txt rename to peps/pep-0320.rst diff --git a/pep-0321.txt b/peps/pep-0321.rst similarity index 100% rename from pep-0321.txt rename to peps/pep-0321.rst diff --git a/pep-0322.txt b/peps/pep-0322.rst similarity index 100% rename from pep-0322.txt rename to peps/pep-0322.rst diff --git a/pep-0323.txt b/peps/pep-0323.rst similarity index 100% rename from pep-0323.txt rename to peps/pep-0323.rst diff --git a/pep-0324.txt b/peps/pep-0324.rst similarity index 100% rename from pep-0324.txt rename to peps/pep-0324.rst diff --git a/pep-0325.txt b/peps/pep-0325.rst similarity index 100% rename from pep-0325.txt rename to peps/pep-0325.rst diff --git a/pep-0326.txt b/peps/pep-0326.rst similarity index 100% rename from pep-0326.txt rename to peps/pep-0326.rst diff --git a/pep-0327.txt b/peps/pep-0327.rst similarity index 100% rename from pep-0327.txt rename to peps/pep-0327.rst diff --git a/pep-0328.txt b/peps/pep-0328.rst similarity index 100% rename from pep-0328.txt rename to peps/pep-0328.rst diff --git a/pep-0329.txt b/peps/pep-0329.rst similarity index 100% rename from pep-0329.txt rename to peps/pep-0329.rst diff --git a/pep-0330.txt b/peps/pep-0330.rst similarity index 100% rename from pep-0330.txt rename to peps/pep-0330.rst diff --git a/pep-0331.txt b/peps/pep-0331.rst similarity index 100% rename from pep-0331.txt rename to peps/pep-0331.rst diff --git a/pep-0332.txt b/peps/pep-0332.rst similarity index 100% rename from pep-0332.txt rename to peps/pep-0332.rst diff --git a/pep-0333.txt b/peps/pep-0333.rst similarity index 100% rename from pep-0333.txt rename to peps/pep-0333.rst diff --git a/pep-0334.txt b/peps/pep-0334.rst similarity index 100% rename from pep-0334.txt rename to peps/pep-0334.rst diff --git a/pep-0335.txt b/peps/pep-0335.rst similarity index 100% rename from pep-0335.txt rename to peps/pep-0335.rst diff --git a/pep-0336.txt b/peps/pep-0336.rst similarity index 100% rename from pep-0336.txt rename to peps/pep-0336.rst diff --git a/pep-0337.txt b/peps/pep-0337.rst similarity index 100% rename from pep-0337.txt rename to peps/pep-0337.rst diff --git a/pep-0338.txt b/peps/pep-0338.rst similarity index 100% rename from pep-0338.txt rename to peps/pep-0338.rst diff --git a/pep-0339.txt b/peps/pep-0339.rst similarity index 100% rename from pep-0339.txt rename to peps/pep-0339.rst diff --git a/pep-0340.txt b/peps/pep-0340.rst similarity index 100% rename from pep-0340.txt rename to peps/pep-0340.rst diff --git a/pep-0341.txt b/peps/pep-0341.rst similarity index 100% rename from pep-0341.txt rename to peps/pep-0341.rst diff --git a/pep-0342.txt b/peps/pep-0342.rst similarity index 100% rename from pep-0342.txt rename to peps/pep-0342.rst diff --git a/pep-0343.txt b/peps/pep-0343.rst similarity index 100% rename from pep-0343.txt rename to peps/pep-0343.rst diff --git a/pep-0344.txt b/peps/pep-0344.rst similarity index 100% rename from pep-0344.txt rename to peps/pep-0344.rst diff --git a/pep-0345.txt b/peps/pep-0345.rst similarity index 100% rename from pep-0345.txt rename to peps/pep-0345.rst diff --git a/pep-0346.txt b/peps/pep-0346.rst similarity index 100% rename from pep-0346.txt rename to peps/pep-0346.rst diff --git a/pep-0347.txt b/peps/pep-0347.rst similarity index 100% rename from pep-0347.txt rename to peps/pep-0347.rst diff --git a/pep-0348.txt b/peps/pep-0348.rst similarity index 100% rename from pep-0348.txt rename to peps/pep-0348.rst diff --git a/pep-0349.txt b/peps/pep-0349.rst similarity index 100% rename from pep-0349.txt rename to peps/pep-0349.rst diff --git a/pep-0350.txt b/peps/pep-0350.rst similarity index 100% rename from pep-0350.txt rename to peps/pep-0350.rst diff --git a/pep-0351.txt b/peps/pep-0351.rst similarity index 100% rename from pep-0351.txt rename to peps/pep-0351.rst diff --git a/pep-0352.txt b/peps/pep-0352.rst similarity index 100% rename from pep-0352.txt rename to peps/pep-0352.rst diff --git a/pep-0353.txt b/peps/pep-0353.rst similarity index 100% rename from pep-0353.txt rename to peps/pep-0353.rst diff --git a/pep-0354.txt b/peps/pep-0354.rst similarity index 100% rename from pep-0354.txt rename to peps/pep-0354.rst diff --git a/pep-0355.txt b/peps/pep-0355.rst similarity index 100% rename from pep-0355.txt rename to peps/pep-0355.rst diff --git a/pep-0356.txt b/peps/pep-0356.rst similarity index 100% rename from pep-0356.txt rename to peps/pep-0356.rst diff --git a/pep-0357.txt b/peps/pep-0357.rst similarity index 100% rename from pep-0357.txt rename to peps/pep-0357.rst diff --git a/pep-0358.txt b/peps/pep-0358.rst similarity index 100% rename from pep-0358.txt rename to peps/pep-0358.rst diff --git a/pep-0359.txt b/peps/pep-0359.rst similarity index 100% rename from pep-0359.txt rename to peps/pep-0359.rst diff --git a/pep-0360.txt b/peps/pep-0360.rst similarity index 100% rename from pep-0360.txt rename to peps/pep-0360.rst diff --git a/pep-0361.txt b/peps/pep-0361.rst similarity index 100% rename from pep-0361.txt rename to peps/pep-0361.rst diff --git a/pep-0362.txt b/peps/pep-0362.rst similarity index 100% rename from pep-0362.txt rename to peps/pep-0362.rst diff --git a/pep-0363.txt b/peps/pep-0363.rst similarity index 100% rename from pep-0363.txt rename to peps/pep-0363.rst diff --git a/pep-0364.txt b/peps/pep-0364.rst similarity index 100% rename from pep-0364.txt rename to peps/pep-0364.rst diff --git a/pep-0365.txt b/peps/pep-0365.rst similarity index 100% rename from pep-0365.txt rename to peps/pep-0365.rst diff --git a/pep-0366.txt b/peps/pep-0366.rst similarity index 100% rename from pep-0366.txt rename to peps/pep-0366.rst diff --git a/pep-0367.txt b/peps/pep-0367.rst similarity index 100% rename from pep-0367.txt rename to peps/pep-0367.rst diff --git a/pep-0368.txt b/peps/pep-0368.rst similarity index 100% rename from pep-0368.txt rename to peps/pep-0368.rst diff --git a/pep-0369.txt b/peps/pep-0369.rst similarity index 100% rename from pep-0369.txt rename to peps/pep-0369.rst diff --git a/pep-0370.txt b/peps/pep-0370.rst similarity index 100% rename from pep-0370.txt rename to peps/pep-0370.rst diff --git a/pep-0371.txt b/peps/pep-0371.rst similarity index 100% rename from pep-0371.txt rename to peps/pep-0371.rst diff --git a/pep-0372.txt b/peps/pep-0372.rst similarity index 100% rename from pep-0372.txt rename to peps/pep-0372.rst diff --git a/pep-0373.txt b/peps/pep-0373.rst similarity index 100% rename from pep-0373.txt rename to peps/pep-0373.rst diff --git a/pep-0374.txt b/peps/pep-0374.rst similarity index 100% rename from pep-0374.txt rename to peps/pep-0374.rst diff --git a/pep-0375.txt b/peps/pep-0375.rst similarity index 100% rename from pep-0375.txt rename to peps/pep-0375.rst diff --git a/pep-0376.txt b/peps/pep-0376.rst similarity index 100% rename from pep-0376.txt rename to peps/pep-0376.rst diff --git a/pep-0377.txt b/peps/pep-0377.rst similarity index 100% rename from pep-0377.txt rename to peps/pep-0377.rst diff --git a/pep-0378.txt b/peps/pep-0378.rst similarity index 100% rename from pep-0378.txt rename to peps/pep-0378.rst diff --git a/pep-0379.txt b/peps/pep-0379.rst similarity index 100% rename from pep-0379.txt rename to peps/pep-0379.rst diff --git a/pep-0380.txt b/peps/pep-0380.rst similarity index 100% rename from pep-0380.txt rename to peps/pep-0380.rst diff --git a/pep-0381.txt b/peps/pep-0381.rst similarity index 100% rename from pep-0381.txt rename to peps/pep-0381.rst diff --git a/pep-0382.txt b/peps/pep-0382.rst similarity index 100% rename from pep-0382.txt rename to peps/pep-0382.rst diff --git a/pep-0383.txt b/peps/pep-0383.rst similarity index 100% rename from pep-0383.txt rename to peps/pep-0383.rst diff --git a/pep-0384.txt b/peps/pep-0384.rst similarity index 100% rename from pep-0384.txt rename to peps/pep-0384.rst diff --git a/pep-0385.txt b/peps/pep-0385.rst similarity index 100% rename from pep-0385.txt rename to peps/pep-0385.rst diff --git a/pep-0386.txt b/peps/pep-0386.rst similarity index 100% rename from pep-0386.txt rename to peps/pep-0386.rst diff --git a/pep-0387.txt b/peps/pep-0387.rst similarity index 100% rename from pep-0387.txt rename to peps/pep-0387.rst diff --git a/pep-0389.txt b/peps/pep-0389.rst similarity index 100% rename from pep-0389.txt rename to peps/pep-0389.rst diff --git a/pep-0390.txt b/peps/pep-0390.rst similarity index 100% rename from pep-0390.txt rename to peps/pep-0390.rst diff --git a/pep-0391.txt b/peps/pep-0391.rst similarity index 100% rename from pep-0391.txt rename to peps/pep-0391.rst diff --git a/pep-0392.txt b/peps/pep-0392.rst similarity index 100% rename from pep-0392.txt rename to peps/pep-0392.rst diff --git a/pep-0393.txt b/peps/pep-0393.rst similarity index 100% rename from pep-0393.txt rename to peps/pep-0393.rst diff --git a/pep-0394.txt b/peps/pep-0394.rst similarity index 100% rename from pep-0394.txt rename to peps/pep-0394.rst diff --git a/pep-0395.txt b/peps/pep-0395.rst similarity index 100% rename from pep-0395.txt rename to peps/pep-0395.rst diff --git a/pep-0396.txt b/peps/pep-0396.rst similarity index 100% rename from pep-0396.txt rename to peps/pep-0396.rst diff --git a/pep-0397.txt b/peps/pep-0397.rst similarity index 100% rename from pep-0397.txt rename to peps/pep-0397.rst diff --git a/pep-0398.txt b/peps/pep-0398.rst similarity index 100% rename from pep-0398.txt rename to peps/pep-0398.rst diff --git a/pep-0399.txt b/peps/pep-0399.rst similarity index 100% rename from pep-0399.txt rename to peps/pep-0399.rst diff --git a/pep-0400.txt b/peps/pep-0400.rst similarity index 100% rename from pep-0400.txt rename to peps/pep-0400.rst diff --git a/pep-0401.txt b/peps/pep-0401.rst similarity index 100% rename from pep-0401.txt rename to peps/pep-0401.rst diff --git a/pep-0402.txt b/peps/pep-0402.rst similarity index 100% rename from pep-0402.txt rename to peps/pep-0402.rst diff --git a/pep-0403.txt b/peps/pep-0403.rst similarity index 100% rename from pep-0403.txt rename to peps/pep-0403.rst diff --git a/pep-0404.txt b/peps/pep-0404.rst similarity index 100% rename from pep-0404.txt rename to peps/pep-0404.rst diff --git a/pep-0405.txt b/peps/pep-0405.rst similarity index 100% rename from pep-0405.txt rename to peps/pep-0405.rst diff --git a/pep-0406.txt b/peps/pep-0406.rst similarity index 100% rename from pep-0406.txt rename to peps/pep-0406.rst diff --git a/pep-0407.txt b/peps/pep-0407.rst similarity index 100% rename from pep-0407.txt rename to peps/pep-0407.rst diff --git a/pep-0408.txt b/peps/pep-0408.rst similarity index 100% rename from pep-0408.txt rename to peps/pep-0408.rst diff --git a/pep-0409.txt b/peps/pep-0409.rst similarity index 100% rename from pep-0409.txt rename to peps/pep-0409.rst diff --git a/pep-0410.txt b/peps/pep-0410.rst similarity index 100% rename from pep-0410.txt rename to peps/pep-0410.rst diff --git a/pep-0411.txt b/peps/pep-0411.rst similarity index 100% rename from pep-0411.txt rename to peps/pep-0411.rst diff --git a/pep-0412.txt b/peps/pep-0412.rst similarity index 100% rename from pep-0412.txt rename to peps/pep-0412.rst diff --git a/pep-0413.txt b/peps/pep-0413.rst similarity index 100% rename from pep-0413.txt rename to peps/pep-0413.rst diff --git a/pep-0414.txt b/peps/pep-0414.rst similarity index 100% rename from pep-0414.txt rename to peps/pep-0414.rst diff --git a/pep-0415.txt b/peps/pep-0415.rst similarity index 100% rename from pep-0415.txt rename to peps/pep-0415.rst diff --git a/pep-0416.txt b/peps/pep-0416.rst similarity index 100% rename from pep-0416.txt rename to peps/pep-0416.rst diff --git a/pep-0417.txt b/peps/pep-0417.rst similarity index 100% rename from pep-0417.txt rename to peps/pep-0417.rst diff --git a/pep-0418.txt b/peps/pep-0418.rst similarity index 100% rename from pep-0418.txt rename to peps/pep-0418.rst diff --git a/pep-0418/bench_time.c b/peps/pep-0418/bench_time.c similarity index 100% rename from pep-0418/bench_time.c rename to peps/pep-0418/bench_time.c diff --git a/pep-0418/clock_resolution.py b/peps/pep-0418/clock_resolution.py similarity index 100% rename from pep-0418/clock_resolution.py rename to peps/pep-0418/clock_resolution.py diff --git a/pep-0418/clockutils.py b/peps/pep-0418/clockutils.py similarity index 100% rename from pep-0418/clockutils.py rename to peps/pep-0418/clockutils.py diff --git a/pep-0419.txt b/peps/pep-0419.rst similarity index 100% rename from pep-0419.txt rename to peps/pep-0419.rst diff --git a/pep-0420.txt b/peps/pep-0420.rst similarity index 100% rename from pep-0420.txt rename to peps/pep-0420.rst diff --git a/pep-0421.txt b/peps/pep-0421.rst similarity index 100% rename from pep-0421.txt rename to peps/pep-0421.rst diff --git a/pep-0422.txt b/peps/pep-0422.rst similarity index 100% rename from pep-0422.txt rename to peps/pep-0422.rst diff --git a/pep-0423.txt b/peps/pep-0423.rst similarity index 100% rename from pep-0423.txt rename to peps/pep-0423.rst diff --git a/pep-0424.txt b/peps/pep-0424.rst similarity index 100% rename from pep-0424.txt rename to peps/pep-0424.rst diff --git a/pep-0425.txt b/peps/pep-0425.rst similarity index 100% rename from pep-0425.txt rename to peps/pep-0425.rst diff --git a/pep-0426.txt b/peps/pep-0426.rst similarity index 100% rename from pep-0426.txt rename to peps/pep-0426.rst diff --git a/pep-0426/pepsort.py b/peps/pep-0426/pepsort.py similarity index 100% rename from pep-0426/pepsort.py rename to peps/pep-0426/pepsort.py diff --git a/pep-0426/pydist-schema.json b/peps/pep-0426/pydist-schema.json similarity index 100% rename from pep-0426/pydist-schema.json rename to peps/pep-0426/pydist-schema.json diff --git a/pep-0427.txt b/peps/pep-0427.rst similarity index 100% rename from pep-0427.txt rename to peps/pep-0427.rst diff --git a/pep-0428.txt b/peps/pep-0428.rst similarity index 100% rename from pep-0428.txt rename to peps/pep-0428.rst diff --git a/pep-0429.txt b/peps/pep-0429.rst similarity index 100% rename from pep-0429.txt rename to peps/pep-0429.rst diff --git a/pep-0430.txt b/peps/pep-0430.rst similarity index 100% rename from pep-0430.txt rename to peps/pep-0430.rst diff --git a/pep-0431.txt b/peps/pep-0431.rst similarity index 100% rename from pep-0431.txt rename to peps/pep-0431.rst diff --git a/pep-0432.txt b/peps/pep-0432.rst similarity index 100% rename from pep-0432.txt rename to peps/pep-0432.rst diff --git a/pep-0433.txt b/peps/pep-0433.rst similarity index 100% rename from pep-0433.txt rename to peps/pep-0433.rst diff --git a/pep-0433/bench_cloexec.py b/peps/pep-0433/bench_cloexec.py similarity index 100% rename from pep-0433/bench_cloexec.py rename to peps/pep-0433/bench_cloexec.py diff --git a/pep-0433/openbsd_bug.py b/peps/pep-0433/openbsd_bug.py similarity index 100% rename from pep-0433/openbsd_bug.py rename to peps/pep-0433/openbsd_bug.py diff --git a/pep-0434.txt b/peps/pep-0434.rst similarity index 100% rename from pep-0434.txt rename to peps/pep-0434.rst diff --git a/pep-0435.txt b/peps/pep-0435.rst similarity index 100% rename from pep-0435.txt rename to peps/pep-0435.rst diff --git a/pep-0436.txt b/peps/pep-0436.rst similarity index 100% rename from pep-0436.txt rename to peps/pep-0436.rst diff --git a/pep-0437.txt b/peps/pep-0437.rst similarity index 100% rename from pep-0437.txt rename to peps/pep-0437.rst diff --git a/pep-0438.txt b/peps/pep-0438.rst similarity index 100% rename from pep-0438.txt rename to peps/pep-0438.rst diff --git a/pep-0439.txt b/peps/pep-0439.rst similarity index 100% rename from pep-0439.txt rename to peps/pep-0439.rst diff --git a/pep-0440.txt b/peps/pep-0440.rst similarity index 100% rename from pep-0440.txt rename to peps/pep-0440.rst diff --git a/pep-0441.txt b/peps/pep-0441.rst similarity index 100% rename from pep-0441.txt rename to peps/pep-0441.rst diff --git a/pep-0442.txt b/peps/pep-0442.rst similarity index 100% rename from pep-0442.txt rename to peps/pep-0442.rst diff --git a/pep-0443.txt b/peps/pep-0443.rst similarity index 100% rename from pep-0443.txt rename to peps/pep-0443.rst diff --git a/pep-0444.txt b/peps/pep-0444.rst similarity index 100% rename from pep-0444.txt rename to peps/pep-0444.rst diff --git a/pep-0445.txt b/peps/pep-0445.rst similarity index 100% rename from pep-0445.txt rename to peps/pep-0445.rst diff --git a/pep-0446.txt b/peps/pep-0446.rst similarity index 100% rename from pep-0446.txt rename to peps/pep-0446.rst diff --git a/pep-0446/test_cloexec.py b/peps/pep-0446/test_cloexec.py similarity index 100% rename from pep-0446/test_cloexec.py rename to peps/pep-0446/test_cloexec.py diff --git a/pep-0447.txt b/peps/pep-0447.rst similarity index 100% rename from pep-0447.txt rename to peps/pep-0447.rst diff --git a/pep-0448.txt b/peps/pep-0448.rst similarity index 100% rename from pep-0448.txt rename to peps/pep-0448.rst diff --git a/pep-0449.txt b/peps/pep-0449.rst similarity index 100% rename from pep-0449.txt rename to peps/pep-0449.rst diff --git a/pep-0450.txt b/peps/pep-0450.rst similarity index 100% rename from pep-0450.txt rename to peps/pep-0450.rst diff --git a/pep-0451.txt b/peps/pep-0451.rst similarity index 100% rename from pep-0451.txt rename to peps/pep-0451.rst diff --git a/pep-0452.txt b/peps/pep-0452.rst similarity index 100% rename from pep-0452.txt rename to peps/pep-0452.rst diff --git a/pep-0453.txt b/peps/pep-0453.rst similarity index 100% rename from pep-0453.txt rename to peps/pep-0453.rst diff --git a/pep-0454.txt b/peps/pep-0454.rst similarity index 100% rename from pep-0454.txt rename to peps/pep-0454.rst diff --git a/pep-0455.txt b/peps/pep-0455.rst similarity index 100% rename from pep-0455.txt rename to peps/pep-0455.rst diff --git a/pep-0456.txt b/peps/pep-0456.rst similarity index 100% rename from pep-0456.txt rename to peps/pep-0456.rst diff --git a/pep-0457.txt b/peps/pep-0457.rst similarity index 100% rename from pep-0457.txt rename to peps/pep-0457.rst diff --git a/pep-0458-1.png b/peps/pep-0458-1.png similarity index 100% rename from pep-0458-1.png rename to peps/pep-0458-1.png diff --git a/pep-0458.txt b/peps/pep-0458.rst similarity index 100% rename from pep-0458.txt rename to peps/pep-0458.rst diff --git a/pep-0459.txt b/peps/pep-0459.rst similarity index 100% rename from pep-0459.txt rename to peps/pep-0459.rst diff --git a/pep-0460.txt b/peps/pep-0460.rst similarity index 100% rename from pep-0460.txt rename to peps/pep-0460.rst diff --git a/pep-0461.txt b/peps/pep-0461.rst similarity index 100% rename from pep-0461.txt rename to peps/pep-0461.rst diff --git a/pep-0462.txt b/peps/pep-0462.rst similarity index 100% rename from pep-0462.txt rename to peps/pep-0462.rst diff --git a/pep-0463.txt b/peps/pep-0463.rst similarity index 100% rename from pep-0463.txt rename to peps/pep-0463.rst diff --git a/pep-0464.txt b/peps/pep-0464.rst similarity index 100% rename from pep-0464.txt rename to peps/pep-0464.rst diff --git a/pep-0465.txt b/peps/pep-0465.rst similarity index 100% rename from pep-0465.txt rename to peps/pep-0465.rst diff --git a/pep-0465/scan-ops.py b/peps/pep-0465/scan-ops.py similarity index 100% rename from pep-0465/scan-ops.py rename to peps/pep-0465/scan-ops.py diff --git a/pep-0466.txt b/peps/pep-0466.rst similarity index 100% rename from pep-0466.txt rename to peps/pep-0466.rst diff --git a/pep-0467.txt b/peps/pep-0467.rst similarity index 100% rename from pep-0467.txt rename to peps/pep-0467.rst diff --git a/pep-0468.txt b/peps/pep-0468.rst similarity index 100% rename from pep-0468.txt rename to peps/pep-0468.rst diff --git a/pep-0469.txt b/peps/pep-0469.rst similarity index 100% rename from pep-0469.txt rename to peps/pep-0469.rst diff --git a/pep-0470.txt b/peps/pep-0470.rst similarity index 100% rename from pep-0470.txt rename to peps/pep-0470.rst diff --git a/pep-0471.txt b/peps/pep-0471.rst similarity index 100% rename from pep-0471.txt rename to peps/pep-0471.rst diff --git a/pep-0472.txt b/peps/pep-0472.rst similarity index 100% rename from pep-0472.txt rename to peps/pep-0472.rst diff --git a/pep-0473.txt b/peps/pep-0473.rst similarity index 100% rename from pep-0473.txt rename to peps/pep-0473.rst diff --git a/pep-0474.txt b/peps/pep-0474.rst similarity index 100% rename from pep-0474.txt rename to peps/pep-0474.rst diff --git a/pep-0475.txt b/peps/pep-0475.rst similarity index 100% rename from pep-0475.txt rename to peps/pep-0475.rst diff --git a/pep-0476.txt b/peps/pep-0476.rst similarity index 100% rename from pep-0476.txt rename to peps/pep-0476.rst diff --git a/pep-0477.txt b/peps/pep-0477.rst similarity index 100% rename from pep-0477.txt rename to peps/pep-0477.rst diff --git a/pep-0478.txt b/peps/pep-0478.rst similarity index 100% rename from pep-0478.txt rename to peps/pep-0478.rst diff --git a/pep-0479.txt b/peps/pep-0479.rst similarity index 100% rename from pep-0479.txt rename to peps/pep-0479.rst diff --git a/pep-0480-1.png b/peps/pep-0480-1.png similarity index 100% rename from pep-0480-1.png rename to peps/pep-0480-1.png diff --git a/pep-0480.txt b/peps/pep-0480.rst similarity index 100% rename from pep-0480.txt rename to peps/pep-0480.rst diff --git a/pep-0481.txt b/peps/pep-0481.rst similarity index 100% rename from pep-0481.txt rename to peps/pep-0481.rst diff --git a/pep-0482.txt b/peps/pep-0482.rst similarity index 100% rename from pep-0482.txt rename to peps/pep-0482.rst diff --git a/pep-0483.txt b/peps/pep-0483.rst similarity index 100% rename from pep-0483.txt rename to peps/pep-0483.rst diff --git a/pep-0484.txt b/peps/pep-0484.rst similarity index 100% rename from pep-0484.txt rename to peps/pep-0484.rst diff --git a/pep-0485.txt b/peps/pep-0485.rst similarity index 100% rename from pep-0485.txt rename to peps/pep-0485.rst diff --git a/pep-0486.txt b/peps/pep-0486.rst similarity index 100% rename from pep-0486.txt rename to peps/pep-0486.rst diff --git a/pep-0487.txt b/peps/pep-0487.rst similarity index 100% rename from pep-0487.txt rename to peps/pep-0487.rst diff --git a/pep-0488.txt b/peps/pep-0488.rst similarity index 100% rename from pep-0488.txt rename to peps/pep-0488.rst diff --git a/pep-0489.txt b/peps/pep-0489.rst similarity index 100% rename from pep-0489.txt rename to peps/pep-0489.rst diff --git a/pep-0490.txt b/peps/pep-0490.rst similarity index 100% rename from pep-0490.txt rename to peps/pep-0490.rst diff --git a/pep-0491.txt b/peps/pep-0491.rst similarity index 100% rename from pep-0491.txt rename to peps/pep-0491.rst diff --git a/pep-0492.txt b/peps/pep-0492.rst similarity index 100% rename from pep-0492.txt rename to peps/pep-0492.rst diff --git a/pep-0493.txt b/peps/pep-0493.rst similarity index 100% rename from pep-0493.txt rename to peps/pep-0493.rst diff --git a/pep-0494.txt b/peps/pep-0494.rst similarity index 100% rename from pep-0494.txt rename to peps/pep-0494.rst diff --git a/pep-0495-daylightsavings.png b/peps/pep-0495-daylightsavings.png similarity index 100% rename from pep-0495-daylightsavings.png rename to peps/pep-0495-daylightsavings.png diff --git a/pep-0495-fold.svg b/peps/pep-0495-fold.svg similarity index 100% rename from pep-0495-fold.svg rename to peps/pep-0495-fold.svg diff --git a/pep-0495-gap.svg b/peps/pep-0495-gap.svg similarity index 100% rename from pep-0495-gap.svg rename to peps/pep-0495-gap.svg diff --git a/pep-0495.txt b/peps/pep-0495.rst similarity index 100% rename from pep-0495.txt rename to peps/pep-0495.rst diff --git a/pep-0496.txt b/peps/pep-0496.rst similarity index 100% rename from pep-0496.txt rename to peps/pep-0496.rst diff --git a/pep-0497.txt b/peps/pep-0497.rst similarity index 100% rename from pep-0497.txt rename to peps/pep-0497.rst diff --git a/pep-0498.txt b/peps/pep-0498.rst similarity index 100% rename from pep-0498.txt rename to peps/pep-0498.rst diff --git a/pep-0499.txt b/peps/pep-0499.rst similarity index 100% rename from pep-0499.txt rename to peps/pep-0499.rst diff --git a/pep-0500.txt b/peps/pep-0500.rst similarity index 100% rename from pep-0500.txt rename to peps/pep-0500.rst diff --git a/pep-0501.txt b/peps/pep-0501.rst similarity index 100% rename from pep-0501.txt rename to peps/pep-0501.rst diff --git a/pep-0502.txt b/peps/pep-0502.rst similarity index 100% rename from pep-0502.txt rename to peps/pep-0502.rst diff --git a/pep-0503.txt b/peps/pep-0503.rst similarity index 100% rename from pep-0503.txt rename to peps/pep-0503.rst diff --git a/pep-0504.txt b/peps/pep-0504.rst similarity index 100% rename from pep-0504.txt rename to peps/pep-0504.rst diff --git a/pep-0505.rst b/peps/pep-0505.rst similarity index 100% rename from pep-0505.rst rename to peps/pep-0505.rst diff --git a/pep-0505/find-pep505.out b/peps/pep-0505/find-pep505.out similarity index 100% rename from pep-0505/find-pep505.out rename to peps/pep-0505/find-pep505.out diff --git a/pep-0505/find-pep505.py b/peps/pep-0505/find-pep505.py similarity index 100% rename from pep-0505/find-pep505.py rename to peps/pep-0505/find-pep505.py diff --git a/pep-0505/test.py b/peps/pep-0505/test.py similarity index 100% rename from pep-0505/test.py rename to peps/pep-0505/test.py diff --git a/pep-0506.txt b/peps/pep-0506.rst similarity index 100% rename from pep-0506.txt rename to peps/pep-0506.rst diff --git a/pep-0507.txt b/peps/pep-0507.rst similarity index 100% rename from pep-0507.txt rename to peps/pep-0507.rst diff --git a/pep-0508.txt b/peps/pep-0508.rst similarity index 100% rename from pep-0508.txt rename to peps/pep-0508.rst diff --git a/pep-0509.txt b/peps/pep-0509.rst similarity index 100% rename from pep-0509.txt rename to peps/pep-0509.rst diff --git a/pep-0510.txt b/peps/pep-0510.rst similarity index 100% rename from pep-0510.txt rename to peps/pep-0510.rst diff --git a/pep-0511.txt b/peps/pep-0511.rst similarity index 100% rename from pep-0511.txt rename to peps/pep-0511.rst diff --git a/pep-0512.txt b/peps/pep-0512.rst similarity index 100% rename from pep-0512.txt rename to peps/pep-0512.rst diff --git a/pep-0513.txt b/peps/pep-0513.rst similarity index 100% rename from pep-0513.txt rename to peps/pep-0513.rst diff --git a/pep-0514.txt b/peps/pep-0514.rst similarity index 100% rename from pep-0514.txt rename to peps/pep-0514.rst diff --git a/pep-0515.txt b/peps/pep-0515.rst similarity index 100% rename from pep-0515.txt rename to peps/pep-0515.rst diff --git a/pep-0516.txt b/peps/pep-0516.rst similarity index 100% rename from pep-0516.txt rename to peps/pep-0516.rst diff --git a/pep-0517.txt b/peps/pep-0517.rst similarity index 100% rename from pep-0517.txt rename to peps/pep-0517.rst diff --git a/pep-0518.txt b/peps/pep-0518.rst similarity index 100% rename from pep-0518.txt rename to peps/pep-0518.rst diff --git a/pep-0519.txt b/peps/pep-0519.rst similarity index 100% rename from pep-0519.txt rename to peps/pep-0519.rst diff --git a/pep-0520.txt b/peps/pep-0520.rst similarity index 100% rename from pep-0520.txt rename to peps/pep-0520.rst diff --git a/pep-0521.txt b/peps/pep-0521.rst similarity index 100% rename from pep-0521.txt rename to peps/pep-0521.rst diff --git a/pep-0522.txt b/peps/pep-0522.rst similarity index 100% rename from pep-0522.txt rename to peps/pep-0522.rst diff --git a/pep-0523.txt b/peps/pep-0523.rst similarity index 100% rename from pep-0523.txt rename to peps/pep-0523.rst diff --git a/pep-0524.txt b/peps/pep-0524.rst similarity index 100% rename from pep-0524.txt rename to peps/pep-0524.rst diff --git a/pep-0525-1.png b/peps/pep-0525-1.png similarity index 100% rename from pep-0525-1.png rename to peps/pep-0525-1.png diff --git a/pep-0525.txt b/peps/pep-0525.rst similarity index 100% rename from pep-0525.txt rename to peps/pep-0525.rst diff --git a/pep-0526.txt b/peps/pep-0526.rst similarity index 100% rename from pep-0526.txt rename to peps/pep-0526.rst diff --git a/pep-0527.txt b/peps/pep-0527.rst similarity index 100% rename from pep-0527.txt rename to peps/pep-0527.rst diff --git a/pep-0528.txt b/peps/pep-0528.rst similarity index 100% rename from pep-0528.txt rename to peps/pep-0528.rst diff --git a/pep-0529.txt b/peps/pep-0529.rst similarity index 100% rename from pep-0529.txt rename to peps/pep-0529.rst diff --git a/pep-0530.txt b/peps/pep-0530.rst similarity index 100% rename from pep-0530.txt rename to peps/pep-0530.rst diff --git a/pep-0531.txt b/peps/pep-0531.rst similarity index 100% rename from pep-0531.txt rename to peps/pep-0531.rst diff --git a/pep-0532.txt b/peps/pep-0532.rst similarity index 100% rename from pep-0532.txt rename to peps/pep-0532.rst diff --git a/pep-0532/circuit-breaking-protocol.svg b/peps/pep-0532/circuit-breaking-protocol.svg similarity index 100% rename from pep-0532/circuit-breaking-protocol.svg rename to peps/pep-0532/circuit-breaking-protocol.svg diff --git a/pep-0533.txt b/peps/pep-0533.rst similarity index 100% rename from pep-0533.txt rename to peps/pep-0533.rst diff --git a/pep-0534.txt b/peps/pep-0534.rst similarity index 100% rename from pep-0534.txt rename to peps/pep-0534.rst diff --git a/pep-0535.txt b/peps/pep-0535.rst similarity index 100% rename from pep-0535.txt rename to peps/pep-0535.rst diff --git a/pep-0536.txt b/peps/pep-0536.rst similarity index 100% rename from pep-0536.txt rename to peps/pep-0536.rst diff --git a/pep-0537.txt b/peps/pep-0537.rst similarity index 100% rename from pep-0537.txt rename to peps/pep-0537.rst diff --git a/pep-0538.txt b/peps/pep-0538.rst similarity index 100% rename from pep-0538.txt rename to peps/pep-0538.rst diff --git a/pep-0539.txt b/peps/pep-0539.rst similarity index 100% rename from pep-0539.txt rename to peps/pep-0539.rst diff --git a/pep-0540.txt b/peps/pep-0540.rst similarity index 100% rename from pep-0540.txt rename to peps/pep-0540.rst diff --git a/pep-0541.txt b/peps/pep-0541.rst similarity index 100% rename from pep-0541.txt rename to peps/pep-0541.rst diff --git a/pep-0542.txt b/peps/pep-0542.rst similarity index 100% rename from pep-0542.txt rename to peps/pep-0542.rst diff --git a/pep-0543.rst b/peps/pep-0543.rst similarity index 100% rename from pep-0543.rst rename to peps/pep-0543.rst diff --git a/pep-0544.txt b/peps/pep-0544.rst similarity index 100% rename from pep-0544.txt rename to peps/pep-0544.rst diff --git a/pep-0545.txt b/peps/pep-0545.rst similarity index 100% rename from pep-0545.txt rename to peps/pep-0545.rst diff --git a/pep-0546.txt b/peps/pep-0546.rst similarity index 100% rename from pep-0546.txt rename to peps/pep-0546.rst diff --git a/pep-0547.rst b/peps/pep-0547.rst similarity index 100% rename from pep-0547.rst rename to peps/pep-0547.rst diff --git a/pep-0548.rst b/peps/pep-0548.rst similarity index 100% rename from pep-0548.rst rename to peps/pep-0548.rst diff --git a/pep-0549.rst b/peps/pep-0549.rst similarity index 100% rename from pep-0549.rst rename to peps/pep-0549.rst diff --git a/pep-0550-hamt_vs_dict-v2.png b/peps/pep-0550-hamt_vs_dict-v2.png similarity index 100% rename from pep-0550-hamt_vs_dict-v2.png rename to peps/pep-0550-hamt_vs_dict-v2.png diff --git a/pep-0550-hamt_vs_dict.png b/peps/pep-0550-hamt_vs_dict.png similarity index 100% rename from pep-0550-hamt_vs_dict.png rename to peps/pep-0550-hamt_vs_dict.png diff --git a/pep-0550-lookup_hamt.png b/peps/pep-0550-lookup_hamt.png similarity index 100% rename from pep-0550-lookup_hamt.png rename to peps/pep-0550-lookup_hamt.png diff --git a/pep-0550.rst b/peps/pep-0550.rst similarity index 100% rename from pep-0550.rst rename to peps/pep-0550.rst diff --git a/pep-0551.rst b/peps/pep-0551.rst similarity index 100% rename from pep-0551.rst rename to peps/pep-0551.rst diff --git a/pep-0552.rst b/peps/pep-0552.rst similarity index 100% rename from pep-0552.rst rename to peps/pep-0552.rst diff --git a/pep-0553.rst b/peps/pep-0553.rst similarity index 100% rename from pep-0553.rst rename to peps/pep-0553.rst diff --git a/pep-0554.rst b/peps/pep-0554.rst similarity index 100% rename from pep-0554.rst rename to peps/pep-0554.rst diff --git a/pep-0555.rst b/peps/pep-0555.rst similarity index 100% rename from pep-0555.rst rename to peps/pep-0555.rst diff --git a/pep-0556.rst b/peps/pep-0556.rst similarity index 100% rename from pep-0556.rst rename to peps/pep-0556.rst diff --git a/pep-0557.rst b/peps/pep-0557.rst similarity index 100% rename from pep-0557.rst rename to peps/pep-0557.rst diff --git a/pep-0558.rst b/peps/pep-0558.rst similarity index 100% rename from pep-0558.rst rename to peps/pep-0558.rst diff --git a/pep-0559.rst b/peps/pep-0559.rst similarity index 100% rename from pep-0559.rst rename to peps/pep-0559.rst diff --git a/pep-0560.rst b/peps/pep-0560.rst similarity index 100% rename from pep-0560.rst rename to peps/pep-0560.rst diff --git a/pep-0561.rst b/peps/pep-0561.rst similarity index 100% rename from pep-0561.rst rename to peps/pep-0561.rst diff --git a/pep-0562.rst b/peps/pep-0562.rst similarity index 100% rename from pep-0562.rst rename to peps/pep-0562.rst diff --git a/pep-0563.rst b/peps/pep-0563.rst similarity index 100% rename from pep-0563.rst rename to peps/pep-0563.rst diff --git a/pep-0564.rst b/peps/pep-0564.rst similarity index 100% rename from pep-0564.rst rename to peps/pep-0564.rst diff --git a/pep-0565.rst b/peps/pep-0565.rst similarity index 100% rename from pep-0565.rst rename to peps/pep-0565.rst diff --git a/pep-0566.rst b/peps/pep-0566.rst similarity index 100% rename from pep-0566.rst rename to peps/pep-0566.rst diff --git a/pep-0567.rst b/peps/pep-0567.rst similarity index 100% rename from pep-0567.rst rename to peps/pep-0567.rst diff --git a/pep-0568.rst b/peps/pep-0568.rst similarity index 100% rename from pep-0568.rst rename to peps/pep-0568.rst diff --git a/pep-0569.rst b/peps/pep-0569.rst similarity index 100% rename from pep-0569.rst rename to peps/pep-0569.rst diff --git a/pep-0570.rst b/peps/pep-0570.rst similarity index 100% rename from pep-0570.rst rename to peps/pep-0570.rst diff --git a/pep-0571.rst b/peps/pep-0571.rst similarity index 100% rename from pep-0571.rst rename to peps/pep-0571.rst diff --git a/pep-0572.rst b/peps/pep-0572.rst similarity index 100% rename from pep-0572.rst rename to peps/pep-0572.rst diff --git a/pep-0573.rst b/peps/pep-0573.rst similarity index 100% rename from pep-0573.rst rename to peps/pep-0573.rst diff --git a/pep-0574.rst b/peps/pep-0574.rst similarity index 100% rename from pep-0574.rst rename to peps/pep-0574.rst diff --git a/pep-0575.rst b/peps/pep-0575.rst similarity index 100% rename from pep-0575.rst rename to peps/pep-0575.rst diff --git a/pep-0576.rst b/peps/pep-0576.rst similarity index 100% rename from pep-0576.rst rename to peps/pep-0576.rst diff --git a/pep-0577.rst b/peps/pep-0577.rst similarity index 100% rename from pep-0577.rst rename to peps/pep-0577.rst diff --git a/pep-0578.rst b/peps/pep-0578.rst similarity index 100% rename from pep-0578.rst rename to peps/pep-0578.rst diff --git a/pep-0579.rst b/peps/pep-0579.rst similarity index 100% rename from pep-0579.rst rename to peps/pep-0579.rst diff --git a/pep-0580.rst b/peps/pep-0580.rst similarity index 100% rename from pep-0580.rst rename to peps/pep-0580.rst diff --git a/pep-0581.rst b/peps/pep-0581.rst similarity index 100% rename from pep-0581.rst rename to peps/pep-0581.rst diff --git a/pep-0582.rst b/peps/pep-0582.rst similarity index 100% rename from pep-0582.rst rename to peps/pep-0582.rst diff --git a/pep-0583.rst b/peps/pep-0583.rst similarity index 100% rename from pep-0583.rst rename to peps/pep-0583.rst diff --git a/pep-0584.rst b/peps/pep-0584.rst similarity index 100% rename from pep-0584.rst rename to peps/pep-0584.rst diff --git a/pep-0585.rst b/peps/pep-0585.rst similarity index 100% rename from pep-0585.rst rename to peps/pep-0585.rst diff --git a/pep-0586.rst b/peps/pep-0586.rst similarity index 100% rename from pep-0586.rst rename to peps/pep-0586.rst diff --git a/pep-0587.rst b/peps/pep-0587.rst similarity index 100% rename from pep-0587.rst rename to peps/pep-0587.rst diff --git a/pep-0588.rst b/peps/pep-0588.rst similarity index 100% rename from pep-0588.rst rename to peps/pep-0588.rst diff --git a/pep-0589.rst b/peps/pep-0589.rst similarity index 100% rename from pep-0589.rst rename to peps/pep-0589.rst diff --git a/pep-0590.rst b/peps/pep-0590.rst similarity index 100% rename from pep-0590.rst rename to peps/pep-0590.rst diff --git a/pep-0591.rst b/peps/pep-0591.rst similarity index 100% rename from pep-0591.rst rename to peps/pep-0591.rst diff --git a/pep-0592.rst b/peps/pep-0592.rst similarity index 100% rename from pep-0592.rst rename to peps/pep-0592.rst diff --git a/pep-0593.rst b/peps/pep-0593.rst similarity index 100% rename from pep-0593.rst rename to peps/pep-0593.rst diff --git a/pep-0594.rst b/peps/pep-0594.rst similarity index 100% rename from pep-0594.rst rename to peps/pep-0594.rst diff --git a/pep-0595.rst b/peps/pep-0595.rst similarity index 100% rename from pep-0595.rst rename to peps/pep-0595.rst diff --git a/pep-0596.rst b/peps/pep-0596.rst similarity index 100% rename from pep-0596.rst rename to peps/pep-0596.rst diff --git a/pep-0597.rst b/peps/pep-0597.rst similarity index 100% rename from pep-0597.rst rename to peps/pep-0597.rst diff --git a/pep-0598.rst b/peps/pep-0598.rst similarity index 100% rename from pep-0598.rst rename to peps/pep-0598.rst diff --git a/pep-0599.rst b/peps/pep-0599.rst similarity index 100% rename from pep-0599.rst rename to peps/pep-0599.rst diff --git a/pep-0600.rst b/peps/pep-0600.rst similarity index 100% rename from pep-0600.rst rename to peps/pep-0600.rst diff --git a/pep-0601.txt b/peps/pep-0601.rst similarity index 100% rename from pep-0601.txt rename to peps/pep-0601.rst diff --git a/pep-0602-example-release-calendar.png b/peps/pep-0602-example-release-calendar.png similarity index 100% rename from pep-0602-example-release-calendar.png rename to peps/pep-0602-example-release-calendar.png diff --git a/pep-0602-example-release-calendar.pptx b/peps/pep-0602-example-release-calendar.pptx similarity index 100% rename from pep-0602-example-release-calendar.pptx rename to peps/pep-0602-example-release-calendar.pptx diff --git a/pep-0602-overlapping-support-matrix.png b/peps/pep-0602-overlapping-support-matrix.png similarity index 100% rename from pep-0602-overlapping-support-matrix.png rename to peps/pep-0602-overlapping-support-matrix.png diff --git a/pep-0602-overlapping-support-matrix.pptx b/peps/pep-0602-overlapping-support-matrix.pptx similarity index 100% rename from pep-0602-overlapping-support-matrix.pptx rename to peps/pep-0602-overlapping-support-matrix.pptx diff --git a/pep-0602.rst b/peps/pep-0602.rst similarity index 100% rename from pep-0602.rst rename to peps/pep-0602.rst diff --git a/pep-0603-hamt_vs_dict.png b/peps/pep-0603-hamt_vs_dict.png similarity index 100% rename from pep-0603-hamt_vs_dict.png rename to peps/pep-0603-hamt_vs_dict.png diff --git a/pep-0603-lookup_hamt.png b/peps/pep-0603-lookup_hamt.png similarity index 100% rename from pep-0603-lookup_hamt.png rename to peps/pep-0603-lookup_hamt.png diff --git a/pep-0603.rst b/peps/pep-0603.rst similarity index 100% rename from pep-0603.rst rename to peps/pep-0603.rst diff --git a/pep-0604.rst b/peps/pep-0604.rst similarity index 100% rename from pep-0604.rst rename to peps/pep-0604.rst diff --git a/pep-0605-example-release-calendar.png b/peps/pep-0605-example-release-calendar.png similarity index 100% rename from pep-0605-example-release-calendar.png rename to peps/pep-0605-example-release-calendar.png diff --git a/pep-0605-overlapping-support-matrix.png b/peps/pep-0605-overlapping-support-matrix.png similarity index 100% rename from pep-0605-overlapping-support-matrix.png rename to peps/pep-0605-overlapping-support-matrix.png diff --git a/pep-0605.rst b/peps/pep-0605.rst similarity index 100% rename from pep-0605.rst rename to peps/pep-0605.rst diff --git a/pep-0605/example-release-calendar.odp b/peps/pep-0605/example-release-calendar.odp similarity index 100% rename from pep-0605/example-release-calendar.odp rename to peps/pep-0605/example-release-calendar.odp diff --git a/pep-0605/overlapping-support-matrix.odp b/peps/pep-0605/overlapping-support-matrix.odp similarity index 100% rename from pep-0605/overlapping-support-matrix.odp rename to peps/pep-0605/overlapping-support-matrix.odp diff --git a/pep-0606.rst b/peps/pep-0606.rst similarity index 100% rename from pep-0606.rst rename to peps/pep-0606.rst diff --git a/pep-0607.rst b/peps/pep-0607.rst similarity index 100% rename from pep-0607.rst rename to peps/pep-0607.rst diff --git a/pep-0608.rst b/peps/pep-0608.rst similarity index 100% rename from pep-0608.rst rename to peps/pep-0608.rst diff --git a/pep-0609.rst b/peps/pep-0609.rst similarity index 100% rename from pep-0609.rst rename to peps/pep-0609.rst diff --git a/pep-0610.rst b/peps/pep-0610.rst similarity index 100% rename from pep-0610.rst rename to peps/pep-0610.rst diff --git a/pep-0611.rst b/peps/pep-0611.rst similarity index 100% rename from pep-0611.rst rename to peps/pep-0611.rst diff --git a/pep-0612.rst b/peps/pep-0612.rst similarity index 100% rename from pep-0612.rst rename to peps/pep-0612.rst diff --git a/pep-0613.rst b/peps/pep-0613.rst similarity index 100% rename from pep-0613.rst rename to peps/pep-0613.rst diff --git a/pep-0614.rst b/peps/pep-0614.rst similarity index 100% rename from pep-0614.rst rename to peps/pep-0614.rst diff --git a/pep-0615.rst b/peps/pep-0615.rst similarity index 100% rename from pep-0615.rst rename to peps/pep-0615.rst diff --git a/pep-0616.rst b/peps/pep-0616.rst similarity index 100% rename from pep-0616.rst rename to peps/pep-0616.rst diff --git a/pep-0617.rst b/peps/pep-0617.rst similarity index 100% rename from pep-0617.rst rename to peps/pep-0617.rst diff --git a/pep-0618.rst b/peps/pep-0618.rst similarity index 100% rename from pep-0618.rst rename to peps/pep-0618.rst diff --git a/pep-0619.rst b/peps/pep-0619.rst similarity index 100% rename from pep-0619.rst rename to peps/pep-0619.rst diff --git a/pep-0620.rst b/peps/pep-0620.rst similarity index 100% rename from pep-0620.rst rename to peps/pep-0620.rst diff --git a/pep-0621.rst b/peps/pep-0621.rst similarity index 100% rename from pep-0621.rst rename to peps/pep-0621.rst diff --git a/pep-0622.rst b/peps/pep-0622.rst similarity index 100% rename from pep-0622.rst rename to peps/pep-0622.rst diff --git a/pep-0623.rst b/peps/pep-0623.rst similarity index 100% rename from pep-0623.rst rename to peps/pep-0623.rst diff --git a/pep-0624.rst b/peps/pep-0624.rst similarity index 100% rename from pep-0624.rst rename to peps/pep-0624.rst diff --git a/pep-0625.rst b/peps/pep-0625.rst similarity index 100% rename from pep-0625.rst rename to peps/pep-0625.rst diff --git a/pep-0626.rst b/peps/pep-0626.rst similarity index 100% rename from pep-0626.rst rename to peps/pep-0626.rst diff --git a/pep-0627.rst b/peps/pep-0627.rst similarity index 100% rename from pep-0627.rst rename to peps/pep-0627.rst diff --git a/pep-0628.txt b/peps/pep-0628.rst similarity index 100% rename from pep-0628.txt rename to peps/pep-0628.rst diff --git a/pep-0629.rst b/peps/pep-0629.rst similarity index 100% rename from pep-0629.rst rename to peps/pep-0629.rst diff --git a/pep-0630.rst b/peps/pep-0630.rst similarity index 100% rename from pep-0630.rst rename to peps/pep-0630.rst diff --git a/pep-0631.rst b/peps/pep-0631.rst similarity index 100% rename from pep-0631.rst rename to peps/pep-0631.rst diff --git a/pep-0632.rst b/peps/pep-0632.rst similarity index 100% rename from pep-0632.rst rename to peps/pep-0632.rst diff --git a/pep-0633.rst b/peps/pep-0633.rst similarity index 100% rename from pep-0633.rst rename to peps/pep-0633.rst diff --git a/pep-0634.rst b/peps/pep-0634.rst similarity index 100% rename from pep-0634.rst rename to peps/pep-0634.rst diff --git a/pep-0635.rst b/peps/pep-0635.rst similarity index 100% rename from pep-0635.rst rename to peps/pep-0635.rst diff --git a/pep-0636.rst b/peps/pep-0636.rst similarity index 100% rename from pep-0636.rst rename to peps/pep-0636.rst diff --git a/pep-0637.rst b/peps/pep-0637.rst similarity index 100% rename from pep-0637.rst rename to peps/pep-0637.rst diff --git a/pep-0638.rst b/peps/pep-0638.rst similarity index 100% rename from pep-0638.rst rename to peps/pep-0638.rst diff --git a/pep-0639.rst b/peps/pep-0639.rst similarity index 100% rename from pep-0639.rst rename to peps/pep-0639.rst diff --git a/pep-0640.rst b/peps/pep-0640.rst similarity index 100% rename from pep-0640.rst rename to peps/pep-0640.rst diff --git a/pep-0641.rst b/peps/pep-0641.rst similarity index 100% rename from pep-0641.rst rename to peps/pep-0641.rst diff --git a/pep-0642.rst b/peps/pep-0642.rst similarity index 100% rename from pep-0642.rst rename to peps/pep-0642.rst diff --git a/pep-0643.rst b/peps/pep-0643.rst similarity index 100% rename from pep-0643.rst rename to peps/pep-0643.rst diff --git a/pep-0644.rst b/peps/pep-0644.rst similarity index 100% rename from pep-0644.rst rename to peps/pep-0644.rst diff --git a/pep-0645.rst b/peps/pep-0645.rst similarity index 100% rename from pep-0645.rst rename to peps/pep-0645.rst diff --git a/pep-0646.rst b/peps/pep-0646.rst similarity index 100% rename from pep-0646.rst rename to peps/pep-0646.rst diff --git a/pep-0647.rst b/peps/pep-0647.rst similarity index 100% rename from pep-0647.rst rename to peps/pep-0647.rst diff --git a/pep-0648.rst b/peps/pep-0648.rst similarity index 100% rename from pep-0648.rst rename to peps/pep-0648.rst diff --git a/pep-0649.rst b/peps/pep-0649.rst similarity index 100% rename from pep-0649.rst rename to peps/pep-0649.rst diff --git a/pep-0650.rst b/peps/pep-0650.rst similarity index 100% rename from pep-0650.rst rename to peps/pep-0650.rst diff --git a/pep-0651.rst b/peps/pep-0651.rst similarity index 100% rename from pep-0651.rst rename to peps/pep-0651.rst diff --git a/pep-0652.rst b/peps/pep-0652.rst similarity index 100% rename from pep-0652.rst rename to peps/pep-0652.rst diff --git a/pep-0653.rst b/peps/pep-0653.rst similarity index 100% rename from pep-0653.rst rename to peps/pep-0653.rst diff --git a/pep-0654.rst b/peps/pep-0654.rst similarity index 100% rename from pep-0654.rst rename to peps/pep-0654.rst diff --git a/pep-0655.rst b/peps/pep-0655.rst similarity index 100% rename from pep-0655.rst rename to peps/pep-0655.rst diff --git a/pep-0656.rst b/peps/pep-0656.rst similarity index 100% rename from pep-0656.rst rename to peps/pep-0656.rst diff --git a/pep-0657.rst b/peps/pep-0657.rst similarity index 100% rename from pep-0657.rst rename to peps/pep-0657.rst diff --git a/pep-0658.rst b/peps/pep-0658.rst similarity index 100% rename from pep-0658.rst rename to peps/pep-0658.rst diff --git a/pep-0659.rst b/peps/pep-0659.rst similarity index 100% rename from pep-0659.rst rename to peps/pep-0659.rst diff --git a/pep-0660.rst b/peps/pep-0660.rst similarity index 100% rename from pep-0660.rst rename to peps/pep-0660.rst diff --git a/pep-0661.rst b/peps/pep-0661.rst similarity index 100% rename from pep-0661.rst rename to peps/pep-0661.rst diff --git a/pep-0662.rst b/peps/pep-0662.rst similarity index 100% rename from pep-0662.rst rename to peps/pep-0662.rst diff --git a/pep-0662/pep-0662-editable.json b/peps/pep-0662/pep-0662-editable.json similarity index 100% rename from pep-0662/pep-0662-editable.json rename to peps/pep-0662/pep-0662-editable.json diff --git a/pep-0663.txt b/peps/pep-0663.rst similarity index 100% rename from pep-0663.txt rename to peps/pep-0663.rst diff --git a/pep-0664.rst b/peps/pep-0664.rst similarity index 100% rename from pep-0664.rst rename to peps/pep-0664.rst diff --git a/pep-0665.rst b/peps/pep-0665.rst similarity index 100% rename from pep-0665.rst rename to peps/pep-0665.rst diff --git a/pep-0666.txt b/peps/pep-0666.rst similarity index 100% rename from pep-0666.txt rename to peps/pep-0666.rst diff --git a/pep-0667.rst b/peps/pep-0667.rst similarity index 100% rename from pep-0667.rst rename to peps/pep-0667.rst diff --git a/pep-0668.rst b/peps/pep-0668.rst similarity index 100% rename from pep-0668.rst rename to peps/pep-0668.rst diff --git a/pep-0669.rst b/peps/pep-0669.rst similarity index 100% rename from pep-0669.rst rename to peps/pep-0669.rst diff --git a/pep-0670.rst b/peps/pep-0670.rst similarity index 100% rename from pep-0670.rst rename to peps/pep-0670.rst diff --git a/pep-0671.rst b/peps/pep-0671.rst similarity index 100% rename from pep-0671.rst rename to peps/pep-0671.rst diff --git a/pep-0672.rst b/peps/pep-0672.rst similarity index 100% rename from pep-0672.rst rename to peps/pep-0672.rst diff --git a/pep-0673.rst b/peps/pep-0673.rst similarity index 100% rename from pep-0673.rst rename to peps/pep-0673.rst diff --git a/pep-0674.rst b/peps/pep-0674.rst similarity index 100% rename from pep-0674.rst rename to peps/pep-0674.rst diff --git a/pep-0675.rst b/peps/pep-0675.rst similarity index 100% rename from pep-0675.rst rename to peps/pep-0675.rst diff --git a/pep-0676.rst b/peps/pep-0676.rst similarity index 100% rename from pep-0676.rst rename to peps/pep-0676.rst diff --git a/pep-0677.rst b/peps/pep-0677.rst similarity index 100% rename from pep-0677.rst rename to peps/pep-0677.rst diff --git a/pep-0678.rst b/peps/pep-0678.rst similarity index 100% rename from pep-0678.rst rename to peps/pep-0678.rst diff --git a/pep-0679.rst b/peps/pep-0679.rst similarity index 100% rename from pep-0679.rst rename to peps/pep-0679.rst diff --git a/pep-0680.rst b/peps/pep-0680.rst similarity index 100% rename from pep-0680.rst rename to peps/pep-0680.rst diff --git a/pep-0681.rst b/peps/pep-0681.rst similarity index 100% rename from pep-0681.rst rename to peps/pep-0681.rst diff --git a/pep-0682.rst b/peps/pep-0682.rst similarity index 100% rename from pep-0682.rst rename to peps/pep-0682.rst diff --git a/pep-0683.rst b/peps/pep-0683.rst similarity index 100% rename from pep-0683.rst rename to peps/pep-0683.rst diff --git a/pep-0684.rst b/peps/pep-0684.rst similarity index 100% rename from pep-0684.rst rename to peps/pep-0684.rst diff --git a/pep-0685.rst b/peps/pep-0685.rst similarity index 100% rename from pep-0685.rst rename to peps/pep-0685.rst diff --git a/pep-0686.rst b/peps/pep-0686.rst similarity index 100% rename from pep-0686.rst rename to peps/pep-0686.rst diff --git a/pep-0687.rst b/peps/pep-0687.rst similarity index 100% rename from pep-0687.rst rename to peps/pep-0687.rst diff --git a/pep-0688.rst b/peps/pep-0688.rst similarity index 100% rename from pep-0688.rst rename to peps/pep-0688.rst diff --git a/pep-0689.rst b/peps/pep-0689.rst similarity index 100% rename from pep-0689.rst rename to peps/pep-0689.rst diff --git a/pep-0690.rst b/peps/pep-0690.rst similarity index 100% rename from pep-0690.rst rename to peps/pep-0690.rst diff --git a/pep-0691.rst b/peps/pep-0691.rst similarity index 100% rename from pep-0691.rst rename to peps/pep-0691.rst diff --git a/pep-0692.rst b/peps/pep-0692.rst similarity index 100% rename from pep-0692.rst rename to peps/pep-0692.rst diff --git a/pep-0693.rst b/peps/pep-0693.rst similarity index 100% rename from pep-0693.rst rename to peps/pep-0693.rst diff --git a/pep-0694.rst b/peps/pep-0694.rst similarity index 100% rename from pep-0694.rst rename to peps/pep-0694.rst diff --git a/pep-0695.rst b/peps/pep-0695.rst similarity index 100% rename from pep-0695.rst rename to peps/pep-0695.rst diff --git a/pep-0696.rst b/peps/pep-0696.rst similarity index 100% rename from pep-0696.rst rename to peps/pep-0696.rst diff --git a/pep-0697.rst b/peps/pep-0697.rst similarity index 100% rename from pep-0697.rst rename to peps/pep-0697.rst diff --git a/pep-0698.rst b/peps/pep-0698.rst similarity index 100% rename from pep-0698.rst rename to peps/pep-0698.rst diff --git a/pep-0699.rst b/peps/pep-0699.rst similarity index 100% rename from pep-0699.rst rename to peps/pep-0699.rst diff --git a/pep-0700.rst b/peps/pep-0700.rst similarity index 100% rename from pep-0700.rst rename to peps/pep-0700.rst diff --git a/pep-0701.rst b/peps/pep-0701.rst similarity index 100% rename from pep-0701.rst rename to peps/pep-0701.rst diff --git a/pep-0702.rst b/peps/pep-0702.rst similarity index 100% rename from pep-0702.rst rename to peps/pep-0702.rst diff --git a/pep-0703.rst b/peps/pep-0703.rst similarity index 100% rename from pep-0703.rst rename to peps/pep-0703.rst diff --git a/pep-0704.rst b/peps/pep-0704.rst similarity index 100% rename from pep-0704.rst rename to peps/pep-0704.rst diff --git a/pep-0705.rst b/peps/pep-0705.rst similarity index 100% rename from pep-0705.rst rename to peps/pep-0705.rst diff --git a/pep-0706.rst b/peps/pep-0706.rst similarity index 100% rename from pep-0706.rst rename to peps/pep-0706.rst diff --git a/pep-0707.rst b/peps/pep-0707.rst similarity index 100% rename from pep-0707.rst rename to peps/pep-0707.rst diff --git a/pep-0708.rst b/peps/pep-0708.rst similarity index 100% rename from pep-0708.rst rename to peps/pep-0708.rst diff --git a/pep-0709.rst b/peps/pep-0709.rst similarity index 100% rename from pep-0709.rst rename to peps/pep-0709.rst diff --git a/pep-0710.rst b/peps/pep-0710.rst similarity index 100% rename from pep-0710.rst rename to peps/pep-0710.rst diff --git a/pep-0711.rst b/peps/pep-0711.rst similarity index 100% rename from pep-0711.rst rename to peps/pep-0711.rst diff --git a/pep-0712.rst b/peps/pep-0712.rst similarity index 100% rename from pep-0712.rst rename to peps/pep-0712.rst diff --git a/pep-0713.rst b/peps/pep-0713.rst similarity index 100% rename from pep-0713.rst rename to peps/pep-0713.rst diff --git a/pep-0714.rst b/peps/pep-0714.rst similarity index 100% rename from pep-0714.rst rename to peps/pep-0714.rst diff --git a/pep-0715.rst b/peps/pep-0715.rst similarity index 100% rename from pep-0715.rst rename to peps/pep-0715.rst diff --git a/pep-0718.rst b/peps/pep-0718.rst similarity index 100% rename from pep-0718.rst rename to peps/pep-0718.rst diff --git a/pep-0719.rst b/peps/pep-0719.rst similarity index 100% rename from pep-0719.rst rename to peps/pep-0719.rst diff --git a/pep-0720.rst b/peps/pep-0720.rst similarity index 100% rename from pep-0720.rst rename to peps/pep-0720.rst diff --git a/pep-0721.rst b/peps/pep-0721.rst similarity index 100% rename from pep-0721.rst rename to peps/pep-0721.rst diff --git a/pep-0722.rst b/peps/pep-0722.rst similarity index 100% rename from pep-0722.rst rename to peps/pep-0722.rst diff --git a/pep-0723.rst b/peps/pep-0723.rst similarity index 100% rename from pep-0723.rst rename to peps/pep-0723.rst diff --git a/pep-0725.rst b/peps/pep-0725.rst similarity index 100% rename from pep-0725.rst rename to peps/pep-0725.rst diff --git a/pep-0726.rst b/peps/pep-0726.rst similarity index 100% rename from pep-0726.rst rename to peps/pep-0726.rst diff --git a/pep-0727.rst b/peps/pep-0727.rst similarity index 100% rename from pep-0727.rst rename to peps/pep-0727.rst diff --git a/pep-0754.txt b/peps/pep-0754.rst similarity index 100% rename from pep-0754.txt rename to peps/pep-0754.rst diff --git a/pep-0801.rst b/peps/pep-0801.rst similarity index 100% rename from pep-0801.rst rename to peps/pep-0801.rst diff --git a/pep-3000.txt b/peps/pep-3000.rst similarity index 100% rename from pep-3000.txt rename to peps/pep-3000.rst diff --git a/pep-3001.txt b/peps/pep-3001.rst similarity index 100% rename from pep-3001.txt rename to peps/pep-3001.rst diff --git a/pep-3002.txt b/peps/pep-3002.rst similarity index 100% rename from pep-3002.txt rename to peps/pep-3002.rst diff --git a/pep-3003.txt b/peps/pep-3003.rst similarity index 100% rename from pep-3003.txt rename to peps/pep-3003.rst diff --git a/pep-3099.txt b/peps/pep-3099.rst similarity index 100% rename from pep-3099.txt rename to peps/pep-3099.rst diff --git a/pep-3100.txt b/peps/pep-3100.rst similarity index 100% rename from pep-3100.txt rename to peps/pep-3100.rst diff --git a/pep-3101.txt b/peps/pep-3101.rst similarity index 100% rename from pep-3101.txt rename to peps/pep-3101.rst diff --git a/pep-3102.txt b/peps/pep-3102.rst similarity index 100% rename from pep-3102.txt rename to peps/pep-3102.rst diff --git a/pep-3103.txt b/peps/pep-3103.rst similarity index 100% rename from pep-3103.txt rename to peps/pep-3103.rst diff --git a/pep-3104.txt b/peps/pep-3104.rst similarity index 100% rename from pep-3104.txt rename to peps/pep-3104.rst diff --git a/pep-3105.txt b/peps/pep-3105.rst similarity index 100% rename from pep-3105.txt rename to peps/pep-3105.rst diff --git a/pep-3106.txt b/peps/pep-3106.rst similarity index 100% rename from pep-3106.txt rename to peps/pep-3106.rst diff --git a/pep-3107.txt b/peps/pep-3107.rst similarity index 100% rename from pep-3107.txt rename to peps/pep-3107.rst diff --git a/pep-3108.txt b/peps/pep-3108.rst similarity index 100% rename from pep-3108.txt rename to peps/pep-3108.rst diff --git a/pep-3109.txt b/peps/pep-3109.rst similarity index 100% rename from pep-3109.txt rename to peps/pep-3109.rst diff --git a/pep-3110.txt b/peps/pep-3110.rst similarity index 100% rename from pep-3110.txt rename to peps/pep-3110.rst diff --git a/pep-3111.txt b/peps/pep-3111.rst similarity index 100% rename from pep-3111.txt rename to peps/pep-3111.rst diff --git a/pep-3112.txt b/peps/pep-3112.rst similarity index 100% rename from pep-3112.txt rename to peps/pep-3112.rst diff --git a/pep-3113.txt b/peps/pep-3113.rst similarity index 100% rename from pep-3113.txt rename to peps/pep-3113.rst diff --git a/pep-3114.txt b/peps/pep-3114.rst similarity index 100% rename from pep-3114.txt rename to peps/pep-3114.rst diff --git a/pep-3115.txt b/peps/pep-3115.rst similarity index 100% rename from pep-3115.txt rename to peps/pep-3115.rst diff --git a/pep-3116.txt b/peps/pep-3116.rst similarity index 100% rename from pep-3116.txt rename to peps/pep-3116.rst diff --git a/pep-3117.txt b/peps/pep-3117.rst similarity index 100% rename from pep-3117.txt rename to peps/pep-3117.rst diff --git a/pep-3118.txt b/peps/pep-3118.rst similarity index 100% rename from pep-3118.txt rename to peps/pep-3118.rst diff --git a/pep-3119.txt b/peps/pep-3119.rst similarity index 100% rename from pep-3119.txt rename to peps/pep-3119.rst diff --git a/pep-3120.txt b/peps/pep-3120.rst similarity index 100% rename from pep-3120.txt rename to peps/pep-3120.rst diff --git a/pep-3121.txt b/peps/pep-3121.rst similarity index 100% rename from pep-3121.txt rename to peps/pep-3121.rst diff --git a/pep-3122.txt b/peps/pep-3122.rst similarity index 100% rename from pep-3122.txt rename to peps/pep-3122.rst diff --git a/pep-3123.txt b/peps/pep-3123.rst similarity index 100% rename from pep-3123.txt rename to peps/pep-3123.rst diff --git a/pep-3124.txt b/peps/pep-3124.rst similarity index 100% rename from pep-3124.txt rename to peps/pep-3124.rst diff --git a/pep-3125.txt b/peps/pep-3125.rst similarity index 100% rename from pep-3125.txt rename to peps/pep-3125.rst diff --git a/pep-3126.txt b/peps/pep-3126.rst similarity index 100% rename from pep-3126.txt rename to peps/pep-3126.rst diff --git a/pep-3127.txt b/peps/pep-3127.rst similarity index 100% rename from pep-3127.txt rename to peps/pep-3127.rst diff --git a/pep-3128.txt b/peps/pep-3128.rst similarity index 100% rename from pep-3128.txt rename to peps/pep-3128.rst diff --git a/pep-3129.txt b/peps/pep-3129.rst similarity index 100% rename from pep-3129.txt rename to peps/pep-3129.rst diff --git a/pep-3130.txt b/peps/pep-3130.rst similarity index 100% rename from pep-3130.txt rename to peps/pep-3130.rst diff --git a/pep-3131.txt b/peps/pep-3131.rst similarity index 100% rename from pep-3131.txt rename to peps/pep-3131.rst diff --git a/pep-3132.txt b/peps/pep-3132.rst similarity index 100% rename from pep-3132.txt rename to peps/pep-3132.rst diff --git a/pep-3133.txt b/peps/pep-3133.rst similarity index 100% rename from pep-3133.txt rename to peps/pep-3133.rst diff --git a/pep-3134.txt b/peps/pep-3134.rst similarity index 100% rename from pep-3134.txt rename to peps/pep-3134.rst diff --git a/pep-3135.txt b/peps/pep-3135.rst similarity index 100% rename from pep-3135.txt rename to peps/pep-3135.rst diff --git a/pep-3136.txt b/peps/pep-3136.rst similarity index 100% rename from pep-3136.txt rename to peps/pep-3136.rst diff --git a/pep-3137.txt b/peps/pep-3137.rst similarity index 100% rename from pep-3137.txt rename to peps/pep-3137.rst diff --git a/pep-3138.txt b/peps/pep-3138.rst similarity index 100% rename from pep-3138.txt rename to peps/pep-3138.rst diff --git a/pep-3139.txt b/peps/pep-3139.rst similarity index 100% rename from pep-3139.txt rename to peps/pep-3139.rst diff --git a/pep-3140.txt b/peps/pep-3140.rst similarity index 100% rename from pep-3140.txt rename to peps/pep-3140.rst diff --git a/pep-3141.txt b/peps/pep-3141.rst similarity index 100% rename from pep-3141.txt rename to peps/pep-3141.rst diff --git a/pep-3142.txt b/peps/pep-3142.rst similarity index 100% rename from pep-3142.txt rename to peps/pep-3142.rst diff --git a/pep-3143.txt b/peps/pep-3143.rst similarity index 100% rename from pep-3143.txt rename to peps/pep-3143.rst diff --git a/pep-3144.txt b/peps/pep-3144.rst similarity index 100% rename from pep-3144.txt rename to peps/pep-3144.rst diff --git a/pep-3145.txt b/peps/pep-3145.rst similarity index 100% rename from pep-3145.txt rename to peps/pep-3145.rst diff --git a/pep-3146.txt b/peps/pep-3146.rst similarity index 100% rename from pep-3146.txt rename to peps/pep-3146.rst diff --git a/pep-3147-1.dia b/peps/pep-3147-1.dia similarity index 100% rename from pep-3147-1.dia rename to peps/pep-3147-1.dia diff --git a/pep-3147-1.png b/peps/pep-3147-1.png similarity index 100% rename from pep-3147-1.png rename to peps/pep-3147-1.png diff --git a/pep-3147.txt b/peps/pep-3147.rst similarity index 100% rename from pep-3147.txt rename to peps/pep-3147.rst diff --git a/pep-3148.txt b/peps/pep-3148.rst similarity index 100% rename from pep-3148.txt rename to peps/pep-3148.rst diff --git a/pep-3149.txt b/peps/pep-3149.rst similarity index 100% rename from pep-3149.txt rename to peps/pep-3149.rst diff --git a/pep-3150.txt b/peps/pep-3150.rst similarity index 100% rename from pep-3150.txt rename to peps/pep-3150.rst diff --git a/pep-3151.txt b/peps/pep-3151.rst similarity index 100% rename from pep-3151.txt rename to peps/pep-3151.rst diff --git a/pep-3152.txt b/peps/pep-3152.rst similarity index 100% rename from pep-3152.txt rename to peps/pep-3152.rst diff --git a/pep-3153.txt b/peps/pep-3153.rst similarity index 100% rename from pep-3153.txt rename to peps/pep-3153.rst diff --git a/pep-3154.txt b/peps/pep-3154.rst similarity index 100% rename from pep-3154.txt rename to peps/pep-3154.rst diff --git a/pep-3155.txt b/peps/pep-3155.rst similarity index 100% rename from pep-3155.txt rename to peps/pep-3155.rst diff --git a/pep-3156.txt b/peps/pep-3156.rst similarity index 100% rename from pep-3156.txt rename to peps/pep-3156.rst diff --git a/pep-3333.txt b/peps/pep-3333.rst similarity index 100% rename from pep-3333.txt rename to peps/pep-3333.rst diff --git a/pep-8000.rst b/peps/pep-8000.rst similarity index 100% rename from pep-8000.rst rename to peps/pep-8000.rst diff --git a/pep-8001.rst b/peps/pep-8001.rst similarity index 100% rename from pep-8001.rst rename to peps/pep-8001.rst diff --git a/pep-8002.rst b/peps/pep-8002.rst similarity index 100% rename from pep-8002.rst rename to peps/pep-8002.rst diff --git a/pep-8010.rst b/peps/pep-8010.rst similarity index 100% rename from pep-8010.rst rename to peps/pep-8010.rst diff --git a/pep-8011.rst b/peps/pep-8011.rst similarity index 100% rename from pep-8011.rst rename to peps/pep-8011.rst diff --git a/pep-8012.rst b/peps/pep-8012.rst similarity index 100% rename from pep-8012.rst rename to peps/pep-8012.rst diff --git a/pep-8013.rst b/peps/pep-8013.rst similarity index 100% rename from pep-8013.rst rename to peps/pep-8013.rst diff --git a/pep-8014.rst b/peps/pep-8014.rst similarity index 100% rename from pep-8014.rst rename to peps/pep-8014.rst diff --git a/pep-8015.rst b/peps/pep-8015.rst similarity index 100% rename from pep-8015.rst rename to peps/pep-8015.rst diff --git a/pep-8016.rst b/peps/pep-8016.rst similarity index 100% rename from pep-8016.rst rename to peps/pep-8016.rst diff --git a/pep-8100.rst b/peps/pep-8100.rst similarity index 100% rename from pep-8100.rst rename to peps/pep-8100.rst diff --git a/pep-8101.rst b/peps/pep-8101.rst similarity index 100% rename from pep-8101.rst rename to peps/pep-8101.rst diff --git a/pep-8102.rst b/peps/pep-8102.rst similarity index 100% rename from pep-8102.rst rename to peps/pep-8102.rst diff --git a/pep-8103.rst b/peps/pep-8103.rst similarity index 100% rename from pep-8103.rst rename to peps/pep-8103.rst diff --git a/pep-8104.rst b/peps/pep-8104.rst similarity index 100% rename from pep-8104.rst rename to peps/pep-8104.rst From 233cd5e06508377574ef64663809069485928b40 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 9 Sep 2023 19:58:51 +0100 Subject: [PATCH 115/173] Meta: Instruct linguist to include PEPs in the statistics (#3430) --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitattributes b/.gitattributes index f3bffe3c0..6107f6104 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,7 @@ *.png binary *.pptx binary *.odp binary + +# Instruct linguist not to ignore the PEPs +# https://github.com/github-linguist/linguist/blob/master/docs/overrides.md +peps/*.rst text linguist-detectable From 2868fe9c84814d685ee92970594d8e3bbb571b16 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Sun, 10 Sep 2023 09:04:40 -0600 Subject: [PATCH 116/173] Lint: Update Ruff config (#3433) --- .github/workflows/lint.yml | 1 + .pre-commit-config.yaml | 20 +++++++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2d29bf2f5..fc096a0cd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,6 +14,7 @@ concurrency: env: FORCE_COLOR: 1 + RUFF_FORMAT: github jobs: pre-commit: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 81d21c8e4..b1c1602fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,17 +42,6 @@ repos: - id: check-yaml name: "Check YAML" - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.287 - hooks: - - id: ruff - name: "Lint with Ruff" - args: - - '--exit-non-zero-on-fix' - - '--diff' - - '--format=github' - files: '^pep_sphinx_extensions/tests/' - - repo: https://github.com/psf/black rev: 23.7.0 hooks: @@ -63,6 +52,15 @@ repos: - '--target-version=py310' files: 'pep_sphinx_extensions/tests/.*' + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.287 + hooks: + - id: ruff + name: "Lint with Ruff" + args: + - '--exit-non-zero-on-fix' + files: '^pep_sphinx_extensions/tests/' + - repo: https://github.com/tox-dev/tox-ini-fmt rev: 1.3.1 hooks: From 94ac1294957bd8c21b113c235be44fd0118dd7d7 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe <gobot1234yt@gmail.com> Date: Thu, 14 Sep 2023 14:33:43 +0100 Subject: [PATCH 117/173] PEP 696: Add section on binding rules (#3427) --- peps/pep-0696.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/peps/pep-0696.rst b/peps/pep-0696.rst index ce1678adc..7e8f7f1e1 100644 --- a/peps/pep-0696.rst +++ b/peps/pep-0696.rst @@ -382,6 +382,21 @@ Function Defaults functions as ensuring the ``default`` is returned in every code path where the ``TypeVarLike`` can go unsolved is too hard to implement. +Binding rules +------------- + +``TypeVarLikes`` defaults should be bound by attribute access +(including call and subscript). + +.. code-block:: python + + class Foo[T = int]: + def meth(self) -> Self: + return self + + reveal_type(Foo.meth) # type is (self: Foo[int]) -> Foo[int] + + Implementation -------------- From 48306604c88f36b82474ec0ef2c2300af87479cc Mon Sep 17 00:00:00 2001 From: Rich Chiodo <rchiodo@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:38:31 -0700 Subject: [PATCH 118/173] PEP 724: Stricter TypeGuard (#3266) Co-authored-by: Erik De Bonte <erikd@microsoft.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- .github/CODEOWNERS | 1 + peps/pep-0724.rst | 331 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100644 peps/pep-0724.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 242084ab2..15fc5c5bd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -602,6 +602,7 @@ peps/pep-0720.rst @FFY00 peps/pep-0721.rst @encukou peps/pep-0722.rst @pfmoore peps/pep-0723.rst @AA-Turner +peps/pep-0724.rst @jellezijlstra peps/pep-0725.rst @pradyunsg peps/pep-0726.rst @AA-Turner peps/pep-0727.rst @JelleZijlstra diff --git a/peps/pep-0724.rst b/peps/pep-0724.rst new file mode 100644 index 000000000..00d3eb7fd --- /dev/null +++ b/peps/pep-0724.rst @@ -0,0 +1,331 @@ +PEP: 724 +Title: Stricter Type Guards +Author: Rich Chiodo <rchiodo at microsoft.com>, + Eric Traut <erictr at microsoft.com>, + Erik De Bonte <erikd at microsoft.com>, +Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com> +Discussions-To: https://mail.python.org/archives/list/typing-sig@python.org/thread/7KZ2VUDXZ5UKAUHRNXBJYBENAYMT6WXN/ +Status: Draft +Type: Standards Track +Topic: Typing +Content-Type: text/x-rst +Created: 28-Jul-2023 +Python-Version: 3.13 +Post-History: `30-Dec-2021 <https://mail.python.org/archives/list/typing-sig@python.org/thread/EMUD2D424OI53DCWQ4H5L6SJD2IXBHUL/>`__ + + +Abstract +======== + +:pep:`647` introduced the concept of a user-defined type guard function which +returns ``True`` if the type of the expression passed to its first parameter +matches its return ``TypeGuard`` type. For example, a function that has a +return type of ``TypeGuard[str]`` is assumed to return ``True`` if and only if +the type of the expression passed to its first input parameter is a ``str``. +This allows type checkers to narrow types when a user-defined type guard +function returns ``True``. + +This PEP refines the ``TypeGuard`` mechanism introduced in :pep:`647`. It +allows type checkers to narrow types when a user-defined type guard function +returns ``False``. It also allows type checkers to apply additional (more +precise) type narrowing under certain circumstances when the type guard +function returns ``True``. + + +Motivation +========== + +User-defined type guard functions enable a type checker to narrow the type of +an expression when it is passed as an argument to the type guard function. The +``TypeGuard`` mechanism introduced in :pep:`647` is flexible, but this +flexibility imposes some limitations that developers have found inconvenient +for some uses. + +Limitation 1: Type checkers are not allowed to narrow a type in the case where +the type guard function returns ``False``. This means the type is not narrowed +in the negative ("else") clause. + +Limitation 2: Type checkers must use the ``TypeGuard`` return type if the type +guard function returns ``True`` regardless of whether additional narrowing can +be applied based on knowledge of the pre-narrowed type. + +The following code sample demonstrates both of these limitations. + +.. code-block:: python + + def is_iterable(val: object) -> TypeGuard[Iterable[Any]]: + return isinstance(val, Iterable) + + def func(val: int | list[int]): + if is_iterable(val): + # The type is narrowed to 'Iterable[Any]' as dictated by + # the TypeGuard return type + reveal_type(val) # Iterable[Any] + else: + # The type is not narrowed in the "False" case + reveal_type(val) # int | list[int] + + # If "isinstance" is used in place of the user-defined type guard + # function, the results differ because type checkers apply additional + # logic for "isinstance" + + if isinstance(val, Iterable): + # Type is narrowed to "list[int]" because this is + # a narrower (more precise) type than "Iterable[Any]" + reveal_type(val) # list[int] + else: + # Type is narrowed to "int" because the logic eliminates + # "list[int]" from the original union + reveal_type(val) # int + + +:pep:`647` imposed these limitations so it could support use cases where the +return ``TypeGuard`` type was not a subtype of the input type. Refer to +:pep:`647` for examples. + + +Specification +============= + +The use of a user-defined type guard function involves five types: + +* I = ``TypeGuard`` input type +* R = ``TypeGuard`` return type +* A = Type of argument passed to type guard function (pre-narrowed) +* NP = Narrowed type (positive) +* NN = Narrowed type (negative) + +.. code-block:: python + + def guard(x: I) -> TypeGuard[R]: ... + + def func1(val: A): + if guard(val): + reveal_type(val) # NP + else: + reveal_type(val) # NN + + +This PEP proposes some modifications to :pep:`647` to address the limitations +discussed above. These limitations are safe to eliminate only when a specific +condition is met. In particular, when the output type ``R`` of a user-defined +type guard function is consistent [#isconsistent]_ with the type of its first +input parameter (``I``), type checkers should apply stricter type guard +semantics. + + .. code-block:: python + + # Stricter type guard semantics are used in this case because + # "Kangaroo | Koala" is consistent with "Animal" + def is_marsupial(val: Animal) -> TypeGuard[Kangaroo | Koala]: + return isinstance(val, Kangaroo | Koala) + + # Stricter type guard semantics are not used in this case because + # "list[T]"" is not consistent with "list[T | None]" + def has_no_nones(val: list[T | None]) -> TypeGuard[list[T]]: + return None not in val + +When stricter type guard semantics are applied, the application of a +user-defined type guard function changes in two ways. + +* Type narrowing is applied in the negative ("else") case. + +.. code-block:: python + + def is_str(val: str | int) -> TypeGuard[str]: + return isinstance(val, str) + + def func(val: str | int): + if not is_str(val): + reveal_type(val) # int + +* Additional type narrowing is applied in the positive "if" case if applicable. + +.. code-block:: python + + def is_cardinal_direction(val: str) -> TypeGuard[Literal["N", "S", "E", "W"]]: + return val in ("N", "S", "E", "W") + + def func(direction: Literal["NW", "E"]): + if is_cardinal_direction(direction): + reveal_type(direction) # "Literal[E]" + else: + reveal_type(direction) # "Literal[NW]" + + +The type-theoretic rules for type narrowing are specificed in the following +table. + +============ ======================= =================== +\ Non-strict type guard Strict type guard +============ ======================= =================== +Applies when R not consistent with I R consistent with I +NP is .. :math:`R` :math:`A \land R` +NN is .. :math:`A` :math:`A \land \neg{R}` +============ ======================= =================== + +In practice, the theoretic types for strict type guards cannot be expressed +precisely in the Python type system. Type checkers should fall back on +practical approximations of these types. As a rule of thumb, a type checker +should use the same type narrowing logic -- and get results that are consistent +with -- its handling of "isinstance". This guidance allows for changes and +improvements if the type system is extended in the future. + + +Additional Examples +=================== + +``Any`` is consistent [#isconsistent]_ with any other type, which means +stricter semantics can be applied. + +.. code-block:: python + + # Stricter type guard semantics are used in this case because + # "str" is consistent with "Any" + def is_str(x: Any) -> TypeGuard[str]: + return isinstance(x, str) + + def test(x: float | str): + if is_str(x): + reveal_type(x) # str + else: + reveal_type(x) # float + + +Backwards Compatibility +======================= + +This PEP proposes to change the existing behavior of ``TypeGuard``. This has no +effect at runtime, but it does change the types evaluated by a type checker. + +.. code-block:: python + + def is_int(val: int | str) -> TypeGuard[int]: + return isinstance(val, int) + + def func(val: int | str): + if is_int(val): + reveal_type(val) # "int" + else: + reveal_type(val) # Previously "int | str", now "str" + + +This behavioral change results in different types evaluated by a type checker. +It could therefore produce new (or mask existing) type errors. + +Type checkers often improve narrowing logic or fix existing bugs in such logic, +so users of static typing will be used to this type of behavioral change. + +We also hypothesize that it is unlikely that existing typed Python code relies +on the current behavior of ``TypeGuard``. To validate our hypothesis, we +implemented the proposed change in pyright and ran this modified version on +roughly 25 typed code bases using `mypy primer`__ to see if there were any +differences in the output. As predicted, the behavioral change had minimal +impact. The only noteworthy change was that some ``# type: ignore`` comments +were no longer necessary, indicating that these code bases were already working +around the existing limitations of ``TypeGuard``. + +__ https://github.com/hauntsaninja/mypy_primer + +Breaking change +--------------- + +It is possible for a user-defined type guard function to rely on the old +behavior. Such type guard functions could break with the new behavior. + +.. code-block:: python + + def is_positive_int(val: int | str) -> TypeGuard[int]: + return isinstance(val, int) and val > 0 + + def func(val: int | str): + if is_positive_int(val): + reveal_type(val) # "int" + else: + # With the older behavior, the type of "val" is evaluated as + # "int | str"; with the new behavior, the type is narrowed to + # "str", which is perhaps not what was intended. + reveal_type(val) + +We think it is unlikley that such user-defined type guards exist in real-world +code. The mypy primer results didn't uncover any such cases. + + +How to Teach This +================= + +Users unfamiliar with ``TypeGuard`` are likely to expect the behavior outlined +in this PEP, therefore making ``TypeGuard`` easier to teach and explain. + + +Reference Implementation +======================== + +A reference `implementation`__ of this idea exists in pyright. + +__ https://github.com/microsoft/pyright/commit/9a5af798d726bd0612cebee7223676c39cf0b9b0 + +To enable the modified behavior, the configuration flag +``enableExperimentalFeatures`` must be set to true. This can be done on a +per-file basis by adding a comment: + +.. code-block:: python + + # pyright: enableExperimentalFeatures=true + + +Rejected Ideas +============== + +StrictTypeGuard +--------------- + +A new ``StrictTypeGuard`` construct was proposed. This alternative form would +be similar to a ``TypeGuard`` except it would apply stricter type guard +semantics. It would also enforce that the return type was consistent +[#isconsistent]_ with the input type. See this thread for details: +`StrictTypeGuard proposal`__ + +__ https://github.com/python/typing/discussions/1013#discussioncomment-1966238 + +This idea was rejected because it is unnecessary in most cases and added +unnecessary complexity. It would require the introduction of a new special +form, and developers would need to be educated about the subtle difference +between the two forms. + +TypeGuard with a second output type +----------------------------------- + +Another idea was proposed where ``TypeGuard`` could support a second optional +type argument that indicates the type that should be used for narrowing in the +negative ("else") case. + +.. code-block:: python + + def is_int(val: int | str) -> TypeGuard[int, str]: + return isinstance(val, int) + + +This idea was proposed `here`__. + +__ https://github.com/python/typing/issues/996 + +It was rejected because it was considered too complicated and addressed only +one of the two main limitations of ``TypeGuard``. Refer to this `thread`__ for +the full discussion. + +__ https://mail.python.org/archives/list/typing-sig@python.org/thread/EMUD2D424OI53DCWQ4H5L6SJD2IXBHUL + + +Footnotes +========= + +.. [#isconsistent] :pep:`PEP 483's discussion of is-consistent <483#summary-of-gradual-typing>` + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. + From 2a9d6a5fcfe660b83186eb200e60a3b39d285363 Mon Sep 17 00:00:00 2001 From: Sean O Brien <sean.obrien.2016@mumail.ie> Date: Tue, 19 Sep 2023 15:26:28 +0100 Subject: [PATCH 119/173] PEP 693: Add Python 3.12.0rc3 release date (#3443) Add Python 3.12.0rc3 release date. --- peps/pep-0693.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/peps/pep-0693.rst b/peps/pep-0693.rst index c5b11929c..092c798e2 100644 --- a/peps/pep-0693.rst +++ b/peps/pep-0693.rst @@ -57,6 +57,7 @@ Actual: - 3.12.0 beta 4: Tuesday, 2023-07-11 - 3.12.0 candidate 1: Sunday, 2023-08-06 - 3.12.0 candidate 2: Wednesday, 2023-09-06 +- 3.12.0 candidate 3: Tuesday, 2023-09-19 Expected: From 2c0c4b377cb054957b1c34676c9031204a965a31 Mon Sep 17 00:00:00 2001 From: Rich Chiodo <rchiodo@users.noreply.github.com> Date: Tue, 19 Sep 2023 09:42:25 -0700 Subject: [PATCH 120/173] PEP 724: Add the current Discussions-To thread (#3446) --- peps/pep-0724.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/peps/pep-0724.rst b/peps/pep-0724.rst index 00d3eb7fd..a6ae5a1d2 100644 --- a/peps/pep-0724.rst +++ b/peps/pep-0724.rst @@ -4,15 +4,15 @@ Author: Rich Chiodo <rchiodo at microsoft.com>, Eric Traut <erictr at microsoft.com>, Erik De Bonte <erikd at microsoft.com>, Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com> -Discussions-To: https://mail.python.org/archives/list/typing-sig@python.org/thread/7KZ2VUDXZ5UKAUHRNXBJYBENAYMT6WXN/ +Discussions-To: https://discuss.python.org/t/pep-724-stricter-type-guards/34124 Status: Draft Type: Standards Track Topic: Typing Content-Type: text/x-rst Created: 28-Jul-2023 Python-Version: 3.13 -Post-History: `30-Dec-2021 <https://mail.python.org/archives/list/typing-sig@python.org/thread/EMUD2D424OI53DCWQ4H5L6SJD2IXBHUL/>`__ - +Post-History: `30-Dec-2021 <https://mail.python.org/archives/list/typing-sig@python.org/thread/EMUD2D424OI53DCWQ4H5L6SJD2IXBHUL/>`__, + `19-Sep-2023 <https://discuss.python.org/t/pep-724-stricter-type-guards/34124>`__, Abstract ======== From c972a769231eee254f2802e7be1fe1f83520a344 Mon Sep 17 00:00:00 2001 From: Sam Gross <colesbury@gmail.com> Date: Tue, 19 Sep 2023 14:21:12 -0400 Subject: [PATCH 121/173] PEP 703: Use 't' for proposed ABI tag (#3445) --- peps/pep-0703.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0703.rst b/peps/pep-0703.rst index 1eb697caf..61fd12d66 100644 --- a/peps/pep-0703.rst +++ b/peps/pep-0703.rst @@ -330,8 +330,8 @@ and python.org downloads. A new build configuration flag, CPython with support for running without the global interpreter lock. When built with ``--disable-gil``, CPython will define the ``Py_NOGIL`` -macro in Python/patchlevel.h. The ABI tag will include the letter "n" -(for "nogil"). +macro in Python/patchlevel.h. The ABI tag will include the letter "t" +(for "threading"). The ``--disable-gil`` builds of CPython will still support optionally running with the GIL enabled at runtime (see `PYTHONGIL Environment From 00295ada362f190043e12d4ef85223b7c593ff6c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Tue, 19 Sep 2023 20:15:30 -0700 Subject: [PATCH 122/173] PEP 702: Move to warnings, expand spec (#3442) --- peps/pep-0702.rst | 64 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/peps/pep-0702.rst b/peps/pep-0702.rst index d1c4c1c2c..d81d42ad2 100644 --- a/peps/pep-0702.rst +++ b/peps/pep-0702.rst @@ -7,7 +7,7 @@ Type: Standards Track Topic: Typing Content-Type: text/x-rst Created: 30-Dec-2022 -Python-Version: 3.12 +Python-Version: 3.13 Post-History: `01-Jan-2023 <https://mail.python.org/archives/list/typing-sig@python.org/thread/AKTFUYW3WDT7R7PGRIJQZMYHMDJNE4QH/>`__, `22-Jan-2023 <https://discuss.python.org/t/pep-702-marking-deprecations-using-the-type-system/23036>`__ @@ -15,7 +15,7 @@ Post-History: `01-Jan-2023 <https://mail.python.org/archives/list/typing-sig@pyt Abstract ======== -This PEP adds an ``@typing.deprecated()`` decorator that marks a class or function +This PEP adds an ``@warnings.deprecated()`` decorator that marks a class or function as deprecated, enabling static checkers to warn when it is used. By default, this decorator will also raise a runtime ``DeprecationWarning``. @@ -99,7 +99,7 @@ There are similar existing third-party tools: Specification ============= -A new decorator ``@deprecated()`` is added to the :mod:`typing` module. This +A new decorator ``@deprecated()`` is added to the :mod:`warnings` module. This decorator can be used on a class, function or method to mark it as deprecated. This includes :class:`typing.TypedDict` and :class:`typing.NamedTuple` definitions. With overloaded functions, the decorator may be applied to individual overloads, @@ -132,16 +132,20 @@ For deprecated classes and functions, this includes: * If ``import *`` is used, usage of deprecated objects from the module (``from module import *; x = deprecated_object()``) * ``from`` imports (``from module import deprecated_object``) +* Any syntax that indirectly triggers a call to the function. For example, + if the ``__add__`` method of a class ``C`` is deprecated, then + the code ``C() + C()`` should trigger a diagnostic. Similarly, if the + setter of a property is marked deprecated, attempts to set the property + should trigger a diagnostic. -There are some additional scenarios where deprecations could come into play: +If a method is marked with the :func:`typing.override` decorator from :pep:`698` +and the base class method it overrides is deprecated, the type checker should +produce a diagnostic. -* An object implements a :class:`typing.Protocol`, but one of the methods - required for protocol compliance is deprecated. -* A class uses the ``@override`` decorator from :pep:`698` to assert that - its method overrides a base class method, but the base class method is - deprecated. - -As these scenarios appear complex and relatively unlikely to come up in practice, +There are additional scenarios where deprecations could come into play. +For example, an object may implement a :class:`typing.Protocol`, but one +of the methods required for protocol compliance is deprecated. +As scenarios such as this one appear complex and relatively unlikely to come up in practice, this PEP does not mandate that type checkers detect them. Example @@ -151,7 +155,7 @@ As an example, consider this library stub named ``library.pyi``: .. code-block:: python - from typing import deprecated + from warnings import deprecated @deprecated("Use Spam instead") class Ham: ... @@ -165,6 +169,20 @@ As an example, consider this library stub named ``library.pyi``: @overload def foo(x: str) -> str: ... + class Spam: + @deprecated("There is enough spam in the world") + def __add__(self, other: object) -> object: ... + + @property + @deprecated("All spam will be equally greasy") + def greasy(self) -> float: ... + + @property + def shape(self) -> str: ... + @shape.setter + @deprecated("Shapes are becoming immutable") + def shape(self, value: str) -> None: ... + Here is how type checkers should handle usage of this library: .. code-block:: python @@ -181,6 +199,15 @@ Here is how type checkers should handle usage of this library: ham = Ham() # no error (already reported above) + spam = library.Spam() + spam + 1 # error: Use of deprecated method Spam.__add__. There is enough spam in the world. + spam.greasy # error: Use of deprecated property Spam.greasy. All spam will be equally greasy. + spam.shape # no error + spam.shape = "cube" # error: Use of deprecated property setter Spam.shape. Shapes are becoming immutable. + +The exact wording of the diagnostics is up to the type checker and is not part +of the specification. + Runtime behavior ---------------- @@ -209,6 +236,7 @@ To accommodate runtime introspection, the decorator sets an attribute ``__deprecated__`` on the object it is passed, as well as on the wrapper callables it generates for deprecated classes and functions. The value of the attribute is the message passed to the decorator. +Decorating objecs that do not allow setting this attribute is not supported. If a ``Protocol`` with the ``@runtime_checkable`` decorator is marked as deprecated, the ``__deprecated__`` attribute should not be considered a member of the protocol, @@ -263,7 +291,8 @@ Reference implementation ======================== A runtime implementation of the ``@deprecated`` decorator is -`available <https://github.com/python/typing_extensions/pull/105>`__. +available in the `typing-extensions <https://pypi.org/project/typing-extensions/>`_ +library since version 4.5.0. The ``pyanalyze`` type checker has `prototype support <https://github.com/quora/pyanalyze/pull/578>`__ for emitting deprecation errors, as does @@ -309,6 +338,15 @@ show that this feature is not commonly needed. Features for deprecating more kinds of objects could be added in a future PEP. +Placing the decorator in the ``typing`` module +---------------------------------------------- + +An earlier version of this PEP proposed placing the ``@deprecated`` +decorator in the :mod:`typing` module. However, there was feedback +that it would be unexpected for a decorator in the :mod:`typing` module +to have runtime behavior. Therefore, the PEP now proposes adding the +decorator the :mod:`warnings` module instead. + Acknowledgments =============== From 3a6714f29e3a8b04af4f9eefeed258c3c3a03477 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" <erlend.aasland@protonmail.com> Date: Wed, 20 Sep 2023 20:53:10 +0200 Subject: [PATCH 123/173] PEP 443: Fix collections.abc example (#3131) --- peps/pep-0443.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0443.rst b/peps/pep-0443.rst index fa800e692..5e0d8fc18 100644 --- a/peps/pep-0443.rst +++ b/peps/pep-0443.rst @@ -226,7 +226,7 @@ implementations on the generic function or when user code calls it is possible to create a situation with ambiguous dispatch, for instance:: - >>> from collections import Iterable, Container + >>> from collections.abc import Iterable, Container >>> class P: ... pass >>> Iterable.register(P) From d226c15c820ded52c7c7fb2f9186bc13ebb9d528 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:01:39 +0100 Subject: [PATCH 124/173] PEP 1: Stop recommending Typing-SIG (it has ceased to be!) (#3453) --- CONTRIBUTING.rst | 4 ++-- peps/pep-0001.rst | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index bf58bd2c4..558e91a7e 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -37,8 +37,8 @@ which don't significantly impair meaning and understanding. If you're still unsure, we encourage you to reach out first before opening a PR here. For example, you could contact the PEP author(s), propose your idea in -a discussion venue appropriate to the PEP (such as `Typing-SIG -<https://mail.python.org/archives/list/typing-sig@python.org/>`__ for static +a discussion venue appropriate to the PEP (such as `Typing Discourse +<https://discuss.python.org/c/typing/>`__ for static typing, or `Packaging Discourse <https://discuss.python.org/c/packaging/>`__ for packaging), or `open an issue <https://github.com/python/peps/issues>`__. diff --git a/peps/pep-0001.rst b/peps/pep-0001.rst index 66da707dc..a73808fa3 100644 --- a/peps/pep-0001.rst +++ b/peps/pep-0001.rst @@ -136,8 +136,8 @@ forums, and attempts to build community consensus around the idea. The PEP champion (a.k.a. Author) should first attempt to ascertain whether the idea is PEP-able. Posting to the `Ideas category`_ of the `Python Discourse`_ is usually the best way to go about this, unless a more specialized venue is appropriate, -such as `Typing-SIG`_ for static typing or the `Packaging category`_ of the -Python Discourse for packaging issues. +such as the `Typing category`_ (for static typing ideas) +or `Packaging category`_ (for packaging ideas) on the Python Discourse. Vetting an idea publicly before going as far as writing a PEP is meant to save the potential author time. Many ideas have been brought @@ -284,8 +284,9 @@ The `PEPs category`_ of the `Python Discourse`_ is the preferred choice for most new PEPs, whereas historically the `Python-Dev`_ mailing list was commonly used. Some specialized topics have specific venues, such as -`Typing-SIG`_ for typing PEPs or the `Packaging category`_ on the Python -Discourse for packaging PEPs. If the PEP authors are unsure of the best venue, +the `Typing category`_ and the `Packaging category`_ on the Python +Discourse for typing and packaging PEPs, respectively. +If the PEP authors are unsure of the best venue, the PEP Sponsor and PEP editors can advise them accordingly. If a PEP undergoes a significant re-write or other major, substantive @@ -859,7 +860,7 @@ Footnotes .. _PEPs category: https://discuss.python.org/c/peps/ -.. _Typing-SIG: https://mail.python.org/mailman3/lists/typing-sig.python.org/ +.. _Typing category: https://discuss.python.org/c/typing/ .. _Packaging category: https://discuss.python.org/c/packaging/ From a703204b82a262985243dbe1994581860eb62f6f Mon Sep 17 00:00:00 2001 From: konsti <konstin@mailbox.org> Date: Fri, 22 Sep 2023 23:23:38 +0200 Subject: [PATCH 125/173] PEP 440: Make examples clearer (#2898) The PEP 440 version matching examples are confusing to read and the `1.1a1` in `== 1.1.*` is dependent on whether the user requested pre-releases or not, which I've clarified (https://github.com/pypa/packaging/issues/617) --- peps/pep-0440.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0440.rst b/peps/pep-0440.rst index 86a82ea1e..4cc287bf3 100644 --- a/peps/pep-0440.rst +++ b/peps/pep-0440.rst @@ -919,7 +919,7 @@ following clauses would match or not as shown:: == 1.1 # Not equal, so 1.1a1 does not match clause == 1.1a1 # Equal, so 1.1a1 matches clause - == 1.1.* # Same prefix, so 1.1a1 matches clause + == 1.1.* # Same prefix, so 1.1a1 matches clause if pre-releases are requested An exact match is also considered a prefix match (this interpretation is implied by the usual zero padding rules for the release segment of version From a159a9ac58ca73dc1da0b626b6df77807af455d0 Mon Sep 17 00:00:00 2001 From: Rich Chiodo <rchiodo@users.noreply.github.com> Date: Fri, 22 Sep 2023 19:02:16 -0700 Subject: [PATCH 126/173] PEP 724: Add the Rationale section (#3447) --- peps/pep-0724.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/peps/pep-0724.rst b/peps/pep-0724.rst index a6ae5a1d2..b00b724fb 100644 --- a/peps/pep-0724.rst +++ b/peps/pep-0724.rst @@ -83,6 +83,19 @@ The following code sample demonstrates both of these limitations. return ``TypeGuard`` type was not a subtype of the input type. Refer to :pep:`647` for examples. +Rationale +========= + +There are a number of issues where a stricter ``TypeGuard`` would have +been a solution: + +* `Python typing issue - TypeGuard doesn't intersect like isinstance <https://github.com/python/typing/issues/1351>`__ +* `Pyright issue - TypeGuard not eliminating possibility on branch <https://github.com/microsoft/pyright/issues/3450>`__ +* `Pyright issue - Type narrowing for Literal doesn't work <https://github.com/microsoft/pyright/issues/3466>`__ +* `Mypy issue - TypeGuard is incompatible with exhaustive check <https://github.com/python/mypy/issues/15305>`__ +* `Mypy issue - Incorrect type narrowing for inspect.isawaitable <https://github.com/python/mypy/issues/15520>`__ +* `Typeshed issue - asyncio.iscoroutinefunction is not a TypeGuard <https://github.com/python/typeshed/issues/8009>`__ + Specification ============= From b794468df651c1d37dba1322fae6a8041d8046ff Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:16:17 -0600 Subject: [PATCH 127/173] Infra: Add Python version to PEP 0 tables (#3434) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .../pep_theme/static/style.css | 9 +++-- .../pep_zero_generator/parser.py | 2 + .../pep_zero_generator/writer.py | 40 ++++++++++++++----- .../tests/pep_zero_generator/test_parser.py | 36 +++++++++++++---- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css index 70e1cbf08..36393159a 100644 --- a/pep_sphinx_extensions/pep_theme/static/style.css +++ b/pep_sphinx_extensions/pep_theme/static/style.css @@ -232,14 +232,17 @@ table td + td { } /* Common column widths for PEP status tables */ table.pep-zero-table tr td:nth-child(1) { - width: 5.5%; + width: 5%; } table.pep-zero-table tr td:nth-child(2) { - width: 6.5%; + width: 7%; } table.pep-zero-table tr td:nth-child(3), table.pep-zero-table tr td:nth-child(4){ - width: 44%; + width: 41%; +} +table.pep-zero-table tr td:nth-child(5) { + width: 6%; } /* Authors & Sponsors table */ #authors-owners table td, diff --git a/pep_sphinx_extensions/pep_zero_generator/parser.py b/pep_sphinx_extensions/pep_zero_generator/parser.py index 193186c74..bd8bf9e68 100644 --- a/pep_sphinx_extensions/pep_zero_generator/parser.py +++ b/pep_sphinx_extensions/pep_zero_generator/parser.py @@ -140,6 +140,8 @@ class PEP: "shorthand": self.shorthand, # the author list as a comma-separated with only last names "authors": ", ".join(author.full_name for author in self.authors), + # The targeted Python-Version (if present) or the empty string + "python_version": self.python_version or "", } @property diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 69a5fe4bc..f8232d0ce 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -74,14 +74,22 @@ class PEPZeroWriter: self.output.append(author_table_separator) def emit_pep_row( - self, *, shorthand: str, number: int, title: str, authors: str + self, + *, + shorthand: str, + number: int, + title: str, + authors: str, + python_version: str | None = None, ) -> None: self.emit_text(f" * - {shorthand}") self.emit_text(f" - :pep:`{number} <{number}>`") self.emit_text(f" - :pep:`{title.replace('`', '')} <{number}>`") self.emit_text(f" - {authors}") + if python_version is not None: + self.emit_text(f" - {python_version}") - def emit_column_headers(self) -> None: + def emit_column_headers(self, *, include_version=True) -> None: """Output the column headers for the PEP indices.""" self.emit_text(".. list-table::") self.emit_text(" :header-rows: 1") @@ -92,6 +100,8 @@ class PEPZeroWriter: self.emit_text(" - PEP") self.emit_text(" - Title") self.emit_text(" - Authors") + if include_version: + self.emit_text(" - ") # for Python-Version def emit_title(self, text: str, *, symbol: str = "=") -> None: self.output.append(text) @@ -101,17 +111,25 @@ class PEPZeroWriter: def emit_subtitle(self, text: str) -> None: self.emit_title(text, symbol="-") + def emit_table(self, peps: list[PEP]) -> None: + include_version = any(pep.details["python_version"] for pep in peps) + self.emit_column_headers(include_version=include_version) + for pep in peps: + details = pep.details + if not include_version: + details.pop("python_version") + self.emit_pep_row(**details) + def emit_pep_category(self, category: str, peps: list[PEP]) -> None: self.emit_subtitle(category) - self.emit_column_headers() - for pep in peps: - self.emit_pep_row(**pep.details) + self.emit_table(peps) # list-table must have at least one body row if len(peps) == 0: self.emit_text(" * -") self.emit_text(" -") self.emit_text(" -") self.emit_text(" -") + self.emit_text(" -") self.emit_newline() def write_pep0( @@ -180,19 +198,21 @@ class PEPZeroWriter: # PEPs by number self.emit_title("Numerical Index") - self.emit_column_headers() - for pep in peps: - self.emit_pep_row(**pep.details) + self.emit_table(peps) self.emit_newline() # Reserved PEP numbers if is_pep0: self.emit_title("Reserved PEP Numbers") - self.emit_column_headers() + self.emit_column_headers(include_version=False) for number, claimants in sorted(self.RESERVED.items()): self.emit_pep_row( - shorthand="", number=number, title="RESERVED", authors=claimants + shorthand="", + number=number, + title="RESERVED", + authors=claimants, + python_version=None, ) self.emit_newline() diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index daeb77c70..d2bd324ea 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -40,15 +40,35 @@ def test_pep_equal(): assert pep_a == pep_b -def test_pep_details(monkeypatch): - pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst") +@pytest.mark.parametrize( + ("test_input", "expected"), + [ + ( + "pep-0008.rst", + { + "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", + "number": 8, + "shorthand": ":abbr:`PA (Process, Active)`", + "title": "Style Guide for Python Code", + "python_version": "", + }, + ), + ( + "pep-0719.rst", + { + "authors": "Thomas Wouters", + "number": 719, + "shorthand": ":abbr:`IA (Informational, Active)`", + "title": "Python 3.13 Release Schedule", + "python_version": "3.13", + }, + ), + ], +) +def test_pep_details(test_input, expected): + pep = parser.PEP(PEP_ROOT / test_input) - assert pep8.details == { - "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", - "number": 8, - "shorthand": ":abbr:`PA (Process, Active)`", - "title": "Style Guide for Python Code", - } + assert pep.details == expected @pytest.mark.parametrize( From 3b5f6f44648cd820988152a2e857afef6f892afd Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:00:23 -0600 Subject: [PATCH 128/173] PEP 1 and 12: Remove optional Content-Type from templates (#3454) --- .pre-commit-config.yaml | 4 ++-- peps/pep-0001.rst | 19 +------------------ peps/pep-0012.rst | 2 -- peps/pep-0012/pep-NNNN.rst | 1 - 4 files changed, 3 insertions(+), 23 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b1c1602fb..c928b5971 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -109,14 +109,14 @@ repos: - id: check-required-headers name: "PEPs must have all required headers" language: pygrep - entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nContent-Type:)(?=[\s\S]*\nCreated:))' + entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nCreated:))' args: ['--negate', '--multiline'] files: '^peps/pep-\d+\.rst$' - id: check-header-order name: "PEP header order must follow PEP 12" language: pygrep - entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?Content-Type:[^\n]+\n(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n' + entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?(Content-Type:[^\n]+\n)?(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n' args: ['--negate', '--multiline'] files: '^peps/pep-\d+\.rst$' diff --git a/peps/pep-0001.rst b/peps/pep-0001.rst index a73808fa3..1764f0614 100644 --- a/peps/pep-0001.rst +++ b/peps/pep-0001.rst @@ -3,7 +3,6 @@ Title: PEP Purpose and Guidelines Author: Barry Warsaw, Jeremy Hylton, David Goodger, Nick Coghlan Status: Active Type: Process -Content-Type: text/x-rst Created: 13-Jun-2000 Post-History: 21-Mar-2001, 29-Jul-2002, 03-May-2003, 05-May-2012, 07-Apr-2013 @@ -610,7 +609,6 @@ optional and are described below. All other headers are required. Withdrawn | Final | Superseded> Type: <Standards Track | Informational | Process> * Topic: <Governance | Packaging | Release | Typing> - * Content-Type: text/x-rst * Requires: <pep numbers> Created: <date created on, in dd-mmm-yyyy format> * Python-Version: <version number> @@ -649,7 +647,7 @@ out. The PEP-Delegate field is used to record the individual appointed by the Steering Council to make the final decision on whether or not to approve or reject a PEP. (The delegate's email address is currently omitted due to a -limitation in the email address masking for reStructuredText PEPs) +limitation in the email address masking for reStructuredText PEPs.) *Note: The Resolution header is required for Standards Track PEPs only. It contains a URL that should point to an email message or @@ -668,11 +666,6 @@ The optional Topic header lists the special topic, if any, the PEP belongs under. See the :ref:`topic-index` for the existing topics. -The format of a PEP is specified with a Content-Type header. -All PEPs must use reStructuredText (see :pep:`12`), -and have a value of ``text/x-rst``, the default. -Previously, plaintext PEPs used ``text/plain`` (see :pep:`9`). - The Created header records the date that the PEP was assigned a number, while Post-History is used to record the dates of and corresponding URLs to the Discussions-To threads for the PEP, with the former as the @@ -878,13 +871,3 @@ Copyright This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive. - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: diff --git a/peps/pep-0012.rst b/peps/pep-0012.rst index 7ad01dc43..073a74dc0 100644 --- a/peps/pep-0012.rst +++ b/peps/pep-0012.rst @@ -5,7 +5,6 @@ Author: David Goodger <goodger@python.org>, Brett Cannon <brett@python.org> Status: Active Type: Process -Content-Type: text/x-rst Created: 05-Aug-2002 Post-History: `30-Aug-2002 <https://mail.python.org/archives/list/python-dev@python.org/thread/KX3AS7QAY26QH3WIUAEOCCNXQ4V2TGGV/>`__ @@ -174,7 +173,6 @@ your PEP): Status: Draft Type: [Standards Track | Informational | Process] Topic: *[Governance | Packaging | Release | Typing] - Content-Type: text/x-rst Requires: *[NNN] Created: [DD-MMM-YYYY] Python-Version: *[M.N] diff --git a/peps/pep-0012/pep-NNNN.rst b/peps/pep-0012/pep-NNNN.rst index 011616f6f..9b922b10a 100644 --- a/peps/pep-0012/pep-NNNN.rst +++ b/peps/pep-0012/pep-NNNN.rst @@ -7,7 +7,6 @@ Discussions-To: <REQUIRED: URL of current canonical discussion thread> Status: <REQUIRED: Draft | Active | Accepted | Provisional | Deferred | Rejected | Withdrawn | Final | Superseded> Type: <REQUIRED: Standards Track | Informational | Process> Topic: <Governance | Packaging | Release | Typing> -Content-Type: text/x-rst Requires: <pep numbers> Created: <date created on, in dd-mmm-yyyy format> Python-Version: <version number> From 186c5adc557588b8e8fc442db463105dfed63f1b Mon Sep 17 00:00:00 2001 From: Toni Alatalo <toni.alatalo@gmail.com> Date: Sat, 30 Sep 2023 10:41:31 +0300 Subject: [PATCH 129/173] PEP 703: typo fix, "with with" -> "with" (#3456) --- peps/pep-0703.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0703.rst b/peps/pep-0703.rst index 61fd12d66..2d7f921fa 100644 --- a/peps/pep-0703.rst +++ b/peps/pep-0703.rst @@ -1767,7 +1767,7 @@ an open issue, but a possible path might look like the following: CPython, one with the GIL and one without. Extension authors target both ABIs. #. After 2--3 releases, (i.e., in 2026--2027), CPython is released - with with the GIL controlled by a runtime environment variable or + with the GIL controlled by a runtime environment variable or flag. The GIL is enabled by default. There is only a single ABI. #. After another 2--3 release (i.e., 2028--2030), CPython switches to the GIL being disabled by default. The GIL can still be enabled From 44472d0c0acd55c00b9b55a6ba4a6ea381845c2b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:19:03 +0100 Subject: [PATCH 130/173] PEP 664, 693: Note the release of 3.11.6 and 3.12.0 (#3458) --- peps/pep-0664.rst | 2 +- peps/pep-0693.rst | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/peps/pep-0664.rst b/peps/pep-0664.rst index 6530677bc..863c237f3 100644 --- a/peps/pep-0664.rst +++ b/peps/pep-0664.rst @@ -71,10 +71,10 @@ Actual: - 3.11.3: Wednesday, 2023-04-05 - 3.11.4: Tuesday, 2023-06-06 - 3.11.5: Thursday, 2023-08-24 +- 3.11.6: Monday, 2023-10-02 Expected: -- 3.11.6: Monday, 2023-10-02 - 3.11.7: Monday, 2023-12-04 - 3.11.8: Monday, 2024-02-05 diff --git a/peps/pep-0693.rst b/peps/pep-0693.rst index 092c798e2..a2270cc5e 100644 --- a/peps/pep-0693.rst +++ b/peps/pep-0693.rst @@ -58,9 +58,6 @@ Actual: - 3.12.0 candidate 1: Sunday, 2023-08-06 - 3.12.0 candidate 2: Wednesday, 2023-09-06 - 3.12.0 candidate 3: Tuesday, 2023-09-19 - -Expected: - - 3.12.0 final: Monday, 2023-10-02 Subsequent bugfix releases every two months. From e173bd0e0ff5179604b48cd68cb242751a55fe64 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Mon, 2 Oct 2023 21:42:15 -0700 Subject: [PATCH 131/173] PEP 695: __type_params__ attribute is writable (#3457) Fixes python/cpython#104600. We realized that the attribute should be writable on functions and classes for the benefit of wrappers such as @functools.wraps. --- peps/pep-0695.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0695.rst b/peps/pep-0695.rst index 182a3eb52..837f8c1b6 100644 --- a/peps/pep-0695.rst +++ b/peps/pep-0695.rst @@ -602,7 +602,7 @@ is a generator or coroutine. Accessing Type Parameters at Runtime ------------------------------------ -A new read-only attribute called ``__type_params__`` is available on generic classes, +A new attribute called ``__type_params__`` is available on generic classes, functions, and type aliases. This attribute is a tuple of the type parameters that parameterize the class, function, or alias. The tuple contains ``TypeVar``, ``ParamSpec``, and ``TypeVarTuple`` instances. From e27162276ea6aaca19dceccff5d72de0f5e08cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= <tiangolo@gmail.com> Date: Tue, 3 Oct 2023 08:01:11 -0500 Subject: [PATCH 132/173] PEP 727: update with latest implementation and feedback from discussion (#3459) --- peps/pep-0727.rst | 840 +++++++++++++++++++++++++++++----------------- 1 file changed, 540 insertions(+), 300 deletions(-) diff --git a/peps/pep-0727.rst b/peps/pep-0727.rst index d8f900415..b090874c6 100644 --- a/peps/pep-0727.rst +++ b/peps/pep-0727.rst @@ -1,5 +1,5 @@ PEP: 727 -Title: Documentation Metadata in Typing +Title: Documentation in Annotated Metadata Author: Sebastián Ramírez <tiangolo@gmail.com> Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com> Discussions-To: https://discuss.python.org/t/32566 @@ -15,50 +15,64 @@ Post-History: `30-Aug-2023 <https://discuss.python.org/t/32566>`__ Abstract ======== -This document proposes a way to complement docstrings to add additional documentation -to Python symbols using type annotations with :py:class:`~typing.Annotated` -(in class attributes, function and method parameters, return values, and variables). +This PEP proposes a standardized way to provide documentation strings for Python +symbols defined with :py:class:`~typing.Annotated` using a new class +``typing.Doc``. Motivation ========== -The current standard method of documenting code APIs in Python is using docstrings. -But there's no standard way to document parameters in docstrings. +There's already a well-defined way to provide documentation for classes, +functions, class methods, and modules: using docstrings. -There are several pseudo-standards for the format in these docstrings, and new -pseudo-standards can appear easily: numpy, Google, Keras, reST, etc. +Currently there is no formalized standard to provide documentation strings for other +types of symbols: parameters, return values, class-scoped variables (class variables +and instance variables), local variables, and type aliases. -All these formats are some specific syntax inside a string. Because of this, when -editing those docstrings, editors can't easily provide support for autocompletion, -inline errors for broken syntax, etc. +Nevertheless, to allow documenting most of these additional symbols, several +conventions have been created as microsyntaxes inside of docstrings, and are +currently commonly used: Sphinx, numpydoc, Google, Keras, etc. -Editors don't have a way to support all the possible micro languages in the docstrings -and show nice user interfaces when developers use libraries with those different -formats. They could even add support for some of the syntaxes, but probably not all, -or not completely. +There are two scenarios in which these conventions would be supported by tools: for +authors, while **editing** the contents of the documentation strings and for users, +while **rendering** that content in some way (in documentation sites, tooltips +in editors, etc). -Because the docstring is in a different place in the code than the actual parameters -and it requires duplication of information (the parameter name) the information about -a parameter is easily in a place in the code quite far away from the declaration of -the actual parameter. This means it's easy to refactor a function, remove a parameter, -and forget to remove its docs. The same happens when adding a new parameter: it's easy -to forget to add the docstring for it. +Because each of these conventions uses a microsyntax inside a string, when +**editing** those docstrings, editors can't easily provide support for autocompletion, +inline errors for broken syntax, etc. Any type of **editing** support for these +conventions would be on top of the support for editing standard Python syntax. + +When documenting parameters with current conventions, because the docstring is in +a different place in the code than the actual parameters and it requires +duplication of information (the parameter name) the information about +a parameter is easily in a place in the code quite far away from the +declaration of the actual parameter and it is disconnected from it. +This means it's easy to refactor a function, remove a parameter, and forget to +remove its docs. The same happens when adding a new parameter: it's easy to forget +to add the docstring for it. And because of this same duplication of information (the parameter name) editors and -other tools would need to have complex custom logic to check or ensure the -consistency of the parameters in the signature and in their docstring, or they -would simply not be able to support that. +other tools need complex custom logic to check or ensure the consistency of the +parameters in the signature and in their docstring, or they simply don't +fully support that. -Additionally, it would be difficult to robustly parse varying existing docstring -conventions to programatically get the documentation for each individual parameter -or variable at runtime. This would be useful, for example, -for testing the contents of each parameter's documentation, to ensure consistency -across several similar functions, or to extract and expose that same parameter -documentation in some other way (e.g. an API, a CLI, etc). +As these existing conventions are different types of microsyntaxes inside of +strings, robustly parsing them for **rendering** requires complex logic that +needs to be implemented by the tools supporting them. Additionally, libraries +and tools don't have a straightforward way to obtain the documentation for +each individual parameter or variable at runtime, without depending on a +specific docstring convention parser. Accessing the parameter documentation +strings at runtime would be useful, for example, for testing the contents +of each parameter's documentation, to ensure consistency across several +similar functions, or to extract and expose that same parameter +documentation in some other way (e.g. an API with FastAPI, a CLI with Typer, etc). Some of these previous formats tried to account for the lack of type annotations -in older Python versions by including typing information in the docstrings, +in older Python versions by including typing information in the docstrings (e.g. +`Sphinx <https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists>`__, +`numpydoc <https://numpydoc.readthedocs.io/en/latest/format.html#parameters>`__) but now that information doesn't need to be in docstrings as there is now an official :pep:`syntax for type annotations <484>`. @@ -67,42 +81,179 @@ Rationale ========= This proposal intends to address these shortcomings by extending and complementing the -information in docstrings, keeping backwards compatibility with existing docstrings, -and doing it in a way that leverages the Python language and structure, via type -annotations with ``Annotated``, and a new function in ``typing``. +information in docstrings, keeping backwards compatibility with existing docstrings +(it doesn't deprecate them), and doing it in a way that leverages the Python +language and structure, via type annotations with :py:class:`~typing.Annotated`, and +a new class ``Doc`` in ``typing``. The reason why this would belong in the standard Python library instead of an external package is because although the implementation would be quite trivial, -the actual power and benefit from it would come from being a standard, so that -editors and other tools could implement support for it. +the actual power and benefit from it would come from being a standard, to facilitate +its usage from library authors and to provide a default way to document Python +symbols using :py:class:`~typing.Annotated`. Some tool providers (at least VS Code +and PyCharm) have shown they would consider implementing support for this only if +it was a standard. -This doesn't deprecate current usage of docstrings, it's transparent to common -developers (library users), and it's only opt-in for library authors that would -like to adopt it. +This doesn't deprecate current usage of docstrings, docstrings should be considered +the preferred documentation method when available (not available in type aliases, +parameters, etc). +And docstrings would be complemented by this proposal for documentation specific to +the symbols that can be declared with :py:class:`~typing.Annotated` +(currently only covered by the several available microsyntax conventions). + +This should be relatively transparent to common developers (library users) unless +they manually open the source files from libraries adopting it. + +It should be considered opt-in for library authors who would like to adopt it and +they should be free to decide to use it or not. + +It would be only useful for libraries that are willing to use optional type hints. + + +Summary +------- + +Here's a short summary of the features of this proposal in contrast to current +conventions: + +* **Editing** would be already fully supported by default by any editor (current + or future) supporting Python syntax, including syntax errors, syntax + highlighting, etc. + +* **Rendering** would be relatively straightforward to implement by static tools + (tools that don't need runtime execution), as the information can be extracted + from the AST they normally already create. + +* Deduplication of information: the name of a parameter would be defined in a single + place, not duplicated inside of a docstring. + +* Elimination of the possibility of having inconsistencies when removing a parameter + or class variable and forgetting to remove its documentation. + +* Minimization of the probability of adding a new parameter or class variable + and forgetting to add its documentation. + +* Elimination of the possibility of having inconsistencies between the name of a + parameter in the signature and the name in the docstring when it is renamed. + +* Reuse of documentation for symbols used in multiple places via type aliases. + +* Access to the documentation string for each symbol at runtime, including existing + (older) Python versions. + +* No microsyntax to learn for newcomers, it's just Python syntax. + +* Parameter documentation inheritance for functions captured + by :py:class:`~typing.ParamSpec`. Specification ============= -The main proposal is to introduce a new function, ``typing.doc()``, -to be used when documenting Python objects. -This function MUST only be used within :py:class:`~typing.Annotated` annotations. -The function takes a single string argument, ``documentation``, -and returns an instance of ``typing.DocInfo``, -which stores the input string unchanged. +The main proposal is to introduce a new class, ``typing.Doc``. +This class should only be used within :py:class:`~typing.Annotated` annotations. +It takes a single positional-only string argument. It should be used to +document the intended meaning and use of the symbol declared using +:py:class:`~typing.Annotated`. -Any tool processing ``typing.DocInfo`` objects SHOULD interpret the string as -a docstring, and therefore SHOULD normalize whitespace +For example: + +.. code:: python + + from typing import Annotated, Doc + + class User: + first_name: Annotated[str, Doc("The user's first name")] + last_name: Annotated[str, Doc("The user's last name")] + + ... + +:py:class:`~typing.Annotated` is normally used as a type annotation, in those cases, +any ``typing.Doc`` inside of it would document the symbol being annotated. + +When :py:class:`~typing.Annotated` is used to declare a type alias and that type +alias is used in an annotation, ``typing.Doc`` would document the symbol being +annotated instead of exclusively the type alias. + +For example: + +.. code:: python + + from typing import Annotated, Doc, TypeAlias + + + UserName: TypeAlias = Annotated[str, Doc("The user's name")] + + + def create_user(name: UserName): ... + + def delete_user(name: UserName): ... + + +When a type alias is put inside of :py:class:`~typing.Annotated` and it has a +``typing.Doc``, the last one used (the top-most) takes precedence, this allows +overriding the documentation. + +For example: + +.. code:: python + + from typing import Annotated, Doc, TypeAlias + + + UserName: TypeAlias = Annotated[str, Doc("The user's name")] + + + def create_user(name: UserName): ... + + def delete_user(name: Annotated[UserName, Doc("The user to delete")]): ... + + +In this case, for the ``name`` parameter in ``delete_user()``, the documentation string +would be ``"The user to delete"``. + +For tools extracting the information at runtime, they would normally use +:py:func:`~typing.get_type_hints` with the parameter ``include_extras=True``, +and as :py:class:`~typing.Annotated` is normalized (even with type aliases), this +would mean they should use the last ``typing.Doc`` available, as that is the last +one used. + +At runtime, ``typing.Doc`` instances have an attribute ``documentation`` with the +string passed to it. + +When a type alias is used on its own, without annotating any additional symbol, +``typing.Doc`` documents the type alias itself. This would be useful if the +type alias is included on its own in documentation systems or if it's used directly +in some way, to show tooltips in editors. + +When a function's signature is captured by a :py:class:`~typing.ParamSpec`, +any documentation strings associated with the parameters should be retained. + +Any tool processing ``typing.Doc`` objects should interpret the string as +a docstring, and therefore should normalize whitespace as if ``inspect.cleandoc()`` were used. -The string passed to ``typing.doc()`` SHOULD be of the form that would be a valid docstring. -This means that `f-strings`__ and string operations SHOULD NOT be used. +The string passed to ``typing.Doc`` should be of the form that would be a +valid docstring. +This means that `f-strings`__ and string operations should not be used. As this cannot be enforced by the Python runtime, -tools SHOULD NOT rely on this behaviour, -and SHOULD exit with an error if such a prohibited string is encountered. +tools should not rely on this behavior. + +When tools providing **rendering** show the raw signature, they could allow +configuring if the whole raw :py:class:`~typing.Annotated` code should be displayed, +but they should default to not include :py:class:`~typing.Annotated` and its +internal code metadata, only the type of the symbols annotated. When those tools +support ``typing.Doc`` and rendering in other ways than just a raw signature, +they should show the string value passed to ``typing.Doc`` in a convenient way that +shows the relation between the documented symbol and the documentation string. + +Tools providing **rendering** could allow ways to configure where to show the +parameter documentation and the prose docstring in different ways. Otherwise, they +could simply show the prose docstring first and then the parameter documentation second. __ https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals + Examples -------- @@ -110,25 +261,25 @@ Class attributes may be documented: .. code:: python - from typing import Annotated, doc + from typing import Annotated, Doc class User: - first_name: Annotated[str, doc("The user's first name")] - last_name: Annotated[str, doc("The user's last name")] + first_name: Annotated[str, Doc("The user's first name")] + last_name: Annotated[str, Doc("The user's last name")] ... -As can function or method parameters: +As can function or method parameters and return values: .. code:: python - from typing import Annotated, doc + from typing import Annotated, Doc def create_user( - first_name: Annotated[str, doc("The user's first name")], - last_name: Annotated[str, doc("The user's last name")], + first_name: Annotated[str, Doc("The user's first name")], + last_name: Annotated[str, Doc("The user's last name")], cursor: DatabaseConnection | None = None, - ) -> Annotated[User, doc("The created user after saving in the database")]: + ) -> Annotated[User, Doc("The created user after saving in the database")]: """Create a new user in the system. It needs the database connection to be already initialized. @@ -136,210 +287,233 @@ As can function or method parameters: pass -Additional Scenarios --------------------- +Backwards Compatibility +======================= -The main scenarios that this proposal intends to cover are described above, and -for implementers to be conformant to this specification, they only need to support -those scenarios described above. +This proposal is fully backwards compatible with existing code and it doesn't +deprecate existing usage of docstring conventions. -Here are some additional edge case scenarios with their respective considerations, -but implementers are not required to support them. +For developers that wish to adopt it before it is available in the standard library, +or to support older versions of Python, they can use ``typing_extensions`` and +import and use ``Doc`` from there. - -Type Alias -'''''''''' - -When creating a type alias, like: +For example: .. code:: python - Username = Annotated[str, doc("The name of a user in the system")] + from typing import Annotated + from typing_extensions import Doc + class User: + first_name: Annotated[str, Doc("The user's first name")] + last_name: Annotated[str, Doc("The user's last name")] -The documentation would be considered to be carried by the parameter annotated -with ``Username``. + ... -So, in a function like: -.. code:: python +Security Implications +===================== - def hi(to: Username) -> None: ... +There are no known security implications. -It would be equivalent to: +How to Teach This +================= -.. code:: python +The main mechanism of documentation should continue to be standard docstrings for +prose information, this applies to modules, classes, functions and methods. - def hi(to: Annotated[str, doc("The name of a user in the system")]) -> None: ... +For authors that want to adopt this proposal to add more granularity, they can use +``typing.Doc`` inside of :py:class:`~typing.Annotated` annotations for the symbols +that support it. -Nevertheless, implementers would not be required to support type aliases outside -of the final type annotation to be conformant with this specification, as it -could require more complex dereferencing logic. - - -Annotating Type Parameters -'''''''''''''''''''''''''' - -When annotating type parameters, as in: - -.. code:: python - - def hi( - to: list[Annotated[str, doc("The name of a user in a list")]], - ) -> None: ... - -The documentation in ``doc()`` would refer to what it is annotating, in this -case, each item in the list, not the list itself. - -There are currently no practical use cases for documenting type parameters, -so implementers are not required to support this scenario to be considered -conformant, but it's included for completeness. - - -Annotating Unions -''''''''''''''''' - -If used in one of the parameters of a union, as in: - -.. code:: python - - def hi( - to: str | Annotated[list[str], doc("List of user names")], - ) -> None: ... - -Again, the documentation in ``doc()`` would refer to what it is annotating, -in this case, this documents the list itself, not its items. - -In particular, the documentation would not refer to a single string passed as a -parameter, only to a list. - -There are currently no practical use cases for documenting unions, so implementers -are not required to support this scenario to be considered conformant, but it's -included for completeness. - - -Nested ``Annotated`` -'''''''''''''''''''' - -Continuing with the same idea above, if ``Annotated`` was used nested and used -multiple times in the same parameter, ``doc()`` would refer to the type it -is annotating. - -So, in an example like: - -.. code:: python - - def hi( - to: Annotated[ - Annotated[str, doc("A user name")] - | Annotated[list, doc("A list of user names")], - doc("Who to say hi to"), - ], - ) -> None: ... - - -The documentation for the whole parameter ``to`` would be considered to be -"``Who to say hi to``". - -The documentation for the case where that parameter ``to`` is specifically a ``str`` -would be considered to be "``A user name``". - -The documentation for the case where that parameter ``to`` is specifically a -``list`` would be considered to be "``A list of user names``". - -Implementers would only be required to support the top level use case, where the -documentation for ``to`` is considered to be "``Who to say hi to``". -They could optionally support having conditional documentation for when the type -of the parameter passed is of one type or another, but they are not required to do so. - - -Duplication -''''''''''' - -If ``doc()`` is used multiple times in a single ``Annotated``, it would be -considered invalid usage from the developer, for example: - -.. code:: python - - def hi( - to: Annotated[str, doc("A user name"), doc("The current user name")], - ) -> None: ... - - -Implementers can consider this invalid and are not required to support this to be -considered conformant. - -Nevertheless, as it might be difficult to enforce it on developers, implementers -can opt to support one of the ``doc()`` declarations. - -In that case, the suggestion would be to support the last one, just because -this would support overriding, for example, in: - -.. code:: python - - User = Annotated[str, doc("A user name")] - - CurrentUser = Annotated[User, doc("The current user name")] - - -Internally, in Python, ``CurrentUser`` here is equivalent to: - -.. code:: python - - CurrentUser = Annotated[str, - doc("A user name"), - doc("The current user name")] - - -For an implementation that supports the last ``doc()`` appearance, the above -example would be equivalent to: - -.. code:: python - - def hi(to: Annotated[str, doc("The current user name")]) -> None: ... - - -.. you need to fill these in: - - Backwards Compatibility - ======================= - - [Describe potential impact and severity on pre-existing code.] - - - Security Implications - ===================== - - [How could a malicious user take advantage of this new feature?] - - - How to Teach This - ================= - - [How to teach users, new and experienced, how to apply the PEP to their work.] +Library authors that wish to adopt this proposal while keeping backwards compatibility +with older versions of Python should use ``typing_extensions.Doc`` instead of +``typing.Doc``. Reference Implementation ======================== -``typing.doc`` and ``typing.DocInfo`` are implemented as follows: +``typing.Doc`` is implemented equivalently to: .. code:: python - def doc(documentation: str, /) -> DocInfo: - return DocInfo(documentation) - - class DocInfo: + class Doc: def __init__(self, documentation: str, /): self.documentation = documentation -These have been implemented in the `typing_extensions`__ package. +It has been implemented in the `typing_extensions`__ package. __ https://pypi.org/project/typing-extensions/ +Survey of Other languages +========================= + +Here's a short survey of how other languages document their symbols. + + +Java +---- + +Java functions and their parameters are documented with +`Javadoc <https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html>`__, +a special format for comments put on top of the function definition. This would be +similar to Python current docstring microsyntax conventions (but only one). + +For example: + +.. code:: java + + /** + * Returns an Image object that can then be painted on the screen. + * The url argument must specify an absolute <a href="#{@link}">{@link URL}</a>. The name + * argument is a specifier that is relative to the url argument. + * <p> + * This method always returns immediately, whether or not the + * image exists. When this applet attempts to draw the image on + * the screen, the data will be loaded. The graphics primitives + * that draw the image will incrementally paint on the screen. + * + * @param url an absolute URL giving the base location of the image + * @param name the location of the image, relative to the url argument + * @return the image at the specified URL + * @see Image + */ + public Image getImage(URL url, String name) { + try { + return getImage(new URL(url, name)); + } catch (MalformedURLException e) { + return null; + } + } + + +JavaScript +---------- + +Both JavaScript and TypeScript use a similar system to Javadoc. + +JavaScript uses `JSDoc <https://jsdoc.app/>`__. + +For example: + +.. code:: javascript + + /** + * Represents a book. + * @constructor + * @param {string} title - The title of the book. + * @param {string} author - The author of the book. + */ + function Book(title, author) { + } + +TypeScript +---------- + +TypeScript has +`its own JSDoc reference <https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html>`__ +with some variations. + +For example: + +.. code:: typescript + + // Parameters may be declared in a variety of syntactic forms + /** + * @param {string} p1 - A string param. + * @param {string=} p2 - An optional param (Google Closure syntax) + * @param {string} [p3] - Another optional param (JSDoc syntax). + * @param {string} [p4="test"] - An optional param with a default value + * @returns {string} This is the result + */ + function stringsStringStrings(p1, p2, p3, p4) { + // TODO + } + + +Rust +---- + +Rust uses another similar variation of a microsyntax in +`Doc comments <https://doc.rust-lang.org/rust-by-example/meta/doc.html#doc-comments>`__. + +But it doesn't have a particular well defined microsyntax structure to denote what +documentation refers to what symbol/parameter other than what can be inferred from +the pure Markdown. + +For example: + +.. code:: rust + + #![crate_name = "doc"] + + /// A human being is represented here + pub struct Person { + /// A person must have a name, no matter how much Juliet may hate it + name: String, + } + + impl Person { + /// Returns a person with the name given them + /// + /// # Arguments + /// + /// * `name` - A string slice that holds the name of the person + /// + /// # Examples + /// + /// ``` + /// // You can have rust code between fences inside the comments + /// // If you pass --test to `rustdoc`, it will even test it for you! + /// use doc::Person; + /// let person = Person::new("name"); + /// ``` + pub fn new(name: &str) -> Person { + Person { + name: name.to_string(), + } + } + + /// Gives a friendly hello! + /// + /// Says "Hello, [name](Person::name)" to the `Person` it is called on. + pub fn hello(& self) { + println!("Hello, {}!", self.name); + } + } + + fn main() { + let john = Person::new("John"); + + john.hello(); + } + + +Go Lang +------- + +Go also uses a form of `Doc Comments <https://go.dev/doc/comment>`__. + +It doesn't have a well defined microsyntax structure to denote what documentation +refers to which symbol/parameter, but parameters can be referenced by name without +any special syntax or marker, this also means that ordinary words that could appear +in the documentation text should be avoided as parameter names. + +.. code:: go + + package strconv + + // Quote returns a double-quoted Go string literal representing s. + // The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) + // for control characters and non-printable characters as defined by IsPrint. + func Quote(s string) string { + ... + } + Rejected Ideas ============== @@ -350,34 +524,107 @@ Standardize Current Docstrings A possible alternative would be to support and try to push as a standard one of the existing docstring formats. But that would only solve the standardization. -It wouldn't solve any of the other problems, like getting editor support -(syntax checks) for library authors, the distance and duplication of information -between a parameter definition and its documentation in the docstring, etc. +It wouldn't solve any of the other problems derived from using a microsyntax inside +of a docstring instead of pure Python syntax, the same as described above in +the **Rationale - Summary**. Extra Metadata and Decorator ---------------------------- -An earlier version of this proposal included several parameters to indicate whether +Some ideas before this proposal included having a function ``doc()`` instead of +the single class ``Doc`` with several parameters to indicate whether an object is discouraged from use, what exceptions it may raise, etc. To allow also deprecating functions and classes, it was also expected that ``doc()`` could be used as a decorator. But this functionality is covered by ``typing.deprecated()`` in :pep:`702`, so it was dropped from this proposal. A way to declare additional information could still be useful in the future, -but taking early feedback on this document, all that was postponed to future +but taking early feedback on this idea, all that was postponed to future proposals. -This also shifts the focus from an all-encompassing function ``doc()`` -with multiple parameters to multiple composable functions, having ``doc()`` -handle one single use case: additional documentation in ``Annotated``. +This also shifted the focus from an all-encompassing function ``doc()`` +with multiple parameters to a single ``Doc`` class to be used in +:py:class:`~typing.Annotated` in a way that could be composed with other +future proposals. This design change also allows better interoperability with other proposals like ``typing.deprecated()``, as in the future it could be considered to -allow having ``typing.deprecated()`` also in ``Annotated`` to deprecate -individual parameters, coexisting with ``doc()``. +allow having ``typing.deprecated()`` also in :py:class:`~typing.Annotated` to deprecate +individual parameters, coexisting with ``Doc``. +String Under Definition +----------------------- + +A proposed alternative in the discussion is declaring a string under the definition +of a symbol and providing runtime access to those values: + +.. code:: python + + class User: + first_name: str + "The user's first name" + last_name: str + "The user's last name" + + ... + +This was already proposed and rejected in :pep:`224`, mainly due to the ambiguity of +how is the string connected with the symbol it's documenting. + +Additionally, there would be no way to provide runtime access to this value in previous +versions of Python. + + +Plain String in Annotated +------------------------- + +In the discussion, it was also suggested to use a plain string inside of +:py:class:`~typing.Annotated`: + +.. code:: python + + from typing import Annotated + + class User: + first_name: Annotated[str, "The user's first name"] + last_name: Annotated[str, "The user's last name"] + + ... + + +But this would create a predefined meaning for any plain string inside of +:py:class:`~typing.Annotated`, and any tool that was using plain strings in them +for any other purpose, which is currently allowed, would now be invalid. + +Having an explicit ``typing.Doc`` makes it compatible with current valid uses of +:py:class:`~typing.Annotated`. + + +Another Annotated-Like Type +--------------------------- + +In the discussion it was suggested to define a new type similar to +:py:class:`~typing.Annotated`, it would take the type and a parameter with the +documentation string: + +.. code:: python + + from typing import Doc + + class User: + first_name: Doc[str, "The user's first name"] + last_name: Doc[str, "The user's last name"] + + ... + + +This idea was rejected as it would only support that use case and would make it more +difficult to combine it with :py:class:`~typing.Annotated` for other purposes ( +e.g. with FastAPI metadata, Pydantic fields, etc.) or adding additional metadata +apart from the documentation string (e.g. deprecation). + Open Issues =========== @@ -387,14 +634,30 @@ Verbosity The main argument against this would be the increased verbosity. -Nevertheless, this verbosity would not affect end users as they would not see the -internal code using ``typing.doc()``. +If the signature was not viewed independently of the documentation and the body of the +function with the docstring was also measured, the total verbosity would be +somewhat similar, as what this proposal does is to move some of the contents +from the docstring in the body to the signature. -And the cost of dealing with the additional verbosity would only be carried -by those library maintainers that decide to opt-in into this feature. +Considering the signature alone, without the body, they could be much longer than +they currently are, they could end up being more than one page long. In exchange, +the equivalent docstrings that currently are more than one page long would be +much shorter. -Any authors that decide not to adopt it, are free to continue using docstrings -with any particular format they decide, no docstrings at all, etc. +When comparing the total verbosity, including the signature and the docstring, +the main additional verbosity added by this would be from using +:py:class:`~typing.Annotated` and ``typing.Doc``. If :py:class:`~typing.Annotated` +had more usage, it could make sense to have an improved shorter syntax for it and for +the type of metadata it would carry. But that would only make sense once +:py:class:`~typing.Annotated` is more widely used. + +On the other hand, this verbosity would not affect end users as they would not see the +internal code using ``typing.Doc``. The majority of users would interact with +libraries through editors without looking at the internals, and if anything, they +would have tooltips from editors supporting this proposal. + +The cost of dealing with the additional verbosity would mainly be carried +by those library maintainers that use this feature. This argument could be analogous to the argument against type annotations in general, as they do indeed increase verbosity, in exchange for their @@ -402,6 +665,21 @@ features. But again, as with type annotations, this would be optional and only to be used by those that are willing to take the extra verbosity in exchange for the benefits. +Additionally, if type aliases were used, documentation could be put outside of the +signature and the docstring, reducing the total verbosity of the signature and the +function body. + +Of course, more advanced users might want to look at the source code of the libraries +and if the authors of those libraries adopted this, those advanced users would end up +having to look at that code with additional signature verbosity instead of docstring +verbosity. + +Any authors that decide not to adopt it should be free to continue using docstrings +with any particular format they decide, no docstrings at all, etc. + +Still, there's a high chance that library authors could receive pressure to +adopt this if it became the blessed solution. + Documentation is not Typing --------------------------- @@ -411,36 +689,33 @@ it should live in a different module. Or that this information should not be par of the signature but live in another place (like the docstring). Nevertheless, type annotations in Python could already be considered, by default, -mainly documentation: they carry additional information about variables, -parameters, return types, and by default they don't have any runtime behavior. +additional metadata: they carry additional information about variables, +parameters, return types, and by default they don't have any runtime behavior. And +this proposal would add one more type of metadata to them. It could be argued that this proposal extends the type of information that type annotations carry, the same way as :pep:`702` extends them to include deprecation information. -And as described above, including this in ``typing_extensions`` to support older -versions of Python would have a very simple and practical benefit. +:py:class:`~typing.Annotated` was added to the standard library precisely to +support adding additional metadata to the annotations, and as the new proposed +``Doc`` class is tightly coupled to :py:class:`~typing.Annotated`, it makes +sense for it to live in the same module. If :py:class:`~typing.Annotated` was moved +to another module, it would make sense to move ``Doc`` with it. Multiple Standards ------------------ Another argument against this would be that it would create another standard, -and that there are already several pseudo-standards for docstrings. It could +and that there are already several conventions for docstrings. It could seem better to formalize one of the currently existing standards. -Nevertheless, as stated above, none of those standards cover the general +Nevertheless, as stated above, none of those conventions cover the general drawbacks of a doctsring-based approach that this proposal solves naturally. -None of the editors have full docstring editing support (even when they have -rendering support). Again, this is solved by this proposal just by using -standard Python syntax and structures instead of a docstring microsyntax. - -The effort required to implement support for this proposal by tools would -be minimal compared to that required for alternative docstring-based -pseudo-standards, as for this proposal, editors would only need to -access an already existing value in their ASTs, instead of writing a parser -for a new string microsyntax. +To see a list of the drawbacks of a docstring-based approach, see the section above +in the **Rationale - Summary**. In the same way, it can be seen that, in many cases, a new standard that takes advantage of new features and solves several problems from previous @@ -456,8 +731,8 @@ interest from the community. Fortunately there's already interest from several mainstream libraries from several developers and teams, including FastAPI, Typer, SQLModel, -Asyncer (from the author of this proposal), Pydantic, Strawberry, and others, -from other teams. +Asyncer (from the author of this proposal), Pydantic, Strawberry (GraphQL), and +others. There's also interest and support from documentation tools, like `mkdocstrings <https://github.com/mkdocstrings/mkdocstrings>`__, which added @@ -467,7 +742,7 @@ All the CPython core developers contacted for early feedback (at least 4) have shown interest and support for this proposal. Editor developers (VS Code and PyCharm) have shown some interest, while showing -concerns about the verbosity of the proposal, although not about the +concerns about the signature verbosity of the proposal, although not about the implementation (which is what would affect them the most). And they have shown they would consider adding support for this if it were to become an official standard. In that case, they would only need to add support for @@ -476,41 +751,6 @@ other standards, is already there, as they already support editing standard Python syntax. -Bike Shedding -------------- - -I think ``doc()`` is a good name for the main function. But it might make sense -to consider changing the names for the other parts. - -The returned class containing info currently named ``DocInfo`` could instead -be named just ``Doc``. Although it could make verbal conversations more -confusing as it's the same word as the name of the function. - -The parameter received by ``doc()`` currently named ``documentation`` could -instead be named also ``doc``, but it would make it more ambiguous in -discussions to distinguish when talking about the function and the parameter, -although it would simplify the amount of terms, but as these terms refer to -different things closely related, it could make sense to have different names. - -The parameter received by ``doc()`` currently named ``documentation`` could -instead be named ``value``, but the word "documentation" might convey -the meaning better. - -The parameter received by ``doc()`` currently named ``documentation`` could be a -position-only parameter, in which case the name wouldn't matter much. But then -there wouldn't be a way to make it match with the ``DocInfo`` attribute. - -The ``DocInfo`` class has a single attribute ``documentation``, this name matches -the parameter passed to ``doc()``. It could be named something different, -like ``doc``, but this would mean a mismatch between the ``doc()`` parameter -``documentation`` and the equivalent attribute ``doc``, and it would mean that in -one case (in the function), the term ``doc`` refers to a function, and in the -other case (the resulting class) the term ``doc`` refers to a string value. - -This shows the logic to select the current terms, but it could all be -discussed further. - - Copyright ========= From 0e28ae91d49b4cea125b93980cd9f2b4be34e8ee Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Tue, 3 Oct 2023 21:48:04 -0700 Subject: [PATCH 133/173] PEP 729: Typing governance process (#3455) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> --- .github/CODEOWNERS | 1 + peps/pep-0729.rst | 423 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 424 insertions(+) create mode 100644 peps/pep-0729.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 15fc5c5bd..e37a20907 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -606,6 +606,7 @@ peps/pep-0724.rst @jellezijlstra peps/pep-0725.rst @pradyunsg peps/pep-0726.rst @AA-Turner peps/pep-0727.rst @JelleZijlstra +peps/pep-0729.rst @JelleZijlstra @hauntsaninja # ... # peps/pep-0754.rst # ... diff --git a/peps/pep-0729.rst b/peps/pep-0729.rst new file mode 100644 index 000000000..6b6fca0f9 --- /dev/null +++ b/peps/pep-0729.rst @@ -0,0 +1,423 @@ +PEP: 729 +Title: Typing governance process +Author: Jelle Zijlstra <jelle.zijlstra@gmail.com>, Shantanu Jain <hauntsaninja at gmail.com> +Discussions-To: https://discuss.python.org/t/proposed-new-typing-governance-process/34244 +Status: Draft +Type: Process +Topic: Typing +Created: 19-Sep-2023 +Python-Version: 3.13 +Post-History: `20-Sep-2023 <https://discuss.python.org/t/proposed-new-typing-governance-process/34244>`__ + +Abstract +======== + +This PEP proposes a new way to govern the Python type system: a council that is responsible +for maintaining and developing the Python type system. The council will maintain a +specification and conformance test suite and will initially be appointed by the Python Steering Council. + +Motivation +========== + +The Python type system was created by :pep:`484`, now almost ten years ago. The type +system is now widely used, and typing has become an important tool for writing +good, maintainable Python code. Many changes have been made to the type system to cover +more use cases and improve usability. Several type checkers have been created, each +with their own strengths. The type annotation syntax has driven several major innovations +in the Python ecosystem, such as the popular :mod:`dataclasses` module, runtime type +checking and validation by packages such as `Pydantic <https://docs.pydantic.dev/latest/>`__, +and static compilation by tools such as `mypyc <https://mypyc.readthedocs.io/en/latest/>`__. + +However, as the type system has grown, several interrelated problems with the current +way to manage the type system have become apparent. + +PEPs are the only specification +-------------------------------- + +The Python type system was initially created by a PEP (:pep:`484`), and +changes to the type system are still made by PEPs. The specification for +the Python type system, to the extent there is one, consists of this series +of PEPs. But Standards Track PEPs aren't meant to be living documents +or specifications; they are change proposals. + +An example may illustrate the problem here. Around the same time +as the introduction of the :mod:`typing` module by :pep:`484`, :pep:`3156` +introduced the :mod:`asyncio` module, another major new feature that has +been instrumental to the success of Python 3. Both modules +have evolved greatly since their initial creation and inspired changes to the +core language. + +However, :mod:`asyncio` and :mod:`typing` are different in an essential aspect: +a user who uses :mod:`asyncio` interacts only with the standard library itself, +while a user of :mod:`typing` has to also think about an external tool, the type +checker. The Python language reference covers the symbols in the typing module, but does +not (and should not) go into detail on how the full type system should be +interpreted by type checkers. That material currently exists only in the PEPs. + +This problem is shared by the packaging ecosystem, which attempts to solve it +by maintaining a separate set of `PyPA specifications <https://packaging.python.org/en/latest/specifications/>`_. + +It's hard to evolve the specification +------------------------------------- + +Because the PEPs are the only specification we have, anything that could be seen +as a change to the specification would theoretically require a new PEP. But that +is often too heavy a process for a small change. Sometimes changes are made +directly to old PEPs instead, but that goes against the idea that accepted and +implemented PEPs become historical documents that should no longer be changed. + +Some concrete examples include: + +* :pep:`484` explicitly says that :data:`typing.NoReturn` cannot be used in + argument annotations. Nevertheless, type checkers have long accepted such + usage. +* A `2023 discussion <https://discuss.python.org/t/pep-561-clarification-regarding-n/32875>`_ + noted that :pep:`561`'s description of partial stubs is unclear, and + major type checkers did not implement it exactly as specified. +* The widely used third-party ``typing_extensions`` package provides backports of new + type system features. Type checkers are expected to treat symbols in this + module the same as symbols in :mod:`typing`, but this is not explicitly + specified in any of the PEPs. + +The type system is underspecified +--------------------------------- + +While the PEPs provide a specification, they are often not sufficiently precise +(sometimes intentionally so). This is especially true as the combinatorial +complexity of the type system has grown. + +It ends up falling to individual type checkers to decide how to navigate +underspecified areas. In cases where type checkers informally coordinate, this +results in de facto standards that aren't clearly recorded anywhere, making +the type system less accessible to newcomers. For example: + +* How ``@overload`` matching works +* How ``ParamSpec`` `should work <https://github.com/python/typing/discussions/946>`_ `with methods <https://github.com/microsoft/pyright/issues/3954#issuecomment-1250098464>`_ +* The concept of `recursive aliases <https://github.com/python/typing/issues/182>`_ +* Semantics of `variable initialization <https://mail.python.org/archives/list/typing-sig@python.org/thread/GYVM5KEE6URE6PAH7UTK6324M7GWSFQS/#SY3KPJCAW4UTOOCH3XRJYROSGDEGOTWI>`_ +* `Reachability semantics <https://github.com/python/mypy/issues/15158#issuecomment-1677915108>`__ + of annotations on ``__exit__`` +* `Symbol visibility <https://mail.python.org/archives/list/typing-sig@python.org/thread/YLJPWECBNPD2K4TRIBRIPISNUZJCRREY/#OX4GLBQOOCMRE5YPZEY3R3XNV6DD7XLW>`_ +* Use of `NoReturn for exhaustiveness checking <https://github.com/python/mypy/issues/5818>`_ + +The Steering Council is not well-placed to solve the above problems +------------------------------------------------------------------- + +The SC has the entire language in its remit, and is not well-placed to make +decisions that are purely about the type system -- if only because they don't have +the time to deal with type system arcana alongside their other responsibilities. +This is similar in spirit to the reasons why the Steering Council sometimes uses +PEP delegation. + +Specification +============= + +We propose the creation of a new group, the Typing Council. This group will +be responsible for developing and maintaining the Python type system, and +for solving the above problems. + +The "operations and process" section describes how this group would operate and +be governed. + +The more exciting "projects" section describes solutions to the above problems +that the Typing Council could shepherd. + +Mandate +------- + +The Typing Council's mandate is to ensure that the Python type system is: + +* **Useful**: The type system should serve common use cases. As identified + by :pep:`484`, the primary use case is static analysis, but there are others, + such as runtime type checking, static compilation, IDE support, and documentation. + The Typing Council should consider all of these use cases when making decisions, + and be open to supporting additional use cases as they come up. +* **Usable**: The type system should be easy to use for Python developers. It + should be ergonomic to write well-typed Python code that is accepted by type + checkers. There should be good documentation for the type system. +* **Stable**: As the type system matures, users should be able to rely on their + typed code continuing to work and be able to trust their mental model for the + type system. Changes should be made with care and in a way + that minimizes disruption. Nevertheless, the type system should be able to + evolve, and it does not make sense to use the same compatibility guidelines + for type checker behavior as for Python itself. Of course, the existence + and runtime behavior of objects in the :mod:`typing` module does follow + Python's standard compatibility policy in :pep:`387`. + +Operations and process +---------------------- + +The council would have three members, comprised of prominent community members, +such as Python core developers and maintainers of major type checkers. The members +should include people affiliated with a variety of projects related to type checking, +which may include type checkers, CPython, typeshed, or other projects. + +The Steering Council would appoint the initial Typing Council. There is no term +limit for council members. Council members may resign their position at any time. +There is an expectation that at least one person will voluntarily resign from the +Typing Council each year. + +To determine replacements, nominations will be collected from the typing +community. Self-nominations are allowed. The existing Typing Council will then decide +the replacement member(s) from the nominees. The expectation is that this would +be done by fiat, but the Typing Council can choose a replacement by any means +they see fit, including a vote. + +The Typing Council remains accountable to the Steering Council. At any point, +for any reason, the Steering Council could (publicly or privately) make a +specific change or request a non-specific change to the composition of the +Typing Council. + +We acknowledge that this is a not particularly democratic structure and puts +a lot of faith in the Typing Council. However, the Python community has a long +history of success with not particularly democratic structures! We believe +self-governance, cycling of membership, and accountability to the +Steering Council will be sufficient to ensure that the Typing Council is meeting +the needs of the community. + +The council would operate primarily through reviews of GitHub PRs. Regular +meetings are likely not necessary, but the council may set up video calls, a +private chat, or whatever other mechanism they decide upon internally. + +The council should aim for transparency, posting all decisions publicly on +`discuss.python.org <https://discuss.python.org/c/typing/32>`__, with a +rationale if possible. Before making a decision, the council should give +all interested community members a chance to weigh in. There should be at +least a week between the start of a discussion and the council's decision. + +Members of the council will be eligible to sponsor PEPs. If this PEP is accepted, +:pep:`1` should be amended to note this fact. + +Relationship with the Steering Council +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Just like today, the Python Steering Council would remain responsible for the +overall direction of the Python language and would continue to decide on +typing-related PEPs. The Typing Council would provide written opinions and +recommendations to the Steering Council on typing-related PEPs. + +However, smaller changes to the type system could be made +by the Typing Council directly. The Steering Council could also choose +to delegate decisions on some PEPs to the Typing Council (exactly as any other +PEP delegation). + +Some examples of how past and recent issues could have been handled under this model: + +- A PEP like :pep:`695` (type parameter syntax), which changes the language + syntax, would need to be decided upon by the Steering Council; the Typing + Council would merely provide opinion or endorsement. Similarly, PEPs + like :pep:`702` would be decided upon by the Steering + Council, because it concerns runtime behaviour beyond pure typing. Other examples + that would need to be decided by the SC include :pep:`718` and :pep:`727`. +- A PEP like :pep:`698` (``@override``), which affects only users of type + checkers and does not change the overall language, would also by default + be decided upon by the Steering Council. However, such PEPs could be + delegated to the Typing Council for a decision (like any other PEP delegation). + Other examples of PEPs that could potentially be delegated include + :pep:`647`, :pep:`655`, :pep:`673`, and :pep:`675`. +- Adding a smaller feature, such as :data:`typing.Never` as an alias for + :data:`typing.NoReturn`, would be done by means of a PR to the spec and + conformance test suite. The Typing + Council would then decide whether or not to merge the PR. They may ask for the + feature to be specified and discussed in a PEP if they feel that is warranted. +- If there is confusion about the interpretation of some part of the spec, like + happened recently with `partial stubs in PEP + 561 <https://discuss.python.org/t/pep-561-clarification-regarding-n/32875/27>`_, + somebody would make a PR to the typing specification to clarify the + spec, and then the Typing Council would decide on the spec change. + +The runtime :mod:`typing` module will continue to be maintained by the +CPython core developer team. However, any changes to the runtime module that +affect type checker behavior should be made in conjunction with a change +to the specification (see below) and should be approved by the Typing Council. +For example, in Python 3.11 the core developers added the new function +:func:`typing.assert_type`. If the Typing Council had been in place, this +change would require a matching change to the specification and approval +by the Typing Council. On the other hand, Python 3.11 also added the +:func:`typing.get_overloads` introspection helper. As this function does not +affect type checker behavior, it would not require approval by the Typing +Council. However, as support for runtime type checkers is within the remit +of the Council, they should monitor such changes and provide feedback when +appropriate. + +Relationship with type checkers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Typing Council has no direct authority over type checkers; it cannot +force them to implement particular features or make behavior changes. Type +checkers are incentivized to follow the specification set out by the Council +because it allows them to take advantage of shared resources, such as +libraries that expose typing information that follows the specification, +the stub files in typeshed, the ``typing`` standard library module, and +user documentation that covers the standard type system. +Type checkers are free to extend the type system or deviate from the +specification, but they should document such differences clearly. + +The fact that type checkers need to implement any decisions made by the +Typing Council acts as a useful brake on the Council, ensuring that its +decisions are conservative and well-considered. Individual type checkers +remain free to innovate as they see fit, and successful innovations can +be incorporated into the standard type system. + +Projects +-------- + +Here are some efforts a Typing Council would be responsible for. + +Conformance test suite +^^^^^^^^^^^^^^^^^^^^^^ + +A conformance test suite would provide machine checkable documentation for how +type checkers should check Python code, accompanied by the results of major type +checker implementations on the test suite. A rough sketch for what this could +look like was `created by Shantanu <https://github.com/hauntsaninja/type_checker_consistency>`_. + +This would contain prescriptive tests from behavior prescribed by previous PEPs +and descriptive tests that let us document behavior of existing implementations +in areas that are not prescribed by any standard. These descriptions would be +useful to inform efforts below and to identify areas of focus for +standardization. + +Specification for the type system +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A specification would initially be created by stitching together the +specification sections from the existing PEPs, and then gradually improved to +clarify points of confusion and cover more areas. A draft of such a +stitched-together spec was `created by Jelle <https://github.com/JelleZijlstra/typing-spec>`_. + +The specification has a few audiences: + +* For type checkers, it provides a description of how an idealized type checker + should behave. Individual type checkers have different goals and technical + constraints and they are free to deviate from the spec if they do not have the + resources to fully implement it or if they believe a different behavior better + serves their users. However, they should document such deviations from the + spec. +* For projects such as typeshed, or libraries that want to be compatible with + multiple type checkers, it provides a set of rules that they can follow to + make their code understood by type checkers. +* For people who want to propose changes to the type system, it provides a + foundation for any new proposals. + +Notably, the specification is not aimed at end users of typing, who typically do not +need to worry about compatibility across type checkers. Such users +are better served by a more informal user-facing reference, which is discussed +in the next section. + +There are different opinions within the community about how formal such a +specification should be. While this document recommends an incremental +approach that builds off existing specification, it does not aim to +prescribe a final state. The Typing Council would provide a mechanism +to allow the specification to evolve to meet the level of formality that +the community desires, for instance, by incorporating parts of +Kevin Millikin's `document on "Python Static Types" <https://docs.google.com/document/d/1mVCU-nVPT_zVfqivVdMY1aOOZqJ9lsgOLweO1U3uwUM/edit>`_ +as a means to achieve a better formalisation of the spec. + +Proposed changes to the specification, including PEPs, should +generally be accompanied by the following: + +* Changes to the conformance test suite that demonstrate the + specified behavior. +* Buy-in from type checker maintainers to confirm that the + change can be implemented and maintained within their type + checkers. +* For changes to existing features, a survey of the behavior + of existing type checkers. If existing type checkers + behave roughly similarly, that is evidence that their shared + behavior should be made part of the specification. + +User-facing reference for the type system +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Documentation is important for the success of the Python type system, so +the Typing Council should ensure that there is good documentation for the +type system. + +As mentioned previously, PEPs are point in time change proposals aimed at +multiple audiences that are hard to clarify. This makes them ill-suited as user +documentation. The specification discussed in the previous section would +be a living document, but it would likely be too technical to serve as +documentation for normal usage. + +Therefore, a separate user-facing reference for the type system would be +useful. Such an effort could expand the documentation on +`typing.readthedocs.io <https://typing.readthedocs.io/en/latest/>`_ and +reuse material from the documentation sections of individual type checkers +and the CPython documentation. + +Amendments +---------- + +This PEP serves as a charter for the Typing Council. Changes to its operation +can be made either through a new PEP or through a change to this PEP. In either +case, the change would be decided upon by the Steering Council after discussion +in the community. + +Rejected ideas +============== + +Writing the specification from scratch +-------------------------------------- + +This PEP proposes creating the typing specification by starting from the +existing PEPs, then clarifying and improving the specification as necessary. +Some members of the community prefer to start from scratch, writing a new, +more formal specification covering the entire type system. This could +provide a more solid basis for the specification. + +However, this would be a much larger undertaking. The existing formalization +effort by Kevin Millikin is a good start, but so far covers only a subset of +PEP 484. Covering the rest of the type system would likely require several +times more effort when we consider that major type system features such +as :class:`typing.Protocol`, :class:`typing.Literal`, and :class:`typing.TypedDict` +were introduced only after PEP 484. It is not clear that there is even energy +in the community for such a huge undertaking. Even if someone steps up to +do all the work of putting together a specification, lots of effort would be +required from community members and type checker maintainers to consider +whether the specification accurately reflects current behavior, and if not, +whether the specification or the type checkers should change. + +Starting with the existing PEPs creates a lower-quality specification, +but it means that the Typing Council can immediately start making a difference +anywhere in the type system by improving and clarifying the specification. +A formalization effort can still proceed by gradually replacing sections of the +specification. + +Alternate governance mechanisms +------------------------------- + +An earlier draft of this PEP suggested that the Steering Council appoint +members of the Typing Council each year. The current Steering Council suggested +that it would be better to have the Typing Council self-organise and avoid +the need for the Steering Council to continuously supervise the Typing Council. + +Alternate governance mechanisms are possible, including more democratic ones, +but these typically raise several thorny questions, require much heavier +amounts of process and are potentially more divisive. For example, see the PEP +8000 series, or recent discussions about alternative governance in other Python +subcommunities. Ultimately, the Typing Council exists under the authority of the +Steering Council, and so can rely on it to bootstrap governance and serve as an +accountability mechanism. + +Do nothing +---------- + +We are hopeful substantial progress will be made on projects that improve the +type system regardless of whether this PEP is accepted. We anticipate projects +like specification or the potential for PEP delegation would benefit more from a +Typing Council, and projects like end user documentation would benefit less. +Certainly the bottleneck is likely to be contributor effort, not governance. + +However, currently the tools available to the community to resolve potential +contention are either establishment of approximate consensus or the exercise of +power by individual projects or contributors. While very valuable, the former is +a slow process that can often end in inaction. The latter can result in a less +consistent ecosystem. Finally, easily legible governance structures make the +community more accessible and equitable. + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From 4387d8b4b83b199c2af2b6cb8efdc4cdd9b04afa Mon Sep 17 00:00:00 2001 From: Mikhail Golubev <qsolo825@gmail.com> Date: Wed, 4 Oct 2023 13:04:03 +0300 Subject: [PATCH 134/173] PEP 695: Fix a typo in a type parameter name (#3461) Fix a type parameter name in PEP 695 --- peps/pep-0695.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0695.rst b/peps/pep-0695.rst index 837f8c1b6..c71dadc0e 100644 --- a/peps/pep-0695.rst +++ b/peps/pep-0695.rst @@ -989,7 +989,7 @@ It is however valid at runtime, and it us used here to illustrate the runtime se :: @decorator - def f[T: int, U: (int, str), *V, **P]( + def f[T: int, U: (int, str), *Ts, **P]( x: T = SOME_CONSTANT, y: U, *args: *Ts, From 495eefba9a4ac22eb7442933756be27657b4a6ed Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Wed, 4 Oct 2023 11:36:33 -0700 Subject: [PATCH 135/173] PEP 729: Update Discussions-To (#3462) --- peps/pep-0729.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/peps/pep-0729.rst b/peps/pep-0729.rst index 6b6fca0f9..e267b2e2b 100644 --- a/peps/pep-0729.rst +++ b/peps/pep-0729.rst @@ -1,13 +1,14 @@ PEP: 729 Title: Typing governance process Author: Jelle Zijlstra <jelle.zijlstra@gmail.com>, Shantanu Jain <hauntsaninja at gmail.com> -Discussions-To: https://discuss.python.org/t/proposed-new-typing-governance-process/34244 +Discussions-To: https://discuss.python.org/t/pep-729-typing-governance-process/35362 Status: Draft Type: Process Topic: Typing Created: 19-Sep-2023 Python-Version: 3.13 -Post-History: `20-Sep-2023 <https://discuss.python.org/t/proposed-new-typing-governance-process/34244>`__ +Post-History: `04-Oct-2023 <https://discuss.python.org/t/pep-729-typing-governance-process/35362>`__, + `20-Sep-2023 <https://discuss.python.org/t/proposed-new-typing-governance-process/34244>`__ Abstract ======== From b05d5c654d6373bf1f41e48f9b29abc0e3712515 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" <erlend@python.org> Date: Thu, 5 Oct 2023 01:18:07 +0200 Subject: [PATCH 136/173] PEP 670, 687: Update Erlend's email (#3463) --- peps/pep-0670.rst | 2 +- peps/pep-0687.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0670.rst b/peps/pep-0670.rst index a9298a682..c09c8bb2b 100644 --- a/peps/pep-0670.rst +++ b/peps/pep-0670.rst @@ -1,6 +1,6 @@ PEP: 670 Title: Convert macros to functions in the Python C API -Author: Erlend Egeberg Aasland <erlend.aasland@protonmail.com>, +Author: Erlend Egeberg Aasland <erlend@python.org>, Victor Stinner <vstinner@python.org> Status: Final Type: Standards Track diff --git a/peps/pep-0687.rst b/peps/pep-0687.rst index 6af4d25de..138fd80a8 100644 --- a/peps/pep-0687.rst +++ b/peps/pep-0687.rst @@ -1,6 +1,6 @@ PEP: 687 Title: Isolating modules in the standard library -Author: Erlend Egeberg Aasland <erlend.aasland@protonmail.com>, Petr Viktorin <encukou@gmail.com> +Author: Erlend Egeberg Aasland <erlend@python.org>, Petr Viktorin <encukou@gmail.com> Discussions-To: https://discuss.python.org/t/14824 Status: Accepted Type: Standards Track From ab708c40b1a65c468553b464e0315ea9721f0786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl> Date: Mon, 9 Oct 2023 13:01:36 +0200 Subject: [PATCH 137/173] Modernize PEP 101 --- peps/pep-0101.rst | 262 +++++++++++++++++++--------------------------- 1 file changed, 108 insertions(+), 154 deletions(-) diff --git a/peps/pep-0101.rst b/peps/pep-0101.rst index e877f8958..e84a68679 100644 --- a/peps/pep-0101.rst +++ b/peps/pep-0101.rst @@ -20,12 +20,12 @@ purring little creatures up, and ride them into town, with some of their buddies firmly attached to your bare back, anchored by newly sharpened claws. At least they're cute, you remind yourself. -Actually, no that's a slight exaggeration <wink>. The Python release +Actually, no, that's a slight exaggeration 😉 The Python release process has steadily improved over the years and now, with the help of our amazing community, is really not too difficult. This PEP attempts to -collect, in one place, all the steps needed to make a Python release. It -is organized as a recipe and you can actually print this out and check -items off as you complete them. +collect, in one place, all the steps needed to make a Python release. +Most of the steps are now automated or guided by automation, so manually +following this list is no longer necessary. Things You'll Need ================== @@ -41,25 +41,23 @@ Here's a hopefully-complete list. * A bunch of software: - * "release.py", the Python release manager's friend. It's in the - python/release-tools repo on GitHub. It doesn't pip install - or have any sort of install process--you'll have to put it on - your path yourself, or just run it with a relative path, or - whatever. + * A checkout of the `python/release-tools + <https://github.com/python/release-tools/>`_ repo. + It contains a ``requirements.txt`` file that you need to install + dependencies from first. Afterwards, you can fire up scripts in the + repo, covered later in this PEP. - * "blurb", the Misc/NEWS management tool. The release process - currently uses three blurb subcommands: - release, merge, and export. Installable via pip3. - - * "virtualenv". The release script installs Sphinx in a virtualenv - when building the docs (for 2.7 and 3.5+). + * ``blurb``, the + `Misc/NEWS <https://github.com/python/cpython/tree/main/Misc/NEWS.d>`_ + management tool. You can pip install it. * A fairly complete installation of a recent TeX distribution, such as texlive. You need that for building the PDF docs. -* Access to ``downloads.nyc1.psf.io``, the server that hosts download files, - and ``docs.nyc1.psf.io``, the server that hosts the documentation. - You'll be uploading files directly here. +* Access to servers where you will upload files: + + * ``downloads.nyc1.psf.io``, the server that hosts download files; and + * ``docs.nyc1.psf.io``, the server that hosts the documentation. * Administrator access to ``https://github.com/python/cpython``. @@ -89,7 +87,8 @@ Types of Releases There are several types of releases you will need to make. These include: * ``alpha`` -* ``beta`` +* ``begin beta``, also known as ``beta 1``, also known as ``new branch`` +* ``beta 2+`` * ``release candidate 1`` * ``release candidate 2+`` * ``final`` @@ -105,8 +104,8 @@ organization of the cpython git repository, the *main* branch is always the target for new features. At some point in the release cycle of the next feature release, a **new branch** release is made which creates a new separate branch for stabilization and later maintenance of the -current in-progress feature release (x.y.0) and the *main* branch is modified -to build a new version (which will eventually be released as x.y+1.0). +current in-progress feature release (``3.n.0``) and the *main* branch is modified +to build a new version (which will eventually be released as ``3.n+1.0``). While the **new branch** release step could occur at one of several points in the release cycle, current practice is for it to occur at feature code cutoff for the release which is scheduled for the first beta release. @@ -114,7 +113,7 @@ cutoff for the release which is scheduled for the first beta release. In the descriptions that follow, steps specific to release types are labeled accordingly, for now, **new branch** and **final**. -How to Make A Release +How To Make A Release ===================== Here are the steps taken to make a Python release. Some steps are more @@ -129,12 +128,10 @@ release. The roles and their current experts are: - Thomas Wouters <thomas@python.org> (NL) - Pablo Galindo Salgado <pablogsal@python.org> (UK) - Łukasz Langa <lukasz@python.org> (PL) - - Ned Deily <nad@python.org> (US) * WE = Windows - Steve Dower <steve.dower@python.org> * ME = Mac - Ned Deily <nad@python.org> (US) * DE = Docs - Julien Palard <julien@python.org> (Central Europe) -* IE = Idle Expert - Terry Reedy <tjreedy@udel.edu> (US) .. note:: It is highly recommended that the RM contact the Experts the day before the release. Because the world is round and everyone lives @@ -146,49 +143,42 @@ release. The roles and their current experts are: In rare cases where the expert for Windows or Mac is MIA, you may add a message "(Platform) binaries will be provided shortly" and proceed. -XXX: We should include a dependency graph to illustrate the steps that can -be taken in parallel, or those that depend on other steps. - As much as possible, the release steps are automated and guided by the release script, which is available in a separate repository: https://github.com/python/release-tools We use the following conventions in the examples below. Where a release -number is given, it is of the form ``X.Y.ZaN``, e.g. 3.3.0a3 for Python 3.3.0 +number is given, it is of the form ``3.X.YaN``, e.g. 3.13.0a3 for Python 3.13.0 alpha 3, where "a" == alpha, "b" == beta, "rc" == release candidate. -Release tags are named ``vX.Y.ZaN``. The branch name for minor release -maintenance branches is ``X.Y``. +Release tags are named ``v3.X.YaN``. The branch name for minor release +maintenance branches is ``3.X``. This helps by performing several automatic editing steps, and guides you to perform some manual editing steps. -- Log into irc.libera.chat and join the #python-dev channel. +- Log into Discord and join the Python Core Devs server. Ask Thomas + or Łukasz for an invite. You probably need to coordinate with other people around the world. - This IRC channel is where we've arranged to meet. + This communication channel is where we've arranged to meet. - Check to see if there are any showstopper bugs. - Go to https://bugs.python.org and look for any open bugs that can block - this release. You're looking at the Priority of the open bugs for the - release you're making; here are the relevant definitions: + Go to https://github.com/python/cpython/issues and look for any open + bugs that can block this release. You're looking at two relevant labels: - release blocker + release-blocker Stops the release dead in its tracks. You may not make any release with any open release blocker bugs. - deferred blocker + deferred-blocker Doesn't block this release, but it will block a future release. You may not make a final or candidate release with any open deferred blocker bugs. - critical - Important bugs that should be fixed, but which does not block - a release. - Review the release blockers and either resolve them, bump them down to deferred, or stop the release and ask for community assistance. If you're making a final or candidate release, do the same with any open @@ -244,22 +234,22 @@ to perform some manual editing steps. - Consider running ``autoconf`` using the currently accepted standard version in case ``configure`` or other autoconf-generated files were last committed with a newer or older version and may contain spurious or - harmful differences. Currently, autoconf 2.69 is our de facto standard. + harmful differences. Currently, autoconf 2.71 is our de facto standard. if there are differences, commit them. - Make sure the ``SOURCE_URI`` in ``Doc/tools/extensions/pyspecific.py`` - points to the right branch in the git repository (``main`` or ``X.Y``). + points to the right branch in the git repository (``main`` or ``3.X``). For a **new branch** release, change the branch in the file from *main* - to the new release branch you are about to create (``X.Y``). + to the new release branch you are about to create (``3.X``). - Bump version numbers via the release script:: - $ .../release-tools/release.py --bump X.Y.ZaN + $ .../release-tools/release.py --bump 3.X.YaN - Reminder: X, Y, Z, and N should be integers. + Reminder: X, Y, and N should be integers. a should be one of "a", "b", or "rc" (e.g. "3.4.3rc1"). For **final** releases omit the aN ("3.4.3"). For the first - release of a new version Z should be 0 ("3.6.0"). + release of a new version Y should be 0 ("3.6.0"). This automates updating various release numbers, but you will have to modify a few files manually. If your $EDITOR environment variable is @@ -285,11 +275,8 @@ to perform some manual editing steps. Properties). This isn't a C include file, it's a Windows "resource file" include file. -- Check with the IE (if there is one <wink>) to be sure that - Lib/idlelib/NEWS.txt has been similarly updated. - - For a **final** major release, edit the first paragraph of - Doc/whatsnew/X.Y.rst to include the actual release date; e.g. "Python + Doc/whatsnew/3.X.rst to include the actual release date; e.g. "Python 2.5 was released on August 1, 2003." There's no need to edit this for alpha or beta releases. @@ -298,9 +285,9 @@ to perform some manual editing steps. You should not see any files. I.e. you better not have any uncommitted changes in your working directory. -- Tag the release for X.Y.ZaN:: +- Tag the release for 3.X.YaN:: - $ .../release-tools/release.py --tag X.Y.ZaN + $ .../release-tools/release.py --tag 3.X.YaN This executes a ``git tag`` command with the ``-s`` option so that the release tag in the repo is signed with your gpg key. When prompted @@ -321,11 +308,11 @@ to perform some manual editing steps. the source gzip and xz tarballs, documentation tar and zip files, and gpg signature files:: - $ .../release-tools/release.py --export X.Y.ZaN + $ .../release-tools/release.py --export 3.X.YaN This can take a while for **final** releases, and it will leave all the - tarballs and signatures in a subdirectory called ``X.Y.ZaN/src``, and the - built docs in ``X.Y.ZaN/docs`` (for **final** releases). + tarballs and signatures in a subdirectory called ``3.X.YaN/src``, and the + built docs in ``3.X.YaN/docs`` (for **final** releases). Note that the script will sign your release with Sigstore. Please use your **@python.org** email address for this. See here for more information: @@ -368,20 +355,16 @@ to perform some manual editing steps. - Notify the experts that they can start building binaries. -- STOP STOP STOP STOP STOP STOP STOP STOP +.. warning:: - At this point you must receive the "green light" from other experts in - order to create the release. There are things you can do while you wait + **STOP**: at this point you must receive the "green light" from other experts + in order to create the release. There are things you can do while you wait though, so keep reading until you hit the next STOP. - The WE generates and publishes the Windows files using the Azure Pipelines build scripts in ``.azure-pipelines/windows-release/``, currently set up at https://dev.azure.com/Python/cpython/_build?definitionId=21. - Note that this build requires a separate VM containing the code signing - certificate. This VM is managed by the WE to ensure only official releases - have access to the certificate. - The build process runs in multiple stages, with each stage's output being available as a downloadable artifact. The stages are: @@ -420,7 +403,7 @@ to perform some manual editing steps. over there. Our policy is that every Python version gets its own directory, but each directory contains all releases of that version. - - On downloads.nyc1.psf.io, cd /srv/www.python.org/ftp/python/X.Y.Z + - On downloads.nyc1.psf.io, ``cd /srv/www.python.org/ftp/python/3.X.Y`` creating it if necessary. Make sure it is owned by group 'downloads' and group-writable. @@ -434,13 +417,13 @@ to perform some manual editing steps. - Use ``gpg --verify`` to make sure they got uploaded intact. - If this is a **final** or rc release: Move the doc zips and tarballs to - ``/srv/www.python.org/ftp/python/doc/X.Y.Z[rcA]``, creating the directory + ``/srv/www.python.org/ftp/python/doc/3.X.Y[rcA]``, creating the directory if necessary, and adapt the "current" symlink in ``.../doc`` to point to that directory. Note though that if you're releasing a maintenance release for an older version, don't change the current link. - If this is a **final** or rc release (even a maintenance release), also - unpack the HTML docs to ``/srv/docs.python.org/release/X.Y.Z[rcA]`` on + unpack the HTML docs to ``/srv/docs.python.org/release/3.X.Y[rcA]`` on docs.nyc1.psf.io. Make sure the files are in group ``docs`` and are group-writeable. If it is a release of a security-fix-only version, tell the DE to start a build (``security-fixes`` and ``EOL`` version @@ -449,18 +432,18 @@ to perform some manual editing steps. - Let the DE check if the docs are built and work all right. - If this is a **final** major release: Tell the DE to adapt redirects for - docs.python.org/X.Y in the nginx config for docs.python.org. + docs.python.org/3.X in the nginx config for docs.python.org. - Note both the documentation and downloads are behind a caching CDN. If you change archives after downloading them through the website, you'll need to purge the stale data in the CDN like this:: - $ curl -X PURGE https://www.python.org/ftp/python/2.7.5/Python-2.7.5.tar.xz + $ curl -X PURGE https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tar.xz You should always purge the cache of the directory listing as people use that to browse the release files:: - $ curl -X PURGE https://www.python.org/ftp/python/2.7.5/ + $ curl -X PURGE https://www.python.org/ftp/python/3.12.0/ - For the extra paranoid, do a completely clean test of the release. This includes downloading the tarball from www.python.org. @@ -475,18 +458,20 @@ to perform some manual editing steps. To ensure that the regression test suite passes. If not, you screwed up somewhere! -- STOP STOP STOP STOP STOP STOP STOP STOP +.. warning:: - - Have you gotten the green light from the WE? + **STOP** and confirm: - - Have you gotten the green light from the ME? + - Have you gotten the green light from the WE? - - Have you gotten the green light from the DE? + - Have you gotten the green light from the ME? + + - Have you gotten the green light from the DE? If green, it's time to merge the release engineering branch back into the main repo. -- In order to push your changes to Github, you'll have to temporarily +- In order to push your changes to GitHub, you'll have to temporarily disable branch protection for administrators. Go to the ``Settings | Branches`` page: @@ -511,18 +496,18 @@ the main repo. # 2. Else, for all other releases, checkout the # appropriate release branch. - $ git checkout X.Y + $ git checkout 3.X # Fetch the newly created and signed tag from your clone repo - $ git fetch --tags git@github.com:your-github-id/cpython.git vX.Y.ZaN + $ git fetch --tags git@github.com:your-github-id/cpython.git v3.X.YaN # Merge the temporary release engineering branch back into - $ git merge --no-squash vX.Y.ZaN + $ git merge --no-squash v3.X.YaN $ git commit -m 'Merge release engineering branch' - If this is a **new branch** release, i.e. first beta, now create the new release branch:: - $ git checkout -b X.Y + $ git checkout -b 3.X Do any steps needed to setup the new release branch, including: @@ -532,7 +517,7 @@ the main repo. - For *all* releases, do the guided post-release steps with the release script.:: - $ .../release-tools/release.py --done X.Y.ZaN + $ .../release-tools/release.py --done 3.X.YaN - For a **final** or **release candidate 2+** release, you may need to do some post-merge cleanup. Check the top-level ``README.rst`` @@ -621,27 +606,27 @@ the main repo. $ git push --tags git@github.com:python/cpython.git main # For a **new branch** release, i.e. first beta: - $ git push --dry-run --tags git@github.com:python/cpython.git X.Y + $ git push --dry-run --tags git@github.com:python/cpython.git 3.X $ git push --dry-run --tags git@github.com:python/cpython.git main # If it looks OK, take the plunge. There's no going back! - $ git push --tags git@github.com:python/cpython.git X.Y + $ git push --tags git@github.com:python/cpython.git 3.X $ git push --tags git@github.com:python/cpython.git main # For all other releases: - $ git push --dry-run --tags git@github.com:python/cpython.git X.Y + $ git push --dry-run --tags git@github.com:python/cpython.git 3.X # If it looks OK, take the plunge. There's no going back! - $ git push --tags git@github.com:python/cpython.git X.Y + $ git push --tags git@github.com:python/cpython.git 3.X - If this is a **new branch** release, add a ``Branch protection rule`` - for the newly created branch (X.Y). Look at the values for the previous - release branch (X.Y-1) and use them as a template. + for the newly created branch (3.X). Look at the values for the previous + release branch (3.X-1) and use them as a template. https://github.com/python/cpython/settings/branches/ - Also, add a ``needs backport to X.Y`` label to the Github repo. + Also, add a ``needs backport to 3.X`` label to the GitHub repo. https://github.com/python/cpython/labels - You can now re-enable enforcement of branch settings against administrators - on Github. Go back to the ``Settings | Branch`` page: + on GitHub. Go back to the ``Settings | Branch`` page: https://github.com/python/cpython/settings/branches/ @@ -692,10 +677,8 @@ with RevSys.) Keep a copy in your home directory on dl-files and keep it fresh. - If new types of files are added to the release - (e.g. the web-based installers or redistributable zip - files added to Python 3.5) someone will need to update - add-to-pydotorg.py so it recognizes these new files. + If new types of files are added to the release, someone will need to + update add-to-pydotorg.py so it recognizes these new files. (It's best to update add-to-pydotorg.py when file types are removed, too.) @@ -715,19 +698,19 @@ with RevSys.) page ``https://www.python.org/doc/versions/`` and remove the current version from any 'in development' section. - - For X.Y.Z, edit all the previous X.Y releases' page(s) to + - For 3.X.Y, edit all the previous X.Y releases' page(s) to point to the new release. This includes the content field of the ``Downloads -> Releases`` entry for the release:: - Note: Python x.y.m has been superseded by - `Python x.y.n </downloads/release/python-xyn/>`_. + Note: Python 3.x.(y-1) has been superseded by + `Python 3.x.y </downloads/release/python-3xy/>`_. And, for those releases having separate release page entries (phasing these out?), update those pages as well, - e.g. ``download/releases/x.y.z``:: + e.g. ``download/releases/3.x.y``:: - Note: Python x.y.m has been superseded by - `Python x.y.n </download/releases/x.y.n/>`_. + Note: Python 3.x.(y-1) has been superseded by + `Python 3.x.y </download/releases/3.x.y/>`_. - Update the "Current Pre-release Testing Versions web page". @@ -739,12 +722,11 @@ with RevSys.) Every time you make a release, one way or another you'll have to update this page: - - If you're releasing a version before *x.y.0*, - or *x.y.z release candidate N,* + - If you're releasing a version before *3.x.0*, you should add it to this page, removing the previous pre-release - of version *x.y* as needed. + of version *3.x* as needed. - - If you're releasing *x.y.z final*, you need to remove the pre-release + - If you're releasing *3.x.0 final*, you need to remove the pre-release version from this page. This is in the "Pages" category on the Django-based website, and finding @@ -764,15 +746,12 @@ with RevSys.) should go. And yes you should be able to click on the link above then press the shiny, exciting "Edit this page" button. - - Other steps (other update for new web site)?? - -- Write the announcement for the mailing lists. This is the +- Write the announcement on https://discuss.python.org/. This is the fuzzy bit because not much can be automated. You can use an earlier announcement as a template, but edit it for content! - -- Once the announcement is ready, send it to the following - addresses: +- Once the announcement is up on Discourse, send an equivalent to the + following mailing lists: python-list@python.org python-announce@python.org @@ -783,29 +762,19 @@ with RevSys.) To add a new entry, go to `your Blogger home page, here. <https://www.blogger.com/home>`_ -- Send email to python-committers informing them that the release has been - published and a reminder about any relevant changes in policy - based on the phase of the release cycle. In particular, - if this is a **new branch** release, remind everyone that the - new release branch exists and that they need to start - considering whether to backport to it when merging changes to - main. +- Update any release PEPs (e.g. 719) with the release dates. -- Update any release PEPs (e.g. 361) with the release dates. +- Update the labels on https://github.com/python/cpython/issues: -- Update the tracker at https://bugs.python.org: - - - Flip all the deferred blocker issues back to release blocker + - Flip all the deferred-blocker issues back to release-blocker for the next release. - - Add version X.Y+1 as when version X.Y enters alpha. + - Add version 3.X+1 as when version 3.X enters alpha. - - Change non-doc RFEs to version X.Y+1 when version X.Y enters beta. + - Change non-doc feature requests to version 3.X+1 when version 3.X + enters beta. - - Add ``X.Yregression`` keyword (https://bugs.python.org/keyword) - when version X.Y enters beta. - - - Update 'behavior' issues from versions that your release make + - Update issues from versions that your release makes unsupported to the next supported version. - Review open issues, as this might find lurking showstopper bugs, @@ -817,13 +786,8 @@ with RevSys.) pieces of the development infrastructure are updated for the new branch. These include: - - Update the issue tracker for the new branch. - - * Add the new version to the versions list (contact the tracker - admins?). - - * Add a `regressions keyword <https://bugs.python.org/keyword>`_ - for the release + - Update the issue tracker for the new branch: add the new version to + the versions list. - Update the devguide to reflect the new branches and versions. @@ -831,12 +795,13 @@ with RevSys.) `downloads page <https://www.python.org/downloads/>`_. (See https://github.com/python/pythondotorg/issues/1302) - - Ensure buildbots are defined for the new branch (contact zware). + - Ensure buildbots are defined for the new branch (contact Łukasz + or Zach Ware). - Ensure the daily docs build scripts are updated to include the new branch (contact DE). - - Ensure the various Github bots are updated, as needed, for the + - Ensure the various GitHub bots are updated, as needed, for the new branch, in particular, make sure backporting to the new branch works (contact core-workflow team) https://github.com/python/core-workflow/issues @@ -904,7 +869,7 @@ else does them. Some of those tasks include: - If all looks good, delete the branch. This may require the assistance of someone with repo administrator privileges:: - git push upstream --delete 3.3 # or perform from Github Settings page + git push upstream --delete 3.3 # or perform from GitHub Settings page - Remove the release from the list of "Active Python Releases" on the Downloads page. To do this, log in to the admin page for python.org, navigate to Boxes, @@ -923,31 +888,20 @@ else does them. Some of those tasks include: list (https://devguide.python.org/devcycle/#end-of-life-branches) and update or remove references to the branch elsewhere in the devguide. -- Retire the release from the bugs.python.org issue tracker. Tasks include: +- Retire the release from the issue tracker. Tasks include: - * remove branch from tracker list of versions + * remove version label from list of versions - * remove any release-release keywords (3.3regressions) + * remove the "needs backport to" label for the retired version * review and dispose of open issues marked for this branch - Note, with the likely future migration of bug tracking from the current - Roundup bugs.python.org to Github issues and with the impending end-of-life - of Python 2.7, it probably makes sense to avoid unnecessary churn for - currently and about-to-be retired 3.x branches by deferring any major - wholesale changes to existing issues until the migration process is - clarified. - - In practice, you're probably not going to do this yourself, you're going - to ask one of the bpo maintainers to do it for you (e.g. Ezio Melotti, - Zachary Ware.) - - Announce the branch retirement in the usual places: - * mailing lists (python-committers, python-dev, python-list, python-announcements) - * discuss.python.org + * mailing lists (python-dev, python-list, python-announcements) + * Python Dev blog - Enjoy your retirement and bask in the glow of a job well done! @@ -956,12 +910,12 @@ else does them. Some of those tasks include: Windows Notes ============= -NOTE, have Steve Dower review; probably obsolete. - Windows has a MSI installer, various flavors of Windows have "special limitations", and the Windows installer also packs -precompiled "foreign" binaries (Tcl/Tk, expat, etc). So Windows -testing is tiresome but very necessary. +precompiled "foreign" binaries (Tcl/Tk, expat, etc). + +The installer is tested as part of the Azure Pipeline. In the past, +those steps were performed manually. We're keeping this for posterity. Concurrent with uploading the installer, the WE installs Python from it twice: once into the default directory suggested by the From 619e4e239383b5f59e34ebebc36278aebf599a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl> Date: Mon, 9 Oct 2023 13:25:03 +0200 Subject: [PATCH 138/173] Update PEP 602 with 2 years of full support of Python 3.13+ --- peps/pep-0602.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/peps/pep-0602.rst b/peps/pep-0602.rst index 2cbf8c29c..1d7089fda 100644 --- a/peps/pep-0602.rst +++ b/peps/pep-0602.rst @@ -9,6 +9,7 @@ Status: Accepted Type: Informational Content-Type: text/x-rst Created: 04-Jun-2019 +Post-History: 9-Oct-2023 Python-Version: 3.9 @@ -44,22 +45,28 @@ This PEP proposes that Python 3.X.0 will be developed for around if necessary) and conclude with the release of the final release of Python 3.X.0. -1½ year of full support, 3½ more years of security fixes --------------------------------------------------------- +2 years of full support, 3 more years of security fixes +------------------------------------------------------- After the release of Python 3.X.0, the 3.X series is maintained for five years: -- During the *first eighteen months* (1½ year) it receives bugfix +- During the *first twenty four months* (2 years) it receives bugfix updates and full releases (sources and installers for Windows and macOS) are made approximately every other month. -- For the next *forty two months* (3½ years) it receives security +- For the next *thirty six months* (3 years) it receives security updates and source-only releases are made on an as-needed basis (no fixed cadence). - The final source-only release is made *five years* after 3.X.0. +Note: 2 years of full support start with +`Python 3.13 <https://peps.python.org/pep-0719/>`_. Python versions +3.9 - 3.12 operate on a calendar with 1½ year of full support, followed +by 3½ more years of security fixes. + + Annual release cadence ---------------------- From f98b4c7dc1050029900b4718bc0ab14f28035fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl> Date: Mon, 9 Oct 2023 15:05:31 +0200 Subject: [PATCH 139/173] Add sphinx-warnings.txt to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6beae9d8e..6004c5e61 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ coverage.xml # Virtual environments *env /venv + +# Builds +/sphinx-warnings.txt \ No newline at end of file From 39eb8f322bfb4243158b813efbd617988a37a70b Mon Sep 17 00:00:00 2001 From: Zachary Ware <zach@python.org> Date: Mon, 9 Oct 2023 18:34:22 -0500 Subject: [PATCH 140/173] PEP 602: Fix lint, unbreak CI (#3467) --- peps/pep-0602.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/peps/pep-0602.rst b/peps/pep-0602.rst index 1d7089fda..f16c5cfdc 100644 --- a/peps/pep-0602.rst +++ b/peps/pep-0602.rst @@ -9,7 +9,6 @@ Status: Accepted Type: Informational Content-Type: text/x-rst Created: 04-Jun-2019 -Post-History: 9-Oct-2023 Python-Version: 3.9 @@ -62,7 +61,7 @@ five years: - The final source-only release is made *five years* after 3.X.0. Note: 2 years of full support start with -`Python 3.13 <https://peps.python.org/pep-0719/>`_. Python versions +:pep:`Python 3.13 <719>`. Python versions 3.9 - 3.12 operate on a calendar with 1½ year of full support, followed by 3½ more years of security fixes. From 7079a94edaab00d7d5a97e1ba7bc061e9a2f14e5 Mon Sep 17 00:00:00 2001 From: Zachary Ware <zach@python.org> Date: Mon, 9 Oct 2023 18:43:15 -0500 Subject: [PATCH 141/173] PEP 8001: Update my email address (#3466) --- peps/pep-8001.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-8001.rst b/peps/pep-8001.rst index d4020e2dc..9746d61d2 100644 --- a/peps/pep-8001.rst +++ b/peps/pep-8001.rst @@ -12,7 +12,7 @@ Author: Brett Cannon <brett@python.org>, Raymond Hettinger <python@rcn.com>, Tal Einat <tal@python.org>, Tim Peters <tim.peters@gmail.com>, - Zachary Ware <zachary.ware@gmail.com> + Zachary Ware <zach@python.org> Status: Final Type: Process Topic: Governance From 7983fbd635ebd8bba8af3226333deb97784d36ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=9C=E6=96=B9=E7=90=83?= <cdhmuer333@126.com> Date: Tue, 10 Oct 2023 13:32:07 +0800 Subject: [PATCH 142/173] PEP 282: update the log4j link in references (#3470) --- peps/pep-0282.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0282.rst b/peps/pep-0282.rst index a328a01b3..36c6730eb 100644 --- a/peps/pep-0282.rst +++ b/peps/pep-0282.rst @@ -613,7 +613,7 @@ References http://java.sun.com/j2se/1.4/docs/guide/util/logging/ .. [2] log4j: a Java logging package - http://jakarta.apache.org/log4j/docs/index.html + https://logging.apache.org/log4j/ .. [3] Protomatter's Syslog http://protomatter.sourceforge.net/1.1.6/index.html From dd08f74688c3fc0b9eea1eb9def81ea796850277 Mon Sep 17 00:00:00 2001 From: Zachary Ware <zach@python.org> Date: Tue, 10 Oct 2023 06:05:14 -0500 Subject: [PATCH 143/173] PEP 632: Mark as Final (#3468) --- peps/pep-0632.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0632.rst b/peps/pep-0632.rst index efd40ec6e..43f732e11 100644 --- a/peps/pep-0632.rst +++ b/peps/pep-0632.rst @@ -2,7 +2,7 @@ PEP: 632 Title: Deprecate distutils module Author: Steve Dower <steve.dower@python.org> Discussions-To: https://discuss.python.org/t/pep-632-deprecate-distutils-module/5134 -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 03-Sep-2020 From 32db9d6112c68158f22f048d4419b366893c1d26 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado <Pablogsal@gmail.com> Date: Tue, 10 Oct 2023 15:14:41 +0200 Subject: [PATCH 144/173] PEP 701: Clarify that newlines also end format specifier mode (#3460) --- peps/pep-0701.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0701.rst b/peps/pep-0701.rst index f4b393d0b..b83ba92a2 100644 --- a/peps/pep-0701.rst +++ b/peps/pep-0701.rst @@ -373,8 +373,8 @@ tokens: 2. Keep consuming tokens until a one of the following is encountered: * A closing quote equal to the opening quote. - * If in "format specifier mode" (see step 3), an opening brace (``{``) or a - closing brace (``}``). + * If in "format specifier mode" (see step 3), an opening brace (``{``), a + closing brace (``}``), or a newline token (``\n``). * If not in "format specifier mode" (see step 3), an opening brace (``{``) or a closing brace (``}``) that is not immediately followed by another opening/closing brace. From ad2f54ba43649d5da391f50b27001e0b2be75883 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:15:34 +0200 Subject: [PATCH 145/173] PEP 654, 678, 680: Mark as Final (#3193) * PEP 654, 678, 680: Mark as Final * PEP 654: Add Discussions-To * PEP 654: Add Resolution * PEP 678, 680: Update Post-History * PEP 654, 678, 680: Link to canonical docs * PEP 654, 707: Update Irit's email --------- Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM> --- peps/pep-0654.rst | 13 ++++++++++--- peps/pep-0678.rst | 7 +++++-- peps/pep-0680.rst | 6 ++++-- peps/pep-0707.rst | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/peps/pep-0654.rst b/peps/pep-0654.rst index 113f657fc..b2b183a32 100644 --- a/peps/pep-0654.rst +++ b/peps/pep-0654.rst @@ -1,15 +1,22 @@ PEP: 654 Title: Exception Groups and except* -Author: Irit Katriel <iritkatriel@gmail.com>, +Author: Irit Katriel <irit@python.org>, Yury Selivanov <yury@edgedb.com>, Guido van Rossum <guido@python.org> -Status: Accepted +Discussions-To: https://discuss.python.org/t/accepting-pep-654-exception-groups-and-except/10813 +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 22-Feb-2021 Python-Version: 3.11 -Post-History: 22-Feb-2021, 20-Mar-2021 +Post-History: `22-Feb-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/L5Q27DVKOKZCDNCAWRIQVOZ5DZCZHLRM/>`__, + `20-Mar-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/MQ2UCSQ2ZC4FIGT7KSVI6BJA4FCXSOCL/>`__, + `03-Oct-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/4B256YKUPW5P2M44GG5H6FBL3PSV6ODP/>`__, +Resolution: https://discuss.python.org/t/accepting-pep-654-exception-groups-and-except/10813/1 +.. canonical-doc:: :ref:`python:lib-exception-groups` and :ref:`python:except_star` + + See :ref:`python:tut-exception-groups` for a user-focused tutorial. Abstract ======== diff --git a/peps/pep-0678.rst b/peps/pep-0678.rst index 140cef283..0e27b0245 100644 --- a/peps/pep-0678.rst +++ b/peps/pep-0678.rst @@ -3,15 +3,18 @@ Title: Enriching Exceptions with Notes Author: Zac Hatfield-Dodds <zac@zhd.dev> Sponsor: Irit Katriel Discussions-To: https://discuss.python.org/t/pep-678-enriching-exceptions-with-notes/13374 -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Requires: 654 Created: 20-Dec-2021 Python-Version: 3.11 -Post-History: 27-Jan-2022 +Post-History: `27-Jan-2022 <https://discuss.python.org/t/pep-678-enriching-exceptions-with-notes/13374>`__ Resolution: https://discuss.python.org/t/pep-678-enriching-exceptions-with-notes/13374/100 +.. canonical-doc:: :meth:`python:BaseException.add_note` and :attr:`python:BaseException.__notes__` + + See :ref:`python:tut-exception-notes` for a user-focused tutorial. Abstract ======== diff --git a/peps/pep-0680.rst b/peps/pep-0680.rst index 97e250d15..d709d4fdb 100644 --- a/peps/pep-0680.rst +++ b/peps/pep-0680.rst @@ -3,14 +3,16 @@ Title: tomllib: Support for Parsing TOML in the Standard Library Author: Taneli Hukkinen, Shantanu Jain <hauntsaninja at gmail.com> Sponsor: Petr Viktorin <encukou@gmail.com> Discussions-To: https://discuss.python.org/t/13040 -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 01-Jan-2022 Python-Version: 3.11 -Post-History: 11-Jan-2022 +Post-History: `09-Dec-2021 <https://mail.python.org/archives/list/python-ideas@python.org/thread/IWJ3I32A4TY6CIVQ6ONPEBPWP4TOV2V7/>`__, + `27-Jan-2022 <https://discuss.python.org/t/pep-680-tomllib-support-for-parsing-toml-in-the-standard-library/13040>`__, Resolution: https://mail.python.org/archives/list/python-dev@python.org/thread/3AHGWYY562HHO55L4Z2OVYUFZP5W73IS/ +.. canonical-doc:: :mod:`python:tomllib` Abstract ======== diff --git a/peps/pep-0707.rst b/peps/pep-0707.rst index eb1ad75b0..6e54b6111 100644 --- a/peps/pep-0707.rst +++ b/peps/pep-0707.rst @@ -1,6 +1,6 @@ PEP: 707 Title: A simplified signature for __exit__ and __aexit__ -Author: Irit Katriel <iritkatriel@gmail.com> +Author: Irit Katriel <irit@python.org> Discussions-To: https://discuss.python.org/t/24402 Status: Rejected Type: Standards Track From 1418d8b7b9b6c1ebf2a88234c0a50f46f56c3b1b Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee <russell@keith-magee.com> Date: Wed, 11 Oct 2023 10:57:44 +0200 Subject: [PATCH 146/173] PEP 730: Adding iOS as a supported platform (#3473) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: T. Wouters <thomas@python.org> Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> --- .github/CODEOWNERS | 1 + peps/pep-0730.rst | 368 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 peps/pep-0730.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e37a20907..b0614a90b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -607,6 +607,7 @@ peps/pep-0725.rst @pradyunsg peps/pep-0726.rst @AA-Turner peps/pep-0727.rst @JelleZijlstra peps/pep-0729.rst @JelleZijlstra @hauntsaninja +peps/pep-0730.rst @ned-deily # ... # peps/pep-0754.rst # ... diff --git a/peps/pep-0730.rst b/peps/pep-0730.rst new file mode 100644 index 000000000..e759aabad --- /dev/null +++ b/peps/pep-0730.rst @@ -0,0 +1,368 @@ +PEP: 730 +Title: Adding iOS as a supported platform +Author: Russell Keith-Magee <russell@keith-magee.com> +Sponsor: Ned Deily <nad@python.org> +Discussions-To: https://discuss.python.org/t/pep730-adding-ios-as-a-supported-platform/35854 +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 09-Oct-2023 +Python-Version: 3.13 + +Abstract +======== + +This PEP proposes adding iOS as a supported platform in CPython. The initial +goal is to achieve Tier 3 support for Python 3.13. This PEP describes the +technical aspects of the changes that are required to support iOS. It also +describes the project management concerns related to adoption of iOS as a Tier 3 +platform. + +Motivation +========== + +Over the last 15 years, mobile platforms have become increasingly important +parts of the computing landscape. iOS is one of two operating systems that +control the vast majority of these devices. However, there is no official +support for iOS in CPython. + +The `BeeWare Project <https://beeware.org>`__ and `Kivy <https://kivy.org>`__ +have both supported iOS for almost 10 years. This support has been able to +generate applications that have been accepted for publication in the iOS App +Store. This demonstrates the technical feasibility of iOS support. + +It is important for the future of Python as a language that it is able to be +used on any hardware or OS that has widespread adoption. If Python cannot be +used a on a platform that has widespread use, adoption of the language will be +impacted as potential users will adopt other languages that *do* provide support +for these platforms. + +Rationale +========= + +Development landscape +--------------------- + +iOS provides a single API, but 2 distinct ABIs - ``iphoneos`` (physical +devices), and ``iphonesimulator``. Each of these ABIs can be provided on +multiple CPU architectures. At time of writing, Apple officially supports +``arm64`` on the device ABI, and ``arm64`` and ``x86_64`` are supported on the +simulator ABI. + +As with macOS, iOS supports the creation of "fat" binaries that contains +multiple CPU architectures. However, fat binaries *cannot* span ABIs. That is, +it is possible to have a fat *simulator* binary, and a fat *device* binary, but +it is not possible to create a single fat "iOS" binary that covers both +simulator and device needs. To support distribution of a single development +artefact, Apple uses an "XCframework" structure - a wrapper around multiple ABIs +that implement a common API. + +iOS runs on a Darwin kernel, similar to macOS. However, there is a need to +differentiate between macOS and iOS at an implementation level, as there are +significant platform differences between iOS and macOS. + +iOS code is compiled for compatibility against a minimum iOS version. + +POSIX compliance +---------------- + +iOS is broadly a POSIX platform. However, similar to WASI/Emscripten, there are +POSIX APIs that exist on iOS, but cannot be used; and POSIX APIs that don't +exist at all. + +Most notable of these is the fact that iOS does not provide any form of +multiprocess support. ``fork`` and ``spawn`` both *exist* in the iOS API; +however, if they are invoked, the invoking iOS process stops, and the new +process doesn't start. + +Unlike WASI/Emscripten, threading *is* supported on iOS. + +There are also significant limits to socket handling. Due to process sandboxing, +there is no availability of interprocess communication via socket. However, +sockets for network communication *are* available. + +Dynamic libraries +----------------- + +The iOS `App Store guidelines +<https://developer.apple.com/app-store/review/guidelines>`__ allow apps to be +written in languages other than Objective C or Swift. However, they have very +strict guidelines about the structure of apps that are submitted for +distribution. + +iOS apps can use dynamically loaded libraries; however, there are very strict +requirements on how dynamically loaded content is packaged for use on iOS: + +* Dynamic binary content must be compiled as dynamic libraries, not shared + objects or binary bundles. + +* They must be packaged in the app bundle as Frameworks. + +* Each Framework can only contain a single dynamic library. + +* The Framework *must* be contained in the iOS App's ``Frameworks`` folder. + +* A Framework may not contain any non-library content. + +This imposes some constraints on the operation of CPython. It is not possible +store binary modules in the ``lib-dynload`` and/or ``site-packages`` folders; +they must be stored in the app's Frameworks folder, with each module wrapped in +a Framework. This also means that the common assumption that a Python module can +construct the location of a binary module by using the ``__file__`` attribute of +the Python module no longer holds. + +As with macOS, compiling a dynamic library requires the use of the ``--undefined +dynamic_lookup`` option to avoid linking libPython into every binary module. +This option currently raises a deprecation warning when it is used. This warning +*was* previously raised on macOS builds as well; however, responses from Apple +staff suggests this was unintentional, and they `did not intend to break the +CPython ecosystem by removing this option +<https://developer.apple.com/forums/thread/719961>`__. It is difficult to judge +whether iOS support would fall under the same umbrella. + +Distribution +------------ + +Adding iOS as a Tier 3 platform only requires adding support for compiling an +iOS-compatibile code with an unpatched CPython code checkout. It does not +require production of officially distributed iOS artefacts for use by end-users. + +If/when iOS is updated to Tier 2 or 1 support, there should be a process for +producing iOS distribution artefacts. This could be in the form of an "embedded +distribution" analogous to the Windows embedded distribution, or as a Cocoapod +or Swift Package that could be added to an Xcode project. + +Console and interactive usage +----------------------------- + +Distribution of a traditional CPython REPL or interactive "python.exe" should +not be considered a goal of this work. + +Mobile devices (including iOS) do not provide a TTY-style console. They do not +provide ``stdin``, ``stdout`` or ``stderr``. iOS provides a system log, and it +is possible to install a redirection so that all ``stdout`` and ``stderr`` +content is redirected to the system log; but there is no analog for +``stdin``. + +In addition, iOS places restrictions on downloading additional code at runtime +(as this behavior would be functionally indistinguishable from trying to work +around App Store review). As a result, a traditional "create a virtual +environment and pip install" development experience will not be viable on iOS. + +It is *possible* to build an native iOS application that provides a REPL +interface. This would be closer to an IDLE-style user experience; however, +Tkinter cannot be used on iOS, so any app would require a ground-up rewrite. The +iOS app store already contains several examples of apps in this category (e.g., +`Pythonista <http://www.omz-software.com/pythonista/>`__ and `Pyto +<https://pyto.readthedocs.io/>`__). The focus of this work would be to provide +an embedded distribution that IDE-style native interfaces could utilize, not a +user-facing "app" interface to iOS on Python. + +Specification +============= + +Platform identification +----------------------- + +``sys`` +''''''' + +``sys.platform`` will identify as ``"ios"`` on both simulator and physical +devices. + +``sys.implementation._multiarch`` will describe the ABI and CPU architecture: + +* ``"iphoneos-arm64"`` for ARM64 devices +* ``"iphonesimulator-arm64"`` for ARM64 simulators +* ``"iphonesimulator-x86_64"`` for x86_64 simulators + +``sys.implementation`` will also have an additional attribute - ``_simulator`` - +storing a Boolean that is ``True`` if the device running the app is a simulator. +This attribute would not exist on non-iOS platforms. + +``platform`` +'''''''''''' + +Platform will be used as the primary mechanism for retrieving OS and device +details. + +* ``platform.system()`` - ``"iOS"`` + +* ``platform.node()`` - the user-provided name of the device, as returned by the + ``[[UIDevice currentDevice] systemName]`` system call (e.g., + ``"Janes-iPhone"``). For simulated devices, this will be the name of the + development computer running the simulator. + +* ``platform.release()`` - the iOS version number, as a string (e.g., ``"16.6.1"``) + +* ``platform.machine()`` - The device model returned by ``[[UIDevice + currentDevice] model]`` (e.g., ``"iPhone13,2"``); or ``"iPhoneSimulator"`` for + simulated devices. + +All other values will be as returned by ``os.uname()`` + +``os`` +'''''' + +``os.uname()`` will return the raw result of a POSIX ``uname()`` call. This will +result in the following values: + +* ``sysname`` - ``"Darwin"`` + +* ``release`` - The Darwin kernel version (e.g., ``"22.6.0"``) + +``sysconfig`` +''''''''''''' + +The ``sysconfig`` module will use the minimum iOS version as part of +``sysconfig.get_platform()`` identifier (e.g., ``"iOS-12.0-iphoneos-arm64"``). +The ``sysconfigdata_name`` and Config makefile will follow the same patterns as +existing platforms (using ``sys.platform``, ``sys.implementation._multiarch`` +etc.) to construct identifiers. + +Subprocess support +------------------ + +iOS will leverage the pattern for disabling subprocesses established by +WASI/Emscripten. The ``subprocess`` module will raise an exception if an attempt +is made to start a subprocess, and ``os.fork`` and ``os.spawn`` calls will raise +an ``OSError``. + +Dynamic module loading +---------------------- + +To accommodate iOS dynamic loading, the ``importlib`` bootstrap will be extended +to add a metapath finder that can convert a request for a Python binary module +into a Framework location. This finder will only be installed if ``sys.platform +== "ios"``. + +This finder will convert a Python module name (e.g., ``foo.bar._whiz``) into a +unique Framework name by replacing the dots with underscores (i.e., +``foo_bar__whiz.framework``). A framework is a directory; the finder will look +for ``_whiz.dylib`` in that directory. + +CI resources +------------ + +GitHub Actions is able to host iOS simulators on their macOS machines, and the +iOS simulator can be controlled by scripting environments. The free tier +currently only provides x86_64 macOS machines; however ARM64 runners `have +recently become available on paid plans <https://github.blog/ +2023-10-02-introducing-the-new-apple-silicon-powered-m1-macos-larger-runner-for-github-actions/>`__. + +If GitHub Actions resources are insufficient or not viable for cost reasons, +Anaconda has offered to provide resources to support CI requirements. + +Packaging +--------- + +iOS will not provide a "universal" wheel format. Instead, wheels will be +provided for each ABI-arch combination. At present, no binary merging is +required. There is only one on-device architecture; and simulator binaries are +not considered to be distributable artefacts, so only one architecture is needed +to build a simulator. + +iOS wheels will use tags: + +* ``iOS_12_0_iphoneos_arm64`` +* ``iOS_12_0_iphonesimulator_arm64`` +* ``iOS_12_0_iphonesimulator_x86_64`` + +In these tags, "12.0" is the minimum supported iOS version. The choice of +minimum supported iOS version is a decision of whoever compiles CPython for iOS. +At time of writing, iOS 12.0 exposes most significant iOS features, while +reaching near 100% of devices. + +These wheels can include binary modules in-situ (i.e., co-located with the +Python source, in the same way as wheels for a desktop platform); however, they +will need to be post-processed as binary modules need to be moved into the +"Frameworks" location for distribution. This can be automated with an Xcode +build step. + +PEP 11 Update +------------- + +:pep:`11` will be updated to include the three iOS ABIs: + +* ``aarch64-apple-ios`` +* ``aarch64-apple-ios-simulator`` +* ``x86_64-apple-ios-simulator`` + +Ned Deily will serve as the initial core team contact for these ABIs. + +Backwards Compatibility +======================= + +Adding a new platform does not introduce any backwards compatibility concerns to +CPython itself. + +There may be some backwards compatibility implications on the projects that have +historically provided CPython support (i.e., BeeWare and Kivy) if the final form +of any CPython patches don't align with the patches they have historically used. + +Although not strictly a backwards compatibility issue, there *is* a platform +adoption consideration. Although CPython itself may support iOS, if it is +unclear how to produce iOS-compatible wheels, and prominent libraries like +cryptography, Pillow, and NumPy don't provide iOS wheels, the ability of the +community to adopt Python on iOS will be limited. Therefore, it will be +necessary to clearly document how projects can add iOS builds to their CI and +release tooling. Adding iOS support to tools like `crossenv +<https://crossenv.readthedocs.io/>`__ and `cibuildwheel +<https://cibuildwheel.readthedocs.io/>`__ may be one way to achieve this. + +Security Implications +===================== + +Adding iOS as a new platform does not add any security implications. + +How to Teach This +================= + +The education needs related to this PEP mostly relate to how end-users can add +iOS support to their own Xcode projects. This can be accomplished with +documentation and tutorials on that process. The need for this documentation +will increase if/when support raises from Tier 3 to Tier 2 or 1; however, this +transition should also be accompanied with simplified deployment artefacts (such +as a Cocoapod or Swift package) that are integrated with Xcode development. + +Reference Implementation +======================== + +The BeeWare `Python-Apple-support +<https://github.com/beeware/Python-Apple-support>`__ repository contains a +reference patch and build tooling to compile a distributable artefact. + +`Briefcase <https://briefcase.readthedocs.org>`__ provides a reference +implementation of code to execute test suites on iOS simulators. The `Toga +Testbed <https://github.com/beeware/toga/tree/main/testbed>`__ is an example of +a test suite that is executed on the iOS simulator using GitHub Actions. + +Rejected Ideas +============== + +``sys.implementation._simulator`` availability +---------------------------------------------- + +The ``_simulator`` attribute could be provided on *all* platforms, returning +``False``. However, the attribute has no use outside of an iOS context. + +Open Issues +=========== + +On-device testing +----------------- + +CI testing on simulators can be accommodated reasonably easily. +On-device testing is much harder, as availability of device farms that could be +configured to provide Buildbots or Github Actions runners is limited. + +However, on device testing may not be necessary. As a data point - Apple's Xcode +Cloud solution doesn't provide on-device testing. They rely on the fact that the +API is consistent between device and simulator, and ARM64 simulator testing is +sufficient to reveal CPU-specific issues. + +Copyright +========= + +This document is placed in the public domain or under the CC0-1.0-Universal +license, whichever is more permissive. From e38ee92c88e8a5bb845becead6a22f6c31c97203 Mon Sep 17 00:00:00 2001 From: Petr Viktorin <encukou@gmail.com> Date: Wed, 11 Oct 2023 11:31:29 +0200 Subject: [PATCH 147/173] PEP-3121: Mark as Final (#3471) --- peps/pep-3121.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/peps/pep-3121.rst b/peps/pep-3121.rst index a116e1e22..047391efe 100644 --- a/peps/pep-3121.rst +++ b/peps/pep-3121.rst @@ -3,13 +3,16 @@ Title: Extension Module Initialization and Finalization Version: $Revision$ Last-Modified: $Date$ Author: Martin von Löwis <martin@v.loewis.de> -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 27-Apr-2007 Python-Version: 3.0 Post-History: +.. canonical-doc:: :external+python:c:func:`PyInit_modulename` and + :external+python:c:type:`PyModuleDef` + Abstract ======== From 532efdb824724ec7bafb6105a445a9702e0dbee5 Mon Sep 17 00:00:00 2001 From: Michael Scott Asato Cuthbert <michael.asato.cuthbert@gmail.com> Date: Tue, 10 Oct 2023 23:37:22 -1000 Subject: [PATCH 148/173] PEP 661: Standardize module name (#2795) standardize mod name The PEP says that the module name is "sentinels" (plural) but the example imports Sentinel from the "sentinel" (singular) module. Not absolutely sure which one is intended but recent standards (secrets, dataclasses) have used the plural. CLA for Python signed, in case that's needed. Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> --- peps/pep-0661.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0661.rst b/peps/pep-0661.rst index e999168ac..4b6fd54be 100644 --- a/peps/pep-0661.rst +++ b/peps/pep-0661.rst @@ -145,7 +145,7 @@ Its initializer will accept a single required argument, the name of the sentinel object, and two optional arguments: the repr of the object, and the name of its module:: - >>> from sentinel import Sentinel + >>> from sentinels import Sentinel >>> NotGiven = Sentinel('NotGiven') >>> NotGiven <NotGiven> From 6f1da2042de8e59d467119044e6ce6a5091157dd Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan <ncoghlan@gmail.com> Date: Wed, 11 Oct 2023 22:05:51 +1000 Subject: [PATCH 149/173] Update references to Alyssa Coghlan (#3475) * For most cases (including all PEP metadata), replace birth name with chosen name * Birth name has been retained in parentheses when this makes other references substantially clearer (e.g. references to mailing list posts, elected members of the inaugural Steering Council) --- .../tests/pep_zero_generator/test_parser.py | 2 +- peps/pep-0001.rst | 2 +- peps/pep-0008.rst | 2 +- peps/pep-0306.rst | 2 +- peps/pep-0338.rst | 2 +- peps/pep-0340.rst | 2 +- peps/pep-0343.rst | 6 +- peps/pep-0346.rst | 2 +- peps/pep-0348.rst | 2 +- peps/pep-0359.rst | 2 +- peps/pep-0366.rst | 2 +- peps/pep-0369.rst | 6 +- peps/pep-0377.rst | 2 +- peps/pep-0378.rst | 4 +- peps/pep-0390.rst | 4 +- peps/pep-0394.rst | 2 +- peps/pep-0395.rst | 2 +- peps/pep-0403.rst | 2 +- peps/pep-0405.rst | 2 +- peps/pep-0406.rst | 2 +- peps/pep-0408.rst | 2 +- peps/pep-0411.rst | 2 +- peps/pep-0413.rst | 2 +- peps/pep-0414.rst | 4 +- peps/pep-0415.rst | 4 +- peps/pep-0420.rst | 10 +-- peps/pep-0421.rst | 4 +- peps/pep-0422.rst | 2 +- peps/pep-0425.rst | 6 +- peps/pep-0426.rst | 2 +- peps/pep-0427.rst | 4 +- peps/pep-0430.rst | 2 +- peps/pep-0432.rst | 2 +- peps/pep-0434.rst | 2 +- peps/pep-0436.rst | 4 +- peps/pep-0438.rst | 2 +- peps/pep-0439.rst | 4 +- peps/pep-0440.rst | 4 +- peps/pep-0443.rst | 2 +- peps/pep-0451.rst | 2 +- peps/pep-0453.rst | 2 +- peps/pep-0456.rst | 2 +- peps/pep-0457.rst | 2 +- peps/pep-0458.rst | 4 +- peps/pep-0459.rst | 4 +- peps/pep-0462.rst | 2 +- peps/pep-0466.rst | 2 +- peps/pep-0467.rst | 2 +- peps/pep-0468.rst | 14 ++-- peps/pep-0469.rst | 2 +- peps/pep-0471.rst | 12 +-- peps/pep-0474.rst | 2 +- peps/pep-0477.rst | 2 +- peps/pep-0479.rst | 12 +-- peps/pep-0480.rst | 2 +- peps/pep-0487.rst | 2 +- peps/pep-0489.rst | 8 +- peps/pep-0492.rst | 2 +- peps/pep-0493.rst | 2 +- peps/pep-0496.rst | 2 +- peps/pep-0499.rst | 6 +- peps/pep-0501.rst | 2 +- peps/pep-0504.rst | 2 +- peps/pep-0506.rst | 6 +- peps/pep-0509.rst | 2 +- peps/pep-0513.rst | 2 +- peps/pep-0516.rst | 2 +- peps/pep-0517.rst | 2 +- peps/pep-0518.rst | 2 +- peps/pep-0520.rst | 2 +- peps/pep-0522.rst | 2 +- peps/pep-0527.rst | 2 +- peps/pep-0531.rst | 2 +- peps/pep-0532.rst | 2 +- peps/pep-0534.rst | 2 +- peps/pep-0535.rst | 2 +- peps/pep-0538.rst | 4 +- peps/pep-0539.rst | 2 +- peps/pep-0543.rst | 2 +- peps/pep-0550.rst | 8 +- peps/pep-0554.rst | 2 +- peps/pep-0558.rst | 2 +- peps/pep-0561.rst | 2 +- peps/pep-0563.rst | 10 +-- peps/pep-0565.rst | 2 +- peps/pep-0566.rst | 2 +- peps/pep-0567.rst | 2 +- peps/pep-0571.rst | 2 +- peps/pep-0572.rst | 2 +- peps/pep-0573.rst | 2 +- peps/pep-0574.rst | 4 +- peps/pep-0577.rst | 2 +- peps/pep-0581.rst | 2 +- peps/pep-0582.rst | 2 +- peps/pep-0584.rst | 2 +- peps/pep-0587.rst | 2 +- peps/pep-0588.rst | 4 +- peps/pep-0594.rst | 4 +- peps/pep-0598.rst | 2 +- peps/pep-0601.rst | 2 +- peps/pep-0605.rst | 2 +- peps/pep-0607.rst | 2 +- peps/pep-0610.rst | 4 +- peps/pep-0628.rst | 4 +- peps/pep-0639.rst | 2 +- peps/pep-0642.rst | 2 +- peps/pep-0654.rst | 2 +- peps/pep-3104.rst | 2 +- peps/pep-3144.rst | 4 +- peps/pep-3150.rst | 2 +- peps/pep-3151.rst | 2 +- peps/pep-3156.rst | 2 +- peps/pep-8015.rst | 2 +- peps/pep-8100.rst | 80 +++++++++---------- peps/pep-8101.rst | 2 +- peps/pep-8102.rst | 2 +- peps/pep-8103.rst | 2 +- peps/pep-8104.rst | 2 +- 118 files changed, 215 insertions(+), 215 deletions(-) diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py index d2bd324ea..225efa73a 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py @@ -46,7 +46,7 @@ def test_pep_equal(): ( "pep-0008.rst", { - "authors": "Guido van Rossum, Barry Warsaw, Nick Coghlan", + "authors": "Guido van Rossum, Barry Warsaw, Alyssa Coghlan", "number": 8, "shorthand": ":abbr:`PA (Process, Active)`", "title": "Style Guide for Python Code", diff --git a/peps/pep-0001.rst b/peps/pep-0001.rst index 1764f0614..e691648e7 100644 --- a/peps/pep-0001.rst +++ b/peps/pep-0001.rst @@ -1,6 +1,6 @@ PEP: 1 Title: PEP Purpose and Guidelines -Author: Barry Warsaw, Jeremy Hylton, David Goodger, Nick Coghlan +Author: Barry Warsaw, Jeremy Hylton, David Goodger, Alyssa Coghlan Status: Active Type: Process Created: 13-Jun-2000 diff --git a/peps/pep-0008.rst b/peps/pep-0008.rst index 6c4ac9099..05aa89614 100644 --- a/peps/pep-0008.rst +++ b/peps/pep-0008.rst @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Guido van Rossum <guido@python.org>, Barry Warsaw <barry@python.org>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> Status: Active Type: Process Content-Type: text/x-rst diff --git a/peps/pep-0306.rst b/peps/pep-0306.rst index f066e44ff..c4d4a0bd9 100644 --- a/peps/pep-0306.rst +++ b/peps/pep-0306.rst @@ -2,7 +2,7 @@ PEP: 306 Title: How to Change Python's Grammar Version: $Revision$ Last-Modified: $Date$ -Author: Michael Hudson <mwh@python.net>, Jack Diederich <jackdied@gmail.com>, Nick Coghlan <ncoghlan@gmail.com>, Benjamin Peterson <benjamin@python.org> +Author: Michael Hudson <mwh@python.net>, Jack Diederich <jackdied@gmail.com>, Alyssa Coghlan <ncoghlan@gmail.com>, Benjamin Peterson <benjamin@python.org> Status: Withdrawn Type: Informational Content-Type: text/x-rst diff --git a/peps/pep-0338.rst b/peps/pep-0338.rst index 81a665541..f452ebdce 100644 --- a/peps/pep-0338.rst +++ b/peps/pep-0338.rst @@ -2,7 +2,7 @@ PEP: 338 Title: Executing modules as scripts Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0340.rst b/peps/pep-0340.rst index e6873a204..ab645a614 100644 --- a/peps/pep-0340.rst +++ b/peps/pep-0340.rst @@ -554,7 +554,7 @@ In no useful order: Alex Martelli, Barry Warsaw, Bob Ippolito, Brett Cannon, Brian Sabbey, Chris Ryland, Doug Landauer, Duncan Booth, Fredrik Lundh, Greg Ewing, Holger Krekel, Jason Diamond, Jim Jewett, Josiah Carlson, Ka-Ping Yee, Michael Chermside, -Michael Hudson, Neil Schemenauer, Nick Coghlan, Paul Moore, +Michael Hudson, Neil Schemenauer, Alyssa Coghlan, Paul Moore, Phillip Eby, Raymond Hettinger, Georg Brandl, Samuele Pedroni, Shannon Behrens, Skip Montanaro, Steven Bethard, Terry Reedy, Tim Delaney, Aahz, and others. Thanks all for the valuable diff --git a/peps/pep-0343.rst b/peps/pep-0343.rst index 8e18d8f79..7256b2a35 100644 --- a/peps/pep-0343.rst +++ b/peps/pep-0343.rst @@ -2,7 +2,7 @@ PEP: 343 Title: The "with" Statement Version: $Revision$ Last-Modified: $Date$ -Author: Guido van Rossum, Nick Coghlan +Author: Guido van Rossum, Alyssa Coghlan Status: Final Type: Standards Track Content-Type: text/x-rst @@ -25,7 +25,7 @@ Author's Note ============= This PEP was originally written in first person by Guido, and -subsequently updated by Nick Coghlan to reflect later discussion +subsequently updated by Alyssa (Nick) Coghlan to reflect later discussion on python-dev. Any first person references are from Guido's original. @@ -938,7 +938,7 @@ References .. [6] Proposal to use the PEP 342 enhanced generator API directly https://mail.python.org/pipermail/python-dev/2005-October/056969.html -.. [7] Guido lets me (Nick Coghlan) talk him into a bad idea ;) +.. [7] Guido lets me (Alyssa Coghlan) talk him into a bad idea ;) https://mail.python.org/pipermail/python-dev/2005-October/057018.html .. [8] Guido raises some exception handling questions diff --git a/peps/pep-0346.rst b/peps/pep-0346.rst index 4666ff6c9..b656b96ff 100644 --- a/peps/pep-0346.rst +++ b/peps/pep-0346.rst @@ -2,7 +2,7 @@ PEP: 346 Title: User Defined ("``with``") Statements Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0348.rst b/peps/pep-0348.rst index d72229047..2c3d7cdc8 100644 --- a/peps/pep-0348.rst +++ b/peps/pep-0348.rst @@ -436,7 +436,7 @@ was used. Acknowledgements ================ -Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy +Thanks to Robert Brewer, Josiah Carlson, Alyssa Coghlan, Timothy Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing, James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull, Raymond Hettinger, and everyone else I missed for participating in the diff --git a/peps/pep-0359.rst b/peps/pep-0359.rst index a2aa6d410..342f5fa77 100644 --- a/peps/pep-0359.rst +++ b/peps/pep-0359.rst @@ -327,7 +327,7 @@ Keyword ------- Does the ``make`` keyword break too much code? Originally, the make -statement used the keyword ``create`` (a suggestion due to Nick +statement used the keyword ``create`` (a suggestion due to Alyssa Coghlan). However, investigations into the standard library [8]_ and Zope+Plone code [9]_ revealed that ``create`` would break a lot more code, so ``make`` was adopted as the keyword instead. However, there diff --git a/peps/pep-0366.rst b/peps/pep-0366.rst index 73eeb61f4..20a8a7280 100644 --- a/peps/pep-0366.rst +++ b/peps/pep-0366.rst @@ -2,7 +2,7 @@ PEP: 366 Title: Main module explicit relative imports Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0369.rst b/peps/pep-0369.rst index 40caa8c66..cdca12230 100644 --- a/peps/pep-0369.rst +++ b/peps/pep-0369.rst @@ -42,11 +42,11 @@ as post import hooks. Use cases ========= -A use case for a post import hook is mentioned in Nick Coghlan's initial +A use case for a post import hook is mentioned in Alyssa (Nick) Coghlan's initial posting [2]_. about callbacks on module import. It was found during the development of Python 3.0 and its ABCs. We wanted to register classes like decimal.Decimal with an ABC but the module should not be imported -on every interpreter startup. Nick came up with this example:: +on every interpreter startup. Alyssa came up with this example:: @imp.when_imported('decimal') def register(decimal): @@ -261,7 +261,7 @@ documentation updates and additional unit tests. Acknowledgments =============== -Nick Coghlan, for proof reading and the initial discussion +Alyssa Coghlan, for proof reading and the initial discussion Phillip J. Eby, for his implementation in PEAK and help with my own implementation diff --git a/peps/pep-0377.rst b/peps/pep-0377.rst index ef3184bc3..749d3d4d5 100644 --- a/peps/pep-0377.rst +++ b/peps/pep-0377.rst @@ -2,7 +2,7 @@ PEP: 377 Title: Allow __enter__() methods to skip the statement body Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Rejected Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0378.rst b/peps/pep-0378.rst index da2293915..7077fc55e 100644 --- a/peps/pep-0378.rst +++ b/peps/pep-0378.rst @@ -44,8 +44,8 @@ task easier for many users. .. _`Babel`: http://babel.edgewall.org/ -Main Proposal (from Nick Coghlan, originally called Proposal I) -=============================================================== +Main Proposal (from Alyssa Coghlan, originally called Proposal I) +================================================================= A comma will be added to the format() specifier mini-language:: diff --git a/peps/pep-0390.rst b/peps/pep-0390.rst index 502e43a4f..e8c1f77d1 100644 --- a/peps/pep-0390.rst +++ b/peps/pep-0390.rst @@ -3,7 +3,7 @@ Title: Static metadata for Distutils Version: $Revision$ Last-Modified: $Date$ Author: Tarek Ziadé <tarek@ziade.org> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Discussions-To: distutils-sig@python.org Status: Rejected Type: Standards Track @@ -25,7 +25,7 @@ Rejection Notice ================ As distutils2 is no longer going to be incorporated into the standard -library, this PEP was rejected by Nick Coghlan in late April, 2013. +library, this PEP was rejected by Alyssa Coghlan in late April, 2013. A replacement PEP based on :pep:`426` (metadata 2.0) will be created that defines the minimum amount of information needed to generate an sdist diff --git a/peps/pep-0394.rst b/peps/pep-0394.rst index c3438657f..f3ffcd7d0 100644 --- a/peps/pep-0394.rst +++ b/peps/pep-0394.rst @@ -3,7 +3,7 @@ Title: The "python" Command on Unix-Like Systems Version: $Revision$ Last-Modified: $Date$ Author: Kerrick Staley <mail@kerrickstaley.com>, - Nick Coghlan <ncoghlan@gmail.com>, + Alyssa Coghlan <ncoghlan@gmail.com>, Barry Warsaw <barry@python.org>, Petr Viktorin <encukou@gmail.com>, Miro Hrončok <miro@hroncok.cz>, diff --git a/peps/pep-0395.rst b/peps/pep-0395.rst index 04e848206..f270183c8 100644 --- a/peps/pep-0395.rst +++ b/peps/pep-0395.rst @@ -2,7 +2,7 @@ PEP: 395 Title: Qualified Names for Modules Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0403.rst b/peps/pep-0403.rst index e91f00bb0..aadaff6c4 100644 --- a/peps/pep-0403.rst +++ b/peps/pep-0403.rst @@ -2,7 +2,7 @@ PEP: 403 Title: General purpose decorator clause (aka "@in" clause) Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Deferred Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0405.rst b/peps/pep-0405.rst index 22e0a2624..8c95d1c1d 100644 --- a/peps/pep-0405.rst +++ b/peps/pep-0405.rst @@ -3,7 +3,7 @@ Title: Python Virtual Environments Version: $Revision$ Last-Modified: $Date$ Author: Carl Meyer <carl@oddbird.net> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Final Type: Standards Track Topic: Packaging diff --git a/peps/pep-0406.rst b/peps/pep-0406.rst index c290980b3..be1ffaeac 100644 --- a/peps/pep-0406.rst +++ b/peps/pep-0406.rst @@ -2,7 +2,7 @@ PEP: 406 Title: Improved Encapsulation of Import State Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, Greg Slodkowicz <jergosh@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Greg Slodkowicz <jergosh@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0408.rst b/peps/pep-0408.rst index bc34c0139..788d7f417 100644 --- a/peps/pep-0408.rst +++ b/peps/pep-0408.rst @@ -2,7 +2,7 @@ PEP: 408 Title: Standard library __preview__ package Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Eli Bendersky <eliben@gmail.com> Status: Rejected Type: Standards Track diff --git a/peps/pep-0411.rst b/peps/pep-0411.rst index 8bee39e6b..e4969dc43 100644 --- a/peps/pep-0411.rst +++ b/peps/pep-0411.rst @@ -2,7 +2,7 @@ PEP: 411 Title: Provisional packages in the Python standard library Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Eli Bendersky <eliben@gmail.com> Status: Superseded Type: Informational diff --git a/peps/pep-0413.rst b/peps/pep-0413.rst index 933972b21..f2778b256 100644 --- a/peps/pep-0413.rst +++ b/peps/pep-0413.rst @@ -2,7 +2,7 @@ PEP: 413 Title: Faster evolution of the Python Standard Library Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Process Content-Type: text/x-rst diff --git a/peps/pep-0414.rst b/peps/pep-0414.rst index d8ef45f61..7b62aae4f 100644 --- a/peps/pep-0414.rst +++ b/peps/pep-0414.rst @@ -3,7 +3,7 @@ Title: Explicit Unicode Literal for Python 3.3 Version: $Revision$ Last-Modified: $Date$ Author: Armin Ronacher <armin.ronacher@active-4.com>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst @@ -102,7 +102,7 @@ Author's Note This PEP was originally written by Armin Ronacher, and Guido's approval was given based on that version. -The currently published version has been rewritten by Nick Coghlan to +The currently published version has been rewritten by Alyssa Coghlan to include additional historical details and rationale that were taken into account when Guido made his decision, but were not explicitly documented in Armin's version of the PEP. diff --git a/peps/pep-0415.rst b/peps/pep-0415.rst index 48715a21f..a8a695cfd 100644 --- a/peps/pep-0415.rst +++ b/peps/pep-0415.rst @@ -3,7 +3,7 @@ Title: Implement context suppression with exception attributes Version: $Revision$ Last-Modified: $Date$ Author: Benjamin Peterson <benjamin@python.org> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Final Type: Standards Track Content-Type: text/x-rst @@ -28,7 +28,7 @@ instances. PEP Acceptance ============== -This PEP was accepted by Nick Coghlan on the 14th of May, 2012. +This PEP was accepted by Alyssa Coghlan on the 14th of May, 2012. Rationale diff --git a/peps/pep-0420.rst b/peps/pep-0420.rst index 0f0baa733..ea20501ab 100644 --- a/peps/pep-0420.rst +++ b/peps/pep-0420.rst @@ -444,7 +444,7 @@ lacking an ``__init__.py`` file. Such a directory will now be imported as a namespace package, whereas in prior Python versions an ImportWarning would be raised. -Nick Coghlan presented a list of his objections to this proposal [4]_. +Alyssa (Nick) Coghlan presented a list of her objections to this proposal [4]_. They are: 1. Implicit package directories go against the Zen of Python. @@ -458,7 +458,7 @@ They are: 4. Implicit package directories will permanently entrench current newbie-hostile behavior in ``__main__``. -Nick later gave a detailed response to his own objections [5]_, which +Alyssa later gave a detailed response to her own objections [5]_, which is summarized here: 1. The practicality of this PEP wins over other proposals and the @@ -500,7 +500,7 @@ Dynamic path computation ------------------------ Guido raised a concern that automatic dynamic path computation was an -unnecessary feature [8]_. Later in that thread, PJ Eby and Nick +unnecessary feature [8]_. Later in that thread, PJ Eby and Alyssa Coghlan presented arguments as to why dynamic computation would minimize surprise to Python users. The conclusion of that discussion has been included in this PEP's Rationale section. @@ -622,10 +622,10 @@ References .. [3] PyCon 2012 Namespace Package discussion outcome (https://mail.python.org/pipermail/import-sig/2012-March/000421.html) -.. [4] Nick Coghlan's objection to the lack of marker files or directories +.. [4] Alyssa Coghlan's objection to the lack of marker files or directories (https://mail.python.org/pipermail/import-sig/2012-March/000423.html) -.. [5] Nick Coghlan's response to his initial objections +.. [5] Alyssa Coghlan's response to her initial objections (https://mail.python.org/pipermail/import-sig/2012-April/000464.html) .. [6] Martin v. Löwis's suggestion to make ``encodings`` a namespace diff --git a/peps/pep-0421.rst b/peps/pep-0421.rst index e1287ea30..1f5a410ed 100644 --- a/peps/pep-0421.rst +++ b/peps/pep-0421.rst @@ -169,7 +169,7 @@ Non-Required Attributes Earlier versions of this PEP included a required attribute called ``metadata`` that held any non-required, per-implementation data -[#Nick]_. However, this proved to be an unnecessary addition +[#Alyssa]_. However, this proved to be an unnecessary addition considering the purpose of ``sys.implementation``. Ultimately, non-required attributes are virtually ignored in this PEP. @@ -502,7 +502,7 @@ References .. [#javatest] The use of ``os.name`` as 'java' in the stdlib test suite. http://hg.python.org/cpython/file/2f563908ebc5/Lib/test/support.py#l512 -.. [#Nick] Nick Coghlan's proposal for ``sys.implementation.metadata``: +.. [#Alyssa] Alyssa (Nick) Coghlan's proposal for ``sys.implementation.metadata``: https://mail.python.org/pipermail/python-ideas/2012-May/014984.html .. [#Barry] Feedback from Barry Warsaw: diff --git a/peps/pep-0422.rst b/peps/pep-0422.rst index 655dc78e8..dad61a6e0 100644 --- a/peps/pep-0422.rst +++ b/peps/pep-0422.rst @@ -2,7 +2,7 @@ PEP: 422 Title: Simpler customisation of class creation Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Daniel Urban <urban.dani+py@gmail.com> Status: Withdrawn Type: Standards Track diff --git a/peps/pep-0425.rst b/peps/pep-0425.rst index 5037b576a..d1fd39d17 100644 --- a/peps/pep-0425.rst +++ b/peps/pep-0425.rst @@ -3,7 +3,7 @@ Title: Compatibility Tags for Built Distributions Version: $Revision$ Last-Modified: 07-Aug-2012 Author: Daniel Holth <dholth@gmail.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Topic: Packaging @@ -30,7 +30,7 @@ they will be included in filenames. PEP Acceptance ============== -This PEP was accepted by Nick Coghlan on 17th February, 2013. +This PEP was accepted by Alyssa Coghlan on 17th February, 2013. Rationale @@ -283,7 +283,7 @@ References Acknowledgements ================ -The author thanks Paul Moore, Nick Coghlan, Marc Abramowitz, and +The author thanks Paul Moore, Alyssa Coghlan, Marc Abramowitz, and Mr. Michele Lacchia for their valuable help and advice. Copyright diff --git a/peps/pep-0426.rst b/peps/pep-0426.rst index 5163310de..6653ecdba 100644 --- a/peps/pep-0426.rst +++ b/peps/pep-0426.rst @@ -2,7 +2,7 @@ PEP: 426 Title: Metadata for Python Software Packages 2.0 Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Daniel Holth <dholth@gmail.com>, Donald Stufft <donald@stufft.io> BDFL-Delegate: Donald Stufft <donald@stufft.io> diff --git a/peps/pep-0427.rst b/peps/pep-0427.rst index d75ac752a..921a6258c 100644 --- a/peps/pep-0427.rst +++ b/peps/pep-0427.rst @@ -3,7 +3,7 @@ Title: The Wheel Binary Package Format 1.0 Version: $Revision$ Last-Modified: $Date$ Author: Daniel Holth <dholth@gmail.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Final Type: Standards Track @@ -35,7 +35,7 @@ PEP Acceptance ============== This PEP was accepted, and the defined wheel version updated to 1.0, by -Nick Coghlan on 16th February, 2013 [1]_ +Alyssa Coghlan on 16th February, 2013 [1]_ Rationale diff --git a/peps/pep-0430.rst b/peps/pep-0430.rst index d00e498c2..6bf2f03a6 100644 --- a/peps/pep-0430.rst +++ b/peps/pep-0430.rst @@ -2,7 +2,7 @@ PEP: 430 Title: Migrating to Python 3 as the default online documentation Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Georg Brandl Status: Final Type: Informational diff --git a/peps/pep-0432.rst b/peps/pep-0432.rst index 6feef5977..676ca96fe 100644 --- a/peps/pep-0432.rst +++ b/peps/pep-0432.rst @@ -2,7 +2,7 @@ PEP: 432 Title: Restructuring the CPython startup sequence Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Victor Stinner <vstinner@python.org>, Eric Snow <ericsnowcurrently@gmail.com> Discussions-To: capi-sig@python.org diff --git a/peps/pep-0434.rst b/peps/pep-0434.rst index b754d2a48..95a072258 100644 --- a/peps/pep-0434.rst +++ b/peps/pep-0434.rst @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Todd Rovito <rovitotv@gmail.com>, Terry Reedy <tjreedy@udel.edu> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Active Type: Informational Content-Type: text/x-rst diff --git a/peps/pep-0436.rst b/peps/pep-0436.rst index c1a7f277e..7528edb3f 100644 --- a/peps/pep-0436.rst +++ b/peps/pep-0436.rst @@ -693,7 +693,7 @@ Notes / TBD currently under discussion. Argument Clinic will add support for the prototype when it becomes viable. -* Nick Coghlan suggests that we a) only support at most one left-optional +* Alyssa Coghlan suggests that we a) only support at most one left-optional group per function, and b) in the face of ambiguity, prefer the left group over the right group. This would solve all our existing use cases including range(). @@ -757,7 +757,7 @@ The PEP author wishes to thank Ned Batchelder for permission to shamelessly rip off his clever design for Cog--"my favorite tool that I've never gotten to use". Thanks also to everyone who provided feedback on the [bugtracker issue] and on python-dev. Special thanks -to Nick Coglan and Guido van Rossum for a rousing two-hour in-person +to Alyssa (Nick) Coghlan and Guido van Rossum for a rousing two-hour in-person deep dive on the topic at PyCon US 2013. diff --git a/peps/pep-0438.rst b/peps/pep-0438.rst index 30ee2d530..4b2aff25e 100644 --- a/peps/pep-0438.rst +++ b/peps/pep-0438.rst @@ -451,7 +451,7 @@ Donald Stufft for pushing away from external hosting and offering to implement both a Pull Request for the necessary PyPI changes and the analysis tool to drive the transition phase 1. -Marc-Andre Lemburg, Nick Coghlan and catalog-sig in general for +Marc-Andre Lemburg, Alyssa Coghlan and catalog-sig in general for thinking through issues regarding getting rid of "external hosting". diff --git a/peps/pep-0439.rst b/peps/pep-0439.rst index b07a72043..a354e9673 100644 --- a/peps/pep-0439.rst +++ b/peps/pep-0439.rst @@ -3,7 +3,7 @@ Title: Inclusion of implicit pip bootstrap in Python installation Version: $Revision$ Last-Modified: $Date$ Author: Richard Jones <richard@python.org> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Rejected Type: Standards Track @@ -234,7 +234,7 @@ References Acknowledgments =============== -Nick Coghlan for his thoughts on the proposal and dealing with the Red +Alyssa Coghlan for her thoughts on the proposal and dealing with the Red Hat issue. Jannis Leidel and Carl Meyer for their thoughts. Marcus Smith for feedback. diff --git a/peps/pep-0440.rst b/peps/pep-0440.rst index 4cc287bf3..b8f2e5b42 100644 --- a/peps/pep-0440.rst +++ b/peps/pep-0440.rst @@ -1,8 +1,8 @@ PEP: 440 Title: Version Identification and Dependency Specification -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Donald Stufft <donald@stufft.io> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Final Type: Standards Track diff --git a/peps/pep-0443.rst b/peps/pep-0443.rst index 5e0d8fc18..36ae2a572 100644 --- a/peps/pep-0443.rst +++ b/peps/pep-0443.rst @@ -370,7 +370,7 @@ PEAK-Rules, influences include Paul Moore's original issue [#issue-5135]_ that proposed exposing ``pkgutil.simplegeneric`` as part of the ``functools`` API, Guido van Rossum's article on multimethods [#artima2005]_, and discussions with Raymond Hettinger on a general -pprint rewrite. Huge thanks to Nick Coghlan for encouraging me to create +pprint rewrite. Huge thanks to Alyssa Coghlan for encouraging me to create this PEP and providing initial feedback. diff --git a/peps/pep-0451.rst b/peps/pep-0451.rst index 6e673e92a..be1fa1718 100644 --- a/peps/pep-0451.rst +++ b/peps/pep-0451.rst @@ -3,7 +3,7 @@ Title: A ModuleSpec Type for the Import System Version: $Revision$ Last-Modified: $Date$ Author: Eric Snow <ericsnowcurrently@gmail.com> -BDFL-Delegate: Brett Cannon <brett@python.org>, Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Brett Cannon <brett@python.org>, Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: import-sig@python.org Status: Final Type: Standards Track diff --git a/peps/pep-0453.rst b/peps/pep-0453.rst index cbb4ac80d..656b11720 100644 --- a/peps/pep-0453.rst +++ b/peps/pep-0453.rst @@ -1,7 +1,7 @@ PEP: 453 Title: Explicit bootstrapping of pip in Python installations Author: Donald Stufft <donald@stufft.io>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Martin von Löwis Status: Final Type: Standards Track diff --git a/peps/pep-0456.rst b/peps/pep-0456.rst index 240ada264..5e0e79675 100644 --- a/peps/pep-0456.rst +++ b/peps/pep-0456.rst @@ -3,7 +3,7 @@ Title: Secure and interchangeable hash algorithm Version: $Revision$ Last-Modified: $Date$ Author: Christian Heimes <christian@python.org> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0457.rst b/peps/pep-0457.rst index bc9730ec8..a687b8ebc 100644 --- a/peps/pep-0457.rst +++ b/peps/pep-0457.rst @@ -242,7 +242,7 @@ Credit for the use of '/' as the separator between positional-only and positiona parameters goes to Guido van Rossum, in a proposal from 2012. [#GUIDO]_ Credit for making left option groups higher precedence goes to -Nick Coghlan. (Conversation in person at PyCon US 2013.) +Alyssa Coghlan. (Conversation in person at PyCon US 2013.) .. [#DICT] http://docs.python.org/3/library/stdtypes.html#dict diff --git a/peps/pep-0458.rst b/peps/pep-0458.rst index f16faab27..e3459db94 100644 --- a/peps/pep-0458.rst +++ b/peps/pep-0458.rst @@ -9,7 +9,7 @@ Author: Trishank Karthik Kuppusamy <karthik@trishank.com>, Joshua Lock <jlock@vmware.com>, Lois Anne DeLong <lad278@nyu.edu>, Justin Cappos <jcappos@nyu.edu> -Sponsor: Nick Coghlan <ncoghlan@gmail.com> +Sponsor: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Donald Stufft <donald@stufft.io> Discussions-To: https://discuss.python.org/t/pep-458-secure-pypi-downloads-with-package-signing/2648 Status: Accepted @@ -1380,7 +1380,7 @@ conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation. -We thank Nick Coghlan, Daniel Holth, Donald Stufft, and the distutils-sig +We thank Alyssa Coghlan, Daniel Holth, Donald Stufft, and the distutils-sig community in general for helping us to think about how to usably and efficiently integrate TUF with PyPI. diff --git a/peps/pep-0459.rst b/peps/pep-0459.rst index 74920f90d..6fe870a0d 100644 --- a/peps/pep-0459.rst +++ b/peps/pep-0459.rst @@ -2,8 +2,8 @@ PEP: 459 Title: Standard Metadata Extensions for Python Software Packages Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Withdrawn Type: Standards Track diff --git a/peps/pep-0462.rst b/peps/pep-0462.rst index 0c2c7d778..73b1846a5 100644 --- a/peps/pep-0462.rst +++ b/peps/pep-0462.rst @@ -1,6 +1,6 @@ PEP: 462 Title: Core development workflow automation for CPython -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Process Content-Type: text/x-rst diff --git a/peps/pep-0466.rst b/peps/pep-0466.rst index 943186590..0cf6d6ba3 100644 --- a/peps/pep-0466.rst +++ b/peps/pep-0466.rst @@ -2,7 +2,7 @@ PEP: 466 Title: Network Security Enhancements for Python 2.7.x Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0467.rst b/peps/pep-0467.rst index 413eba6ce..50eaf43ac 100644 --- a/peps/pep-0467.rst +++ b/peps/pep-0467.rst @@ -2,7 +2,7 @@ PEP: 467 Title: Minor API improvements for binary sequences Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, Ethan Furman <ethan@stoneleaf.us> +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Ethan Furman <ethan@stoneleaf.us> Status: Draft Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0468.rst b/peps/pep-0468.rst index fec816e7f..a7d2277b6 100644 --- a/peps/pep-0468.rst +++ b/peps/pep-0468.rst @@ -56,8 +56,8 @@ and with this proposal:: def spam(a, **kwargs): ... -Nick Coglan, speaking of some of the uses cases, summed it up well -[#nick_obvious]_:: +Alyssa (Nick) Coghlan, speaking of some of the uses cases, summed it up well +[#alyssa_obvious]_:: These *can* all be done today, but *not* by using keyword arguments. In my view, the problem to be addressed is that keyword arguments @@ -80,11 +80,11 @@ constructor for OrderedDict. [#past_threads]_ [#loss_of_order]_ Use Cases ========= -As Nick noted, the current behavior of \*\*kwargs is unintuitive in +As Alyssa noted, the current behavior of \*\*kwargs is unintuitive in cases where one would expect order to matter. Aside from more specific cases outlined below, in general "anything else where you want to control the iteration order *and* set field names and values in a single -call will potentially benefit." [#nick_general]_ That matters in the +call will potentially benefit." [#alyssa_general]_ That matters in the case of factories (e.g. __init__()) for ordered types. Serialization @@ -92,7 +92,7 @@ Serialization Obviously OrderedDict would benefit (both __init__() and update()) from ordered kwargs. However, the benefit also extends to serialization -APIs [#nick_obvious]_:: +APIs [#alyssa_obvious]_:: In the context of serialisation, one key lesson we have learned is that arbitrary ordering is a problem when you want to minimise @@ -365,7 +365,7 @@ Footnotes References ========== -.. [#nick_obvious] +.. [#alyssa_obvious] https://mail.python.org/pipermail/python-ideas/2014-April/027512.html .. [#past_threads] @@ -401,7 +401,7 @@ References https://mail.python.org/pipermail/python-dev/2013-May/126328.html -.. [#nick_general] +.. [#alyssa_general] https://mail.python.org/pipermail/python-dev/2012-December/123105.html .. [#raymond_debug] diff --git a/peps/pep-0469.rst b/peps/pep-0469.rst index 1307bfc08..b390be40c 100644 --- a/peps/pep-0469.rst +++ b/peps/pep-0469.rst @@ -2,7 +2,7 @@ PEP: 469 Title: Migration of dict iteration code to Python 3 Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0471.rst b/peps/pep-0471.rst index 3a02fda57..f40fce5fa 100644 --- a/peps/pep-0471.rst +++ b/peps/pep-0471.rst @@ -296,7 +296,7 @@ others on the python-dev and python-ideas mailing lists. A sampling: scandir and :pep:`471` on `this June 2014 python-dev thread <https://mail.python.org/pipermail/python-dev/2014-June/135217.html>`_ -* **Nick Coghlan**, a core Python developer: "I've had the local Red +* **Alyssa Coghlan**, a core Python developer: "I've had the local Red Hat release engineering team express their displeasure at having to stat every file in a network mounted directory tree for info that is present in the dirent structure, so a definite +1 to os.scandir from @@ -327,7 +327,7 @@ others on the python-dev and python-ideas mailing lists. A sampling: it to 3.4." [`source6 <https://mail.python.org/pipermail/python-dev/2013-November/130583.html>`_] -Support for this PEP itself (meta-support?) was given by Nick Coghlan +Support for this PEP itself (meta-support?) was given by Alyssa (Nick) Coghlan on python-dev: "A PEP reviewing all this for 3.5 and proposing a specific os.scandir API would be a good thing." [`source7 <https://mail.python.org/pipermail/python-dev/2013-November/130588.html>`_] @@ -526,7 +526,7 @@ DirEntry fields being static with an ensure_lstat option -------------------------------------------------------- Another seemingly simpler and attractive option was suggested by -Nick Coghlan in this `June 2014 python-dev message +Alyssa Coghlan in this `June 2014 python-dev message <https://mail.python.org/pipermail/python-dev/2014-June/135261.html>`_: make ``DirEntry.is_X`` and ``DirEntry.lstat_result`` properties, and populate ``DirEntry.lstat_result`` at iteration time, but only if @@ -586,12 +586,12 @@ See also some previous discussion: * `May 2013 python-dev thread <https://mail.python.org/pipermail/python-dev/2013-May/126148.html>`_ - where Nick Coghlan makes the original case for a ``DirEntry``-style + where Alyssa Coghlan makes the original case for a ``DirEntry``-style object. * `June 2014 python-dev thread <https://mail.python.org/pipermail/python-dev/2014-June/135244.html>`_ - where Nick Coghlan makes (another) good case against the two-tuple + where Alyssa Coghlan makes (another) good case against the two-tuple approach. @@ -659,7 +659,7 @@ Previous discussion * `Further May 2013 thread Ben Hoyt started on python-dev <https://mail.python.org/pipermail/python-dev/2013-May/126119.html>`_ - that refined the ``scandir()`` API, including Nick Coghlan's + that refined the ``scandir()`` API, including Alyssa Coghlan's suggestion of scandir yielding ``DirEntry``-like objects * `November 2013 thread Ben Hoyt started on python-dev diff --git a/peps/pep-0474.rst b/peps/pep-0474.rst index 4e3490e87..ce94bc4a7 100644 --- a/peps/pep-0474.rst +++ b/peps/pep-0474.rst @@ -2,7 +2,7 @@ PEP: 474 Title: Creating forge.python.org Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Process Content-Type: text/x-rst diff --git a/peps/pep-0477.rst b/peps/pep-0477.rst index 721bae141..acb8a2a88 100644 --- a/peps/pep-0477.rst +++ b/peps/pep-0477.rst @@ -1,7 +1,7 @@ PEP: 477 Title: Backport ensurepip (PEP 453) to Python 2.7 Author: Donald Stufft <donald@stufft.io>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Benjamin Peterson <benjamin@python.org> Status: Final Type: Standards Track diff --git a/peps/pep-0479.rst b/peps/pep-0479.rst index e5cbe823e..11c4b752e 100644 --- a/peps/pep-0479.rst +++ b/peps/pep-0479.rst @@ -210,7 +210,7 @@ implementation of ``groupby`` [5]_ currently has comments "Exit on propagate and then be handled. This will be unusual, but not unknown, and such constructs will fail. Other examples abound, e.g. [6]_, [7]_. -(Nick Coghlan comments: """If you wanted to factor out a helper +(Alyssa Coghlan comments: """If you wanted to factor out a helper function that terminated the generator you'd have to do "return yield from helper()" rather than just "helper()".""") @@ -425,7 +425,7 @@ exception. Supplying a specific exception to raise on return ------------------------------------------------- -Nick Coghlan suggested a means of providing a specific +Alyssa (Nick) Coghlan suggested a means of providing a specific ``StopIteration`` instance to the generator; if any other instance of ``StopIteration`` is raised, it is an error, but if that particular one is raised, the generator has properly completed. This subproposal @@ -443,7 +443,7 @@ raising ``StopIteration``, it raises a specific subclass of If it is not that subclass, it is an escaping exception rather than a return statement. -The inspiration for this alternative proposal was Nick's observation +The inspiration for this alternative proposal was Alyssa's observation [8]_ that if an ``asyncio`` coroutine [9]_ accidentally raises ``StopIteration``, it currently terminates silently, which may present a hard-to-debug mystery to the developer. The main proposal turns @@ -502,7 +502,7 @@ avoid a ``try/except`` block. Sub-proposal: decorator to explicitly request current behaviour --------------------------------------------------------------- -Nick Coghlan suggested [11]_ that the situations where the current +Alyssa Coghlan suggested [11]_ that the situations where the current behaviour is desired could be supported by means of a decorator:: from itertools import allow_implicit_stop @@ -598,7 +598,7 @@ References .. [7] wrap unbounded generator to restrict its output (http://code.activestate.com/recipes/66427-wrap-unbounded-generator-to-restrict-its-output/) -.. [8] Post from Nick Coghlan mentioning asyncio +.. [8] Post from Alyssa (Nick) Coghlan mentioning asyncio (https://mail.python.org/pipermail/python-ideas/2014-November/029961.html) .. [9] Coroutines in asyncio @@ -607,7 +607,7 @@ References .. [10] Post from Mark Shannon with alternate proposal (https://mail.python.org/pipermail/python-dev/2014-November/137129.html) -.. [11] Idea from Nick Coghlan +.. [11] Idea from Alyssa Coghlan (https://mail.python.org/pipermail/python-dev/2014-November/137201.html) .. [12] Rejection of above idea by GvR diff --git a/peps/pep-0480.rst b/peps/pep-0480.rst index dbd5e3dd6..339287275 100644 --- a/peps/pep-0480.rst +++ b/peps/pep-0480.rst @@ -898,7 +898,7 @@ conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation. -We thank Nick Coghlan, Daniel Holth, Donald Stufft, Sumana +We thank Alyssa Coghlan, Daniel Holth, Donald Stufft, Sumana Harihareswara, and the distutils-sig community in general for helping us to think about how to usably and efficiently integrate TUF with PyPI. diff --git a/peps/pep-0487.rst b/peps/pep-0487.rst index 4b63ad369..c5ff2a08b 100644 --- a/peps/pep-0487.rst +++ b/peps/pep-0487.rst @@ -455,7 +455,7 @@ This got its own :pep:`520`. History ======= -This used to be a competing proposal to :pep:`422` by Nick Coghlan and Daniel +This used to be a competing proposal to :pep:`422` by Alyssa Coghlan and Daniel Urban. :pep:`422` intended to achieve the same goals as this PEP, but with a different way of implementation. In the meantime, :pep:`422` has been withdrawn favouring this approach. diff --git a/peps/pep-0489.rst b/peps/pep-0489.rst index 4b08d104e..1f06fcbc3 100644 --- a/peps/pep-0489.rst +++ b/peps/pep-0489.rst @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Petr Viktorin <encukou@gmail.com>, Stefan Behnel <stefan_ml@behnel.de>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Eric Snow <ericsnowcurrently@gmail.com> Discussions-To: import-sig@python.org Status: Final @@ -812,8 +812,8 @@ This proposal did not correspond to the (then nonexistent) :pep:`451`, where module creation and initialization is broken into distinct steps. It also did not support loading an extension into pre-existing module objects. -Nick Coghlan proposed "Create" and "Exec" hooks, and wrote a prototype -implementation [#nicks-prototype]_. +Alyssa (Nick) Coghlan proposed "Create" and "Exec" hooks, and wrote a prototype +implementation [#alyssas-prototype]_. At this time :pep:`451` was still not implemented, so the prototype does not use ModuleSpec. @@ -837,7 +837,7 @@ References .. [#stefans_protopep] https://mail.python.org/pipermail/python-dev/2013-August/128087.html -.. [#nicks-prototype] +.. [#alyssas-prototype] https://mail.python.org/pipermail/python-dev/2013-August/128101.html .. [#gh-repo] diff --git a/peps/pep-0492.rst b/peps/pep-0492.rst index 2bab371de..7d4f09280 100644 --- a/peps/pep-0492.rst +++ b/peps/pep-0492.rst @@ -1444,7 +1444,7 @@ Acknowledgments I thank Guido van Rossum, Victor Stinner, Elvis Pranskevichus, Andrew Svetlov, Łukasz Langa, Greg Ewing, Stephen J. Turnbull, Jim J. Jewett, -Brett Cannon, Nick Coghlan, Steven D'Aprano, Paul Moore, Nathaniel +Brett Cannon, Alyssa Coghlan, Steven D'Aprano, Paul Moore, Nathaniel Smith, Ethan Furman, Stefan Behnel, Paul Sokolovsky, Victor Petrovykh, and many others for their feedback, ideas, edits, criticism, code reviews, and discussions around this PEP. diff --git a/peps/pep-0493.rst b/peps/pep-0493.rst index 0cf4c5341..9636fcee0 100644 --- a/peps/pep-0493.rst +++ b/peps/pep-0493.rst @@ -2,7 +2,7 @@ PEP: 493 Title: HTTPS verification migration tools for Python 2.7 Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Robert Kuska <rkuska@redhat.com>, Marc-André Lemburg <mal@lemburg.com> BDFL-Delegate: Barry Warsaw diff --git a/peps/pep-0496.rst b/peps/pep-0496.rst index 53068cfc2..4f2a37175 100644 --- a/peps/pep-0496.rst +++ b/peps/pep-0496.rst @@ -3,7 +3,7 @@ Title: Environment Markers Version: $Revision$ Last-Modified: $Date$ Author: James Polley <jp@jamezpolley.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Status: Rejected Type: Informational Topic: Packaging diff --git a/peps/pep-0499.rst b/peps/pep-0499.rst index 8a4862af7..40c593ea9 100644 --- a/peps/pep-0499.rst +++ b/peps/pep-0499.rst @@ -1,7 +1,7 @@ PEP: 499 Title: ``python -m foo`` should also bind ``'foo'`` in ``sys.modules`` Author: Cameron Simpson <cs@cskk.id.au>, Chris Angelico <rosuav@gmail.com>, Joseph Jevnik <joejev@gmail.com> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Deferred Type: Standards Track Content-Type: text/x-rst @@ -95,7 +95,7 @@ simple change to the way the ``-m`` option is implemented: in addition to binding the module object to ``sys.modules['__main__']``, it is also bound to ``sys.modules['module.name']``. -Nick Coghlan has suggested that this is as simple as modifying the +Alyssa (Nick) Coghlan has suggested that this is as simple as modifying the ``runpy`` module's ``_run_module_as_main`` function as follows:: main_globals = sys.modules["__main__"].__dict__ @@ -120,7 +120,7 @@ Considerations and Prerequisites Pickling Modules ---------------- -Nick has mentioned `issue 19702`_ which proposes (quoted from the issue): +Alyssa has mentioned `issue 19702`_ which proposes (quoted from the issue): - runpy will ensure that when __main__ is executed via the import system, it will also be aliased in sys.modules as __spec__.name diff --git a/peps/pep-0501.rst b/peps/pep-0501.rst index f368a54bd..af2492aa1 100644 --- a/peps/pep-0501.rst +++ b/peps/pep-0501.rst @@ -2,7 +2,7 @@ PEP: 501 Title: General purpose string interpolation Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Deferred Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0504.rst b/peps/pep-0504.rst index d893596b6..a10f25e21 100644 --- a/peps/pep-0504.rst +++ b/peps/pep-0504.rst @@ -2,7 +2,7 @@ PEP: 504 Title: Using the System RNG by default Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0506.rst b/peps/pep-0506.rst index bd170f4ae..294a22717 100644 --- a/peps/pep-0506.rst +++ b/peps/pep-0506.rst @@ -141,7 +141,7 @@ The consensus appears to be that there is no need to add a new CSPRNG to the ``random`` module to support these uses, ``SystemRandom`` will be sufficient. -Some illustrative implementations have been given by Nick Coghlan [#]_ +Some illustrative implementations have been given by Alyssa (Nick) Coghlan [#]_ and a minimalist API by Tim Peters [#]_. This idea has also been discussed on the issue tracker for the "cryptography" module [#]_. The following pseudo-code should be taken as the starting point for the real @@ -226,7 +226,7 @@ module [#]_. This received considerable scepticism and outright opposition: without a proven attack against Python applications, many people object to a backwards-incompatible change. -Nick Coghlan made an :pep:`earlier suggestion <504>` +Alyssa Coghlan made an :pep:`earlier suggestion <504>` for a globally configurable PRNG which uses the system CSPRNG by default, but has since withdrawn it in favour of this proposal. @@ -342,7 +342,7 @@ Frequently Asked Questions A: No. This is a "batteries included" solution, not a full-featured "nuclear reactor". It is intended to mitigate against some basic security errors, not be a solution to all security-related issues. To - quote Nick Coghlan referring to his earlier proposal [#]_:: + quote Alyssa Coghlan referring to her earlier proposal [#]_:: "...folks really are better off learning to use things like cryptography.io for security sensitive software, so this change diff --git a/peps/pep-0509.rst b/peps/pep-0509.rst index 6f30f5ac7..386cea239 100644 --- a/peps/pep-0509.rst +++ b/peps/pep-0509.rst @@ -345,7 +345,7 @@ There are multiple issues: Mandatory bikeshedding on the property name: -* ``__cache_token__``: name proposed by Nick Coghlan, name coming from +* ``__cache_token__``: name proposed by Alyssa Coghlan, name coming from `abc.get_cache_token() <https://docs.python.org/3/library/abc.html#abc.get_cache_token>`_. * ``__version__`` diff --git a/peps/pep-0513.rst b/peps/pep-0513.rst index bae964a83..52bfecda6 100644 --- a/peps/pep-0513.rst +++ b/peps/pep-0513.rst @@ -3,7 +3,7 @@ Title: A Platform Tag for Portable Linux Built Distributions Version: $Revision$ Last-Modified: $Date$ Author: Robert T. McGibbon <rmcgibbo@gmail.com>, Nathaniel J. Smith <njs@pobox.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Superseded Type: Informational diff --git a/peps/pep-0516.rst b/peps/pep-0516.rst index 1f66518e1..31a3d5f70 100644 --- a/peps/pep-0516.rst +++ b/peps/pep-0516.rst @@ -2,7 +2,7 @@ PEP: 516 Title: Build system abstraction for pip/conda etc Author: Robert Collins <rbtcollins@hp.com>, Nathaniel J. Smith <njs@pobox.com> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Rejected Type: Standards Track diff --git a/peps/pep-0517.rst b/peps/pep-0517.rst index 1ad562030..a37f5aaf9 100644 --- a/peps/pep-0517.rst +++ b/peps/pep-0517.rst @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Nathaniel J. Smith <njs@pobox.com>, Thomas Kluyver <thomas@kluyver.me.uk> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Final Type: Standards Track diff --git a/peps/pep-0518.rst b/peps/pep-0518.rst index a2ce91924..3a23368a9 100644 --- a/peps/pep-0518.rst +++ b/peps/pep-0518.rst @@ -3,7 +3,7 @@ Title: Specifying Minimum Build System Requirements for Python Projects Author: Brett Cannon <brett@python.org>, Nathaniel J. Smith <njs@pobox.com>, Donald Stufft <donald@stufft.io> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Discussions-To: distutils-sig@python.org Status: Final Type: Standards Track diff --git a/peps/pep-0520.rst b/peps/pep-0520.rst index 978456b90..add19e1aa 100644 --- a/peps/pep-0520.rst +++ b/peps/pep-0520.rst @@ -419,7 +419,7 @@ References * `Follow-up 2 <https://mail.python.org/pipermail/python-dev/2015-May/140137.html>`__ -* `Nick Coghlan's concerns about mutability +* `Alyssa (Nick) Coghlan's concerns about mutability <https://mail.python.org/pipermail/python-dev/2016-June/144883.html>`__ Copyright diff --git a/peps/pep-0522.rst b/peps/pep-0522.rst index be3690e75..d7cba326d 100644 --- a/peps/pep-0522.rst +++ b/peps/pep-0522.rst @@ -2,7 +2,7 @@ PEP: 522 Title: Allow BlockingIOError in security sensitive APIs Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, Nathaniel J. Smith <njs@pobox.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Nathaniel J. Smith <njs@pobox.com> Status: Rejected Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0527.rst b/peps/pep-0527.rst index fbe682f77..d0927c54d 100644 --- a/peps/pep-0527.rst +++ b/peps/pep-0527.rst @@ -3,7 +3,7 @@ Title: Removing Un(der)used file types/extensions on PyPI Version: $Revision$ Last-Modified: $Date$ Author: Donald Stufft <donald@stufft.io> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Final Type: Standards Track diff --git a/peps/pep-0531.rst b/peps/pep-0531.rst index 13be86600..66e087f46 100644 --- a/peps/pep-0531.rst +++ b/peps/pep-0531.rst @@ -2,7 +2,7 @@ PEP: 531 Title: Existence checking operators Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0532.rst b/peps/pep-0532.rst index 9b974a8d0..35dbe7672 100644 --- a/peps/pep-0532.rst +++ b/peps/pep-0532.rst @@ -2,7 +2,7 @@ PEP: 532 Title: A circuit breaking protocol and binary operators Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com>, +Author: Alyssa Coghlan <ncoghlan@gmail.com>, Mark E. Haase <mehaase@gmail.com> Status: Deferred Type: Standards Track diff --git a/peps/pep-0534.rst b/peps/pep-0534.rst index a572180fd..7dbefb345 100644 --- a/peps/pep-0534.rst +++ b/peps/pep-0534.rst @@ -2,7 +2,7 @@ PEP: 534 Title: Improved Errors for Missing Standard Library Modules Author: Tomáš Orsava <tomas.n@orsava.cz>, Petr Viktorin <encukou@gmail.com>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> Status: Deferred Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0535.rst b/peps/pep-0535.rst index 420cfac69..6c51cc7b3 100644 --- a/peps/pep-0535.rst +++ b/peps/pep-0535.rst @@ -2,7 +2,7 @@ PEP: 535 Title: Rich comparison chaining Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Deferred Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0538.rst b/peps/pep-0538.rst index cf3df04b2..20a178eef 100644 --- a/peps/pep-0538.rst +++ b/peps/pep-0538.rst @@ -2,7 +2,7 @@ PEP: 538 Title: Coercing the legacy C locale to a UTF-8 based locale Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: INADA Naoki Status: Final Type: Standards Track @@ -1093,7 +1093,7 @@ Implementation ============== The reference implementation is being developed in the -``pep538-coerce-c-locale`` feature branch [18]_ in Nick Coghlan's fork of the +``pep538-coerce-c-locale`` feature branch [18]_ in Alyssa Coghlan's fork of the CPython repository on GitHub. A work-in-progress PR is available at [20]_. This reference implementation covers not only the enhancement request in diff --git a/peps/pep-0539.rst b/peps/pep-0539.rst index 2aa74fc8a..71d17301e 100644 --- a/peps/pep-0539.rst +++ b/peps/pep-0539.rst @@ -3,7 +3,7 @@ Title: A New C-API for Thread-Local Storage in CPython Version: $Revision$ Last-Modified: $Date$ Author: Erik M. Bray, Masayuki Yamamoto -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0543.rst b/peps/pep-0543.rst index a605edca0..076bccd34 100644 --- a/peps/pep-0543.rst +++ b/peps/pep-0543.rst @@ -1532,7 +1532,7 @@ by: * Hynek Schlawack * Jim J Jewett * Nathaniel J. Smith -* Nick Coghlan +* Alyssa Coghlan * Paul Kehrer * Steve Dower * Steven Fackler diff --git a/peps/pep-0550.rst b/peps/pep-0550.rst index 32d0e1496..5d58dd033 100644 --- a/peps/pep-0550.rst +++ b/peps/pep-0550.rst @@ -1611,7 +1611,7 @@ Thanks to Nathaniel Smith for proposing the ``ContextVar`` design coming up with the idea of having a stack of contexts in the thread state. -Thanks to Nick Coghlan for numerous suggestions and ideas on the +Thanks to Alyssa (Nick) Coghlan for numerous suggestions and ideas on the mailing list, and for coming up with a case that cause the complete rewrite of the initial PEP version [19]_. @@ -1638,7 +1638,7 @@ Version History * Local Context was renamed to Logical Context. The term "local" was ambiguous and conflicted with local name scopes. - * Context Item was renamed to Context Key, see the thread with Nick + * Context Item was renamed to Context Key, see the thread with Alyssa Coghlan, Stefan Krah, and Yury Selivanov [23]_ for details. * Context Item get cache design was adjusted, per Nathaniel Smith's @@ -1646,7 +1646,7 @@ Version History * Coroutines are created without a Logical Context; ceval loop no longer needs to special case the ``await`` expression - (proposed by Nick Coghlan in [24]_.) + (proposed by Alyssa Coghlan in [24]_.) 4. V4 posted on 25-Aug-2017 [31]_. @@ -1674,7 +1674,7 @@ Version History * All APIs have been placed to the ``contextvars`` module, and the factory functions were changed to class constructors (``ContextVar``, ``ExecutionContext``, and ``LogicalContext``). - Thanks to Nick for the idea [33]_. + Thanks to Alyssa for the idea [33]_. * ``ContextVar.lookup()`` got renamed back to ``ContextVar.get()`` and gained the ``topmost`` and ``default`` keyword arguments. diff --git a/peps/pep-0554.rst b/peps/pep-0554.rst index b8573ddca..a5c500c46 100644 --- a/peps/pep-0554.rst +++ b/peps/pep-0554.rst @@ -333,7 +333,7 @@ isolation within the same process. This can be leveraged in a number of ways. Furthermore, subinterpreters provide a well-defined framework in which such isolation may extended. (See :pep:`684`.) -Nick Coghlan explained some of the benefits through a comparison with +Alyssa (Nick) Coghlan explained some of the benefits through a comparison with multi-processing [benefits]_:: [I] expect that communicating between subinterpreters is going diff --git a/peps/pep-0558.rst b/peps/pep-0558.rst index 2ec688ba9..71af552ef 100644 --- a/peps/pep-0558.rst +++ b/peps/pep-0558.rst @@ -1,6 +1,6 @@ PEP: 558 Title: Defined semantics for locals() -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Nathaniel J. Smith Discussions-To: python-dev@python.org Status: Deferred diff --git a/peps/pep-0561.rst b/peps/pep-0561.rst index c8c424860..0344bb912 100644 --- a/peps/pep-0561.rst +++ b/peps/pep-0561.rst @@ -270,7 +270,7 @@ Acknowledgements ================ This PEP would not have been possible without the ideas, feedback, and support -of Ivan Levkivskyi, Jelle Zijlstra, Nick Coghlan, Daniel F Moisset, Andrey +of Ivan Levkivskyi, Jelle Zijlstra, Alyssa Coghlan, Daniel F Moisset, Andrey Vlasovskikh, Nathaniel Smith, and Guido van Rossum. diff --git a/peps/pep-0563.rst b/peps/pep-0563.rst index 585734c1e..e3b13727f 100644 --- a/peps/pep-0563.rst +++ b/peps/pep-0563.rst @@ -585,7 +585,7 @@ requirement to call ``eval()`` on the annotation with the correct ``globals`` and ``locals`` set. This detail about ``globals`` and ``locals`` having to be correct was -picked up by a number of commenters. Nick Coghlan benchmarked turning +picked up by a number of commenters. Alyssa (Nick) Coghlan benchmarked turning annotations into lambdas instead of strings, sadly this proved to be much slower at runtime than the current situation. @@ -597,10 +597,10 @@ and modal support to either perform or not perform evaluation is a messy solution. His biggest concern remained loss of functionality stemming from the evaluation restrictions on global and local scope. -Nick Coghlan pointed out that some of those evaluation restrictions from +Alyssa Coghlan pointed out that some of those evaluation restrictions from the PEP could be lifted by a clever implementation of an evaluation helper, which could solve self-referencing classes even in the form of a -class decorator. He suggested the PEP should provide this helper +class decorator. She suggested the PEP should provide this helper function in the standard library. Second draft discussion on python-dev @@ -617,7 +617,7 @@ linters or programming text editors) will catch this type of error. Jukka Lehtosalo added that this situation is analogous to how names in function bodies are not resolved until the function is called. -A major topic of discussion was Nick Coghlan's suggestion to store +A major topic of discussion was Alyssa Coghlan's suggestion to store annotations in "thunk form", in other words as a specialized lambda which would be able to access class-level scope (and allow for scope customization at call time). He presented a possible design for it @@ -642,7 +642,7 @@ introspectable as strings. Most importantly, Guido van Rossum explicitly stated interest in gradually restricting the use of annotations to static typing (with an optional runtime component). -Nick Coghlan got convinced to :pep:`563`, too, promptly beginning +Alyssa Coghlan got convinced to :pep:`563`, too, promptly beginning the mandatory bike shedding session on the name of the ``__future__`` import. Many debaters agreed that ``annotations`` seems like an overly broad name for the feature name. Guido van Rossum briefly diff --git a/peps/pep-0565.rst b/peps/pep-0565.rst index 9082e2d3d..d85b260fb 100644 --- a/peps/pep-0565.rst +++ b/peps/pep-0565.rst @@ -1,6 +1,6 @@ PEP: 565 Title: Show DeprecationWarning in __main__ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0566.rst b/peps/pep-0566.rst index 7c0391175..ff20cf4e8 100644 --- a/peps/pep-0566.rst +++ b/peps/pep-0566.rst @@ -175,7 +175,7 @@ This document has been placed in the public domain. Acknowledgements ================ -Thanks to Nick Coghlan and Thomas Kluyver for contributing to this PEP. +Thanks to Alyssa Coghlan and Thomas Kluyver for contributing to this PEP. .. diff --git a/peps/pep-0567.rst b/peps/pep-0567.rst index 4c6514293..40a29a4e0 100644 --- a/peps/pep-0567.rst +++ b/peps/pep-0567.rst @@ -883,7 +883,7 @@ Acknowledgments =============== I thank Guido van Rossum, Nathaniel Smith, Victor Stinner, -Elvis Pranskevichus, Nick Coghlan, Antoine Pitrou, INADA Naoki, +Elvis Pranskevichus, Alyssa Coghlan, Antoine Pitrou, INADA Naoki, Paul Moore, Eric Snow, Greg Ewing, and many others for their feedback, ideas, edits, criticism, code reviews, and discussions around this PEP. diff --git a/peps/pep-0571.rst b/peps/pep-0571.rst index 8aed6d6d9..1577ff697 100644 --- a/peps/pep-0571.rst +++ b/peps/pep-0571.rst @@ -3,7 +3,7 @@ Title: The manylinux2010 Platform Tag Author: Mark Williams <mrw@enotuniq.org>, Geoffrey Thomas <geofft@ldpreload.com>, Thomas Kluyver <thomas@kluyver.me.uk> -BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com> +BDFL-Delegate: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: distutils-sig@python.org Status: Superseded Type: Informational diff --git a/peps/pep-0572.rst b/peps/pep-0572.rst index 4d04081cc..603e054c3 100644 --- a/peps/pep-0572.rst +++ b/peps/pep-0572.rst @@ -967,7 +967,7 @@ benefit of style guides such as :pep:`8`, two recommendations are suggested. Acknowledgements ================ -The authors wish to thank Nick Coghlan and Steven D'Aprano for their +The authors wish to thank Alyssa Coghlan and Steven D'Aprano for their considerable contributions to this proposal, and members of the core-mentorship mailing list for assistance with implementation. diff --git a/peps/pep-0573.rst b/peps/pep-0573.rst index 6007d0015..d286008b7 100644 --- a/peps/pep-0573.rst +++ b/peps/pep-0573.rst @@ -3,7 +3,7 @@ Title: Module State Access from C Extension Methods Version: $Revision$ Last-Modified: $Date$ Author: Petr Viktorin <encukou@gmail.com>, - Nick Coghlan <ncoghlan@gmail.com>, + Alyssa Coghlan <ncoghlan@gmail.com>, Eric Snow <ericsnowcurrently@gmail.com>, Marcel Plch <gmarcel.plch@gmail.com> BDFL-Delegate: Stefan Behnel diff --git a/peps/pep-0574.rst b/peps/pep-0574.rst index 891ca3fb3..82e4d413a 100644 --- a/peps/pep-0574.rst +++ b/peps/pep-0574.rst @@ -3,7 +3,7 @@ Title: Pickle protocol 5 with out-of-band data Version: $Revision$ Last-Modified: $Date$ Author: Antoine Pitrou <solipsis@pitrou.net> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Status: Final Type: Standards Track Content-Type: text/x-rst @@ -512,7 +512,7 @@ scheme. Acknowledgements ================ -Thanks to the following people for early feedback: Nick Coghlan, Olivier +Thanks to the following people for early feedback: Alyssa Coghlan, Olivier Grisel, Stefan Krah, MinRK, Matt Rocklin, Eric Snow. Thanks to Pierre Glaser and Olivier Grisel for experimenting with the diff --git a/peps/pep-0577.rst b/peps/pep-0577.rst index 91684a025..94927a3e8 100644 --- a/peps/pep-0577.rst +++ b/peps/pep-0577.rst @@ -1,6 +1,6 @@ PEP: 577 Title: Augmented Assignment Expressions -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Withdrawn Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-0581.rst b/peps/pep-0581.rst index 6ef0843de..4f13db077 100644 --- a/peps/pep-0581.rst +++ b/peps/pep-0581.rst @@ -221,7 +221,7 @@ You can post questions on Discourse under the Acknowledgements ================ -Thanks to Guido van Rossum, Brett Cannon, and Nick Coghlan, who were consulted +Thanks to Guido van Rossum, Brett Cannon, and Alyssa Coghlan, who were consulted in the early stage and research of this PEP. Their feedback, concerns, input, and ideas have been valuable. diff --git a/peps/pep-0582.rst b/peps/pep-0582.rst index d21c30b0e..9fb4b44e8 100644 --- a/peps/pep-0582.rst +++ b/peps/pep-0582.rst @@ -3,7 +3,7 @@ Title: Python local packages directory Version: $Revision$ Last-Modified: $Date$ Author: Kushal Das <mail@kushaldas.in>, Steve Dower <steve.dower@python.org>, - Donald Stufft <donald@stufft.io>, Nick Coghlan <ncoghlan@gmail.com> + Donald Stufft <donald@stufft.io>, Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: https://discuss.python.org/t/pep-582-python-local-packages-directory/963/ Status: Rejected Type: Standards Track diff --git a/peps/pep-0584.rst b/peps/pep-0584.rst index d0a002a77..6735a2a0f 100644 --- a/peps/pep-0584.rst +++ b/peps/pep-0584.rst @@ -595,7 +595,7 @@ Disadvantages * It isn't an operator. Guido discusses `why operators are useful <https://mail.python.org/archives/list/python-ideas@python.org/message/52DLME5DKNZYFEETCTRENRNKWJ2B4DD5/>`_. - For another viewpoint, see `Nick Coghlan's blog post + For another viewpoint, see `Alyssa Coghlan's blog post <https://www.curiousefficiency.org/posts/2019/03/what-does-x-equals-a-plus-b-mean.html>`_. diff --git a/peps/pep-0587.rst b/peps/pep-0587.rst index 134d1248d..381969a1b 100644 --- a/peps/pep-0587.rst +++ b/peps/pep-0587.rst @@ -1,6 +1,6 @@ PEP: 587 Title: Python Initialization Configuration -Author: Victor Stinner <vstinner@python.org>, Nick Coghlan <ncoghlan@gmail.com> +Author: Victor Stinner <vstinner@python.org>, Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Thomas Wouters <thomas@python.org> Discussions-To: python-dev@python.org Status: Final diff --git a/peps/pep-0588.rst b/peps/pep-0588.rst index 20e93b23c..b3ea24d8d 100644 --- a/peps/pep-0588.rst +++ b/peps/pep-0588.rst @@ -264,7 +264,7 @@ Can the list be shortened? Priority list ------------- -Is the current "priority" list useful? Nick Coghlan noted that perhaps only +Is the current "priority" list useful? Alyssa Coghlan noted that perhaps only ``release blocker`` and ``deferred blocker`` are useful. @@ -278,7 +278,7 @@ You can post questions on Discourse under the Acknowledgements ================ -Thanks to Guido van Rossum, Brett Cannon, and Nick Coghlan, who were consulted +Thanks to Guido van Rossum, Brett Cannon, and Alyssa Coghlan, who were consulted in the early stage and research of this PEP. Their feedback, concerns, input, and ideas have been valuable. diff --git a/peps/pep-0594.rst b/peps/pep-0594.rst index 1a89458c4..78de4cca0 100644 --- a/peps/pep-0594.rst +++ b/peps/pep-0594.rst @@ -593,7 +593,7 @@ the ``array`` module could gain support for 24-bit (3-byte) arrays. Discussions =========== -* Elana Hashman and Nick Coghlan suggested to keep the ``getopt`` module. +* Elana Hashman and Alyssa Coghlan suggested to keep the ``getopt`` module. * Berker Peksag proposed to deprecate and remove ``msilib``. * Brett Cannon recommended to delay active deprecation warnings and removal of modules like ``imp`` until Python 3.10. Version 3.8 will be released @@ -603,7 +603,7 @@ Discussions To avoid lengthy discussion and delay of the PEP, I decided against dealing with distutils. Deprecation of the distutils package will be handled by another PEP. -* Multiple people (Gregory P. Smith, David Beazley, Nick Coghlan, ...) +* Multiple people (Gregory P. Smith, David Beazley, Alyssa Coghlan, ...) convinced me to keep the `wave`_ module. [4]_ * Gregory P. Smith proposed to deprecate `nntplib`_. [4]_ * Andrew Svetlov mentioned the ``socketserver`` module is questionable. diff --git a/peps/pep-0598.rst b/peps/pep-0598.rst index 0271d56a8..c9191664e 100644 --- a/peps/pep-0598.rst +++ b/peps/pep-0598.rst @@ -2,7 +2,7 @@ PEP: 598 Title: Introducing incremental feature releases Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: https://discuss.python.org/t/pep-596-python-3-9-release-schedule-doubling-the-release-cadence/1828 Status: Withdrawn Type: Informational diff --git a/peps/pep-0601.rst b/peps/pep-0601.rst index 046c898b2..5254d1c2b 100644 --- a/peps/pep-0601.rst +++ b/peps/pep-0601.rst @@ -1,7 +1,7 @@ PEP: 601 Title: Forbid return/break/continue breaking out of finally Author: Damien George, Batuhan Taskaya -Sponsor: Nick Coghlan +Sponsor: Alyssa Coghlan Discussions-To: https://discuss.python.org/t/pep-601-forbid-return-break-continue-breaking-out-of-finally/2239 Status: Rejected Type: Standards Track diff --git a/peps/pep-0605.rst b/peps/pep-0605.rst index e76f1a7da..76b043554 100644 --- a/peps/pep-0605.rst +++ b/peps/pep-0605.rst @@ -2,7 +2,7 @@ PEP: 605 Title: A rolling feature release stream for CPython Version: $Revision$ Last-Modified: $Date$ -Author: Steve Dower <steve.dower@python.org>, Nick Coghlan <ncoghlan@gmail.com> +Author: Steve Dower <steve.dower@python.org>, Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: https://discuss.python.org/t/pep-605-a-rolling-feature-release-stream-for-cpython/2418 Status: Rejected Type: Informational diff --git a/peps/pep-0607.rst b/peps/pep-0607.rst index e1019ddde..8d3073a0c 100644 --- a/peps/pep-0607.rst +++ b/peps/pep-0607.rst @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Łukasz Langa <lukasz@python.org>, Steve Dower <steve.dower@python.org>, - Nick Coghlan <ncoghlan@gmail.com> + Alyssa Coghlan <ncoghlan@gmail.com> Discussions-To: https://discuss.python.org/t/pep-607-shared-background-for-the-release-cadence-peps/2528 Status: Final Type: Informational diff --git a/peps/pep-0610.rst b/peps/pep-0610.rst index 5e20ea55c..bfd2f0dd5 100644 --- a/peps/pep-0610.rst +++ b/peps/pep-0610.rst @@ -1,7 +1,7 @@ PEP: 610 Title: Recording the Direct URL Origin of installed distributions Author: Stéphane Bidoul <stephane.bidoul@gmail.com>, Chris Jerdonek <chris.jerdonek@gmail.com> -Sponsor: Nick Coghlan <ncoghlan@gmail.com> +Sponsor: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Pradyun Gedam <pradyunsg@gmail.com> Discussions-To: https://discuss.python.org/t/recording-the-source-url-of-an-installed-distribution/1535 Status: Final @@ -552,7 +552,7 @@ Acknowledgements ================ Various people helped make this PEP a reality. Paul F. Moore provided the -essence of the abstract. Nick Coghlan suggested the direct_url name. +essence of the abstract. Alyssa Coghlan suggested the direct_url name. Copyright ========= diff --git a/peps/pep-0628.rst b/peps/pep-0628.rst index 43088ac2b..cdfb472bb 100644 --- a/peps/pep-0628.rst +++ b/peps/pep-0628.rst @@ -2,7 +2,7 @@ PEP: 628 Title: Add ``math.tau`` Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst @@ -27,7 +27,7 @@ PEP Acceptance ============== This PEP is now `accepted`_ and ``math.tau`` will be a part of Python 3.6. -Happy birthday Nick! +Happy birthday Alyssa! The idea in this PEP has been implemented in the auspiciously named `issue 12345`_. diff --git a/peps/pep-0639.rst b/peps/pep-0639.rst index b655733ae..74f0fc24a 100644 --- a/peps/pep-0639.rst +++ b/peps/pep-0639.rst @@ -2771,7 +2771,7 @@ References Acknowledgments =============== -- Nick Coghlan +- Alyssa Coghlan - Kevin P. Fleming - Pradyun Gedam - Oleg Grenrus diff --git a/peps/pep-0642.rst b/peps/pep-0642.rst index 6418dfa23..59c8ef6a2 100644 --- a/peps/pep-0642.rst +++ b/peps/pep-0642.rst @@ -2,7 +2,7 @@ PEP: 642 Title: Explicit Pattern Syntax for Structural Pattern Matching Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> BDFL-Delegate: Discussions-To: python-dev@python.org Status: Rejected diff --git a/peps/pep-0654.rst b/peps/pep-0654.rst index b2b183a32..a7bb82a44 100644 --- a/peps/pep-0654.rst +++ b/peps/pep-0654.rst @@ -1456,7 +1456,7 @@ and elsewhere helped us improve upon the first draft of the PEP in multiple ways, both the design and the exposition. For this we appreciate all those who contributed ideas and asked good questions: Ammar Askar, Matthew Barnett, Ran Benita, Emily Bowman, Brandt Bucher, Joao Bueno, Baptiste Carvello, -Rob Cliffe, Nick Coghlan, Steven D'Aprano, Caleb Donovick, Steve Dower, +Rob Cliffe, Alyssa Coghlan, Steven D'Aprano, Caleb Donovick, Steve Dower, Greg Ewing, Ethan Furman, Pablo Salgado, Jonathan Goble, Joe Gottman, Thomas Grainger, Larry Hastings, Zac Hatfield-Dodds, Chris Jerdonek, Jim Jewett, Sven Kunze, Łukasz Langa, Glenn Linderman, Paul Moore, Antoine Pitrou, Ivan Pozdeev, diff --git a/peps/pep-3104.rst b/peps/pep-3104.rst index 920b929a5..316ec3eb3 100644 --- a/peps/pep-3104.rst +++ b/peps/pep-3104.rst @@ -513,7 +513,7 @@ References .. [25] Draft PEP for outer scopes (Talin) https://mail.python.org/pipermail/python-3000/2006-November/004190.html -.. [26] Draft PEP for outer scopes (Nick Coghlan) +.. [26] Draft PEP for outer scopes (Alyssa Coghlan) https://mail.python.org/pipermail/python-3000/2006-November/004237.html .. [27] Global variable (version 2006-11-01T01:23:16) diff --git a/peps/pep-3144.rst b/peps/pep-3144.rst index aff805637..059ec7658 100644 --- a/peps/pep-3144.rst +++ b/peps/pep-3144.rst @@ -3,7 +3,7 @@ Title: IP Address Manipulation Library for the Python Standard Library Version: $Revision$ Last-Modified: $Date$ Author: Peter Moody <pmoody@google.com> -BDFL-Delegate: Nick Coghlan +BDFL-Delegate: Alyssa Coghlan Discussions-To: ipaddr-py-dev@googlegroups.com Status: Final Type: Standards Track @@ -23,7 +23,7 @@ python. PEP Acceptance ============== -This PEP was accepted by Nick Coghlan on the 15th of May, 2012. +This PEP was accepted by Alyssa Coghlan on the 15th of May, 2012. Motivation diff --git a/peps/pep-3150.rst b/peps/pep-3150.rst index 0406c92ed..4c72d0684 100644 --- a/peps/pep-3150.rst +++ b/peps/pep-3150.rst @@ -2,7 +2,7 @@ PEP: 3150 Title: Statement local namespaces (aka "given" clause) Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan <ncoghlan@gmail.com> +Author: Alyssa Coghlan <ncoghlan@gmail.com> Status: Deferred Type: Standards Track Content-Type: text/x-rst diff --git a/peps/pep-3151.rst b/peps/pep-3151.rst index e1ba710e2..f20a3f3f3 100644 --- a/peps/pep-3151.rst +++ b/peps/pep-3151.rst @@ -937,7 +937,7 @@ zipimporter.get_data() can raise IOError. Acknowledgments =============== -Significant input has been received from Nick Coghlan. +Significant input has been received from Alyssa Coghlan. References ========== diff --git a/peps/pep-3156.rst b/peps/pep-3156.rst index a9343fa36..c8bf9e5a9 100644 --- a/peps/pep-3156.rst +++ b/peps/pep-3156.rst @@ -2057,7 +2057,7 @@ References - PyPI: the Python Package Index at http://pypi.python.org/ -- Nick Coghlan wrote a nice blog post with some background, thoughts +- Alyssa Coghlan wrote a nice blog post with some background, thoughts about different approaches to async I/O, gevent, and how to use futures with constructs like ``while``, ``for`` and ``with``: http://python-notes.boredomandlaziness.org/en/latest/pep_ideas/async_programming.html diff --git a/peps/pep-8015.rst b/peps/pep-8015.rst index 64f93e53d..3b772fdf0 100644 --- a/peps/pep-8015.rst +++ b/peps/pep-8015.rst @@ -471,7 +471,7 @@ their own PEPs. * Mailing list: `distutils-sig <https://mail.python.org/mm3/mailman3/lists/distutils-sig.python.org/>`_ * Bug tracker component: ``Distutils`` -* Example of members: Paul Moore, Nick Coghlan, Donald Stuff +* Example of members: Paul Moore, Alyssa Coghlan, Donald Stuff * Stdlib module: ``distutils`` * Current PEP delegate: Paul Moore diff --git a/peps/pep-8100.rst b/peps/pep-8100.rst index b42207cb7..f74c37be0 100644 --- a/peps/pep-8100.rst +++ b/peps/pep-8100.rst @@ -49,7 +49,7 @@ is a core team member, they may nominate themselves. Once the nomination period opens, candidates will be listed here: 1. `Brett Cannon <https://discuss.python.org/t/steering-council-nomination-brett-cannon/620>`_ -2. `Nick Coghlan <https://discuss.python.org/t/steering-council-nomination-nick-coghlan/624>`_ +2. `Alyssa (Nick) Coghlan <https://discuss.python.org/t/steering-council-nomination-nick-coghlan/624>`_ 3. `Barry Warsaw <https://discuss.python.org/t/steering-council-nomination-barry-warsaw/629>`__ 4. `Guido van Rossum <https://discuss.python.org/t/steering-council-nomination-guido-van-rossum/628>`__ 5. `Victor Stinner <https://discuss.python.org/t/steering-council-nomination-victor-stinner/635>`_ @@ -141,49 +141,49 @@ The top five vote-getters are: * Brett Cannon * Carol Willing * Guido van Rossum -* Nick Coghlan +* Alyssa (Nick) Coghlan No conflict of interest as defined in :pep:`13` were observed. The full vote counts are as follows: -+-------------------+----------------+ -| Candidate | Votes Received | -+===================+================+ -| Guido van Rossum | 45 | -+-------------------+----------------+ -| Brett Cannon | 44 | -+-------------------+----------------+ -| Carol Willing | 33 | -+-------------------+----------------+ -| Barry Warsaw | 31 | -+-------------------+----------------+ -| Nick Coghlan | 25 | -+-------------------+----------------+ -| Benjamin Peterson | 22 | -+-------------------+----------------+ -| Łukasz Langa | 21 | -+-------------------+----------------+ -| Victor Stinner | 21 | -+-------------------+----------------+ -| Mariatta | 20 | -+-------------------+----------------+ -| Emily Morehouse | 18 | -+-------------------+----------------+ -| Yury Selivanov | 15 | -+-------------------+----------------+ -| Donald Stufft | 11 | -+-------------------+----------------+ -| Peter Wang | 10 | -+-------------------+----------------+ -| Travis Oliphant | 8 | -+-------------------+----------------+ -| Kushal Das | 7 | -+-------------------+----------------+ -| Gregory P. Smith | 6 | -+-------------------+----------------+ -| David Mertz | 3 | -+-------------------+----------------+ ++-----------------------+----------------+ +| Candidate | Votes Received | ++=======================+================+ +| Guido van Rossum | 45 | ++-----------------------+----------------+ +| Brett Cannon | 44 | ++-----------------------+----------------+ +| Carol Willing | 33 | ++-----------------------+----------------+ +| Barry Warsaw | 31 | ++-----------------------+----------------+ +| Alyssa (Nick) Coghlan | 25 | ++-----------------------+----------------+ +| Benjamin Peterson | 22 | ++-----------------------+----------------+ +| Łukasz Langa | 21 | ++-----------------------+----------------+ +| Victor Stinner | 21 | ++-----------------------+----------------+ +| Mariatta | 20 | ++-----------------------+----------------+ +| Emily Morehouse | 18 | ++-----------------------+----------------+ +| Yury Selivanov | 15 | ++-----------------------+----------------+ +| Donald Stufft | 11 | ++-----------------------+----------------+ +| Peter Wang | 10 | ++-----------------------+----------------+ +| Travis Oliphant | 8 | ++-----------------------+----------------+ +| Kushal Das | 7 | ++-----------------------+----------------+ +| Gregory P. Smith | 6 | ++-----------------------+----------------+ +| David Mertz | 3 | ++-----------------------+----------------+ Copyright ========= @@ -265,7 +265,7 @@ Active Python core developers Nathaniel J. Smith Ned Deily Neil Schemenauer - Nick Coghlan + Alyssa Coghlan Pablo Galindo Paul Moore Petr Viktorin diff --git a/peps/pep-8101.rst b/peps/pep-8101.rst index ea89abb76..3534a25bd 100644 --- a/peps/pep-8101.rst +++ b/peps/pep-8101.rst @@ -238,7 +238,7 @@ Active Python core developers Nathaniel J. Smith Ned Deily Neil Schemenauer - Nick Coghlan + Alyssa Coghlan Pablo Galindo Paul Ganssle Paul Moore diff --git a/peps/pep-8102.rst b/peps/pep-8102.rst index 5cce7ccec..229da8810 100644 --- a/peps/pep-8102.rst +++ b/peps/pep-8102.rst @@ -257,7 +257,7 @@ Active Python core developers Nathaniel J. Smith Ned Deily Neil Schemenauer - Nick Coghlan + Alyssa Coghlan Pablo Galindo Paul Ganssle Paul Moore diff --git a/peps/pep-8103.rst b/peps/pep-8103.rst index ebc575854..e1672203b 100644 --- a/peps/pep-8103.rst +++ b/peps/pep-8103.rst @@ -244,7 +244,7 @@ Active Python core developers Nathaniel J. Smith Ned Deily Neil Schemenauer - Nick Coghlan + Alyssa Coghlan Pablo Galindo Paul Ganssle Paul Moore diff --git a/peps/pep-8104.rst b/peps/pep-8104.rst index 438d8d0a2..bef7094f3 100644 --- a/peps/pep-8104.rst +++ b/peps/pep-8104.rst @@ -240,7 +240,7 @@ Active Python core developers Nathaniel J. Smith Ned Deily Neil Schemenauer - Nick Coghlan + Alyssa Coghlan Pablo Galindo Paul Ganssle Paul Moore From 6c817a6bb7b36de58bbdc5ee722374100416668d Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee <russell@keith-magee.com> Date: Thu, 12 Oct 2023 08:02:35 +0200 Subject: [PATCH 150/173] Meta: Add a note about populating the PR from a template. (#3474) Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> --- CONTRIBUTING.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 558e91a7e..bc5141271 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -42,6 +42,25 @@ a discussion venue appropriate to the PEP (such as `Typing Discourse typing, or `Packaging Discourse <https://discuss.python.org/c/packaging/>`__ for packaging), or `open an issue <https://github.com/python/peps/issues>`__. +Opening a pull request +---------------------- + +The PEPs repository defines a set of pull request templates, which should be +used when opening a PR. + +If you use Git from the command line, you may be accustomed to creating PRs +by following the URL that is provided after pushing a new branch. **Do not use +this link**, as it does not provide the option to populate the PR template. + +However, you *can* use the ``gh`` command line tool. ``gh pr create`` will allow +you to create a pull request, will prompt you for the template you wish to use, +and then give you the option of continuing editing in your broswer. + +Alternatively, after pushing your branch, you can visit +`https://github.com/python/peps <https://github.com/python/peps>`__, and follow +the link in the notification about recent changes to your branch to +create a new PR. The in-browser interface will allow you to select a PR template +for your new PR. Commit messages and PR titles ----------------------------- @@ -56,7 +75,7 @@ the Readme/Contributing Guide, issue/PR template, etc., with ``Meta:``. Sign the Contributor License Agreement -------------------------------------- -All contributors need to sign the +All contributors need to sign the `PSF Contributor Agreement <https://www.python.org/psf/contrib/contrib-form/>`_. to ensure we legally accept your work. From 7fba02d76c2d16da7b8c26d2c7d0d05a6b53cb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= <tiangolo@gmail.com> Date: Thu, 12 Oct 2023 16:16:44 +0200 Subject: [PATCH 151/173] PEP 727: Update `first_name` to `name` from feedback by Gregory P. Smith (#3478) --- peps/pep-0727.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/peps/pep-0727.rst b/peps/pep-0727.rst index b090874c6..b30b34608 100644 --- a/peps/pep-0727.rst +++ b/peps/pep-0727.rst @@ -163,8 +163,8 @@ For example: from typing import Annotated, Doc class User: - first_name: Annotated[str, Doc("The user's first name")] - last_name: Annotated[str, Doc("The user's last name")] + name: Annotated[str, Doc("The user's name")] + age: Annotated[int, Doc("The user's age")] ... @@ -264,8 +264,8 @@ Class attributes may be documented: from typing import Annotated, Doc class User: - first_name: Annotated[str, Doc("The user's first name")] - last_name: Annotated[str, Doc("The user's last name")] + name: Annotated[str, Doc("The user's name")] + age: Annotated[int, Doc("The user's age")] ... @@ -276,8 +276,8 @@ As can function or method parameters and return values: from typing import Annotated, Doc def create_user( - first_name: Annotated[str, Doc("The user's first name")], - last_name: Annotated[str, Doc("The user's last name")], + name: Annotated[str, Doc("The user's name")], + age: Annotated[int, Doc("The user's age")], cursor: DatabaseConnection | None = None, ) -> Annotated[User, Doc("The created user after saving in the database")]: """Create a new user in the system. @@ -305,8 +305,8 @@ For example: from typing_extensions import Doc class User: - first_name: Annotated[str, Doc("The user's first name")] - last_name: Annotated[str, Doc("The user's last name")] + name: Annotated[str, Doc("The user's name")] + age: Annotated[int, Doc("The user's age")] ... @@ -563,10 +563,10 @@ of a symbol and providing runtime access to those values: .. code:: python class User: - first_name: str - "The user's first name" - last_name: str - "The user's last name" + name: str + "The user's name" + age: int + "The user's age" ... @@ -588,8 +588,8 @@ In the discussion, it was also suggested to use a plain string inside of from typing import Annotated class User: - first_name: Annotated[str, "The user's first name"] - last_name: Annotated[str, "The user's last name"] + name: Annotated[str, "The user's name"] + age: Annotated[int, "The user's age"] ... @@ -614,8 +614,8 @@ documentation string: from typing import Doc class User: - first_name: Doc[str, "The user's first name"] - last_name: Doc[str, "The user's last name"] + name: Doc[str, "The user's name"] + age: Doc[int, "The user's age"] ... From 52a3481381643588d6fb0e73f84c0d6e11d45991 Mon Sep 17 00:00:00 2001 From: Ofek Lev <ofekmeister@gmail.com> Date: Fri, 13 Oct 2023 01:15:59 -0400 Subject: [PATCH 152/173] PEP 658: fix typo (#3479) --- peps/pep-0658.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0658.rst b/peps/pep-0658.rst index 84b9834a5..04d9ef374 100644 --- a/peps/pep-0658.rst +++ b/peps/pep-0658.rst @@ -128,7 +128,7 @@ Expose more files in the distribution ------------------------------------- It was proposed to provide the entire ``.dist-info`` directory as a -separate part, instead of only the metadata file. However, searving +separate part, instead of only the metadata file. However, serving multiple files in one entity through HTTP requires re-archiving them separately after they are extracted from the original distribution by the repository server, and there are no current use cases for files From 32adf8fb236a239e1bc5d08f386143593b478e8e Mon Sep 17 00:00:00 2001 From: Guido van Rossum <guido@python.org> Date: Fri, 13 Oct 2023 15:12:18 +0200 Subject: [PATCH 153/173] PEP 731: C API Working Group Charter (#3476) (Co-authored by all listed co-authors, and also by Jelle, since we cribbed a lot of words from his PEP 729.) --- .github/CODEOWNERS | 1 + peps/pep-0731.rst | 181 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 peps/pep-0731.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b0614a90b..25e077ef2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -608,6 +608,7 @@ peps/pep-0726.rst @AA-Turner peps/pep-0727.rst @JelleZijlstra peps/pep-0729.rst @JelleZijlstra @hauntsaninja peps/pep-0730.rst @ned-deily +peps/pep-0731.rst @gvanrossum @encukou @vstinner @zooba @iritkatriel # ... # peps/pep-0754.rst # ... diff --git a/peps/pep-0731.rst b/peps/pep-0731.rst new file mode 100644 index 000000000..2ab43b4c1 --- /dev/null +++ b/peps/pep-0731.rst @@ -0,0 +1,181 @@ +PEP: 731 +Title: C API Working Group Charter +Author: Guido van Rossum <guido@python.org>, + Petr Viktorin <encukou@gmail.com>, + Victor Stinner <vstinner@python.org>, + Steve Dower <steve.dower@python.org>, + Irit Katriel <irit@python.org> +Status: Draft +Type: Process +Created: 11-Oct-2023 +Python-Version: 3.13 + +Abstract +======== + +This PEP proposes to establish the C API Working Group: +a small committee of Python core developers responsible for +overseeing and coordinating the development and maintenance of the Python C API. + +The working group will maintain +documentation, test suites and tooling related to Python's C API. +As delegated by the Steering Council +it is the deciding body for changes to the C API, +from the addition or removal of individual API functions, types, etc., +to the acceptance of new designs of a more or less radical nature. + +The working group's mandate is to represent the interests of all Python users, +but especially all maintainers of code that uses Python's C API, +whether in the context of CPython, using an alternate Python implementation, +or using a binding framework for other programming languages (such as C++ and Rust). + +The working group serves at the pleasure of the Python Steering Council. +The working group's members are the listed authors of this PEP. +This document serves as the working group's charter. + +Epigraph +======== + +| KEEPER +| Stop! + Who would cross the Bridge of Death must answer me these questions three, + ere the other side he see. + +#. What was Python named after? +#. What was Python 2's EOL? +#. What is the optimal strategy to evolve the CPython C API? + +| LANCELOT +| Auuuuuuuugh! + +Motivation +========== + +Despite many discussions and in-person meetings +at core developer sprints and Language Summits, +and a thorough inventory of the problems and stakeholders of the C API, +no consensus has been reached about many contentious issues, +including, but not limited to: + +- Conventions for designing new API functions; +- How to deal with compatibility; +- What's the best strategy for handling errors; +- The future of the Stable ABI and the Limited API; +- Whether to switch to a handle-based API convention (and how). + +The general feeling is that there are too many stakeholders, +proposals, requirements, constraints, and conventions, +to make progress without having a small trusted group of deciders. + +At the 2023 Language Summit in Salt Lake City it was decided to start work on +an `inventory of problems <https://github.com/capi-working-group/problems>`__. +At the 2023 core developer sprint in Brno this work is more or less finished +and after a discussion it appeared that the next step is to establish +a working group to ensure that we're not stymied forever. + +The Steering Council has +`indicated <https://github.com/python/steering-council/issues/201#issuecomment-1648848155>`__ +its desire to delegate decisions about the C API +to such a working group, anticipating its formal establishment. + +Specification +============= + +We propose the creation of a new group, the C API Working Group. +This group will be responsible for overseeing and coordinating the development and +maintenance of the Python C API. +It will do this by establishing the principles underpinning the work +and publishing guidelines that the core developers can refer to. + +The "operations and process" section below describes +how the working group operates and how it is governed. + +Mandate +------- + +The working group's mandate is to ensure that the Python C API +is suitable for all users of and contributors to the API, +without unduly preferencing one group over another. +The working group will identify exemplar stakeholders, +their needs and preferences, +and will determine a plan for meeting these needs equitably and sustainably. +It will oversee execution of the plan. + +Operations and process +---------------------- + +The working group has at least three members, +comprised of prominent Python core developers. +The members should consider the needs of the various stakeholders carefully. + +The Steering Council appoints the initial working group. +There is no term limit for working group members. +Working group members may resign their position at any time, for any reason. +There is an expectation that the membership will change over time. + +To determine replacements, +nominations will be collected from the core developer community. +Self-nominations are allowed. +The existing working group will then decide the replacement member(s) +from the nominees. +The expectation is that this will be done by fiat, +but the working group can choose a replacement by any means they see fit, +including a vote. + +The working group remains accountable to the Steering Council. +At any point, for any reason, the Steering Council could +(publicly or privately) make a specific change +or request a non-specific change to the composition of the working group. + +We acknowledge that this is not a particularly democratic structure +and puts a lot of faith in the working group. +However, the Python community has a long history of success +with structures that are not fully democratic! +We believe that self-governance, cycling of membership, +and accountability to the Steering Council will be sufficient +to ensure that the C API workgroup is meeting the needs of the community. + +The working group may operate primarily through reviews of GitHub issues and PRs. +Regular meetings are likely not necessary, +but the working group may set up video calls, +a private chat, or whatever other mechanism they decide upon internally. + +The working group should aim for transparency, +posting all decisions publicly on +`discuss.python.org <https://discuss.python.org>`__, +with a rationale if possible. +Before making a decision, the working group should give +all interested community members +(as examples of different categories of stakeholders) +a chance to weigh in. +There should be at least a week between the start of a discussion +and the working group's decision. + +Relationship with the Steering Council +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Just like today, the Python Steering Council remains responsible +for the overall direction of the Python C API +and continues to decide on PEPs related to the C API, +using the standard PEP review process (community discussion, etc.). +The C API working group provides written opinions and +recommendations to the Steering Council on PEPs related to the C API. + +However, the working group can make smaller C API changes directly. +The Steering Council may also choose to delegate decisions on some PEPs +to the working group (exactly as any other PEP delegation). + +Amendments +---------- + +This PEP serves as a charter for the working group. +Changes to its operation can be made either through a new PEP +or through a change to this PEP. +In either case, the change will be decided upon +by the Steering Council after discussion in the community. + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From b9138054bcce10d8f814b05505a39c69b9f51aa0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum <guido@python.org> Date: Fri, 13 Oct 2023 15:47:19 +0200 Subject: [PATCH 154/173] PEP 731: Add Discussions-To and Post-History (#3481) --- peps/pep-0731.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/peps/pep-0731.rst b/peps/pep-0731.rst index 2ab43b4c1..d08c0dc2d 100644 --- a/peps/pep-0731.rst +++ b/peps/pep-0731.rst @@ -5,10 +5,12 @@ Author: Guido van Rossum <guido@python.org>, Victor Stinner <vstinner@python.org>, Steve Dower <steve.dower@python.org>, Irit Katriel <irit@python.org> +Discussions-To: https://discuss.python.org/t/pep-731-c-api-working-group-charter/36117 Status: Draft Type: Process Created: 11-Oct-2023 Python-Version: 3.13 +Post-History: `13-Oct-2023 <https://discuss.python.org/t/pep-731-c-api-working-group-charter/36117>`__ Abstract ======== From 4ea40e0d6aee72bca27b62cd5a4a3252d63a478d Mon Sep 17 00:00:00 2001 From: Sebastian Rittau <srittau@rittau.biz> Date: Fri, 13 Oct 2023 15:51:44 +0200 Subject: [PATCH 155/173] PEP 729: A few proposed small changes (#3483) * Remove a "now", which gets repeated in the next sentence. * Add explanations behind PEP numbers. * Move "conformance tests" behind "buy-in" items, seems it seems to me that buy-in should come before writing the tests. --- peps/pep-0729.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/peps/pep-0729.rst b/peps/pep-0729.rst index e267b2e2b..93cf5d318 100644 --- a/peps/pep-0729.rst +++ b/peps/pep-0729.rst @@ -20,7 +20,7 @@ specification and conformance test suite and will initially be appointed by the Motivation ========== -The Python type system was created by :pep:`484`, now almost ten years ago. The type +The Python type system was created by :pep:`484`, almost ten years ago. The type system is now widely used, and typing has become an important tool for writing good, maintainable Python code. Many changes have been made to the type system to cover more use cases and improve usability. Several type checkers have been created, each @@ -207,15 +207,17 @@ Some examples of how past and recent issues could have been handled under this m - A PEP like :pep:`695` (type parameter syntax), which changes the language syntax, would need to be decided upon by the Steering Council; the Typing Council would merely provide opinion or endorsement. Similarly, PEPs - like :pep:`702` would be decided upon by the Steering + like :pep:`702` (deprecations) would be decided upon by the Steering Council, because it concerns runtime behaviour beyond pure typing. Other examples - that would need to be decided by the SC include :pep:`718` and :pep:`727`. + that would need to be decided by the SC include :pep:`718` (subscriptable + functions) and :pep:`727` (documentation metadata). - A PEP like :pep:`698` (``@override``), which affects only users of type checkers and does not change the overall language, would also by default be decided upon by the Steering Council. However, such PEPs could be delegated to the Typing Council for a decision (like any other PEP delegation). Other examples of PEPs that could potentially be delegated include - :pep:`647`, :pep:`655`, :pep:`673`, and :pep:`675`. + :pep:`647` (type guards), :pep:`655` (individual required ``TypedDict`` items), + :pep:`673` (``Self``), and :pep:`675` (``Literal``). - Adding a smaller feature, such as :data:`typing.Never` as an alias for :data:`typing.NoReturn`, would be done by means of a PR to the spec and conformance test suite. The Typing @@ -318,8 +320,6 @@ as a means to achieve a better formalisation of the spec. Proposed changes to the specification, including PEPs, should generally be accompanied by the following: -* Changes to the conformance test suite that demonstrate the - specified behavior. * Buy-in from type checker maintainers to confirm that the change can be implemented and maintained within their type checkers. @@ -327,6 +327,8 @@ generally be accompanied by the following: of existing type checkers. If existing type checkers behave roughly similarly, that is evidence that their shared behavior should be made part of the specification. +* Changes to the conformance test suite that demonstrate the + specified behavior. User-facing reference for the type system ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 6875de21e8a0287b9bba90a0cc1cf1317106e6d1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Fri, 13 Oct 2023 06:59:36 -0700 Subject: [PATCH 156/173] PEP 729, 731: Remove Python-Version (#3484) --- peps/pep-0729.rst | 1 - peps/pep-0731.rst | 1 - 2 files changed, 2 deletions(-) diff --git a/peps/pep-0729.rst b/peps/pep-0729.rst index 93cf5d318..e8726c2ad 100644 --- a/peps/pep-0729.rst +++ b/peps/pep-0729.rst @@ -6,7 +6,6 @@ Status: Draft Type: Process Topic: Typing Created: 19-Sep-2023 -Python-Version: 3.13 Post-History: `04-Oct-2023 <https://discuss.python.org/t/pep-729-typing-governance-process/35362>`__, `20-Sep-2023 <https://discuss.python.org/t/proposed-new-typing-governance-process/34244>`__ diff --git a/peps/pep-0731.rst b/peps/pep-0731.rst index d08c0dc2d..99eb33f3c 100644 --- a/peps/pep-0731.rst +++ b/peps/pep-0731.rst @@ -9,7 +9,6 @@ Discussions-To: https://discuss.python.org/t/pep-731-c-api-working-group-charter Status: Draft Type: Process Created: 11-Oct-2023 -Python-Version: 3.13 Post-History: `13-Oct-2023 <https://discuss.python.org/t/pep-731-c-api-working-group-charter/36117>`__ Abstract From 2ff051f662a57f2bc0acaa08e8ea691635fdeb41 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Fri, 13 Oct 2023 17:21:08 +0200 Subject: [PATCH 157/173] PEP 719: The first alpha of 3.13 was released on Friday 13th (#3485) --- peps/pep-0719.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0719.rst b/peps/pep-0719.rst index 40bcec4b0..c2df8e693 100644 --- a/peps/pep-0719.rst +++ b/peps/pep-0719.rst @@ -43,10 +43,10 @@ in a 12-month release cadence between feature versions, as defined by Actual: - 3.13 development begins: Monday, 2023-05-22 +- 3.13.0 alpha 1: Friday, 2023-10-13 Expected: -- 3.13.0 alpha 1: Tuesday, 2023-10-17 - 3.13.0 alpha 2: Tuesday, 2023-11-21 - 3.13.0 alpha 3: Tuesday, 2023-12-19 - 3.13.0 alpha 4: Tuesday, 2024-01-16 From 43bdd16f01d15d36c44426a2c734edd161e9d02a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Fri, 13 Oct 2023 18:08:03 +0200 Subject: [PATCH 158/173] PEPs 729, 731: Apply Governance topic (#3487) --- peps/pep-0729.rst | 2 +- peps/pep-0731.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/peps/pep-0729.rst b/peps/pep-0729.rst index e8726c2ad..93ecd8b26 100644 --- a/peps/pep-0729.rst +++ b/peps/pep-0729.rst @@ -4,7 +4,7 @@ Author: Jelle Zijlstra <jelle.zijlstra@gmail.com>, Shantanu Jain <hauntsaninja a Discussions-To: https://discuss.python.org/t/pep-729-typing-governance-process/35362 Status: Draft Type: Process -Topic: Typing +Topic: Governance, Typing Created: 19-Sep-2023 Post-History: `04-Oct-2023 <https://discuss.python.org/t/pep-729-typing-governance-process/35362>`__, `20-Sep-2023 <https://discuss.python.org/t/proposed-new-typing-governance-process/34244>`__ diff --git a/peps/pep-0731.rst b/peps/pep-0731.rst index 99eb33f3c..a53911362 100644 --- a/peps/pep-0731.rst +++ b/peps/pep-0731.rst @@ -8,6 +8,7 @@ Author: Guido van Rossum <guido@python.org>, Discussions-To: https://discuss.python.org/t/pep-731-c-api-working-group-charter/36117 Status: Draft Type: Process +Topic: Governance Created: 11-Oct-2023 Post-History: `13-Oct-2023 <https://discuss.python.org/t/pep-731-c-api-working-group-charter/36117>`__ From 6715be7d1ca69912983f0e75101a6cecec52b09f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Sun, 15 Oct 2023 15:18:19 -0700 Subject: [PATCH 159/173] PEP 702: Tools may clean up the deprecation message (#3482) See https://discuss.python.org/t/pep-702-marking-deprecations-using-the-type-system/23036/53?u=jelle I don't want to prescribe the exact behavior on tools and IDEs; they can figure out for themselves what works best. This change is intended to make it so they can adjust the message without worrying that they are breaking the specification. --- peps/pep-0702.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/peps/pep-0702.rst b/peps/pep-0702.rst index d81d42ad2..5e0ce03b5 100644 --- a/peps/pep-0702.rst +++ b/peps/pep-0702.rst @@ -115,6 +115,8 @@ The decorator takes the following arguments: The positional-only argument is of type ``str`` and contains a message that should be shown by the type checker when it encounters a usage of the decorated object. +Tools may clean up the deprecation message for display, for example +by using :func:`inspect.cleandoc` or equivalent logic. The message must be a string literal. The content of deprecation messages is up to the user, but it may include the version in which the deprecated object is to be removed, and information about suggested From 54f10d9ca49bc369f9e43c5de22de65690010b5d Mon Sep 17 00:00:00 2001 From: Alice <alicederyn@gmail.com> Date: Mon, 16 Oct 2023 15:49:44 +0100 Subject: [PATCH 160/173] PEP 705: Rewrite to focus on TypedDict changes (#3440) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- peps/pep-0705.rst | 606 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 478 insertions(+), 128 deletions(-) diff --git a/peps/pep-0705.rst b/peps/pep-0705.rst index f62a8305c..15bcfe8af 100644 --- a/peps/pep-0705.rst +++ b/peps/pep-0705.rst @@ -1,5 +1,5 @@ PEP: 705 -Title: TypedMapping: Type Hints for Mappings with a Fixed Set of Keys +Title: TypedDict: Read-only and other keys Author: Alice Purcell <alicederyn@gmail.com> Sponsor: Pablo Galindo <pablogsal@gmail.com> Discussions-To: https://discuss.python.org/t/pep-705-typedmapping/24827 @@ -8,7 +8,7 @@ Type: Standards Track Topic: Typing Content-Type: text/x-rst Created: 07-Nov-2022 -Python-Version: 3.12 +Python-Version: 3.13 Post-History: `30-Sep-2022 <https://mail.python.org/archives/list/typing-sig@python.org/thread/6FR6RKNUZU4UY6B6RXC2H4IAHKBU3UKV/>`__, `02-Nov-2022 <https://mail.python.org/archives/list/python-dev@python.org/thread/2P26R4VH2ZCNNNOQCBZWEM4RNF35OXOW/>`__, `14-Mar-2023 <https://discuss.python.org/t/pep-705-typedmapping/24827>`__, @@ -19,14 +19,19 @@ Abstract :pep:`589` defines the structural type :class:`~typing.TypedDict` for dictionaries with a fixed set of keys. As ``TypedDict`` is a mutable type, it is difficult to correctly annotate methods which accept read-only parameters in a way that doesn't prevent valid inputs. -This PEP proposes a type constructor ``typing.TypedMapping`` to support this use case. +As structural subtypes can add other keys in, it is also difficult for type-checkers to safely define covariant methods like ``update``, or support type narrowing. +This PEP proposes two new ``TypedDict`` flags, ``readonly`` and ``other_keys``, plus an associated type qualifier, ``typing.ReadOnly``. Motivation ========== Representing structured data using (potentially nested) dictionaries with string keys is a common pattern in Python programs. :pep:`589` allows these values to be type checked when the exact type is known up-front, but it is hard to write read-only code that accepts more specific variants: for instance, where fields may be subtypes or restrict a union of possible types. This is an especially common issue when writing APIs for services, which may support a wide range of input structures, and typically do not need to modify their input. -For illustration, we will try to add type hints to a function ``movie_string``:: + +Pure functions +-------------- + +Consider trying to add type hints to a function ``movie_string``:: def movie_string(movie: Movie) -> str: if movie.get("year") is None: @@ -77,106 +82,319 @@ The problem disappears if we don't have mutator methods in ``Movie``. This could This is very repetitive, easy to get wrong, and is still missing important method definitions like ``__contains__()`` and ``keys()``. +Updating nested dicts +--------------------- + +The structural typing of ``TypedDict`` is supposed to permit writing update functions that only constrain the types of entries they modify:: + + class HasTimestamp(TypedDict): + timestamp: float + + class Logs(TypedDict): + timestamp: float + loglines: list[str] + + def update_timestamp(d: HasTimestamp) -> None: + d["timestamp"] = now() + + def add_logline(logs: Logs, logline: str) -> None: + logs["loglines"].append(logline) + update_timestamp(logs) # Accepted by type checker + +However, this no longer works once you start nesting dictionaries:: + + class HasTimestampedMetadata(TypedDict): + metadata: HasTimestamp + + class UserAudit(TypedDict): + name: str + metadata: Logs + + def update_metadata_timestamp(d: HasTimestampedMetadata) -> None: + d["metadata"]["timestamp"] = now() + + def rename_user(d: UserAudit, name: str) -> None: + d["name"] = name + update_metadata_timestamp(d) # Type check error: "metadata" is not of type HasTimestamp + +This looks like an error, but is simply due to the (unwanted) ability to overwrite the ``metadata`` entry held by the ``HasTimestampedMetadata`` instance with a different ``HasTimestamp`` instance, that may no longer be a ``UserAudit`` instance. + +It is possible to work around this issue with generics (as of Python 3.11), but it is very complicated, requiring a type parameter for every nested dict. + + +Type discrimination +------------------- + +Another common idiom in JSON APIs is to discriminate between mutually exclusive choices with a single-entry dictionary, where the key on the dictionary distinguishes between choices, and constrains the associated value type:: + + class Movie(TypedDict): + name: str + director: str + + class Book(TypedDict): + name: str + author: str + + class EntertainmentMovie(TypedDict): + movie: Movie + + class EntertainmentBook(TypedDict): + book: Book + + Entertainment = EntertainmentMovie | EntertainmentBook + +Users of this pattern expect type-checkers to allow the following pattern:: + + def get_name(entertainment: Entertainment) -> str: + if "movie" in entertainment: + return entertainment["movie"]["name"] + elif "book" in entertainment: + return entertainment["book"]["name"] + else: + # Theoretically unreachable but common defensive coding + raise ValueError("Unexpected entertainment type") + +However, type-checkers will actually raise an error on this code; mypy, for instance, will complain that ``TypedDict "EntertainmentBook" has no key "movie"`` on the third line. This is because ``TypedDict`` does not prevent instances from having keys not specified in the type, and so the check ``"movie" in entertainment`` can return True for an ``EntertainmentBook``. + +Users can alternatively use a non-total ``TypedDict`` instead of a union:: + + class Entertainment(TypedDict, total=False): + movie: Movie + book: Book + +This ensures the ``get_name`` example type-checks correctly, but it no longer encodes the constraint that exactly one key must be present, meaning other valid code raises spurious type-check failures. In practice, we tend to see code using types like this either casting to the correct type, with the associated risk of mistakes, or moving the ``in`` checks to dedicated ``TypeGuard`` functions, reducing readability. + Rationale ========= -The proposed ``TypedMapping`` type allows a straightforward way of defining these types that should be familiar to existing users of ``TypedDict`` and support the cases exemplified above:: +The first two motivating examples can be solved by removing the ability to update one or more of the entries in a ``TypedDict``. This does not mean the entries are immutable; a reference to the underlying dictionary could still exist with a different but compatible type in which those entries have mutator operations. As such, these are not "final" entries; using this term would risk confusion with final attributes, which are fully immutable. These entries are "readonly". - from typing import NotRequired, TypedMapping +To support this, we propose adding a new boolean flag to ``TypedDict``, ``readonly``, which when set to True, removes all mutator operations from the type:: - class Movie(TypedMapping): + from typing import NotRequired, TypedDict + + class Movie(TypedDict, readonly=True): name: str - year: NotRequired[int | None] + director: str -In addition to those benefits, by flagging arguments of a function as ``TypedMapping``, it makes explicit not just to typecheckers but also to users that the function is not going to modify its inputs, which is usually a desirable property of a function interface. -Finally, this allows bringing the benefits of ``TypedDict`` to other mapping types that are unrelated to ``dict``. + class Book(TypedDict, readonly=True): + name: str + author: str + +In addition to these benefits, by flagging arguments of a function as read-only (by using a read-only ``TypedDict`` like ``Movie`` or ``Book``), it makes explicit not just to typecheckers but also to users that the function is not going to modify its inputs, which is usually a desireable property of a function interface. + +A new ``typing.ReadOnly`` type qualifier allows removing the ability to mutate individual entries, permitting a mixture of readonly and mutable entries. This is necessary for supporting the second motivating example, updating nested dicts:: + + class UserAudit(TypedDict): + name: str + metadata: ReadOnly[Logs] + +This PEP only proposes making ``ReadOnly`` valid in a ``TypedDict``. A possible future extension would be to support it in additional contexts, such as in protocols. + +Finally, to support type discrimination, we add a second flag to ``TypedDict``, ``other_keys``, which when set to ``typing.Never``, prevents instances from holding any key not explicitly listed in the type:: + + class EntertainmentMovie(TypedDict, readonly=True, other_keys=Never): + movie: Movie + + class EntertainmentBook(TypedDict, readonly=True, other_keys=Never): + book: Book + + Entertainment = EntertainmentMovie | EntertainmentBook + + def get_name(entertainment: Entertainment) -> str: + if "movie" in entertainment: + return entertainment["movie"]["name"] + elif "book" in entertainment: + return entertainment["book"]["name"] + else: + raise ValueError("Unexpected entertainment type") + +Note this is a subset of the functionality of the `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_. Specification ============= -A ``TypedMapping`` type defines a protocol with the same methods as :class:`~collections.abc.Mapping`, but with value types determined per-key as with ``TypedDict``. +``TypedDict`` will gain two new flags: ``other_keys`` and ``readonly``. A new ``typing.ReadOnly`` type qualifier is added. -Notable similarities to ``TypedDict``: +``other_keys`` flag +------------------- -* A ``TypedMapping`` protocol can be declared using class-based or alternative syntax. -* Keys must be strings. -* By default, all specified keys must be present in a ``TypedMapping`` instance. It is possible to override this by specifying totality, or by using ``NotRequired`` from :pep:`655`. -* Methods are not allowed in the declaration (though they may be inherited). +The optional ``other_keys`` flag to ``TypedDict`` can have the value ``typing.Never``, indicating that instances may only contain keys explicitly listed in the type:: -Notable differences from ``TypedDict``: - -* The runtime type of a ``TypedMapping`` object is not constrained to be a ``dict``. -* No mutator methods (``__setitem__``, ``__delitem__``, ``update``, etc.) will be generated. -* The ``|`` operator is not supported. -* A class definition defines a ``TypedMapping`` protocol if and only if ``TypedMapping`` appears directly in its class bases. -* Subclasses can narrow value types, in the same manner as other protocols. - -As with :pep:`589`, this PEP provides a sketch of how a type checker is expected to support type checking operations involving ``TypedMapping`` and ``TypedDict`` objects, but details are left to implementors. In particular, type compatibility should be based on structural compatibility. - - -Multiple inheritance and TypedDict ----------------------------------- - -A type that inherits from a ``TypedMapping`` protocol and from ``TypedDict`` (either directly or indirectly): - -* is the structural intersection of its parents, or invalid if no such intersection exists -* instances must be a dict subclass -* adds mutator methods only for fields it explicitly (re)declares - -For example:: - - class Movie(TypedMapping): + class Album(TypedDict, other_keys=Never): name: str - year: int | None - - class MovieRecord(Movie, TypedDict): year: int - movie: MovieRecord = { "name": "Blade Runner", - "year": 1982 } - - movie["year"] = 1985 # Fine; mutator methods added in definition - movie["name"] = "Terminator" # Type check error; "name" mutator not declared + class AlbumExtra(Album, TypedDict): + band: str # Runtime error -Inheriting, directly or indirectly, from both ``TypedDict`` and ``Protocol`` will continue to fail at runtime, and should continue to be rejected by type checkers. +Type-checkers may rely on this restriction:: + + def album_keys(album: Album) -> Collection[Literal['name', 'year']]: + # Type checkers may permit this, but should error if Album did not specify `other_keys=Never` + return album.keys() + +Type-checkers should prevent operations that would violate this restriction:: + + class AlbumExtra(TypedDict, other_keys=Never): + name: str + year: int + band: str + + album: AlbumExtra = { "name": "Flood", year: 1990, band: "They Might Be Giants" } + album_keys(album) # Type check error: extra key 'band' + +This PEP does not propose supporting any other values than ``other_keys=Never``. Future or concurrent PEPs may extend this flag to permit other types. + +``readonly`` flag +----------------- + +The optional boolean ``readonly`` flag to ``TypedDict``, when ``True``, indicates that no mutator operations (``__setitem__``, ``__delitem__``, ``update``, etc.) will be permitted:: + + class NamedDict(TypedDict, readonly=True): + name: str + + def get_name(d: NamedDict) -> str: + return d["name"] + + def set_name(d: NamedDict, name: str) -> None: + d["name"] = name # Type check error: cannot modify a read-only entry + +The ``readonly`` flag defaults to ``False``. + +``typing.ReadOnly`` flag +------------------------ + +The ``typing.ReadOnly`` type qualifier is used to indicate that a variable declared in a ``TypedDict`` definition may not be mutated by any operation performed on instances of the ``TypedDict``:: + + from typing import ReadOnly + + class BandAndAlbum(TypedDict): + band: str + album: ReadOnly[Album] + +The ``readonly`` flag is equivalent to marking all entries as ``ReadOnly[]``, guaranteeing no entries are missed by mistake. To avoid potential confusion, it is an error to use both ``readonly=True`` and ``ReadOnly[]``:: + + class Band(TypedDict, readonly=True): + name: ReadOnly[str] # Runtime error: redundant ReadOnly qualifier + members: Collection[str] + +Alternative functional syntax +----------------------------- + +The :pep:`alternative functional syntax <589#alternative-syntax>` for TypedDict also supports these features:: + + EntityBand = TypedDict('EntityBand', {'band': Band}, readonly=True, other_keys=Never) + BandAndAlbum = TypedDict(`BandAndAlbum', {'band': str, 'album': ReadOnly[Album]}) + +Interaction with other special types +------------------------------------ + +``ReadOnly[]`` can be used with ``Required[]``, ``NotRequired[]`` and ``Annotated[]``, in any nesting order: + +:: + + class Movie(TypedDict): + title: ReadOnly[Required[str]] # OK + year: ReadOnly[NotRequired[Annotated[int, ValueRange(-9999, 9999)]]] # OK + +:: + + class Movie(TypedDict): + title: Required[ReadOnly[str]] # OK + year: Annotated[NotRequired[ReadOnly[int]], ValueRange(-9999, 9999)] # OK + +This is consistent with the behavior introduced in :pep:`655`. + +Inheritance +----------- + +To avoid potential confusion, it is an error to have a read-only type extend a non-read-only type:: + + class BandAlbumAndLabel(BandAndAlbum, readonly=True): # Runtime error + label: str -Multiple inheritance and Protocol ---------------------------------- +It is also an error to have a type without ``other_keys`` specified extend a type with ``other_keys=Never``:: -* A type that inherits from a ``TypedMapping`` protocol and from a ``Protocol`` protocol must satisfy the protocols defined by both, but is not itself a protocol unless it inherits directly from ``TypedMapping`` or ``Protocol``. -* A type that inherits from a ``TypedMapping`` protocol and from ``Protocol`` itself is configured as a ``Protocol``. Methods and properties may be defined; keys may not:: + class NamedDict(TypedDict, readonly=True): + name: str - class A(Movie, Protocol): - # Declare a mutable property called 'year' - # This does not affect the dictionary key 'year' - year: str + class Person(NamedDict): # Runtime error + age: float -* A type that inherits from a ``Protocol`` protocol and from ``TypedMapping`` itself is configured as a ``TypedMapping``. Keys may be defined; methods and properties may not:: +It is valid to have a non-read-only type extend a read-only one. The subclass will not be read-only, but any keys not redeclared in the subclass will remain read-only:: - class B(A, TypedMapping): - # Declare a key 'year' - # This does not affect the property 'year' + class Album(NamedDict, TypedDict): year: int + album: Album = { name: "Flood", year: 1990 } + album["year"] = 1973 # OK + album["name"] = "Dark Side Of The Moon" # Type check error: "name" is read-only -Type consistency rules ----------------------- +Subclasses can redeclare read-only entries as non-read-only, allowing them to be mutated:: -Informally speaking, *type consistency* is a generalization of the is-subtype-of relation to support the ``Any`` type. It is defined more formally in :pep:`483`. This section introduces the new, non-trivial rules needed to support type consistency for ``TypedMapping`` types. + class Album(NamedDict, TypedDict): + name: str + year: int -First, any ``TypedMapping`` type is consistent with ``Mapping[str, object]``. -Second, a ``TypedMapping`` or ``TypedDict`` type ``A`` is consistent with ``TypedMapping`` ``B`` if ``A`` is structurally compatible with ``B``. This is true if and only if both of these conditions are satisfied: + album: Album = { name: "Flood", year: 1990 } + album["year"] = 1973 # OK + album["name"] = "Dark Side Of The Moon" # Also OK now -* For each key in ``A``, ``B`` has the corresponding key and the corresponding value type in ``B`` is consistent with the value type in ``A``. +Subclasses can narrow value types of read-only entries:: -* For each required key in ``A``, the corresponding key is required in ``B``. + class AlbumCollection(TypedDict, readonly=True): + albums: Collection[Album] + + class RecordShop(AlbumCollection, TypedDict): + name: str + albums: list[Album] + +Subclasses can also require keys that are read-only but not required in the superclass:: + + class OptionalName(TypedDict, readonly=True): + name: NotRequired[str] + + class Person(OptionalName, TypedDict): + name: Required[str] + + person: Person = {} # Type check error: "name" required + +Note that these are just consequences of structural typing, but they are highlighted here as the behavior now differs from the rules specified in :pep:`589`. + +Finally, subclasses can have ``other_keys=Never`` even if the superclass does not:: + + class Person(OptionalName, other_keys=Never): + name: Required[str] + +Type consistency +---------------- + +*This section updates the type consistency rules introduced in* :pep:`589` *to cover the new features in this PEP. In particular, any pair of types that do not use the new features will be consistent under these new rules if (and only if) they were already consistent.* + +A TypedDict type with ``other_keys=Never`` is consistent with ``Mapping[str, V]``, where ``V`` is the union of all its value types. For instance, the following type is consistent with ``Mapping[str, int | str]``:: + + class Person(TypedDict, other_keys=Never): + name: str + age: int + +A TypedDict type ``A`` is consistent with TypedDict ``B`` if ``A`` is structurally compatible with ``B``. This is true if and only if all of the following are satisfied: + +* For each key in ``B``, ``A`` has the corresponding key and the corresponding value type in ``A`` is consistent with the value type in ``B``, unless the key in ``B`` is of type ``ReadOnly[NotRequired[Any]]``, in which case it may be missing in ``A`` provided ``A`` allows other keys. +* For each non-read-only key in ``B``, the corresponding value type in ``B`` is also consistent with the corresponding value type in ``A``. +* For each required key in ``B``, the corresponding key is required in ``A``. +* For each non-read-only, non-required key in ``B``, the corresponding key is not required in ``A``. +* If ``B`` does not allow other keys, then ``A`` does not allow other keys. +* If ``B`` does not allow other keys, then for each key in ``A``, ``B`` has the corresponding key. Discussion: -* Value types behave covariantly, since ``TypedMapping`` objects have no mutator methods. This is similar to container types such as ``Mapping``, and different from relationships between two ``TypedDict`` types. Example:: +* All non-specified keys in a type that allows other keys are implicitly of type ``ReadOnly[NotRequired[Any]]`` (or ``ReadOnly[NotRequired[Unknown]]`` in pyright). - class A(TypedMapping): +* Read-only value types behave covariantly, as they cannot be mutated. This is similar to container types such as ``Sequence``, and different from non-read-only value types, which behave invariantly. Example:: + + class A(TypedDict, readonly=True): x: int | None class B(TypedDict): @@ -185,111 +403,243 @@ Discussion: def f(a: A) -> None: print(a['x'] or 0) - b: B = {'x': 0} + b: B = {'x': 1} f(b) # Accepted by type checker -* A ``TypedDict`` or ``TypedMapping`` type with a required key is consistent with a ``TypedMapping`` type where the same key is a non-required key, again unlike relationships between two ``TypedDict`` types. Example:: +* A TypedDict type ``A`` with no explicit key ``'x'`` that allows other keys is not consistent with a TypedDict type with a non-required key ``'x'``, since at runtime the key ``'x'`` could be present and have an incompatible type (which may not be visible through ``A`` due to structural subtyping). The only exception to this rule is if ``'x'`` is non-required, read-only and of type ``object`` (or ``Any`` or pylance's ``Unknown``). - class A(TypedMapping, total=False): - x: int +* A TypedDict type ``A`` with no key ``'x'`` that does not allow other keys may be consistent with a TypedDict type with a read-only, non-required key ``'x'``. Example:: - class B(TypedDict): - x: int - - def f(a: A) -> None: - print(a.get('x', 0)) - - b: B = {'x': 0} - f(b) # Accepted by type checker - -* A ``TypedMapping`` type ``A`` with no key ``'x'`` is not consistent with a ``TypedMapping`` type with a non-required key ``'x'``, since at runtime the key ``'x'`` could be present and have an incompatible type (which may not be visible through ``A`` due to structural subtyping). This is the same as for ``TypedDict`` types. Example:: - - class A(TypedMapping, total=False): - x: int + class A(TypedDict, total=False, readonly=True): y: int - class B(TypedMapping, total=False): + class B(TypedDict, other_keys=Never): x: int - class C(TypedMapping, total=False): - x: int - y: str - - def f(a: A) -> None: - print(a.get('y') + 1) + def f(a: A) -> int: + return a.get("y", 0) def g(b: B) -> None: - f(b) # Type check error: 'B' incompatible with 'A' + b["x"] = f(b) # Accepted by type checker - c: C = {'x': 0, 'y': 'foo'} - g(c) # Runtime error: str + int +Union Operation +--------------- -* A ``TypedMapping`` with all ``int`` values is not consistent with ``Mapping[str, int]``, since there may be additional non-``int`` values not visible through the type, due to structural subtyping. This mirrors ``TypedDict``. Example:: +The union operation creates a new dictionary with the merged keys and values of its two operands. As such, the result should be consistent with any type that can hold the possible key-value pairs, not just types compatible with the operand types. For example:: - class A(TypedMapping): + class A(TypedDict, readonly=True, other_keys=Never): x: int - class B(TypedMapping): + class B(TypedDict, total=False, readonly=True, other_keys=Never): + x: str + + class C(TypedDict): + x: int | str + + def union_a_b(a: A, b: B) -> C: + # Accepted by type-checker, even though C is not read-only and + # allows other keys: + return a | b + +This is different from the usual compatibility rules, where the result of an operation has a defined type which the variable it is assigned to must be consistent with. A similar situation occurs with ``TypedDict`` and ``copy()`` or ``deepcopy()``. + +If the union of two TypedDict objects of type ``A`` and ``B`` are assigned to a TypedDict of type ``C``, the type checker should verify that: + +* if ``C`` does not allow other keys, neither ``A`` nor ``B`` allow other keys +* if ``C`` does not allow other keys, it contains all keys found in either ``A`` or ``B`` +* if a key ``'x'`` is found in ``A`` and ``C``, its type in ``A`` is consistent with its type in ``C``. +* if a key ``'x'`` is found in ``B`` and ``C``, its type in ``B`` is consistent with its type in ``C``. +* if a key ``'x'`` is required in ``C``, it is required in either ``A`` or ``B``. + +Notes: + +* The read-only status of the keys does not matter. A key can be read-only on just ``A``, just ``B``, or just ``C``, or any combination. +* A key found on ``A`` or ``B`` may be missed off ``C`` if it allows other keys. Type-checkers may however choose to flag this edge-case with a warning or error in some circumstances, if it is found to be a source of mistakes. + +Update Operations +----------------- + +Previously, ``clear()`` and ``popitem()`` were rejected by type checkers on TypedDict objects, as they could remove required keys, some of which may not be directly visible because of structural subtyping. However, these methods should be allowed on TypedDicts objects with all keys non-read-only and non-required and with no other keys allowed:: + + class A(TypedDict, total=False, other_keys=Never): x: int y: str - def sum_values(m: Mapping[str, int]) -> int: - return sum(m.values()) + a: A = { "x": 1, "y": "foo" } + a.popitem() # Accepted by type checker + a.clear() # Accepted by type checker - def f(a: A) -> None: - sum_values(a) # Type check error: 'A' incompatible with Mapping[str, int] +``update`` has been difficult to type correctly due to the open nature of TypedDict objects. Keys not specified on the type could still be present (and constrained) due to structural subtyping, meaning type safety could be accidentally violated. For instance:: - b: B = {'x': 0, 'y': 'foo'} - f(b) # Runtime error: int + str + class B(TypedDict, total=False): + x: int + + def update_b(b1: B, b2: B) -> None: + b1.update(b2) + + class C(B, TypedDict, total=False): + y: int + + class D(B, TypedDict, total=False): + y: str + + c: C = { "x": 1, "y": 2 } + d: D = { "x": 3, "y": "foo" } + update_b(c, d) # c is no longer a C at runtime + +Both mypy and pyright currectly permit this usage, however, as the only viable alternative has been to prevent calling ``update`` at all. + +With the addition of ``other_keys``, it becomes possible to more accurately type the update method: + +* Declare a new read-only TypedDict type that does not allow other keys +* Copy all non-read-only entries to it +* Make all entries read-only and non-required +* Union this with an iterable of matching key-value pairs + +For instance:: + + class Example(TypedDict): + a: int + b: NotRequired[str] + c: ReadOnly[int] + + class ExampleUpdateDict(TypedDict, total=False, readonly=True, other_keys=Never): + a: int + b: str + # c is not present as it is read-only in Example + + ExampleUpdateEntry = tuple[Literal["a"], int] | tuple[Literal["b"], str] + ExampleUpdate = ExampleUpdateDict | Iterable[ExampleUpdateEntry] + +Type checkers should permit any type compatible with this TypedDict to be passed into the update operation. As with :pep:`589`, they may choose to continue permitting TypedDict types that allow other keys as well, to avoid generating false positives. + +Keyword argument typing +----------------------- + +:pep:`692` introduced ``Unpack`` to annotate ``**kwargs`` with a ``TypedDict``. Marking one or more of the entries of a ``TypedDict`` used in this way as read-only will have no effect on the type signature of the method, since all keyword arguments are read-only by design in Python. However, it *will* prevent the entry from being modified in the body of the function:: + + class Args(TypedDict): + key1: int + key2: str + + class ReadonlyArgs(TypedDict, readonly=True): + key1: int + key2: str + + class Function(Protocol): + def __call__(self, **kwargs: Unpack[Args]) -> None: ... + + def impl(self, **kwargs: Unpack[ReadonlyArgs]) -> None: + kwargs["key1"] = 3 # Type check error: key1 is readonly + + fn: Function = impl # Accepted by type checker: function signatures are identical -Backwards Compatibility +Backwards compatibility ======================= -This PEP changes the rules for how ``TypedDict`` behaves (allowing subclasses to -inherit from ``TypedMapping`` protocols in a way that changes the resulting -overloads), so code that inspects ``TypedDict`` types will have to change. This -is expected to mainly affect type-checkers. +This PEP adds new features to ``TypedDict``, so code that inspects ``TypedDict`` types will have to change to support types using the new features. This is expected to mainly affect type-checkers. -The ``TypedMapping`` type will be added to the ``typing_extensions`` module, -enabling its use in older versions of Python. - - -Security Implications +Security implications ===================== There are no known security consequences arising from this PEP. - How to Teach This ================= -Class documentation should be added to the :mod:`typing` module's documentation, using -that for :class:`~collections.abc.Mapping`, :class:`~typing.Protocol` and -:class:`~typing.TypedDict` as examples. Suggested introductory sentence: "Base class -for read-only mapping protocol classes." +Suggestion for changes to the :mod:`typing` module, in line with current practice: -This PEP could be added to the others listed in the :mod:`typing` module's documentation. +* Add this PEP to the others listed. +* Add ``typing.ReadOnly``, linked to TypedDict and this PEP. +* Add the following text to the TypedDict entry: +By default, keys not specified in a TypedDict may still be present. Instances can be restricted to only the named keys with the ``other_keys`` flag. *insert example, perhaps using ``in`` to illustrate the benefit* + +Individual keys can be excluded from mutate operations using ReadOnly, allowing them to be read but not changed. This is useful when the exact type of the value is not known yet, and so modifying it would break structural subtypes. *insert example* + +If all keys on a TypedDict should be read-only, the ``readonly`` flag can be used as a shorthand. *insert example* Reference Implementation ======================== -No reference implementation exists yet. - +No complete reference implementation exists yet. pyright 1.1.310 ships with a partial implementation of the ReadOnly qualifier. Rejected Alternatives ===================== -Several variations were considered and discarded: +A TypedMapping protocol type +---------------------------- -* A ``readonly`` parameter to ``TypedDict``, behaving much like ``TypedMapping`` but with the additional constraint that instances must be dictionaries at runtime. This was discarded as less flexible due to the extra constraint; additionally, the new type nicely mirrors the existing ``Mapping``/``Dict`` types. -* Inheriting from a ``TypedMapping`` subclass and ``TypedDict`` resulting in mutator methods being added for all fields, not just those actively (re)declared in the class body. Discarded as less flexible, and not matching how inheritance works in other cases for ``TypedDict`` (e.g. total=False and total=True do not affect fields not specified in the class body). -* A generic type that removes mutator methods from its parameter, e.g. ``Readonly[MovieRecord]``. This would naturally want to be defined for a wider set of types than just ``TypedDict`` subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower. -* Declaring methods directly on a ``TypedMapping`` class. Methods are a kind of property, but declarations on a ``TypedMapping`` class are defining keys, so mixing the two is potentially confusing. Banning methods also makes it very easy to decide whether a ``TypedDict`` subclass can mix in a protocol or not (yes if it's just ``TypedMapping`` superclasses, no if there's a ``Protocol``). +An earlier version of :pep:`705` proposed a ``TypedMapping`` protocol type, behaving much like a read-only TypedDict but without the constraint that the runtime type be a ``dict``. The behavior described in the current version of this PEP could then be obtained by inheriting a TypedDict from a TypedMapping. This has been set aside for now as more complex, without a strong use-case motivating the additional complexity. + +A higher-order Readonly type +---------------------------- + +A generalized higher-order type could be added that removes mutator methods from its parameter, e.g. ``ReadOnly[MovieRecord]``. For a TypedDict, this would be like adding ``readonly=True`` to the declaration. This would naturally want to be defined for a wider set of types than just TypedDict subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower. + +Preventing other keys with the typing.final decorator +----------------------------------------------------- + +Instead of adding an ``other_keys`` flag to TypedDict, treat classes decorated with :func:`~typing.final` as disallowing other keys. This makes intuitive sense for TypedDict as it stands now: preventing adding any other keys guarantees no other types will be structurally compatible, so it is effectively final. There is also partial support for this idiom in mypy and pyright, which both use it as a way to achieve type discrimination. However, if any keys are read-only, preventing adding any other keys does **not** make the type final any more, so using the decorator this way seems incorrect. For example:: + + class Foo: ... + class Bar(Foo): ... + + @final + class FooHolder(TypedDict, readonly=True): + item: Foo + + @final + class BarHolder(FooHolder, readonly=True): + item: Bar + +Extending a ``TypedDict`` to refine the types is a reasonable feature, but the above code looks like it should raise a runtime error. Should ``@final`` be modified to allow inheritance? Should users be prevented from using this pattern? + +More context for this can be found on `pyright issue 5254 <https://github.com/microsoft/pyright/issues/5254>`_. + +We recommend type checkers treat decorating a TypedDict type with final as identical to setting ``other_keys=Never``, if they continue to support the idiom for backwards compatibility, but reject any use of final on a TypedDict with read-only keys. Once ``other_keys`` is adopted, they may also wish to deprecate use of final on TypedDicts entirely. + +Using different casing for ``readonly`` keyword or ``ReadOnly`` type +-------------------------------------------------------------------- + +It appears to be common convention to put an initial caps onto words separated by a dash when converting to CamelCase, but to drop the dash completely when converting to snake_case. Django uses ``readonly``, for instance. This appears consistent with the definition of both on Wikipedia: snake_case replaces spaces with dashes, while CamelCase uppercases the first letter of each word. That said, more examples or counterexamples, ideally from the core Python libraries, or better explicit guidance on the convention, would be greatly appreciated. + +Mandate unsound type narrowing +------------------------------ + +The main use-case we are aware of for ``other_keys=Never`` (and the current workaround of final-decorated TypedDict types) is to simplify type discrimination, as shown in the motivation section. + +By comparison, TypeScript handles this edge-case by ignoring the possibility of instances of one type in the union having undeclared keys. If a variable is known to be of type ``A | B`` and an ``in`` check is done using a key not explicitly declared on ``B``, it is assumed no instance of ``B`` will pass that check. While technically unsound, this a common enough idiom that it could fall under the recommendation in :pep:`589` that "potentially unsafe operations may be accepted if the alternative is to generate false positive errors for idiomatic code". + +This user request has been rejected multiple times by type checkers, however, suggesting the community prefers strict type-safety over idiomatic code here. + +Make the ``other_keys`` flag a boolean +-------------------------------------- + +Since ``other_keys`` can only effectively take two values, ``Never`` or absent, it was originally proposed as a boolean flag, with ``other_keys=False`` equivalent to the current ``other_keys=Never``. However, the `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_ provides equivalent functionality when restricting other types to ``Never``, so this proposal was updated to use comparable syntax, to make it clearer how the proposals intersect. + +Use a reserved ``__extra__`` key +-------------------------------- + +The `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_ proposes different syntax for disallowing other keys:: + + class EntertainmentMovie(TypedDict, readonly=True): + movie: Movie + __extra__: Never + +This new key does not function like other keys -- for instance, it is implicitly ``NotRequired`` but cannot be explicitly marked as such. The author of this PEP prefers the asymmetry of using a keyword argument to set expectations that it does not behave like other key declarations, and others have provided similar feedback on the PR. + +However, this PEP will be updated to match whatever syntax the PEP-728 author decides to go with. + +Leave other_keys to PEP-728 +--------------------------- + +This PEP could drop the ``other_keys`` proposal entirely rather than propose a limited subset of it. However, as this PEP affects the unofficial status-quo of using final to disallow other keys, it seems important to both highlight that issue and propose a solution. Copyright ========= This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive. + From 3759887f42d39aef96299b0aa43ca9e4a7e5cfcb Mon Sep 17 00:00:00 2001 From: Sebastian Rittau <srittau@rittau.biz> Date: Tue, 17 Oct 2023 15:40:42 +0200 Subject: [PATCH 161/173] PEP 696: Update the discussions to link (#3493) The latest discussion thread is now on discourse. --- peps/pep-0696.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0696.rst b/peps/pep-0696.rst index 7e8f7f1e1..a1cfd0057 100644 --- a/peps/pep-0696.rst +++ b/peps/pep-0696.rst @@ -2,7 +2,7 @@ PEP: 696 Title: Type defaults for TypeVarLikes Author: James Hilton-Balfe <gobot1234yt@gmail.com> Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com> -Discussions-To: https://mail.python.org/archives/list/typing-sig@python.org/thread/7VWBZWXTCX6RAJO6GG67BAXUPFZ24NTC +Discussions-To: https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569 Status: Draft Type: Standards Track Topic: Typing From fb526a8822b0d33327221451c51fa7ec1d966d54 Mon Sep 17 00:00:00 2001 From: Alice <alicederyn@gmail.com> Date: Tue, 17 Oct 2023 14:53:12 +0100 Subject: [PATCH 162/173] PEP 705 Link to new discussion thread (#3492) --- peps/pep-0705.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/peps/pep-0705.rst b/peps/pep-0705.rst index 15bcfe8af..b25d2e323 100644 --- a/peps/pep-0705.rst +++ b/peps/pep-0705.rst @@ -2,7 +2,7 @@ PEP: 705 Title: TypedDict: Read-only and other keys Author: Alice Purcell <alicederyn@gmail.com> Sponsor: Pablo Galindo <pablogsal@gmail.com> -Discussions-To: https://discuss.python.org/t/pep-705-typedmapping/24827 +Discussions-To: https://discuss.python.org/t/pep-705-typeddict-read-only-and-other-keys/36457 Status: Draft Type: Standards Track Topic: Typing @@ -12,6 +12,7 @@ Python-Version: 3.13 Post-History: `30-Sep-2022 <https://mail.python.org/archives/list/typing-sig@python.org/thread/6FR6RKNUZU4UY6B6RXC2H4IAHKBU3UKV/>`__, `02-Nov-2022 <https://mail.python.org/archives/list/python-dev@python.org/thread/2P26R4VH2ZCNNNOQCBZWEM4RNF35OXOW/>`__, `14-Mar-2023 <https://discuss.python.org/t/pep-705-typedmapping/24827>`__, + `17-Oct-2023 <https://discuss.python.org/t/pep-705-typeddict-read-only-and-other-keys/36457>`__, Abstract @@ -262,8 +263,8 @@ The optional boolean ``readonly`` flag to ``TypedDict``, when ``True``, indicate The ``readonly`` flag defaults to ``False``. -``typing.ReadOnly`` flag ------------------------- +``typing.ReadOnly`` type qualifier +---------------------------------- The ``typing.ReadOnly`` type qualifier is used to indicate that a variable declared in a ``TypedDict`` definition may not be mutated by any operation performed on instances of the ``TypedDict``:: From ad131c6132f54fb5865f50592604ac6c4b84fc1e Mon Sep 17 00:00:00 2001 From: Mikhail Golubev <qsolo825@gmail.com> Date: Wed, 18 Oct 2023 09:06:41 +0300 Subject: [PATCH 163/173] PEP 698: Add "self" parameters to methods and a colon to a class (#3490) --- peps/pep-0698.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/peps/pep-0698.rst b/peps/pep-0698.rst index 9363c4493..f89a449ff 100644 --- a/peps/pep-0698.rst +++ b/peps/pep-0698.rst @@ -196,7 +196,7 @@ method or attribute in some ancestor class. return 2 @override - def baz() -> int: # Type check error: no matching signature in ancestor + def baz(self) -> int: # Type check error: no matching signature in ancestor return 1 @@ -240,7 +240,7 @@ Consider the following code: pass class Child(Parent): - def foo() -> int: + def foo(self) -> int: return 2 Imagine we refactor it as follows: @@ -248,12 +248,12 @@ Imagine we refactor it as follows: .. code-block:: python - class Parent - def foo() -> int: # This method is new + class Parent: + def foo(self) -> int: # This method is new return 1 class Child(Parent): - def foo() -> int: # This is now an override! + def foo(self) -> int: # This is now an override! return 2 def call_foo(parent: Parent) -> int: @@ -416,22 +416,22 @@ ancestor class where the overridden method should be defined: .. code-block:: python class Parent0: - def foo() -> int: + def foo(self) -> int: return 1 class Parent1: - def bar() -> int: + def bar(self) -> int: return 1 class Child(Parent0, Parent1): @override(Parent0) # okay, Parent0 defines foo - def foo() -> int: + def foo(self) -> int: return 2 @override(Parent0) # type error, Parent0 does not define bar - def bar() -> int: + def bar(self) -> int: return 2 From acecb12b9cd994dc7b643c46f5b87ecbbf65301f Mon Sep 17 00:00:00 2001 From: Alice <alicederyn@gmail.com> Date: Wed, 18 Oct 2023 20:09:45 +0100 Subject: [PATCH 164/173] PEP 705: Clean up examples in Inheritance section (#3495) Clean up examples in Inheritance section --- peps/pep-0705.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/peps/pep-0705.rst b/peps/pep-0705.rst index b25d2e323..36eb02009 100644 --- a/peps/pep-0705.rst +++ b/peps/pep-0705.rst @@ -312,20 +312,28 @@ Inheritance To avoid potential confusion, it is an error to have a read-only type extend a non-read-only type:: + class BandAndAlbum(TypedDict): + band: str + album: ReadOnly[Album] + class BandAlbumAndLabel(BandAndAlbum, readonly=True): # Runtime error label: str It is also an error to have a type without ``other_keys`` specified extend a type with ``other_keys=Never``:: - class NamedDict(TypedDict, readonly=True): + class Building(TypedDict, other_keys=Never): name: str + address: str - class Person(NamedDict): # Runtime error - age: float + class Museum(Building): # Runtime error + pass It is valid to have a non-read-only type extend a read-only one. The subclass will not be read-only, but any keys not redeclared in the subclass will remain read-only:: + class NamedDict(TypedDict, readonly=True): + name: str + class Album(NamedDict, TypedDict): year: int From 54b14ed559730e06069536d264542fa3e8687ba2 Mon Sep 17 00:00:00 2001 From: jablonskidev <36643503+jablonskidev@users.noreply.github.com> Date: Thu, 19 Oct 2023 08:00:08 -0700 Subject: [PATCH 165/173] PEP 732: The Python Documentation Editorial Board (#3489) Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> Co-authored-by: Guido van Rossum <guido@python.org> Co-authored-by: Mariatta <Mariatta@users.noreply.github.com> --- .github/CODEOWNERS | 1 + peps/pep-0732-concentric.drawio.svg | 4 + peps/pep-0732.rst | 167 ++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 peps/pep-0732-concentric.drawio.svg create mode 100644 peps/pep-0732.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 25e077ef2..8d6ba1744 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -609,6 +609,7 @@ peps/pep-0727.rst @JelleZijlstra peps/pep-0729.rst @JelleZijlstra @hauntsaninja peps/pep-0730.rst @ned-deily peps/pep-0731.rst @gvanrossum @encukou @vstinner @zooba @iritkatriel +peps/pep-0732.rst @Mariatta # ... # peps/pep-0754.rst # ... diff --git a/peps/pep-0732-concentric.drawio.svg b/peps/pep-0732-concentric.drawio.svg new file mode 100644 index 000000000..02677c5ee --- /dev/null +++ b/peps/pep-0732-concentric.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="361px" height="141px" viewBox="-0.5 -0.5 361 141" content="<mxfile host="app.diagrams.net" modified="2023-10-12T09:46:51.576Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/118.0" etag="h6adg471QBkqzw671lY0" version="22.0.4" type="github"> <diagram name="Page-1" id="kZtS35ugGwuJtex959gc"> <mxGraphModel dx="954" dy="617" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="p-wkVVe-5KVzENaLsR-k-11" value="&lt;div align=&quot;right&quot;&gt;3 &amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;/div&gt;" style="ellipse;whiteSpace=wrap;html=1;dashed=1;dashPattern=8 8;align=right;" parent="1" vertex="1"> <mxGeometry x="230" y="30" width="140" height="140" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-2" value="2&amp;nbsp;&amp;nbsp;&amp;nbsp; " style="ellipse;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#D6B656;align=right;" parent="1" vertex="1"> <mxGeometry x="258.75" y="58.75" width="82.5" height="82.5" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-1" value="1" style="ellipse;whiteSpace=wrap;html=1;strokeColor=#D6B656;align=center;" parent="1" vertex="1"> <mxGeometry x="285" y="85" width="30" height="30" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-5" value="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1b764;" parent="1" vertex="1"> <mxGeometry x="10" y="49.5" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-7" value="2" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fdf3d0;strokeColor=#d1b764;" parent="1" vertex="1"> <mxGeometry x="10" y="90" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-12" value="3" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;dashPattern=8 8;" parent="1" vertex="1"> <mxGeometry x="10" y="130" width="20" height="20" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-13" value="World&lt;br&gt;&lt;font style=&quot;font-size: 10px;&quot;&gt;includes readers of the documentation&lt;br&gt;&lt;/font&gt;" style="text;html=1;align=left;verticalAlign=bottom;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1"> <mxGeometry x="40" y="120" width="190" height="40" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-15" value="Documentation Working Group&lt;br&gt;&lt;font style=&quot;font-size: 10px;&quot;&gt;volunteers who contribute to the docs&lt;/font&gt;" style="text;html=1;align=left;verticalAlign=bottom;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1"> <mxGeometry x="40" y="80" width="190" height="40" as="geometry" /> </mxCell> <mxCell id="p-wkVVe-5KVzENaLsR-k-16" value="Documentation Editoral Board&lt;br&gt;&lt;font style=&quot;font-size: 10px;&quot;&gt;trusted group&lt;br&gt;&lt;/font&gt;" style="text;html=1;align=left;verticalAlign=bottom;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1"> <mxGeometry x="40" y="40" width="180" height="40" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " resource="https://app.diagrams.net/#Hpradyunsg%2Fdiagrams%2Fmain%2Fdocs-pep-concentric.drawio.svg"><defs/><g><ellipse cx="290" cy="70" rx="70" ry="70" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-dasharray="8 8" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 138px; height: 1px; padding-top: 70px; margin-left: 220px;"><div style="box-sizing: border-box; font-size: 0px; text-align: right;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div align="right">3    <br /></div></div></div></div></foreignObject><text x="358" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">3    </text></switch></g><ellipse cx="290" cy="70" rx="41.25" ry="41.25" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 81px; height: 1px; padding-top: 70px; margin-left: 249px;"><div style="box-sizing: border-box; font-size: 0px; text-align: right;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">2    </div></div></div></foreignObject><text x="329" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">2    </text></switch></g><ellipse cx="290" cy="70" rx="15" ry="15" fill="rgb(255, 255, 255)" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 70px; margin-left: 276px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1</div></div></div></foreignObject><text x="290" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1</text></switch></g><rect x="0" y="19.5" width="20" height="20" fill="#ffffff" stroke="#d1b764" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 30px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1</div></div></div></foreignObject><text x="10" y="33" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1</text></switch></g><rect x="0" y="60" width="20" height="20" fill="#fdf3d0" stroke="#d1b764" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 70px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">2</div></div></div></foreignObject><text x="10" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">2</text></switch></g><rect x="0" y="100" width="20" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-dasharray="8 8" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 110px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">3</div></div></div></foreignObject><text x="10" y="114" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">3</text></switch></g><rect x="30" y="90" width="190" height="40" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 127px; margin-left: 32px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">World<br /><font style="font-size: 10px;">includes readers of the documentation<br /></font></div></div></div></foreignObject><text x="32" y="127" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">World...</text></switch></g><rect x="30" y="50" width="190" height="40" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 87px; margin-left: 32px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Documentation Working Group<br /><font style="font-size: 10px;">volunteers who contribute to the docs</font></div></div></div></foreignObject><text x="32" y="87" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Documentation Working Group...</text></switch></g><rect x="30" y="10" width="180" height="40" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 47px; margin-left: 32px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Documentation Editoral Board<br /><font style="font-size: 10px;">trusted group<br /></font></div></div></div></foreignObject><text x="32" y="47" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Documentation Editoral Board...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/peps/pep-0732.rst b/peps/pep-0732.rst new file mode 100644 index 000000000..0ab82d777 --- /dev/null +++ b/peps/pep-0732.rst @@ -0,0 +1,167 @@ +PEP: 732 +Title: The Python Documentation Editorial Board +Author: Joanna Jablonski +Sponsor: Mariatta Wijaya +Status: Draft +Type: Process +Topic: Governance +Created: 14-Oct-2023 + + +Abstract +======== + +This PEP: + +* Establishes the Python Documentation Editorial Board +* Proposes how the editorial board will work + +Motivation +========== + +The Steering Council approved the creation of a +`Documentation Working Group <https://github.com/python/docs-community/blame/main/docs/workgroup/workgroup_charter.rst>`_ +in March 2021. + +The purpose of the Python documentation is to serve the +present and future end users of Python. As such, the core +development community and the greater Python documentation +contributors work together to achieve this: + +.. image:: pep-0732-concentric.drawio.svg + :class: invert-in-dark-mode + + +Specification +============= + +Mandate +------- + +The editorial board will: + +* Ensure processes are in place to maintain and improve the quality of Python's documentation +* Foster Python documentation as a community resource to serve the current and future users +* Act in alignment with the `Python Software Foundation mission + <https://www.python.org/psf/mission/>`_, which is to advance the Python + programming language, and to support and facilitate the growth of a diverse + and international community of Python programmers +* Ensure that contributing to documentation is accessible, inclusive, and sustainable +* Establish appropriate decision-making processes for documentation content +* Seek to achieve consensus among contributors prior to making decisions +* Be the final arbiter for documentation content decisions + +Responsiblities +--------------- + +The board has authority to make decisions about Python’s +documentation, as scoped below. For example, it can: + +* Set big-picture strategy for Python’s documentation +* Set the intended structure for documentation +* Make style and editorial decisions for both writing and design +* Handle documentation governance (for example, delegation of decision-making + to subject-matter experts, resolution of disagreements, decisions.) + +Scope +----- + +The Editorial board oversees the content and strategy for the following: + +.. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - In scope + - Not in scope + * - CPython documentation (docs.python.org) + - Code comments in CPython codebase + * - CPython devguide (devguide.python.org) + - CPython docstrings + * - Translations of CPython docs + - PEPs (peps.python.org) + * - + - PyPA documentation + * - + - www.python.org + +Composition +~~~~~~~~~~~ + +The Python Documentation Editorial Board is composed of five members. + +Editorial Board Members +~~~~~~~~~~~~~~~~~~~~~~~ + +The initial Editorial Board members are: + +* Mariatta Wijaya +* Ned Batchelder +* Joanna Jablonski +* Guido van Rossum +* Carol Willing + +Editorial Board Member Qualifications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Editorial board members should have: + +* A good grasp of the philosophy of the Python project +* A background in Python education and developer-facing documentation +* A solid track record of being constructive and helpful +* A history of making significant contributions to Python +* A willingness to dedicate time to improving Python's docs + +Members of the Editorial Board should have experience in education, +communication, technical writing, Python’s documentation, accessibility, +translation, or community management. + +Term +~~~~ + +Editorial Board members serve for an indefinite term, though it is +generally expected that there will be changes in Editorial Board +composition each year. Editorial Board members will confirm annually +whether they wish to continue as a board member. Members may resign +at any time. + +If a board member drops out of touch and cannot be contacted for a +month or longer, then the rest of the board may vote to replace them. + +Changes to the Editorial Board's Size +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Annually after each major Python release, the Editorial Board will +review whether the board's size should change. This provides +flexibility if the needs of the documentation community change +over time. A simple majority is needed to make a decision to +increase the board's size where quorum is 80% of the current board. + +As the sponsoring organization of the Documentation Editorial +Board, the Steering Council may change the number of members of +the Board at any time, including appointing new members or +dismissing existing members. + +Vacancies +~~~~~~~~~ + +If a vacancy exists on the board for any reason, the Documentation +Editorial Board will publicly announce a call for prospective +board members. Prospective board members would submit a brief +document stating qualifications and their motivation to serve. +The sitting members of the Editorial Board will select new board +members by a simple majority where quorum is 80% of the current board. + +Amendments +========== + +This PEP serves as a charter for the Docs Editorial Board. Changes +to its operation can be made either through a new PEP or through +a change to this PEP. In either case, the change would be decided +upon by the Steering Council after discussion in the community. + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From afd253e6b1a1f114027b11b495c7f79968245e20 Mon Sep 17 00:00:00 2001 From: Julien Palard <julien@palard.fr> Date: Fri, 20 Oct 2023 14:14:42 +0200 Subject: [PATCH 166/173] PEP 101: Docs: Less steps to update versions. (#3494) --- peps/pep-0101.rst | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/peps/pep-0101.rst b/peps/pep-0101.rst index e84a68679..664c90a04 100644 --- a/peps/pep-0101.rst +++ b/peps/pep-0101.rst @@ -293,14 +293,6 @@ to perform some manual editing steps. release tag in the repo is signed with your gpg key. When prompted choose the private key you use for signing release tarballs etc. -- For a **new branch** release, add it to the ``VERSIONS`` list of - `docsbuild scripts`_, so that the new maintenance branch is now - ``pre-release`` and add the new ``in development`` version. - -- For a **final** major release, update the ``VERSIONS`` list of - `docsbuild scripts`_: the release branch must be changed from - ``pre-release`` to ``stable``. - - For **begin security-only mode** and **end-of-life** releases, review the two files and update the versions accordingly in all active branches. @@ -425,15 +417,10 @@ to perform some manual editing steps. - If this is a **final** or rc release (even a maintenance release), also unpack the HTML docs to ``/srv/docs.python.org/release/3.X.Y[rcA]`` on docs.nyc1.psf.io. Make sure the files are in group ``docs`` and are - group-writeable. If it is a release of a security-fix-only version, - tell the DE to start a build (``security-fixes`` and ``EOL`` version - are not built daily). + group-writeable. - Let the DE check if the docs are built and work all right. - - If this is a **final** major release: Tell the DE to adapt redirects for - docs.python.org/3.X in the nginx config for docs.python.org. - - Note both the documentation and downloads are behind a caching CDN. If you change archives after downloading them through the website, you'll need to purge the stale data in the CDN like this:: @@ -798,9 +785,6 @@ with RevSys.) - Ensure buildbots are defined for the new branch (contact Łukasz or Zach Ware). - - Ensure the daily docs build scripts are updated to include - the new branch (contact DE). - - Ensure the various GitHub bots are updated, as needed, for the new branch, in particular, make sure backporting to the new branch works (contact core-workflow team) @@ -848,16 +832,6 @@ else does them. Some of those tasks include: - Optionally making a final release to publish any remaining unreleased changes. -- Update the ``VERSIONS`` list of `docsbuild scripts`_: change the - version state to ``EOL``. - -- On the docs download server (docs.nyc1.psf.io), ensure the top-level - symlink points to the upload of unpacked html docs from final release:: - - cd /srv/docs.python.org - ls -l 3.3 - lrwxrwxrwx 1 nad docs 13 Sep 6 21:38 3.3 -> release/3.3.7 - - Freeze the state of the release branch by creating a tag of its current HEAD and then deleting the branch from the cpython repo. The current HEAD should be at or beyond the final security release for the branch:: @@ -948,9 +922,6 @@ Copyright This document has been placed in the public domain. -.. _docsbuild scripts: - https://github.com/python/docsbuild-scripts/blob/main/build_docs.py - .. Local Variables: mode: indented-text From 7e39ae246b2984311b2faff972ad50cc099c75a9 Mon Sep 17 00:00:00 2001 From: Paul Moore <p.f.moore@gmail.com> Date: Sat, 21 Oct 2023 11:30:17 +0100 Subject: [PATCH 167/173] PEP 722: Mark as rejected (#3499) --- peps/pep-0722.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peps/pep-0722.rst b/peps/pep-0722.rst index 56599d99a..9d4213027 100644 --- a/peps/pep-0722.rst +++ b/peps/pep-0722.rst @@ -3,12 +3,13 @@ Title: Dependency specification for single-file scripts Author: Paul Moore <p.f.moore@gmail.com> PEP-Delegate: Brett Cannon <brett@python.org> Discussions-To: https://discuss.python.org/t/29905 -Status: Draft +Status: Rejected Type: Standards Track Topic: Packaging Content-Type: text/x-rst Created: 19-Jul-2023 Post-History: `19-Jul-2023 <https://discuss.python.org/t/29905>`__ +Resolution: https://discuss.python.org/t/pep-722-723-decision/36763/ Abstract From 5a230ee5c93eaa970c33eb005988b5a645f7aa50 Mon Sep 17 00:00:00 2001 From: amak <64077+amak@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:28:26 +0100 Subject: [PATCH 168/173] PEP 3333: Fix a TypeError in the example CGI Driver code (#3497) --- peps/pep-3333.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-3333.rst b/peps/pep-3333.rst index 4ec70d84f..1803b28b9 100644 --- a/peps/pep-3333.rst +++ b/peps/pep-3333.rst @@ -348,7 +348,7 @@ server. if data: # don't send headers until body appears write(data) if not headers_sent: - write('') # send headers now if body was empty + write(b'') # send headers now if body was empty finally: if hasattr(result, 'close'): result.close() From fab61d6a3bb50db8e803a85a93a20074c938588d Mon Sep 17 00:00:00 2001 From: Ee Durbin <ewdurbin@gmail.com> Date: Mon, 23 Oct 2023 15:28:56 -0400 Subject: [PATCH 169/173] PEP 8105: 2024 Term Steering Council Election - Initial (#3508) --- peps/pep-8105.rst | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 peps/pep-8105.rst diff --git a/peps/pep-8105.rst b/peps/pep-8105.rst new file mode 100644 index 000000000..951eb901e --- /dev/null +++ b/peps/pep-8105.rst @@ -0,0 +1,165 @@ +PEP: 8105 +Title: 2024 Term Steering Council election +Author: Ee Durbin <ee@python.org> +Sponsor: Thomas Wouters <thomas@python.org> +Status: Active +Type: Informational +Topic: Governance +Content-Type: text/x-rst +Created: 23-Oct-2023 + + +Abstract +======== + +This document describes the schedule and other details of the November +2023 election for the Python steering council, as specified in +:pep:`13`. This is the steering council election for the 2024 term +(i.e. Python 3.13). + + +Election Administration +======================= + +The steering council appointed the +`Python Software Foundation <https://www.python.org/psf-landing/>`__ +Director of Infrastructure, Ee Durbin, to administer the election. + + +Schedule +======== + +There will be a two-week nomination period, followed by a two-week +vote. + +The nomination period will be: October 30, 2023 through `November 13, 2023 AoE +<https://www.timeanddate.com/worldclock/fixedtime.html?msg=Python+Steering+Council+nominations+close&iso=20231114T00&p1=3399>`_ [#note-aoe]_. + +The voting period will be: November 16, 2023 through `November 30, 2023 AoE +<https://www.timeanddate.com/worldclock/fixedtime.html?msg=Python+Steering+Council+voting+closes&iso=20231201T00&p1=3399>`_ [#note-aoe]_. + + +Candidates +========== + +Candidates must be nominated by a core team member. If the candidate +is a core team member, they may nominate themselves. + +Nominees (in alphabetical order): + +- TBD + +Withdrawn nominations: + +- None + +Voter Roll +========== + +All active Python core team members are eligible to vote. Active status +is determined as :pep:`described in PEP 13 <13#membership>` +and implemented via the software at `python/voters <https://github.com/python/voters>`_ +[#note-voters]_. + +Ballots will be distributed based on the the `Python Voter Roll +<https://github.com/python/voters/blob/master/voter-files/>`_ [#note-voters]_ +for this election. + +While this file is not public as it contains private email addresses, the +`Complete Voter Roll`_ by name will be made available when the roll is +created. + +Election Implementation +======================= + +The election will be conducted using the `Helios Voting Service +<https://heliosvoting.org>`__. + + +Configuration +------------- + +Short name: ``2024-python-steering-council`` + +Name: ``2024 Python Steering Council Election`` + +Description: ``Election for the Python steering council, as specified in PEP 13. This is steering council election for the 2024 term.`` + +type: ``Election`` + +Use voter aliases: ``[X]`` + +Randomize answer order: ``[X]`` + +Private: ``[X]`` + +Help Email Address: ``psf-election@python.org`` + +Voting starts at: ``November 16, 2023 12:00 UTC`` + +Voting ends at: ``December 1, 2023 12:00 UTC`` + +This will create an election in which: + +* Voting is not open to the public, only those on the `Voter Roll`_ may + participate. Ballots will be emailed when voting starts. +* Candidates are presented in random order, to help avoid bias. +* Voter identities and ballots are protected against cryptographic advances. + +Questions +--------- + +Question 1 +~~~~~~~~~~ + +Select between ``0`` and ``- (approval)`` answers. Result Type: ``absolute`` + +Question: ``Select candidates for the Python Steering Council`` + +Answer #1 - #N: ``Candidates from Candidates_ Section`` + + + +Results +======= + +Of NN eligible voters, MM cast ballots. + +The top five vote-getters are: + +* TBD +* TBD +* TBD +* TBD +* TBD + +No conflict of interest as defined in :pep:`13` were observed. + +The full vote counts are as follows: + ++-----------------------+----------------+ +| Candidate | Votes Received | ++=======================+================+ +| TBD | | ++-----------------------+----------------+ + +Copyright +========= + +This document has been placed in the public domain. + + +Complete Voter Roll +=================== + +Active Python core developers +----------------------------- + +.. code-block:: text + + TBD + +.. [#note-voters] This repository is private and accessible only to Python Core + Developers, administrators, and Python Software Foundation Staff as it + contains personal email addresses. +.. [#note-aoe] AoE: `Anywhere on Earth <https://www.ieee802.org/16/aoe.html>`_. From 4d14f7a1f975100b53a862d039b9a1913496a579 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee <russell@keith-magee.com> Date: Tue, 24 Oct 2023 08:19:00 +0800 Subject: [PATCH 170/173] PEP 730: Revisions and clarifications following community discussion (#3506) --- peps/pep-0730.rst | 201 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 160 insertions(+), 41 deletions(-) diff --git a/peps/pep-0730.rst b/peps/pep-0730.rst index e759aabad..50ebc9369 100644 --- a/peps/pep-0730.rst +++ b/peps/pep-0730.rst @@ -124,7 +124,7 @@ Distribution ------------ Adding iOS as a Tier 3 platform only requires adding support for compiling an -iOS-compatibile code with an unpatched CPython code checkout. It does not +iOS-compatible build from an unpatched CPython code checkout. It does not require production of officially distributed iOS artefacts for use by end-users. If/when iOS is updated to Tier 2 or 1 support, there should be a process for @@ -176,30 +176,27 @@ devices. * ``"iphonesimulator-arm64"`` for ARM64 simulators * ``"iphonesimulator-x86_64"`` for x86_64 simulators -``sys.implementation`` will also have an additional attribute - ``_simulator`` - -storing a Boolean that is ``True`` if the device running the app is a simulator. -This attribute would not exist on non-iOS platforms. - ``platform`` '''''''''''' -Platform will be used as the primary mechanism for retrieving OS and device -details. +``platform`` will be modified to support returning iOS-specific details. Most of +the values returned by the ``platform`` module will match those returned by +``os.uname()``, with the exception of: -* ``platform.system()`` - ``"iOS"`` +* ``platform.system()`` - ``"iOS"``, instead of the default ``"Darwin"`` -* ``platform.node()`` - the user-provided name of the device, as returned by the - ``[[UIDevice currentDevice] systemName]`` system call (e.g., - ``"Janes-iPhone"``). For simulated devices, this will be the name of the - development computer running the simulator. +* ``platform.release()`` - the iOS version number, as a string (e.g., + ``"16.6.1"``), instead of the Darwin kernel version. -* ``platform.release()`` - the iOS version number, as a string (e.g., ``"16.6.1"``) +In addition, a ``platform.ios_ver()`` method will be added. This mirrors +``platform.mac_ver()``, which can be used to provide macOS version information. +``ios_ver()`` will return a namedtuple that contains the following: -* ``platform.machine()`` - The device model returned by ``[[UIDevice - currentDevice] model]`` (e.g., ``"iPhone13,2"``); or ``"iPhoneSimulator"`` for - simulated devices. - -All other values will be as returned by ``os.uname()`` +* ``release`` - the iOS version, as a string (e.g., ``"16.6.1"``). +* ``min_release`` - the minimum supported iOS version, as a string (e.g., ``"12.0"``) +* ``model`` - the model identifier of the device, as a string (e.g., ``"iPhone13,2"``). + On simulators, this will return ``"iPhoneSimulator"``. +* ``is_simulator`` - a boolean indicating if the device is a simulator. ``os`` '''''' @@ -211,11 +208,14 @@ result in the following values: * ``release`` - The Darwin kernel version (e.g., ``"22.6.0"``) +This approach treats the ``os`` module as a "raw" interface to system APIs, and +``platform`` as a higher-level API providing more generally useful values. + ``sysconfig`` ''''''''''''' The ``sysconfig`` module will use the minimum iOS version as part of -``sysconfig.get_platform()`` identifier (e.g., ``"iOS-12.0-iphoneos-arm64"``). +``sysconfig.get_platform()`` (e.g., ``"ios-12.0-iphoneos-arm64"``). The ``sysconfigdata_name`` and Config makefile will follow the same patterns as existing platforms (using ``sys.platform``, ``sys.implementation._multiarch`` etc.) to construct identifiers. @@ -237,41 +237,42 @@ into a Framework location. This finder will only be installed if ``sys.platform == "ios"``. This finder will convert a Python module name (e.g., ``foo.bar._whiz``) into a -unique Framework name by replacing the dots with underscores (i.e., -``foo_bar__whiz.framework``). A framework is a directory; the finder will look +unique Framework name by using the full module name as the framework name (i.e., +``foo.bar._whiz.framework``). A framework is a directory; the finder will look for ``_whiz.dylib`` in that directory. CI resources ------------ +`Anaconda <https://anaconda.com>`__ has offered to provide physical hardware to +run iOS buildbots. + GitHub Actions is able to host iOS simulators on their macOS machines, and the iOS simulator can be controlled by scripting environments. The free tier -currently only provides x86_64 macOS machines; however ARM64 runners `have -recently become available on paid plans <https://github.blog/ +currently only provides x86_64 macOS machines; however ARM64 runners `recently +became available on paid plans <https://github.blog/ 2023-10-02-introducing-the-new-apple-silicon-powered-m1-macos-larger-runner-for-github-actions/>`__. - -If GitHub Actions resources are insufficient or not viable for cost reasons, -Anaconda has offered to provide resources to support CI requirements. +However, in order to avoid exhausting macOS runner resources, a GitHub Actions +run for iOS will not be added as part of the standard CI configuration. Packaging --------- iOS will not provide a "universal" wheel format. Instead, wheels will be -provided for each ABI-arch combination. At present, no binary merging is -required. There is only one on-device architecture; and simulator binaries are -not considered to be distributable artefacts, so only one architecture is needed -to build a simulator. +provided for each ABI-arch combination. iOS wheels will use tags: -* ``iOS_12_0_iphoneos_arm64`` -* ``iOS_12_0_iphonesimulator_arm64`` -* ``iOS_12_0_iphonesimulator_x86_64`` +* ``ios_12_0_iphoneos_arm64`` +* ``ios_12_0_iphonesimulator_arm64`` +* ``ios_12_0_iphonesimulator_x86_64`` -In these tags, "12.0" is the minimum supported iOS version. The choice of -minimum supported iOS version is a decision of whoever compiles CPython for iOS. -At time of writing, iOS 12.0 exposes most significant iOS features, while -reaching near 100% of devices. +In these tags, "12.0" is the minimum supported iOS version. As with macOS, the +tag will incorporate the minimum iOS version that is selected when the wheel +is compiled; a wheel compiled with a minimum iOS version of 15.0 would use the +``ios_15_0_iphone*`` tags. At time of writing, iOS 12.0 exposes most significant +iOS features, while reaching near 100% of devices; this will be used as a floor +for iOS version matching. These wheels can include binary modules in-situ (i.e., co-located with the Python source, in the same way as wheels for a desktop platform); however, they @@ -340,15 +341,133 @@ a test suite that is executed on the iOS simulator using GitHub Actions. Rejected Ideas ============== -``sys.implementation._simulator`` availability ----------------------------------------------- +Simulator identification +------------------------ -The ``_simulator`` attribute could be provided on *all* platforms, returning -``False``. However, the attribute has no use outside of an iOS context. +Earlier versions of this PEP suggested the inclusion of +``sys.implementation._simulator`` attribute to identify when code is running on +device, or on a simulator. This was rejected due to the use of a protected name +for a public API, plus the pollution of the ``sys`` namespace with an +iOS-specific detail. + +Another proposal during discussion was to include a generic +``platform.is_emulator()`` API that could be implemented by any platform - for +example to differentiate running on x86_64 code on ARM64 hardware, or when +running in QEMU or other virtualization methods. This was rejected on the basis +that it wasn't clear what a consistent interpretation of "emulator" would be, or +how an emulator would be detected outside of the iOS case. + +The decision was made to keep this detail iOS-specific, and include it on the +``platform.ios_ver()`` API. + +GNU compiler triples +-------------------- + +``autoconf`` requires the use of a GNU compiler triple to identify build and +host platforms. However, the ``autoconf`` toolchain doesn't provide native +support for iOS simulators, so we are left with the task of working out how to +squeeze iOS hardware into GNU's naming regimen. + +This can be done (with some patching of ``config.sub``), but it leads to 2 major +sources of naming inconsistency: + +* ``arm64`` vs ``aarch64`` as an identifier of 64-bit ARM hardware; and +* What identifier is used to represent simulators. + +Apple's own tools use ``arm64`` as the architecture, but appear to be tolerant +of ``aarch64`` in some cases. The device platform is identified as ``iphoneos`` +and ``iphonesimulator``. + +Rust toolchains uses ``aarch64`` as the architecture, and use +``aarch64-apple-ios`` and ``aarch64-apple-ios-sim`` to identify the device +platform; however, they use ``x86_64-apple-ios`` to represent iOS *simulators* +on x86_64 hardware. + +The decision was made to use ``arm64-apple-ios`` and +``arm64-apple-ios-simulator`` because: + +1. The ``autoconf`` toolchain already contains support for ``ios`` as a platform + in ``config.sub``; it's only the simulator that doesn't have a representation. +2. The third part of the host triple is used as ``sys.platform``. +3. When Apple's own tools reference CPU architecture, they use ``arm64``, and the + GNU tooling usage of the architecture isn't visible outside the build process. +4. When Apple's own tools reference simulator status independent of the OS + (e.g., in the naming of Swift submodules), they use a ``-simulator`` suffix. +5. While *some* iOS packages will use Rust, *all* iOS packages will use Apple's + tooling. + +"Universal" wheel format +------------------------ + +macOS currently supports 2 CPU architectures. To aid the end-user development +experience, Python defines a "universal2" wheel format that incorporates both +x86_64 and ARM64 binaries. + +It would be conceptually possible to offer an analogous "universal" iOS wheel +format. However, this PEP does not use this approach, for 2 reasons. + +Firstly, the experience on macOS, especially in the numerical Python ecosystem, +has been that universal wheels can be exceedingly difficult to accommodate. While +native macOS libraries maintain strong multi-platform support, and Python itself +has been updated, the vast majority of upstream non-Python libraries do not +provide multi-architecture build support. As a result, compiling universal +wheels inevitably requires multiple compilation passes, and complex decisions +over how to distribute header files for different architectures. As a result of +this complexity, many popular projects (including NumPy and Pillow) do not +provide universal wheels at all, instead providing separate ARM64 and x86_64 +wheels. + +Secondly, historical experience is that iOS would require a much more fluid +"universal" definition. In the last 10 years, there have been *at least* 5 +different possible interpretations of "universal" that would apply to iOS, +including various combinations of armv6, armv7, armv7s, arm64, x86 and +x86_64 architectures, on device and simulator. If defined right now, +"universal-iOS" would likely include x86_64 and arm64 on simulator, and arm64 on +device; however, the pending deprecation of x86_64 hardware would add another +interpretation; and there may be a need to add arm64e as a new device +architecture in the future. Specifying iOS wheels as single-platform-only means +the Python core team can avoid an ongoing standardization discussion about the +updated "universal" formats. + +It also means wheel publishers are able to make per-project decisions over which +platforms are feasible to support. For example, a project may choose to drop +x86_64 support, or adopt a new architecture earlier than other parts of the +Python ecosystem. Using platform-specific wheels means this decision can be left +to individual package publishers. + +This decision comes at cost of making deployment more complicated. However, +deployment on iOS is already a complicated process that is best aided by tools. +At present, no binary merging is required, as there is only one on-device +architecture, and simulator binaries are not considered to be distributable +artefacts, so only one architecture is needed to build an app for a simulator. + +Interactive/REPL mode +--------------------- + +A traditional ``python.exe`` command line experience isn't really viable on +mobile devices, because mobile devices don't have a command line. iOS apps don't +have a stdout, stderr or stdin; and while you can redirect stdout and stderr to +the system log, there's no source for stdin that exists that doesn't also +involve building a very specific user-facing app that would be closer to an +IDLE-style IDE experience. Therefore, the decision was made to only focus on +"embedded mode" as a target for mobile distribution. Open Issues =========== +x86_64 buildbot availability +---------------------------- + +Apple no longer sells x86_64 hardware. As a result, commissioning an x86_64 +buildbot may not be possible. It is possible to run macOS binaries in x86_64 +compatibility mode on ARM64 hardware; however, this isn't ideal for testing +purposes. + +If native x86_64 Mac hardware cannot be sourced for buildbot purposes, it may be +necessary to exclude the x86_64 simulator platform in Tier 3. Given the +anticipated deprecation of x86_64 as a macOS development platform, this doesn't +pose a significant impediment to adoption or long term maintenance. + On-device testing ----------------- From 718157a661b579148cf2f78211ac83f1c758e41c Mon Sep 17 00:00:00 2001 From: Alice <Alice.Purcell.39@gmail.com> Date: Tue, 24 Oct 2023 16:32:16 +0100 Subject: [PATCH 171/173] PEP 705: Simplify and clarify proposal (#3504) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- peps/pep-0705.rst | 625 +++++++++++++++++++--------------------------- 1 file changed, 258 insertions(+), 367 deletions(-) diff --git a/peps/pep-0705.rst b/peps/pep-0705.rst index 36eb02009..31bb5e2a1 100644 --- a/peps/pep-0705.rst +++ b/peps/pep-0705.rst @@ -1,5 +1,5 @@ PEP: 705 -Title: TypedDict: Read-only and other keys +Title: TypedDict: Read-only items Author: Alice Purcell <alicederyn@gmail.com> Sponsor: Pablo Galindo <pablogsal@gmail.com> Discussions-To: https://discuss.python.org/t/pep-705-typeddict-read-only-and-other-keys/36457 @@ -20,14 +20,12 @@ Abstract :pep:`589` defines the structural type :class:`~typing.TypedDict` for dictionaries with a fixed set of keys. As ``TypedDict`` is a mutable type, it is difficult to correctly annotate methods which accept read-only parameters in a way that doesn't prevent valid inputs. -As structural subtypes can add other keys in, it is also difficult for type-checkers to safely define covariant methods like ``update``, or support type narrowing. -This PEP proposes two new ``TypedDict`` flags, ``readonly`` and ``other_keys``, plus an associated type qualifier, ``typing.ReadOnly``. +This PEP proposes a new type qualifier, ``typing.ReadOnly``, to support these usages. Motivation ========== -Representing structured data using (potentially nested) dictionaries with string keys is a common pattern in Python programs. :pep:`589` allows these values to be type checked when the exact type is known up-front, but it is hard to write read-only code that accepts more specific variants: for instance, where fields may be subtypes or restrict a union of possible types. This is an especially common issue when writing APIs for services, which may support a wide range of input structures, and typically do not need to modify their input. - +Representing structured data using (potentially nested) dictionaries with string keys is a common pattern in Python programs. :pep:`589` allows these values to be type checked when the exact type is known up-front, but it is hard to write read-only code that accepts more specific variants: for instance, where values may be subtypes or restrict a union of possible types. This is an especially common issue when writing APIs for services, which may support a wide range of input structures, and typically do not need to modify their input. Pure functions -------------- @@ -86,7 +84,7 @@ This is very repetitive, easy to get wrong, and is still missing important metho Updating nested dicts --------------------- -The structural typing of ``TypedDict`` is supposed to permit writing update functions that only constrain the types of entries they modify:: +The structural typing of ``TypedDict`` is supposed to permit writing update functions that only constrain the types of items they modify:: class HasTimestamp(TypedDict): timestamp: float @@ -118,175 +116,84 @@ However, this no longer works once you start nesting dictionaries:: d["name"] = name update_metadata_timestamp(d) # Type check error: "metadata" is not of type HasTimestamp -This looks like an error, but is simply due to the (unwanted) ability to overwrite the ``metadata`` entry held by the ``HasTimestampedMetadata`` instance with a different ``HasTimestamp`` instance, that may no longer be a ``UserAudit`` instance. +This looks like an error, but is simply due to the (unwanted) ability to overwrite the ``metadata`` item held by the ``HasTimestampedMetadata`` instance with a different ``HasTimestamp`` instance, that may no longer be a ``UserAudit`` instance. It is possible to work around this issue with generics (as of Python 3.11), but it is very complicated, requiring a type parameter for every nested dict. -Type discrimination -------------------- - -Another common idiom in JSON APIs is to discriminate between mutually exclusive choices with a single-entry dictionary, where the key on the dictionary distinguishes between choices, and constrains the associated value type:: - - class Movie(TypedDict): - name: str - director: str - - class Book(TypedDict): - name: str - author: str - - class EntertainmentMovie(TypedDict): - movie: Movie - - class EntertainmentBook(TypedDict): - book: Book - - Entertainment = EntertainmentMovie | EntertainmentBook - -Users of this pattern expect type-checkers to allow the following pattern:: - - def get_name(entertainment: Entertainment) -> str: - if "movie" in entertainment: - return entertainment["movie"]["name"] - elif "book" in entertainment: - return entertainment["book"]["name"] - else: - # Theoretically unreachable but common defensive coding - raise ValueError("Unexpected entertainment type") - -However, type-checkers will actually raise an error on this code; mypy, for instance, will complain that ``TypedDict "EntertainmentBook" has no key "movie"`` on the third line. This is because ``TypedDict`` does not prevent instances from having keys not specified in the type, and so the check ``"movie" in entertainment`` can return True for an ``EntertainmentBook``. - -Users can alternatively use a non-total ``TypedDict`` instead of a union:: - - class Entertainment(TypedDict, total=False): - movie: Movie - book: Book - -This ensures the ``get_name`` example type-checks correctly, but it no longer encodes the constraint that exactly one key must be present, meaning other valid code raises spurious type-check failures. In practice, we tend to see code using types like this either casting to the correct type, with the associated risk of mistakes, or moving the ``in`` checks to dedicated ``TypeGuard`` functions, reducing readability. - Rationale ========= -The first two motivating examples can be solved by removing the ability to update one or more of the entries in a ``TypedDict``. This does not mean the entries are immutable; a reference to the underlying dictionary could still exist with a different but compatible type in which those entries have mutator operations. As such, these are not "final" entries; using this term would risk confusion with final attributes, which are fully immutable. These entries are "readonly". +These problems can be resolved by removing the ability to update one or more of the items in a ``TypedDict``. This does not mean the items are immutable: a reference to the underlying dictionary could still exist with a different but compatible type in which those items have mutator operations. As such, these are not "final" items; using this term would risk confusion with final attributes, which are fully immutable. These items are "read-only", and we introduce a new ``typing.ReadOnly`` type qualifier for this purpose. -To support this, we propose adding a new boolean flag to ``TypedDict``, ``readonly``, which when set to True, removes all mutator operations from the type:: +The ``movie_string`` function in the first motivating example can then be typed as follows:: - from typing import NotRequired, TypedDict + from typing import NotRequired, ReadOnly, TypedDict - class Movie(TypedDict, readonly=True): - name: str - director: str + class Movie(TypedDict): + name: ReadOnly[str] + year: ReadOnly[NotRequired[int | None]] - class Book(TypedDict, readonly=True): - name: str - author: str + def movie_string(movie: Movie) -> str: + if movie.get("year") is None: + return movie["name"] + else: + return f'{movie["name"]} ({movie["year"]})' -In addition to these benefits, by flagging arguments of a function as read-only (by using a read-only ``TypedDict`` like ``Movie`` or ``Book``), it makes explicit not just to typecheckers but also to users that the function is not going to modify its inputs, which is usually a desireable property of a function interface. +A mixture of read-only and non-read-only items is permitted, allowing the second motivating example to be correctly annotated:: -A new ``typing.ReadOnly`` type qualifier allows removing the ability to mutate individual entries, permitting a mixture of readonly and mutable entries. This is necessary for supporting the second motivating example, updating nested dicts:: + class HasTimestamp(TypedDict): + timestamp: float + + class HasTimestampedMetadata(TypedDict): + metadata: ReadOnly[HasTimestamp] + + def update_metadata_timestamp(d: HasTimestampedMetadata) -> None: + d["metadata"]["timestamp"] = now() + + class Logs(HasTimestamp): + loglines: list[str] class UserAudit(TypedDict): name: str - metadata: ReadOnly[Logs] + metadata: Logs -This PEP only proposes making ``ReadOnly`` valid in a ``TypedDict``. A possible future extension would be to support it in additional contexts, such as in protocols. + def rename_user(d: UserAudit, name: str) -> None: + d["name"] = name + update_metadata_timestamp(d) # Now OK -Finally, to support type discrimination, we add a second flag to ``TypedDict``, ``other_keys``, which when set to ``typing.Never``, prevents instances from holding any key not explicitly listed in the type:: +In addition to these benefits, by flagging arguments of a function as read-only (by using a ``TypedDict`` like ``Movie`` with read-only items), it makes explicit not just to typecheckers but also to users that the function is not going to modify its inputs, which is usually a desirable property of a function interface. - class EntertainmentMovie(TypedDict, readonly=True, other_keys=Never): - movie: Movie +This PEP proposes making ``ReadOnly`` valid only in a ``TypedDict``. A possible future extension would be to support it in additional contexts, such as in protocols. - class EntertainmentBook(TypedDict, readonly=True, other_keys=Never): - book: Book - - Entertainment = EntertainmentMovie | EntertainmentBook - - def get_name(entertainment: Entertainment) -> str: - if "movie" in entertainment: - return entertainment["movie"]["name"] - elif "book" in entertainment: - return entertainment["book"]["name"] - else: - raise ValueError("Unexpected entertainment type") - -Note this is a subset of the functionality of the `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_. Specification ============= -``TypedDict`` will gain two new flags: ``other_keys`` and ``readonly``. A new ``typing.ReadOnly`` type qualifier is added. - -``other_keys`` flag -------------------- - -The optional ``other_keys`` flag to ``TypedDict`` can have the value ``typing.Never``, indicating that instances may only contain keys explicitly listed in the type:: - - class Album(TypedDict, other_keys=Never): - name: str - year: int - - class AlbumExtra(Album, TypedDict): - band: str # Runtime error - -Type-checkers may rely on this restriction:: - - def album_keys(album: Album) -> Collection[Literal['name', 'year']]: - # Type checkers may permit this, but should error if Album did not specify `other_keys=Never` - return album.keys() - -Type-checkers should prevent operations that would violate this restriction:: - - class AlbumExtra(TypedDict, other_keys=Never): - name: str - year: int - band: str - - album: AlbumExtra = { "name": "Flood", year: 1990, band: "They Might Be Giants" } - album_keys(album) # Type check error: extra key 'band' - -This PEP does not propose supporting any other values than ``other_keys=Never``. Future or concurrent PEPs may extend this flag to permit other types. - -``readonly`` flag ------------------ - -The optional boolean ``readonly`` flag to ``TypedDict``, when ``True``, indicates that no mutator operations (``__setitem__``, ``__delitem__``, ``update``, etc.) will be permitted:: - - class NamedDict(TypedDict, readonly=True): - name: str - - def get_name(d: NamedDict) -> str: - return d["name"] - - def set_name(d: NamedDict, name: str) -> None: - d["name"] = name # Type check error: cannot modify a read-only entry - -The ``readonly`` flag defaults to ``False``. +A new ``typing.ReadOnly`` type qualifier is added. ``typing.ReadOnly`` type qualifier ---------------------------------- -The ``typing.ReadOnly`` type qualifier is used to indicate that a variable declared in a ``TypedDict`` definition may not be mutated by any operation performed on instances of the ``TypedDict``:: +The ``typing.ReadOnly`` type qualifier is used to indicate that an item declared in a ``TypedDict`` definition may not be mutated (added, modified, or removed):: from typing import ReadOnly - class BandAndAlbum(TypedDict): - band: str - album: ReadOnly[Album] + class Band(TypedDict): + name: str + members: ReadOnly[list[str]] -The ``readonly`` flag is equivalent to marking all entries as ``ReadOnly[]``, guaranteeing no entries are missed by mistake. To avoid potential confusion, it is an error to use both ``readonly=True`` and ``ReadOnly[]``:: - - class Band(TypedDict, readonly=True): - name: ReadOnly[str] # Runtime error: redundant ReadOnly qualifier - members: Collection[str] + blur: Band = {"name": "blur", "members": []} + blur["name"] = "Blur" # OK: "name" is not read-only + blur["members"] = ["Damon Albarn"] # Type check error: "members" is read-only + blur["members"].append("Damon Albarn") # OK: list is mutable Alternative functional syntax ----------------------------- -The :pep:`alternative functional syntax <589#alternative-syntax>` for TypedDict also supports these features:: +The :pep:`alternative functional syntax <589#alternative-syntax>` for TypedDict also supports the new type qualifier:: - EntityBand = TypedDict('EntityBand', {'band': Band}, readonly=True, other_keys=Never) - BandAndAlbum = TypedDict(`BandAndAlbum', {'band': str, 'album': ReadOnly[Album]}) + Band = TypedDict("Band", {"name": str, "members": ReadOnly[list[str]]}) Interaction with other special types ------------------------------------ @@ -310,235 +217,138 @@ This is consistent with the behavior introduced in :pep:`655`. Inheritance ----------- -To avoid potential confusion, it is an error to have a read-only type extend a non-read-only type:: +Subclasses can redeclare read-only items as non-read-only, allowing them to be mutated:: - class BandAndAlbum(TypedDict): - band: str - album: ReadOnly[Album] + class NamedDict(TypedDict): + name: ReadOnly[str] - class BandAlbumAndLabel(BandAndAlbum, readonly=True): # Runtime error - label: str - - -It is also an error to have a type without ``other_keys`` specified extend a type with ``other_keys=Never``:: - - class Building(TypedDict, other_keys=Never): - name: str - address: str - - class Museum(Building): # Runtime error - pass - -It is valid to have a non-read-only type extend a read-only one. The subclass will not be read-only, but any keys not redeclared in the subclass will remain read-only:: - - class NamedDict(TypedDict, readonly=True): - name: str - - class Album(NamedDict, TypedDict): - year: int - - album: Album = { name: "Flood", year: 1990 } - album["year"] = 1973 # OK - album["name"] = "Dark Side Of The Moon" # Type check error: "name" is read-only - -Subclasses can redeclare read-only entries as non-read-only, allowing them to be mutated:: - - class Album(NamedDict, TypedDict): + class Album(NamedDict): name: str year: int - album: Album = { name: "Flood", year: 1990 } - album["year"] = 1973 # OK - album["name"] = "Dark Side Of The Moon" # Also OK now + album: Album = { "name": "Flood", "year": 1990 } + album["year"] = 1973 + album["name"] = "Dark Side Of The Moon" # OK: "name" is not read-only in Album -Subclasses can narrow value types of read-only entries:: +If a read-only item is not redeclared, it remains read-only:: - class AlbumCollection(TypedDict, readonly=True): - albums: Collection[Album] + class Album(NamedDict): + year: int - class RecordShop(AlbumCollection, TypedDict): + album: Album = { "name": "Flood", "year": 1990 } + album["name"] = "Dark Side Of The Moon" # Type check error: "name" is read-only in Album + +Subclasses can narrow value types of read-only items:: + + class AlbumCollection(TypedDict): + albums: ReadOnly[Collection[Album]] + + class RecordShop(AlbumCollection): name: str - albums: list[Album] + albums: ReadOnly[list[Album]] # OK: "albums" is read-only in AlbumCollection -Subclasses can also require keys that are read-only but not required in the superclass:: +Subclasses can require items that are read-only but not required in the superclass:: - class OptionalName(TypedDict, readonly=True): - name: NotRequired[str] + class OptionalName(TypedDict): + name: ReadOnly[NotRequired[str]] - class Person(OptionalName, TypedDict): - name: Required[str] + class RequiredName(OptionalName): + name: ReadOnly[Required[str]] - person: Person = {} # Type check error: "name" required + d: RequiredName = {} # Type check error: "name" required + +Subclasses can combine these rules:: + + class OptionalIdent(TypedDict): + ident: ReadOnly[NotRequired[str | int]] + + class User(OptionalIdent): + ident: str # Required, mutable, and not an int Note that these are just consequences of structural typing, but they are highlighted here as the behavior now differs from the rules specified in :pep:`589`. -Finally, subclasses can have ``other_keys=Never`` even if the superclass does not:: - - class Person(OptionalName, other_keys=Never): - name: Required[str] - Type consistency ---------------- -*This section updates the type consistency rules introduced in* :pep:`589` *to cover the new features in this PEP. In particular, any pair of types that do not use the new features will be consistent under these new rules if (and only if) they were already consistent.* - -A TypedDict type with ``other_keys=Never`` is consistent with ``Mapping[str, V]``, where ``V`` is the union of all its value types. For instance, the following type is consistent with ``Mapping[str, int | str]``:: - - class Person(TypedDict, other_keys=Never): - name: str - age: int +*This section updates the type consistency rules introduced in* :pep:`589` *to cover the new feature in this PEP. In particular, any pair of types that do not use the new feature will be consistent under these new rules if (and only if) they were already consistent.* A TypedDict type ``A`` is consistent with TypedDict ``B`` if ``A`` is structurally compatible with ``B``. This is true if and only if all of the following are satisfied: -* For each key in ``B``, ``A`` has the corresponding key and the corresponding value type in ``A`` is consistent with the value type in ``B``, unless the key in ``B`` is of type ``ReadOnly[NotRequired[Any]]``, in which case it may be missing in ``A`` provided ``A`` allows other keys. -* For each non-read-only key in ``B``, the corresponding value type in ``B`` is also consistent with the corresponding value type in ``A``. +* For each item in ``B``, ``A`` has the corresponding key, unless the item in ``B`` is read-only, not required, and of top value type (``ReadOnly[NotRequired[object]]``). +* For each item in ``B``, if ``A`` has the corresponding key, the corresponding value type in ``A`` is consistent with the value type in ``B``. +* For each non-read-only item in ``B``, its value type is consistent with the corresponding value type in ``A``. * For each required key in ``B``, the corresponding key is required in ``A``. -* For each non-read-only, non-required key in ``B``, the corresponding key is not required in ``A``. -* If ``B`` does not allow other keys, then ``A`` does not allow other keys. -* If ``B`` does not allow other keys, then for each key in ``A``, ``B`` has the corresponding key. +* For each non-required key in ``B``, if the item is not read-only in ``B``, the corresponding key is not required in ``A``. Discussion: -* All non-specified keys in a type that allows other keys are implicitly of type ``ReadOnly[NotRequired[Any]]`` (or ``ReadOnly[NotRequired[Unknown]]`` in pyright). +* All non-specified items in a TypedDict implicitly have value type ``ReadOnly[NotRequired[object]]``. -* Read-only value types behave covariantly, as they cannot be mutated. This is similar to container types such as ``Sequence``, and different from non-read-only value types, which behave invariantly. Example:: +* Read-only items behave covariantly, as they cannot be mutated. This is similar to container types such as ``Sequence``, and different from non-read-only items, which behave invariantly. Example:: - class A(TypedDict, readonly=True): - x: int | None + class A(TypedDict): + x: ReadOnly[int | None] class B(TypedDict): x: int def f(a: A) -> None: - print(a['x'] or 0) + print(a["x"] or 0) - b: B = {'x': 1} + b: B = {"x": 1} f(b) # Accepted by type checker -* A TypedDict type ``A`` with no explicit key ``'x'`` that allows other keys is not consistent with a TypedDict type with a non-required key ``'x'``, since at runtime the key ``'x'`` could be present and have an incompatible type (which may not be visible through ``A`` due to structural subtyping). The only exception to this rule is if ``'x'`` is non-required, read-only and of type ``object`` (or ``Any`` or pylance's ``Unknown``). +* A TypedDict type ``A`` with no explicit key ``'x'`` is not consistent with a TypedDict type ``B`` with a non-required key ``'x'``, since at runtime the key ``'x'`` could be present and have an incompatible type (which may not be visible through ``A`` due to structural subtyping). The only exception to this rule is if the item in ``B`` is read-only, and the value type is of top type (``object``). For example:: -* A TypedDict type ``A`` with no key ``'x'`` that does not allow other keys may be consistent with a TypedDict type with a read-only, non-required key ``'x'``. Example:: + class A(TypedDict): + x: int - class A(TypedDict, total=False, readonly=True): + class B(TypedDict): + x: int + y: ReadOnly[NotRequired[object]] + + a: A = { "x": 1 } + b: B = a # Accepted by type checker + +Update method +------------- + +In addition to existing type checking rules, type checkers should error if a TypedDict with a read-only item is updated with another TypedDict that declares that key:: + + class A(TypedDict): + x: ReadOnly[int] y: int - class B(TypedDict, other_keys=Never): - x: int + a1: A = { "x": 1, "y": 2 } + a2: A = { "x": 3, "y": 4 } + a1.update(a2) # Type check error: "x" is read-only in A - def f(a: A) -> int: - return a.get("y", 0) +Unless the declared value is of bottom type:: - def g(b: B) -> None: - b["x"] = f(b) # Accepted by type checker + class B(TypedDict): + x: NotRequired[typing.Never] + y: ReadOnly[int] -Union Operation ---------------- - -The union operation creates a new dictionary with the merged keys and values of its two operands. As such, the result should be consistent with any type that can hold the possible key-value pairs, not just types compatible with the operand types. For example:: - - class A(TypedDict, readonly=True, other_keys=Never): - x: int - - class B(TypedDict, total=False, readonly=True, other_keys=Never): - x: str - - class C(TypedDict): - x: int | str - - def union_a_b(a: A, b: B) -> C: - # Accepted by type-checker, even though C is not read-only and - # allows other keys: - return a | b - -This is different from the usual compatibility rules, where the result of an operation has a defined type which the variable it is assigned to must be consistent with. A similar situation occurs with ``TypedDict`` and ``copy()`` or ``deepcopy()``. - -If the union of two TypedDict objects of type ``A`` and ``B`` are assigned to a TypedDict of type ``C``, the type checker should verify that: - -* if ``C`` does not allow other keys, neither ``A`` nor ``B`` allow other keys -* if ``C`` does not allow other keys, it contains all keys found in either ``A`` or ``B`` -* if a key ``'x'`` is found in ``A`` and ``C``, its type in ``A`` is consistent with its type in ``C``. -* if a key ``'x'`` is found in ``B`` and ``C``, its type in ``B`` is consistent with its type in ``C``. -* if a key ``'x'`` is required in ``C``, it is required in either ``A`` or ``B``. - -Notes: - -* The read-only status of the keys does not matter. A key can be read-only on just ``A``, just ``B``, or just ``C``, or any combination. -* A key found on ``A`` or ``B`` may be missed off ``C`` if it allows other keys. Type-checkers may however choose to flag this edge-case with a warning or error in some circumstances, if it is found to be a source of mistakes. - -Update Operations ------------------ - -Previously, ``clear()`` and ``popitem()`` were rejected by type checkers on TypedDict objects, as they could remove required keys, some of which may not be directly visible because of structural subtyping. However, these methods should be allowed on TypedDicts objects with all keys non-read-only and non-required and with no other keys allowed:: - - class A(TypedDict, total=False, other_keys=Never): - x: int - y: str - - a: A = { "x": 1, "y": "foo" } - a.popitem() # Accepted by type checker - a.clear() # Accepted by type checker - -``update`` has been difficult to type correctly due to the open nature of TypedDict objects. Keys not specified on the type could still be present (and constrained) due to structural subtyping, meaning type safety could be accidentally violated. For instance:: - - class B(TypedDict, total=False): - x: int - - def update_b(b1: B, b2: B) -> None: - b1.update(b2) - - class C(B, TypedDict, total=False): - y: int - - class D(B, TypedDict, total=False): - y: str - - c: C = { "x": 1, "y": 2 } - d: D = { "x": 3, "y": "foo" } - update_b(c, d) # c is no longer a C at runtime - -Both mypy and pyright currectly permit this usage, however, as the only viable alternative has been to prevent calling ``update`` at all. - -With the addition of ``other_keys``, it becomes possible to more accurately type the update method: - -* Declare a new read-only TypedDict type that does not allow other keys -* Copy all non-read-only entries to it -* Make all entries read-only and non-required -* Union this with an iterable of matching key-value pairs - -For instance:: - - class Example(TypedDict): - a: int - b: NotRequired[str] - c: ReadOnly[int] - - class ExampleUpdateDict(TypedDict, total=False, readonly=True, other_keys=Never): - a: int - b: str - # c is not present as it is read-only in Example - - ExampleUpdateEntry = tuple[Literal["a"], int] | tuple[Literal["b"], str] - ExampleUpdate = ExampleUpdateDict | Iterable[ExampleUpdateEntry] - -Type checkers should permit any type compatible with this TypedDict to be passed into the update operation. As with :pep:`589`, they may choose to continue permitting TypedDict types that allow other keys as well, to avoid generating false positives. + def update_a(a: A, b: B) -> None: + a.update(b) # Accepted by type checker: "x" cannot be set on b Keyword argument typing ----------------------- -:pep:`692` introduced ``Unpack`` to annotate ``**kwargs`` with a ``TypedDict``. Marking one or more of the entries of a ``TypedDict`` used in this way as read-only will have no effect on the type signature of the method, since all keyword arguments are read-only by design in Python. However, it *will* prevent the entry from being modified in the body of the function:: +:pep:`692` introduced ``Unpack`` to annotate ``**kwargs`` with a ``TypedDict``. Marking one or more of the items of a ``TypedDict`` used in this way as read-only will have no effect on the type signature of the method. However, it *will* prevent the item from being modified in the body of the function:: class Args(TypedDict): key1: int key2: str - class ReadonlyArgs(TypedDict, readonly=True): - key1: int - key2: str + class ReadOnlyArgs(TypedDict): + key1: ReadOnly[int] + key2: ReadOnly[str] class Function(Protocol): def __call__(self, **kwargs: Unpack[Args]) -> None: ... - def impl(self, **kwargs: Unpack[ReadonlyArgs]) -> None: + def impl(self, **kwargs: Unpack[ReadOnlyArgs]) -> None: kwargs["key1"] = 3 # Type check error: key1 is readonly fn: Function = impl # Accepted by type checker: function signatures are identical @@ -547,14 +357,14 @@ Keyword argument typing Backwards compatibility ======================= -This PEP adds new features to ``TypedDict``, so code that inspects ``TypedDict`` types will have to change to support types using the new features. This is expected to mainly affect type-checkers. +This PEP adds a new feature to ``TypedDict``, so code that inspects ``TypedDict`` types will have to change to support types using it. This is expected to mainly affect type-checkers. Security implications ===================== There are no known security consequences arising from this PEP. -How to Teach This +How to teach this ================= Suggestion for changes to the :mod:`typing` module, in line with current practice: @@ -563,88 +373,169 @@ Suggestion for changes to the :mod:`typing` module, in line with current practic * Add ``typing.ReadOnly``, linked to TypedDict and this PEP. * Add the following text to the TypedDict entry: -By default, keys not specified in a TypedDict may still be present. Instances can be restricted to only the named keys with the ``other_keys`` flag. *insert example, perhaps using ``in`` to illustrate the benefit* +Individual items can be excluded from mutate operations using ReadOnly, allowing them to be read but not changed. This is useful when the exact type of the value is not known yet, and so modifying it would break structural subtypes. *insert example* -Individual keys can be excluded from mutate operations using ReadOnly, allowing them to be read but not changed. This is useful when the exact type of the value is not known yet, and so modifying it would break structural subtypes. *insert example* - -If all keys on a TypedDict should be read-only, the ``readonly`` flag can be used as a shorthand. *insert example* - -Reference Implementation +Reference implementation ======================== -No complete reference implementation exists yet. pyright 1.1.310 ships with a partial implementation of the ReadOnly qualifier. +pyright 1.1.332 fully implements this proposal. -Rejected Alternatives +Rejected alternatives ===================== A TypedMapping protocol type ---------------------------- -An earlier version of :pep:`705` proposed a ``TypedMapping`` protocol type, behaving much like a read-only TypedDict but without the constraint that the runtime type be a ``dict``. The behavior described in the current version of this PEP could then be obtained by inheriting a TypedDict from a TypedMapping. This has been set aside for now as more complex, without a strong use-case motivating the additional complexity. +An earlier version of this PEP proposed a ``TypedMapping`` protocol type, behaving much like a read-only TypedDict but without the constraint that the runtime type be a ``dict``. The behavior described in the current version of this PEP could then be obtained by inheriting a TypedDict from a TypedMapping. This has been set aside for now as more complex, without a strong use-case motivating the additional complexity. -A higher-order Readonly type +A higher-order ReadOnly type ---------------------------- -A generalized higher-order type could be added that removes mutator methods from its parameter, e.g. ``ReadOnly[MovieRecord]``. For a TypedDict, this would be like adding ``readonly=True`` to the declaration. This would naturally want to be defined for a wider set of types than just TypedDict subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower. +A generalized higher-order type could be added that removes mutator methods from its parameter, e.g. ``ReadOnly[MovieRecord]``. For a TypedDict, this would be like adding ``ReadOnly`` to every item, including those declared in superclasses. This would naturally want to be defined for a wider set of types than just TypedDict subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower. -Preventing other keys with the typing.final decorator ------------------------------------------------------ +Calling the type ``Readonly`` +----------------------------- -Instead of adding an ``other_keys`` flag to TypedDict, treat classes decorated with :func:`~typing.final` as disallowing other keys. This makes intuitive sense for TypedDict as it stands now: preventing adding any other keys guarantees no other types will be structurally compatible, so it is effectively final. There is also partial support for this idiom in mypy and pyright, which both use it as a way to achieve type discrimination. However, if any keys are read-only, preventing adding any other keys does **not** make the type final any more, so using the decorator this way seems incorrect. For example:: +``Read-only`` is generally hyphenated, and it appears to be common convention to put initial caps onto words separated by a dash when converting to CamelCase. This appears consistent with the definition of CamelCase on Wikipedia: CamelCase uppercases the first letter of each word. That said, Python examples or counter-examples, ideally from the core Python libraries, or better explicit guidance on the convention, would be greatly appreciated. - class Foo: ... - class Bar(Foo): ... +A readonly flag +--------------- + +Earlier versions of this PEP introduced a boolean flag that would ensure all items in a TypedDict were read-only:: + + class Movie(TypedDict, readonly=True): + name: str + year: NotRequired[int | None] + + movie: Movie = { "name": "A Clockwork Orange" } + movie["year"] = 1971 # Type check error: "year" is read-only + +However, this led to confusion when inheritance was introduced:: + + class A(TypedDict): + key1: int + + class B(A, TypedDict, readonly=True): + key2: int + + b: B = { "key1": 1, "key2": 2 } + b["key1"] = 4 # Accepted by type checker: "key1" is not read-only + +It would be reasonable for someone familiar with ``frozen``, on seeing just the definition of B, to assume that the whole type was read-only. On the other hand, it would be reasonable for someone familiar with ``total`` to assume that read-only only applies to the current type. + +The original proposal attempted to eliminate this ambiguity by making it both a type check and a runtime error to define ``B`` in this way. This was still a source of surprise to people expecting it to work like ``total``. + +Given that no extra types could be expressed with the ``readonly`` flag, it has been removed from the proposal to avoid ambiguity and surprise. + +Supporting type-checked removal of read-only qualifier via copy and other methods +--------------------------------------------------------------------------------- + +An earlier version of this PEP mandated that code like the following be supported by type-checkers:: + + class A(TypedDict): + x: ReadOnly[int] + + class B(TypedDict): + x: ReadOnly[str] + + class C(TypedDict): + x: int | str + + def copy_and_modify(a: A) -> C: + c: C = copy.copy(a) + if not c['x']: + c['x'] = "N/A" + return c + + def merge_and_modify(a: A, b: B) -> C: + c: C = a | b + if not c['x']: + c['x'] = "N/A" + return c + +However, there is currently no way to express this in the typeshed, meaning type-checkers would be forced to special-case these functions. There is already a way to code these operations that mypy and pyright do support, though arguably this is less readable:: + + copied: C = { **a } + merged: C = { **a, **b } + +While not as flexible as would be ideal, the current typeshed stubs are sound, and remain so if this PEP is accepted. Updating the typeshed would require new typing features, like a type constructor to express the type resulting from merging two or more dicts, and a type qualifier to indicate a returned value is not shared (so may have type constraints like read-only and invariance of generics loosened in specific ways), plus details of how type-checkers would be expected to interpret these features. These could be valuable additions to the language, but are outside the scope of this PEP. + +Given this, we have deferred any update of the typeshed stubs. + +Preventing unspecified keys in TypedDicts +----------------------------------------- + +Consider the following "type discrimination" code:: + + class A(TypedDict): + foo: int + + class B(TypedDict): + bar: int + + def get_field(d: A | B) -> int: + if "foo" in d: + return d["foo"] # !!! + else: + return d["bar"] + +This is a common idiom, and other languages like Typescript allow it. Technically, however, this code is unsound: ``B`` does not declare ``foo``, but instances of ``B`` may still have the key present, and the associated value may be of any type:: + + class C(TypedDict): + foo: str + bar: int + + c: C = { "foo": "hi", "bar" 3 } + b: B = c # OK: C is structurally compatible with B + v = get_field(b) # Returns a string at runtime, not an int! + +mypy rejects the definition of ``get_field`` on the marked line with the error ``TypedDict "B" has no key "foo"``, which is a rather confusing error message, but is caused by this unsoundness. + +One option for correcting this would be to explicitly prevent ``B`` from holding a ``foo``:: + + class B(TypedDict): + foo: NotRequired[Never] + bar: int + + b: B = c # Type check error: key "foo" not allowed in B + +However, this requires every possible key that might be used to discriminate on to be explicitly declared in every type, which is not generally feasible. A better option would be to have a way of preventing all unspecified keys from being included in ``B``. mypy supports this using the ``@final`` decorator from :pep:`591`:: @final - class FooHolder(TypedDict, readonly=True): - item: Foo + class B(TypedDict): + bar: int + +The reasoning here is that this prevents ``C`` or any other type from being considered a "subclass" of ``B``, so instances of ``B`` can now be relied on to never hold the key ``foo``, even though it is not explicitly declared to be of bottom type. + +With the introduction of read-only items, however, this reasoning would imply type-checkers should ban the following:: @final - class BarHolder(FooHolder, readonly=True): - item: Bar + class D(TypedDict): + field: ReadOnly[Collection[str]] -Extending a ``TypedDict`` to refine the types is a reasonable feature, but the above code looks like it should raise a runtime error. Should ``@final`` be modified to allow inheritance? Should users be prevented from using this pattern? + @final + class E(TypedDict): + field: list[str] -More context for this can be found on `pyright issue 5254 <https://github.com/microsoft/pyright/issues/5254>`_. + e: E = { "field": ["value1", "value2"] } + d: D = e # Error? -We recommend type checkers treat decorating a TypedDict type with final as identical to setting ``other_keys=Never``, if they continue to support the idiom for backwards compatibility, but reject any use of final on a TypedDict with read-only keys. Once ``other_keys`` is adopted, they may also wish to deprecate use of final on TypedDicts entirely. +The conceptual problem here is that TypedDicts are structural types: they cannot really be subclassed. As such, using ``@final`` on them is not well-defined; it is certainly not mentioned in :pep:`591`. -Using different casing for ``readonly`` keyword or ``ReadOnly`` type --------------------------------------------------------------------- +An earlier version of this PEP proposed resolving this by adding a new flag to ``TypedDict`` that would explicitly prevent other keys from being used, but not other kinds of structural compatibility:: -It appears to be common convention to put an initial caps onto words separated by a dash when converting to CamelCase, but to drop the dash completely when converting to snake_case. Django uses ``readonly``, for instance. This appears consistent with the definition of both on Wikipedia: snake_case replaces spaces with dashes, while CamelCase uppercases the first letter of each word. That said, more examples or counterexamples, ideally from the core Python libraries, or better explicit guidance on the convention, would be greatly appreciated. + class B(TypedDict, other_keys=Never): + bar: int -Mandate unsound type narrowing ------------------------------- + b: B = c # Type check error: key "foo" not allowed in B -The main use-case we are aware of for ``other_keys=Never`` (and the current workaround of final-decorated TypedDict types) is to simplify type discrimination, as shown in the motivation section. +However, during the process of drafting, the situation changed: -By comparison, TypeScript handles this edge-case by ignoring the possibility of instances of one type in the union having undeclared keys. If a variable is known to be of type ``A | B`` and an ``in`` check is done using a key not explicitly declared on ``B``, it is assumed no instance of ``B`` will pass that check. While technically unsound, this a common enough idiom that it could fall under the recommendation in :pep:`589` that "potentially unsafe operations may be accepted if the alternative is to generate false positive errors for idiomatic code". +* pyright, which previously worked similarly to mypy in this type discrimination case, `changed to allow the original example without error <https://github.com/microsoft/pyright/commit/6a25a7bf0b5cb3721a06d0e0d6245b2ebfbf053b>`_, despite the unsoundness, due to it being a common idiom +* mypy has `an open issue <https://github.com/python/mypy/issues/15697>`_ to follow the lead of pyright and Typescript and permit the idiom as well +* a `draft of PEP-728 <https://github.com/python/peps/pull/3441>`_ was created that is a superset of the ``other_keys`` functionality -This user request has been rejected multiple times by type checkers, however, suggesting the community prefers strict type-safety over idiomatic code here. - -Make the ``other_keys`` flag a boolean --------------------------------------- - -Since ``other_keys`` can only effectively take two values, ``Never`` or absent, it was originally proposed as a boolean flag, with ``other_keys=False`` equivalent to the current ``other_keys=Never``. However, the `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_ provides equivalent functionality when restricting other types to ``Never``, so this proposal was updated to use comparable syntax, to make it clearer how the proposals intersect. - -Use a reserved ``__extra__`` key --------------------------------- - -The `unmerged proposal of PEP-728 <https://github.com/python/peps/pull/3441>`_ proposes different syntax for disallowing other keys:: - - class EntertainmentMovie(TypedDict, readonly=True): - movie: Movie - __extra__: Never - -This new key does not function like other keys -- for instance, it is implicitly ``NotRequired`` but cannot be explicitly marked as such. The author of this PEP prefers the asymmetry of using a keyword argument to set expectations that it does not behave like other key declarations, and others have provided similar feedback on the PR. - -However, this PEP will be updated to match whatever syntax the PEP-728 author decides to go with. - -Leave other_keys to PEP-728 ---------------------------- - -This PEP could drop the ``other_keys`` proposal entirely rather than propose a limited subset of it. However, as this PEP affects the unofficial status-quo of using final to disallow other keys, it seems important to both highlight that issue and propose a solution. +As such, there is less urgency to address this issue in this PEP, and it has been deferred to PEP-728. Copyright From 8df0448eca27ecb8ad74051b8c0bc55e0573def5 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <hugovk@users.noreply.github.com> Date: Wed, 25 Oct 2023 09:16:43 +0300 Subject: [PATCH 172/173] PEP 732: Add Discussions-To and Post-History, fix typo (#3509) --- peps/pep-0732.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/peps/pep-0732.rst b/peps/pep-0732.rst index 0ab82d777..a1ab7868f 100644 --- a/peps/pep-0732.rst +++ b/peps/pep-0732.rst @@ -2,10 +2,12 @@ PEP: 732 Title: The Python Documentation Editorial Board Author: Joanna Jablonski Sponsor: Mariatta Wijaya +Discussions-To: https://discuss.python.org/t/pep-732-the-python-documentation-editorial-board/36710 Status: Draft Type: Process Topic: Governance Created: 14-Oct-2023 +Post-History: `20-Oct-2023 <https://discuss.python.org/t/pep-732-the-python-documentation-editorial-board/36710>`__ Abstract @@ -51,8 +53,8 @@ The editorial board will: * Seek to achieve consensus among contributors prior to making decisions * Be the final arbiter for documentation content decisions -Responsiblities ---------------- +Responsibilities +---------------- The board has authority to make decisions about Python’s documentation, as scoped below. For example, it can: From 4e4ea9196ad5e51817396071e3cdfad03573fc81 Mon Sep 17 00:00:00 2001 From: Philipp A <flying-sheep@web.de> Date: Thu, 26 Oct 2023 11:35:14 +0200 Subject: [PATCH 173/173] PEP 536: Mark as Withdrawn (#3510) Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> --- peps/pep-0536.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/peps/pep-0536.rst b/peps/pep-0536.rst index f4a6ba3c6..77aba14f2 100644 --- a/peps/pep-0536.rst +++ b/peps/pep-0536.rst @@ -3,12 +3,15 @@ Title: Final Grammar for Literal String Interpolation Version: $Revision$ Last-Modified: $Date$ Author: Philipp Angerer <phil.angerer@gmail.com> -Status: Deferred +Status: Withdrawn Type: Standards Track Content-Type: text/x-rst Created: 11-Dec-2016 Python-Version: 3.7 -Post-History: 12-Dec-2016 +Post-History: `18-Aug-2016 <https://mail.python.org/archives/list/python-ideas@python.org/thread/FOYKXOFWEINPVQSK2XGEHKXSTEVO5WWA/>`__, + `23-Dec-2016 <https://mail.python.org/archives/list/python-ideas@python.org/thread/YKKEA5NIMMKHZTMRE5UFHST4WQ4NN3XJ/>`__, + `15-Mar-2019 <https://mail.python.org/archives/list/python-dev@python.org/thread/N43O4KNLZW4U7YZC4NVPCETZIVRDUVU2/>`__ +Resolution: https://discuss.python.org/t/pep-536-should-be-marked-as-rejected/35226/4 Abstract ======== @@ -21,10 +24,11 @@ those restrictions, promoting “f-strings” to “f expressions” or f-litera This PEP expands upon the f-strings introduced by :pep:`498`, so this text requires familiarity with :pep:`498`. -PEP Status -========== +PEP Withdrawal +============== -This PEP is deferred until an implementation is available. +This PEP has been withdrawn in favour of :pep:`701`. +:pep:`701` addresses all important points of this PEP. Terminology