Skip to content

Commit 78cf096

Browse files
authored
Merge branch 'main' into packaging-governance
2 parents 0a65207 + 5e0935a commit 78cf096

File tree

596 files changed

+1371
-4640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

596 files changed

+1371
-4640
lines changed

.github/CODEOWNERS

+2
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ peps/pep-0760.rst @pablogsal @brettcannon
642642
peps/pep-0761.rst @sethmlarson @hugovk
643643
peps/pep-0762.rst @pablogsal @ambv @lysnikolaou @emilyemorehouse
644644
peps/pep-0763.rst @dstufft
645+
peps/pep-0764.rst @JelleZijlstra
645646
peps/pep-0765.rst @iritkatriel @ncoghlan
646647
peps/pep-0766.rst @warsaw
647648
peps/pep-0767.rst @carljm
@@ -651,6 +652,7 @@ peps/pep-0770.rst @sethmlarson @brettcannon
651652
peps/pep-0771.rst @pradyunsg
652653
peps/pep-0772.rst @warsaw @pradyunsg
653654
peps/pep-0773.rst @zooba
655+
peps/pep-0774.rst @savannahostrowski
654656
# ...
655657
peps/pep-0777.rst @warsaw
656658
# ...

.github/PULL_REQUEST_TEMPLATE/Mark a PEP Final.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ If you're unsure about something, just leave it blank and we'll take a look.
99
* [ ] Any substantial changes since the accepted version approved by the SC/PEP delegate
1010
* [ ] Pull request title in appropriate format (``PEP 123: Mark Final``)
1111
* [ ] ``Status`` changed to ``Final`` (and ``Python-Version`` is correct)
12-
* [ ] Canonical docs/spec linked with a ``canonical-doc`` directive
12+
* [ ] Canonical docs/spec linked with a ``canonical-doc`` directive
1313
(or ``canonical-pypa-spec`` for packaging PEPs,
1414
or ``canonical-typing-spec`` for typing PEPs)

.pre-commit-config.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ repos:
1414
- repo: https://github.com/pre-commit/pre-commit-hooks
1515
rev: v5.0.0
1616
hooks:
17+
- id: end-of-file-fixer
18+
name: "Ensure files end with a single newline"
1719
- id: mixed-line-ending
1820
name: "Normalize mixed line endings"
1921
args: [--fix=lf]
22+
- id: trailing-whitespace
23+
name: "Remove trailing whitespace"
24+
2025
- id: file-contents-sorter
2126
name: "Sort codespell ignore list"
2227
files: '.codespell/ignore-words.txt'

check-peps.py

+6-16
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,13 @@
3939
ALL_HEADERS = (
4040
"PEP",
4141
"Title",
42-
"Version",
43-
"Last-Modified",
4442
"Author",
4543
"Sponsor",
4644
"BDFL-Delegate", "PEP-Delegate",
4745
"Discussions-To",
4846
"Status",
4947
"Type",
5048
"Topic",
51-
"Content-Type",
5249
"Requires",
5350
"Created",
5451
"Python-Version",
@@ -132,16 +129,18 @@ def check_headers(lines: Sequence[str], /) -> MessageIterator:
132129
yield from _validate_pep_number(next(iter(lines), ""))
133130

134131
found_headers = {}
132+
found_header_lines: list[tuple[str, int]] = []
135133
line_num = 0
136134
for line_num, line in enumerate(lines, start=1):
137135
if line.strip() == "":
138136
headers_end_line_num = line_num
139137
break
140138
if match := HEADER_PATTERN.match(line):
141139
header = match[1]
140+
found_header_lines.append((header, line_num))
142141
if header in ALL_HEADERS:
143142
if header not in found_headers:
144-
found_headers[match[1]] = line_num
143+
found_headers[header] = None
145144
else:
146145
yield line_num, f"Must not have duplicate header: {header} "
147146
else:
@@ -151,11 +150,11 @@ def check_headers(lines: Sequence[str], /) -> MessageIterator:
151150

152151
yield from _validate_required_headers(found_headers.keys())
153152

154-
shifted_line_nums = list(found_headers.values())[1:]
155-
for i, (header, line_num) in enumerate(found_headers.items()):
153+
shifted_line_nums = [line for _, line in found_header_lines[1:]]
154+
for i, (header, line_num) in enumerate(found_header_lines):
156155
start = line_num - 1
157156
end = headers_end_line_num - 1
158-
if i < len(found_headers) - 1:
157+
if i < len(found_header_lines) - 1:
159158
end = shifted_line_nums[i] - 1
160159
remainder = "\n".join(lines[start:end]).removeprefix(f"{header}:")
161160
if remainder != "":
@@ -182,8 +181,6 @@ def _validate_header(header: str, line_num: int, content: str) -> MessageIterato
182181
yield from _validate_type(line_num, content)
183182
elif header == "Topic":
184183
yield from _validate_topic(line_num, content)
185-
elif header == "Content-Type":
186-
yield from _validate_content_type(line_num, content)
187184
elif header in {"Requires", "Replaces", "Superseded-By"}:
188185
yield from _validate_pep_references(line_num, content)
189186
elif header == "Created":
@@ -348,13 +345,6 @@ def _validate_topic(line_num: int, line: str) -> MessageIterator:
348345
yield line_num, "Topic must be sorted lexicographically"
349346

350347

351-
def _validate_content_type(line_num: int, line: str) -> MessageIterator:
352-
"""'Content-Type' must be 'text/x-rst'"""
353-
354-
if line != "text/x-rst":
355-
yield line_num, "Content-Type must be 'text/x-rst'"
356-
357-
358348
def _validate_pep_references(line_num: int, line: str) -> MessageIterator:
359349
"""`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs"""
360350

pep_sphinx_extensions/pep_zero_generator/parser.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import dataclasses
6+
from collections.abc import Iterable, Sequence
67
from email.parser import HeaderParser
78
from pathlib import Path
89

@@ -121,6 +122,11 @@ def __lt__(self, other: PEP) -> bool:
121122
def __eq__(self, other):
122123
return self.number == other.number
123124

125+
@property
126+
def _author_names(self) -> Iterable[str]:
127+
"""An iterator of the authors' full names."""
128+
return (author.full_name for author in self.authors)
129+
124130
@property
125131
def shorthand(self) -> str:
126132
"""Return reStructuredText tooltip for the PEP type and status."""
@@ -138,19 +144,19 @@ def details(self) -> dict[str, str | int]:
138144
"title": self.title,
139145
# a tooltip representing the type and status
140146
"shorthand": self.shorthand,
141-
# the author list as a comma-separated with only last names
142-
"authors": ", ".join(author.full_name for author in self.authors),
147+
# the comma-separated list of authors
148+
"authors": ", ".join(self._author_names),
143149
# The targeted Python-Version (if present) or the empty string
144150
"python_version": self.python_version or "",
145151
}
146152

147153
@property
148-
def full_details(self) -> dict[str, str | int]:
154+
def full_details(self) -> dict[str, str | int | Sequence[str]]:
149155
"""Returns all headers of the PEP as a dict."""
150156
return {
151157
"number": self.number,
152158
"title": self.title,
153-
"authors": ", ".join(author.full_name for author in self.authors),
159+
"authors": ", ".join(self._author_names),
154160
"discussions_to": self.discussions_to,
155161
"status": self.status,
156162
"type": self.pep_type,
@@ -162,6 +168,8 @@ def full_details(self) -> dict[str, str | int]:
162168
"requires": self.requires,
163169
"replaces": self.replaces,
164170
"superseded_by": self.superseded_by,
171+
# extra non-header keys for use in ``peps.json``
172+
"author_names": tuple(self._author_names),
165173
"url": f"https://peps.python.org/pep-{self.number:0>4}/",
166174
}
167175

pep_sphinx_extensions/tests/pep_lint/test_headers.py

-24
Original file line numberDiff line numberDiff line change
@@ -253,30 +253,6 @@ def test_validate_topic(line: str, expected_warnings: set):
253253
assert found_warnings == expected_warnings
254254

255255

256-
def test_validate_content_type_valid():
257-
warnings = [
258-
warning for (_, warning) in check_peps._validate_content_type(1, "text/x-rst")
259-
]
260-
assert warnings == [], warnings
261-
262-
263-
@pytest.mark.parametrize(
264-
"line",
265-
[
266-
"text/plain",
267-
"text/markdown",
268-
"text/csv",
269-
"text/rtf",
270-
"text/javascript",
271-
"text/html",
272-
"text/xml",
273-
],
274-
)
275-
def test_validate_content_type_invalid(line: str):
276-
warnings = [warning for (_, warning) in check_peps._validate_content_type(1, line)]
277-
assert warnings == ["Content-Type must be 'text/x-rst'"], warnings
278-
279-
280256
@pytest.mark.parametrize(
281257
"line",
282258
[

pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,30 @@ def test_with_fake_pep():
1212
warnings = list(check_peps.check_peps(PEP_9002, content))
1313
assert warnings == [
1414
(1, "PEP must begin with the 'PEP:' header"),
15+
(6, "Must not have invalid header: Version"),
1516
(9, "Must not have duplicate header: Sponsor "),
1617
(10, "Must not have invalid header: Horse-Guards"),
18+
(15, "Must not have invalid header: Content-Type"),
1719
(1, "Must have required header: PEP"),
1820
(1, "Must have required header: Type"),
1921
(
2022
1,
21-
"Headers must be in PEP 12 order. Correct order: Title, Version, "
22-
"Author, Sponsor, BDFL-Delegate, Discussions-To, Status, Topic, "
23-
"Content-Type, Requires, Created, Python-Version, Post-History, "
24-
"Resolution",
23+
"Headers must be in PEP 12 order. Correct order: Title, Author, "
24+
"Sponsor, BDFL-Delegate, Discussions-To, Status, Topic, Requires, "
25+
"Created, Python-Version, Post-History, Resolution",
2526
),
2627
(4, "Author continuation lines must end with a comma"),
2728
(5, "Author line must not be over-indented"),
2829
(7, "Python-Version major part must be 1, 2, or 3: 4.0"),
29-
(
30-
8,
31-
"Sponsor entries must begin with a valid 'Name': "
32-
r"'Sponsor:\nHorse-Guards: Parade'",
33-
),
30+
(8, "Sponsor entries must begin with a valid 'Name': ''"),
31+
(9, "Sponsor entries must begin with a valid 'Name': ''"),
3432
(11, "Created must be a 'DD-mmm-YYYY' date: '1-Jan-1989'"),
3533
(12, "Delegate entries must begin with a valid 'Name': 'Barry!'"),
3634
(13, "Status must be a valid PEP status"),
3735
(14, "Topic must not contain duplicates"),
3836
(14, "Topic must be properly capitalised (Title Case)"),
3937
(14, "Topic must be for a valid sub-index"),
4038
(14, "Topic must be sorted lexicographically"),
41-
(15, "Content-Type must be 'text/x-rst'"),
4239
(16, "PEP references must be separated by comma-spaces (', ')"),
4340
(17, "Discussions-To must be a valid thread URL or mailing list"),
4441
(18, "Post-History must be a 'DD-mmm-YYYY' date: '2-Feb-2000'"),

pep_sphinx_extensions/tests/peps/pep-9000.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PEP: 9000
22
Title: Test with authors with email addresses
3-
Author: Francis Fussyreverend <[email protected]>,
3+
Author: Francis Fussyreverend <[email protected]>,
44
Javier Soulfulcommodore <[email protected]>
55
Created: 20-Apr-2022
66
Status: Draft

peps/api/index.rst

+52-39
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
PEPs API
22
========
33

4-
There is a read-only API of published PEPs available at:
4+
There is a read-only JSON document of every published PEP available at
5+
https://peps.python.org/api/peps.json.
56

6-
* https://peps.python.org/api/peps.json
7+
Each PEP is represented as a JSON object, keyed by the PEP number.
8+
The structure of each JSON object is as follows:
79

8-
The structure is like:
9-
10-
.. code-block:: javascript
10+
.. code-block:: typescript
1111
1212
{
1313
"<PEP number>": {
14-
"number": integer,
14+
"number": integer, // always identical to <PEP number>
1515
"title": string,
1616
"authors": string,
1717
"discussions_to": string | null,
@@ -25,67 +25,80 @@ The structure is like:
2525
"requires": string | null,
2626
"replaces": string | null,
2727
"superseded_by": string | null,
28+
"author_names": Array<string>,
2829
"url": string
2930
},
3031
}
3132
3233
Date values are formatted as DD-MMM-YYYY,
3334
and multiple dates are combined in a comma-separated list.
3435

35-
For example:
36+
A selection of example PEPs are shown here,
37+
illustrating some of the possible values for each field:
3638

3739
.. code-block:: json
3840
3941
{
40-
"8": {
41-
"number": 8,
42-
"title": "Style Guide for Python Code",
43-
"authors": "Guido van Rossum, Barry Warsaw, Alyssa Coghlan",
42+
"12": {
43+
"number": 12,
44+
"title": "Sample reStructuredText PEP Template",
45+
"authors": "David Goodger, Barry Warsaw, Brett Cannon",
4446
"discussions_to": null,
4547
"status": "Active",
4648
"type": "Process",
4749
"topic": "",
48-
"created": "05-Jul-2001",
50+
"created": "05-Aug-2002",
4951
"python_version": null,
50-
"post_history": "05-Jul-2001, 01-Aug-2013",
52+
"post_history": "`30-Aug-2002 <https://mail.python.org/archives/list/[email protected]/thread/KX3AS7QAY26QH3WIUAEOCCNXQ4V2TGGV/>`__",
5153
"resolution": null,
5254
"requires": null,
5355
"replaces": null,
5456
"superseded_by": null,
55-
"url": "https://peps.python.org/pep-0008/"
57+
"author_names": [
58+
"David Goodger",
59+
"Barry Warsaw",
60+
"Brett Cannon"
61+
],
62+
"url": "https://peps.python.org/pep-0012/"
5663
},
57-
"484": {
58-
"number": 484,
59-
"title": "Type Hints",
60-
"authors": "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa",
61-
"discussions_to": "[email protected]",
64+
"160": {
65+
"number": 160,
66+
"title": "Python 1.6 Release Schedule",
67+
"authors": "Fred L. Drake, Jr.",
68+
"discussions_to": null,
6269
"status": "Final",
63-
"type": "Standards Track",
64-
"topic": "typing",
65-
"created": "29-Sep-2014",
66-
"python_version": "3.5",
67-
"post_history": "16-Jan-2015, 20-Mar-2015, 17-Apr-2015, 20-May-2015, 22-May-2015",
68-
"resolution": "https://mail.python.org/pipermail/python-dev/2015-May/140104.html",
70+
"type": "Informational",
71+
"topic": "release",
72+
"created": "25-Jul-2000",
73+
"python_version": "1.6",
74+
"post_history": null,
75+
"resolution": null,
6976
"requires": null,
7077
"replaces": null,
7178
"superseded_by": null,
72-
"url": "https://peps.python.org/pep-0484/"
79+
"author_names": [
80+
"Fred L. Drake, Jr."
81+
],
82+
"url": "https://peps.python.org/pep-0160/"
7383
},
74-
"622": {
75-
"number": 622,
76-
"title": "Structural Pattern Matching",
77-
"authors": "Brandt Bucher, Daniel F Moisset, Tobias Kohn, Ivan Levkivskyi, Guido van Rossum, Talin",
78-
"discussions_to": "python-dev@python.org",
79-
"status": "Superseded",
84+
"3124": {
85+
"number": 3124,
86+
"title": "Overloading, Generic Functions, Interfaces, and Adaptation",
87+
"authors": "Phillip J. Eby",
88+
"discussions_to": "python-3000@python.org",
89+
"status": "Deferred",
8090
"type": "Standards Track",
8191
"topic": "",
82-
"created": "23-Jun-2020",
83-
"python_version": "3.10",
84-
"post_history": "23-Jun-2020, 08-Jul-2020",
92+
"created": "28-Apr-2007",
93+
"python_version": null,
94+
"post_history": "30-Apr-2007",
8595
"resolution": null,
86-
"requires": null,
87-
"replaces": null,
88-
"superseded_by": "634",
89-
"url": "https://peps.python.org/pep-0622/"
96+
"requires": "3107, 3115, 3119",
97+
"replaces": "245, 246",
98+
"superseded_by": null,
99+
"author_names": [
100+
"Phillip J. Eby"
101+
],
102+
"url": "https://peps.python.org/pep-3124/"
90103
}
91104
}

0 commit comments

Comments
 (0)