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

fmtr/tools/__init__.py CHANGED
@@ -1,8 +1,4 @@
1
- from fmtr.tools import version_tools as version
2
-
3
- __version__ = version.read()
4
-
5
-
1
+ import fmtr.tools.async_tools as asyncio
6
2
  import fmtr.tools.dataclass_tools as dataclass
7
3
  import fmtr.tools.datatype_tools as datatype
8
4
  import fmtr.tools.environment_tools as env
@@ -12,26 +8,22 @@ import fmtr.tools.hash_tools as hash
12
8
  import fmtr.tools.import_tools as import_
13
9
  import fmtr.tools.iterator_tools as iterator
14
10
  import fmtr.tools.json_tools as json
11
+ import fmtr.tools.logging_tools as logging
12
+ import fmtr.tools.name_tools as name
13
+ import fmtr.tools.packaging_tools as packaging
15
14
  import fmtr.tools.path_tools as path
16
15
  import fmtr.tools.platform_tools as platform
17
16
  import fmtr.tools.random_tools as random
17
+ import fmtr.tools.setup_tools as setup
18
18
  import fmtr.tools.string_tools as string
19
- import fmtr.tools.name_tools as name
20
- import fmtr.tools.logging_tools as logging
21
- import fmtr.tools.async_tools as asyncio
22
- import fmtr.tools.packaging_tools as packaging
23
- from fmtr.tools.logging_tools import logger
24
-
25
- from fmtr.tools.import_tools import MissingExtraMockModule
26
-
19
+ from fmtr.tools import ai_tools as ai
20
+ from fmtr.tools import dns_tools as dns
21
+ from fmtr.tools import version_tools as version
27
22
  from fmtr.tools.constants import Constants
28
-
23
+ from fmtr.tools.import_tools import MissingExtraMockModule
24
+ from fmtr.tools.logging_tools import logger
29
25
  # Submodules
30
26
  from fmtr.tools.path_tools import Path, PackagePaths, AppPaths
31
- from fmtr.tools import ai_tools as ai
32
- from fmtr.tools import dns_tools as dns
33
-
34
- import fmtr.tools.setup_tools as setup
35
27
  from fmtr.tools.setup_tools import Setup, SetupPaths, Dependencies, Tools
36
28
 
37
29
  try:
@@ -178,3 +170,12 @@ try:
178
170
  from fmtr.tools.http_tools import Client
179
171
  except ImportError as exception:
180
172
  http = Client = MissingExtraMockModule('http', exception)
173
+
174
+
175
+ def get_version():
176
+ """
177
+
178
+ Defer reading version
179
+
180
+ """
181
+ return version.read()
fmtr/tools/api_tools.py CHANGED
@@ -3,7 +3,7 @@ from dataclasses import dataclass
3
3
  from fastapi import FastAPI, Request
4
4
  from typing import Callable, List, Optional, Union
5
5
 
6
- from fmtr.tools.environment_tools import IS_DEBUG
6
+ from fmtr.tools import environment_tools
7
7
  from fmtr.tools.iterator_tools import enlist
8
8
  from fmtr.tools.logging_tools import logger
9
9
 
@@ -57,7 +57,7 @@ class ApiBase:
57
57
  for endpoint in self.get_endpoints():
58
58
  self.add_endpoint(endpoint)
59
59
 
60
- if IS_DEBUG:
60
+ if environment_tools.IS_DEV:
61
61
  self.app.exception_handler(Exception)(self.handle_exception)
62
62
 
63
63
  def get_endpoints(self) -> List[Endpoint]:
@@ -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):
fmtr/tools/constants.py CHANGED
@@ -17,6 +17,7 @@ class Constants:
17
17
  ARROW = '→'
18
18
  ARROW_SEP = f' {ARROW} '
19
19
 
20
+ FMTR_DEV_KEY = 'FMTR_DEV'
20
21
  FMTR_LOG_LEVEL_KEY = 'FMTR_LOG_LEVEL'
21
22
  FMTR_OBS_API_KEY_KEY = 'FMTR_OBS_API_KEY'
22
23
  FMTR_OBS_HOST = 'obs.sv.fmtr.dev'
@@ -43,3 +44,6 @@ class Constants:
43
44
  ENTRYPOINTS_DIR = 'entrypoints'
44
45
  PACKAGE_EXCLUDE_DIRS = {'data', 'build', 'dist', '.*', '*egg-info*'}
45
46
  INIT_FILENAME = '__init__.py'
47
+
48
+ DEVELOPMENT = "development"
49
+ PRODUCTION = "production"
@@ -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
@@ -1,11 +1,11 @@
1
1
  from dataclasses import dataclass
2
2
 
3
- from fmtr.tools import logger
4
3
  from fmtr.tools.dns_tools import server, client
5
4
  from fmtr.tools.dns_tools.dm import Exchange
5
+ from fmtr.tools.logging_tools import logger
6
6
 
7
7
 
8
- @dataclass
8
+ @dataclass(kw_only=True, eq=False)
9
9
  class Proxy(server.Plain):
10
10
  """
11
11
 
@@ -31,7 +31,7 @@ class Proxy(server.Plain):
31
31
  """
32
32
  return
33
33
 
34
- def resolve(self, exchange: Exchange):
34
+ def resolve(self, exchange: Exchange) -> Exchange:
35
35
  """
36
36
 
37
37
  Resolve a request, processing each stage, initial question, upstream response etc.
@@ -39,29 +39,19 @@ class Proxy(server.Plain):
39
39
 
40
40
  """
41
41
 
42
- request = exchange.request
42
+ with logger.span(f'Processing question...'):
43
+ self.process_question(exchange)
44
+ if exchange.response.is_complete:
45
+ return exchange
43
46
 
44
- with logger.span(f'Handling request {request.message.id=} {request.question=} {exchange.client=}...'):
47
+ with logger.span(f'Making upstream request...'):
48
+ self.client.resolve(exchange)
49
+ if exchange.response.is_complete:
50
+ return exchange
45
51
 
46
- if not request.is_valid:
47
- raise ValueError(f'Only one question per request is supported. Got {len(request.question)} questions.')
52
+ with logger.span(f'Processing upstream response...'):
53
+ self.process_upstream(exchange)
54
+ if exchange.response.is_complete:
55
+ return exchange
48
56
 
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
57
+ return exchange
@@ -1,11 +1,14 @@
1
1
  import socket
2
2
  from dataclasses import dataclass
3
+ from datetime import timedelta
4
+ from functools import cached_property
3
5
 
6
+ from fmtr.tools import caching_tools as caching
4
7
  from fmtr.tools.dns_tools.dm import Exchange
5
8
  from fmtr.tools.logging_tools import logger
6
9
 
7
10
 
8
- @dataclass
11
+ @dataclass(kw_only=True, eq=False)
9
12
  class Plain:
10
13
  """
11
14
 
@@ -16,12 +19,19 @@ class Plain:
16
19
  host: str
17
20
  port: int
18
21
 
19
- def __post_init__(self):
22
+ @cached_property
23
+ def sock(self):
24
+ return socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
20
25
 
21
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
26
+ @cached_property
27
+ def cache(self):
28
+ """
22
29
 
23
- def resolve(self, exchange: Exchange):
24
- raise NotImplemented
30
+ Overridable cache.
31
+
32
+ """
33
+ cache = caching.TLRU(maxsize=1_024, ttu_static=timedelta(hours=1), desc='DNS Request')
34
+ return cache
25
35
 
26
36
  def start(self):
27
37
  """
@@ -35,5 +45,50 @@ class Plain:
35
45
  while True:
36
46
  data, (ip, port) = sock.recvfrom(512)
37
47
  exchange = Exchange.from_wire(data, ip=ip, port=port)
38
- self.resolve(exchange)
48
+ self.handle(exchange)
39
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
@@ -76,4 +76,4 @@ get_date = get_getter(date.fromisoformat)
76
76
  get_datetime = get_getter(datetime.fromisoformat)
77
77
  get_path = get_getter(Path)
78
78
 
79
- IS_DEBUG = get(Constants.FMTR_LOG_LEVEL_KEY, None, converter=str.upper) == 'DEBUG'
79
+ IS_DEV = get_bool(Constants.FMTR_DEV_KEY, default=False)
@@ -4,23 +4,26 @@ import os
4
4
  from fmtr.tools import environment_tools
5
5
  from fmtr.tools.constants import Constants
6
6
 
7
- DEVELOPMENT = "development"
8
- PRODUCTION = "production"
9
- STREAM_DEFAULT = DEVELOPMENT
10
- ENVIRONMENT_DEFAULT = DEVELOPMENT
7
+ if environment_tools.IS_DEV:
8
+ STREAM_DEFAULT = ENVIRONMENT_DEFAULT = Constants.DEVELOPMENT
9
+ else:
10
+ STREAM_DEFAULT = None
11
+ ENVIRONMENT_DEFAULT = Constants.PRODUCTION
11
12
 
12
- LEVEL_DEFAULT = logging.DEBUG if environment_tools.IS_DEBUG else logging.INFO
13
+ IS_DEBUG = environment_tools.get(Constants.FMTR_LOG_LEVEL_KEY, None, converter=str.upper) == 'DEBUG'
14
+ LEVEL_DEFAULT = logging.DEBUG if IS_DEBUG else logging.INFO
13
15
 
14
16
 
15
17
  def get_logger(name, version=None, host=Constants.FMTR_OBS_HOST, key=None, org=Constants.ORG_NAME,
16
- stream=STREAM_DEFAULT,
17
- environment=ENVIRONMENT_DEFAULT, level=LEVEL_DEFAULT):
18
+ stream=STREAM_DEFAULT, environment=ENVIRONMENT_DEFAULT, level=LEVEL_DEFAULT):
18
19
  """
19
20
 
20
21
  Get a pre-configured logfire logger, if dependency is present, otherwise default to native logger.
21
22
 
22
23
  """
23
24
 
25
+ stream = stream or name
26
+
24
27
  try:
25
28
  import logfire
26
29
  except ImportError:
@@ -65,7 +68,8 @@ def get_logger(name, version=None, host=Constants.FMTR_OBS_HOST, key=None, org=C
65
68
  )
66
69
 
67
70
  if key is None:
68
- logger.warning(f'Observability dependencies installed, but "{Constants.FMTR_OBS_API_KEY_KEY}" not set. Cloud observability will be disabled.')
71
+ msg = f'Observability dependencies installed, but "{Constants.FMTR_OBS_API_KEY_KEY}" not set. Cloud observability will be disabled.'
72
+ logger.warning(msg)
69
73
 
70
74
  return logger
71
75
 
@@ -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
 
fmtr/tools/version CHANGED
@@ -1 +1 @@
1
- 1.3.8
1
+ 1.3.10
@@ -0,0 +1,12 @@
1
+ from fmtr.tools.import_tools import MissingExtraMockModule
2
+
3
+ from fmtr.tools.version_tools.version_tools import read, read_path, get
4
+
5
+ try:
6
+ import semver
7
+
8
+ semver = semver
9
+ parse = semver.VersionInfo.parse
10
+
11
+ except ImportError as exception:
12
+ semver = parse = MissingExtraMockModule('version.dev', exception)
@@ -0,0 +1,51 @@
1
+ from fmtr.tools import environment_tools as env
2
+ from fmtr.tools.constants import Constants
3
+ from fmtr.tools.inspection_tools import get_call_path
4
+
5
+
6
+ def read() -> str:
7
+ """
8
+
9
+ Read a generic version file from the calling package path.
10
+
11
+ """
12
+
13
+ path = get_call_path(offset=2).parent / Constants.FILENAME_VERSION
14
+ return read_path(path)
15
+
16
+
17
+ def read_path(path) -> str:
18
+ """
19
+
20
+ Read in version from specified path
21
+
22
+ """
23
+ from fmtr.tools.tools import Constants
24
+ text = path.read_text(encoding=Constants.ENCODING).strip()
25
+
26
+ text = get(text)
27
+ return text
28
+
29
+
30
+ def get(text) -> str:
31
+ """
32
+
33
+ Optionally add dev build info to raw version string.
34
+
35
+ """
36
+
37
+ if not env.IS_DEV:
38
+ return text
39
+
40
+ import datetime
41
+ from fmtr.tools.tools import Constants
42
+ from fmtr.tools.version_tools import parse
43
+
44
+ timestamp = datetime.datetime.now(datetime.timezone.utc).strftime(Constants.DATETIME_SEMVER_BUILD_FORMAT)
45
+
46
+ version = parse(text)
47
+ version = version.bump_patch()
48
+ version = version.replace(prerelease=Constants.DEVELOPMENT, build=timestamp)
49
+ text = str(version)
50
+
51
+ return text
fmtr/tools/yaml_tools.py CHANGED
@@ -29,7 +29,7 @@ def install():
29
29
 
30
30
 
31
31
  @lru_cache
32
- def get_module(is_auto=env.IS_DEBUG):
32
+ def get_module(is_auto=env.IS_DEV):
33
33
  """
34
34
 
35
35
  Get the YAML Script runtime module, installing the runtime if specified
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.8
3
+ Version: 1.3.10
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
@@ -15,7 +15,6 @@ Requires-Dist: yamlscript; extra == "yaml"
15
15
  Requires-Dist: pyyaml; extra == "yaml"
16
16
  Provides-Extra: logging
17
17
  Requires-Dist: logfire; extra == "logging"
18
- Requires-Dist: semver; extra == "logging"
19
18
  Provides-Extra: parallel
20
19
  Requires-Dist: dask[bag]; extra == "parallel"
21
20
  Requires-Dist: distributed; extra == "parallel"
@@ -27,7 +26,6 @@ Requires-Dist: faker; extra == "augmentation"
27
26
  Requires-Dist: sre_yield; extra == "augmentation"
28
27
  Provides-Extra: process
29
28
  Requires-Dist: logfire; extra == "process"
30
- Requires-Dist: semver; extra == "process"
31
29
  Provides-Extra: profiling
32
30
  Requires-Dist: contexttimer; extra == "profiling"
33
31
  Provides-Extra: docker-api
@@ -35,7 +33,8 @@ Requires-Dist: docker; extra == "docker-api"
35
33
  Provides-Extra: unicode
36
34
  Requires-Dist: Unidecode; extra == "unicode"
37
35
  Provides-Extra: version
38
- Requires-Dist: semver; extra == "version"
36
+ Provides-Extra: version-dev
37
+ Requires-Dist: semver; extra == "version-dev"
39
38
  Provides-Extra: spaces
40
39
  Requires-Dist: tinynetrc; extra == "spaces"
41
40
  Provides-Extra: netrc
@@ -48,7 +47,6 @@ Provides-Extra: api
48
47
  Requires-Dist: fastapi; extra == "api"
49
48
  Requires-Dist: uvicorn[standard]; extra == "api"
50
49
  Requires-Dist: logfire; extra == "api"
51
- Requires-Dist: semver; extra == "api"
52
50
  Requires-Dist: pydantic; extra == "api"
53
51
  Requires-Dist: logfire[fastapi]; extra == "api"
54
52
  Provides-Extra: ai
@@ -63,7 +61,6 @@ Provides-Extra: openai-api
63
61
  Requires-Dist: openai; extra == "openai-api"
64
62
  Provides-Extra: ai-client
65
63
  Requires-Dist: logfire; extra == "ai-client"
66
- Requires-Dist: semver; extra == "ai-client"
67
64
  Requires-Dist: pydantic; extra == "ai-client"
68
65
  Requires-Dist: openai; extra == "ai-client"
69
66
  Requires-Dist: pydantic-ai[logfire,openai]; extra == "ai-client"
@@ -118,7 +115,6 @@ Requires-Dist: dnspython[doh]; extra == "dns"
118
115
  Requires-Dist: httpx; extra == "dns"
119
116
  Requires-Dist: httpx_retries; extra == "dns"
120
117
  Requires-Dist: logfire; extra == "dns"
121
- Requires-Dist: semver; extra == "dns"
122
118
  Requires-Dist: logfire[httpx]; extra == "dns"
123
119
  Provides-Extra: patterns
124
120
  Requires-Dist: regex; extra == "patterns"
@@ -126,66 +122,65 @@ Provides-Extra: http
126
122
  Requires-Dist: httpx; extra == "http"
127
123
  Requires-Dist: httpx_retries; extra == "http"
128
124
  Requires-Dist: logfire; extra == "http"
129
- Requires-Dist: semver; extra == "http"
130
125
  Requires-Dist: logfire[httpx]; extra == "http"
131
126
  Provides-Extra: setup
132
127
  Requires-Dist: setuptools; extra == "setup"
133
128
  Provides-Extra: all
134
- Requires-Dist: html2text; extra == "all"
135
- Requires-Dist: appdirs; extra == "all"
136
- Requires-Dist: httpx_retries; extra == "all"
137
- Requires-Dist: diskcache; extra == "all"
138
- Requires-Dist: google-auth; extra == "all"
139
- Requires-Dist: docker; extra == "all"
129
+ Requires-Dist: flet-video; extra == "all"
140
130
  Requires-Dist: faker; extra == "all"
141
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
142
- Requires-Dist: sre_yield; extra == "all"
143
131
  Requires-Dist: fastapi; extra == "all"
132
+ Requires-Dist: torchvision; extra == "all"
144
133
  Requires-Dist: bokeh; extra == "all"
145
- Requires-Dist: huggingface_hub; extra == "all"
146
- Requires-Dist: pymupdf; extra == "all"
147
- Requires-Dist: google-api-python-client; extra == "all"
148
- Requires-Dist: pydantic; extra == "all"
149
- Requires-Dist: dnspython[doh]; extra == "all"
150
- Requires-Dist: pandas; extra == "all"
151
- Requires-Dist: yamlscript; extra == "all"
152
- Requires-Dist: openai; extra == "all"
153
- Requires-Dist: deepmerge; extra == "all"
154
- Requires-Dist: filetype; extra == "all"
155
134
  Requires-Dist: regex; extra == "all"
156
- Requires-Dist: peft; extra == "all"
157
- Requires-Dist: transformers[sentencepiece]; extra == "all"
158
- Requires-Dist: tinynetrc; extra == "all"
159
- Requires-Dist: flet-video; extra == "all"
160
135
  Requires-Dist: logfire; extra == "all"
161
- Requires-Dist: google-auth-oauthlib; extra == "all"
136
+ Requires-Dist: google-auth; extra == "all"
137
+ Requires-Dist: html2text; extra == "all"
138
+ Requires-Dist: tokenizers; extra == "all"
139
+ Requires-Dist: sentence_transformers; extra == "all"
162
140
  Requires-Dist: logfire[fastapi]; extra == "all"
141
+ Requires-Dist: peft; extra == "all"
142
+ Requires-Dist: cachetools; extra == "all"
143
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
163
144
  Requires-Dist: httpx; extra == "all"
164
- Requires-Dist: pytest-cov; extra == "all"
165
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
166
- Requires-Dist: distributed; extra == "all"
167
145
  Requires-Dist: contexttimer; extra == "all"
168
- Requires-Dist: pymupdf4llm; extra == "all"
169
- Requires-Dist: setuptools; extra == "all"
146
+ Requires-Dist: distributed; extra == "all"
147
+ Requires-Dist: appdirs; extra == "all"
148
+ Requires-Dist: dask[bag]; extra == "all"
149
+ Requires-Dist: yamlscript; extra == "all"
170
150
  Requires-Dist: uvicorn[standard]; extra == "all"
171
- Requires-Dist: logfire[httpx]; extra == "all"
172
- Requires-Dist: json_repair; extra == "all"
173
- Requires-Dist: pyyaml; extra == "all"
151
+ Requires-Dist: openai; extra == "all"
152
+ Requires-Dist: pandas; extra == "all"
153
+ Requires-Dist: pydantic; extra == "all"
154
+ Requires-Dist: deepmerge; extra == "all"
155
+ Requires-Dist: dnspython[doh]; extra == "all"
174
156
  Requires-Dist: openpyxl; extra == "all"
175
- Requires-Dist: semver; extra == "all"
157
+ Requires-Dist: huggingface_hub; extra == "all"
158
+ Requires-Dist: flet-webview; extra == "all"
159
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
160
+ Requires-Dist: sre_yield; extra == "all"
161
+ Requires-Dist: tinynetrc; extra == "all"
162
+ Requires-Dist: pymupdf; extra == "all"
176
163
  Requires-Dist: torchaudio; extra == "all"
177
164
  Requires-Dist: pydantic-settings; extra == "all"
178
- Requires-Dist: dask[bag]; extra == "all"
179
- Requires-Dist: tokenizers; extra == "all"
180
- Requires-Dist: tabulate; extra == "all"
181
- Requires-Dist: cachetools; extra == "all"
182
- Requires-Dist: torchvision; extra == "all"
165
+ Requires-Dist: filetype; extra == "all"
166
+ Requires-Dist: semver; extra == "all"
167
+ Requires-Dist: json_repair; extra == "all"
168
+ Requires-Dist: flet[all]; extra == "all"
169
+ Requires-Dist: diskcache; extra == "all"
170
+ Requires-Dist: logfire[httpx]; extra == "all"
171
+ Requires-Dist: pytest-cov; extra == "all"
172
+ Requires-Dist: pyyaml; extra == "all"
173
+ Requires-Dist: docker; extra == "all"
183
174
  Requires-Dist: Unidecode; extra == "all"
184
- Requires-Dist: sentence_transformers; extra == "all"
175
+ Requires-Dist: tabulate; extra == "all"
176
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
177
+ Requires-Dist: google-api-python-client; extra == "all"
178
+ Requires-Dist: httpx_retries; extra == "all"
179
+ Requires-Dist: google-auth-oauthlib; extra == "all"
185
180
  Requires-Dist: google-auth-httplib2; extra == "all"
186
- Requires-Dist: flet[all]; extra == "all"
187
- Requires-Dist: flet-webview; extra == "all"
188
181
  Requires-Dist: ollama; extra == "all"
182
+ Requires-Dist: setuptools; extra == "all"
183
+ Requires-Dist: pymupdf4llm; extra == "all"
189
184
  Dynamic: author
190
185
  Dynamic: author-email
191
186
  Dynamic: description
@@ -1,15 +1,15 @@
1
- fmtr/tools/__init__.py,sha256=vCxKR0SymygpO-EtCGPmGZEQv5O1goM7Jr8P4m-eJsQ,5676
2
- fmtr/tools/api_tools.py,sha256=w8Zrp_EwN5KlUghwLoTCXo4z1irg5tAsReCqDLjASfE,2133
1
+ fmtr/tools/__init__.py,sha256=sjXo4eRDOPp20zlLpJqaB48h7RQXKJd_RwR3fwD6oGk,5731
2
+ fmtr/tools/api_tools.py,sha256=u2uEw-5OGN-eU4bNMC7ef5nmopVZTPyVN5eb_rr8ZS0,2140
3
3
  fmtr/tools/async_tools.py,sha256=ewz757WcveQJd-G5SVr2JDOQVbdLGecCgl-tsBGVZz4,284
4
4
  fmtr/tools/augmentation_tools.py,sha256=-6ESbO4CDlKqVOV1J1V6qBeoBMzbFIinkDHRHnCBej0,55
5
- fmtr/tools/caching_tools.py,sha256=BZ5HSzcyCSnvJ6h5xtu5jELPSPDazVsMU7q7OX_oKBE,4886
6
- fmtr/tools/constants.py,sha256=QHJWu2UZwdV1ceGKT-pq-eYGPw4t7aFxb_W8r4G9VVk,1429
5
+ fmtr/tools/caching_tools.py,sha256=74p7m2GLFfeP41LX69wxgfkilxEAoWkMIfFMjKsYpyg,4976
6
+ fmtr/tools/constants.py,sha256=R6kyJOahQwwjBqmiD-c-4pMMAyGpffxZUSHMffkYmLI,1522
7
7
  fmtr/tools/data_modelling_tools.py,sha256=0BFm-F_cYzVTxftWQwORkPd0FM2BTLVh9-s0-rTTFoo,1744
8
8
  fmtr/tools/dataclass_tools.py,sha256=0Gt6KeLhtPgubo_2tYkIVqB8oQ91Qzag8OAGZDdjvMU,1209
9
9
  fmtr/tools/datatype_tools.py,sha256=3P4AWIFGkJ-UqvXlj0Jc9IvkIIgTOE9jRrOk3NVbpH8,1508
10
10
  fmtr/tools/debugging_tools.py,sha256=_xzqS0V5BpL8d06j-jVQjGgI7T020QsqVXKAKMz7Du8,2082
11
11
  fmtr/tools/docker_tools.py,sha256=rdaZje2xhlmnfQqZnR7IHgRdWncTLjrJcViUTt5oEwk,617
12
- fmtr/tools/environment_tools.py,sha256=ZO2e8pTzbQ8jNXnmKpaZF7_3qkVM6U5iqku5YSwOszE,1849
12
+ fmtr/tools/environment_tools.py,sha256=jlx6LYFVv9tyNBT_pVD-tDhyR3ccNC7w6ENVlnoxCLM,1823
13
13
  fmtr/tools/function_tools.py,sha256=_oW3-HZXMst2pcU-I-U7KTMmzo0g9MIQKmX-c2_NEoE,858
14
14
  fmtr/tools/google_api_tools.py,sha256=owWE0GlnJjmVbXus8ENxT2PH7Fnd3m_r-14xyR7lAnA,1107
15
15
  fmtr/tools/hash_tools.py,sha256=tr4HXpeT6rRrDk6TvMlRPUSrLRRaov96y128OI2tzsc,729
@@ -22,7 +22,7 @@ fmtr/tools/interface_tools.py,sha256=JVYUV7wuMr24BORuUtNaBlTeBFt8VDGJ3HPRajd7Y_4
22
22
  fmtr/tools/iterator_tools.py,sha256=xj5f0c7LgLK53dddRRRJxBoLaBzlZoQS3_GfmpDPMoo,1311
23
23
  fmtr/tools/json_fix_tools.py,sha256=vNSlswVQnujPmKEqDjFJcO901mjMyv59q3awsT7mlhs,477
24
24
  fmtr/tools/json_tools.py,sha256=WkFc5q7oqMtcFejhN1K5zQFULa9TdLOup83Fr0saDRY,348
25
- fmtr/tools/logging_tools.py,sha256=rVNoq46hsO3wF1dnpaGZxu_usFV_SLy16MlKbhivN_M,2332
25
+ fmtr/tools/logging_tools.py,sha256=M7I5igs_tX5SIRv4f-jfb75LOODclSdmEg5ziAAMSPE,2503
26
26
  fmtr/tools/merging_tools.py,sha256=KDxCEFJEQJEwGw1qGKAgR55uUE2X2S5NWLKcfHRmX_k,227
27
27
  fmtr/tools/metric_tools.py,sha256=Lvia5CGFRIfrDFA8s37btIfTU5zHbo04cPJdAMtbndQ,272
28
28
  fmtr/tools/name_tools.py,sha256=5CB_phqhHjl66iI8oLxOGPF2odC1apdul-M8Fv2xBhs,5514
@@ -30,7 +30,7 @@ fmtr/tools/netrc_tools.py,sha256=PpNpz_mWlQi6VHGromKwFfTyLpHUXsd4LY6-OKLCbeI,376
30
30
  fmtr/tools/openai_tools.py,sha256=6SUgejgzUzmlKKct2_ePXntvMegu3FJgfk9x7aqtqYc,742
31
31
  fmtr/tools/packaging_tools.py,sha256=FlgOTnDRHZWQL2iR-wucTsyGEHRE-MlddKL30MPmUqE,253
32
32
  fmtr/tools/parallel_tools.py,sha256=QEb_gN1StkxsqYaH4HSjiJX8Y3gpb2uKNsOzG4uFpaM,3071
33
- fmtr/tools/pattern_tools.py,sha256=Rmengjn_Ya246mlkAVR9fxVxXJUqEHWdDYu8Hsl9pXw,6003
33
+ fmtr/tools/pattern_tools.py,sha256=DlEKzNJKhwFmU3-awoGkN5Xy-yLF_bsoj8eoSMCEytE,6018
34
34
  fmtr/tools/pdf_tools.py,sha256=xvv9B84uAF81rFJRnXhSsxYuP42vY9ZdPVFrSMVe8G8,4069
35
35
  fmtr/tools/platform_tools.py,sha256=7p69CmAHe_sF68Fx9uVhns1k5EewTHTWgUYzkl6ZQKA,308
36
36
  fmtr/tools/process_tools.py,sha256=Ysh5Dk2QFBhXQerArjKdt7xZd3JrN5Ho02AaOjH0Nnw,1425
@@ -44,17 +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=TcdU53CiqvG9NX8A4sH_s0eyfztzmjd5EWmCXTCwpQE,5
48
- fmtr/tools/version_tools.py,sha256=yNs_CGqWpqE4jbK9wsPIi14peJVXYbhIcMqHAFOw3yE,1480
49
- fmtr/tools/yaml_tools.py,sha256=9kuYChqJelWQIjGlSnK4iDdOWWH06P0gp9jIcRrC3UI,1903
47
+ fmtr/tools/version,sha256=KXp_jTzlhrmPBGoDE8ZyMR8_fR2OLdfF-J8Z6JpyZHk,6
48
+ fmtr/tools/yaml_tools.py,sha256=Bhhyd6GQVKO72Lp8ky7bAUjIB_65Hdh0Q45SKIEe6S8,1901
50
49
  fmtr/tools/ai_tools/__init__.py,sha256=JZrLuOFNV1A3wvJgonxOgz_4WS-7MfCuowGWA5uYCjs,372
51
50
  fmtr/tools/ai_tools/agentic_tools.py,sha256=acSEPFS-aguDXanWGs3fAAlRyJSYPZW7L-Kb2qDLm-I,4300
52
51
  fmtr/tools/ai_tools/inference_tools.py,sha256=2UP2gXEyOJUjyyV6zmFIYmIxUsh1rXkRH0IbFvr2bRs,11908
53
52
  fmtr/tools/dns_tools/__init__.py,sha256=PjD3Og6D5yvDVpKmsUsrnSpz_rjXpl4zBtvMqm8xKWU,237
54
53
  fmtr/tools/dns_tools/client.py,sha256=c2vzWBDZSxijwL1KvWUoDGc8wqk_KTAFxCr0P1rNjy8,2367
55
- fmtr/tools/dns_tools/dm.py,sha256=KWQeeZhsDyrKoXzAD5zEOoHH3aiD4uKRqwnD8fFP1nI,3725
56
- fmtr/tools/dns_tools/proxy.py,sha256=L0utKw8D1JXtAW9IfXcBdNMb-AyPFgW5XGiPnWuk7D8,1878
57
- fmtr/tools/dns_tools/server.py,sha256=t38TmSpra3FRoMk351eHzOOPlSuaCyjxbvPwX9o15ak,942
54
+ fmtr/tools/dns_tools/dm.py,sha256=QqEYebamLWMzr1KM1x4P4dUvPZL_zvymZrNj6ghw0rg,4445
55
+ fmtr/tools/dns_tools/proxy.py,sha256=b3TdSwRO7IwcNjrWg1e8jVQb-YxJhT377rdVkeDc8_I,1466
56
+ fmtr/tools/dns_tools/server.py,sha256=FK5S9r34aWapD3tv7rYG1dvHZrfCgg0hL9yGpZkZHkc,2623
58
57
  fmtr/tools/entrypoints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
58
  fmtr/tools/entrypoints/cache_hfh.py,sha256=fQNs4J9twQuZH_Yj98-oOvEX7-LrSUP3kO8nzw2HrHs,60
60
59
  fmtr/tools/entrypoints/ep_test.py,sha256=B8HfWISfSgw_xVX475CbJGh_QnpOe9MH65H8qGjTWbY,46
@@ -75,9 +74,11 @@ fmtr/tools/tests/test_environment.py,sha256=iHaiMQfECYZPkPKwfuIZV9uHuWe3aE-p_dN_
75
74
  fmtr/tools/tests/test_json.py,sha256=IeSP4ziPvRcmS8kq7k9tHonC9rN5YYq9GSNT2ul6Msk,287
76
75
  fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g,2188
77
76
  fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
78
- fmtr_tools-1.3.8.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
79
- fmtr_tools-1.3.8.dist-info/METADATA,sha256=m6mbZy-IYtew40xeEmDdyBYhxDLdfiLg_hhR_H2xMEc,16148
80
- fmtr_tools-1.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
81
- fmtr_tools-1.3.8.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
82
- fmtr_tools-1.3.8.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
83
- fmtr_tools-1.3.8.dist-info/RECORD,,
77
+ fmtr/tools/version_tools/__init__.py,sha256=pg4iLtmIr5HtyEW_j0fMFoIdzqi_w9xH8-grQaXLB28,318
78
+ fmtr/tools/version_tools/version_tools.py,sha256=Hcc6yferZS1hHbugRTdiHhSNmXEEG0hjCiTTXKna-YY,1127
79
+ fmtr_tools-1.3.10.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
80
+ fmtr_tools-1.3.10.dist-info/METADATA,sha256=9m1RZ98vJX10nSFr-cIsA7VaNfePzOTqRjyMj_jDv_o,15938
81
+ fmtr_tools-1.3.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ fmtr_tools-1.3.10.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
83
+ fmtr_tools-1.3.10.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
84
+ fmtr_tools-1.3.10.dist-info/RECORD,,
@@ -1,62 +0,0 @@
1
- from fmtr.tools.import_tools import MissingExtraMockModule
2
- from fmtr.tools.inspection_tools import get_call_path
3
-
4
- try:
5
- import semver
6
-
7
- semver = semver
8
- parse = semver.VersionInfo.parse
9
- except ImportError as exception:
10
- # Special case to allow module import.
11
- # Should be slit out into separate version.dev subpackage
12
- parse = MissingExtraMockModule('version', exception)
13
- semver = MissingExtraMockModule('version', exception)
14
-
15
-
16
- def read() -> str:
17
- """
18
-
19
- Read a generic version file from the calling package path.
20
-
21
- """
22
-
23
- path = get_call_path(offset=2).parent / 'version'
24
- return read_path(path)
25
-
26
-
27
- def read_path(path) -> str:
28
- """
29
-
30
- Read in version from specified path
31
-
32
- """
33
- from fmtr.tools.tools import Constants
34
- text = path.read_text(encoding=Constants.ENCODING).strip()
35
-
36
- text = get(text)
37
- return text
38
-
39
-
40
- def get(text) -> str:
41
- """
42
-
43
- Optionally add dev build info to raw version string.
44
-
45
- """
46
- import os
47
- from fmtr.tools import datatype_tools
48
-
49
- is_dev = datatype_tools.to_bool(os.getenv('FMTR_DEV', default=False))
50
-
51
- if is_dev:
52
- import datetime
53
- from fmtr.tools.tools import Constants
54
-
55
- timestamp = datetime.datetime.now(datetime.timezone.utc).strftime(Constants.DATETIME_SEMVER_BUILD_FORMAT)
56
-
57
- version = parse(text)
58
- version = version.bump_patch()
59
- version = version.replace(prerelease='dev', build=timestamp)
60
- text = str(version)
61
-
62
- return text