From 2fd87049fc1f347aadc9d96ef8dc0d5db543e7dc Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 14 Jul 2025 13:21:33 -0700 Subject: [PATCH 1/8] feat(_ext.lexers): Extract out Regex mixin lexer. Create improved cython lexer. --- docs/source/_ext/lexers.py | 203 +++++++++++++++++++++++++++---------- docs/source/_ext/styles.py | 4 +- 2 files changed, 154 insertions(+), 53 deletions(-) diff --git a/docs/source/_ext/lexers.py b/docs/source/_ext/lexers.py index 9421ff3..c5c4b7e 100644 --- a/docs/source/_ext/lexers.py +++ b/docs/source/_ext/lexers.py @@ -33,13 +33,14 @@ from collections.abc import Iterator from typing import ClassVar -from pygments.lexer import bygroups, include -from pygments.lexers.python import PythonLexer +from pygments.lexer import bygroups, combined, include, words +from pygments.lexers.python import CythonLexer, PythonLexer, RegexLexer from pygments.token import ( Comment, Keyword, Name, Number, + Operator, Punctuation, String, Text, @@ -63,8 +64,63 @@ def inner(a, b) -> bool: return inner -root: list = [ - (r"\n", Whitespace), +class MixinLexer(RegexLexer): + """Regex Mixin Lexer class. + + Notes: + 1. Supports primitive rainbow bracket coloring. + 2. Supports primitive constant declaration (uppercase variables) + + """ + + n_brackets: int + _stack: deque[int] + + def __init__(self, **options) -> None: + self.n_brackets = int(options.pop("n_brackets", 4)) + super().__init__(**options) + self._stack = deque[int]() + + def _enter(self) -> _TokenType: + """Retrieve next token in cycle.""" + idx = len(self._stack) % self.n_brackets + self._stack.append(idx) + + return get_bracket_level(idx) + + def _exit(self) -> _TokenType: + """Remove element from stack and return token.""" + try: + idx: int = self._stack.pop() + return get_bracket_level(idx) + + except IndexError: + return Punctuation.Error + + def get_tokens_unprocessed( + self, + text, + stack=("root",), + ) -> Iterator[tuple[int, _TokenType, str]]: + _token: _TokenType + for idx, token, value in super().get_tokens_unprocessed(text, stack): + _token = token + if token is Name and value.isupper(): + _token = Name.Constant + + elif token is Punctuation: + match value: + case "(" | "[" | "{" | "<": + _token = self._enter() + case "}" | "]" | ")" | ">": + _token = self._exit() + case _: + ... + + yield idx, _token, value + + +docstrings: list = [ ( # single line docstrings (edge case) r'^(\s*)([rRuUbB]{,2})("""(?:.)*?""")', bygroups(Whitespace, String.Affix, String.Doc), @@ -72,20 +128,29 @@ def inner(a, b) -> bool: ( # Modfied triple double quote docstrings to highlight docstring titles r'^(\s*)([rRuUbB]{,2})(""")', bygroups(Whitespace, String.Affix, String.Doc), - "docstring-double", + "docstring-double-quotes", ), ( # Intentionally treat text encapsulated within single triple quotes as String r"^(\s*)([rRuUbB]{,2})('''(?:.|\n)*?''')", bygroups(Whitespace, String.Affix, String), ), +] + +comments: list = [ (r"\A#!.+$", Comment.Hashbang), + # Format Special Common Keywords in Comments ( - # Format Special Common Keyword Comments - # NOTE: Must come before Comment.Single token in order to be matched. - r"(#\s*)(TODO|FIXME|NOTE|BUG|HACK|XXX)(:?)(.*$)", - bygroups(Comment.Single, Comment.Special, Comment.Special, Comment.Single), + r"(#\s*)(TODO|FIXME|NOTE|BUG|HACK|XXX)(.*$)", + bygroups(Comment.Single, Comment.Special, Comment.Single), ), (r"#.*$", Comment.Single), +] + + +python_root: list = [ + (r"\n", Whitespace), + *docstrings, + *comments, (r"\\\n", Text), (r"\\", Text), include("keywords"), @@ -115,8 +180,8 @@ def inner(a, b) -> bool: python_tokens: dict[str, list] = PythonLexer.tokens.copy() -python_tokens["root"] = root -python_tokens["docstring-double"] = [ +python_tokens["root"] = python_root +python_tokens["docstring-double-quotes"] = [ ( r"(?<=\n)(\s*)(Args|Attributes|Returns|Raises|" r"Examples|Yields|References|Notes|Equations)(:)(\s*)", @@ -135,6 +200,7 @@ def inner(a, b) -> bool: (r"\b([a-zA-Z_]\w*)(?=\s*\()", Name.Function), ) +# Tokenize segment of number literals declared in different base (non base 10) python_tokens["numbers"] = [ ( r"(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)" @@ -149,7 +215,7 @@ def inner(a, b) -> bool: ] -class CustomPythonLexer(PythonLexer): +class CustomPythonLexer(MixinLexer, PythonLexer): """Enhanced regex-based python Lexer. Notes: @@ -161,49 +227,84 @@ class CustomPythonLexer(PythonLexer): """ - n_brackets: int - _stack: deque[int] tokens: ClassVar[dict[str, list]] = python_tokens - def __init__(self, **options) -> None: - super().__init__(**options) - self._stack = deque[int]() - self.n_brackets = int(options.get("n_brackets", 4)) - - def _enter(self) -> _TokenType: - """Retrieve next token in cycle.""" - idx = len(self._stack) % self.n_brackets - self._stack.append(idx) - - return get_bracket_level(idx) - def _exit(self) -> _TokenType: - """Remove element from stack and return token.""" - try: - idx: int = self._stack.pop() - return get_bracket_level(idx) +cython_root = [ + (r"\n", Whitespace), + *docstrings, + (r"[^\S\n]+", Text), + *comments, + (r"[]{}:(),;[]", Punctuation), + (r"\\\n", Whitespace), + (r"\\", Text), + (r"(in|is|and|or|not)\b", Operator.Word), + (r"(<)([a-zA-Z0-9.?]+)(>)", bygroups(Punctuation, Keyword.Type, Punctuation)), + (r"!=|==|<<|>>|[-~+/*%=<>&^|.?]", Operator), + ( + r"(from)(\d+)(<=)(\s+)(<)(\d+)(:)", + bygroups( + Keyword, Number.Integer, Operator, Whitespace, Operator, Name, Punctuation + ), + ), + include("keywords"), + (r"(def)(\s+)", bygroups(Keyword.Declare, Whitespace), "funcname"), + (r"(property)(\s+)", bygroups(Keyword.Type, Whitespace), "funcname"), + (r"(cp?def)(\s+)", bygroups(Keyword.Declare, Whitespace), "cdef"), + # (should actually start a block with only cdefs) + (r"(cdef)(:)", bygroups(Keyword.Declare, Punctuation)), + (r"(class|struct)(\s+)", bygroups(Keyword.Declare, Whitespace), "classname"), + (r"(from)(\s+)", bygroups(Keyword.Namespace, Whitespace), "fromimport"), + (r"(c?import)(\s+)", bygroups(Keyword.Namespace, Whitespace), "import"), + include("builtins"), + include("backtick"), + ('(?:[rR]|[uU][rR]|[rR][uU])"""', String, "tdqs"), + ("(?:[rR]|[uU][rR]|[rR][uU])'''", String, "tsqs"), + ('(?:[rR]|[uU][rR]|[rR][uU])"', String, "dqs"), + ("(?:[rR]|[uU][rR]|[rR][uU])'", String, "sqs"), + ('[uU]?"""', String, combined("stringescape", "tdqs")), + ("[uU]?'''", String, combined("stringescape", "tsqs")), + ('[uU]?"', String, combined("stringescape", "dqs")), + ("[uU]?'", String, combined("stringescape", "sqs")), + include("name"), + include("numbers"), +] - except IndexError: - return Punctuation.Error +cython_tokens: dict[str, list] = CythonLexer.tokens.copy() +cython_tokens["root"] = cython_root +cython_tokens["numbers"] = python_tokens["numbers"] +cython_tokens["docstring-double-quotes"] = python_tokens["docstring-double-quotes"] +cython_tokens["name"].insert( + _find(cython_tokens["name"], Name, _get_index(1)), + (r"\b([a-zA-Z_]\w*)(?=\s*\()", Name.Function), +) +cython_tokens["cdef"] = [ + (r"(public|readonly|extern|api|inline|packed)\b", Keyword.Reserved), + # Specialize Name.Class, Name.Function, vs Name.Variable + ( + r"(struct|enum|union|class|cppclass)\b(\s+)([a-zA-Z_]\w*)", + bygroups(Keyword.Declare, Whitespace, Name.Class), + "#pop", + ), + (r"([a-zA-Z_]\w*)(\s*)(?=\()", bygroups(Name.Function, Whitespace), "#pop"), + (r"([a-zA-Z_]\w*)(\s*)(?=[:,=#\n]|$)", bygroups(Name.Variable, Whitespace), "#pop"), + (r"([a-zA-Z_]\w*)(\s*)(,)", bygroups(Name.Variable, Whitespace, Punctuation)), + (r"from\b", Keyword, "#pop"), + (r"as\b", Keyword), + (r":", Punctuation, "#pop"), + (r'(?=["\'])', Text, "#pop"), + (r"[a-zA-Z_]\w*", Keyword.Type), + (r".", Text), +] +cython_tokens["keywords"].append( + (words(("True", "False", "None", "NULL"), suffix=r"\b"), Keyword.Constant) +) +cython_tokens["builtins"][ + _find(cython_tokens["builtins"], Name.Builtin.Pseudo, _get_index(1)) +] = (r"(? Iterator[tuple[int, _TokenType, str]]: - _token: _TokenType - for idx, token, value in super().get_tokens_unprocessed(text, stack): - _token = token - if token is Name and value.isupper(): - _token = Name.Constant - elif token is Punctuation: - match value: - case "(" | "[" | "{": - _token = self._enter() - case "}" | "]" | ")": - _token = self._exit() - case _: - ... +class CustomCythonLexer(MixinLexer, CythonLexer): + """Custom enhanced cython regex-based lexer.""" - yield idx, _token, value + tokens: ClassVar[dict[str, list]] = cython_tokens diff --git a/docs/source/_ext/styles.py b/docs/source/_ext/styles.py index 1b66028..1b9c7f0 100644 --- a/docs/source/_ext/styles.py +++ b/docs/source/_ext/styles.py @@ -97,12 +97,12 @@ class VSCodeDarkPlus(Style): Keyword.Type: Colors.datatype, Keyword.Declare: bold(Colors.declare), Keyword.Constant: bold(Colors.declare), - Keyword.Reserved: bold(Colors.reserved), + Keyword.Reserved: Colors.declare, Keyword.Namespace: Colors.control, # Variable Names Name: Colors.variable, Name.Type: Colors.builtin, - Name.Class: bold(Colors.datatype), + Name.Class: Colors.datatype, Name.Builtin: Colors.builtin, Name.Builtin.Pseudo: italic(Colors.variable), Name.Constant: "#4FC1FF", From 5c4e70fbbb8c2710c9ae0aa168e884f0b0704586 Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 14 Jul 2025 13:22:27 -0700 Subject: [PATCH 2/8] feat(conf): Include cython lexer in sphinx configuration setup, and provide simple framework for html theme options. --- docs/source/conf.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index e61cec9..2a071e0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -72,11 +72,17 @@ html_theme = "sphinx_rtd_theme" html_static_path = ["_static"] html_css_files = ["custom.css"] +# html_logo = "_static/logo.png" +github_url = "https://github.com/Spill-Tea/PyTemplate" + +# Theme options (specific to sphinx_rtd_theme) +# https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/configuring.rst#id7 +# html_theme_options = {} def setup(app: Sphinx) -> None: """Custom sphinx application startup setup.""" - from lexers import CustomPythonLexer # type: ignore + from lexers import CustomCythonLexer, CustomPythonLexer # type: ignore # NOTE: overwrite default python lexer app.add_lexer("python", CustomPythonLexer) @@ -84,3 +90,9 @@ def setup(app: Sphinx) -> None: assert _lexer_registry["python"] == CustomPythonLexer, ( "custom Lexer not found in registry." ) + + app.add_lexer("cython", CustomCythonLexer) + assert "cython" in _lexer_registry, "python language not found in registry" + assert _lexer_registry["cython"] == CustomCythonLexer, ( + "custom Lexer not found in registry." + ) From 587cec18620ef672ccdaf034a2e67ed705e61c7d Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 14 Jul 2025 14:12:04 -0700 Subject: [PATCH 3/8] chore(_ext.lexers): Add a few notes within code to describe intent and purpose of specific rules. --- docs/source/_ext/lexers.py | 149 ++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/docs/source/_ext/lexers.py b/docs/source/_ext/lexers.py index c5c4b7e..3cda4da 100644 --- a/docs/source/_ext/lexers.py +++ b/docs/source/_ext/lexers.py @@ -94,6 +94,8 @@ def _exit(self) -> _TokenType: idx: int = self._stack.pop() return get_bracket_level(idx) + # NOTE: Only additional ending brackets trigger this (e.g. `{{ }}}` ). + # NOTE: We are not attempting to detect correct matching brackets (e.g. `(]` ) except IndexError: return Punctuation.Error @@ -216,11 +218,12 @@ def get_tokens_unprocessed( class CustomPythonLexer(MixinLexer, PythonLexer): - """Enhanced regex-based python Lexer. + """Custom enhanced regex-based python lexer. Notes: 1. Implemented a simple stack based rainbow bracket colorizer. - * limitation: Only detects errors that close more brackets than opens. + * limitation: Only detects errors that close more brackets than it opens. + * limitation: No attempt is made to confirm matching closing brackets. 2. Highlight Docstring titles (assumes google docstring format) 3. Improved highlighting function calls (with limitations) 4. Modify display of number components which indicate a different base number. @@ -279,9 +282,11 @@ class CustomPythonLexer(MixinLexer, PythonLexer): (r"\b([a-zA-Z_]\w*)(?=\s*\()", Name.Function), ) cython_tokens["cdef"] = [ + # include packed keyword (r"(public|readonly|extern|api|inline|packed)\b", Keyword.Reserved), - # Specialize Name.Class, Name.Function, vs Name.Variable + # Specialize Name.Class vs Name.Function vs Name.Variable tokens ( + # include cppclass keyword r"(struct|enum|union|class|cppclass)\b(\s+)([a-zA-Z_]\w*)", bygroups(Keyword.Declare, Whitespace, Name.Class), "#pop", @@ -296,15 +301,151 @@ class CustomPythonLexer(MixinLexer, PythonLexer): (r"[a-zA-Z_]\w*", Keyword.Type), (r".", Text), ] +# Define Keyword.Constant token cython_tokens["keywords"].append( (words(("True", "False", "None", "NULL"), suffix=r"\b"), Keyword.Constant) ) +cython_tokens["keywords"][_find(cython_tokens["keywords"], Keyword, _get_index(1))] = ( + words( + ( + "assert", + "async", + "await", + "break", + "by", + "continue", + "ctypedef", + "del", + "elif", + "else", + "except", + "except?", + "exec", + "finally", + "for", + "fused", + "gil", + "global", + "if", + "include", + "lambda", + "new", # added - relevant for c++ syntax + "nogil", + "pass", + "print", + "raise", + "return", + "try", + "while", + "yield", + "as", + "with", + ), + suffix=r"\b", + ), + Keyword, +) +# Redefine Name.Builtin.Pseudo token (to not include Keyword.Constant values) cython_tokens["builtins"][ _find(cython_tokens["builtins"], Name.Builtin.Pseudo, _get_index(1)) ] = (r"(? Date: Mon, 14 Jul 2025 14:19:45 -0700 Subject: [PATCH 4/8] feat(pre-commit): Update args to pre commit hook to limit larg file size limit. --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb3b3bf..d212bff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,7 @@ repos: - id: check-yaml - id: check-toml - id: check-added-large-files + args: [ --maxkb=1024 ] - id: requirements-txt-fixer - repo: https://github.com/Spill-Tea/addlicense-pre-commit From 5f28b3e64b78cf6a75fe5ca20bfb5fb2346de0d2 Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 14 Jul 2025 14:20:18 -0700 Subject: [PATCH 5/8] feat(.gitignore): Exclude documentation build from repository. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8826ec0..b48cd49 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ # recursively re-ignore __pycache__ *.egg-info/ +docs/build From 1de51a30bfe7392dcd1b411478beb7bdac812878 Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 14 Jul 2025 23:41:22 -0700 Subject: [PATCH 6/8] feat(_ext.lexers): Improve custom cython lexer to style ctydef declaration keyword with improved context, such that variable names are of Keyword.Type or Name.Class tokens. --- docs/source/_ext/lexers.py | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/source/_ext/lexers.py b/docs/source/_ext/lexers.py index 3cda4da..41f492c 100644 --- a/docs/source/_ext/lexers.py +++ b/docs/source/_ext/lexers.py @@ -254,9 +254,13 @@ class CustomPythonLexer(MixinLexer, PythonLexer): (r"(def)(\s+)", bygroups(Keyword.Declare, Whitespace), "funcname"), (r"(property)(\s+)", bygroups(Keyword.Type, Whitespace), "funcname"), (r"(cp?def)(\s+)", bygroups(Keyword.Declare, Whitespace), "cdef"), - # (should actually start a block with only cdefs) + (r"(ctypedef)(\s+)", bygroups(Keyword.Declare, Whitespace), "ctypedef"), (r"(cdef)(:)", bygroups(Keyword.Declare, Punctuation)), - (r"(class|struct)(\s+)", bygroups(Keyword.Declare, Whitespace), "classname"), + ( + r"(class|cppclass|struct)(\s+)", + bygroups(Keyword.Declare, Whitespace), + "classname", + ), (r"(from)(\s+)", bygroups(Keyword.Namespace, Whitespace), "fromimport"), (r"(c?import)(\s+)", bygroups(Keyword.Namespace, Whitespace), "import"), include("builtins"), @@ -283,7 +287,7 @@ class CustomPythonLexer(MixinLexer, PythonLexer): ) cython_tokens["cdef"] = [ # include packed keyword - (r"(public|readonly|extern|api|inline|packed)\b", Keyword.Reserved), + (r"(public|readonly|extern|api|inline|packed|fused)\b", Keyword), # Specialize Name.Class vs Name.Function vs Name.Variable tokens ( # include cppclass keyword @@ -301,6 +305,26 @@ class CustomPythonLexer(MixinLexer, PythonLexer): (r"[a-zA-Z_]\w*", Keyword.Type), (r".", Text), ] +# Define new ctypedef context +cython_tokens["ctypedef"] = [ + (r"(public|readonly|extern|api|inline|packed|fused)\b", Keyword), + ( + r"(\s*)([a-zA-Z_]\w*)(\s*)(:)", + bygroups(Whitespace, Name.Class, Whitespace, Punctuation), + "#pop", + ), + ( + r"(struct|enum|union|class|cppclass)(\s+)([a-zA-Z_]\w*)", + bygroups(Keyword.Declare, Whitespace, Name.Class), + "#pop", + ), + ( + r"([a-zA-Z_]\w*)(\s+)([a-zA-Z_]\w*)", + bygroups(Keyword.Type, Whitespace, Name.Class), + "#pop", + ), + (r"([a-zA-Z_]\w*)", Name.Class, "#pop"), +] # Define Keyword.Constant token cython_tokens["keywords"].append( (words(("True", "False", "None", "NULL"), suffix=r"\b"), Keyword.Constant) @@ -314,7 +338,7 @@ class CustomPythonLexer(MixinLexer, PythonLexer): "break", "by", "continue", - "ctypedef", + # "ctypedef", "del", "elif", "else", @@ -323,13 +347,15 @@ class CustomPythonLexer(MixinLexer, PythonLexer): "exec", "finally", "for", - "fused", + # "fused", "gil", "global", "if", "include", "lambda", + "namespace", # added "new", # added - relevant for c++ syntax + "noexcept", # added "nogil", "pass", "print", @@ -349,6 +375,7 @@ class CustomPythonLexer(MixinLexer, PythonLexer): cython_tokens["builtins"][ _find(cython_tokens["builtins"], Name.Builtin.Pseudo, _get_index(1)) ] = (r"(? Date: Mon, 14 Jul 2025 23:42:05 -0700 Subject: [PATCH 7/8] feat(api.index): Provide a simple demonstration of python and cython code snippets to showcase highlighting with custom lexer and style. --- docs/source/api/index.rst | 102 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst index 1af17b1..9025511 100644 --- a/docs/source/api/index.rst +++ b/docs/source/api/index.rst @@ -3,10 +3,21 @@ PyTemplate API Documentation PyTemplate API documentation. +Here are python and cython code snippets to demonstrate the use of respective customized +lexers with custom syntax highlighting style. These examples are not necessarily meant +to be fully valid code, but to demonstrate key features not available through standard +pygments syntax highlighting styles. + +Python Example Snippet +---------------------- + .. code-block:: python :caption: example.py - from typing import ClassVar as ClassV + #!/usr/bin/env python3 + """Module level docstring.""" + from typing import ClassVar + import numpy as np CONSTANT_A: int = 0xFF CONSTANT_B: float = np.pi @@ -26,7 +37,8 @@ PyTemplate API documentation. arg1: str arg2: int data: dict - other: ClassV[list[int]] = [1, 5, 7] + seventeen: ClassVar[list[int]] = [17, 0x11, 0o21, 0b10001] + other: ClassVar[list[int]] = [1e-5, 1.0e+3, 2j, 2l, 2.7E4J] def __init__(self, arg1: str, arg2: int) -> None: self.arg1 = arg1 @@ -37,10 +49,10 @@ PyTemplate API documentation. } def __getattr__(self, value): - return self.data[value] + return self.method(value) def method(self, value): - return self[value] + return self.data[value] def write(self, text): print(f"{text:<5}\n") @@ -52,6 +64,88 @@ PyTemplate API documentation. return value + 0b10011 +Cython Example Snippet +---------------------- + +.. code-block:: cython + :caption: example.pyx + + """Module level docstring.""" + import cython + from libc.stdlib cimport free, malloc + + cdef extern from "" namespace "std": + cdef cppclass vector[T]: + vector() + T& operator[](int) + + ctypedef fused StringTypeObject: + str + bytes + + ctypedef struct CustomStruct: + int y + str z + + cdef packed struct Breakfast: + int[4] spam + signed char[5] eggs + + cdef enum CheeseType: + manchego = 1 + gouda = 2 + camembert = 3 + + cdef union MyUnion: + int i + float f + char c + + cdef inline unsigned char* function(bint flag) noexcept: + cdef: + Py_ssize_t j + unsigned char* k = NULL + + k = malloc(5 * sizeof(unsigned char)) + + for j in range(5): + k[j] = "A" + + return k + + # XXX: this is an example class + cdef class Example: + """The little example class that couldn't. + + Args: + arg1 (unsigned long long): ... + arg2 (double): ... + + """ + cdef public unsigned long long v + cdef readonly double k + cdef char* mem + + def __cinit__(self, unsigned long long arg1, double arg2): + self.v = arg1 + self.k = arg2 + self.mem = malloc(5 * sizeof(char)) + + def __dealloc__(self): + free(self.mem) + + @cython.boundscheck(False) + cdef char index(self, size_t idx): + return self.mem[idx] + + # just an example of nested parenthesis to demonstrate rainbow coloring + cdef dict obj = { + "a": [(1, 2, (3, 4, 5)), (6, 7, (8, 9 , 10))], + "b": {"c": (7, 4, 3), "d": {"e", "f", "g"}}, + } + cdef tuple builtin_constants = (True, False, NULL, None,) + + .. toctree:: :caption: Submodules From 9c3a916e3773fede52e8ebbead98f133c2e64d49 Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Tue, 15 Jul 2025 00:06:40 -0700 Subject: [PATCH 8/8] fix(pre-commit): Update pre commit config for addlicense not to exclude docs directory. Also check cython files. --- .pre-commit-config.yaml | 3 +-- docs/source/api/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d212bff..da84716 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,8 +20,7 @@ repos: hooks: - id: addlicense language: golang - exclude: ^docs/ args: [ -f, LICENSE, ] - types_or: [ python ] + types_or: [ python, cython ] diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst index 9025511..135137e 100644 --- a/docs/source/api/index.rst +++ b/docs/source/api/index.rst @@ -25,11 +25,11 @@ Python Example Snippet # NOTE: this is an example class class Example(object): """Example docstring. - + Args: arg1 (str): argument 1 arg2 (int): argument 2 - + Attributes: data (dict): data