fmtr.tools 1.3.13__py3-none-any.whl → 1.3.14__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.

Potentially problematic release.


This version of fmtr.tools might be problematic. Click here for more details.

@@ -2,6 +2,7 @@ import dns
2
2
  import httpx
3
3
  from dataclasses import dataclass
4
4
  from dns import rcode as dnsrcode
5
+ from dns import reversename
5
6
  from dns.message import Message, QueryMessage
6
7
  from dns.rrset import RRset
7
8
  from functools import cached_property
@@ -37,6 +38,7 @@ class Response(BaseDNSData):
37
38
 
38
39
  http: Optional[httpx.Response] = None
39
40
  is_complete: bool = False
41
+ blocked_by: Optional[str] = None
40
42
 
41
43
  @classmethod
42
44
  def from_http(cls, response: httpx.Response) -> Self:
@@ -142,14 +144,16 @@ class Exchange:
142
144
 
143
145
  request: Request
144
146
  response: Optional[Response] = None
147
+ is_internal: bool = False
148
+ client_name: Optional[str] = None
149
+
145
150
 
146
151
 
147
152
  @classmethod
148
- def from_wire(cls, wire: bytes, ip: str, port: int) -> Self:
153
+ def from_wire(cls, wire: bytes, **kwargs) -> Self:
149
154
  request = Request(wire)
150
155
  response = Response.from_message(request.get_response_template())
151
-
152
- return cls(request=request, response=response, ip=ip, port=port)
156
+ return cls(request=request, response=response, **kwargs)
153
157
 
154
158
  @cached_property
155
159
  def client(self):
@@ -202,3 +206,15 @@ class Exchange:
202
206
  """
203
207
  data = tuple(self.request.question.to_text().split())
204
208
  return data
209
+
210
+ @cached_property
211
+ def reverse(self) -> Self:
212
+ """
213
+
214
+ Create an Exchange for a reverse lookup of this Exchange's client IP.
215
+
216
+ """
217
+ name = reversename.from_address(self.ip)
218
+ query = dns.message.make_query(name, dns.rdatatype.PTR)
219
+ exchange = self.__class__.from_wire(query.to_wire(), ip=self.ip, port=self.port, is_internal=True)
220
+ return exchange
@@ -68,22 +68,51 @@ class Plain:
68
68
  exchange.response.message.id = exchange.request.message.id
69
69
  exchange.response.is_complete = True
70
70
 
71
- def handle(self, exchange: Exchange):
71
+ def get_span(self, exchange: Exchange):
72
72
  """
73
73
 
74
- Check validity of request, presence in cache and resolve.
74
+ Get handling span
75
75
 
76
76
  """
77
77
  request = exchange.request
78
+ span = logger.span(
79
+ f'Handling request {exchange.client_name=} {request.message.id=} {request.type_text} {request.name_text} {request.question=}...'
80
+ )
81
+ return span
78
82
 
79
- if not request.is_valid:
80
- raise ValueError(f'Only one question per request is supported. Got {len(request.question)} questions.')
83
+ def log_response(self, exchange: Exchange):
84
+ """
81
85
 
82
- span = logger.span(
83
- f'Handling request {request.message.id=} {request.type_text} {request.name_text} {request.question=} {exchange.ip=} {exchange.port=}...'
86
+ Log when resolution complete
87
+
88
+ """
89
+ request = exchange.request
90
+ response = exchange.response
91
+
92
+ logger.info(
93
+ f'Resolution complete {exchange.client_name=} {request.message.id=} {request.type_text} {request.name_text} {request.question=} {response.is_complete=} {response.rcode=} {response.rcode_text=} {response.answer=} {response.blocked_by=}...'
84
94
  )
85
- with span:
86
95
 
96
+
97
+
98
+ def handle(self, exchange: Exchange):
99
+ """
100
+
101
+ Check validity of request, reverse lookup client address, check presence in cache and resolve.
102
+
103
+ """
104
+
105
+ if not exchange.request.is_valid:
106
+ raise ValueError(f'Only one question per request is supported. Got {len(exchange.request.question)} questions.')
107
+
108
+ if not exchange.is_internal:
109
+ self.handle(exchange.reverse)
110
+ client_name = exchange.reverse.question_last.name.to_text()
111
+ if not exchange.reverse.response.answer:
112
+ logger.warning(f'Client name could not be resolved {client_name=}.')
113
+ exchange.client_name = client_name
114
+
115
+ with self.get_span(exchange):
87
116
  with logger.span(f'Checking cache...'):
88
117
  self.check_cache(exchange)
89
118
 
@@ -92,9 +121,6 @@ class Plain:
92
121
  exchange.response.is_complete = True
93
122
 
94
123
  self.cache[exchange.key] = exchange.response
95
- logger.info(f'Resolution complete {request.message.id=} {exchange.response.rcode_text=} {exchange.response.answer=}')
96
-
97
- attribs = dict(rcode=exchange.response.rcode, rcode_text=exchange.response.rcode_text)
98
- span.set_attributes(attribs)
124
+ self.log_response(exchange)
99
125
 
100
126
  return exchange
fmtr/tools/version CHANGED
@@ -1 +1 @@
1
- 1.3.13
1
+ 1.3.14
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.13
3
+ Version: 1.3.14
4
4
  Summary: Collection of high-level tools to simplify everyday development tasks, with a focus on AI/ML
5
5
  Home-page: https://github.com/fmtr/fmtr.tools
6
6
  Author: Frontmatter
@@ -126,61 +126,61 @@ Requires-Dist: logfire[httpx]; extra == "http"
126
126
  Provides-Extra: setup
127
127
  Requires-Dist: setuptools; extra == "setup"
128
128
  Provides-Extra: all
129
- Requires-Dist: logfire; extra == "all"
130
- Requires-Dist: torchaudio; extra == "all"
131
- Requires-Dist: pydantic; extra == "all"
132
- Requires-Dist: ollama; extra == "all"
133
- Requires-Dist: contexttimer; extra == "all"
129
+ Requires-Dist: sentence_transformers; extra == "all"
134
130
  Requires-Dist: Unidecode; extra == "all"
135
- Requires-Dist: bokeh; extra == "all"
136
- Requires-Dist: dask[bag]; extra == "all"
137
- Requires-Dist: faker; extra == "all"
138
- Requires-Dist: yamlscript; extra == "all"
139
- Requires-Dist: pytest-cov; extra == "all"
140
- Requires-Dist: logfire[fastapi]; extra == "all"
141
- Requires-Dist: logfire[httpx]; extra == "all"
142
- Requires-Dist: diskcache; extra == "all"
143
- Requires-Dist: pyyaml; extra == "all"
144
- Requires-Dist: distributed; extra == "all"
131
+ Requires-Dist: peft; extra == "all"
145
132
  Requires-Dist: tinynetrc; extra == "all"
146
- Requires-Dist: deepmerge; extra == "all"
133
+ Requires-Dist: contexttimer; extra == "all"
134
+ Requires-Dist: torchaudio; extra == "all"
147
135
  Requires-Dist: uvicorn[standard]; extra == "all"
148
- Requires-Dist: pymupdf4llm; extra == "all"
149
- Requires-Dist: filetype; extra == "all"
136
+ Requires-Dist: openpyxl; extra == "all"
137
+ Requires-Dist: pydantic-settings; extra == "all"
150
138
  Requires-Dist: sre_yield; extra == "all"
151
- Requires-Dist: transformers[sentencepiece]; extra == "all"
152
- Requires-Dist: sentence_transformers; extra == "all"
139
+ Requires-Dist: distributed; extra == "all"
140
+ Requires-Dist: semver; extra == "all"
141
+ Requires-Dist: tokenizers; extra == "all"
142
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
153
143
  Requires-Dist: fastapi; extra == "all"
144
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
145
+ Requires-Dist: httpx_retries; extra == "all"
154
146
  Requires-Dist: flet[all]; extra == "all"
147
+ Requires-Dist: pymupdf4llm; extra == "all"
148
+ Requires-Dist: filetype; extra == "all"
149
+ Requires-Dist: pytest-cov; extra == "all"
155
150
  Requires-Dist: flet-webview; extra == "all"
156
- Requires-Dist: setuptools; extra == "all"
151
+ Requires-Dist: pymupdf; extra == "all"
152
+ Requires-Dist: json_repair; extra == "all"
157
153
  Requires-Dist: openai; extra == "all"
158
- Requires-Dist: google-auth-oauthlib; extra == "all"
154
+ Requires-Dist: google-auth; extra == "all"
155
+ Requires-Dist: huggingface_hub; extra == "all"
156
+ Requires-Dist: ollama; extra == "all"
157
+ Requires-Dist: faker; extra == "all"
158
+ Requires-Dist: dnspython[doh]; extra == "all"
159
+ Requires-Dist: logfire[fastapi]; extra == "all"
160
+ Requires-Dist: httpx; extra == "all"
161
+ Requires-Dist: google-api-python-client; extra == "all"
159
162
  Requires-Dist: docker; extra == "all"
160
- Requires-Dist: flet-video; extra == "all"
161
- Requires-Dist: tabulate; extra == "all"
162
- Requires-Dist: semver; extra == "all"
163
- Requires-Dist: httpx_retries; extra == "all"
164
- Requires-Dist: json_repair; extra == "all"
165
- Requires-Dist: tokenizers; extra == "all"
166
- Requires-Dist: pydantic-settings; extra == "all"
163
+ Requires-Dist: google-auth-oauthlib; extra == "all"
167
164
  Requires-Dist: torchvision; extra == "all"
168
- Requires-Dist: google-api-python-client; extra == "all"
169
- Requires-Dist: html2text; extra == "all"
170
- Requires-Dist: google-auth-httplib2; extra == "all"
171
- Requires-Dist: cachetools; extra == "all"
172
- Requires-Dist: httpx; extra == "all"
173
- Requires-Dist: google-auth; extra == "all"
174
- Requires-Dist: pymupdf; extra == "all"
175
165
  Requires-Dist: regex; extra == "all"
176
- Requires-Dist: huggingface_hub; extra == "all"
177
- Requires-Dist: openpyxl; extra == "all"
178
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
166
+ Requires-Dist: dask[bag]; extra == "all"
179
167
  Requires-Dist: appdirs; extra == "all"
180
- Requires-Dist: dnspython[doh]; extra == "all"
181
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
182
- Requires-Dist: peft; extra == "all"
168
+ Requires-Dist: html2text; extra == "all"
169
+ Requires-Dist: deepmerge; extra == "all"
170
+ Requires-Dist: logfire[httpx]; extra == "all"
183
171
  Requires-Dist: pandas; extra == "all"
172
+ Requires-Dist: flet-video; extra == "all"
173
+ Requires-Dist: tabulate; extra == "all"
174
+ Requires-Dist: google-auth-httplib2; extra == "all"
175
+ Requires-Dist: bokeh; extra == "all"
176
+ Requires-Dist: logfire; extra == "all"
177
+ Requires-Dist: cachetools; extra == "all"
178
+ Requires-Dist: setuptools; extra == "all"
179
+ Requires-Dist: yamlscript; extra == "all"
180
+ Requires-Dist: pydantic; extra == "all"
181
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
182
+ Requires-Dist: pyyaml; extra == "all"
183
+ Requires-Dist: diskcache; extra == "all"
184
184
  Dynamic: author
185
185
  Dynamic: author-email
186
186
  Dynamic: description
@@ -44,16 +44,16 @@ fmtr/tools/tabular_tools.py,sha256=tpIpZzYku1HcJrHZJL6BC39LmN3WUWVhFbK2N7nDVmE,1
44
44
  fmtr/tools/tokenization_tools.py,sha256=me-IBzSLyNYejLybwjO9CNB6Mj2NYfKPaOVThXyaGNg,4268
45
45
  fmtr/tools/tools.py,sha256=CAsApa1YwVdNE6H66Vjivs_mXYvOas3rh7fPELAnTpk,795
46
46
  fmtr/tools/unicode_tools.py,sha256=yS_9wpu8ogNoiIL7s1G_8bETFFO_YQlo4LNPv1NLDeY,52
47
- fmtr/tools/version,sha256=328hBDnJV-prjTlVQ7pm2D7s-V9Yds2R3yjA2Xc9M4Q,6
47
+ fmtr/tools/version,sha256=GG4QPlY_pdWNhfbn575pBPL9Qt2zJ_Kt1m89Ii4ieks,6
48
48
  fmtr/tools/yaml_tools.py,sha256=Bhhyd6GQVKO72Lp8ky7bAUjIB_65Hdh0Q45SKIEe6S8,1901
49
49
  fmtr/tools/ai_tools/__init__.py,sha256=JZrLuOFNV1A3wvJgonxOgz_4WS-7MfCuowGWA5uYCjs,372
50
50
  fmtr/tools/ai_tools/agentic_tools.py,sha256=acSEPFS-aguDXanWGs3fAAlRyJSYPZW7L-Kb2qDLm-I,4300
51
51
  fmtr/tools/ai_tools/inference_tools.py,sha256=2UP2gXEyOJUjyyV6zmFIYmIxUsh1rXkRH0IbFvr2bRs,11908
52
52
  fmtr/tools/dns_tools/__init__.py,sha256=PjD3Og6D5yvDVpKmsUsrnSpz_rjXpl4zBtvMqm8xKWU,237
53
53
  fmtr/tools/dns_tools/client.py,sha256=zAPJbQZIuNJPTA-HDBtrVZHvHRP_7QYWLgH7D73g5LU,2598
54
- fmtr/tools/dns_tools/dm.py,sha256=rg2y-zyMW8PzkzEkFah3KcbrIeInFBdLdemJHGwW8Vk,4661
54
+ fmtr/tools/dns_tools/dm.py,sha256=_G3ELId69SDMm0YciWQCW9-cTwt1l6cMVCt5-3T9V58,5177
55
55
  fmtr/tools/dns_tools/proxy.py,sha256=b3TdSwRO7IwcNjrWg1e8jVQb-YxJhT377rdVkeDc8_I,1466
56
- fmtr/tools/dns_tools/server.py,sha256=reHQvZq1kqMShpRyIK985u08XdkMnHlDOQh8vPUOiIg,2899
56
+ fmtr/tools/dns_tools/server.py,sha256=yL76rbYesdr1kHqLis5q1bxc3nzq68Utx-_PWA3Vu9U,3656
57
57
  fmtr/tools/entrypoints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  fmtr/tools/entrypoints/cache_hfh.py,sha256=fQNs4J9twQuZH_Yj98-oOvEX7-LrSUP3kO8nzw2HrHs,60
59
59
  fmtr/tools/entrypoints/ep_test.py,sha256=B8HfWISfSgw_xVX475CbJGh_QnpOe9MH65H8qGjTWbY,46
@@ -76,9 +76,9 @@ fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g
76
76
  fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
77
77
  fmtr/tools/version_tools/__init__.py,sha256=pg4iLtmIr5HtyEW_j0fMFoIdzqi_w9xH8-grQaXLB28,318
78
78
  fmtr/tools/version_tools/version_tools.py,sha256=Hcc6yferZS1hHbugRTdiHhSNmXEEG0hjCiTTXKna-YY,1127
79
- fmtr_tools-1.3.13.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
80
- fmtr_tools-1.3.13.dist-info/METADATA,sha256=-ichUA6JZb4dYc08MhnCKtZvyL6uuTIy824HI5QFpt4,15938
81
- fmtr_tools-1.3.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
- fmtr_tools-1.3.13.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
83
- fmtr_tools-1.3.13.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
84
- fmtr_tools-1.3.13.dist-info/RECORD,,
79
+ fmtr_tools-1.3.14.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
80
+ fmtr_tools-1.3.14.dist-info/METADATA,sha256=Yj9yReion57e01vzQDF85BNGZVVLXHOUxfv8KQWYj1o,15938
81
+ fmtr_tools-1.3.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ fmtr_tools-1.3.14.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
83
+ fmtr_tools-1.3.14.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
84
+ fmtr_tools-1.3.14.dist-info/RECORD,,