Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sphinx - theming #1933

Merged
merged 87 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
6060f77
Add Sphinx Jinja2 custom template bridge
AA-Turner Apr 20, 2021
9b32ce4
Add sphinx theme options and favicon
AA-Turner Apr 20, 2021
2f0875a
Add breadcrumbs template
AA-Turner Apr 20, 2021
6c6da48
Add sidebar template
AA-Turner Apr 20, 2021
9d0ae13
Add search template
AA-Turner Apr 20, 2021
8392119
Add main layout template override
AA-Turner Apr 20, 2021
57673a1
Add javascript overrides
AA-Turner Apr 20, 2021
db6bab6
Add fonts and stylesheets
AA-Turner Apr 20, 2021
76acf20
Add PEP override styles
AA-Turner Apr 20, 2021
e81b54b
Disable search
AA-Turner May 7, 2021
079abff
Control included JavaScript in templates
AA-Turner May 7, 2021
6a9ba7d
Remove old JS (search related)
AA-Turner May 7, 2021
74a7cd2
Add theme config
AA-Turner Jun 12, 2021
f501f61
Update layout.html template to remove inheritance
AA-Turner Jun 12, 2021
222d641
Move layout.html to page.html
AA-Turner Jun 12, 2021
514fea5
Add body jinja code
AA-Turner Jun 12, 2021
13606da
Remove unneeded block
AA-Turner Jun 12, 2021
f1d4971
Remove doc relations functionality
AA-Turner Jun 12, 2021
dc491ee
Use google fonts, remove local files
AA-Turner Jun 12, 2021
b8ef2d4
Move templates folder so as not to include in built static files
AA-Turner Jun 12, 2021
1975119
Remove PEPTemplateLoader as the `pep_id` filter is not used
AA-Turner Jun 12, 2021
57ee102
Remove breadcrumbs.html
AA-Turner Jun 12, 2021
c707253
Move static CSS and JavaScript one level up
AA-Turner Jun 12, 2021
b9475dd
Run PurgeCSS
AA-Turner Jun 12, 2021
0c5b30d
Remove more unused selectors
AA-Turner Jun 12, 2021
6342abd
Remove more unused selectors / prefixes
AA-Turner Jun 13, 2021
5077817
Start to rearrange and de-duplicate
AA-Turner Jun 13, 2021
fbbdbef
Continue removing, also consolidate some classes
AA-Turner Jun 13, 2021
aa6ea5a
More grouping & rearranging
AA-Turner Jun 13, 2021
0687404
Fix parsing for definition list
AA-Turner Jun 13, 2021
2271fc9
Clean up code and blockquote rules
AA-Turner Jun 13, 2021
56f6949
Add explicit CSS overrides file
AA-Turner Jun 13, 2021
eb48d34
Move blockquote style to overrides
AA-Turner Jun 13, 2021
56204ba
Update code style
AA-Turner Jun 13, 2021
69fbe9d
Header styles
AA-Turner Jun 13, 2021
ef1d0b0
Update breadcrumbs and move .text rules to groups
AA-Turner Jun 13, 2021
77b16d4
Move hyphenation to explicit overrides
AA-Turner Jun 13, 2021
ddcc4ab
Move bottom margin & line height to explicit overrides
AA-Turner Jun 13, 2021
d0fec5c
Update monospace fonts
AA-Turner Jun 13, 2021
83a3229
Make style-pydotorg-compat.css standalone
AA-Turner Jun 13, 2021
f55dcec
Fix footer metadata display
AA-Turner Jun 13, 2021
3024a5d
Improve PEPContents, use HTML title elements and use self-backlinks
AA-Turner Jun 13, 2021
121b119
Adjust header styles
AA-Turner Jun 13, 2021
535d3c3
Adjust admonitions
AA-Turner Jun 13, 2021
16a650f
Adjust definition lists
AA-Turner Jun 13, 2021
22789d0
Add comments
AA-Turner Jun 13, 2021
2806db9
Reorder rule groups (mostly) alphabetically
AA-Turner Jun 13, 2021
df66b2d
Use rem units
AA-Turner Jun 13, 2021
35a9dd7
Merge pep.css and style.css
AA-Turner Jun 13, 2021
9c86b52
Remove main legacy CSS reset
AA-Turner Jun 13, 2021
b3bdbe8
Remove some print rules
AA-Turner Jun 13, 2021
16e1968
Remove media query rules with non-existent targets
AA-Turner Jun 13, 2021
a862d40
Update media queries & breakpoints
AA-Turner Jun 13, 2021
1f26fb4
Remove two levels of div elements
AA-Turner Jun 13, 2021
5357af5
Move print to mq.css
AA-Turner Jun 13, 2021
1db6b5d
Use <link /> tag for fonts, not CSS import
AA-Turner Jun 13, 2021
9a0064e
Fix indentation error from RST conversion
AA-Turner Jun 13, 2021
9eae911
Remove duplicate table of contents
AA-Turner Jun 13, 2021
54fdfc2
Fix footnote fixing
AA-Turner Jun 13, 2021
c766f77
Use tango pygments style
AA-Turner Jun 13, 2021
e1fa5c1
Update page header
AA-Turner Jun 13, 2021
b8fcf1a
Add border to PEP header table
AA-Turner Jun 13, 2021
616976e
Remove compat file
AA-Turner Jun 13, 2021
76c3670
Merge customsidebar.html into page.html
AA-Turner Jun 13, 2021
3de7610
Disambiguate and rename pep theme as such
AA-Turner Jun 13, 2021
ecd1074
Handle index file for directory and file building
AA-Turner Jun 13, 2021
99027b5
Change footer metadata to paragraphs from spans
AA-Turner Jun 14, 2021
1c82ea8
Simplify new title node logic
AA-Turner Jun 14, 2021
256f807
Update & further simplify styles
AA-Turner Jun 14, 2021
e0027e5
Add notes on colours used
AA-Turner Jun 14, 2021
2ca667e
Update admonition colours
AA-Turner Jun 15, 2021
0ded9fd
Simplify the mask email algorithm
AA-Turner Jun 15, 2021
ed1d6cd
Stop using .settings.pep_base_url in various places
AA-Turner Jun 15, 2021
1905480
Remove unneeded escapes in page.html
AA-Turner Jun 15, 2021
a4ca92e
Add clean up step for deployments
AA-Turner Jun 15, 2021
8c3daaa
Update selectors for sphinx 4
AA-Turner Jun 16, 2021
b968c1a
Register PEPTranslator for dirhtml builder
AA-Turner Jun 16, 2021
ae433d1
Add meta description
AA-Turner Jun 16, 2021
029ad2e
Update config values dependent on builder used
AA-Turner Jun 16, 2021
cda149f
Update create_index_file for multiple builders
AA-Turner Jun 16, 2021
d5a5e7e
Fix sidebar position
AA-Turner Jun 16, 2021
8d66f82
Update margins
AA-Turner Jun 18, 2021
e52b0da
Reduce padding and margins for smaller screens
AA-Turner Jun 21, 2021
e98760d
Update pep_sphinx_extensions/pep_processor/transforms/pep_contents.py
AA-Turner Jun 29, 2021
bc3d560
Remove recursion check in Contents
AA-Turner Jun 29, 2021
ab8c2c1
Fix literal markup in PEP titles
AA-Turner Jun 30, 2021
792e013
Remove extraneous links within section titles
AA-Turner Jun 30, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/deploy-gh-pages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
17 changes: 11 additions & 6 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import argparse
from pathlib import Path
import shutil

from sphinx.application import Sphinx

Expand All @@ -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__":
Expand Down Expand Up @@ -67,7 +71,8 @@ def create_index_file(html_root: Path):
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 changes: 11 additions & 1 deletion conf.py
Original file line number Diff line number Diff line change
@@ -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()))

Expand Down Expand Up @@ -44,3 +44,13 @@
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`
9 changes: 3 additions & 6 deletions pep-0310.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
=========
Expand Down
4 changes: 2 additions & 2 deletions pep-0439.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 0 additions & 18 deletions pep-3143.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
============
Expand Down
16 changes: 15 additions & 1 deletion pep_sphinx_extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
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
Expand All @@ -26,19 +28,31 @@
"_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
Expand Down
7 changes: 3 additions & 4 deletions pep_sphinx_extensions/pep_processor/parsing/pep_role.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
from sphinx import roles

from pep_sphinx_extensions.config import pep_url
from pep_sphinx_extensions import config


class PEPRole(roles.PEP):
"""Override the :pep: role"""

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
62 changes: 39 additions & 23 deletions pep_sphinx_extensions/pep_processor/transforms/pep_contents.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from pathlib import Path

from docutils import nodes
Expand All @@ -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()
Expand All @@ -37,27 +38,42 @@ def apply(self) -> None:

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
self.toc_id = None
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 []
72 changes: 36 additions & 36 deletions pep_sphinx_extensions/pep_processor/transforms/pep_footer.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,43 +69,43 @@ def apply(self) -> None:

# 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)

@staticmethod
def cleanup_callback(pending: nodes.pending) -> None:
"""Remove an empty "References" section.

Called after the `references.TargetNotes` transform is complete.

"""
if len(pending.parent) == 2: # <title> and <pending>
pending.parent.parent.remove(pending.parent)

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)

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)
if pep_source_path.stem != "pep-0000":
self.document += _add_source_link(pep_source_path)
self.document += _add_commit_history_info(pep_source_path)


def _cleanup_callback(pending: nodes.pending) -> None:
"""Remove an empty "References" section.

Called after the `references.TargetNotes` transform is complete.

"""
if len(pending.parent) == 2: # <title> and <pending>
pending.parent.parent.remove(pending.parent)


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)
Loading