fmtr.tools 1.3.8__tar.gz → 1.3.9__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 (92) hide show
  1. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/PKG-INFO +46 -46
  2. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/caching_tools.py +3 -1
  3. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/dns_tools/dm.py +41 -5
  4. fmtr_tools-1.3.9/fmtr/tools/dns_tools/proxy.py +57 -0
  5. fmtr_tools-1.3.9/fmtr/tools/dns_tools/server.py +94 -0
  6. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/pattern_tools.py +2 -1
  7. fmtr_tools-1.3.9/fmtr/tools/version +1 -0
  8. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/PKG-INFO +46 -46
  9. fmtr_tools-1.3.8/fmtr/tools/dns_tools/proxy.py +0 -67
  10. fmtr_tools-1.3.8/fmtr/tools/dns_tools/server.py +0 -39
  11. fmtr_tools-1.3.8/fmtr/tools/version +0 -1
  12. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/LICENSE +0 -0
  13. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/README.md +0 -0
  14. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/__init__.py +0 -0
  15. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/ai_tools/__init__.py +0 -0
  16. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/ai_tools/agentic_tools.py +0 -0
  17. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/ai_tools/inference_tools.py +0 -0
  18. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/api_tools.py +0 -0
  19. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/async_tools.py +0 -0
  20. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/augmentation_tools.py +0 -0
  21. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/constants.py +0 -0
  22. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/data_modelling_tools.py +0 -0
  23. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/dataclass_tools.py +0 -0
  24. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/datatype_tools.py +0 -0
  25. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/debugging_tools.py +0 -0
  26. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/dns_tools/__init__.py +0 -0
  27. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/dns_tools/client.py +0 -0
  28. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/docker_tools.py +0 -0
  29. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/__init__.py +0 -0
  30. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/cache_hfh.py +0 -0
  31. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/ep_test.py +0 -0
  32. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/install_yamlscript.py +0 -0
  33. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/remote_debug_test.py +0 -0
  34. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/entrypoints/shell_debug.py +0 -0
  35. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/environment_tools.py +0 -0
  36. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/function_tools.py +0 -0
  37. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/google_api_tools.py +0 -0
  38. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/hash_tools.py +0 -0
  39. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/hfh_tools.py +0 -0
  40. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/html_tools.py +0 -0
  41. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/http_tools.py +0 -0
  42. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/import_tools.py +0 -0
  43. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/inspection_tools.py +0 -0
  44. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/interface_tools.py +0 -0
  45. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/iterator_tools.py +0 -0
  46. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/json_fix_tools.py +0 -0
  47. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/json_tools.py +0 -0
  48. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/logging_tools.py +0 -0
  49. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/merging_tools.py +0 -0
  50. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/metric_tools.py +0 -0
  51. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/name_tools.py +0 -0
  52. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/netrc_tools.py +0 -0
  53. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/openai_tools.py +0 -0
  54. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/packaging_tools.py +0 -0
  55. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/parallel_tools.py +0 -0
  56. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/path_tools/__init__.py +0 -0
  57. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/path_tools/app_path_tools.py +0 -0
  58. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/path_tools/path_tools.py +0 -0
  59. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/path_tools/type_path_tools.py +0 -0
  60. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/pdf_tools.py +0 -0
  61. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/platform_tools.py +0 -0
  62. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/process_tools.py +0 -0
  63. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/profiling_tools.py +0 -0
  64. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/random_tools.py +0 -0
  65. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/semantic_tools.py +0 -0
  66. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/settings_tools.py +0 -0
  67. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/setup_tools/__init__.py +0 -0
  68. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/setup_tools/setup_tools.py +0 -0
  69. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/spaces_tools.py +0 -0
  70. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/string_tools.py +0 -0
  71. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tabular_tools.py +0 -0
  72. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/__init__.py +0 -0
  73. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/conftest.py +0 -0
  74. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/helpers.py +0 -0
  75. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/test_datatype.py +0 -0
  76. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/test_environment.py +0 -0
  77. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/test_json.py +0 -0
  78. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/test_path.py +0 -0
  79. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tests/test_yaml.py +0 -0
  80. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tokenization_tools.py +0 -0
  81. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/tools.py +0 -0
  82. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/unicode_tools.py +0 -0
  83. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/version_tools.py +0 -0
  84. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr/tools/yaml_tools.py +0 -0
  85. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/SOURCES.txt +0 -0
  86. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/dependency_links.txt +0 -0
  87. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/entry_points.txt +0 -0
  88. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/requires.txt +45 -45
  89. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/fmtr.tools.egg-info/top_level.txt +0 -0
  90. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/pyproject.toml +0 -0
  91. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/setup.cfg +0 -0
  92. {fmtr_tools-1.3.8 → fmtr_tools-1.3.9}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.8
3
+ Version: 1.3.9
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
@@ -131,61 +131,61 @@ Requires-Dist: logfire[httpx]; extra == "http"
131
131
  Provides-Extra: setup
132
132
  Requires-Dist: setuptools; extra == "setup"
133
133
  Provides-Extra: all
134
- Requires-Dist: tinynetrc; extra == "all"
135
- Requires-Dist: flet-webview; extra == "all"
136
- Requires-Dist: distributed; extra == "all"
137
- Requires-Dist: logfire[httpx]; extra == "all"
138
- Requires-Dist: pytest-cov; extra == "all"
139
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
140
- Requires-Dist: torchaudio; extra == "all"
141
- Requires-Dist: docker; extra == "all"
134
+ Requires-Dist: uvicorn[standard]; extra == "all"
135
+ Requires-Dist: json_repair; extra == "all"
142
136
  Requires-Dist: httpx; extra == "all"
143
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
144
- Requires-Dist: logfire[fastapi]; extra == "all"
145
- Requires-Dist: filetype; extra == "all"
146
137
  Requires-Dist: openai; extra == "all"
147
- Requires-Dist: semver; extra == "all"
148
- Requires-Dist: fastapi; extra == "all"
149
- Requires-Dist: logfire; extra == "all"
150
- Requires-Dist: faker; extra == "all"
151
- Requires-Dist: appdirs; extra == "all"
152
- Requires-Dist: sre_yield; extra == "all"
153
- Requires-Dist: huggingface_hub; extra == "all"
138
+ Requires-Dist: openpyxl; extra == "all"
139
+ Requires-Dist: flet[all]; extra == "all"
154
140
  Requires-Dist: regex; extra == "all"
155
- Requires-Dist: google-auth; extra == "all"
156
- Requires-Dist: bokeh; extra == "all"
157
- Requires-Dist: ollama; extra == "all"
158
- Requires-Dist: Unidecode; extra == "all"
141
+ Requires-Dist: tabulate; extra == "all"
142
+ Requires-Dist: tinynetrc; extra == "all"
143
+ Requires-Dist: filetype; extra == "all"
144
+ Requires-Dist: google-api-python-client; extra == "all"
145
+ Requires-Dist: yamlscript; extra == "all"
146
+ Requires-Dist: tokenizers; extra == "all"
159
147
  Requires-Dist: deepmerge; extra == "all"
148
+ Requires-Dist: sre_yield; extra == "all"
149
+ Requires-Dist: diskcache; extra == "all"
150
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
151
+ Requires-Dist: google-auth-oauthlib; extra == "all"
152
+ Requires-Dist: Unidecode; extra == "all"
153
+ Requires-Dist: sentence_transformers; extra == "all"
154
+ Requires-Dist: logfire; extra == "all"
155
+ Requires-Dist: logfire[fastapi]; extra == "all"
156
+ Requires-Dist: pydantic; extra == "all"
157
+ Requires-Dist: semver; extra == "all"
158
+ Requires-Dist: dnspython[doh]; extra == "all"
159
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
160
+ Requires-Dist: google-auth-httplib2; extra == "all"
161
+ Requires-Dist: pymupdf4llm; extra == "all"
162
+ Requires-Dist: html2text; extra == "all"
163
+ Requires-Dist: google-auth; extra == "all"
164
+ Requires-Dist: pydantic-settings; extra == "all"
165
+ Requires-Dist: huggingface_hub; extra == "all"
166
+ Requires-Dist: pyyaml; extra == "all"
167
+ Requires-Dist: torchvision; extra == "all"
160
168
  Requires-Dist: pymupdf; extra == "all"
161
- Requires-Dist: uvicorn[standard]; extra == "all"
169
+ Requires-Dist: fastapi; extra == "all"
170
+ Requires-Dist: logfire[httpx]; extra == "all"
171
+ Requires-Dist: contexttimer; extra == "all"
162
172
  Requires-Dist: httpx_retries; extra == "all"
163
- Requires-Dist: tokenizers; extra == "all"
164
173
  Requires-Dist: dask[bag]; extra == "all"
165
- Requires-Dist: tabulate; extra == "all"
166
- Requires-Dist: flet[all]; extra == "all"
174
+ Requires-Dist: peft; extra == "all"
175
+ Requires-Dist: distributed; extra == "all"
176
+ Requires-Dist: docker; extra == "all"
177
+ Requires-Dist: faker; extra == "all"
167
178
  Requires-Dist: cachetools; extra == "all"
168
- Requires-Dist: pymupdf4llm; extra == "all"
169
- Requires-Dist: sentence_transformers; extra == "all"
170
- Requires-Dist: diskcache; extra == "all"
171
- Requires-Dist: pydantic-settings; extra == "all"
172
- Requires-Dist: google-auth-httplib2; extra == "all"
179
+ Requires-Dist: torchaudio; extra == "all"
180
+ Requires-Dist: setuptools; extra == "all"
181
+ Requires-Dist: pytest-cov; extra == "all"
182
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
173
183
  Requires-Dist: flet-video; extra == "all"
174
- Requires-Dist: yamlscript; extra == "all"
175
- Requires-Dist: contexttimer; extra == "all"
176
- Requires-Dist: pydantic; extra == "all"
177
- Requires-Dist: peft; extra == "all"
178
- Requires-Dist: transformers[sentencepiece]; extra == "all"
179
- Requires-Dist: torchvision; extra == "all"
184
+ Requires-Dist: flet-webview; extra == "all"
185
+ Requires-Dist: appdirs; extra == "all"
180
186
  Requires-Dist: pandas; extra == "all"
181
- Requires-Dist: html2text; extra == "all"
182
- Requires-Dist: google-auth-oauthlib; extra == "all"
183
- Requires-Dist: pyyaml; extra == "all"
184
- Requires-Dist: google-api-python-client; extra == "all"
185
- Requires-Dist: openpyxl; extra == "all"
186
- Requires-Dist: setuptools; extra == "all"
187
- Requires-Dist: json_repair; extra == "all"
188
- Requires-Dist: dnspython[doh]; extra == "all"
187
+ Requires-Dist: bokeh; extra == "all"
188
+ Requires-Dist: ollama; extra == "all"
189
189
  Dynamic: author
190
190
  Dynamic: author-email
191
191
  Dynamic: description
@@ -2,7 +2,9 @@ import cachetools
2
2
  from datetime import timedelta, datetime
3
3
  from diskcache import Cache
4
4
 
5
- from fmtr.tools import logger, Path, Constants
5
+ from fmtr.tools.constants import Constants
6
+ from fmtr.tools.logging_tools import logger
7
+ from fmtr.tools.path_tools.path_tools import Path
6
8
 
7
9
 
8
10
  class Dump(dict):
@@ -1,11 +1,12 @@
1
- from dataclasses import dataclass
2
- from functools import cached_property
3
- from typing import Self, Optional
4
-
5
1
  import dns
6
2
  import httpx
3
+ from dataclasses import dataclass
7
4
  from dns.message import Message, QueryMessage
8
5
  from dns.rrset import RRset
6
+ from functools import cached_property
7
+ from typing import Self, Optional
8
+
9
+ from fmtr.tools.string_tools import join
9
10
 
10
11
 
11
12
  @dataclass
@@ -25,7 +26,6 @@ class BaseDNSData:
25
26
  def from_message(cls, message: Message) -> Self:
26
27
  return cls(message.to_wire())
27
28
 
28
-
29
29
  @dataclass
30
30
  class Response(BaseDNSData):
31
31
  """
@@ -39,15 +39,41 @@ class Response(BaseDNSData):
39
39
 
40
40
  @classmethod
41
41
  def from_http(cls, response: httpx.Response) -> Self:
42
+ """
43
+
44
+ Initialise from an HTTP response.
45
+
46
+ """
42
47
  self = cls(response.content, http=response)
43
48
  return self
44
49
 
45
50
  @property
46
51
  def answer(self) -> Optional[RRset]:
52
+ """
53
+
54
+ Get the latest answer, if one exists.
55
+
56
+ """
47
57
  if not self.message.answer:
48
58
  return None
49
59
  return self.message.answer[-1]
50
60
 
61
+ def __str__(self):
62
+ """
63
+
64
+ Put answer and ID text in string representation.
65
+
66
+ """
67
+ answer = self.answer
68
+
69
+ if answer:
70
+ answer = join(answer.to_text().splitlines(), sep=', ')
71
+
72
+ string = join([answer, self.message.flags], sep=', ')
73
+ string = f'{self.__class__.__name__}({string})'
74
+ return string
75
+
76
+
51
77
 
52
78
  @dataclass
53
79
  class Request(BaseDNSData):
@@ -157,3 +183,13 @@ class Exchange:
157
183
  question_last = self.question_last
158
184
  query = dns.message.make_query(qname=question_last.name, rdclass=question_last.rdclass, rdtype=question_last.rdtype)
159
185
  return query
186
+
187
+ @property
188
+ def key(self):
189
+ """
190
+
191
+ Hashable key for caching
192
+
193
+ """
194
+ data = tuple(self.request.question.to_text().split())
195
+ return data
@@ -0,0 +1,57 @@
1
+ from dataclasses import dataclass
2
+
3
+ from fmtr.tools.dns_tools import server, client
4
+ from fmtr.tools.dns_tools.dm import Exchange
5
+ from fmtr.tools.logging_tools import logger
6
+
7
+
8
+ @dataclass(kw_only=True, eq=False)
9
+ class Proxy(server.Plain):
10
+ """
11
+
12
+ Base for a DNS Proxy server (plain server) TODO: Allow subclassing of any server type.
13
+
14
+ """
15
+
16
+ client: client.HTTP
17
+
18
+ def process_question(self, exchange: Exchange):
19
+ """
20
+
21
+ Modify exchange based on initial question.
22
+
23
+ """
24
+ return
25
+
26
+ def process_upstream(self, exchange: Exchange):
27
+ """
28
+
29
+ Modify exchange after upstream response.
30
+
31
+ """
32
+ return
33
+
34
+ def resolve(self, exchange: Exchange) -> Exchange:
35
+ """
36
+
37
+ Resolve a request, processing each stage, initial question, upstream response etc.
38
+ Subclasses can override the relevant processing methods to implement custom behaviour.
39
+
40
+ """
41
+
42
+ with logger.span(f'Processing question...'):
43
+ self.process_question(exchange)
44
+ if exchange.response.is_complete:
45
+ return exchange
46
+
47
+ with logger.span(f'Making upstream request...'):
48
+ self.client.resolve(exchange)
49
+ if exchange.response.is_complete:
50
+ return exchange
51
+
52
+ with logger.span(f'Processing upstream response...'):
53
+ self.process_upstream(exchange)
54
+ if exchange.response.is_complete:
55
+ return exchange
56
+
57
+ return exchange
@@ -0,0 +1,94 @@
1
+ import socket
2
+ from dataclasses import dataclass
3
+ from datetime import timedelta
4
+ from functools import cached_property
5
+
6
+ from fmtr.tools import caching_tools as caching
7
+ from fmtr.tools.dns_tools.dm import Exchange
8
+ from fmtr.tools.logging_tools import logger
9
+
10
+
11
+ @dataclass(kw_only=True, eq=False)
12
+ class Plain:
13
+ """
14
+
15
+ Base for starting a plain DNS server
16
+
17
+ """
18
+
19
+ host: str
20
+ port: int
21
+
22
+ @cached_property
23
+ def sock(self):
24
+ return socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
25
+
26
+ @cached_property
27
+ def cache(self):
28
+ """
29
+
30
+ Overridable cache.
31
+
32
+ """
33
+ cache = caching.TLRU(maxsize=1_024, ttu_static=timedelta(hours=1), desc='DNS Request')
34
+ return cache
35
+
36
+ def start(self):
37
+ """
38
+
39
+ Listen and resolve via overridden resolve method.
40
+
41
+ """
42
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
43
+ sock.bind((self.host, self.port))
44
+ logger.info(f'Listening on {self.host}:{self.port}')
45
+ while True:
46
+ data, (ip, port) = sock.recvfrom(512)
47
+ exchange = Exchange.from_wire(data, ip=ip, port=port)
48
+ self.handle(exchange)
49
+ sock.sendto(exchange.response.message.to_wire(), (ip, port))
50
+
51
+ def resolve(self, exchange: Exchange) -> Exchange:
52
+ """
53
+
54
+ Defined in subclasses
55
+
56
+ """
57
+ raise NotImplemented
58
+
59
+ def check_cache(self, exchange: Exchange):
60
+ """
61
+
62
+ Check cache, patch in in new ID and mark complete
63
+
64
+ """
65
+ if exchange.key in self.cache:
66
+ logger.info(f'Request found in cache.')
67
+ exchange.response = self.cache[exchange.key]
68
+ exchange.response.message.id = exchange.request.message.id
69
+ exchange.response.is_complete = True
70
+
71
+ def handle(self, exchange: Exchange):
72
+ """
73
+
74
+ Check validity of request, presence in cache and resolve.
75
+
76
+ """
77
+ request = exchange.request
78
+
79
+ if not request.is_valid:
80
+ raise ValueError(f'Only one question per request is supported. Got {len(request.question)} questions.')
81
+
82
+ with logger.span(f'Handling request {request.message.id=} {request.question=} {exchange.client=}...'):
83
+
84
+ with logger.span(f'Checking cache...'):
85
+ self.check_cache(exchange)
86
+
87
+ if not exchange.response.is_complete:
88
+ exchange = self.resolve(exchange)
89
+ exchange.response.is_complete = True
90
+
91
+ self.cache[exchange.key] = exchange.response
92
+
93
+ logger.info(f'Resolution complete {request.message.id=} {exchange.response.answer=}')
94
+ return exchange
@@ -92,7 +92,8 @@ class Item:
92
92
  source: Key
93
93
  target: Key
94
94
 
95
- @dataclass
95
+
96
+ @dataclass(kw_only=True)
96
97
  class Transformer:
97
98
  """
98
99
 
@@ -0,0 +1 @@
1
+ 1.3.9
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.8
3
+ Version: 1.3.9
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
@@ -131,61 +131,61 @@ Requires-Dist: logfire[httpx]; extra == "http"
131
131
  Provides-Extra: setup
132
132
  Requires-Dist: setuptools; extra == "setup"
133
133
  Provides-Extra: all
134
- Requires-Dist: tinynetrc; extra == "all"
135
- Requires-Dist: flet-webview; extra == "all"
136
- Requires-Dist: distributed; extra == "all"
137
- Requires-Dist: logfire[httpx]; extra == "all"
138
- Requires-Dist: pytest-cov; extra == "all"
139
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
140
- Requires-Dist: torchaudio; extra == "all"
141
- Requires-Dist: docker; extra == "all"
134
+ Requires-Dist: uvicorn[standard]; extra == "all"
135
+ Requires-Dist: json_repair; extra == "all"
142
136
  Requires-Dist: httpx; extra == "all"
143
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
144
- Requires-Dist: logfire[fastapi]; extra == "all"
145
- Requires-Dist: filetype; extra == "all"
146
137
  Requires-Dist: openai; extra == "all"
147
- Requires-Dist: semver; extra == "all"
148
- Requires-Dist: fastapi; extra == "all"
149
- Requires-Dist: logfire; extra == "all"
150
- Requires-Dist: faker; extra == "all"
151
- Requires-Dist: appdirs; extra == "all"
152
- Requires-Dist: sre_yield; extra == "all"
153
- Requires-Dist: huggingface_hub; extra == "all"
138
+ Requires-Dist: openpyxl; extra == "all"
139
+ Requires-Dist: flet[all]; extra == "all"
154
140
  Requires-Dist: regex; extra == "all"
155
- Requires-Dist: google-auth; extra == "all"
156
- Requires-Dist: bokeh; extra == "all"
157
- Requires-Dist: ollama; extra == "all"
158
- Requires-Dist: Unidecode; extra == "all"
141
+ Requires-Dist: tabulate; extra == "all"
142
+ Requires-Dist: tinynetrc; extra == "all"
143
+ Requires-Dist: filetype; extra == "all"
144
+ Requires-Dist: google-api-python-client; extra == "all"
145
+ Requires-Dist: yamlscript; extra == "all"
146
+ Requires-Dist: tokenizers; extra == "all"
159
147
  Requires-Dist: deepmerge; extra == "all"
148
+ Requires-Dist: sre_yield; extra == "all"
149
+ Requires-Dist: diskcache; extra == "all"
150
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
151
+ Requires-Dist: google-auth-oauthlib; extra == "all"
152
+ Requires-Dist: Unidecode; extra == "all"
153
+ Requires-Dist: sentence_transformers; extra == "all"
154
+ Requires-Dist: logfire; extra == "all"
155
+ Requires-Dist: logfire[fastapi]; extra == "all"
156
+ Requires-Dist: pydantic; extra == "all"
157
+ Requires-Dist: semver; extra == "all"
158
+ Requires-Dist: dnspython[doh]; extra == "all"
159
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
160
+ Requires-Dist: google-auth-httplib2; extra == "all"
161
+ Requires-Dist: pymupdf4llm; extra == "all"
162
+ Requires-Dist: html2text; extra == "all"
163
+ Requires-Dist: google-auth; extra == "all"
164
+ Requires-Dist: pydantic-settings; extra == "all"
165
+ Requires-Dist: huggingface_hub; extra == "all"
166
+ Requires-Dist: pyyaml; extra == "all"
167
+ Requires-Dist: torchvision; extra == "all"
160
168
  Requires-Dist: pymupdf; extra == "all"
161
- Requires-Dist: uvicorn[standard]; extra == "all"
169
+ Requires-Dist: fastapi; extra == "all"
170
+ Requires-Dist: logfire[httpx]; extra == "all"
171
+ Requires-Dist: contexttimer; extra == "all"
162
172
  Requires-Dist: httpx_retries; extra == "all"
163
- Requires-Dist: tokenizers; extra == "all"
164
173
  Requires-Dist: dask[bag]; extra == "all"
165
- Requires-Dist: tabulate; extra == "all"
166
- Requires-Dist: flet[all]; extra == "all"
174
+ Requires-Dist: peft; extra == "all"
175
+ Requires-Dist: distributed; extra == "all"
176
+ Requires-Dist: docker; extra == "all"
177
+ Requires-Dist: faker; extra == "all"
167
178
  Requires-Dist: cachetools; extra == "all"
168
- Requires-Dist: pymupdf4llm; extra == "all"
169
- Requires-Dist: sentence_transformers; extra == "all"
170
- Requires-Dist: diskcache; extra == "all"
171
- Requires-Dist: pydantic-settings; extra == "all"
172
- Requires-Dist: google-auth-httplib2; extra == "all"
179
+ Requires-Dist: torchaudio; extra == "all"
180
+ Requires-Dist: setuptools; extra == "all"
181
+ Requires-Dist: pytest-cov; extra == "all"
182
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
173
183
  Requires-Dist: flet-video; extra == "all"
174
- Requires-Dist: yamlscript; extra == "all"
175
- Requires-Dist: contexttimer; extra == "all"
176
- Requires-Dist: pydantic; extra == "all"
177
- Requires-Dist: peft; extra == "all"
178
- Requires-Dist: transformers[sentencepiece]; extra == "all"
179
- Requires-Dist: torchvision; extra == "all"
184
+ Requires-Dist: flet-webview; extra == "all"
185
+ Requires-Dist: appdirs; extra == "all"
180
186
  Requires-Dist: pandas; extra == "all"
181
- Requires-Dist: html2text; extra == "all"
182
- Requires-Dist: google-auth-oauthlib; extra == "all"
183
- Requires-Dist: pyyaml; extra == "all"
184
- Requires-Dist: google-api-python-client; extra == "all"
185
- Requires-Dist: openpyxl; extra == "all"
186
- Requires-Dist: setuptools; extra == "all"
187
- Requires-Dist: json_repair; extra == "all"
188
- Requires-Dist: dnspython[doh]; extra == "all"
187
+ Requires-Dist: bokeh; extra == "all"
188
+ Requires-Dist: ollama; extra == "all"
189
189
  Dynamic: author
190
190
  Dynamic: author-email
191
191
  Dynamic: description
@@ -1,67 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
- from fmtr.tools import logger
4
- from fmtr.tools.dns_tools import server, client
5
- from fmtr.tools.dns_tools.dm import Exchange
6
-
7
-
8
- @dataclass
9
- class Proxy(server.Plain):
10
- """
11
-
12
- Base for a DNS Proxy server (plain server) TODO: Allow subclassing of any server type.
13
-
14
- """
15
-
16
- client: client.HTTP
17
-
18
- def process_question(self, exchange: Exchange):
19
- """
20
-
21
- Modify exchange based on initial question.
22
-
23
- """
24
- return
25
-
26
- def process_upstream(self, exchange: Exchange):
27
- """
28
-
29
- Modify exchange after upstream response.
30
-
31
- """
32
- return
33
-
34
- def resolve(self, exchange: Exchange):
35
- """
36
-
37
- Resolve a request, processing each stage, initial question, upstream response etc.
38
- Subclasses can override the relevant processing methods to implement custom behaviour.
39
-
40
- """
41
-
42
- request = exchange.request
43
-
44
- with logger.span(f'Handling request {request.message.id=} {request.question=} {exchange.client=}...'):
45
-
46
- if not request.is_valid:
47
- raise ValueError(f'Only one question per request is supported. Got {len(request.question)} questions.')
48
-
49
- with logger.span(f'Processing question...'):
50
- self.process_question(exchange)
51
- if exchange.response.is_complete:
52
- return
53
-
54
- with logger.span(f'Making upstream request...'):
55
- self.client.resolve(exchange)
56
- if exchange.response.is_complete:
57
- return
58
-
59
- with logger.span(f'Processing upstream response...'):
60
- self.process_upstream(exchange)
61
- if exchange.response.is_complete:
62
- return
63
-
64
- exchange.response.is_complete = True
65
-
66
- logger.info(f'Resolution complete {request.message.id=} {exchange.response.answer=}')
67
- return
@@ -1,39 +0,0 @@
1
- import socket
2
- from dataclasses import dataclass
3
-
4
- from fmtr.tools.dns_tools.dm import Exchange
5
- from fmtr.tools.logging_tools import logger
6
-
7
-
8
- @dataclass
9
- class Plain:
10
- """
11
-
12
- Base for starting a plain DNS server
13
-
14
- """
15
-
16
- host: str
17
- port: int
18
-
19
- def __post_init__(self):
20
-
21
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
22
-
23
- def resolve(self, exchange: Exchange):
24
- raise NotImplemented
25
-
26
- def start(self):
27
- """
28
-
29
- Listen and resolve via overridden resolve method.
30
-
31
- """
32
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
33
- sock.bind((self.host, self.port))
34
- logger.info(f'Listening on {self.host}:{self.port}')
35
- while True:
36
- data, (ip, port) = sock.recvfrom(512)
37
- exchange = Exchange.from_wire(data, ip=ip, port=port)
38
- self.resolve(exchange)
39
- sock.sendto(exchange.response.message.to_wire(), (ip, port))
@@ -1 +0,0 @@
1
- 1.3.8
File without changes
File without changes
@@ -15,61 +15,61 @@ pydantic-ai[logfire,openai]
15
15
  ollama
16
16
 
17
17
  [all]
18
- tinynetrc
19
- flet-webview
20
- distributed
21
- logfire[httpx]
22
- pytest-cov
23
- pydevd-pycharm~=251.25410.159
24
- torchaudio
25
- docker
18
+ uvicorn[standard]
19
+ json_repair
26
20
  httpx
27
- pydantic-ai[logfire,openai]
28
- logfire[fastapi]
29
- filetype
30
21
  openai
31
- semver
32
- fastapi
33
- logfire
34
- faker
35
- appdirs
36
- sre_yield
37
- huggingface_hub
22
+ openpyxl
23
+ flet[all]
38
24
  regex
39
- google-auth
40
- bokeh
41
- ollama
42
- Unidecode
25
+ tabulate
26
+ tinynetrc
27
+ filetype
28
+ google-api-python-client
29
+ yamlscript
30
+ tokenizers
43
31
  deepmerge
32
+ sre_yield
33
+ diskcache
34
+ transformers[sentencepiece]
35
+ google-auth-oauthlib
36
+ Unidecode
37
+ sentence_transformers
38
+ logfire
39
+ logfire[fastapi]
40
+ pydantic
41
+ semver
42
+ dnspython[doh]
43
+ pydevd-pycharm~=251.25410.159
44
+ google-auth-httplib2
45
+ pymupdf4llm
46
+ html2text
47
+ google-auth
48
+ pydantic-settings
49
+ huggingface_hub
50
+ pyyaml
51
+ torchvision
44
52
  pymupdf
45
- uvicorn[standard]
53
+ fastapi
54
+ logfire[httpx]
55
+ contexttimer
46
56
  httpx_retries
47
- tokenizers
48
57
  dask[bag]
49
- tabulate
50
- flet[all]
58
+ peft
59
+ distributed
60
+ docker
61
+ faker
51
62
  cachetools
52
- pymupdf4llm
53
- sentence_transformers
54
- diskcache
55
- pydantic-settings
56
- google-auth-httplib2
63
+ torchaudio
64
+ setuptools
65
+ pytest-cov
66
+ pydantic-ai[logfire,openai]
57
67
  flet-video
58
- yamlscript
59
- contexttimer
60
- pydantic
61
- peft
62
- transformers[sentencepiece]
63
- torchvision
68
+ flet-webview
69
+ appdirs
64
70
  pandas
65
- html2text
66
- google-auth-oauthlib
67
- pyyaml
68
- google-api-python-client
69
- openpyxl
70
- setuptools
71
- json_repair
72
- dnspython[doh]
71
+ bokeh
72
+ ollama
73
73
 
74
74
  [api]
75
75
  fastapi
File without changes
File without changes
File without changes