Infra: Link status and type headers to descriptions (#2842)

Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
Hugo van Kemenade 2022-11-29 11:48:51 +02:00 committed by GitHub
parent 580f8e3c70
commit 67512a10ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 159 additions and 16 deletions

View File

@ -7,7 +7,42 @@ from sphinx import errors
from pep_sphinx_extensions.pep_processor.transforms import pep_zero
from pep_sphinx_extensions.pep_processor.transforms.pep_zero import _mask_email
from pep_sphinx_extensions.pep_zero_generator.constants import (
SPECIAL_STATUSES,
STATUS_ACCEPTED,
STATUS_ACTIVE,
STATUS_DEFERRED,
STATUS_DRAFT,
STATUS_FINAL,
STATUS_PROVISIONAL,
STATUS_REJECTED,
STATUS_SUPERSEDED,
STATUS_WITHDRAWN,
TYPE_INFO,
TYPE_PROCESS,
TYPE_STANDARDS,
)
ABBREVIATED_STATUSES = {
STATUS_DRAFT: "Proposal under active discussion and revision",
STATUS_DEFERRED: "Inactive draft that may be taken up again at a later time",
STATUS_ACCEPTED: "Normative proposal accepted for implementation",
STATUS_ACTIVE: "Currently valid informational guidance, or an in-use process",
STATUS_FINAL: "Accepted and implementation complete, or no longer active",
STATUS_WITHDRAWN: "Removed from consideration by sponsor or authors",
STATUS_REJECTED: "Formally declined and will not be accepted",
STATUS_SUPERSEDED: "Replaced by another succeeding PEP",
STATUS_PROVISIONAL: "Provisionally accepted but additional feedback needed",
}
ABBREVIATED_TYPES = {
TYPE_STANDARDS: "Normative PEP with a new feature for Python, implementation "
"change for CPython or interoperability standard for the ecosystem",
TYPE_INFO: "Non-normative PEP containing background, guidelines or other "
"information relevant to the Python ecosystem",
TYPE_PROCESS: "Normative PEP describing or proposing a change to a Python "
"community process, workflow or governance",
}
class PEPParsingError(errors.SphinxError):
pass
@ -109,6 +144,22 @@ class PEPHeaders(transforms.Transform):
]
if new_body:
para[:] = new_body[:-1] # Drop trailing space/comma
elif name == "status":
para[:] = [
nodes.abbreviation(
body.astext(),
body.astext(),
explanation=_abbreviate_status(body.astext()),
)
]
elif name == "type":
para[:] = [
nodes.abbreviation(
body.astext(),
body.astext(),
explanation=_abbreviate_type(body.astext()),
)
]
elif name in {"last-modified", "content-type", "version"}:
# Mark unneeded fields
fields_to_remove.append(field)
@ -223,3 +274,20 @@ def _process_pretty_url(url: str) -> tuple[str, str]:
def _make_link_pretty(url: str) -> str:
item_name, item_type = _process_pretty_url(url)
return f"{item_name} {item_type}"
def _abbreviate_status(status: str) -> str:
if status in SPECIAL_STATUSES:
status = SPECIAL_STATUSES[status]
try:
return ABBREVIATED_STATUSES[status]
except KeyError:
raise PEPParsingError(f"Unknown status: {status}")
def _abbreviate_type(type_: str) -> str:
try:
return ABBREVIATED_TYPES[type_]
except KeyError:
raise PEPParsingError(f"Unknown type: {type_}")

View File

@ -19,8 +19,8 @@ STATUS_VALUES = {
SPECIAL_STATUSES = {
"April Fool!": STATUS_REJECTED, # See PEP 401 :)
}
# Draft PEPs have no status displayed, Active shares a key with Accepted
HIDE_STATUS = {STATUS_DRAFT, STATUS_ACTIVE}
# Draft PEPs have no status displayed
HIDE_STATUS = {STATUS_DRAFT}
# Dead PEP statuses
DEAD_STATUSES = {STATUS_REJECTED, STATUS_WITHDRAWN, STATUS_SUPERSEDED}

View File

@ -131,7 +131,7 @@ class PEP:
"""Return reStructuredText tooltip for the PEP type and status."""
type_code = self.pep_type[0].upper()
if self.status in HIDE_STATUS:
return f":abbr:`{type_code} ({self.pep_type})`"
return f":abbr:`{type_code} ({self.pep_type}, {self.status})`"
status_code = self.status[0].upper()
return f":abbr:`{type_code}{status_code} ({self.pep_type}, {self.status})`"

View File

@ -6,8 +6,11 @@ import datetime
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_zero_generator.constants import DEAD_STATUSES
from pep_sphinx_extensions.pep_zero_generator.constants import HIDE_STATUS
from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACCEPTED
from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACTIVE
from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_DEFERRED
@ -177,24 +180,25 @@ class PEPZeroWriter:
# PEP types key
self.emit_title("PEP Types Key")
for type_ in sorted(TYPE_VALUES):
self.emit_text(f" {type_[0]} - {type_} PEP")
self.emit_text(
f"* **{type_[0]}** --- *{type_}*: {ABBREVIATED_TYPES[type_]}"
)
self.emit_newline()
self.emit_text(":pep:`More info in PEP 1 <1#pep-types>`.")
self.emit_newline()
# PEP status key
self.emit_title("PEP Status Key")
for status in sorted(STATUS_VALUES):
# Draft PEPs have no status displayed, Active shares a key with Accepted
if status in HIDE_STATUS:
continue
if status == STATUS_ACCEPTED:
msg = " A - Accepted (Standards Track only) or Active proposal"
else:
msg = f" {status[0]} - {status} proposal"
self.emit_text(msg)
status_code = "<No letter>" if status == STATUS_DRAFT else status[0]
self.emit_text(
f"* **{status_code}** --- *{status}*: {ABBREVIATED_STATUSES[status]}"
)
self.emit_newline()
self.emit_text(":pep:`More info in PEP 1 <1#pep-review-resolution>`.")
self.emit_newline()
if is_pep0:

View File

@ -1,6 +1,20 @@
import pytest
from pep_sphinx_extensions.pep_processor.transforms import pep_headers
from pep_sphinx_extensions.pep_zero_generator.constants import (
STATUS_ACCEPTED,
STATUS_ACTIVE,
STATUS_DEFERRED,
STATUS_DRAFT,
STATUS_FINAL,
STATUS_PROVISIONAL,
STATUS_REJECTED,
STATUS_SUPERSEDED,
STATUS_WITHDRAWN,
TYPE_INFO,
TYPE_PROCESS,
TYPE_STANDARDS,
)
@pytest.mark.parametrize(
@ -112,3 +126,60 @@ def test_make_link_pretty(test_input, expected):
out = pep_headers._make_link_pretty(test_input)
assert out == expected
@pytest.mark.parametrize(
"test_input, expected",
[
(STATUS_ACCEPTED, "Normative proposal accepted for implementation"),
(STATUS_ACTIVE, "Currently valid informational guidance, or an in-use process"),
(STATUS_DEFERRED, "Inactive draft that may be taken up again at a later time"),
(STATUS_DRAFT, "Proposal under active discussion and revision"),
(STATUS_FINAL, "Accepted and implementation complete, or no longer active"),
(STATUS_REJECTED, "Formally declined and will not be accepted"),
("April Fool!", "Formally declined and will not be accepted"),
(STATUS_SUPERSEDED, "Replaced by another succeeding PEP"),
(STATUS_WITHDRAWN, "Removed from consideration by sponsor or authors"),
(STATUS_PROVISIONAL, "Provisionally accepted but additional feedback needed"),
],
)
def test_abbreviate_status(test_input, expected):
out = pep_headers._abbreviate_status(test_input)
assert out == expected
def test_abbreviate_status_unknown():
with pytest.raises(pep_headers.PEPParsingError):
pep_headers._abbreviate_status("an unknown status")
@pytest.mark.parametrize(
"test_input, expected",
[
(
TYPE_INFO,
"Non-normative PEP containing background, guidelines or other information "
"relevant to the Python ecosystem",
),
(
TYPE_PROCESS,
"Normative PEP describing or proposing a change to a Python community "
"process, workflow or governance",
),
(
TYPE_STANDARDS,
"Normative PEP with a new feature for Python, implementation change for "
"CPython or interoperability standard for the ecosystem",
),
],
)
def test_abbreviate_type(test_input, expected):
out = pep_headers._abbreviate_type(test_input)
assert out == expected
def test_abbreviate_type_unknown():
with pytest.raises(pep_headers.PEPParsingError):
pep_headers._abbreviate_type("an unknown type")

View File

@ -48,7 +48,7 @@ def test_pep_details(monkeypatch):
assert pep8.details == {
"authors": "GvR, Warsaw, Coghlan",
"number": 8,
"shorthand": ":abbr:`P (Process)`",
"shorthand": ":abbr:`PA (Process, Active)`",
"title": "Style Guide for Python Code",
}
@ -97,12 +97,12 @@ def test_parse_authors_invalid():
@pytest.mark.parametrize(
"test_type, test_status, expected",
[
(TYPE_INFO, STATUS_DRAFT, ":abbr:`I (Informational)`"),
(TYPE_INFO, STATUS_ACTIVE, ":abbr:`I (Informational)`"),
(TYPE_INFO, STATUS_DRAFT, ":abbr:`I (Informational, Draft)`"),
(TYPE_INFO, STATUS_ACTIVE, ":abbr:`IA (Informational, Active)`"),
(TYPE_INFO, STATUS_ACCEPTED, ":abbr:`IA (Informational, Accepted)`"),
(TYPE_INFO, STATUS_DEFERRED, ":abbr:`ID (Informational, Deferred)`"),
(TYPE_PROCESS, STATUS_ACCEPTED, ":abbr:`PA (Process, Accepted)`"),
(TYPE_PROCESS, STATUS_ACTIVE, ":abbr:`P (Process)`"),
(TYPE_PROCESS, STATUS_ACTIVE, ":abbr:`PA (Process, Active)`"),
(TYPE_PROCESS, STATUS_FINAL, ":abbr:`PF (Process, Final)`"),
(TYPE_PROCESS, STATUS_SUPERSEDED, ":abbr:`PS (Process, Superseded)`"),
(TYPE_PROCESS, STATUS_WITHDRAWN, ":abbr:`PW (Process, Withdrawn)`"),