podns 0.1.1__py3-none-any.whl
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.
- podns/__init__.py +37 -0
- podns/dns.py +51 -0
- podns/error.py +76 -0
- podns/parser.py +201 -0
- podns/pronouns.py +60 -0
- podns/py.typed +0 -0
- podns-0.1.1.dist-info/METADATA +67 -0
- podns-0.1.1.dist-info/RECORD +10 -0
- podns-0.1.1.dist-info/WHEEL +4 -0
- podns-0.1.1.dist-info/licenses/LICENSE +21 -0
podns/__init__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-present abigail phoebe <abigail@phoebe.sh>
|
|
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.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from .dns import fetch_pronouns_from_domain_sync, fetch_pronouns_from_domain_async
|
|
26
|
+
from .error import PODNSError
|
|
27
|
+
from .parser import parse_pronoun_records
|
|
28
|
+
from .pronouns import PronounsResponse
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__: tuple[str, ...] = (
|
|
32
|
+
"fetch_pronouns_from_domain_sync",
|
|
33
|
+
"fetch_pronouns_from_domain_async",
|
|
34
|
+
"PODNSError",
|
|
35
|
+
"parse_pronoun_records",
|
|
36
|
+
"PronounsResponse",
|
|
37
|
+
)
|
podns/dns.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-present abigail phoebe <abigail@phoebe.sh>
|
|
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.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import dns.asyncresolver
|
|
26
|
+
import dns.resolver
|
|
27
|
+
|
|
28
|
+
from podns.parser import parse_pronoun_records
|
|
29
|
+
from podns.pronouns import PronounsResponse
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__: tuple[str, ...] = (
|
|
33
|
+
"fetch_pronouns_from_domain_sync",
|
|
34
|
+
"fetch_pronouns_from_domain_async",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def fetch_pronouns_from_domain_sync(domain: str, *, pedantic: bool = False) -> PronounsResponse | None:
|
|
39
|
+
try:
|
|
40
|
+
dns_answers = dns.resolver.resolve(f"pronouns.{domain}", "TXT")
|
|
41
|
+
except dns.resolver.NXDOMAIN:
|
|
42
|
+
return None
|
|
43
|
+
return parse_pronoun_records(list(dns_answers), pedantic=pedantic)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def fetch_pronouns_from_domain_async(domain: str, *, pedantic: bool = False) -> PronounsResponse | None:
|
|
47
|
+
try:
|
|
48
|
+
dns_answers = await dns.asyncresolver.resolve(f"pronouns.{domain}", "TXT")
|
|
49
|
+
except dns.resolver.NXDOMAIN:
|
|
50
|
+
return None
|
|
51
|
+
return parse_pronoun_records(list(dns_answers), pedantic=pedantic)
|
podns/error.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-present abigail phoebe <abigail@phoebe.sh>
|
|
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.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__all__: tuple[str, ...] = (
|
|
26
|
+
"PODNSError",
|
|
27
|
+
"PODNSParserError",
|
|
28
|
+
"PODNSParserSetsAfterNone",
|
|
29
|
+
"PODNSParserInvalidTag",
|
|
30
|
+
"PODNSParserEmptySegmentInPronounSet",
|
|
31
|
+
"PODNSParserTagWithoutPronounSet",
|
|
32
|
+
"PODNSParserTrailingSlash",
|
|
33
|
+
"PODNSParserInsufficientPronounSetValues",
|
|
34
|
+
"PODNSParserIllegalCharacterInPronouns",
|
|
35
|
+
"PODNSParserTooManyPronounSetValues",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class PODNSError(Exception):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PODNSParserError(PODNSError):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PODNSParserSetsAfterNone(PODNSParserError):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class PODNSParserInvalidTag(PODNSParserError):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class PODNSParserEmptySegmentInPronounSet(PODNSParserError):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class PODNSParserTagWithoutPronounSet(PODNSParserError):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class PODNSParserTrailingSlash(PODNSParserError):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PODNSParserInsufficientPronounSetValues(PODNSParserError):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PODNSParserIllegalCharacterInPronouns(PODNSParserError):
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class PODNSParserTooManyPronounSetValues(PODNSParserError):
|
|
76
|
+
pass
|
podns/parser.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-present abigail phoebe <abigail@phoebe.sh>
|
|
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.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import Final, Literal
|
|
26
|
+
|
|
27
|
+
from podns.error import (
|
|
28
|
+
PODNSParserEmptySegmentInPronounSet,
|
|
29
|
+
PODNSParserIllegalCharacterInPronouns,
|
|
30
|
+
PODNSParserInsufficientPronounSetValues,
|
|
31
|
+
PODNSParserInvalidTag,
|
|
32
|
+
PODNSParserSetsAfterNone,
|
|
33
|
+
PODNSParserTagWithoutPronounSet,
|
|
34
|
+
PODNSParserTooManyPronounSetValues,
|
|
35
|
+
PODNSParserTrailingSlash,
|
|
36
|
+
)
|
|
37
|
+
from podns.pronouns import (
|
|
38
|
+
PronounRecord,
|
|
39
|
+
Pronouns,
|
|
40
|
+
PronounsResponse,
|
|
41
|
+
PronounTag,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__: tuple[str, ...] = (
|
|
46
|
+
"parse_pronoun_records",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
ILLEGAL_PRONOUN_CHARACTERS: Final[Literal[r'*;/!#']] = r'*;/!#'
|
|
51
|
+
PARSER_CONVERSIONS: Final[dict[str, str]] = {
|
|
52
|
+
"it/its": "it/it/its/its/itself",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _normalise_record(record: str) -> str:
|
|
57
|
+
# remove comments, capitalisation and leading/trailing whitespace.
|
|
58
|
+
record = record.split("#")[0].lower().strip()
|
|
59
|
+
|
|
60
|
+
# remove spaces around /'s
|
|
61
|
+
pronoun_segment: str = record.split(";")[0]
|
|
62
|
+
pronoun_segments: list[str] = pronoun_segment.split("/")
|
|
63
|
+
pronoun_segment: str = '/'.join(seg.strip() for seg in pronoun_segments)
|
|
64
|
+
|
|
65
|
+
# ensure that there are no illegal characters present
|
|
66
|
+
illegal_characters_set: set[str] = set(ILLEGAL_PRONOUN_CHARACTERS)
|
|
67
|
+
for seg in pronoun_segments:
|
|
68
|
+
if illegal_characters_set.difference(seg) != illegal_characters_set:
|
|
69
|
+
raise PODNSParserIllegalCharacterInPronouns(f"{seg=} contains an illegal character defined by: {ILLEGAL_PRONOUN_CHARACTERS=}")
|
|
70
|
+
|
|
71
|
+
# add tag part back to record
|
|
72
|
+
tag_segment_parts: list[str] = record.split(";")
|
|
73
|
+
if len(tag_segment_parts) == 1:
|
|
74
|
+
full_record = pronoun_segment
|
|
75
|
+
else:
|
|
76
|
+
tag_segment: str = ';'.join(tag_segment_parts[1:])
|
|
77
|
+
full_record: str = pronoun_segment + ";" + tag_segment
|
|
78
|
+
|
|
79
|
+
# normalise repeating ;
|
|
80
|
+
_strip_chars: bool = False
|
|
81
|
+
stripped_record: str = ""
|
|
82
|
+
for char in full_record:
|
|
83
|
+
if char == ";" and not _strip_chars:
|
|
84
|
+
_strip_chars = True
|
|
85
|
+
stripped_record += char
|
|
86
|
+
elif char != ";" and _strip_chars:
|
|
87
|
+
_strip_chars = False
|
|
88
|
+
stripped_record += char
|
|
89
|
+
elif not _strip_chars:
|
|
90
|
+
stripped_record += char
|
|
91
|
+
|
|
92
|
+
return stripped_record
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _parse_pronouns(record, *, pedantic: bool) -> Pronouns:
|
|
96
|
+
# we do not care about the tag section here.
|
|
97
|
+
pronoun_part = record.split(";")[0]
|
|
98
|
+
|
|
99
|
+
if pronoun_part in PARSER_CONVERSIONS.keys():
|
|
100
|
+
pronoun_part = PARSER_CONVERSIONS[pronoun_part]
|
|
101
|
+
|
|
102
|
+
# check for trailing slash
|
|
103
|
+
if pronoun_part.endswith("/") and pedantic:
|
|
104
|
+
raise PODNSParserTrailingSlash(f"Trailing slash in pronouns with {pedantic=} - {record=}")
|
|
105
|
+
|
|
106
|
+
# check for empty segment
|
|
107
|
+
pronouns_set = pronoun_part.split("/")
|
|
108
|
+
if any(True for p in pronouns_set if len(p) == 0):
|
|
109
|
+
raise PODNSParserEmptySegmentInPronounSet(f"Empty pronoun segment: {record=}")
|
|
110
|
+
|
|
111
|
+
# ensure at least subject/object are present
|
|
112
|
+
if len(pronouns_set) < 2:
|
|
113
|
+
raise PODNSParserInsufficientPronounSetValues(f"There must be at least subject and object pronouns: {record=}")
|
|
114
|
+
|
|
115
|
+
if len(pronouns_set) > 5 and pedantic:
|
|
116
|
+
raise PODNSParserTooManyPronounSetValues(f"There are too many provided pronoun values: {record=}")
|
|
117
|
+
|
|
118
|
+
# appropriately parse into a `Pronouns` object
|
|
119
|
+
possessive_determiner = None
|
|
120
|
+
if len(pronouns_set) > 2:
|
|
121
|
+
possessive_determiner = pronouns_set[2]
|
|
122
|
+
|
|
123
|
+
possessive_pronoun = None
|
|
124
|
+
if len(pronouns_set) > 3:
|
|
125
|
+
possessive_pronoun = pronouns_set[3]
|
|
126
|
+
|
|
127
|
+
reflexive = None
|
|
128
|
+
if len(pronouns_set) > 4:
|
|
129
|
+
reflexive = pronouns_set[4]
|
|
130
|
+
|
|
131
|
+
return Pronouns(
|
|
132
|
+
subject=pronouns_set[0],
|
|
133
|
+
object=pronouns_set[1],
|
|
134
|
+
possessive_determiner=possessive_determiner,
|
|
135
|
+
possessive_pronoun=possessive_pronoun,
|
|
136
|
+
reflexive=reflexive,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _parse_tags(record, *, pedantic: bool) -> set[PronounTag]:
|
|
141
|
+
parts = record.rsplit(";")
|
|
142
|
+
if len(parts) == 1 and ";" in record:
|
|
143
|
+
if pedantic:
|
|
144
|
+
raise PODNSParserTagWithoutPronounSet(f"A tag was defined without a preceding pronoun set declaration: {record=}")
|
|
145
|
+
else:
|
|
146
|
+
return set()
|
|
147
|
+
|
|
148
|
+
pronoun_tags: set[PronounTag] = set()
|
|
149
|
+
parsed_tags = set(parts[1:]).difference("")
|
|
150
|
+
for parsed_tag in parsed_tags:
|
|
151
|
+
try:
|
|
152
|
+
pronoun_tags.add(PronounTag(parsed_tag))
|
|
153
|
+
except ValueError:
|
|
154
|
+
if pedantic:
|
|
155
|
+
raise PODNSParserInvalidTag(f"Invalid tag: {parsed_tag=}")
|
|
156
|
+
|
|
157
|
+
return pronoun_tags
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _parse_record(record: str, *, pedantic: bool) -> PronounRecord:
|
|
161
|
+
# parse the pronouns and tags part into an appropriate record
|
|
162
|
+
pronouns: Pronouns = _parse_pronouns(record, pedantic=pedantic)
|
|
163
|
+
tags: set[PronounTag] = _parse_tags(record, pedantic=pedantic)
|
|
164
|
+
|
|
165
|
+
if ( # specifically mark they/them as plural
|
|
166
|
+
pronouns.subject == "they"
|
|
167
|
+
and pronouns.object == "them"
|
|
168
|
+
and PronounTag.PLURAL not in tags
|
|
169
|
+
):
|
|
170
|
+
tags.add(PronounTag.PLURAL)
|
|
171
|
+
|
|
172
|
+
return PronounRecord(pronouns=pronouns, tags=tags)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def parse_pronoun_records(pronoun_records: list[str], *, pedantic: bool = False) -> PronounsResponse:
|
|
176
|
+
uses_any_pronouns: bool = False
|
|
177
|
+
uses_name_only: bool = False
|
|
178
|
+
records: list[PronounRecord] = []
|
|
179
|
+
|
|
180
|
+
for record in pronoun_records:
|
|
181
|
+
normalised_record: str = _normalise_record(record)
|
|
182
|
+
if len(normalised_record) == 0: # empty record
|
|
183
|
+
continue
|
|
184
|
+
elif normalised_record.startswith("!"): # none; use name only declarator
|
|
185
|
+
uses_name_only = True
|
|
186
|
+
continue
|
|
187
|
+
elif normalised_record.startswith("*"): # wildcard; any pronoun is declarator
|
|
188
|
+
uses_any_pronouns = True
|
|
189
|
+
continue
|
|
190
|
+
else: # pronoun set
|
|
191
|
+
parsed_record: PronounRecord = _parse_record(normalised_record, pedantic=pedantic)
|
|
192
|
+
records.append(parsed_record)
|
|
193
|
+
|
|
194
|
+
if pedantic and uses_name_only and len(records) > 0:
|
|
195
|
+
raise PODNSParserSetsAfterNone(f"{uses_name_only=} and {len(records) > 0=}.")
|
|
196
|
+
|
|
197
|
+
return PronounsResponse(
|
|
198
|
+
uses_any_pronouns=uses_any_pronouns,
|
|
199
|
+
uses_name_only=uses_name_only,
|
|
200
|
+
records=[] if uses_name_only else records,
|
|
201
|
+
)
|
podns/pronouns.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-present abigail phoebe <abigail@phoebe.sh>
|
|
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.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from dataclasses import dataclass
|
|
26
|
+
from enum import StrEnum
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__: tuple[str, ...] = (
|
|
30
|
+
"PronounsResponse",
|
|
31
|
+
"PronounTag",
|
|
32
|
+
"Pronouns",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class PronounTag(StrEnum):
|
|
37
|
+
PREFERRED = "preferred"
|
|
38
|
+
PLURAL = "plural"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(slots=True, frozen=True)
|
|
42
|
+
class Pronouns:
|
|
43
|
+
subject: str
|
|
44
|
+
object: str
|
|
45
|
+
possessive_determiner: str | None
|
|
46
|
+
possessive_pronoun: str | None
|
|
47
|
+
reflexive: str | None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(slots=True, frozen=True)
|
|
51
|
+
class PronounRecord:
|
|
52
|
+
pronouns: Pronouns
|
|
53
|
+
tags: set[PronounTag]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(slots=True, frozen=True)
|
|
57
|
+
class PronounsResponse:
|
|
58
|
+
uses_any_pronouns: bool
|
|
59
|
+
uses_name_only: bool
|
|
60
|
+
records: list[PronounRecord]
|
podns/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: podns
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A Pronouns over DNS specification compliant Python API.
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Author: abigail phoebe
|
|
8
|
+
Author-email: abigail@phoebe.sh
|
|
9
|
+
Requires-Python: >=3.14
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: dnspython (>=2.8.0)
|
|
14
|
+
Project-URL: Bug Tracker, https://github.com/ijsbol/podns_py/issues
|
|
15
|
+
Project-URL: Homepage, https://github.com/ijsbol/podns_py
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# podns_py
|
|
19
|
+
|
|
20
|
+
A [Pronouns over DNS](https://github.com/CutieZone/pronouns-over-dns/) specification compliant Python API.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
### Fetching from domain record.
|
|
26
|
+
|
|
27
|
+
If you want to fetch someones pronouns from their domain, see the below:
|
|
28
|
+
|
|
29
|
+
Note that we support both synchronous and asynchronous lookups.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
|
|
35
|
+
import podns.dns
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def main() -> None:
|
|
39
|
+
domain = "abigail.sh"
|
|
40
|
+
podns.dns.fetch_pronouns_from_domain_sync(domain)
|
|
41
|
+
await podns.dns.fetch_pronouns_from_domain_async(domain)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
asyncio.run(main())
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Parsing a raw list
|
|
49
|
+
|
|
50
|
+
If you already have fetched the users pronouns, or are just parsing a raw literal:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import podns.parser
|
|
54
|
+
|
|
55
|
+
podns.parser.parse_pronoun_records([
|
|
56
|
+
"she/her",
|
|
57
|
+
"they/them/theirs;preferred"
|
|
58
|
+
])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Optional pedantic `kwarg` on user APIs
|
|
62
|
+
|
|
63
|
+
For all user-level APIs (that is, `podns.dns.fetch_pronouns_from_domain_*` and `podns.parser.parse_pronoun_records`), there is an optional kwarg, `pedantic`, that defaults to `False`.
|
|
64
|
+
|
|
65
|
+
- Setting this to `True` will raise errors on all specification-violating parse errors from the provided records.
|
|
66
|
+
- Setting this to `False` will only raise errors on egregious specification violations that make parsing impossible. When set to `False`, podns will do its' best to infer intent when met with trivial violations, it will however never return a `podns.pronouns.PronounsResponse` that violates the specification.
|
|
67
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
podns/__init__.py,sha256=kMQV4rZozSEsiUq7mYsziyYgfsX3VG87jBYRqKCXL50,1485
|
|
2
|
+
podns/dns.py,sha256=zGLPEvamxjRdZCFTvrEhO1Qa4QVZ5UBpaWNqNpyO264,1999
|
|
3
|
+
podns/error.py,sha256=k1L5jybcQ-bdels_wsJz-1oRMrPrlyURJGcgw8ElkUs,2118
|
|
4
|
+
podns/parser.py,sha256=jMypxkVDauybcAPHUma_DG6R_-mqEeUH2F82aPhSVjA,7252
|
|
5
|
+
podns/pronouns.py,sha256=hcH0ZIi0SjniE3Aq53HgDu5NQF-op6Q-vaKeSyh0B68,1779
|
|
6
|
+
podns/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
podns-0.1.1.dist-info/METADATA,sha256=-02_Yf6CjVSTt_F69X-DeLi2_OEdgeoacZ8gi9hAA_4,2049
|
|
8
|
+
podns-0.1.1.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
|
|
9
|
+
podns-0.1.1.dist-info/licenses/LICENSE,sha256=wcpZDgCp7rR4gv4QLE-rmgeYYEyX3-MO9RDyGxldD0s,1099
|
|
10
|
+
podns-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 abigail phoebe ୧ ‧₊˚ 🍵 ⋅ᰔᩚ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|