Coverage for src/lexigram/auth/authz/_parsers.py: 77%
44 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
1"""Value parser classes for authorization service."""
3from __future__ import annotations
5import threading
6from typing import Any, Protocol, cast
8from lexigram import serialization as json
11class ValueParser(Protocol):
12 """Protocol for value parsers."""
14 def can_parse(self, val: Any) -> bool:
15 """Check if this parser can handle the given value."""
16 ...
18 def parse(self, val: Any) -> list[str]:
19 """Parse the value into a list of strings."""
20 ...
23class StringValueParser:
24 """Parser for string values, including JSON-encoded lists."""
26 def can_parse(self, val: Any) -> bool:
27 return isinstance(val, str)
29 def parse(self, val: Any) -> list[str]:
30 try:
31 parsed = json.loads(val)
32 return parsed if isinstance(parsed, list) else [str(parsed)]
33 except (ValueError, TypeError, json.JSONDecodeError):
34 return [val]
37class ListValueParser:
38 """Parser for list values."""
40 def can_parse(self, val: Any) -> bool:
41 return isinstance(val, list)
43 def parse(self, val: Any) -> list[str]:
44 return cast("list[str]", val)
47class NoneValueParser:
48 """Parser for None values."""
50 def can_parse(self, val: Any) -> bool:
51 return val is None
53 def parse(self, val: Any) -> list[str]:
54 return []
57class ValueParserRegistry:
58 """Registry for value parsers.
60 Provides extensible parsing of various value types into string lists.
61 Thread-safe registry for value parsers.
62 """
64 def __init__(self) -> None:
65 self._lock = threading.Lock()
66 self._parsers: list[ValueParser] = []
67 self._register_default_parsers()
69 def _register_default_parsers(self) -> None:
70 """Register the default value parsers."""
71 self._parsers = [
72 StringValueParser(),
73 ListValueParser(),
74 NoneValueParser(),
75 ]
77 def register_parser(self, parser: ValueParser) -> None:
78 """Register a custom value parser."""
79 with self._lock:
80 self._parsers.insert(0, parser)
82 def parse(self, val: Any) -> list[str]:
83 """Parse the value using registered parsers."""
84 with self._lock:
85 for parser in self._parsers:
86 if parser.can_parse(val):
87 return parser.parse(val)
88 return [str(val)]
91# Global registry instance
92_value_parser_registry = ValueParserRegistry()
94__all__ = [
95 "ListValueParser",
96 "NoneValueParser",
97 "StringValueParser",
98 "ValueParser",
99 "ValueParserRegistry",
100]