diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f6f1c9..31f8cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file. * Function `is_valid_syntax_non_zero` (via [#48]) * Function `is_valid_syntax_pct_encoded` (via [#48]) * Dict `RFC3987_SYNTAX_TERM_VALIDATORS` mapping `RFC3987_SYNTAX_TERMS` to validator function (via [#49]) + * Function `is_valid_syntax` issues a warning if an unexpected error occurred (via [#51]) * Performance * Public symbols use lazy loading (via [#43]) * Tests @@ -33,6 +34,7 @@ All notable changes to this project will be documented in this file. [#48]: https://github.com/jkowalleck/rfc3987-syntax2/pull/48 [#49]: https://github.com/jkowalleck/rfc3987-syntax2/pull/49 [#50]: https://github.com/jkowalleck/rfc3987-syntax2/pull/50 +[#51]: https://github.com/jkowalleck/rfc3987-syntax2/pull/51 [#52]: https://github.com/jkowalleck/rfc3987-syntax2/pull/52 ## v1.2.0 - 2026-07-16 diff --git a/src/rfc3987_syntax2/syntax_helpers.py b/src/rfc3987_syntax2/syntax_helpers.py index 24a3b59..fd1ebda 100644 --- a/src/rfc3987_syntax2/syntax_helpers.py +++ b/src/rfc3987_syntax2/syntax_helpers.py @@ -5,6 +5,7 @@ from pathlib import Path from threading import Lock from typing import Any, Callable, Optional, TYPE_CHECKING, Literal +from warnings import warn from lark import Lark, ParseTree, exceptions @@ -120,9 +121,17 @@ def parse(term: _T_SYNTAX_PARSER_TERM, value: str) -> 'ParseTree': def is_valid_syntax(term: _T_SYNTAX_PARSER_TERM, value: str) -> bool: try: parse(term=term, value=value) - return True - except exceptions.LarkError: + except exceptions.UnexpectedInput: + # from Lark.parse() return False + except exceptions.LarkError as err: + # from Lark internals / initialization (non-UnexpectedInput) + warn("Unexpected LarkError (non-UnexpectedInput) " + f"for term={term!r}: {type(err).__name__}: {err}", + RuntimeWarning, + stacklevel=2) + return False + return True _T_SYNTAX_VALIDATOR = Callable[[str], bool] @@ -139,9 +148,10 @@ def syntax_validator(text: str) -> bool: parser=RFC3987_SYNTAX_PARSER_TYPE) try: parser.parse(text) - return True except exceptions.LarkError: return False + else: + return True return syntax_validator diff --git a/tests/test_is_valid_syntax_warning.py b/tests/test_is_valid_syntax_warning.py new file mode 100644 index 0000000..b7c5054 --- /dev/null +++ b/tests/test_is_valid_syntax_warning.py @@ -0,0 +1,22 @@ +# Copyright (c) 2026 Jan Kowalleck - modifications and maintenance +# SPDX-License-Identifier: MIT + +import pytest +from unittest.mock import patch + +from lark import exceptions + +import rfc3987_syntax2.syntax_helpers as sut + + +def _raise_lark_error(*args: object, **kwargs: object) -> None: + raise exceptions.LarkError("unexpected test error") + + +def test_is_valid_syntax_warns_on_unexpected_lark_error() -> None: + with patch.object(sut, "parse", side_effect=_raise_lark_error): + with pytest.warns(RuntimeWarning, match=r"Unexpected LarkError"): + result = sut.is_valid_syntax( + term='unsupported-term', # type: ignore[arg-type] # on purpose + value="any-value") + assert result is False