{"id":699,"library":"rfc3987-syntax","title":"RFC 3987 Syntax Validation","description":"rfc3987-syntax is a Python library (current version 1.1.0) that provides helper functions to syntactically validate strings according to the ABNF grammar defined in RFC 3987, which specifies Internationalized Resource Identifiers (IRIs). It is lightweight, permissively licensed (MIT), and leverages the Lark parsing library. The project strictly focuses on ABNF syntax validation, explicitly stating that additional semantic rules (like Unicode normalization or BiDi constraints) must be handled separately. With a relatively active release cadence, its latest major update (v1.1.0) introduced support for IRI-reference and absolute-IRI.","status":"active","version":"1.1.0","language":"python","source_language":"en","source_url":"https://github.com/willynilly/rfc3987-syntax","tags":["IRI","URI","validation","RFC3987","syntax","lark"],"install":[{"cmd":"pip install rfc3987-syntax","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Used for parsing the ABNF grammar.","package":"lark"}],"imports":[{"symbol":"is_valid_syntax","correct":"from rfc3987_syntax import is_valid_syntax"},{"symbol":"RFC3987_SYNTAX_TERMS","correct":"from rfc3987_syntax import RFC3987_SYNTAX_TERMS"}],"quickstart":{"code":"from rfc3987_syntax import is_valid_syntax, RFC3987_SYNTAX_TERMS\n\n# List all supported validation terms\nprint(f\"Supported terms: {RFC3987_SYNTAX_TERMS}\\n\")\n\n# Validate a string against a specific term\nif is_valid_syntax(term='iri', value='http://example.com/path/to/resource?query=param#fragment'):\n    print(\"✓ 'http://example.com/path/to/resource?query=param#fragment' is a valid IRI syntax\")\nelse:\n    print(\"✗ Invalid IRI syntax\")\n\n# Example of invalid syntax\nif not is_valid_syntax(term='iri', value='not-an-iri-with- space'):\n    print(\"✗ 'not-an-iri-with- space' is invalid IRI syntax as expected\")\n","lang":"python","description":"Demonstrates how to list supported validation terms and use the `is_valid_syntax` function to check if a string conforms to a specific RFC 3987 syntax rule, such as 'iri'."},"warnings":[{"fix":"Implement additional logic for semantic validation as required by your application.","message":"This library *only* performs syntactic validation of RFC 3987 based on ABNF grammar. It does not validate semantic rules such as Unicode Normalization Form C (NFC), Bidirectional text (BiDi) constraints, port number ranges (0-65535), valid IPv6 compression, or context-aware percent-encoding requirements. These must be enforced separately for full compliance.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Confirm the correct package name during installation: `pip install rfc3987-syntax`.","message":"This `rfc3987-syntax` package is a distinct project and is *not* affiliated with the older, GPL-licensed `rfc3987` Python package by Daniel Gerber, which has a different scope. Ensure you are installing `rfc3987-syntax` to avoid licensing conflicts or unexpected API differences.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review validation logic and expected outcomes when upgrading from versions prior to 1.1.0, especially for inputs involving IRI-references, absolute-IRIs, or single quotes within delimited components.","message":"Version 1.1.0 introduced explicit support for `IRI-reference` and `absolute-IRI` terms and fixed a bug related to single quote sub-delimiters. While primarily adding functionality, these changes *could* subtly alter validation results for certain inputs that were previously considered invalid or parsed differently in older versions.","severity":"breaking","affected_versions":">=1.1.0"}],"env_vars":null,"last_verified":"2026-05-12T17:56:28.227Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the library using `pip install rfc3987-syntax` and ensure your import statement is `import rfc3987_syntax`.","cause":"The `rfc3987-syntax` library is either not installed in the environment or the import statement uses an incorrect module name (e.g., `rfc3987-syntax` instead of `rfc3987_syntax`).","error":"ModuleNotFoundError: No module named 'rfc3987_syntax'"},{"fix":"Use `rfc3987_syntax.parse_iri()` (or other `parse_` functions) within a `try-except lark.exceptions.UnexpectedInput` block to handle invalid input.\n```python\nimport rfc3987_syntax\nfrom lark.exceptions import UnexpectedInput\n\ntry:\n    rfc3987_syntax.parse_iri(\"http://example.com/path?query\")\n    print(\"IRI is valid\")\nexcept UnexpectedInput:\n    print(\"IRI is invalid\")\n```","cause":"The library does not provide a convenience `validate_iri` (or similar `validate_` prefixed) function; validation is implicitly performed by attempting to parse the input, which raises an exception on failure.","error":"AttributeError: module 'rfc3987_syntax' has no attribute 'validate_iri'"},{"fix":"Review the input string to ensure it adheres precisely to RFC 3987 syntax rules, paying attention to valid characters, structure, and component delimiters for the specific `parse_` function used.","cause":"The provided string does not strictly conform to the ABNF grammar for the specified IRI/URI component as defined in RFC 3987.","error":"lark.exceptions.UnexpectedInput: No rule matches the current input, or it is ambiguous."},{"fix":"Upgrade the `rfc3987-syntax` library to version 1.1.0 or newer using the command `pip install --upgrade rfc3987-syntax`.","cause":"The function `parse_iri_reference` (and `parse_absolute_iri`) was introduced in version 1.1.0, and an older version of the library is currently installed.","error":"AttributeError: module 'rfc3987_syntax' has no attribute 'parse_iri_reference'"}],"ecosystem":"pypi","meta_description":null,"install_score":85,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"1.1.0","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":4.03,"mem_mb":20.5,"disk_size":"18.7M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.51,"mem_mb":20.5,"disk_size":"18.7M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":2.76,"mem_mb":20.5,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.81,"mem_mb":20.5,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":5.09,"mem_mb":17.9,"disk_size":"20.7M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":6.2,"mem_mb":17.9,"disk_size":"20.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":4.78,"mem_mb":17.9,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":4.6,"mem_mb":17.9,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":4.6,"mem_mb":17.1,"disk_size":"12.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.93,"mem_mb":17.1,"disk_size":"12.5M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":5.32,"mem_mb":17.1,"disk_size":"13M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.35,"mem_mb":17.1,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":4.44,"mem_mb":18.1,"disk_size":"12.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.24,"mem_mb":18.1,"disk_size":"12.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":4.88,"mem_mb":18.1,"disk_size":"13M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.36,"mem_mb":18.1,"disk_size":"13M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":4.19,"mem_mb":20.3,"disk_size":"18.2M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":5.04,"mem_mb":20.3,"disk_size":"18.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.8,"import_time_s":3.46,"mem_mb":20.3,"disk_size":"19M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":4.19,"mem_mb":20.3,"disk_size":"19M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}