rfc3987-syntax2 1.1.0rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ *.pyc
2
+ .pytest_cache
3
+ dist
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Will Riley
4
+ Copyright (c) 2026 Jan Kowalleck โ€” modifications and maintenance.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: rfc3987-syntax2
3
+ Version: 1.1.0rc1
4
+ Summary: Helper functions to syntactically validate strings according to RFC 3987.
5
+ Project-URL: Homepage, https://github.com/jkowalleck/rfc3987-syntax2
6
+ Project-URL: Documentation, https://github.com/jkowalleck/rfc3987-syntax2#readme
7
+ Project-URL: Issues, https://github.com/jkowalleck/rfc3987-syntax2/issues
8
+ Project-URL: Source, https://github.com/jkowalleck/rfc3987-syntax2
9
+ Author: Jan Kowalleck
10
+ Author-email: Will Riley <wanderingwill@gmail.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: RFC 3987,RFC3987,parser,syntax,validator
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Education
17
+ Classifier: Intended Audience :: Information Technology
18
+ Classifier: Intended Audience :: Science/Research
19
+ Classifier: Intended Audience :: System Administrators
20
+ Classifier: License :: OSI Approved :: MIT License
21
+ Classifier: Natural Language :: English
22
+ Classifier: Programming Language :: Python
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Classifier: Topic :: Software Development
26
+ Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.9
28
+ Requires-Dist: lark>=1.2.2
29
+ Provides-Extra: testing
30
+ Requires-Dist: pytest>=8.3.5; extra == 'testing'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # rfc3987-syntax2
34
+
35
+ Helper functions to parse and validate the **syntax** of terms defined in **[RFC 3987](https://www.rfc-editor.org/info/rfc3987)** โ€” the IETF standard for Internationalized Resource Identifiers (IRIs).
36
+
37
+ > [!NOTE]
38
+ > This is a maintained fork of <https://github.com/willynilly/rfc3987-syntax>.
39
+
40
+ ## ๐ŸŽฏ Purpose
41
+
42
+ The goal of `rfc3987-syntax2` is to provide a **lightweight, permissively licensed Python module** for validating that strings conform to the **ABNF grammar defined in RFC 3987**. These helpers are:
43
+
44
+ - โœ… Strictly aligned with the **syntax rules of RFC 3987**
45
+ - โœ… Built using a **permissive MIT license**
46
+ - โœ… Designed for both **open source and proprietary use**
47
+ - โœ… Powered by [Lark](https://github.com/lark-parser/lark), a fast, EBNF-based parser
48
+
49
+ > ๐Ÿง  **Note:** This project focuses on **syntax validation only**. RFC 3987 specifies **additional semantic rules** (e.g., Unicode normalization, BiDi constraints, percent-encoding requirements) that must be enforced separately.
50
+
51
+
52
+ ## ๐Ÿ“„ License, Attribution, and Citation
53
+
54
+ **`rfc3987-syntax2`** is licensed under the [MIT License](LICENSE), which allows reuse in both open source and commercial software.
55
+
56
+ This project:
57
+
58
+ - โŒ Does **not** depend on the `rfc3987` Python package (GPL-licensed)
59
+ - โœ… Uses [`lark`](https://github.com/lark-parser/lark), licensed under MIT
60
+ - โœ… Implements grammar from **[RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987)**, using **[RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)** where RFC 3987 delegates syntax
61
+
62
+ > โš ๏ธ This project is **not affiliated with or endorsed by** the authors of RFC 3987 or the `rfc3987` Python package.
63
+
64
+ Please cite this software in accordance with the enclosed CITATION.cff file.
65
+
66
+
67
+ ## โš ๏ธ Limitations
68
+
69
+ The grammar and parser enforce **only the ABNF syntax** defined in RFC 3987. The following are **not validated** and must be handled separately for full compliance:
70
+
71
+ - โœ… Unicode **Normalization Form C (NFC)**
72
+ - โœ… Bidirectional text (**BiDi**) constraints (RFC 3987 ยง4.1)
73
+ - โœ… **Port number ranges** (must be 0โ€“65535)
74
+ - โœ… Valid **IPv6 compression** (only one `::`, max segments)
75
+ - โœ… Context-aware **percent-encoding** requirements
76
+
77
+ ChatGPT 40 was used during the original development process. Errors may exist due to this assistance. Additional review, testing, and bug fixes by human experts is welcome.
78
+
79
+
80
+ ## ๐Ÿ“ฆ Installation
81
+
82
+ ```bash
83
+ pip install rfc3987-syntax2
84
+ ```
85
+
86
+ ## ๐Ÿ›  Usage
87
+
88
+ ### List all supported "terms" (i.e., non-terminals and terminals within ABNF production rules) used to validate the syntax of an IRI according to RFC 3987
89
+
90
+ ```python
91
+ from rfc3987_syntax2 import RFC3987_SYNTAX_TERMS
92
+
93
+ print("Supported terms:")
94
+ for term in RFC3987_SYNTAX_TERMS:
95
+ print(term)
96
+ ```
97
+
98
+ ### Syntactically validate a string using the general-purpose validator
99
+
100
+ ```python
101
+ from rfc3987_syntax2 import is_valid_syntax
102
+
103
+ if is_valid_syntax(term='iri', value='http://github.com'):
104
+ print("โœ“ Valid IRI syntax")
105
+
106
+ if not is_valid_syntax(term='iri', value='bob'):
107
+ print("โœ— Invalid IRI syntax")
108
+
109
+ if not is_valid_syntax(term='iri_reference', value='bob'):
110
+ print("โœ“ Valid IRI-reference syntax")
111
+ ```
112
+
113
+ ### Alternatively, use term-specific helpers to validate RFC 3987 syntax.
114
+
115
+ ```python
116
+ from rfc3987_syntax2 import is_valid_syntax_iri
117
+ from rfc3987_syntax2 import is_valid_syntax_iri_reference
118
+
119
+ if is_valid_syntax_iri('http://github.com'):
120
+ print("โœ“ Valid IRI syntax")
121
+
122
+ if not is_valid_syntax_iri('bob'):
123
+ print("โœ— Invalid IRI syntax")
124
+
125
+ if is_valid_syntax_iri_reference('bob'):
126
+ print("โœ“ Valid IRI-reference syntax")
127
+ ```
128
+
129
+ ### Get the Lark parse tree for a syntax validation (useful for additional semantic validation)
130
+
131
+ ```python
132
+ from rfc3987_syntax2 import parse
133
+
134
+ ptree: ParseTree = parse(term="iri", value="http://github.com")
135
+
136
+ print(ptree)
137
+ ```
138
+
139
+ ## ๐Ÿ“š Sources
140
+
141
+ This grammar was derived from:
142
+
143
+ - **[RFC 3987 โ€“ Internationalized Resource Identifiers (IRIs)]**
144
+ โ†’ Defines IRI syntax and extensions to URI (e.g. Unicode characters, `ucschar`)
145
+ โ†’ https://datatracker.ietf.org/doc/html/rfc3987
146
+
147
+ - **[RFC 3986 โ€“ Uniform Resource Identifier (URI): Generic Syntax)]**
148
+ โ†’ Provides reusable components like `scheme`, `authority`, `ipv4address`, etc.
149
+ โ†’ https://datatracker.ietf.org/doc/html/rfc3986
150
+
151
+ > ๐Ÿ“ When `RFC 3986` is listed as the source, it is **used in accordance with RFC 3987**, which explicitly references it for foundational elements.
152
+
153
+ ### Rule-to-Source Mapping
154
+
155
+ | Rule/Component | Source | Notes |
156
+ |----------------------|------------|-------|
157
+ | `iri` | RFC 3987 | Top-level IRI rule |
158
+ | `iri_reference` | RFC 3987 | Top-level IRI Reference rule |
159
+ | `absolute_iri` | RFC 3987 | Top-level Absolute IRI rule |
160
+ | `scheme` | RFC 3986 | Referenced by RFC 3987 ยง2.2 |
161
+ | `ihier_part` | RFC 3987 | IRI-specific hierarchy |
162
+ | `irelative_ref` | RFC 3987 | IRI-specific relative ref |
163
+ | `irelative_part` | RFC 3987 | IRI-specific relative part |
164
+ | `iauthority` | RFC 3986 | Standard URI authority |
165
+ | `ipath_abempty` | RFC 3986 | Path format variant |
166
+ | `ipath_absolute` | RFC 3986 | Absolute path |
167
+ | `ipath_noscheme` | RFC 3986 | Path disallowing scheme prefix |
168
+ | `ipath_rootless` | RFC 3986 | Used in non-scheme contexts |
169
+ | `iquery` | RFC 3987 | Query extension to URI |
170
+ | `ifragment` | RFC 3987 | Fragment extension to URI |
171
+ | `ipchar`, `isegment` | RFC 3986 | Path characters and segments |
172
+ | `isegment_nz_nc` | RFC 3987 | IRI-specific path constraint |
173
+ | `iunreserved` | RFC 3987 | Includes `ucschar` |
174
+ | `ucschar`, `iprivate`| RFC 3987 | Unicode support |
175
+ | `sub_delims` | RFC 3986 | Reserved characters |
176
+ | `ip_literal` | RFC 3986 | IPv6 or IPvFuture in `[]` |
177
+ | `ipv6address` | RFC 3986 | Expanded forms only |
178
+ | `ipvfuture` | RFC 3986 | Forward-compatible |
179
+ | `ipv4address` | RFC 3986 | Dotted-decimal IPv4 |
180
+ | `ls32` | RFC 3986 | Final 32 bits of IPv6 |
181
+ | `h16`, `dec_octet` | RFC 3986 | Hex and decimal chunks |
182
+ | `port` | RFC 3986 | Optional numeric |
183
+ | `pct_encoded` | RFC 3986 | Percent encoding (e.g. `%20`) |
184
+ | `alpha`, `digit`, `hexdig` | RFC 3986 | Character classes |
@@ -0,0 +1,152 @@
1
+ # rfc3987-syntax2
2
+
3
+ Helper functions to parse and validate the **syntax** of terms defined in **[RFC 3987](https://www.rfc-editor.org/info/rfc3987)** โ€” the IETF standard for Internationalized Resource Identifiers (IRIs).
4
+
5
+ > [!NOTE]
6
+ > This is a maintained fork of <https://github.com/willynilly/rfc3987-syntax>.
7
+
8
+ ## ๐ŸŽฏ Purpose
9
+
10
+ The goal of `rfc3987-syntax2` is to provide a **lightweight, permissively licensed Python module** for validating that strings conform to the **ABNF grammar defined in RFC 3987**. These helpers are:
11
+
12
+ - โœ… Strictly aligned with the **syntax rules of RFC 3987**
13
+ - โœ… Built using a **permissive MIT license**
14
+ - โœ… Designed for both **open source and proprietary use**
15
+ - โœ… Powered by [Lark](https://github.com/lark-parser/lark), a fast, EBNF-based parser
16
+
17
+ > ๐Ÿง  **Note:** This project focuses on **syntax validation only**. RFC 3987 specifies **additional semantic rules** (e.g., Unicode normalization, BiDi constraints, percent-encoding requirements) that must be enforced separately.
18
+
19
+
20
+ ## ๐Ÿ“„ License, Attribution, and Citation
21
+
22
+ **`rfc3987-syntax2`** is licensed under the [MIT License](LICENSE), which allows reuse in both open source and commercial software.
23
+
24
+ This project:
25
+
26
+ - โŒ Does **not** depend on the `rfc3987` Python package (GPL-licensed)
27
+ - โœ… Uses [`lark`](https://github.com/lark-parser/lark), licensed under MIT
28
+ - โœ… Implements grammar from **[RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987)**, using **[RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)** where RFC 3987 delegates syntax
29
+
30
+ > โš ๏ธ This project is **not affiliated with or endorsed by** the authors of RFC 3987 or the `rfc3987` Python package.
31
+
32
+ Please cite this software in accordance with the enclosed CITATION.cff file.
33
+
34
+
35
+ ## โš ๏ธ Limitations
36
+
37
+ The grammar and parser enforce **only the ABNF syntax** defined in RFC 3987. The following are **not validated** and must be handled separately for full compliance:
38
+
39
+ - โœ… Unicode **Normalization Form C (NFC)**
40
+ - โœ… Bidirectional text (**BiDi**) constraints (RFC 3987 ยง4.1)
41
+ - โœ… **Port number ranges** (must be 0โ€“65535)
42
+ - โœ… Valid **IPv6 compression** (only one `::`, max segments)
43
+ - โœ… Context-aware **percent-encoding** requirements
44
+
45
+ ChatGPT 40 was used during the original development process. Errors may exist due to this assistance. Additional review, testing, and bug fixes by human experts is welcome.
46
+
47
+
48
+ ## ๐Ÿ“ฆ Installation
49
+
50
+ ```bash
51
+ pip install rfc3987-syntax2
52
+ ```
53
+
54
+ ## ๐Ÿ›  Usage
55
+
56
+ ### List all supported "terms" (i.e., non-terminals and terminals within ABNF production rules) used to validate the syntax of an IRI according to RFC 3987
57
+
58
+ ```python
59
+ from rfc3987_syntax2 import RFC3987_SYNTAX_TERMS
60
+
61
+ print("Supported terms:")
62
+ for term in RFC3987_SYNTAX_TERMS:
63
+ print(term)
64
+ ```
65
+
66
+ ### Syntactically validate a string using the general-purpose validator
67
+
68
+ ```python
69
+ from rfc3987_syntax2 import is_valid_syntax
70
+
71
+ if is_valid_syntax(term='iri', value='http://github.com'):
72
+ print("โœ“ Valid IRI syntax")
73
+
74
+ if not is_valid_syntax(term='iri', value='bob'):
75
+ print("โœ— Invalid IRI syntax")
76
+
77
+ if not is_valid_syntax(term='iri_reference', value='bob'):
78
+ print("โœ“ Valid IRI-reference syntax")
79
+ ```
80
+
81
+ ### Alternatively, use term-specific helpers to validate RFC 3987 syntax.
82
+
83
+ ```python
84
+ from rfc3987_syntax2 import is_valid_syntax_iri
85
+ from rfc3987_syntax2 import is_valid_syntax_iri_reference
86
+
87
+ if is_valid_syntax_iri('http://github.com'):
88
+ print("โœ“ Valid IRI syntax")
89
+
90
+ if not is_valid_syntax_iri('bob'):
91
+ print("โœ— Invalid IRI syntax")
92
+
93
+ if is_valid_syntax_iri_reference('bob'):
94
+ print("โœ“ Valid IRI-reference syntax")
95
+ ```
96
+
97
+ ### Get the Lark parse tree for a syntax validation (useful for additional semantic validation)
98
+
99
+ ```python
100
+ from rfc3987_syntax2 import parse
101
+
102
+ ptree: ParseTree = parse(term="iri", value="http://github.com")
103
+
104
+ print(ptree)
105
+ ```
106
+
107
+ ## ๐Ÿ“š Sources
108
+
109
+ This grammar was derived from:
110
+
111
+ - **[RFC 3987 โ€“ Internationalized Resource Identifiers (IRIs)]**
112
+ โ†’ Defines IRI syntax and extensions to URI (e.g. Unicode characters, `ucschar`)
113
+ โ†’ https://datatracker.ietf.org/doc/html/rfc3987
114
+
115
+ - **[RFC 3986 โ€“ Uniform Resource Identifier (URI): Generic Syntax)]**
116
+ โ†’ Provides reusable components like `scheme`, `authority`, `ipv4address`, etc.
117
+ โ†’ https://datatracker.ietf.org/doc/html/rfc3986
118
+
119
+ > ๐Ÿ“ When `RFC 3986` is listed as the source, it is **used in accordance with RFC 3987**, which explicitly references it for foundational elements.
120
+
121
+ ### Rule-to-Source Mapping
122
+
123
+ | Rule/Component | Source | Notes |
124
+ |----------------------|------------|-------|
125
+ | `iri` | RFC 3987 | Top-level IRI rule |
126
+ | `iri_reference` | RFC 3987 | Top-level IRI Reference rule |
127
+ | `absolute_iri` | RFC 3987 | Top-level Absolute IRI rule |
128
+ | `scheme` | RFC 3986 | Referenced by RFC 3987 ยง2.2 |
129
+ | `ihier_part` | RFC 3987 | IRI-specific hierarchy |
130
+ | `irelative_ref` | RFC 3987 | IRI-specific relative ref |
131
+ | `irelative_part` | RFC 3987 | IRI-specific relative part |
132
+ | `iauthority` | RFC 3986 | Standard URI authority |
133
+ | `ipath_abempty` | RFC 3986 | Path format variant |
134
+ | `ipath_absolute` | RFC 3986 | Absolute path |
135
+ | `ipath_noscheme` | RFC 3986 | Path disallowing scheme prefix |
136
+ | `ipath_rootless` | RFC 3986 | Used in non-scheme contexts |
137
+ | `iquery` | RFC 3987 | Query extension to URI |
138
+ | `ifragment` | RFC 3987 | Fragment extension to URI |
139
+ | `ipchar`, `isegment` | RFC 3986 | Path characters and segments |
140
+ | `isegment_nz_nc` | RFC 3987 | IRI-specific path constraint |
141
+ | `iunreserved` | RFC 3987 | Includes `ucschar` |
142
+ | `ucschar`, `iprivate`| RFC 3987 | Unicode support |
143
+ | `sub_delims` | RFC 3986 | Reserved characters |
144
+ | `ip_literal` | RFC 3986 | IPv6 or IPvFuture in `[]` |
145
+ | `ipv6address` | RFC 3986 | Expanded forms only |
146
+ | `ipvfuture` | RFC 3986 | Forward-compatible |
147
+ | `ipv4address` | RFC 3986 | Dotted-decimal IPv4 |
148
+ | `ls32` | RFC 3986 | Final 32 bits of IPv6 |
149
+ | `h16`, `dec_octet` | RFC 3986 | Hex and decimal chunks |
150
+ | `port` | RFC 3986 | Optional numeric |
151
+ | `pct_encoded` | RFC 3986 | Percent encoding (e.g. `%20`) |
152
+ | `alpha`, `digit`, `hexdig` | RFC 3986 | Character classes |
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "rfc3987-syntax2"
7
+ version = "1.1.0rc1"
8
+ description = "Helper functions to syntactically validate strings according to RFC 3987."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICEN[CS]E*"]
13
+ keywords = ["RFC 3987", "RFC3987", "validator", "syntax", "parser"]
14
+ authors = [
15
+ { name = "Jan Kowalleck" },
16
+ { name = "Will Riley", email = "wanderingwill@gmail.com" }
17
+ ]
18
+ classifiers = [
19
+ # ALPHA - not all features of RFC 3987 are implemented, yet
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: Education",
23
+ "Intended Audience :: Information Technology",
24
+ "Intended Audience :: Science/Research",
25
+ "Intended Audience :: System Administrators",
26
+ "License :: OSI Approved :: MIT License",
27
+ "Natural Language :: English",
28
+ "Programming Language :: Python",
29
+ "Programming Language :: Python :: 3",
30
+ "Topic :: Scientific/Engineering",
31
+ "Topic :: Software Development",
32
+ "Topic :: Utilities"
33
+ ]
34
+ dependencies = ["lark>=1.2.2"]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/jkowalleck/rfc3987-syntax2"
38
+ Documentation = "https://github.com/jkowalleck/rfc3987-syntax2#readme"
39
+ Issues = "https://github.com/jkowalleck/rfc3987-syntax2/issues"
40
+ Source = "https://github.com/jkowalleck/rfc3987-syntax2"
41
+
42
+ [project.optional-dependencies]
43
+ testing = [
44
+ "pytest>=8.3.5",
45
+ ]
46
+
47
+ [tool.pytest.ini_options]
48
+ pythonpath = ["src"]
49
+
50
+ [tool.hatch.build.targets.sdist]
51
+ exclude = [
52
+ "/.*",
53
+ "/_*",
54
+ ]
55
+ include = [
56
+ "/src",
57
+ "/tests"
58
+ ]
59
+
60
+ [tool.hatch.build.targets.wheel]
61
+ packages = ["src/rfc3987_syntax2"]
@@ -0,0 +1 @@
1
+ from .syntax_helpers import *
@@ -0,0 +1,152 @@
1
+ from lark import Lark, ParseTree, exceptions
2
+
3
+ from pathlib import Path
4
+
5
+ from .utils import load_grammar
6
+
7
+ RFC3987_SYNTAX_PARSER_TYPE: str = "earley"
8
+ RFC3987_SYNTAX_GRAMMAR_PATH: Path = Path(__file__).parent / "syntax_rfc3987.lark"
9
+ RFC3987_SYNTAX_TERMS: list[str] = [
10
+ "iri",
11
+ "iri_reference",
12
+ "absolute_iri",
13
+ "scheme",
14
+ "irelative_ref",
15
+ "irelative_part"
16
+ "ihier_part",
17
+ "iauthority",
18
+ "iuserinfo",
19
+ "ihost",
20
+ "ireg_name",
21
+ "ipath_abempty",
22
+ "isegment",
23
+ "isegment_nz",
24
+ "isegment_nz_nc",
25
+ "ipchar",
26
+ "iquery",
27
+ "ifragment",
28
+ "iunreserved",
29
+ "ucschar",
30
+ "iprivate",
31
+ "sub_delims",
32
+ "ip_literal",
33
+ "ipvfuture",
34
+ "ipv6address",
35
+ "h16",
36
+ "ls32",
37
+ "ipv4address",
38
+ "dec_octet",
39
+ "digit",
40
+ "non_zero",
41
+ "unreserved",
42
+ "alpha",
43
+ "hexdig",
44
+ "port",
45
+ "pct_encoded",
46
+ ]
47
+
48
+ grammar: str = load_grammar(RFC3987_SYNTAX_GRAMMAR_PATH)
49
+
50
+ syntax_parser = Lark(grammar, start=["iri", "iri_reference", "absolute_iri"], parser=RFC3987_SYNTAX_PARSER_TYPE)
51
+
52
+
53
+ def parse(term: str, value: str) -> ParseTree:
54
+ return syntax_parser.parse(value, start=term)
55
+
56
+
57
+ def is_valid_syntax(term: str, value: str):
58
+ try:
59
+ parse(term=term, value=value)
60
+ return True
61
+ except exceptions.LarkError:
62
+ return False
63
+
64
+
65
+ def make_syntax_validator(rule_name):
66
+ parser = Lark(grammar, start=rule_name, parser=RFC3987_SYNTAX_PARSER_TYPE)
67
+
68
+ def syntax_validator(text):
69
+ try:
70
+ parser.parse(text)
71
+ return True
72
+ except exceptions.LarkError:
73
+ return False
74
+
75
+ return syntax_validator
76
+
77
+
78
+ is_valid_syntax_iri = make_syntax_validator("iri")
79
+
80
+ is_valid_syntax_iri_reference = make_syntax_validator("iri_reference")
81
+
82
+ is_valid_syntax_absolute_iri = make_syntax_validator("absolute_iri")
83
+
84
+ is_valid_syntax_irelative_ref = make_syntax_validator("irelative_ref")
85
+
86
+ is_valid_syntax_irelative_part = make_syntax_validator("irelative_part")
87
+
88
+ is_valid_syntax_ihier_part = make_syntax_validator("ihier_part")
89
+
90
+ is_valid_syntax_iauthority = make_syntax_validator("iauthority")
91
+
92
+ is_valid_syntax_iuserinfo = make_syntax_validator("iuserinfo")
93
+
94
+ is_valid_syntax_ihost = make_syntax_validator("ihost")
95
+
96
+ is_valid_syntax_ireg_name = make_syntax_validator("ireg_name")
97
+
98
+ is_valid_syntax_ipath = make_syntax_validator("ipath")
99
+
100
+ is_valid_syntax_ipath_abempty = make_syntax_validator("ipath_abempty")
101
+
102
+ is_valid_syntax_ipath_absolute = make_syntax_validator("ipath_absolute")
103
+
104
+ is_valid_syntax_ipath_noscheme = make_syntax_validator("ipath_noscheme")
105
+
106
+ is_valid_syntax_ipath_rootless = make_syntax_validator("ipath_rootless")
107
+
108
+ is_valid_syntax_ipath_empty = make_syntax_validator("ipath_empty")
109
+
110
+ is_valid_syntax_isegment = make_syntax_validator("isegment")
111
+
112
+ is_valid_syntax_isegment_nz = make_syntax_validator("isegment_nz")
113
+
114
+ is_valid_syntax_isegment_nz_nc = make_syntax_validator("isegment_nz_nc")
115
+
116
+ is_valid_syntax_ipchar = make_syntax_validator("ipchar")
117
+
118
+ is_valid_syntax_iquery = make_syntax_validator("iquery")
119
+
120
+ is_valid_syntax_ifragment = make_syntax_validator("ifragment")
121
+
122
+ is_valid_syntax_iunreserved = make_syntax_validator("iunreserved")
123
+
124
+ is_valid_syntax_ucschar = make_syntax_validator("ucschar")
125
+
126
+ is_valid_syntax_iprivate = make_syntax_validator("iprivate")
127
+
128
+ is_valid_syntax_sub_delims = make_syntax_validator("sub_delims")
129
+
130
+ is_valid_syntax_ip_literal = make_syntax_validator("ip_literal")
131
+
132
+ is_valid_syntax_ipvfuture = make_syntax_validator("ipvfuture")
133
+
134
+ is_valid_syntax_ipv6address = make_syntax_validator("ipv6address")
135
+
136
+ is_valid_syntax_h16 = make_syntax_validator("h16")
137
+
138
+ is_valid_syntax_ls32 = make_syntax_validator("ls32")
139
+
140
+ is_valid_syntax_ipv4address = make_syntax_validator("ipv4address")
141
+
142
+ is_valid_syntax_dec_octet = make_syntax_validator("dec_octet")
143
+
144
+ is_valid_syntax_unreserved = make_syntax_validator("unreserved")
145
+
146
+ is_valid_syntax_alpha = make_syntax_validator("alpha")
147
+
148
+ is_valid_syntax_digit = make_syntax_validator("digit")
149
+
150
+ is_valid_syntax_hexdig = make_syntax_validator("hexdig")
151
+
152
+ is_valid_syntax_port = make_syntax_validator("port")
@@ -0,0 +1,111 @@
1
+
2
+ iri: scheme ":" ihier_part ("?" iquery)? ("#" ifragment)?
3
+
4
+ iri_reference: iri | irelative_ref
5
+
6
+ absolute_iri: scheme ":" ihier_part ("?" iquery)?
7
+
8
+ scheme: alpha (alpha | digit | "+" | "-" | ".")*
9
+
10
+ ihier_part: "//" iauthority ipath_abempty
11
+ | ipath_absolute
12
+ | ipath_rootless
13
+ | ipath_empty
14
+
15
+ irelative_ref: irelative_part ("?" iquery)? ("#" ifragment)?
16
+
17
+ irelative_part: "//" iauthority ipath_abempty
18
+ | ipath_absolute
19
+ | ipath_noscheme
20
+ | ipath_empty
21
+
22
+ iauthority: (iuserinfo "@")? ihost (":" port)?
23
+
24
+ iuserinfo: (iunreserved | pct_encoded | sub_delims | ":")*
25
+
26
+ ihost: ip_literal | ipv4address | ireg_name
27
+
28
+ ireg_name: (iunreserved | pct_encoded | sub_delims)*
29
+
30
+ ipath: ipath_abempty
31
+ | ipath_absolute
32
+ | ipath_noscheme
33
+ | ipath_rootless
34
+ | ipath_empty
35
+
36
+ ipath_abempty: ("/" isegment)*
37
+
38
+ ipath_absolute: "/" (isegment_nz ("/" isegment)*)?
39
+
40
+ ipath_noscheme: isegment_nz_nc ("/" isegment)*
41
+
42
+ ipath_rootless: isegment_nz ("/" isegment)*
43
+
44
+ ipath_empty: -> empty
45
+
46
+ isegment: ipchar*
47
+
48
+ isegment_nz: ipchar+
49
+
50
+ isegment_nz_nc: (iunreserved | pct_encoded | sub_delims | "@")+
51
+
52
+ ipchar: iunreserved | pct_encoded | sub_delims | ":" | "@"
53
+
54
+ iquery: (ipchar | iprivate | "/" | "?")*
55
+
56
+ ifragment: (ipchar | "/" | "?")*
57
+
58
+ iunreserved: alpha | digit | "-" | "." | "_" | "~" | ucschar
59
+
60
+ ucschar: /[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]/
61
+ iprivate: /[\uE000-\uF8FF]/
62
+
63
+ sub_delims: "!" | "$" | "&" | "'" | "(" | ")"
64
+ | "*" | "+" | "," | ";" | "="
65
+
66
+ ip_literal: "[" (ipv6address | ipvfuture) "]"
67
+
68
+ ipvfuture: "v" hexdig+ "." (unreserved | sub_delims | ":")+
69
+
70
+ ipv6address: h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" ls32
71
+ | "::" h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" ls32
72
+ | h16 "::" h16 ":" h16 ":" h16 ":" h16 ":" ls32
73
+ | h16 ":" h16 "::" h16 ":" h16 ":" h16 ":" ls32
74
+ | h16 ":" h16 ":" h16 "::" h16 ":" h16 ":" ls32
75
+ | h16 ":" h16 ":" h16 ":" h16 "::" h16 ":" ls32
76
+ | h16 ":" h16 ":" h16 ":" h16 ":" h16 "::" ls32
77
+ | h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" h16 "::" h16
78
+ | h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" h16 "::"
79
+
80
+ h16: hexdig
81
+ | hexdig hexdig
82
+ | hexdig hexdig hexdig
83
+ | hexdig hexdig hexdig hexdig
84
+
85
+ ls32: h16 ":" h16 | ipv4address
86
+
87
+ ipv4address: dec_octet "." dec_octet "." dec_octet "." dec_octet
88
+
89
+ dec_octet: digit
90
+ | non_zero digit
91
+ | "1" digit digit
92
+ | "2" ("0".."4") digit
93
+ | "25" ("0".."5")
94
+
95
+ digit: T_DIGIT
96
+ T_DIGIT: /[0-9]/
97
+
98
+ non_zero: T_NON_ZERO
99
+ T_NON_ZERO: /[1-9]/
100
+
101
+ unreserved: alpha | digit | "-" | "." | "_" | "~"
102
+
103
+ alpha: T_ALPHA
104
+ T_ALPHA: /[A-Za-z]/
105
+
106
+ hexdig: T_HEXDIG
107
+ T_HEXDIG: /[0-9A-Fa-f]/
108
+
109
+ port: digit*
110
+
111
+ pct_encoded: "%" hexdig hexdig