fmtr.tools 1.3.16__tar.gz → 1.3.18__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.

Potentially problematic release.


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

Files changed (91) hide show
  1. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/PKG-INFO +42 -42
  2. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dns_tools/dm.py +12 -3
  3. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dns_tools/proxy.py +1 -1
  4. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dns_tools/server.py +37 -39
  5. fmtr_tools-1.3.18/fmtr/tools/version +1 -0
  6. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/PKG-INFO +42 -42
  7. fmtr_tools-1.3.16/fmtr/tools/version +0 -1
  8. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/LICENSE +0 -0
  9. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/README.md +0 -0
  10. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/__init__.py +0 -0
  11. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/ai_tools/__init__.py +0 -0
  12. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/ai_tools/agentic_tools.py +0 -0
  13. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/ai_tools/inference_tools.py +0 -0
  14. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/api_tools.py +0 -0
  15. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/async_tools.py +0 -0
  16. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/augmentation_tools.py +0 -0
  17. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/caching_tools.py +0 -0
  18. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/constants.py +0 -0
  19. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/data_modelling_tools.py +0 -0
  20. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dataclass_tools.py +0 -0
  21. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/datatype_tools.py +0 -0
  22. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/debugging_tools.py +0 -0
  23. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dns_tools/__init__.py +0 -0
  24. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/dns_tools/client.py +0 -0
  25. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/docker_tools.py +0 -0
  26. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/__init__.py +0 -0
  27. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/cache_hfh.py +0 -0
  28. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/ep_test.py +0 -0
  29. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/install_yamlscript.py +0 -0
  30. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/remote_debug_test.py +0 -0
  31. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/entrypoints/shell_debug.py +0 -0
  32. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/environment_tools.py +0 -0
  33. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/function_tools.py +0 -0
  34. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/google_api_tools.py +0 -0
  35. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/hash_tools.py +0 -0
  36. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/hfh_tools.py +0 -0
  37. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/html_tools.py +0 -0
  38. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/http_tools.py +0 -0
  39. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/import_tools.py +0 -0
  40. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/inspection_tools.py +0 -0
  41. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/interface_tools.py +0 -0
  42. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/iterator_tools.py +0 -0
  43. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/json_fix_tools.py +0 -0
  44. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/json_tools.py +0 -0
  45. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/logging_tools.py +0 -0
  46. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/merging_tools.py +0 -0
  47. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/metric_tools.py +0 -0
  48. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/name_tools.py +0 -0
  49. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/netrc_tools.py +0 -0
  50. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/openai_tools.py +0 -0
  51. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/packaging_tools.py +0 -0
  52. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/parallel_tools.py +0 -0
  53. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/path_tools/__init__.py +0 -0
  54. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/path_tools/app_path_tools.py +0 -0
  55. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/path_tools/path_tools.py +0 -0
  56. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/path_tools/type_path_tools.py +0 -0
  57. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/pattern_tools.py +0 -0
  58. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/pdf_tools.py +0 -0
  59. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/platform_tools.py +0 -0
  60. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/process_tools.py +0 -0
  61. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/profiling_tools.py +0 -0
  62. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/random_tools.py +0 -0
  63. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/semantic_tools.py +0 -0
  64. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/settings_tools.py +0 -0
  65. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/setup_tools/__init__.py +0 -0
  66. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/setup_tools/setup_tools.py +0 -0
  67. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/spaces_tools.py +0 -0
  68. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/string_tools.py +0 -0
  69. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tabular_tools.py +0 -0
  70. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/__init__.py +0 -0
  71. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/conftest.py +0 -0
  72. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/helpers.py +0 -0
  73. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/test_datatype.py +0 -0
  74. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/test_environment.py +0 -0
  75. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/test_json.py +0 -0
  76. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/test_path.py +0 -0
  77. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tests/test_yaml.py +0 -0
  78. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tokenization_tools.py +0 -0
  79. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/tools.py +0 -0
  80. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/unicode_tools.py +0 -0
  81. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/version_tools/__init__.py +0 -0
  82. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/version_tools/version_tools.py +0 -0
  83. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr/tools/yaml_tools.py +0 -0
  84. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/SOURCES.txt +0 -0
  85. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/dependency_links.txt +0 -0
  86. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/entry_points.txt +0 -0
  87. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/requires.txt +41 -41
  88. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/fmtr.tools.egg-info/top_level.txt +0 -0
  89. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/pyproject.toml +0 -0
  90. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/setup.cfg +0 -0
  91. {fmtr_tools-1.3.16 → fmtr_tools-1.3.18}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.16
3
+ Version: 1.3.18
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: filetype; extra == "all"
130
- Requires-Dist: pyyaml; extra == "all"
131
- Requires-Dist: huggingface_hub; extra == "all"
132
- Requires-Dist: tinynetrc; extra == "all"
133
- Requires-Dist: flet[all]; extra == "all"
134
129
  Requires-Dist: tabulate; extra == "all"
135
- Requires-Dist: pydantic-settings; extra == "all"
136
- Requires-Dist: flet-webview; extra == "all"
137
- Requires-Dist: docker; extra == "all"
138
130
  Requires-Dist: Unidecode; extra == "all"
139
- Requires-Dist: openpyxl; extra == "all"
140
- Requires-Dist: sentence_transformers; extra == "all"
141
- Requires-Dist: deepmerge; extra == "all"
142
- Requires-Dist: pymupdf; extra == "all"
143
- Requires-Dist: google-auth-oauthlib; extra == "all"
144
- Requires-Dist: torchaudio; extra == "all"
145
- Requires-Dist: logfire; extra == "all"
131
+ Requires-Dist: pytest-cov; extra == "all"
132
+ Requires-Dist: torchvision; extra == "all"
146
133
  Requires-Dist: diskcache; extra == "all"
147
- Requires-Dist: cachetools; extra == "all"
148
- Requires-Dist: setuptools; extra == "all"
149
- Requires-Dist: distributed; extra == "all"
150
- Requires-Dist: tokenizers; extra == "all"
134
+ Requires-Dist: google-api-python-client; extra == "all"
151
135
  Requires-Dist: faker; extra == "all"
136
+ Requires-Dist: sentence_transformers; extra == "all"
137
+ Requires-Dist: logfire[httpx]; extra == "all"
152
138
  Requires-Dist: logfire[fastapi]; extra == "all"
153
- Requires-Dist: google-auth; extra == "all"
154
- Requires-Dist: fastapi; extra == "all"
155
139
  Requires-Dist: peft; extra == "all"
156
- Requires-Dist: transformers[sentencepiece]; extra == "all"
157
- Requires-Dist: yamlscript; extra == "all"
140
+ Requires-Dist: bokeh; extra == "all"
141
+ Requires-Dist: semver; extra == "all"
142
+ Requires-Dist: ollama; extra == "all"
143
+ Requires-Dist: flet[all]; extra == "all"
144
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
145
+ Requires-Dist: logfire; extra == "all"
158
146
  Requires-Dist: contexttimer; extra == "all"
159
- Requires-Dist: torchvision; extra == "all"
160
- Requires-Dist: appdirs; extra == "all"
147
+ Requires-Dist: google-auth-oauthlib; extra == "all"
148
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
161
149
  Requires-Dist: google-auth-httplib2; extra == "all"
162
- Requires-Dist: logfire[httpx]; extra == "all"
163
- Requires-Dist: pytest-cov; extra == "all"
164
- Requires-Dist: regex; extra == "all"
165
- Requires-Dist: pydantic; extra == "all"
150
+ Requires-Dist: cachetools; extra == "all"
151
+ Requires-Dist: deepmerge; extra == "all"
166
152
  Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
153
+ Requires-Dist: openpyxl; extra == "all"
154
+ Requires-Dist: sre_yield; extra == "all"
155
+ Requires-Dist: tinynetrc; extra == "all"
156
+ Requires-Dist: flet-webview; extra == "all"
157
+ Requires-Dist: pydantic; extra == "all"
167
158
  Requires-Dist: openai; extra == "all"
168
- Requires-Dist: dask[bag]; extra == "all"
169
- Requires-Dist: pandas; extra == "all"
170
- Requires-Dist: json_repair; extra == "all"
171
- Requires-Dist: uvicorn[standard]; extra == "all"
172
- Requires-Dist: html2text; extra == "all"
173
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
174
- Requires-Dist: semver; extra == "all"
159
+ Requires-Dist: google-auth; extra == "all"
175
160
  Requires-Dist: dnspython[doh]; extra == "all"
176
- Requires-Dist: ollama; extra == "all"
161
+ Requires-Dist: httpx_retries; extra == "all"
177
162
  Requires-Dist: flet-video; extra == "all"
178
- Requires-Dist: google-api-python-client; extra == "all"
163
+ Requires-Dist: tokenizers; extra == "all"
164
+ Requires-Dist: json_repair; extra == "all"
165
+ Requires-Dist: docker; extra == "all"
166
+ Requires-Dist: dask[bag]; extra == "all"
167
+ Requires-Dist: pymupdf; extra == "all"
168
+ Requires-Dist: yamlscript; extra == "all"
169
+ Requires-Dist: fastapi; extra == "all"
179
170
  Requires-Dist: httpx; extra == "all"
180
- Requires-Dist: httpx_retries; extra == "all"
181
- Requires-Dist: sre_yield; extra == "all"
182
- Requires-Dist: bokeh; extra == "all"
171
+ Requires-Dist: pydantic-settings; extra == "all"
172
+ Requires-Dist: torchaudio; extra == "all"
173
+ Requires-Dist: huggingface_hub; extra == "all"
183
174
  Requires-Dist: pymupdf4llm; extra == "all"
175
+ Requires-Dist: pandas; extra == "all"
176
+ Requires-Dist: html2text; extra == "all"
177
+ Requires-Dist: setuptools; extra == "all"
178
+ Requires-Dist: distributed; extra == "all"
179
+ Requires-Dist: uvicorn[standard]; extra == "all"
180
+ Requires-Dist: pyyaml; extra == "all"
181
+ Requires-Dist: regex; extra == "all"
182
+ Requires-Dist: filetype; extra == "all"
183
+ Requires-Dist: appdirs; extra == "all"
184
184
  Dynamic: author
185
185
  Dynamic: author-email
186
186
  Dynamic: description
@@ -179,6 +179,9 @@ class Exchange:
179
179
  client_name: Optional[str] = None
180
180
  is_complete: bool = False
181
181
 
182
+ @property
183
+ def addr(self):
184
+ return self.ip, self.port
182
185
 
183
186
  @classmethod
184
187
  def from_wire(cls, wire: bytes, **kwargs) -> Self:
@@ -194,11 +197,17 @@ class Exchange:
194
197
  def question_last(self) -> RRset:
195
198
  """
196
199
 
197
- Create an RRset surrogate representing the latest/current question. This can be the original question - or a hybrid one if we've injected our own answers into the Exchange.
200
+ Create an RRset surrogate representing the latest/current question.
201
+ This can be the original question - or a hybrid one if we've injected our own answers into the Exchange.
202
+ If there's a response, use its answers, else fall back to answers_pre, else to the original question.
198
203
 
199
204
  """
200
- if self.answers_pre:
201
- rrset = self.answers_pre[-1]
205
+ answers = self.answers_pre
206
+ if self.response:
207
+ answers = self.response.message.answer or answers
208
+
209
+ if answers:
210
+ rrset = answers[-1]
202
211
  rdtype = self.request.type
203
212
  ttl = self.request.question.ttl
204
213
  rdclass = self.request.question.rdclass
@@ -39,7 +39,7 @@ class Proxy(server.Plain):
39
39
  """
40
40
  exchange.is_complete = True
41
41
 
42
- def resolve(self, exchange: Exchange) -> Exchange:
42
+ async def resolve(self, exchange: Exchange) -> Exchange:
43
43
  """
44
44
 
45
45
  Resolve a request, processing each stage, initial question, upstream response etc.
@@ -1,8 +1,9 @@
1
- import dns
2
- import socket
3
- from dataclasses import dataclass
1
+ import asyncio
2
+ import dns.rcode
3
+ from dataclasses import dataclass, field
4
4
  from datetime import timedelta
5
5
  from functools import cached_property
6
+ from typing import Optional
6
7
 
7
8
  from fmtr.tools import caching_tools as caching
8
9
  from fmtr.tools.dns_tools.dm import Exchange
@@ -10,59 +11,61 @@ from fmtr.tools.logging_tools import logger
10
11
 
11
12
 
12
13
  @dataclass(kw_only=True, eq=False)
13
- class Plain:
14
+ class Plain(asyncio.DatagramProtocol):
14
15
  """
15
16
 
16
- Base for starting a plain DNS server
17
-
17
+ Async base class for a plain DNS server using asyncio DatagramProtocol.
18
18
  """
19
19
 
20
20
  host: str
21
21
  port: int
22
+ transport: Optional[asyncio.DatagramTransport] = field(default=None, init=False)
22
23
 
23
24
  @cached_property
24
- def sock(self):
25
- return socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
25
+ def loop(self):
26
+ return asyncio.get_event_loop()
27
+
26
28
 
27
29
  @cached_property
28
30
  def cache(self):
29
31
  """
30
32
 
31
33
  Overridable cache.
32
-
33
34
  """
34
35
  cache = caching.TLRU(maxsize=1_024, ttu_static=timedelta(hours=1), desc='DNS Request')
35
36
  return cache
36
37
 
37
- def start(self):
38
- """
38
+ def connection_made(self, transport: asyncio.DatagramTransport):
39
+ self.transport = transport
40
+ logger.info(f'Listening on {self.host}:{self.port}')
39
41
 
40
- Listen and resolve via overridden resolve method.
42
+ def datagram_received(self, data: bytes, addr):
43
+ ip, port = addr
44
+ exchange = Exchange.from_wire(data, ip=ip, port=port)
45
+ asyncio.create_task(self.handle(exchange))
41
46
 
47
+ async def start(self):
42
48
  """
43
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
44
- sock.bind((self.host, self.port))
45
- logger.info(f'Listening on {self.host}:{self.port}')
46
- while True:
47
- data, (ip, port) = sock.recvfrom(512)
48
- exchange = Exchange.from_wire(data, ip=ip, port=port)
49
- self.handle(exchange)
50
- sock.sendto(exchange.response.message.to_wire(), (ip, port))
51
49
 
52
- def resolve(self, exchange: Exchange) -> Exchange:
50
+ Start the async UDP server.
53
51
  """
54
52
 
55
- Defined in subclasses
53
+ logger.info(f'Starting async DNS server on {self.host}:{self.port}...')
54
+ await self.loop.create_datagram_endpoint(
55
+ lambda: self,
56
+ local_addr=(self.host, self.port)
57
+ )
58
+ await asyncio.Future() # Prevent exit by blocking forever
56
59
 
60
+ async def resolve(self, exchange: Exchange) -> Exchange:
57
61
  """
58
- raise NotImplemented
59
62
 
60
- def check_cache(self, exchange: Exchange):
61
- """
62
-
63
- Check cache, patch in in new ID and mark complete
63
+ To be defined in subclasses.
64
64
 
65
65
  """
66
+ raise NotImplementedError
67
+
68
+ def check_cache(self, exchange: Exchange):
66
69
  if exchange.key in self.cache:
67
70
  logger.info(f'Request found in cache.')
68
71
  exchange.response = self.cache[exchange.key]
@@ -89,7 +92,6 @@ class Plain:
89
92
  """
90
93
  request = exchange.request
91
94
  response = exchange.response
92
-
93
95
  logger.info(
94
96
  f'Resolution complete {exchange.client_name=} {request.message.id=} {request.type_text} {request.name_text} {request.question=} {exchange.is_complete=} {response.rcode=} {response.rcode_text=} {response.answer=} {response.blocked_by=}...'
95
97
  )
@@ -100,24 +102,20 @@ class Plain:
100
102
  Warn about any errors
101
103
 
102
104
  """
105
+ if exchange.response.rcode != dns.rcode.NOERROR:
106
+ logger.warning(f'Error {exchange.response.rcode_text=}')
103
107
 
104
- if exchange.response.rcode == dns.rcode.NOERROR:
105
- return
106
-
107
- logger.warning(f'Error {exchange.response.rcode_text=}')
108
-
109
- def handle(self, exchange: Exchange):
108
+ async def handle(self, exchange: Exchange):
110
109
  """
111
110
 
112
- Check validity of request, reverse lookup client address, check presence in cache and resolve.
111
+ Warn about any errors
113
112
 
114
113
  """
115
-
116
114
  if not exchange.request.is_valid:
117
115
  raise ValueError(f'Only one question per request is supported. Got {len(exchange.request.question)} questions.')
118
116
 
119
117
  if not exchange.is_internal:
120
- self.handle(exchange.reverse)
118
+ await self.handle(exchange.reverse)
121
119
  client_name = exchange.reverse.question_last.name.to_text()
122
120
  if not exchange.reverse.response.answer:
123
121
  logger.warning(f'Client name could not be resolved {client_name=}.')
@@ -128,10 +126,10 @@ class Plain:
128
126
  self.check_cache(exchange)
129
127
 
130
128
  if not exchange.is_complete:
131
- exchange = self.resolve(exchange)
129
+ exchange = await self.resolve(exchange)
132
130
  self.cache[exchange.key] = exchange.response
133
131
 
134
132
  self.log_dns_errors(exchange)
135
133
  self.log_response(exchange)
136
134
 
137
- return exchange
135
+ self.transport.sendto(exchange.response.message.to_wire(), exchange.addr)
@@ -0,0 +1 @@
1
+ 1.3.18
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.16
3
+ Version: 1.3.18
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: filetype; extra == "all"
130
- Requires-Dist: pyyaml; extra == "all"
131
- Requires-Dist: huggingface_hub; extra == "all"
132
- Requires-Dist: tinynetrc; extra == "all"
133
- Requires-Dist: flet[all]; extra == "all"
134
129
  Requires-Dist: tabulate; extra == "all"
135
- Requires-Dist: pydantic-settings; extra == "all"
136
- Requires-Dist: flet-webview; extra == "all"
137
- Requires-Dist: docker; extra == "all"
138
130
  Requires-Dist: Unidecode; extra == "all"
139
- Requires-Dist: openpyxl; extra == "all"
140
- Requires-Dist: sentence_transformers; extra == "all"
141
- Requires-Dist: deepmerge; extra == "all"
142
- Requires-Dist: pymupdf; extra == "all"
143
- Requires-Dist: google-auth-oauthlib; extra == "all"
144
- Requires-Dist: torchaudio; extra == "all"
145
- Requires-Dist: logfire; extra == "all"
131
+ Requires-Dist: pytest-cov; extra == "all"
132
+ Requires-Dist: torchvision; extra == "all"
146
133
  Requires-Dist: diskcache; extra == "all"
147
- Requires-Dist: cachetools; extra == "all"
148
- Requires-Dist: setuptools; extra == "all"
149
- Requires-Dist: distributed; extra == "all"
150
- Requires-Dist: tokenizers; extra == "all"
134
+ Requires-Dist: google-api-python-client; extra == "all"
151
135
  Requires-Dist: faker; extra == "all"
136
+ Requires-Dist: sentence_transformers; extra == "all"
137
+ Requires-Dist: logfire[httpx]; extra == "all"
152
138
  Requires-Dist: logfire[fastapi]; extra == "all"
153
- Requires-Dist: google-auth; extra == "all"
154
- Requires-Dist: fastapi; extra == "all"
155
139
  Requires-Dist: peft; extra == "all"
156
- Requires-Dist: transformers[sentencepiece]; extra == "all"
157
- Requires-Dist: yamlscript; extra == "all"
140
+ Requires-Dist: bokeh; extra == "all"
141
+ Requires-Dist: semver; extra == "all"
142
+ Requires-Dist: ollama; extra == "all"
143
+ Requires-Dist: flet[all]; extra == "all"
144
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
145
+ Requires-Dist: logfire; extra == "all"
158
146
  Requires-Dist: contexttimer; extra == "all"
159
- Requires-Dist: torchvision; extra == "all"
160
- Requires-Dist: appdirs; extra == "all"
147
+ Requires-Dist: google-auth-oauthlib; extra == "all"
148
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
161
149
  Requires-Dist: google-auth-httplib2; extra == "all"
162
- Requires-Dist: logfire[httpx]; extra == "all"
163
- Requires-Dist: pytest-cov; extra == "all"
164
- Requires-Dist: regex; extra == "all"
165
- Requires-Dist: pydantic; extra == "all"
150
+ Requires-Dist: cachetools; extra == "all"
151
+ Requires-Dist: deepmerge; extra == "all"
166
152
  Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
153
+ Requires-Dist: openpyxl; extra == "all"
154
+ Requires-Dist: sre_yield; extra == "all"
155
+ Requires-Dist: tinynetrc; extra == "all"
156
+ Requires-Dist: flet-webview; extra == "all"
157
+ Requires-Dist: pydantic; extra == "all"
167
158
  Requires-Dist: openai; extra == "all"
168
- Requires-Dist: dask[bag]; extra == "all"
169
- Requires-Dist: pandas; extra == "all"
170
- Requires-Dist: json_repair; extra == "all"
171
- Requires-Dist: uvicorn[standard]; extra == "all"
172
- Requires-Dist: html2text; extra == "all"
173
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
174
- Requires-Dist: semver; extra == "all"
159
+ Requires-Dist: google-auth; extra == "all"
175
160
  Requires-Dist: dnspython[doh]; extra == "all"
176
- Requires-Dist: ollama; extra == "all"
161
+ Requires-Dist: httpx_retries; extra == "all"
177
162
  Requires-Dist: flet-video; extra == "all"
178
- Requires-Dist: google-api-python-client; extra == "all"
163
+ Requires-Dist: tokenizers; extra == "all"
164
+ Requires-Dist: json_repair; extra == "all"
165
+ Requires-Dist: docker; extra == "all"
166
+ Requires-Dist: dask[bag]; extra == "all"
167
+ Requires-Dist: pymupdf; extra == "all"
168
+ Requires-Dist: yamlscript; extra == "all"
169
+ Requires-Dist: fastapi; extra == "all"
179
170
  Requires-Dist: httpx; extra == "all"
180
- Requires-Dist: httpx_retries; extra == "all"
181
- Requires-Dist: sre_yield; extra == "all"
182
- Requires-Dist: bokeh; extra == "all"
171
+ Requires-Dist: pydantic-settings; extra == "all"
172
+ Requires-Dist: torchaudio; extra == "all"
173
+ Requires-Dist: huggingface_hub; extra == "all"
183
174
  Requires-Dist: pymupdf4llm; extra == "all"
175
+ Requires-Dist: pandas; extra == "all"
176
+ Requires-Dist: html2text; extra == "all"
177
+ Requires-Dist: setuptools; extra == "all"
178
+ Requires-Dist: distributed; extra == "all"
179
+ Requires-Dist: uvicorn[standard]; extra == "all"
180
+ Requires-Dist: pyyaml; extra == "all"
181
+ Requires-Dist: regex; extra == "all"
182
+ Requires-Dist: filetype; extra == "all"
183
+ Requires-Dist: appdirs; extra == "all"
184
184
  Dynamic: author
185
185
  Dynamic: author-email
186
186
  Dynamic: description
@@ -1 +0,0 @@
1
- 1.3.16
File without changes
File without changes
@@ -14,61 +14,61 @@ pydantic-ai[logfire,openai]
14
14
  ollama
15
15
 
16
16
  [all]
17
- filetype
18
- pyyaml
19
- huggingface_hub
20
- tinynetrc
21
- flet[all]
22
17
  tabulate
23
- pydantic-settings
24
- flet-webview
25
- docker
26
18
  Unidecode
27
- openpyxl
28
- sentence_transformers
29
- deepmerge
30
- pymupdf
31
- google-auth-oauthlib
32
- torchaudio
33
- logfire
19
+ pytest-cov
20
+ torchvision
34
21
  diskcache
35
- cachetools
36
- setuptools
37
- distributed
38
- tokenizers
22
+ google-api-python-client
39
23
  faker
24
+ sentence_transformers
25
+ logfire[httpx]
40
26
  logfire[fastapi]
41
- google-auth
42
- fastapi
43
27
  peft
44
- transformers[sentencepiece]
45
- yamlscript
28
+ bokeh
29
+ semver
30
+ ollama
31
+ flet[all]
32
+ pydantic-ai[logfire,openai]
33
+ logfire
46
34
  contexttimer
47
- torchvision
48
- appdirs
35
+ google-auth-oauthlib
36
+ transformers[sentencepiece]
49
37
  google-auth-httplib2
50
- logfire[httpx]
51
- pytest-cov
52
- regex
53
- pydantic
38
+ cachetools
39
+ deepmerge
54
40
  pydevd-pycharm~=251.25410.159
41
+ openpyxl
42
+ sre_yield
43
+ tinynetrc
44
+ flet-webview
45
+ pydantic
55
46
  openai
56
- dask[bag]
57
- pandas
58
- json_repair
59
- uvicorn[standard]
60
- html2text
61
- pydantic-ai[logfire,openai]
62
- semver
47
+ google-auth
63
48
  dnspython[doh]
64
- ollama
49
+ httpx_retries
65
50
  flet-video
66
- google-api-python-client
51
+ tokenizers
52
+ json_repair
53
+ docker
54
+ dask[bag]
55
+ pymupdf
56
+ yamlscript
57
+ fastapi
67
58
  httpx
68
- httpx_retries
69
- sre_yield
70
- bokeh
59
+ pydantic-settings
60
+ torchaudio
61
+ huggingface_hub
71
62
  pymupdf4llm
63
+ pandas
64
+ html2text
65
+ setuptools
66
+ distributed
67
+ uvicorn[standard]
68
+ pyyaml
69
+ regex
70
+ filetype
71
+ appdirs
72
72
 
73
73
  [api]
74
74
  fastapi
File without changes
File without changes
File without changes