From 1d9d0e068031497c969fbc686ffc831aa3596132 Mon Sep 17 00:00:00 2001 From: Silviu Bogan Date: Mon, 5 Oct 2026 20:04:32 +0300 Subject: [PATCH 1/3] New Sphinx extension for syntax for getting the latest version of a repo - currently the syntax is not used anywhere - improve formatting in addMetaData.py --- docs/addMetaData.py | 7 +-- docs/conf.py | 17 ++++---- docs/latest_gh_version_substitution.py | 60 ++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 docs/latest_gh_version_substitution.py diff --git a/docs/addMetaData.py b/docs/addMetaData.py index 5529c81a72..008de0f3ba 100644 --- a/docs/addMetaData.py +++ b/docs/addMetaData.py @@ -1,5 +1,6 @@ -import os import logging +import os + metadata_check = """--- myst: """ @@ -39,5 +40,5 @@ logger.info(f"{filename} html_meta prepended.") else: count_files["unmodified"] += 1 -logger.info(f'html_meta snippet added to {count_files["modified"]} files.') -logger.info(f'{count_files["unmodified"]} files unmodified.') +logger.info(f"html_meta snippet added to {count_files['modified']} files.") +logger.info(f"{count_files['unmodified']} files unmodified.") diff --git a/docs/conf.py b/docs/conf.py index e1619ddedc..a33939262c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,16 +4,16 @@ # -- Path setup -------------------------------------------------------------- -import re -from datetime import datetime - # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath(".")) +import os +import re +import sys +from datetime import datetime, timezone + +sys.path.insert(0, os.path.abspath(".")) # -- Project information ----------------------------------------------------- @@ -22,7 +22,7 @@ copyright = "Plone Foundation" author = "Plone community" trademark_name = "Plone" -now = datetime.now() +now = datetime.now(timezone.utc) year = str(now.year) # The version info for the project you're documenting, acts as replacement for @@ -44,6 +44,7 @@ # They can be extensions coming with Sphinx (named "sphinx.ext.*") # or your custom ones. extensions = [ + "latest_gh_version_substitution", "myst_parser", "notfound.extension", "sphinx.ext.autodoc", @@ -276,7 +277,7 @@ # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = "%(project)s v%(release)s" % {"project": project, "release": release} +html_title = f"{project} v{release}" html_css_files = ["search.css", ("print.css", {"media": "print"})] html_js_files = [] diff --git a/docs/latest_gh_version_substitution.py b/docs/latest_gh_version_substitution.py new file mode 100644 index 0000000000..411e05d5d5 --- /dev/null +++ b/docs/latest_gh_version_substitution.py @@ -0,0 +1,60 @@ +# The latest stable version name of a GitHub repo is available in the docs +# through a special syntax: {{ version gh_owner/gh_repo_name }}. +# The version is found only at build time. For a given repo used in the docs, +# the latest version is found only once because we cache the version name. + +import json +import re +import urllib +import urllib.request as req + +gh_version_cache = {} + + +def sub_replace_func(match): + owner = match.group("owner") + repo = match.group("repo") + name = f"{owner}/{repo}" + if name not in gh_version_cache: + gh_version_cache[name] = latest_release_for_github_repo(name) + return gh_version_cache[name] + + +sub_pattern = ( + r"(?\S+)\/(?P\S+)(\s*)\}\}(?!\}\})" +) + + +def latest_gh_replace(app, docname, source): + result = source[0] + result = re.sub(sub_pattern, sub_replace_func, result) + source[0] = result + + +def latest_gh_include_replace(app, relative_path, parent_docname, content): + return latest_gh_replace(app, parent_docname, content) + + +def latest_release_for_github_repo(repo): + latest_release_url = "https://api.github.com/repos/" + repo + "/releases/latest" + try: + with req.urlopen(latest_release_url) as response: + commit = json.load(response) + return commit["name"] + except urllib.error.HTTPError as e: + # Handles HTTP errors (e.g., 404, 500) + print(f"HTTP Error: {e.code} - {e.reason}") + except urllib.error.URLError as e: + # Handles URL errors (e.g., DNS failure, refused connection) + print(f"URL Error: {e.reason}") + except TimeoutError: + # Handles timeout specifically + print("Request timed out.") + + +def setup(app): + app.connect("source-read", latest_gh_replace) + app.connect("include-read", latest_gh_include_replace) + return { + "version": "1.0.0", + } From 477cf9ffcb647a5f0772371cc73ec4976816bec1 Mon Sep 17 00:00:00 2001 From: Silviu Bogan Date: Tue, 6 Oct 2026 06:26:09 +0300 Subject: [PATCH 2/3] Fix typo & gitignore *.pyc --- .gitignore | 2 ++ docs/backend/fields.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 452db68f49..cfea646819 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ docs/volto # editor files .vscode + +*.pyc diff --git a/docs/backend/fields.md b/docs/backend/fields.md index b3c2212c8a..ec3ea1c8c6 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -85,7 +85,7 @@ The following tables describe the most commonly used field types, grouped by the | `Timedelta` | `timedelta` | Stores a Python `timedelta`. | `IField`, `IMinMax` | | `SourceText` | `unicode` | A text field intended to store source text, such as HTML or Python code. | `IField`, `IMinMaxLen` | | `Object` | n/a | Stores a Python object that conforms to the interface given as the `schema`. There is no standard widget for this. | `IField`, `IObject` | -| `URI` | `str` | A URI (URL) string. | `IField`, `MinMaxLen` | +| `URI` | `str` | A URI (URL) string. | `IField`, `IMinMaxLen` | | `Id` | `str` | A unique identifier, either a URI or a dotted name. | `IField`, `IMinMaxLen` | | `DottedName` | `str` | A dotted name string. | `IField`, `IMinMaxLen` | | `InterfaceField` | `Interface` | A Zope interface. | `IField` | From bfbd071bc0d84cd76dd5df6f896369ea45bdc57e Mon Sep 17 00:00:00 2001 From: Silviu Bogan Date: Sat, 17 Oct 2026 03:07:55 +0300 Subject: [PATCH 3/3] Use package collective-sphinxextexternalpackageversion & run Ruff --- docs/conf.py | 14 +++--- docs/latest_gh_version_substitution.py | 60 -------------------------- requirements.txt | 1 + 3 files changed, 8 insertions(+), 67 deletions(-) delete mode 100644 docs/latest_gh_version_substitution.py diff --git a/docs/conf.py b/docs/conf.py index 14877bd8a0..71eef7aa3f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,7 +11,7 @@ import os import re import sys -from datetime import datetime, timezone +from datetime import UTC, datetime sys.path.insert(0, os.path.abspath(".")) @@ -22,7 +22,7 @@ copyright = "Plone Foundation" author = "Plone community" trademark_name = "Plone" -now = datetime.now(timezone.utc) +now = datetime.now(UTC) year = str(now.year) # The version info for the project you're documenting, acts as replacement for @@ -44,7 +44,7 @@ # They can be extensions coming with Sphinx (named "sphinx.ext.*") # or your custom ones. extensions = [ - "latest_gh_version_substitution", + "collective.sphinxextexternalpackageversion", "myst_parser", "notfound.extension", "sphinx.ext.autodoc", @@ -100,17 +100,17 @@ r"https://github.com/plone/documentation/issues/new", r"https://javascript.plainenglish.io/you-dont-need-lodash-how-i-gave-up-lodash-693c8b96a07c", # Ignore pages that are rate limited or otherwise blocked - r"https://codesandbox.io/", #volto + r"https://codesandbox.io/", # volto r"https://docutils.sourceforge.io/", r"https://flaviocopes.com", # volto r"https://hosted.weblate.org/", r"https://medium.com", - r"https://stackoverflow.com", #volto - r"https://v5.reactrouter.com", #volto + r"https://stackoverflow.com", # volto + r"https://v5.reactrouter.com", # volto r"https://web.archive.org/", r"https://www.gnu.org", r"https://www.merriam-webster.com/", - r"https://www.npmjs.com", #volto + r"https://www.npmjs.com", # volto # Bad TLS certificate r"https://pastanaga.io", # See https://github.com/plone/volto/issues/8399 # Ignore redirects and rate limiting by github.com diff --git a/docs/latest_gh_version_substitution.py b/docs/latest_gh_version_substitution.py deleted file mode 100644 index 411e05d5d5..0000000000 --- a/docs/latest_gh_version_substitution.py +++ /dev/null @@ -1,60 +0,0 @@ -# The latest stable version name of a GitHub repo is available in the docs -# through a special syntax: {{ version gh_owner/gh_repo_name }}. -# The version is found only at build time. For a given repo used in the docs, -# the latest version is found only once because we cache the version name. - -import json -import re -import urllib -import urllib.request as req - -gh_version_cache = {} - - -def sub_replace_func(match): - owner = match.group("owner") - repo = match.group("repo") - name = f"{owner}/{repo}" - if name not in gh_version_cache: - gh_version_cache[name] = latest_release_for_github_repo(name) - return gh_version_cache[name] - - -sub_pattern = ( - r"(?\S+)\/(?P\S+)(\s*)\}\}(?!\}\})" -) - - -def latest_gh_replace(app, docname, source): - result = source[0] - result = re.sub(sub_pattern, sub_replace_func, result) - source[0] = result - - -def latest_gh_include_replace(app, relative_path, parent_docname, content): - return latest_gh_replace(app, parent_docname, content) - - -def latest_release_for_github_repo(repo): - latest_release_url = "https://api.github.com/repos/" + repo + "/releases/latest" - try: - with req.urlopen(latest_release_url) as response: - commit = json.load(response) - return commit["name"] - except urllib.error.HTTPError as e: - # Handles HTTP errors (e.g., 404, 500) - print(f"HTTP Error: {e.code} - {e.reason}") - except urllib.error.URLError as e: - # Handles URL errors (e.g., DNS failure, refused connection) - print(f"URL Error: {e.reason}") - except TimeoutError: - # Handles timeout specifically - print("Request timed out.") - - -def setup(app): - app.connect("source-read", latest_gh_replace) - app.connect("include-read", latest_gh_include_replace) - return { - "version": "1.0.0", - } diff --git a/requirements.txt b/requirements.txt index 994eea9cfb..df835e9fe9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +collective-sphinxextexternalpackageversion linkify-it-py plone-sphinx-theme<2 sphinx<9 # See https://github.com/plone/documentation/issues/2037