diff --git a/CHANGELOG.md b/CHANGELOG.md index cb43b0c..6dbee8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,12 @@ All notable changes to this project will be documented in this file. +* Refactor + * Marked exported constants/lazy globals as `Final` for downstream users (via [#69]) * Docs * Fixed docstring of `T_SYNTAX_PARSER_TERM` (via [#70]) +[#69]: https://github.com/jkowalleck/rfc3987-syntax2/pull/69 [#70]: https://github.com/jkowalleck/rfc3987-syntax2/pull/70 ## v1.3.1 - 2026-07-23 diff --git a/src/rfc3987_syntax2/syntax_helpers.py b/src/rfc3987_syntax2/syntax_helpers.py index 57790e2..689e073 100644 --- a/src/rfc3987_syntax2/syntax_helpers.py +++ b/src/rfc3987_syntax2/syntax_helpers.py @@ -4,7 +4,7 @@ from pathlib import Path from threading import Lock -from typing import TYPE_CHECKING, Any, Callable, Literal, Optional +from typing import TYPE_CHECKING, Any, Callable, Final, Literal, Mapping, Optional, Sequence from warnings import warn from lark import Lark, ParseTree, exceptions @@ -65,9 +65,9 @@ "is_valid_syntax_pct_encoded", ] -RFC3987_SYNTAX_PARSER_TYPE: str = "earley" -RFC3987_SYNTAX_GRAMMAR_PATH: Path = Path(__file__).parent / "syntax_rfc3987.lark" -RFC3987_SYNTAX_TERMS: list[str] = [ +RFC3987_SYNTAX_PARSER_TYPE: Final[str] = "earley" +RFC3987_SYNTAX_GRAMMAR_PATH: Final[Path] = Path(__file__).parent / "syntax_rfc3987.lark" +RFC3987_SYNTAX_TERMS: Final[Sequence[str]] = [ # TODO: BreakingChaneg: make tuple "iri", "iri_reference", "absolute_iri", @@ -124,7 +124,7 @@ Allowed values are ``"iri"``, ``"iri_reference"``, and ``"absolute_iri"``. """ -_SYNTAX_PARSER_STARTS: list[T_SYNTAX_PARSER_TERM] = ["iri", "iri_reference", "absolute_iri"] +_SYNTAX_PARSER_STARTS: Final[Sequence[T_SYNTAX_PARSER_TERM]] = ["iri", "iri_reference", "absolute_iri"] def parse(term: T_SYNTAX_PARSER_TERM, value: str) -> ParseTree: @@ -161,6 +161,7 @@ def is_valid_syntax(term: T_SYNTAX_PARSER_TERM, value: str) -> bool: return False except exceptions.LarkError as err: # from Lark internals / initialization (non-UnexpectedInput) + # TODO: BreakingChange: dont catch warn("Unexpected LarkError (non-UnexpectedInput) " f"for term={term!r}: {type(err).__name__}: {err}", RuntimeWarning, @@ -526,7 +527,8 @@ def is_valid_syntax_pct_encoded(text: str) -> bool: is_valid_syntax_pct_encoded = make_syntax_validator("pct_encoded") -RFC3987_SYNTAX_TERM_VALIDATORS: dict[str, T_SYNTAX_VALIDATOR] = { # frozendict +RFC3987_SYNTAX_TERM_VALIDATORS: Final[Mapping[str, T_SYNTAX_VALIDATOR]] = { + # TODO: BreakingChange: make frozendict / MappingProxyType "iri": is_valid_syntax_iri, "iri_reference": is_valid_syntax_iri_reference, "absolute_iri": is_valid_syntax_absolute_iri, @@ -578,22 +580,22 @@ def is_valid_syntax_pct_encoded(text: str) -> bool: # region lazy loaded attrs if TYPE_CHECKING: # types for lazy-loaded symbols - grammar: str + grammar: Final[str] # type: ignore[misc] # lazy loading is Final downstream """Lark grammar text for RFC 3987.""" if TYPE_CHECKING: # types for lazy-loaded symbols - syntax_parser: Lark + syntax_parser: Final[Lark] # type: ignore[misc] # lazy loading is Final downstream """Lazily initialized parser for RFC 3987 syntax.""" def __getattr__(name: str) -> Any: if name == "grammar": global grammar - grammar = _get_grammar() + grammar = _get_grammar() # type: ignore[misc] # lazy loading is Final downstream return grammar if name == "syntax_parser": global syntax_parser - syntax_parser = _get_syntax_parser() + syntax_parser = _get_syntax_parser() # type: ignore[misc] # lazy loading is Final downstream return syntax_parser raise AttributeError(f"module {__name__!r} has no attribute {name!r}")