Skip to content

Commit

Permalink
Infra: Prepare for moving PEPs to a subfolder (#3417)
Browse files Browse the repository at this point in the history
  • Loading branch information
AA-Turner authored Sep 3, 2023
1 parent e7314c9 commit 2d4c98d
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 56 deletions.
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----------------------------------------------------

Expand Down Expand Up @@ -60,16 +62,18 @@

# -- 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
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`
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from docutils import nodes
from docutils.parsers import rst


PYPA_SPEC_BASE_URL = "https://packaging.python.org/en/latest/specifications/"


Expand Down
40 changes: 21 additions & 19 deletions pep_sphinx_extensions/pep_processor/transforms/pep_footer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import datetime as dt
import time
from pathlib import Path
import subprocess

Expand All @@ -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
Expand Down Expand Up @@ -62,42 +62,44 @@ 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)


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()
2 changes: 1 addition & 1 deletion pep_sphinx_extensions/pep_theme/templates/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ <h1>Python Enhancement Proposals</h1>
<h2>Contents</h2>
{{ toc }}
<br>
{%- if not (sourcename.startswith("pep-0000") or sourcename.startswith("topic")) %}
{%- if not sourcename.startswith(("pep-0000", "topic")) %}
<a id="source" href="https://github.com/python/peps/blob/main/{{sourcename}}">Page Source (GitHub)</a>
{%- endif %}
</nav>
Expand Down
21 changes: 13 additions & 8 deletions pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@
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():
Expand All @@ -52,16 +52,21 @@ 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)
peps.append(parser.PEP(pep0_path))

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))
7 changes: 5 additions & 2 deletions pep_sphinx_extensions/pep_zero_generator/subindices.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import os
from pathlib import Path
from typing import TYPE_CHECKING

Expand All @@ -14,8 +15,7 @@


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
Expand All @@ -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)

Expand Down
6 changes: 2 additions & 4 deletions pep_sphinx_extensions/pep_zero_generator/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
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
Expand Down
3 changes: 3 additions & 0 deletions pep_sphinx_extensions/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from pathlib import Path

PEP_ROOT = Path(__file__, "..", "..", "..").resolve()
Original file line number Diff line number Diff line change
@@ -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(
"<paragraph>Last modified: "
Expand All @@ -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) == "<paragraph/>"

Expand All @@ -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
18 changes: 9 additions & 9 deletions pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from pathlib import Path

import pytest

from pep_sphinx_extensions.pep_zero_generator import parser
Expand All @@ -19,29 +17,31 @@
)
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) == "<PEP 0008 - Style Guide for Python Code>"


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",
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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)

Expand Down

0 comments on commit 2d4c98d

Please sign in to comment.