From 4b545322f08751669d31e3ecf574b3f2f393fe95 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Tue, 22 Jul 2025 22:10:18 +0200 Subject: [PATCH 01/24] Enable strict typing --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index fed528d..56c172e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" + +[tool.mypy] +strict = true From 836d079c439acdfd8916ad2f4f1f26242d2bd149 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Tue, 22 Jul 2025 22:10:55 +0200 Subject: [PATCH 02/24] First batch of type fixes --- djhtml/lines.py | 23 ++++++++++++++++------- djhtml/modes.py | 45 ++++++++++++++++++++++++++++++++------------- djhtml/tokens.py | 14 ++++++++++++-- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/djhtml/lines.py b/djhtml/lines.py index 03f8153..2e9d0e6 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -1,10 +1,19 @@ +from tokens import Token + + class Line: """ A single output line not including the final newline. """ - def __init__(self, tokens=None, level=0, offset=0, ignore=False): + def __init__( + self, + tokens: list[Token] | None = None, + level: int = 0, + offset: int = 0, + ignore: bool = False, + ) -> None: """ Lines are currently never instantiated with arguments, but that doesn't mean they can't. @@ -15,7 +24,7 @@ def __init__(self, tokens=None, level=0, offset=0, ignore=False): self.offset = offset self.ignore = ignore - def append(self, token): + def append(self, token: Token) -> None: """ Append token to line. @@ -23,7 +32,7 @@ def append(self, token): self.tokens.append(token) @property - def text(self): + def text(self) -> str: """ The text of this line including the original leading/trailing spaces. @@ -32,7 +41,7 @@ def text(self): return "".join([token.text for token in self.tokens]) @property - def indents(self): + def indents(self) -> bool: """ Whether this line has more opening than closing tokens. @@ -41,7 +50,7 @@ def indents(self): [token for token in self.tokens if token.dedents] ) - def indent(self, tabwidth): + def indent(self, tabwidth: int) -> str: """ The final, indented text of this line. @@ -52,7 +61,7 @@ def indent(self, tabwidth): return " " * (tabwidth * self.level + self.offset) + text return "" - def __len__(self): + def __len__(self) -> int: """ The length of the line (so far), excluding the whitespace at the beginning. Be careful calling len() because it might @@ -62,7 +71,7 @@ def __len__(self): """ return len(self.text.lstrip()) - def __repr__(self): + def __repr__(self) -> str: kwargs = "" for attr in ["level", "offset", "ignore"]: if value := getattr(self, attr): diff --git a/djhtml/modes.py b/djhtml/modes.py index 5f6238e..fb53d41 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -1,18 +1,32 @@ import re +from abc import ABC, abstractmethod from .lines import Line from .tokens import Token -class BaseMode: +class BaseMode(ABC): """ Base class for the different modes. """ + RAW_TOKENS: list[str] + COMMENT_TAGS: list[str] MAX_LINE_LENGTH = 10_000 - def __init__(self, source=None, return_mode=None, extra_blocks=None): + @abstractmethod + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: + ... + + def __init__( + self, + source: str = "", + return_mode: "BaseMode" | None = None, + extra_blocks: list[tuple[str, str]] | None = None, + ) -> None: """ Instantiate with source text before calling indent(), or with the return_mode when invoked from within another mode. @@ -28,9 +42,9 @@ def __init__(self, source=None, return_mode=None, extra_blocks=None): # To keep track of the current and previous offsets. self.offsets = dict(relative=0, absolute=0) - self.previous_offsets = [] + self.previous_offsets: list[dict[str, int]] = [] - def indent(self, tabwidth): + def indent(self, tabwidth: int) -> str: """ Return the indented text as a single string. @@ -39,7 +53,7 @@ def indent(self, tabwidth): self.parse() return "\n".join([line.indent(tabwidth) for line in self.lines]) - def tokenize(self): + def tokenize(self) -> None: """ Split the source text into tokens and place them on lines. @@ -91,7 +105,7 @@ def tokenize(self): # Set the new source to the old tail for the next iteration. src = tail - def parse(self): + def parse(self) -> None: """ You found the top-secret indenting algorithm! @@ -101,9 +115,9 @@ def parse(self): thereby accomodates different languages used interchangeably. """ - stack = [] + stack: list[Token._Base] = [] - def mode_in_stack(mode): + def mode_in_stack(mode: type[BaseMode]) -> bool: """ Helper function to see if a token from a specific mode is in the stack. @@ -172,7 +186,7 @@ def mode_in_stack(mode): if token.text.strip(): first_token = False - def debug(self): + def debug(self) -> str: self.tokenize() self.parse() return "\n".join([repr(line) for line in self.lines]) @@ -212,10 +226,13 @@ class DjTXT(BaseMode): } OPENING_TAG = r"{%[-+]? *[#/]?(\w+).*?[-+]?%}" - def create_token(self, raw_token, src, line): + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, BaseMode]: mode = self if tag := re.match(self.OPENING_TAG, raw_token): + token: Token._Base name = tag.group(1) if name in self.COMMENT_TAGS: token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), Comment( @@ -513,14 +530,16 @@ class Comment(DjTXT): """ - def __init__(self, endtag, *, mode, return_mode): + def __init__( + self, endtag: str, *, mode: type[BaseMode], return_mode: BaseMode + ) -> None: self.endtag = endtag self.mode = mode self.return_mode = return_mode self.token_re = compile_re([r"\n", endtag]) self.extra_blocks = {} - def create_token(self, raw_token, src, line): + def create_token(self, raw_token: str, src: str, line: Line) -> None: if re.match(self.endtag, raw_token): return Token.Close(raw_token, mode=self.mode, ignore=True), self.return_mode return Token.Text(raw_token, mode=Comment, ignore=True), self @@ -598,5 +617,5 @@ class MaxLineLengthExceeded(Exception): pass -def compile_re(raw_tokens): +def compile_re(raw_tokens: list[str]) -> re.Pattern[str]: return re.compile("(" + "|".join(raw_tokens) + ")") diff --git a/djhtml/tokens.py b/djhtml/tokens.py index 831fe7a..411deae 100644 --- a/djhtml/tokens.py +++ b/djhtml/tokens.py @@ -1,3 +1,6 @@ +from .modes import BaseMode + + class Token: """ Container class for token types. @@ -11,8 +14,15 @@ class _Base: is_double = False def __init__( - self, text, *, mode, level=0, relative=0, absolute=0, ignore=False - ): + self, + text: str, + *, + mode: type[BaseMode], + level: int = 0, + relative: int = 0, + absolute: int = 0, + ignore: bool = False, + ) -> None: """ Tokens must have a text and a mode class. The level represents the line level of opening tokens and is set From 7d9b58eb6128c25074187b3f84f87851e1ae37c9 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Wed, 23 Jul 2025 18:33:52 +0200 Subject: [PATCH 03/24] Second batch of type fixes --- djhtml/lines.py | 9 ++++--- djhtml/modes.py | 62 ++++++++++++++++++++++++++++++++---------------- djhtml/tokens.py | 9 ++++--- 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/djhtml/lines.py b/djhtml/lines.py index 2e9d0e6..c1c2fdc 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -1,4 +1,7 @@ -from tokens import Token +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .tokens import Token class Line: @@ -9,7 +12,7 @@ class Line: def __init__( self, - tokens: list[Token] | None = None, + tokens: list["Token._Base"] | None = None, level: int = 0, offset: int = 0, ignore: bool = False, @@ -24,7 +27,7 @@ def __init__( self.offset = offset self.ignore = ignore - def append(self, token: Token) -> None: + def append(self, token: "Token._Base") -> None: """ Append token to line. diff --git a/djhtml/modes.py b/djhtml/modes.py index fb53d41..0439a15 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -1,5 +1,6 @@ import re from abc import ABC, abstractmethod +from typing import Any from .lines import Line from .tokens import Token @@ -24,7 +25,7 @@ def create_token( def __init__( self, source: str = "", - return_mode: "BaseMode" | None = None, + return_mode: "BaseMode | None" = None, extra_blocks: list[tuple[str, str]] | None = None, ) -> None: """ @@ -258,15 +259,15 @@ def create_token( return token, mode - def _has_closing_token(self, name, raw_token, src): + def _has_closing_token(self, name: str, raw_token: str, src: str) -> bool: endtag = self.extra_blocks.get(name) if endtag: - return re.search(f"{{%[-+]? *{endtag}(?: .*?|)%}}", src) + return bool(re.search(f"{{%[-+]? *{endtag}(?: .*?|)%}}", src)) if not re.search(f"{{%[-+]? *(end_?|/){name}(?: .*?|)%}}", src): return False if regex := self.AMBIGUOUS_BLOCK_TAGS.get(name): if regex[0]: - return re.search(regex[0], raw_token) + return bool(re.search(regex[0], raw_token)) if regex[1]: return not re.search(regex[1], raw_token) return True @@ -304,15 +305,17 @@ class DjHTML(DjTXT): "wbr", ] - def create_token(self, raw_token, src, line): - mode = self + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: + mode: BaseMode = self if raw_token == "<": if match := re.match(r"([\w\-\.:]+)(\s*)", src): tagname = match[1] following_spaces = match[2] absolute = True - token = Token.Text(raw_token, mode=DjHTML) + token: Token._Base = Token.Text(raw_token, mode=DjHTML) offsets = dict( relative=-1 if line.indents else 0, absolute=len(line) + len(tagname) + 2, @@ -362,13 +365,15 @@ class DjCSS(DjTXT): r"", ] - def create_token(self, raw_token, src, line): - mode = self + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: + mode: BaseMode = self if raw_token in "{(": self.previous_offsets.append(self.offsets.copy()) self.offsets = dict(relative=0, absolute=0) - token = Token.Open(raw_token, mode=DjCSS) + token: Token._Base = Token.Open(raw_token, mode=DjCSS) elif raw_token in "})": if self.previous_offsets: self.offsets = self.previous_offsets.pop() @@ -421,7 +426,7 @@ class DjJS(DjTXT): r"", ] - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.haskell = False self.haskell_re = re.compile(r"^ *, ([$\w-]+ *=|[$\w-]+;?)") @@ -429,8 +434,10 @@ def __init__(self, *args, **kwargs): self.previous_line_ended_with_comma = False self.extra_blocks = {} - def create_token(self, raw_token, src, line): - mode = self + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: + mode: BaseMode = self persist_relative_offset = False # Reset absolute offset in almost all cases @@ -448,7 +455,7 @@ def create_token(self, raw_token, src, line): if raw_token in "{[(": self.previous_offsets.append(self.offsets.copy()) self.offsets = dict(relative=0, absolute=0) - token = Token.Open(raw_token, mode=DjJS) + token: Token._Base = Token.Open(raw_token, mode=DjJS) elif raw_token in ")]}": if self.previous_offsets: self.offsets = self.previous_offsets.pop() @@ -539,7 +546,9 @@ def __init__( self.token_re = compile_re([r"\n", endtag]) self.extra_blocks = {} - def create_token(self, raw_token: str, src: str, line: Line) -> None: + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: if re.match(self.endtag, raw_token): return Token.Close(raw_token, mode=self.mode, ignore=True), self.return_mode return Token.Text(raw_token, mode=Comment, ignore=True), self @@ -553,18 +562,27 @@ class InsideHTMLTag(DjTXT): RAW_TOKENS = DjTXT.RAW_TOKENS + [r"/?>", r"[^ ='\">/\n]+=", r'"', r"'"] - def __init__(self, tagname, line, return_mode, absolute, offsets): + def __init__( + self, + tagname: str, + line: Line, + return_mode: BaseMode, + absolute: int, + offsets: dict[str, int], + ) -> None: self.tagname = tagname self.return_mode = return_mode self.absolute = absolute self.offsets = offsets self.token_re = compile_re(self.RAW_TOKENS) - self.inside_attr = False + self.inside_attr: str | bool = False self.additional_offset = -len(tagname) - 1 if absolute else 0 self.extra_blocks = {} - def create_token(self, raw_token, src, line): - mode = self + def create_token( + self, raw_token: str, src: str, line: Line + ) -> tuple[Token._Base, "BaseMode"]: + mode: BaseMode = self if not line: self.additional_offset = 0 @@ -575,14 +593,16 @@ def create_token(self, raw_token, src, line): if raw_token in ['"', "'"]: if self.inside_attr: - token = Token.Text(raw_token, mode=InsideHTMLTag, **self.offsets) + token: Token._Base = Token.Text( + raw_token, mode=InsideHTMLTag, **self.offsets + ) if self.inside_attr == raw_token: self.inside_attr = False token.absolute = self.offsets["absolute"] - 1 self.offsets["absolute"] = self.previous_offset else: self.inside_attr = raw_token - self.previous_offset = self.offsets["absolute"] + self.previous_offset: int = self.offsets["absolute"] self.offsets["absolute"] += self.additional_offset token = Token.Text(raw_token, mode=InsideHTMLTag, **self.offsets) elif not self.inside_attr and raw_token == "/>": diff --git a/djhtml/tokens.py b/djhtml/tokens.py index 411deae..7c5bc1e 100644 --- a/djhtml/tokens.py +++ b/djhtml/tokens.py @@ -1,4 +1,7 @@ -from .modes import BaseMode +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .modes import BaseMode class Token: @@ -17,7 +20,7 @@ def __init__( self, text: str, *, - mode: type[BaseMode], + mode: type["BaseMode"], level: int = 0, relative: int = 0, absolute: int = 0, @@ -38,7 +41,7 @@ def __init__( self.absolute = absolute self.ignore = ignore - def __repr__(self): + def __repr__(self) -> str: kwargs = f", mode={self.mode.__name__}" for attr in ["level", "relative", "absolute", "ignore"]: if value := getattr(self, attr): From 027f732e7c16bdbf734173067498f972a2f3975f Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Thu, 24 Jul 2025 22:46:30 +0200 Subject: [PATCH 04/24] Third batch of type fixes --- djhtml/modes.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/djhtml/modes.py b/djhtml/modes.py index 0439a15..fd5b8cb 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -1,11 +1,16 @@ import re from abc import ABC, abstractmethod -from typing import Any +from typing import Any, TypedDict from .lines import Line from .tokens import Token +class OffsetDict(TypedDict): + relative: int + absolute: int + + class BaseMode(ABC): """ Base class for the different modes. @@ -42,8 +47,8 @@ def __init__( self.extra_blocks = dict(extra_blocks or []) # To keep track of the current and previous offsets. - self.offsets = dict(relative=0, absolute=0) - self.previous_offsets: list[dict[str, int]] = [] + self.offsets: OffsetDict = dict(relative=0, absolute=0) + self.previous_offsets: list[OffsetDict] = [] def indent(self, tabwidth: int) -> str: """ @@ -316,7 +321,7 @@ def create_token( following_spaces = match[2] absolute = True token: Token._Base = Token.Text(raw_token, mode=DjHTML) - offsets = dict( + offsets: OffsetDict = dict( relative=-1 if line.indents else 0, absolute=len(line) + len(tagname) + 2, ) @@ -372,7 +377,7 @@ def create_token( if raw_token in "{(": self.previous_offsets.append(self.offsets.copy()) - self.offsets = dict(relative=0, absolute=0) + self.offsets: OffsetDict = dict(relative=0, absolute=0) token: Token._Base = Token.Open(raw_token, mode=DjCSS) elif raw_token in "})": if self.previous_offsets: @@ -568,7 +573,7 @@ def __init__( line: Line, return_mode: BaseMode, absolute: int, - offsets: dict[str, int], + offsets: OffsetDict, ) -> None: self.tagname = tagname self.return_mode = return_mode From 9fdf70bcebb0581610c629e14821956472f071d5 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Thu, 24 Jul 2025 23:02:51 +0200 Subject: [PATCH 05/24] Fix Python 3.9 compatibility --- djhtml/lines.py | 2 ++ djhtml/modes.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/djhtml/lines.py b/djhtml/lines.py index c1c2fdc..52cf29d 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/djhtml/modes.py b/djhtml/modes.py index fd5b8cb..6ef46bb 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re from abc import ABC, abstractmethod from typing import Any, TypedDict From ba7ec3b18b0feeffdf9b3e0d064603064b72317c Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sat, 26 Jul 2025 12:08:36 +0200 Subject: [PATCH 06/24] Final batch of type fixes --- djhtml/__main__.py | 27 ++++++++++++++++----------- djhtml/options.pyi | 8 ++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 djhtml/options.pyi diff --git a/djhtml/__main__.py b/djhtml/__main__.py index ffb693f..5a0d53e 100644 --- a/djhtml/__main__.py +++ b/djhtml/__main__.py @@ -15,13 +15,16 @@ """ +from __future__ import annotations + import sys +from collections.abc import Iterator from pathlib import Path from . import modes, options -def main(): +def main() -> None: changed_files = 0 unchanged_files = 0 problematic_files = 0 @@ -54,7 +57,7 @@ def main(): source = input_file.read() except Exception as e: problematic_files += 1 - _error(e) + _error(str(e)) continue # Guess tabwidth @@ -103,7 +106,7 @@ def main(): except Exception as e: changed_files -= 1 problematic_files += 1 - _error(e) + _error(str(e)) continue _info(f"reindented {output_file.name}") elif changed and filename != "-": @@ -134,7 +137,7 @@ def main(): sys.exit(0) -def _generate_filenames(paths, suffixes): +def _generate_filenames(paths: list[str], suffixes: list[str]) -> Iterator[str]: for filename in paths: if filename == "-": yield filename @@ -143,18 +146,20 @@ def _generate_filenames(paths, suffixes): if path.is_dir(): yield from _generate_filenames_from_directory(path, suffixes) else: - yield path + yield str(path) -def _generate_filenames_from_directory(directory, suffixes): +def _generate_filenames_from_directory( + directory: Path, suffixes: list[str] +) -> Iterator[str]: for path in directory.iterdir(): if path.is_file() and path.suffix in suffixes: - yield path + yield str(path) elif path.is_dir(): yield from _generate_filenames_from_directory(path, suffixes) -def _verify_changed(source, result): +def _verify_changed(source: str, result: str) -> bool: output_lines = result.split("\n") changed = False for line_nr, line in enumerate(source.split("\n")): @@ -165,7 +170,7 @@ def _verify_changed(source, result): return changed -def _get_depth(line): +def _get_depth(line: str) -> int: count = 0 for char in line: if char == " ": @@ -177,11 +182,11 @@ def _get_depth(line): return count -def _info(msg): +def _info(msg: str) -> None: print(msg, file=sys.stderr) -def _error(msg): +def _error(msg: str) -> None: _info(f"Error: {msg}") diff --git a/djhtml/options.pyi b/djhtml/options.pyi new file mode 100644 index 0000000..81f4754 --- /dev/null +++ b/djhtml/options.pyi @@ -0,0 +1,8 @@ +tabwidth: int +input_filenames: list[str] +check: bool +show_help: bool +show_version: bool +debug: bool +in_place: bool +extra_block: list[tuple[str, str]] | None From 042e5c5b715ba33414c5fe8f20bb53ff8f33ce06 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sat, 26 Jul 2025 12:23:27 +0200 Subject: [PATCH 07/24] Add mypy pre-commit hook --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8b0fc01..1c91de4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,3 +11,7 @@ repos: rev: 6.0.0 hooks: - id: flake8 +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.17.0 + hooks: + - id: mypy From b813040b7958e8262774d0c370b8b172b8c13635 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Mon, 28 Jul 2025 16:56:01 +0200 Subject: [PATCH 08/24] Get rid of redundant `options.pyi` --- djhtml/options.py | 10 ++++++++++ djhtml/options.pyi | 8 -------- 2 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 djhtml/options.pyi diff --git a/djhtml/options.py b/djhtml/options.py index 831f9b0..5297331 100644 --- a/djhtml/options.py +++ b/djhtml/options.py @@ -10,6 +10,16 @@ import sys from importlib.metadata import version +tabwidth: int +input_filenames: list[str] +check: bool +show_help: bool +show_version: bool +debug: bool +in_place: bool +extra_block: list[tuple[str, str]] | None + + parser = argparse.ArgumentParser( description=( """ diff --git a/djhtml/options.pyi b/djhtml/options.pyi deleted file mode 100644 index 81f4754..0000000 --- a/djhtml/options.pyi +++ /dev/null @@ -1,8 +0,0 @@ -tabwidth: int -input_filenames: list[str] -check: bool -show_help: bool -show_version: bool -debug: bool -in_place: bool -extra_block: list[tuple[str, str]] | None From 79a366b6dcca35954e4cf902a7cdfb6e9fd7693d Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:07:45 +0200 Subject: [PATCH 09/24] Stop using `self` as the namespace for command-line arguments This pattern was idiosyncratic and mypy doesn't like it. --- djhtml/__main__.py | 3 ++- djhtml/options.py | 18 ++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/djhtml/__main__.py b/djhtml/__main__.py index 5a0d53e..7479fd3 100644 --- a/djhtml/__main__.py +++ b/djhtml/__main__.py @@ -21,7 +21,8 @@ from collections.abc import Iterator from pathlib import Path -from . import modes, options +from . import modes +from .options import options def main() -> None: diff --git a/djhtml/options.py b/djhtml/options.py index 5297331..770af59 100644 --- a/djhtml/options.py +++ b/djhtml/options.py @@ -10,16 +10,6 @@ import sys from importlib.metadata import version -tabwidth: int -input_filenames: list[str] -check: bool -show_help: bool -show_version: bool -debug: bool -in_place: bool -extra_block: list[tuple[str, str]] | None - - parser = argparse.ArgumentParser( description=( """ @@ -78,15 +68,15 @@ # Parse arguments and assign attributes to self self = sys.modules[__name__] -args = parser.parse_args(namespace=self) +options = parser.parse_args() -if show_version: +if options.show_version: print(version("djhtml")) sys.exit() -elif show_help or not input_filenames: +elif options.show_help or not options.input_filenames: parser.print_help() sys.exit() -elif in_place: +elif options.in_place: sys.exit( """ You have called DjHTML with the -i or --in-place argument which From a98222fa6cf15ca4d34838f6f6db8332bfd315e7 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:16:11 +0200 Subject: [PATCH 10/24] Add typing to test suite --- tests/test_suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_suite.py b/tests/test_suite.py index ce4fa73..63c5122 100644 --- a/tests/test_suite.py +++ b/tests/test_suite.py @@ -8,7 +8,7 @@ class TestSuite(unittest.TestCase): maxDiff = None DIR = Path(__file__).parent / "suite" - def test_available_files(self): + def test_available_files(self) -> None: """ Loop over all the files in the suite directory and compare the expected output to the actual output. @@ -19,7 +19,7 @@ def test_available_files(self): with self.subTest(filename): self._test_file(filename.stem) - def _test_file(self, basename): + def _test_file(self, basename: str) -> None: with open(self.DIR / (basename + ".html")) as f: expected_output = f.read() From 85ae8b6779607ffe98f86428f26b5e192959e4db Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:17:17 +0200 Subject: [PATCH 11/24] Run `pre-commit run -a` --- tests/generate_tokens.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/generate_tokens.py b/tests/generate_tokens.py index ceb6959..5054a56 100755 --- a/tests/generate_tokens.py +++ b/tests/generate_tokens.py @@ -13,4 +13,8 @@ if filename.suffix == ".html": with open(DIR / filename) as html: with open(DIR / (filename.stem + ".tokens"), "w") as f: - f.write(DjHTML(html.read(), extra_blocks=[("weird_tag", "endweird")]).debug()) + f.write( + DjHTML( + html.read(), extra_blocks=[("weird_tag", "endweird")] + ).debug() + ) From 175684bb9576f5842bc5170fcb97d1f3cec7b881 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:33:54 +0200 Subject: [PATCH 12/24] Unpin dependencies in pipeline to catch breakages early, and add `pre-commit run -a` If all goes well, this will cause the pipeline to complete successfully but fail with a pre-commit error, which the next commit will solve. --- .github/workflows/main.yml | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3fe61e8..0ca8ee6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,15 +2,21 @@ name: CI on: push: - branches: - - main pull_request: jobs: - tests: - name: Python ${{ matrix.python-version }} - runs-on: ubuntu-24.04 + pre-commit: + name: Run pre-commit hooks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout + - uses: actions/setup-python + - run: python -m pip install --upgrade pre-commit + - run: pre-commit run -a + tests: + name: Run tests using Python ${{ matrix.python-version }} + runs-on: ubuntu-latest strategy: matrix: python-version: @@ -19,18 +25,10 @@ jobs: - '3.11' - '3.12' - '3.13' - steps: - - uses: actions/checkout@v2 - - - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade nox - - - name: Run tox targets for ${{ matrix.python-version }} - run: nox --session tests-${{ matrix.python-version }} + - uses: actions/checkout + - uses: actions/setup-python + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install --upgrade nox + - run: nox --session tests-${{ matrix.python-version }} From 851acfff1aecd844ff1f0d94566e67dfcfd888e1 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:37:52 +0200 Subject: [PATCH 13/24] Re-add `@rev` to workflow actions --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0ca8ee6..77b2822 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,8 +9,8 @@ jobs: name: Run pre-commit hooks runs-on: ubuntu-latest steps: - - uses: actions/checkout - - uses: actions/setup-python + - uses: actions/checkout@main + - uses: actions/setup-python@main - run: python -m pip install --upgrade pre-commit - run: pre-commit run -a @@ -26,8 +26,8 @@ jobs: - '3.12' - '3.13' steps: - - uses: actions/checkout - - uses: actions/setup-python + - uses: actions/checkout@main + - uses: actions/setup-python@main with: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade nox From 3965037b9811455565b496ec388c965b0d25e012 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:41:22 +0200 Subject: [PATCH 14/24] Prevent workflow jobs from running twice --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 77b2822..8c2f05b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,8 @@ name: CI on: push: + branches: + - main pull_request: jobs: From ae31e87a53490687f7ea4d77ff9145c931ebef40 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 12:54:16 +0200 Subject: [PATCH 15/24] Upgrade pre-commit hooks --- .pre-commit-config.yaml | 33 +++++++++++++++++---------------- djhtml/modes.py | 11 +++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c91de4..17708cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,18 @@ repos: -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort -- repo: https://github.com/psf/black - rev: 23.1.0 - hooks: - - id: black -- repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.17.0 - hooks: - - id: mypy + - repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 25.1.0 + hooks: + - id: black + - repo: https://github.com/pycqa/flake8 + rev: 7.3.0 + hooks: + - id: flake8 + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.17.1 + hooks: + - id: mypy + exclude: ^noxfile\.py$ diff --git a/djhtml/modes.py b/djhtml/modes.py index 6ef46bb..4f7b969 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -26,8 +26,7 @@ class BaseMode(ABC): @abstractmethod def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: - ... + ) -> tuple[Token._Base, "BaseMode"]: ... def __init__( self, @@ -255,10 +254,10 @@ def create_token( else: token = Token.Text(raw_token, mode=DjTXT, **self.offsets) elif raw_token == "{#": - token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), Comment( - "{# fmt:on #}", mode=DjTXT, return_mode=self - ) if src.startswith(" fmt:off #}") else Comment( - "#}", mode=DjTXT, return_mode=self + token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), ( + Comment("{# fmt:on #}", mode=DjTXT, return_mode=self) + if src.startswith(" fmt:off #}") + else Comment("#}", mode=DjTXT, return_mode=self) ) else: From a17d1e4d6cc41039b61f0dafbd71fa8d5bcc7f5d Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:00:53 +0200 Subject: [PATCH 16/24] Improve typing of class variables --- djhtml/modes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/djhtml/modes.py b/djhtml/modes.py index 4f7b969..2c1ad7b 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -2,7 +2,7 @@ import re from abc import ABC, abstractmethod -from typing import Any, TypedDict +from typing import Any, ClassVar, Sequence, TypedDict from .lines import Line from .tokens import Token @@ -19,8 +19,8 @@ class BaseMode(ABC): """ - RAW_TOKENS: list[str] - COMMENT_TAGS: list[str] + RAW_TOKENS: ClassVar[Sequence[str]] + COMMENT_TAGS: ClassVar[Sequence[str]] MAX_LINE_LENGTH = 10_000 @abstractmethod @@ -643,5 +643,5 @@ class MaxLineLengthExceeded(Exception): pass -def compile_re(raw_tokens: list[str]) -> re.Pattern[str]: +def compile_re(raw_tokens: Sequence[str]) -> re.Pattern[str]: return re.compile("(" + "|".join(raw_tokens) + ")") From 6965313d642692fccfef3c314d67e52e6a433f82 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:06:00 +0200 Subject: [PATCH 17/24] Improve typing off places that use `OffsetDict` --- djhtml/modes.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/djhtml/modes.py b/djhtml/modes.py index 2c1ad7b..ca70a6f 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -23,6 +23,9 @@ class BaseMode(ABC): COMMENT_TAGS: ClassVar[Sequence[str]] MAX_LINE_LENGTH = 10_000 + offsets: OffsetDict + previous_offsets: list[OffsetDict] + @abstractmethod def create_token( self, raw_token: str, src: str, line: Line @@ -48,8 +51,8 @@ def __init__( self.extra_blocks = dict(extra_blocks or []) # To keep track of the current and previous offsets. - self.offsets: OffsetDict = dict(relative=0, absolute=0) - self.previous_offsets: list[OffsetDict] = [] + self.offsets = OffsetDict(relative=0, absolute=0) + self.previous_offsets = [] def indent(self, tabwidth: int) -> str: """ @@ -322,7 +325,7 @@ def create_token( following_spaces = match[2] absolute = True token: Token._Base = Token.Text(raw_token, mode=DjHTML) - offsets: OffsetDict = dict( + offsets = OffsetDict( relative=-1 if line.indents else 0, absolute=len(line) + len(tagname) + 2, ) @@ -330,7 +333,7 @@ def create_token( # Use "relative" multi-line indendation instead absolute = False token.indents = True - offsets = dict(relative=0, absolute=0) + offsets = OffsetDict(relative=0, absolute=0) mode = InsideHTMLTag(tagname, line, self, absolute, offsets) else: token = Token.Text(raw_token, mode=DjHTML) @@ -378,7 +381,7 @@ def create_token( if raw_token in "{(": self.previous_offsets.append(self.offsets.copy()) - self.offsets: OffsetDict = dict(relative=0, absolute=0) + self.offsets = OffsetDict(relative=0, absolute=0) token: Token._Base = Token.Open(raw_token, mode=DjCSS) elif raw_token in "})": if self.previous_offsets: @@ -460,7 +463,7 @@ def create_token( # Opening and closing tokens if raw_token in "{[(": self.previous_offsets.append(self.offsets.copy()) - self.offsets = dict(relative=0, absolute=0) + self.offsets = OffsetDict(relative=0, absolute=0) token: Token._Base = Token.Open(raw_token, mode=DjJS) elif raw_token in ")]}": if self.previous_offsets: From 79400bc7c797ee869b356092bc30cec4c34d1450 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:08:34 +0200 Subject: [PATCH 18/24] Rename `_Base` to `BaseToken` --- djhtml/lines.py | 4 ++-- djhtml/modes.py | 26 +++++++++++++------------- djhtml/tokens.py | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/djhtml/lines.py b/djhtml/lines.py index 52cf29d..ba663a3 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -14,7 +14,7 @@ class Line: def __init__( self, - tokens: list["Token._Base"] | None = None, + tokens: list["Token.BaseToken"] | None = None, level: int = 0, offset: int = 0, ignore: bool = False, @@ -29,7 +29,7 @@ def __init__( self.offset = offset self.ignore = ignore - def append(self, token: "Token._Base") -> None: + def append(self, token: "Token.BaseToken") -> None: """ Append token to line. diff --git a/djhtml/modes.py b/djhtml/modes.py index ca70a6f..b0cbba4 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -29,7 +29,7 @@ class BaseMode(ABC): @abstractmethod def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: ... + ) -> tuple[Token.BaseToken, "BaseMode"]: ... def __init__( self, @@ -125,7 +125,7 @@ def parse(self) -> None: thereby accomodates different languages used interchangeably. """ - stack: list[Token._Base] = [] + stack: list[Token.BaseToken] = [] def mode_in_stack(mode: type[BaseMode]) -> bool: """ @@ -238,11 +238,11 @@ class DjTXT(BaseMode): def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, BaseMode]: + ) -> tuple[Token.BaseToken, BaseMode]: mode = self if tag := re.match(self.OPENING_TAG, raw_token): - token: Token._Base + token: Token.BaseToken name = tag.group(1) if name in self.COMMENT_TAGS: token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), Comment( @@ -316,7 +316,7 @@ class DjHTML(DjTXT): def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: + ) -> tuple[Token.BaseToken, "BaseMode"]: mode: BaseMode = self if raw_token == "<": @@ -324,7 +324,7 @@ def create_token( tagname = match[1] following_spaces = match[2] absolute = True - token: Token._Base = Token.Text(raw_token, mode=DjHTML) + token: Token.BaseToken = Token.Text(raw_token, mode=DjHTML) offsets = OffsetDict( relative=-1 if line.indents else 0, absolute=len(line) + len(tagname) + 2, @@ -376,13 +376,13 @@ class DjCSS(DjTXT): def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: + ) -> tuple[Token.BaseToken, "BaseMode"]: mode: BaseMode = self if raw_token in "{(": self.previous_offsets.append(self.offsets.copy()) self.offsets = OffsetDict(relative=0, absolute=0) - token: Token._Base = Token.Open(raw_token, mode=DjCSS) + token: Token.BaseToken = Token.Open(raw_token, mode=DjCSS) elif raw_token in "})": if self.previous_offsets: self.offsets = self.previous_offsets.pop() @@ -445,7 +445,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: + ) -> tuple[Token.BaseToken, "BaseMode"]: mode: BaseMode = self persist_relative_offset = False @@ -464,7 +464,7 @@ def create_token( if raw_token in "{[(": self.previous_offsets.append(self.offsets.copy()) self.offsets = OffsetDict(relative=0, absolute=0) - token: Token._Base = Token.Open(raw_token, mode=DjJS) + token: Token.BaseToken = Token.Open(raw_token, mode=DjJS) elif raw_token in ")]}": if self.previous_offsets: self.offsets = self.previous_offsets.pop() @@ -557,7 +557,7 @@ def __init__( def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: + ) -> tuple[Token.BaseToken, "BaseMode"]: if re.match(self.endtag, raw_token): return Token.Close(raw_token, mode=self.mode, ignore=True), self.return_mode return Token.Text(raw_token, mode=Comment, ignore=True), self @@ -590,7 +590,7 @@ def __init__( def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token._Base, "BaseMode"]: + ) -> tuple[Token.BaseToken, "BaseMode"]: mode: BaseMode = self if not line: @@ -602,7 +602,7 @@ def create_token( if raw_token in ['"', "'"]: if self.inside_attr: - token: Token._Base = Token.Text( + token: Token.BaseToken = Token.Text( raw_token, mode=InsideHTMLTag, **self.offsets ) if self.inside_attr == raw_token: diff --git a/djhtml/tokens.py b/djhtml/tokens.py index 7c5bc1e..f9fb638 100644 --- a/djhtml/tokens.py +++ b/djhtml/tokens.py @@ -10,7 +10,7 @@ class Token: """ - class _Base: + class BaseToken: indents = False dedents = False ignore = False @@ -48,23 +48,23 @@ def __repr__(self) -> str: kwargs += f", {attr}={value!r}" return f"{self.__class__.__name__}({self.text!r}{kwargs})" - class Text(_Base): + class Text(BaseToken): pass - class Open(_Base): + class Open(BaseToken): indents = True - class OpenDouble(_Base): + class OpenDouble(BaseToken): indents = True is_double = True - class Close(_Base): + class Close(BaseToken): dedents = True - class CloseDouble(_Base): + class CloseDouble(BaseToken): dedents = True is_double = True - class CloseAndOpen(_Base): + class CloseAndOpen(BaseToken): indents = True dedents = True From 6f9390c1008a5995f1834858c27b1c0c516b1b26 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:17:46 +0200 Subject: [PATCH 19/24] Write out all arguments to `__init__()` explicitly --- djhtml/modes.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/djhtml/modes.py b/djhtml/modes.py index b0cbba4..2f9c0ab 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -2,7 +2,7 @@ import re from abc import ABC, abstractmethod -from typing import Any, ClassVar, Sequence, TypedDict +from typing import ClassVar, Sequence, TypedDict from .lines import Line from .tokens import Token @@ -435,8 +435,13 @@ class DjJS(DjTXT): r"", ] - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) + def __init__( + self, + source: str = "", + return_mode: "BaseMode | None" = None, + extra_blocks: list[tuple[str, str]] | None = None, + ) -> None: + super().__init__(source, return_mode, extra_blocks) self.haskell = False self.haskell_re = re.compile(r"^ *, ([$\w-]+ *=|[$\w-]+;?)") self.variable_re = re.compile(r"^ *([$\w-]+ *=|[$\w-]+;?)") From 0401c49c5e4da4aca47450b909a5bee26c3c75f4 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:26:18 +0200 Subject: [PATCH 20/24] Convert `extra_blocks` to `dict[str, str]` at an earlier stage --- djhtml/__main__.py | 3 ++- djhtml/modes.py | 6 +++--- tests/generate_tokens.py | 4 +--- tests/test_suite.py | 6 +++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/djhtml/__main__.py b/djhtml/__main__.py index 7479fd3..6c147a6 100644 --- a/djhtml/__main__.py +++ b/djhtml/__main__.py @@ -74,8 +74,9 @@ def main() -> None: guess = probabilities.index(max(probabilities)) # Indent input file + extra_blocks = dict(options.extra_block or []) try: - result = Mode(source, extra_blocks=options.extra_block).indent( + result = Mode(source, extra_blocks=extra_blocks).indent( options.tabwidth or guess or 4 ) except modes.MaxLineLengthExceeded: diff --git a/djhtml/modes.py b/djhtml/modes.py index 2f9c0ab..5a2b14f 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -35,7 +35,7 @@ def __init__( self, source: str = "", return_mode: "BaseMode | None" = None, - extra_blocks: list[tuple[str, str]] | None = None, + extra_blocks: dict[str, str] | None = None, ) -> None: """ Instantiate with source text before calling indent(), or @@ -48,7 +48,7 @@ def __init__( self.source = source self.return_mode = return_mode or self self.token_re = compile_re(self.RAW_TOKENS) - self.extra_blocks = dict(extra_blocks or []) + self.extra_blocks = extra_blocks or {} # To keep track of the current and previous offsets. self.offsets = OffsetDict(relative=0, absolute=0) @@ -439,7 +439,7 @@ def __init__( self, source: str = "", return_mode: "BaseMode | None" = None, - extra_blocks: list[tuple[str, str]] | None = None, + extra_blocks: dict[str, str] | None = None, ) -> None: super().__init__(source, return_mode, extra_blocks) self.haskell = False diff --git a/tests/generate_tokens.py b/tests/generate_tokens.py index 5054a56..cf87c04 100755 --- a/tests/generate_tokens.py +++ b/tests/generate_tokens.py @@ -14,7 +14,5 @@ with open(DIR / filename) as html: with open(DIR / (filename.stem + ".tokens"), "w") as f: f.write( - DjHTML( - html.read(), extra_blocks=[("weird_tag", "endweird")] - ).debug() + DjHTML(html.read(), extra_blocks={"weird_tag": "endweird"}).debug() ) diff --git a/tests/test_suite.py b/tests/test_suite.py index 63c5122..cab0eba 100644 --- a/tests/test_suite.py +++ b/tests/test_suite.py @@ -28,18 +28,18 @@ def _test_file(self, basename: str) -> None: # Indent the expected output to 0 (no indentation) unindented = DjHTML( - expected_output, extra_blocks=[("weird_tag", "endweird")] + expected_output, extra_blocks={"weird_tag": "endweird"} ).indent(0) self.assertNotEqual(unindented, expected_output) # Re-indent the unindented output to 4 actual_output = DjHTML( - unindented, extra_blocks=[("weird_tag", "endweird")] + unindented, extra_blocks={"weird_tag": "endweird"} ).indent(4) self.assertEqual(expected_output, actual_output) # Compare the tokenization actual_tokens = DjHTML( - actual_output, extra_blocks=[("weird_tag", "endweird")] + actual_output, extra_blocks={"weird_tag": "endweird"} ).debug() self.assertEqual(expected_tokens, actual_tokens) From 903f4f58a2875de1b25d8aa06368de8cc939a03b Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Sun, 10 Aug 2025 13:48:47 +0200 Subject: [PATCH 21/24] Remove obsolute self variable and its associated comment --- djhtml/options.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/djhtml/options.py b/djhtml/options.py index 770af59..2223e71 100644 --- a/djhtml/options.py +++ b/djhtml/options.py @@ -66,8 +66,6 @@ type=lambda x: tuple(x.split(",")), ) -# Parse arguments and assign attributes to self -self = sys.modules[__name__] options = parser.parse_args() if options.show_version: From 0c801f9339cbea53742e2606c3a2fd0e2844f648 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Tue, 12 Aug 2025 21:19:01 +0200 Subject: [PATCH 22/24] Unquote types --- djhtml/lines.py | 4 ++-- djhtml/modes.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/djhtml/lines.py b/djhtml/lines.py index ba663a3..53c0da1 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -14,7 +14,7 @@ class Line: def __init__( self, - tokens: list["Token.BaseToken"] | None = None, + tokens: list[Token.BaseToken] | None = None, level: int = 0, offset: int = 0, ignore: bool = False, @@ -29,7 +29,7 @@ def __init__( self.offset = offset self.ignore = ignore - def append(self, token: "Token.BaseToken") -> None: + def append(self, token: Token.BaseToken) -> None: """ Append token to line. diff --git a/djhtml/modes.py b/djhtml/modes.py index 5a2b14f..65d3de2 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -29,12 +29,12 @@ class BaseMode(ABC): @abstractmethod def create_token( self, raw_token: str, src: str, line: Line - ) -> tuple[Token.BaseToken, "BaseMode"]: ... + ) -> tuple[Token.BaseToken, BaseMode]: ... def __init__( self, source: str = "", - return_mode: "BaseMode | None" = None, + return_mode: BaseMode | None = None, extra_blocks: dict[str, str] | None = None, ) -> None: """ @@ -438,7 +438,7 @@ class DjJS(DjTXT): def __init__( self, source: str = "", - return_mode: "BaseMode | None" = None, + return_mode: BaseMode | None = None, extra_blocks: dict[str, str] | None = None, ) -> None: super().__init__(source, return_mode, extra_blocks) From 272186dac2d1046e48a0237c5f64dfaff09dd9e6 Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Tue, 12 Aug 2025 21:26:50 +0200 Subject: [PATCH 23/24] Move type of `inside_attr` to class-level --- djhtml/modes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/djhtml/modes.py b/djhtml/modes.py index 65d3de2..c3ea11a 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -576,6 +576,8 @@ class InsideHTMLTag(DjTXT): RAW_TOKENS = DjTXT.RAW_TOKENS + [r"/?>", r"[^ ='\">/\n]+=", r'"', r"'"] + inside_attr: str | bool + def __init__( self, tagname: str, @@ -589,7 +591,7 @@ def __init__( self.absolute = absolute self.offsets = offsets self.token_re = compile_re(self.RAW_TOKENS) - self.inside_attr: str | bool = False + self.inside_attr = False self.additional_offset = -len(tagname) - 1 if absolute else 0 self.extra_blocks = {} From b3c52dddd61ac48892b9448c2ef25977e39aff6a Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Tue, 12 Aug 2025 21:35:28 +0200 Subject: [PATCH 24/24] Replace `[]` with `()` for no practical reason --- djhtml/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djhtml/__main__.py b/djhtml/__main__.py index 6c147a6..2842ac0 100644 --- a/djhtml/__main__.py +++ b/djhtml/__main__.py @@ -74,7 +74,7 @@ def main() -> None: guess = probabilities.index(max(probabilities)) # Indent input file - extra_blocks = dict(options.extra_block or []) + extra_blocks = dict(options.extra_block or ()) try: result = Mode(source, extra_blocks=extra_blocks).indent( options.tabwidth or guess or 4