Sphinx 7.x and python3.11 support

This commit is contained in:
Kujiu 2023-08-03 15:32:01 +02:00
parent 4236146717
commit 4587c8c17d
Signed by: kujiu
GPG key ID: ABBB2CAC6855599F
5 changed files with 200 additions and 89 deletions

View file

@ -2,6 +2,11 @@
Changes Changes
======= =======
2.0.0 (*2023-08-02*)
====================
- Sphinx 7.x compatibility
1.0.0 (*2021-06-06*) 1.0.0 (*2021-06-06*)
==================== ====================

97
pyproject.toml Normal file
View file

@ -0,0 +1,97 @@
[build-system]
requires = ["flit_core>=3.2"]
build-backend = "flit_core.buildapi"
[project]
name = "sphinx_fasvg"
version = "2.0.0"
requires-python = ">=3.8"
dependencies = [
"Sphinx>=7.0.0"
]
license = {text = "EUPL-1.2"}
authors = [
{name = "Nerv Project ASBL", email = "contact@nerv-project.eu"},
{name = "kujiu"},
{name = "ptitgnu"}
]
maintainers = [
{name = "Nerv Project ASBL", email = "contact@nerv-project.eu"},
{name = "kujiu"},
{name = "ptitgnu"}
]
description = "A Sphinx fontawesome wrapper for SVG format"
readme = {file = "README.rst", content-type = "text/x-rst"}
keywords=["sphinx", "doc", "theme"]
classifiers=[
"Framework :: Sphinx",
"Framework :: Sphinx :: Theme",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
"Environment :: Console",
"Environment :: Web Environment",
"Framework :: Sphinx :: Theme",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Topic :: Documentation",
"Topic :: Software Development :: Documentation",
]
[project.urls]
homepage = "https://www.nerv-project.eu"
repository = "https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg"
issues = "https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg/issues"
editor = "https://www.nerv-project.eu"
changelog = "https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg/raw/branch/main/CHANGES.rst"
[project.optional-dependencies]
tests = [
"pytest",
"flake8",
"pylint",
"pytest-cov"
]
setup = [
"Sphinx",
"pytest-runner",
"flake8",
"pylint",
"babel",
"flit",
]
[project.scripts]
[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-ra -q"
testpaths = [
"tests",
]
[tool.babel.extract_messages]
mapping_file = "babel.cfg"
output_file = "locale/sphinx.pot"
keywords = ["_", "__", "l_", "lazy_gettext", "gettext", "ngettext"]
add_comments = "Translators:"
[tool.babel.init_catalog]
domain = "sphinx"
input_file = "locale/sphinx.pot"
output_dir = "locale/"
[tool.babel.update_catalog]
domain = "sphinx"
input_file = "locale/sphinx.pot"
output_dir = "locale/"
[tool.babel.compile_catalog]
domain = "sphinx"
directory = "locale/"
[tool.flit.sdist]
include = [
"*.py",
]

View file

@ -1,7 +0,0 @@
[metadata]
description-file = README.rst
license-files =
LICENSE
LICENSE-de
LICENSE-fr
LICENSE-nl

View file

@ -1,45 +0,0 @@
from setuptools import setup
with open("README.rst", "r") as fh:
long_description = fh.read()
setup(
name="sphinx_fasvg",
version="1.0.0",
url="https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg",
license="EUPL 1.2",
author="Kujiu",
author_email="kujiu-pypi@kujiu.org",
description="Use font-awesome icons in SVG form",
long_description=long_description,
long_description_content_type="text/x-rst",
packages=["sphinx_fasvg"],
package_data={
"sphinx_fasvg": [
"*.py",
]
},
entry_points={"sphinx.html_themes": ["nervproject = sphinx_nervproject_theme"]},
install_requires=["sphinx>=2.0.0"],
classifiers=[
"Framework :: Sphinx",
"Framework :: Sphinx :: Extension",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Operating System :: OS Independent",
"Topic :: Documentation",
"Topic :: Software Development :: Documentation",
],
keywords="sphinx fontawesome svg",
project_urls={
"Source": "https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg",
"Issues": "https://procrastinator.nerv-project.eu/nerv-project/sphinx_fasvg/issues",
},
)

View file

@ -1,6 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# pylint:disable=invalid-name,unused-argument,too-many-arguments
""" """
Use fontawesome icons Use fontawesome icons
""" """
@ -10,7 +12,7 @@ import uuid
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import Directive from docutils.parsers.rst import Directive
import docutils.parsers.rst.directives as directives from docutils.parsers.rst import directives
from sphinx.writers.html import HTMLTranslator from sphinx.writers.html import HTMLTranslator
from sphinx.writers.latex import LaTeXTranslator from sphinx.writers.latex import LaTeXTranslator
@ -19,19 +21,20 @@ from sphinx.writers.text import TextTranslator
from sphinx.writers.manpage import ManualPageTranslator from sphinx.writers.manpage import ManualPageTranslator
from sphinx.util.osutil import relative_uri from sphinx.util.osutil import relative_uri
__version_info__ = (1, 0, 0) __version_info__ = (2, 0, 0)
__version__ = '.'.join([str(val) for val in __version_info__]) __version__ = '.'.join([str(val) for val in __version_info__])
class fa(nodes.General, nodes.Inline, nodes.Element): class fa(nodes.General, nodes.Inline, nodes.Element):
pass """Generic node for FontAwesome"""
class falink(nodes.General, nodes.Inline, nodes.Element): class falink(nodes.General, nodes.Inline, nodes.Element):
pass """Generic link node for FontAwesome"""
def append_fa_image(self: HTMLTranslator, node: fa or falink) -> None: def append_fa_image(self: HTMLTranslator, node: fa or falink) -> None:
"""Add image to node"""
path = { path = {
'brands': self.builder.config.fa_brands_path, 'brands': self.builder.config.fa_brands_path,
'regular': self.builder.config.fa_regular_path, 'regular': self.builder.config.fa_regular_path,
@ -49,64 +52,71 @@ def append_fa_image(self: HTMLTranslator, node: fa or falink) -> None:
options += ' xmlns="http://www.w3.org/2000/svg"' options += ' xmlns="http://www.w3.org/2000/svg"'
options += ' xmlns:xlink="http://www.w3.org/1999/xlink"' options += ' xmlns:xlink="http://www.w3.org/1999/xlink"'
if node.get('alt', None): if node.get('alt', None):
options += ' aria-labelledby="fa_%s"' % label_uid options += f' aria-labelledby="fa_{label_uid}"'
title = '<title id="%s">%s</title>' % (label_uid, node['alt']) title = f'<title id="{label_uid}">{node["alt"]}</title>'
else: else:
options += ' aria-hidden="true" xlink:title=""' options += ' aria-hidden="true" xlink:title=""'
if node.get('html_id', None): if node.get('html_id', None):
options += ' id="%s"' % node['html_id'] options += f' id={node["html_id"]}'
options += ' class="fasvg %s"' % (node.get('html_class', '') or '') options += f' class="fasvg {node.get("html_class", "") or ""}"'
self.body.append( self.body.append(
'<svg %s>' % options f'<svg {options}>'
) )
if title: if title:
self.body.append(title) self.body.append(title)
self.body.append( self.body.append(
'<use xlink:href="%s#%s"></use></svg>' % (path, node['icon']) f'<use xlink:href="{path}#{node["icon"]}"></use></svg>'
) )
def html_visit_fa(self: HTMLTranslator, node: fa) -> None: def html_visit_fa(self: HTMLTranslator, node: fa) -> None:
"""Rendering FA node in HTML"""
append_fa_image(self, node) append_fa_image(self, node)
raise nodes.SkipNode raise nodes.SkipNode
def latex_visit_fa(self: LaTeXTranslator, node: fa) -> None: def latex_visit_fa(self: LaTeXTranslator, node: fa) -> None:
"""Rendering FA node in LaTeX"""
if 'alt' in node.attributes: if 'alt' in node.attributes:
self.body.append('[%s]' % node['alt']) self.body.append(f'[{node["alt"]}]')
raise nodes.SkipNode raise nodes.SkipNode
def texinfo_visit_fa(self: TexinfoTranslator, node: fa) -> None: def texinfo_visit_fa(self: TexinfoTranslator, node: fa) -> None:
"""Rendering FA node in TeXinfo"""
if 'alt' in node.attributes: if 'alt' in node.attributes:
self.body.append('[%s]' % node['alt']) self.body.append(f'[{node["alt"]}]')
raise nodes.SkipNode raise nodes.SkipNode
def text_visit_fa(self: TextTranslator, node: fa) -> None: def text_visit_fa(self: TextTranslator, node: fa) -> None:
"""Rendering FA node in text"""
if 'alt' in node.attributes: if 'alt' in node.attributes:
self.add_text('[%s]' % node['alt']) self.add_text(f'[{node["alt"]}]')
raise nodes.SkipNode raise nodes.SkipNode
def gemini_visit_fa(self, node: fa) -> None: def gemini_visit_fa(self, node: fa) -> None:
"""Rendering FA node in Gemini"""
if 'alt' in node.attributes: if 'alt' in node.attributes:
self.add_text('[%s]' % node['alt']) self.add_text(f'[{node["alt"]}]')
raise nodes.SkipNode raise nodes.SkipNode
def man_visit_fa(self: ManualPageTranslator, node: fa) -> None: def man_visit_fa(self: ManualPageTranslator, node: fa) -> None:
"""Rendering FA node in Man file"""
if 'alt' in node.attributes: if 'alt' in node.attributes:
self.body.append('[%s]' % node['alt']) self.body.append(f'[{node["alt"]}]')
raise nodes.SkipNode raise nodes.SkipNode
def create_fa_node(iconset, icon, html_id=None, html_class=None, alt=None): def create_fa_node(iconset, icon, html_id=None, html_class=None, alt=None):
"""Create FA node"""
node = fa() node = fa()
node['iconset'] = iconset node['iconset'] = iconset
node['icon'] = icon node['icon'] = icon
@ -117,95 +127,140 @@ def create_fa_node(iconset, icon, html_id=None, html_class=None, alt=None):
def html_visit_falink(self: HTMLTranslator, node: fa) -> None: def html_visit_falink(self: HTMLTranslator, node: fa) -> None:
"""Rendering FA link node in HTML"""
self.body.append( self.body.append(
'<a class="fasvglink %s" href="%s">' % f'<a class="fasvglink {node["icon"]}" href="{node["url"]}">'
(node['icon'], node['url'])) )
append_fa_image(self, node) append_fa_image(self, node)
self.body.append(' %s</a>' % node['text']) self.body.append(f' {node["text"]}</a>')
raise nodes.SkipNode raise nodes.SkipNode
def latex_visit_falink(self: LaTeXTranslator, node: fa) -> None: def latex_visit_falink(self: LaTeXTranslator, node: fa) -> None:
self.body.append('\\href{%s}{%s %s}' % ( """Rendering FA link node in LaTeX"""
node['url'], node['alt'], node['text'])) self.body.append(
f'\\href{{{node["url"]}}}'
f'{{{node["alt"]} {node["text"]}}}'
)
raise nodes.SkipNode raise nodes.SkipNode
def texinfo_visit_falink(self: TexinfoTranslator, node: fa) -> None: def texinfo_visit_falink(self: TexinfoTranslator, node: fa) -> None:
self.body.append('\\href{%s}{%s %s}' % ( """Rendering FA link node in TexInfo"""
node['url'], node['alt'], node['text'])) self.body.append(
f'\\href{{{node["url"]}}}{{{node["alt"]} {node["text"]}}}'
)
raise nodes.SkipNode raise nodes.SkipNode
def text_visit_falink(self: TextTranslator, node: fa) -> None: def text_visit_falink(self: TextTranslator, node: fa) -> None:
self.add_text('%s %s <%s>' % (node['alt'], node['text'], node['url'])) """Rendering FA link node in text"""
self.add_text(
f'{node["alt"]} {node["text"]} <{node["url"]}>'
)
raise nodes.SkipNode raise nodes.SkipNode
def gemini_visit_falink(self, node: fa) -> None: def gemini_visit_falink(self, node: fa) -> None:
"""Rendering FA link node in Gemini"""
self.end_block() self.end_block()
self.add_text('=> %s %s %s' % (node['alt'], node['url'], node['text'])) self.add_text(
f'=> {node["alt"]} {node["url"]} {node["text"]}'
)
self.end_block() self.end_block()
raise nodes.SkipNode raise nodes.SkipNode
def man_visit_falink(self: ManualPageTranslator, node: fa) -> None: def man_visit_falink(self: ManualPageTranslator, node: fa) -> None:
self.body.append('%s %s <%s>' % (node['text'], node['alt'], node['url'])) """Rendering FA link node in Man file"""
self.body.append(f'{node["text"]} {node["alt"]} <{node["url"]}>')
raise nodes.SkipNode raise nodes.SkipNode
def create_falink_node(iconset, text): def create_falink_node(iconset, text):
"""Create a new link node depending of text and iconset"""
node = falink() node = falink()
regex = re.compile( regex = re.compile(
r'(?P<icon>[a-zA-Z-_]*):(?P<text>.*)' r'(?P<icon> *[a-zA-Z-_]* *):(?P<text>.*)'
+ r'(?P<alt>\[.*\] *)<(?P<url>.*)>') + r'(?P<alt>\[.*\] *)?<(?P<url>.*)>')
parsed = regex.search(text) parsed = regex.search(text)
node['iconset'] = iconset node['iconset'] = iconset
node['icon'] = parsed.group('icon') node['icon'] = parsed.group('icon').strip()
node['url'] = parsed.group('url').strip() node['url'] = parsed.group('url').strip()
node['alt'] = (parsed.group('alt') or '').strip().strip('[]') node['alt'] = (parsed.group('alt') or '').strip().strip('[]')
node['text'] = parsed.group('text').strip() node['text'] = parsed.group('text').strip()
return node return node
def fab(role, rawtext, text, lineno, inliner, options={}, content=[]): def fab(role, rawtext, text, lineno, inliner, options=None, content=None):
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)') """Node for FontAwesome brand icon"""
if not options:
options = {}
if not content:
content = []
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)?')
parsed = regex.search(text) parsed = regex.search(text)
alt = (parsed.group('alt') or '').strip().strip('[]') alt = (parsed.group('alt') or '').strip().strip('[]')
icon = parsed.group('icon').strip() icon = parsed.group('icon').strip()
return [create_fa_node('brands', icon, alt=alt)], [] return [create_fa_node('brands', icon, alt=alt)], []
def far(role, rawtext, text, lineno, inliner, options={}, content=[]): def far(role, rawtext, text, lineno, inliner, options=None, content=None):
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)') """Node for FontAwesome regular icon"""
if not options:
options = {}
if not content:
content = []
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)?')
parsed = regex.search(text) parsed = regex.search(text)
alt = (parsed.group('alt') or '').strip().strip('[]') alt = (parsed.group('alt') or '').strip().strip('[]')
icon = parsed.group('icon').strip() icon = parsed.group('icon').strip()
return [create_fa_node('regular', icon, alt=alt)], [] return [create_fa_node('regular', icon, alt=alt)], []
def fas(role, rawtext, text, lineno, inliner, options={}, content=[]): def fas(role, rawtext, text, lineno, inliner, options=None, content=None):
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)') """Node for FontAwesome solid icon"""
if not options:
options = {}
if not content:
content = []
regex = re.compile(r'(?P<icon>[a-zA-Z-_]*)(?P<alt>\[.*\] *)?')
parsed = regex.search(text) parsed = regex.search(text)
alt = (parsed.group('alt') or '').strip().strip('[]') alt = (parsed.group('alt') or '').strip().strip('[]')
icon = parsed.group('icon').strip() icon = parsed.group('icon').strip()
return [create_fa_node('solid', icon, alt=alt)], [] return [create_fa_node('solid', icon, alt=alt)], []
def fablink(role, rawtext, text, lineno, inliner, options={}, content=[]): def fablink(role, rawtext, text, lineno, inliner, options=None, content=None):
"""Node for link with FontAwesome brands iconset"""
if not options:
options = {}
if not content:
content = []
return [create_falink_node('brands', text)], [] return [create_falink_node('brands', text)], []
def farlink(role, rawtext, text, lineno, inliner, options={}, content=[]): def farlink(role, rawtext, text, lineno, inliner, options=None, content=None):
"""Node for link with FontAwesome regular iconset"""
if not options:
options = {}
if not content:
content = []
return [create_falink_node('regular', text)], [] return [create_falink_node('regular', text)], []
def faslink(role, rawtext, text, lineno, inliner, options={}, content=[]): def faslink(role, rawtext, text, lineno, inliner, options=None, content=None):
"""Node for link with FontAwesome solid iconset"""
if not options:
options = {}
if not content:
content = []
return [create_falink_node('solid', text)], [] return [create_falink_node('solid', text)], []
class FaDirective(Directive): class FaDirective(Directive):
""" Main directive for FontAwesome icons """
has_content = False has_content = False
required_arguments = 1 required_arguments = 1
@ -229,18 +284,24 @@ class FaDirective(Directive):
class Fab(FaDirective): class Fab(FaDirective):
""" Directive for FontAwesome brands iconset """
iconset = 'brands' iconset = 'brands'
class Far(FaDirective): class Far(FaDirective):
""" Directive for FontAwesome regular iconset """
iconset = 'regular' iconset = 'regular'
class Fas(FaDirective): class Fas(FaDirective):
""" Directive for FontAwesome solid iconset """
iconset = 'solid' iconset = 'solid'
def setup(app): def setup(app):
"""
Setup Sphinx app
"""
app.add_node( app.add_node(
fa, fa,
html=(html_visit_fa, None), html=(html_visit_fa, None),