Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ All notable changes to this project will be documented in this file.

<!-- unreleased things below this line -->

* 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
Expand Down
22 changes: 12 additions & 10 deletions src/rfc3987_syntax2/syntax_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
jkowalleck marked this conversation as resolved.
from warnings import warn

from lark import Lark, ParseTree, exceptions
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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}")

Expand Down