Sphinx support: theming (#1933)
See #2, #1385 for context. Superseeds #1568. This is the Sphinx-theming part, building on PR #1930. ### Stylesheets: - `style.css` - styles - `mq.css` - media queries ### Jinja2 Templates: - `page.html` - overarching template ### Javascript: - `doctools.js` - fixes footnote brackets ### Theme miscellany - `theme.conf` - sets pygments styles, theme internals
This commit is contained in:
parent
7d727005fd
commit
0d93abf9bf
|
@ -36,6 +36,10 @@ jobs:
|
|||
- name: 🔧 Build PEPs
|
||||
run: make pages -j$(nproc)
|
||||
|
||||
# remove the .doctrees folder when building for deployment as it takes two thirds of disk space
|
||||
- name: 🔥 Clean up files
|
||||
run: rm -r build/.doctrees/
|
||||
|
||||
- name: 🚀 Deploy to GitHub pages
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.1
|
||||
with:
|
||||
|
|
17
build.py
17
build.py
|
@ -2,7 +2,6 @@
|
|||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
@ -25,11 +24,16 @@ def create_parser():
|
|||
return parser.parse_args()
|
||||
|
||||
|
||||
def create_index_file(html_root: Path):
|
||||
def create_index_file(html_root: Path, builder: str) -> None:
|
||||
"""Copies PEP 0 to the root index.html so that /peps/ works."""
|
||||
pep_zero_path = html_root / "pep-0000" / "index.html"
|
||||
if pep_zero_path.is_file():
|
||||
shutil.copy(pep_zero_path, html_root / "index.html")
|
||||
pep_zero_file = "pep-0000.html" if builder == "html" else "pep-0000/index.html"
|
||||
try:
|
||||
pep_zero_text = html_root.joinpath(pep_zero_file).read_text(encoding="utf-8")
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
if builder == "dirhtml":
|
||||
pep_zero_text = pep_zero_text.replace('="../', '="') # remove relative directory links
|
||||
html_root.joinpath("index.html").write_text(pep_zero_text, encoding="utf-8")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -67,7 +71,8 @@ if __name__ == "__main__":
|
|||
parallel=args.jobs,
|
||||
)
|
||||
app.builder.copysource = False # Prevent unneeded source copying - we link direct to GitHub
|
||||
app.builder.search = False # Disable search
|
||||
app.build()
|
||||
|
||||
if args.index_file:
|
||||
create_index_file(build_directory)
|
||||
create_index_file(build_directory, sphinx_builder)
|
||||
|
|
12
conf.py
12
conf.py
|
@ -1,7 +1,7 @@
|
|||
"""Configuration for building PEPs using Sphinx."""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
sys.path.append(str(Path("pep_sphinx_extensions").absolute()))
|
||||
|
||||
|
@ -44,3 +44,13 @@ html_math_renderer = "maths_to_html" # Maths rendering
|
|||
html_show_copyright = False # Turn off miscellany
|
||||
html_show_sphinx = False
|
||||
html_title = "peps.python.org" # Set <title/>
|
||||
|
||||
# Theme settings
|
||||
html_theme_path = ["pep_sphinx_extensions"]
|
||||
html_theme = "pep_theme" # The actual theme directory (child of html_theme_path)
|
||||
html_use_index = False # Disable index (we use PEP 0)
|
||||
html_sourcelink_suffix = "" # Fix links to GitHub (don't append .txt)
|
||||
html_style = "" # must be defined here or in theme.conf, but is unused
|
||||
html_permalinks = False # handled in the PEPContents transform
|
||||
|
||||
templates_path = ['pep_sphinx_extensions/pep_theme/templates'] # Theme template relative paths from `confdir`
|
||||
|
|
|
@ -238,12 +238,9 @@ 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
|
||||
|
||||
starting at
|
||||
|
||||
https://mail.python.org/pipermail/python-dev/2003-August/037803.html
|
||||
`[Python-Dev] pre-PEP: Resource-Release Support for Generators`
|
||||
starting at
|
||||
https://mail.python.org/pipermail/python-dev/2003-August/037803.html
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
|
|
@ -147,11 +147,11 @@ The "pip3" command will support two new command-line options that are used
|
|||
in the boostrapping, and otherwise ignored. They control where the pip
|
||||
implementation is installed:
|
||||
|
||||
--bootstrap
|
||||
``--bootstrap``
|
||||
Install to the user's packages directory. The name of this option is chosen
|
||||
to promote it as the preferred installation option.
|
||||
|
||||
--bootstrap-to-system
|
||||
``--bootstrap-to-system``
|
||||
Install to the system site-packages directory.
|
||||
|
||||
These command-line options will also need to be implemented, but otherwise
|
||||
|
|
18
pep-3143.txt
18
pep-3143.txt
|
@ -22,24 +22,6 @@ any daemon regardless of what else the program may need to do.
|
|||
This PEP introduces a package to the Python standard library that
|
||||
provides a simple interface to the task of becoming a daemon process.
|
||||
|
||||
|
||||
.. contents::
|
||||
..
|
||||
Table of Contents:
|
||||
Abstract
|
||||
Specification
|
||||
Example usage
|
||||
Interface
|
||||
``DaemonContext`` objects
|
||||
Motivation
|
||||
Rationale
|
||||
Correct daemon behaviour
|
||||
A daemon is not a service
|
||||
Reference Implementation
|
||||
Other daemon implementations
|
||||
References
|
||||
Copyright
|
||||
|
||||
============
|
||||
PEP Deferral
|
||||
============
|
||||
|
|
|
@ -5,8 +5,10 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from docutils.writers.html5_polyglot import HTMLTranslator
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment import default_settings
|
||||
|
||||
from pep_sphinx_extensions import config
|
||||
from pep_sphinx_extensions.pep_processor.html import pep_html_translator
|
||||
from pep_sphinx_extensions.pep_processor.parsing import pep_parser
|
||||
from pep_sphinx_extensions.pep_processor.parsing import pep_role
|
||||
|
@ -26,19 +28,31 @@ default_settings |= {
|
|||
"_disable_config": True, # disable using docutils.conf whilst running both PEP generators
|
||||
}
|
||||
|
||||
# Monkeypatch sphinx.environment.BuildEnvironment.collect_relations, as it takes a long time
|
||||
# and we don't use the parent/next/prev functionality
|
||||
BuildEnvironment.collect_relations = lambda self: {}
|
||||
|
||||
|
||||
def _depart_maths():
|
||||
pass # No-op callable for the type checker
|
||||
|
||||
|
||||
def _update_config_for_builder(app: Sphinx):
|
||||
if app.builder.name == "dirhtml":
|
||||
config.pep_url = f"../{config.pep_stem}"
|
||||
app.env.settings["pep_file_url_template"] = "../pep-%04d"
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> dict[str, bool]:
|
||||
"""Initialize Sphinx extension."""
|
||||
|
||||
# Register plugin logic
|
||||
app.add_source_parser(pep_parser.PEPParser) # Add PEP transforms
|
||||
app.add_role("pep", pep_role.PEPRole(), override=True) # Transform PEP references to links
|
||||
app.set_translator("html", pep_html_translator.PEPTranslator) # Docutils Node Visitor overrides
|
||||
app.set_translator("html", pep_html_translator.PEPTranslator) # Docutils Node Visitor overrides (html builder)
|
||||
app.set_translator("dirhtml", pep_html_translator.PEPTranslator) # Docutils Node Visitor overrides (dirhtml builder)
|
||||
app.connect("env-before-read-docs", create_pep_zero) # PEP 0 hook
|
||||
app.connect("builder-inited", _update_config_for_builder) # Update configuration values for builder used
|
||||
|
||||
# Mathematics rendering
|
||||
inline_maths = HTMLTranslator.visit_math, _depart_maths
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from sphinx import roles
|
||||
|
||||
from pep_sphinx_extensions.config import pep_url
|
||||
from pep_sphinx_extensions import config
|
||||
|
||||
|
||||
class PEPRole(roles.PEP):
|
||||
|
@ -8,9 +8,8 @@ class PEPRole(roles.PEP):
|
|||
|
||||
def build_uri(self) -> str:
|
||||
"""Get PEP URI from role text."""
|
||||
base_url = self.inliner.document.settings.pep_base_url
|
||||
pep_num, _, fragment = self.target.partition("#")
|
||||
pep_base = base_url + pep_url.format(int(pep_num))
|
||||
pep_str, _, fragment = self.target.partition("#")
|
||||
pep_base = config.pep_url.format(int(pep_str))
|
||||
if fragment:
|
||||
return f"{pep_base}#{fragment}"
|
||||
return pep_base
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from docutils import nodes
|
||||
|
@ -14,21 +16,20 @@ class PEPContents(transforms.Transform):
|
|||
def apply(self) -> None:
|
||||
if not Path(self.document["source"]).match("pep-*"):
|
||||
return # not a PEP file, exit early
|
||||
|
||||
# Create the contents placeholder section
|
||||
title = nodes.title("", "Contents")
|
||||
contents_topic = nodes.topic("", title, classes=["contents"])
|
||||
title = nodes.title("", "", nodes.Text("Contents"))
|
||||
contents_section = nodes.section("", title)
|
||||
if not self.document.has_name("contents"):
|
||||
contents_topic["names"].append("contents")
|
||||
self.document.note_implicit_target(contents_topic)
|
||||
contents_section["names"].append("contents")
|
||||
self.document.note_implicit_target(contents_section)
|
||||
|
||||
# Add a table of contents builder
|
||||
pending = nodes.pending(Contents)
|
||||
contents_topic += pending
|
||||
contents_section += pending
|
||||
self.document.note_pending(pending)
|
||||
|
||||
# Insert the toc after title and PEP headers
|
||||
self.document.children[0].insert(2, contents_topic)
|
||||
self.document.children[0].insert(2, contents_section)
|
||||
|
||||
# Add a horizontal rule before contents
|
||||
transition = nodes.transition()
|
||||
|
@ -37,7 +38,7 @@ class PEPContents(transforms.Transform):
|
|||
|
||||
class Contents(parts.Contents):
|
||||
"""Build Table of Contents from document."""
|
||||
def __init__(self, document, startnode=None):
|
||||
def __init__(self, document: nodes.document, startnode: nodes.Node | None = None):
|
||||
super().__init__(document, startnode)
|
||||
|
||||
# used in parts.Contents.build_contents
|
||||
|
@ -45,19 +46,34 @@ class Contents(parts.Contents):
|
|||
self.backlinks = None
|
||||
|
||||
def apply(self) -> None:
|
||||
# used in parts.Contents.build_contents
|
||||
self.toc_id = self.startnode.parent["ids"][0]
|
||||
self.backlinks = self.document.settings.toc_backlinks
|
||||
|
||||
# let the writer (or output software) build the contents list?
|
||||
if getattr(self.document.settings, "use_latex_toc", False):
|
||||
# move customisation settings to the parent node
|
||||
self.startnode.parent.attributes.update(self.startnode.details)
|
||||
self.startnode.parent.remove(self.startnode)
|
||||
contents = self.build_contents(self.document[0][4:]) # skip PEP title, headers, <hr/>, and contents
|
||||
if contents:
|
||||
self.startnode.replace_self(contents)
|
||||
else:
|
||||
contents = self.build_contents(self.document[0])
|
||||
if contents:
|
||||
self.startnode.replace_self(contents)
|
||||
else:
|
||||
# if no contents, remove the empty placeholder
|
||||
self.startnode.parent.parent.remove(self.startnode.parent)
|
||||
# if no contents, remove the empty placeholder
|
||||
self.startnode.parent.parent.remove(self.startnode.parent)
|
||||
|
||||
def build_contents(self, node: nodes.Node | list[nodes.Node], _level: None = None):
|
||||
entries = []
|
||||
children = getattr(node, "children", node)
|
||||
|
||||
for section in children:
|
||||
if not isinstance(section, nodes.section):
|
||||
continue
|
||||
|
||||
title = section[0]
|
||||
|
||||
# remove all pre-existing hyperlinks in the title (e.g. PEP references)
|
||||
while (link_node := title.next_node(nodes.reference)) is not None:
|
||||
link_node.replace_self(link_node[0])
|
||||
ref_id = section['ids'][0]
|
||||
title["refid"] = ref_id # Add a link to self
|
||||
entry_text = self.copy_and_filter(title)
|
||||
reference = nodes.reference("", "", refid=ref_id, *entry_text)
|
||||
item = nodes.list_item("", nodes.paragraph("", "", reference))
|
||||
|
||||
item += self.build_contents(section) # recurse to add sub-sections
|
||||
entries.append(item)
|
||||
if entries:
|
||||
return nodes.bullet_list('', *entries)
|
||||
return []
|
||||
|
|
|
@ -69,43 +69,43 @@ class PEPFooter(transforms.Transform):
|
|||
|
||||
# If there are no references after TargetNotes has finished, remove the
|
||||
# references section
|
||||
pending = nodes.pending(misc.CallBack, details={"callback": self.cleanup_callback})
|
||||
pending = nodes.pending(misc.CallBack, details={"callback": _cleanup_callback})
|
||||
reference_section.append(pending)
|
||||
self.document.note_pending(pending, priority=1)
|
||||
|
||||
# Add link to source text and last modified date
|
||||
self.add_source_link(pep_source_path)
|
||||
self.add_commit_history_info(pep_source_path)
|
||||
if pep_source_path.stem != "pep-0000":
|
||||
self.document += _add_source_link(pep_source_path)
|
||||
self.document += _add_commit_history_info(pep_source_path)
|
||||
|
||||
@staticmethod
|
||||
def cleanup_callback(pending: nodes.pending) -> None:
|
||||
"""Remove an empty "References" section.
|
||||
|
||||
Called after the `references.TargetNotes` transform is complete.
|
||||
def _cleanup_callback(pending: nodes.pending) -> None:
|
||||
"""Remove an empty "References" section.
|
||||
|
||||
"""
|
||||
if len(pending.parent) == 2: # <title> and <pending>
|
||||
pending.parent.parent.remove(pending.parent)
|
||||
Called after the `references.TargetNotes` transform is complete.
|
||||
|
||||
def add_source_link(self, pep_source_path: Path) -> None:
|
||||
"""Add link to source text on VCS (GitHub)"""
|
||||
source_link = config.pep_vcs_url + pep_source_path.name
|
||||
link_node = nodes.reference("", source_link, refuri=source_link)
|
||||
span_node = nodes.inline("", "Source: ", link_node)
|
||||
self.document.append(span_node)
|
||||
"""
|
||||
if len(pending.parent) == 2: # <title> and <pending>
|
||||
pending.parent.parent.remove(pending.parent)
|
||||
|
||||
def add_commit_history_info(self, pep_source_path: Path) -> None:
|
||||
"""Use local git history to find last modified date."""
|
||||
args = ["git", "--no-pager", "log", "-1", "--format=%at", pep_source_path.name]
|
||||
try:
|
||||
file_modified = subprocess.check_output(args)
|
||||
since_epoch = file_modified.decode("utf-8").strip()
|
||||
dt = datetime.datetime.utcfromtimestamp(float(since_epoch))
|
||||
except (subprocess.CalledProcessError, ValueError):
|
||||
return None
|
||||
|
||||
commit_link = config.pep_commits_url + pep_source_path.name
|
||||
link_node = nodes.reference("", f"{dt.isoformat()}Z", refuri=commit_link)
|
||||
span_node = nodes.inline("", "Last modified: ", link_node)
|
||||
self.document.append(nodes.line("", "", classes=["zero-height"]))
|
||||
self.document.append(span_node)
|
||||
def _add_source_link(pep_source_path: Path) -> nodes.paragraph:
|
||||
"""Add link to source text on VCS (GitHub)"""
|
||||
source_link = config.pep_vcs_url + pep_source_path.name
|
||||
link_node = nodes.reference("", source_link, refuri=source_link)
|
||||
return nodes.paragraph("", "Source: ", link_node)
|
||||
|
||||
|
||||
def _add_commit_history_info(pep_source_path: Path) -> nodes.paragraph:
|
||||
"""Use local git history to find last modified date."""
|
||||
args = ["git", "--no-pager", "log", "-1", "--format=%at", pep_source_path.name]
|
||||
try:
|
||||
file_modified = subprocess.check_output(args)
|
||||
since_epoch = file_modified.decode("utf-8").strip()
|
||||
dt = datetime.datetime.utcfromtimestamp(float(since_epoch))
|
||||
except (subprocess.CalledProcessError, ValueError):
|
||||
return nodes.paragraph()
|
||||
|
||||
commit_link = config.pep_commits_url + pep_source_path.name
|
||||
link_node = nodes.reference("", f"{dt.isoformat(sep=' ')} GMT", refuri=commit_link)
|
||||
return nodes.paragraph("", "Last modified: ", link_node)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils import transforms
|
||||
from docutils.transforms import peps
|
||||
from sphinx import errors
|
||||
|
||||
from pep_sphinx_extensions.config import pep_url
|
||||
from pep_sphinx_extensions import config
|
||||
from pep_sphinx_extensions.pep_processor.transforms import pep_zero
|
||||
|
||||
|
||||
|
@ -69,21 +70,18 @@ class PEPHeaders(transforms.Transform):
|
|||
raise PEPParsingError(msg)
|
||||
|
||||
para = body[0]
|
||||
if name in {"author", "bdfl-delegate", "pep-delegate", "sponsor"}:
|
||||
if name in {"author", "bdfl-delegate", "pep-delegate", "discussions-to", "sponsor"}:
|
||||
# mask emails
|
||||
for node in para:
|
||||
if isinstance(node, nodes.reference):
|
||||
pep_num = pep if name == "discussions-to" else -1
|
||||
node.replace_self(peps.mask_email(node, pep_num))
|
||||
pep_num = pep if name == "discussions-to" else None
|
||||
node.replace_self(_mask_email(node, pep_num))
|
||||
elif name in {"replaces", "superseded-by", "requires"}:
|
||||
# replace PEP numbers with normalised list of links to PEPs
|
||||
new_body = []
|
||||
space = nodes.Text(" ")
|
||||
for ref_pep in re.split(r",?\s+", body.astext()):
|
||||
new_body.append(nodes.reference(
|
||||
ref_pep, ref_pep,
|
||||
refuri=(self.document.settings.pep_base_url + pep_url.format(int(ref_pep)))))
|
||||
new_body.append(space)
|
||||
new_body += [nodes.reference("", ref_pep, refuri=config.pep_url.format(int(ref_pep)))]
|
||||
new_body += [nodes.Text(", ")]
|
||||
para[:] = new_body[:-1] # drop trailing space
|
||||
elif name in {"last-modified", "content-type", "version"}:
|
||||
# Mark unneeded fields
|
||||
|
@ -94,7 +92,7 @@ class PEPHeaders(transforms.Transform):
|
|||
field.parent.remove(field)
|
||||
|
||||
|
||||
def _mask_email(ref: nodes.reference, pep_num: int = -1) -> nodes.reference:
|
||||
def _mask_email(ref: nodes.reference, pep_num: int | None = None) -> nodes.reference:
|
||||
"""Mask the email address in `ref` and return a replacement node.
|
||||
|
||||
`ref` is returned unchanged if it contains no email address.
|
||||
|
@ -105,15 +103,12 @@ def _mask_email(ref: nodes.reference, pep_num: int = -1) -> nodes.reference:
|
|||
If given a PEP number `pep_num`, add a default email subject.
|
||||
|
||||
"""
|
||||
if "refuri" in ref and ref["refuri"].startswith("mailto:"):
|
||||
non_masked_addresses = {"peps@python.org", "python-list@python.org", "python-dev@python.org"}
|
||||
if ref['refuri'].removeprefix("mailto:").strip() in non_masked_addresses:
|
||||
replacement = ref[0]
|
||||
else:
|
||||
replacement_text = ref.astext().replace("@", " at ")
|
||||
replacement = nodes.raw('', replacement_text, format="html")
|
||||
|
||||
if pep_num != -1:
|
||||
replacement['refuri'] += f"?subject=PEP%20{pep_num}"
|
||||
return replacement
|
||||
if "refuri" not in ref or not ref["refuri"].startswith("mailto:"):
|
||||
return ref
|
||||
non_masked_addresses = {"peps@python.org", "python-list@python.org", "python-dev@python.org"}
|
||||
if ref["refuri"].removeprefix("mailto:").strip() not in non_masked_addresses:
|
||||
ref[0] = nodes.raw("", ref[0].replace("@", " at "), format="html")
|
||||
if pep_num is None:
|
||||
return ref[0] # return email text without mailto link
|
||||
ref["refuri"] += f"?subject=PEP%20{pep_num}"
|
||||
return ref
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
from pathlib import Path
|
||||
|
||||
from docutils import nodes
|
||||
import docutils.transforms as transforms
|
||||
from docutils import transforms
|
||||
from docutils import utils
|
||||
from docutils.parsers.rst import roles
|
||||
from docutils.parsers.rst import states
|
||||
|
||||
|
||||
class PEPTitle(transforms.Transform):
|
||||
|
@ -34,16 +37,20 @@ class PEPTitle(transforms.Transform):
|
|||
pep_title_string = f"PEP {pep_number} -- {pep_title}" # double hyphen for en dash
|
||||
|
||||
# Generate the title section node and its properties
|
||||
pep_title_node = nodes.section()
|
||||
text_node = nodes.Text(pep_title_string, pep_title_string)
|
||||
title_node = nodes.title(pep_title_string, "", text_node)
|
||||
title_node["classes"].append("page-title")
|
||||
name = " ".join(title_node.astext().lower().split()) # normalise name
|
||||
pep_title_node["names"].append(name)
|
||||
pep_title_node += title_node
|
||||
title_nodes = _line_to_nodes(pep_title_string)
|
||||
pep_title_node = nodes.section("", nodes.title("", "", *title_nodes, classes=["page-title"]), names=["pep-content"])
|
||||
|
||||
# Insert the title node as the root element, move children down
|
||||
document_children = self.document.children
|
||||
self.document.children = [pep_title_node]
|
||||
pep_title_node.extend(document_children)
|
||||
self.document.note_implicit_target(pep_title_node, pep_title_node)
|
||||
|
||||
|
||||
def _line_to_nodes(text: str) -> list[nodes.Node]:
|
||||
"""Parse RST string to nodes."""
|
||||
document = utils.new_document("<inline-rst>")
|
||||
document.settings.pep_references = document.settings.rfc_references = False # patch settings
|
||||
states.RSTStateMachine(state_classes=states.state_classes, initial_state="Body").run([text], document) # do parsing
|
||||
roles._roles.pop("", None) # restore the "default" default role after parsing a document
|
||||
return document[0].children
|
||||
|
|
|
@ -2,7 +2,7 @@ from docutils import nodes
|
|||
from docutils import transforms
|
||||
from docutils.transforms import peps
|
||||
|
||||
from pep_sphinx_extensions.config import pep_url
|
||||
from pep_sphinx_extensions import config
|
||||
|
||||
|
||||
class PEPZero(transforms.Transform):
|
||||
|
@ -68,7 +68,7 @@ class PEPZeroSpecial(nodes.SparseNodeVisitor):
|
|||
if isinstance(para, nodes.paragraph) and len(para) == 1:
|
||||
pep_str = para.astext()
|
||||
try:
|
||||
ref = self.document.settings.pep_base_url + pep_url.format(int(pep_str))
|
||||
ref = config.pep_url.format(int(pep_str))
|
||||
para[0] = nodes.reference(pep_str, pep_str, refuri=ref)
|
||||
except ValueError:
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/* JavaScript utilities for all documentation. */
|
||||
|
||||
// Footnote fixer
|
||||
document.querySelectorAll("span.brackets").forEach(el => el.innerHTML = "[" + el.innerHTML + "]")
|
||||
document.querySelectorAll("a.brackets").forEach(el => el.innerHTML = "[" + el.innerHTML + "]")
|
|
@ -0,0 +1,95 @@
|
|||
@charset "UTF-8";
|
||||
/* Media Queries */
|
||||
@media (max-width: 32.5em) {
|
||||
/* Reduce padding & margins for the smallest screens */
|
||||
section#pep-page-section > header > h1 {
|
||||
padding-right: 0;
|
||||
border-right: none;
|
||||
}
|
||||
ul.breadcrumbs {
|
||||
padding: 0 0 .5rem;
|
||||
}
|
||||
nav#pep-sidebar {
|
||||
display: none;
|
||||
}
|
||||
table th,
|
||||
table td {
|
||||
padding: 0 0.1rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 32.5em) {
|
||||
section#pep-page-section {
|
||||
max-width: 40em;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: .5rem 1rem 0;
|
||||
}
|
||||
}
|
||||
@media (min-width: 54em) {
|
||||
section#pep-page-section {
|
||||
max-width: 75em;
|
||||
}
|
||||
section#pep-page-section > article {
|
||||
max-width: 40em;
|
||||
width: 74%;
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
nav#pep-sidebar {
|
||||
width: 24%;
|
||||
float: left;
|
||||
margin-right: 2%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 60em) {
|
||||
section#pep-page-section > article {
|
||||
max-width: none;
|
||||
padding-left: 3.2%;
|
||||
padding-right: 3.2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
color: #000 !important;
|
||||
}
|
||||
body {
|
||||
font-size: 10pt;
|
||||
line-height: 1.67;
|
||||
}
|
||||
*[role="main"] a[href]:after {
|
||||
content: " (" attr(href) ")";
|
||||
font-size: .75rem;
|
||||
}
|
||||
pre,
|
||||
blockquote {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
tr,
|
||||
img {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
@page {
|
||||
margin: 0.5cm;
|
||||
}
|
||||
p,
|
||||
h2,
|
||||
h3 {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 695 B |
|
@ -0,0 +1,292 @@
|
|||
@charset "UTF-8";
|
||||
/* Styles for PEPs
|
||||
|
||||
Colours:
|
||||
white:
|
||||
background
|
||||
footnotes/references vertical border
|
||||
#333
|
||||
body text
|
||||
#888
|
||||
blockquote left line
|
||||
header breadcrumbs separator
|
||||
link underline (hovered/focussed)
|
||||
#ccc:
|
||||
scrollbar
|
||||
#ddd
|
||||
header bottom border
|
||||
horizontal rule
|
||||
table vertical border
|
||||
#eee:
|
||||
link underline
|
||||
table rows & top/bottom border
|
||||
PEP header rows
|
||||
footnotes/references rows
|
||||
admonition note background
|
||||
#f8f8f8:
|
||||
inline code background
|
||||
|
||||
#0072aa:
|
||||
links
|
||||
# fee:
|
||||
admonition warning background
|
||||
|
||||
*/
|
||||
|
||||
/* Set master rules */
|
||||
* {box-sizing: border-box}
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 0;
|
||||
line-height: 1.4rem;
|
||||
font-weight: normal;
|
||||
font-size: 1rem;
|
||||
font-family: "Source Sans Pro", Arial, sans-serif;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
background-color: white;
|
||||
}
|
||||
section#pep-page-section {
|
||||
padding: 0.25rem 0.25rem 0;
|
||||
display: table;
|
||||
}
|
||||
|
||||
/* Reduce margin sizes for body text */
|
||||
p {margin: .5rem 0}
|
||||
|
||||
/* Header rules */
|
||||
h1.page-title {
|
||||
line-height: 2.3rem;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.6rem;
|
||||
font-weight: bold;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
font-weight: normal;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: normal;
|
||||
margin-top: .5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Anchor link rules */
|
||||
a,
|
||||
a:active,
|
||||
a:visited {
|
||||
color: #0072aa;
|
||||
text-decoration-color: #eee;
|
||||
display: inline;
|
||||
}
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration-color: #888;
|
||||
}
|
||||
|
||||
/* Blockquote rules */
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
border-left: 1px solid #888;
|
||||
margin: .5rem;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
blockquote em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
cite {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Code rules (code literals and Pygments highlighting blocks) */
|
||||
pre,
|
||||
code {
|
||||
font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", "DejaVu Sans Mono", Consolas, monospace;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
-webkit-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
code.literal {
|
||||
font-size: .8em;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
pre {
|
||||
padding: .5rem .75rem;
|
||||
}
|
||||
|
||||
/* Definition list rules */
|
||||
dl dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
dl dd {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Horizontal rule rule */
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 1.75rem 0;
|
||||
}
|
||||
/*Image rules */
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
a img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* List rules */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0;
|
||||
margin: 0 0 0 1.5rem;
|
||||
}
|
||||
ul {list-style: square}
|
||||
ol.arabic {list-style: decimal}
|
||||
ol.loweralpha {list-style: lower-alpha}
|
||||
ol.upperalpha {list-style: upper-alpha}
|
||||
ol.lowerroman {list-style: lower-roman}
|
||||
ol.upperroman {list-style: upper-roman}
|
||||
|
||||
/* Maths rules */
|
||||
sub,
|
||||
sup {
|
||||
font-size: .75em;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sup {top: -0.5em}
|
||||
sub {bottom: -0.25em}
|
||||
|
||||
/* Table rules */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
table caption {
|
||||
margin: 1rem 0 .75rem;
|
||||
}
|
||||
table tbody tr:nth-of-type(odd) {
|
||||
background-color: #eee;
|
||||
}
|
||||
table th,
|
||||
table td {
|
||||
text-align: left;
|
||||
padding: 0.25rem 0.5rem 0.2rem;
|
||||
}
|
||||
table td + td {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Breadcrumbs rules */
|
||||
section#pep-page-section > header {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
section#pep-page-section > header > h1 {
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
padding-right: .6rem;
|
||||
border-right: 1px solid #888;
|
||||
}
|
||||
ul.breadcrumbs {
|
||||
margin: 0;
|
||||
padding: .5rem 0 .5rem .4rem;
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
}
|
||||
ul.breadcrumbs li {
|
||||
display: inline;
|
||||
}
|
||||
ul.breadcrumbs a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Admonitions rules */
|
||||
div.note,
|
||||
div.warning {
|
||||
padding: 0.5rem 0.75rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
}
|
||||
div.warning {
|
||||
background-color: #fee;
|
||||
}
|
||||
p.admonition-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* PEP Header / references rules */
|
||||
dl.rfc2822,
|
||||
dl.footnote {
|
||||
display: grid;
|
||||
grid-template-columns: fit-content(30%) auto;
|
||||
line-height: 1.875;
|
||||
width: 100%;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
dl.rfc2822 > dt, dl.rfc2822 > dd,
|
||||
dl.footnote > dt, dl.footnote > dd {
|
||||
padding: .25rem .5rem .2rem;
|
||||
}
|
||||
dl.rfc2822 > dt:nth-of-type(even), dl.rfc2822 > dd:nth-of-type(even),
|
||||
dl.footnote > dt:nth-of-type(even), dl.footnote > dd:nth-of-type(even) {
|
||||
background-color: #eee;
|
||||
}
|
||||
dl.footnote > dt {
|
||||
font-weight: normal;
|
||||
border-right: 1px solid white;
|
||||
}
|
||||
|
||||
/* Sidebar formatting */
|
||||
nav#pep-sidebar {
|
||||
overflow-y: scroll;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
scrollbar-width: thin; /* CSS Standards, not *yet* widely supported */
|
||||
scrollbar-color: #ccc transparent;
|
||||
}
|
||||
nav#pep-sidebar::-webkit-scrollbar {width: 6px}
|
||||
nav#pep-sidebar::-webkit-scrollbar-track {background: transparent}
|
||||
nav#pep-sidebar::-webkit-scrollbar-thumb {background: #ccc}
|
||||
nav#pep-sidebar > h2 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
nav#pep-sidebar ul {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
nav#pep-sidebar ul a {
|
||||
text-decoration: none;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
{# Master template for simple pages (e.g. RST files) #}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ title + " | "|safe + docstitle }}</title>
|
||||
<link rel="shortcut icon" href="{{ pathto('_static/py.png', resource=True) }}"/>
|
||||
<link rel="stylesheet" href="{{ pathto('_static/style.css', resource=True) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/mq.css', resource=True) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', resource=True) }}" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
|
||||
<meta name="description" content="Python Enhancement Proposals (PEPs)"/>
|
||||
</head>
|
||||
<body>
|
||||
<section id="pep-page-section">
|
||||
<header>
|
||||
<h1>Python Enhancement Proposals</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||||
<li><a href="{{ pathto("pep-0000") }}">PEP Index</a> » </li>
|
||||
<li>{{ title }}</li>
|
||||
</ul>
|
||||
</header>
|
||||
<article>
|
||||
{{ body }}
|
||||
</article>
|
||||
<nav id="pep-sidebar">
|
||||
<h2>Contents</h2>
|
||||
{{ toc }}
|
||||
<br />
|
||||
<strong><a href="https://github.com/python/peps/blob/master/{{sourcename}}">Page Source (GitHub)</a></strong>
|
||||
</nav>
|
||||
</section>
|
||||
<script src="{{ pathto('_static/doctools.js', resource=True) }}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
[theme]
|
||||
# Theme options
|
||||
inherit = none
|
||||
pygments_style = tango
|
Loading…
Reference in New Issue