summaryrefslogtreecommitdiff
path: root/tools/lib/python/abi
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2026-01-23 11:46:08 -0700
committerJonathan Corbet <corbet@lwn.net>2026-01-23 11:46:08 -0700
commit330367bdc176a8f52cc4c5065ba0312277202dee (patch)
tree4e7965522177b29a5f51c3fb85f285e8b69585ff /tools/lib/python/abi
parentffb569d59c253399efb2345ddfefe7929cd7e2a8 (diff)
parentef6aa110d8888a14dfb2e843794097263c45a06b (diff)
Merge branch 'mauro' into docs-mw
Mauro's work to include documentation from our Python modules. His cover letter follows: This is an extended version of: https://lore.kernel.org/linux-doc/cover.1768488832.git.mchehab+huawei@kernel.org/ It basically adds everything we currently have inside libs/tool/python to "tools" book inside documentation. This version should be independent of the other series yet to be merged, (including the jobserver one). The vast amount of changes here are docstring cleanups and additions. They mainly consists on: - ensuring that every phrase will end with a period, making it uniform along all files; - cleaning ups to better uniform docstrings; - variable descriptions now use "#:" markup, as it allows autodoc to add them inside the documentation; - added some missing docstrings; - some new blank lines at comments to make ReST syntax parser happy; - add a couple of sphinx markups (mainly, code blocks). Most of those are minor changes, affecting only comments. It also has one patch per libarary type, adding them to docs. For kernel-doc, I did the cleanups first, as there is one code block inside tools/lib/python/kdoc/latex_fonts.py that would cause a Sphinx crash without such markups. The series actually starts with 3 fixes: - avoid "*" markups on indexes with deep> 3 to override text - a variable rename to stop abusing doctree name - don't rely on cwd to get Documentation/ location patch 4 adds support to document scripts either at: - tools/ - scripts/ patch 5 contains a CSS to better display autodoc html output. For those who want to play with documentation, documenting a python file is very simple. All it takes is to use: .. automodule:: lib.python.<dir+name> Usually, we add a couple of control members to it to adjust the desired documentation scope (add/remove members, showing class inheritance, showing members that currently don't have docstrings, etc). That's why we're using: .. automodule:: lib.python.kdoc.enrich_formatter :members: :show-inheritance: :undoc-members: (and similar) inside tools/kdoc*.rst. autodoc allows filtering in/out members, file docstrings, etc. It also allows documenting just some members or functions with directives like: ..autofunction: ..automember: Sphinx also has a helper script to generate .rst files with documentation: $ sphinx-apidoc -o foobar tools/lib/python/ which can be helpful to discover what should be documented, although changes are needed to use what it produces.
Diffstat (limited to 'tools/lib/python/abi')
-rw-r--r--tools/lib/python/abi/abi_parser.py33
-rw-r--r--tools/lib/python/abi/abi_regex.py26
-rw-r--r--tools/lib/python/abi/helpers.py42
-rw-r--r--tools/lib/python/abi/system_symbols.py14
4 files changed, 67 insertions, 48 deletions
diff --git a/tools/lib/python/abi/abi_parser.py b/tools/lib/python/abi/abi_parser.py
index 9b8db70067ef..d7bb20ef3acc 100644
--- a/tools/lib/python/abi/abi_parser.py
+++ b/tools/lib/python/abi/abi_parser.py
@@ -21,14 +21,17 @@ from abi.helpers import AbiDebug, ABI_DIR
class AbiParser:
- """Main class to parse ABI files"""
+ """Main class to parse ABI files."""
+ #: Valid tags at Documentation/ABI.
TAGS = r"(what|where|date|kernelversion|contact|description|users)"
+
+ #: ABI elements that will auto-generate cross-references.
XREF = r"(?:^|\s|\()(\/(?:sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)(?:[,.:;\)\s]|\Z)"
def __init__(self, directory, logger=None,
enable_lineno=False, show_warnings=True, debug=0):
- """Stores arguments for the class and initialize class vars"""
+ """Stores arguments for the class and initialize class vars."""
self.directory = directory
self.enable_lineno = enable_lineno
@@ -65,7 +68,7 @@ class AbiParser:
self.re_xref_node = re.compile(self.XREF)
def warn(self, fdata, msg, extra=None):
- """Displays a parse error if warning is enabled"""
+ """Displays a parse error if warning is enabled."""
if not self.show_warnings:
return
@@ -77,7 +80,7 @@ class AbiParser:
self.log.warning(msg)
def add_symbol(self, what, fname, ln=None, xref=None):
- """Create a reference table describing where each 'what' is located"""
+ """Create a reference table describing where each 'what' is located."""
if what not in self.what_symbols:
self.what_symbols[what] = {"file": {}}
@@ -92,7 +95,7 @@ class AbiParser:
self.what_symbols[what]["xref"] = xref
def _parse_line(self, fdata, line):
- """Parse a single line of an ABI file"""
+ """Parse a single line of an ABI file."""
new_what = False
new_tag = False
@@ -264,7 +267,7 @@ class AbiParser:
self.warn(fdata, "Unexpected content", line)
def parse_readme(self, nametag, fname):
- """Parse ABI README file"""
+ """Parse ABI README file."""
nametag["what"] = ["Introduction"]
nametag["path"] = "README"
@@ -282,7 +285,7 @@ class AbiParser:
nametag["description"] += line
def parse_file(self, fname, path, basename):
- """Parse a single file"""
+ """Parse a single file."""
ref = f"abi_file_{path}_{basename}"
ref = self.re_unprintable.sub("_", ref).strip("_")
@@ -348,7 +351,7 @@ class AbiParser:
self.add_symbol(what=w, fname=fname, xref=fdata.key)
def _parse_abi(self, root=None):
- """Internal function to parse documentation ABI recursively"""
+ """Internal function to parse documentation ABI recursively."""
if not root:
root = self.directory
@@ -377,7 +380,7 @@ class AbiParser:
self.parse_file(name, path, basename)
def parse_abi(self, root=None):
- """Parse documentation ABI"""
+ """Parse documentation ABI."""
self._parse_abi(root)
@@ -385,7 +388,7 @@ class AbiParser:
self.log.debug(pformat(self.data))
def desc_txt(self, desc):
- """Print description as found inside ABI files"""
+ """Print description as found inside ABI files."""
desc = desc.strip(" \t\n")
@@ -393,7 +396,7 @@ class AbiParser:
def xref(self, fname):
"""
- Converts a Documentation/ABI + basename into a ReST cross-reference
+ Converts a Documentation/ABI + basename into a ReST cross-reference.
"""
xref = self.file_refs.get(fname)
@@ -403,7 +406,7 @@ class AbiParser:
return xref
def desc_rst(self, desc):
- """Enrich ReST output by creating cross-references"""
+ """Enrich ReST output by creating cross-references."""
# Remove title markups from the description
# Having titles inside ABI files will only work if extra
@@ -459,7 +462,7 @@ class AbiParser:
def doc(self, output_in_txt=False, show_symbols=True, show_file=True,
filter_path=None):
- """Print ABI at stdout"""
+ """Print ABI at stdout."""
part = None
for key, v in sorted(self.data.items(),
@@ -549,7 +552,7 @@ class AbiParser:
yield (msg, file_ref[0][0], ln)
def check_issues(self):
- """Warn about duplicated ABI entries"""
+ """Warn about duplicated ABI entries."""
for what, v in self.what_symbols.items():
files = v.get("file")
@@ -575,7 +578,7 @@ class AbiParser:
self.log.warning("%s is defined %d times: %s", what, len(f), "; ".join(f))
def search_symbols(self, expr):
- """ Searches for ABI symbols """
+ """ Searches for ABI symbols."""
regex = re.compile(expr, re.I)
diff --git a/tools/lib/python/abi/abi_regex.py b/tools/lib/python/abi/abi_regex.py
index d5553206de3c..d0c5e3ede6b5 100644
--- a/tools/lib/python/abi/abi_regex.py
+++ b/tools/lib/python/abi/abi_regex.py
@@ -16,10 +16,22 @@ from abi.abi_parser import AbiParser
from abi.helpers import AbiDebug
class AbiRegex(AbiParser):
- """Extends AbiParser to search ABI nodes with regular expressions"""
+ """
+ Extends AbiParser to search ABI nodes with regular expressions.
- # Escape only ASCII visible characters
+ There some optimizations here to allow a quick symbol search:
+ instead of trying to place all symbols altogether an doing linear
+ search which is very time consuming, create a tree with one depth,
+ grouping similar symbols altogether.
+
+ Yet, sometimes a full search will be needed, so we have a special branch
+ on such group tree where other symbols are placed.
+ """
+
+ #: Escape only ASCII visible characters.
escape_symbols = r"([\x21-\x29\x2b-\x2d\x3a-\x40\x5c\x60\x7b-\x7e])"
+
+ #: Special group for other nodes.
leave_others = "others"
# Tuples with regular expressions to be compiled and replacement data
@@ -88,13 +100,15 @@ class AbiRegex(AbiParser):
# Recover plus characters
(re.compile(r"\xf7"), "+"),
]
+
+ #: Regex to check if the symbol name has a number on it.
re_has_num = re.compile(r"\\d")
- # Symbol name after escape_chars that are considered a devnode basename
+ #: Symbol name after escape_chars that are considered a devnode basename.
re_symbol_name = re.compile(r"(\w|\\[\.\-\:])+$")
- # List of popular group names to be skipped to minimize regex group size
- # Use AbiDebug.SUBGROUP_SIZE to detect those
+ #: List of popular group names to be skipped to minimize regex group size
+ #: Use AbiDebug.SUBGROUP_SIZE to detect those.
skip_names = set(["devices", "hwmon"])
def regex_append(self, what, new):
@@ -148,7 +162,7 @@ class AbiRegex(AbiParser):
def get_regexes(self, what):
"""
Given an ABI devnode, return a list of all regular expressions that
- may match it, based on the sub-groups created by regex_append()
+ may match it, based on the sub-groups created by regex_append().
"""
re_list = []
diff --git a/tools/lib/python/abi/helpers.py b/tools/lib/python/abi/helpers.py
index 639b23e4ca33..2a378d780d3c 100644
--- a/tools/lib/python/abi/helpers.py
+++ b/tools/lib/python/abi/helpers.py
@@ -13,26 +13,28 @@ ABI_DIR = "Documentation/ABI/"
class AbiDebug:
"""Debug levels"""
- WHAT_PARSING = 1
- WHAT_OPEN = 2
- DUMP_ABI_STRUCTS = 4
- UNDEFINED = 8
- REGEX = 16
- SUBGROUP_MAP = 32
- SUBGROUP_DICT = 64
- SUBGROUP_SIZE = 128
- GRAPH = 256
-
+ WHAT_PARSING = 1 #: Enable debug parsing logic.
+ WHAT_OPEN = 2 #: Enable debug messages on file open.
+ DUMP_ABI_STRUCTS = 4 #: Enable debug for ABI parse data.
+ UNDEFINED = 8 #: Enable extra undefined symbol data.
+ REGEX = 16 #: Enable debug for what to regex conversion.
+ SUBGROUP_MAP = 32 #: Enable debug for symbol regex subgroups
+ SUBGROUP_DICT = 64 #: Enable debug for sysfs graph tree variable.
+ SUBGROUP_SIZE = 128 #: Enable debug of search groups.
+ GRAPH = 256 #: Display ref tree graph for undefined symbols.
+#: Helper messages for each debug variable
DEBUG_HELP = """
-1 - enable debug parsing logic
-2 - enable debug messages on file open
-4 - enable debug for ABI parse data
-8 - enable extra debug information to identify troubles
- with ABI symbols found at the local machine that
- weren't found on ABI documentation (used only for
- undefined subcommand)
-16 - enable debug for what to regex conversion
-32 - enable debug for symbol regex subgroups
-64 - enable debug for sysfs graph tree variable
+1 - enable debug parsing logic
+2 - enable debug messages on file open
+4 - enable debug for ABI parse data
+8 - enable extra debug information to identify troubles
+ with ABI symbols found at the local machine that
+ weren't found on ABI documentation (used only for
+ undefined subcommand)
+16 - enable debug for what to regex conversion
+32 - enable debug for symbol regex subgroups
+64 - enable debug for sysfs graph tree variable
+128 - enable debug of search groups
+256 - enable displaying refrence tree graphs for undefined symbols.
"""
diff --git a/tools/lib/python/abi/system_symbols.py b/tools/lib/python/abi/system_symbols.py
index 4a2554da217b..7bbefd274ea2 100644
--- a/tools/lib/python/abi/system_symbols.py
+++ b/tools/lib/python/abi/system_symbols.py
@@ -18,11 +18,11 @@ from random import shuffle
from abi.helpers import AbiDebug
class SystemSymbols:
- """Stores arguments for the class and initialize class vars"""
+ """Stores arguments for the class and initialize class vars."""
def graph_add_file(self, path, link=None):
"""
- add a file path to the sysfs graph stored at self.root
+ add a file path to the sysfs graph stored at self.root.
"""
if path in self.files:
@@ -43,7 +43,7 @@ class SystemSymbols:
self.files.add(path)
def print_graph(self, root_prefix="", root=None, level=0):
- """Prints a reference tree graph using UTF-8 characters"""
+ """Prints a reference tree graph using UTF-8 characters."""
if not root:
root = self.root
@@ -173,7 +173,7 @@ class SystemSymbols:
self._walk(sysfs)
def check_file(self, refs, found):
- """Check missing ABI symbols for a given sysfs file"""
+ """Check missing ABI symbols for a given sysfs file."""
res_list = []
@@ -214,7 +214,7 @@ class SystemSymbols:
return res_list
def _ref_interactor(self, root):
- """Recursive function to interact over the sysfs tree"""
+ """Recursive function to interact over the sysfs tree."""
for k, v in root.items():
if isinstance(v, dict):
@@ -232,7 +232,7 @@ class SystemSymbols:
def get_fileref(self, all_refs, chunk_size):
- """Interactor to group refs into chunks"""
+ """Interactor to group refs into chunks."""
n = 0
refs = []
@@ -250,7 +250,7 @@ class SystemSymbols:
def check_undefined_symbols(self, max_workers=None, chunk_size=50,
found=None, dry_run=None):
- """Seach ABI for sysfs symbols missing documentation"""
+ """Seach ABI for sysfs symbols missing documentation."""
self.abi.parse_abi()