fmtr.tools 1.0.55__py3-none-any.whl → 1.1.0__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
@@ -2,7 +2,7 @@ from fmtr.tools import version_tools as version
2
2
 
3
3
  __version__ = version.read()
4
4
 
5
- import fmtr.tools.config_tools as config
5
+
6
6
  import fmtr.tools.dataclass_tools as dataclass
7
7
  import fmtr.tools.datatype_tools as datatype
8
8
  import fmtr.tools.environment_tools as env
@@ -22,7 +22,8 @@ import fmtr.tools.async_tools as asyncio
22
22
  from fmtr.tools.logging_tools import logger
23
23
 
24
24
  from fmtr.tools.import_tools import MissingExtraMockModule
25
- from fmtr.tools.path_tools import Path
25
+ from fmtr.tools.path_tools import Path, PackagePaths
26
+ from fmtr.tools.constants import Constants
26
27
 
27
28
  try:
28
29
  from fmtr.tools import augmentation_tools as augmentation
@@ -158,9 +159,13 @@ try:
158
159
  except ImportError as exception:
159
160
  debug = MissingExtraMockModule('debug', exception)
160
161
 
162
+ try:
163
+ from fmtr.tools import settings_tools as sets
164
+ except ImportError as exception:
165
+ sets = MissingExtraMockModule('sets', exception)
166
+
161
167
 
162
168
  __all__ = [
163
- 'config',
164
169
  'dataclass',
165
170
  'datatype',
166
171
  'environment',
@@ -6,7 +6,7 @@ from pydantic_ai.models.openai import OpenAIModel
6
6
  from pydantic_ai.providers.openai import OpenAIProvider
7
7
 
8
8
  from fmtr.tools import environment_tools as env
9
- from fmtr.tools.config import ToolsConfig
9
+ from fmtr.tools.constants import Constants
10
10
 
11
11
  pydantic_ai.Agent.instrument_all()
12
12
 
@@ -17,9 +17,9 @@ class Task:
17
17
 
18
18
  """
19
19
 
20
- PROVIDER = OpenAIProvider(api_key=env.get(ToolsConfig.FMTR_OPENAI_API_KEY_KEY))
20
+ PROVIDER = OpenAIProvider(api_key=env.get(Constants.FMTR_OPENAI_API_KEY_KEY))
21
21
 
22
- API_HOST_FMTR = env.get(ToolsConfig.FMTR_AI_HOST_KEY, ToolsConfig.FMTR_AI_HOST_DEFAULT)
22
+ API_HOST_FMTR = env.get(Constants.FMTR_AI_HOST_KEY, Constants.FMTR_AI_HOST_DEFAULT)
23
23
  API_URL_FMTR = f'https://{API_HOST_FMTR}/v1'
24
24
  PROVIDER_FMTR = OpenAIProvider(base_url=API_URL_FMTR)
25
25
 
@@ -1,9 +1,7 @@
1
1
  import datetime
2
2
 
3
- from fmtr.tools.config_tools import ConfigClass
4
3
 
5
-
6
- class ToolsConfig(ConfigClass):
4
+ class Constants:
7
5
  ENCODING = 'UTF-8'
8
6
  ORG_NAME = 'fmtr'
9
7
  LIBRARY_NAME = f'{ORG_NAME}.tools'
@@ -1,7 +1,7 @@
1
1
  import pydevd_pycharm
2
2
 
3
3
  from fmtr.tools import environment_tools as env
4
- from fmtr.tools.config import ToolsConfig
4
+ from fmtr.tools.constants import Constants
5
5
 
6
6
  MASK = 'Starting debugger at tcp://{host}:{port}...'
7
7
 
@@ -12,16 +12,16 @@ def trace(is_debug=None, host=None, port=None, stdoutToServer=True, stderrToServ
12
12
 
13
13
  """
14
14
  if not is_debug:
15
- is_debug = env.get_bool(ToolsConfig.FMTR_REMOTE_DEBUG_ENABLED_KEY, False)
15
+ is_debug = env.get_bool(Constants.FMTR_REMOTE_DEBUG_ENABLED_KEY, False)
16
16
 
17
17
  if not is_debug:
18
18
  return
19
19
 
20
20
  if is_debug is True and not host:
21
- host = ToolsConfig.FMTR_REMOTE_DEBUG_HOST_DEFAULT
21
+ host = Constants.FMTR_REMOTE_DEBUG_HOST_DEFAULT
22
22
 
23
- host = host or env.get(ToolsConfig.FMTR_REMOTE_DEBUG_HOST_KEY, ToolsConfig.FMTR_REMOTE_DEBUG_HOST_DEFAULT)
24
- port = port or ToolsConfig.FMTR_REMOTE_DEBUG_PORT_DEFAULT
23
+ host = host or env.get(Constants.FMTR_REMOTE_DEBUG_HOST_KEY, Constants.FMTR_REMOTE_DEBUG_HOST_DEFAULT)
24
+ port = port or Constants.FMTR_REMOTE_DEBUG_PORT_DEFAULT
25
25
 
26
26
  from fmtr.tools import logger
27
27
 
@@ -8,7 +8,7 @@ from collections.abc import Callable
8
8
  from datetime import date, datetime
9
9
  from typing import Any, Dict
10
10
 
11
- from fmtr.tools.config import ToolsConfig
11
+ from fmtr.tools.constants import Constants
12
12
  from fmtr.tools.datatype_tools import to_bool
13
13
  from fmtr.tools.path_tools import Path
14
14
  from fmtr.tools.tools import identity, EMPTY
@@ -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(ToolsConfig.FMTR_LOG_LEVEL_KEY, None, converter=str.upper) == 'DEBUG'
79
+ IS_DEBUG = get(Constants.FMTR_LOG_LEVEL_KEY, None, converter=str.upper) == 'DEBUG'
fmtr/tools/hash_tools.py CHANGED
@@ -2,7 +2,7 @@ import base64
2
2
  import hashlib
3
3
  from zlib import crc32
4
4
 
5
- from fmtr.tools.config import ToolsConfig
5
+ from fmtr.tools.constants import Constants
6
6
 
7
7
  SPECIALS = {'O': '9', '=': '9', 'I': '9'}
8
8
 
@@ -12,7 +12,7 @@ def hash_unit(value: str) -> float:
12
12
  Hash the input string to a value between 0.0 and 1.0 (not secure).
13
13
 
14
14
  """
15
- value = str(value).encode(ToolsConfig.ENCODING)
15
+ value = str(value).encode(Constants.ENCODING)
16
16
  return float(crc32(value) & 0xffffffff) / 2 ** 32
17
17
 
18
18
 
fmtr/tools/json_tools.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import json
2
2
 
3
- from fmtr.tools.config import ToolsConfig
3
+ from fmtr.tools.constants import Constants
4
4
 
5
5
 
6
6
  def to_json(obj):
@@ -9,7 +9,7 @@ def to_json(obj):
9
9
  Serialise to JSON
10
10
 
11
11
  """
12
- json_str = json.dumps(obj, indent=ToolsConfig.SERIALIZATION_INDENT, ensure_ascii=False)
12
+ json_str = json.dumps(obj, indent=Constants.SERIALIZATION_INDENT, ensure_ascii=False)
13
13
  return json_str
14
14
 
15
15
 
@@ -2,7 +2,7 @@ import logging
2
2
  import os
3
3
 
4
4
  from fmtr.tools import environment_tools
5
- from fmtr.tools.config import ToolsConfig
5
+ from fmtr.tools.constants import Constants
6
6
 
7
7
  DEVELOPMENT = "development"
8
8
  PRODUCTION = "production"
@@ -12,7 +12,7 @@ ENVIRONMENT_DEFAULT = DEVELOPMENT
12
12
  LEVEL_DEFAULT = logging.DEBUG if environment_tools.IS_DEBUG else logging.INFO
13
13
 
14
14
 
15
- def get_logger(name, version=None, host=ToolsConfig.FMTR_OBS_HOST, key=None, org=ToolsConfig.ORG_NAME,
15
+ def get_logger(name, version=None, host=Constants.FMTR_OBS_HOST, key=None, org=Constants.ORG_NAME,
16
16
  stream=STREAM_DEFAULT,
17
17
  environment=ENVIRONMENT_DEFAULT, level=LEVEL_DEFAULT):
18
18
  """
@@ -31,7 +31,7 @@ def get_logger(name, version=None, host=ToolsConfig.FMTR_OBS_HOST, key=None, org
31
31
  return logger
32
32
 
33
33
  if key is None:
34
- key = environment_tools.get(ToolsConfig.FMTR_OBS_API_KEY_KEY)
34
+ key = environment_tools.get(Constants.FMTR_OBS_API_KEY_KEY)
35
35
  url = f"https://{host}/api/{org}/v1/traces"
36
36
  headers = f"Authorization=Basic {key},stream-name={stream}"
37
37
 
@@ -57,7 +57,7 @@ def get_logger(name, version=None, host=ToolsConfig.FMTR_OBS_HOST, key=None, org
57
57
  return logger
58
58
 
59
59
 
60
- logger = get_logger(name=ToolsConfig.LIBRARY_NAME)
60
+ logger = get_logger(name=Constants.LIBRARY_NAME)
61
61
 
62
62
  if __name__ == '__main__':
63
63
  logger.info('Hello World')
@@ -6,13 +6,12 @@ from contextlib import nullcontext as NullContext
6
6
  from dask.diagnostics import ProgressBar
7
7
  from typing import List, Callable, Any, Union
8
8
 
9
- from fmtr.tools.config_tools import ConfigClass
10
9
  from fmtr.tools.iterator_tools import dict_records_to_lists
11
10
  from fmtr.tools.logging_tools import logger
12
11
  from fmtr.tools.path_tools import Path
13
12
 
14
13
 
15
- class ParallelConfig(ConfigClass):
14
+ class ParallelConfig:
16
15
  """
17
16
 
18
17
  Configuration values.
fmtr/tools/path_tools.py CHANGED
@@ -1,11 +1,10 @@
1
1
  import re
2
2
  import subprocess
3
- from inspect import stack
4
3
  from pathlib import Path
5
4
  from tempfile import gettempdir
6
5
  from typing import Union, Any
7
6
 
8
- from fmtr.tools.config import ToolsConfig
7
+ from fmtr.tools.constants import Constants
9
8
  from fmtr.tools.platform_tools import is_wsl
10
9
 
11
10
  WIN_PATH_PATTERN = r'''([a-z]:(\\|$)|\\\\)'''
@@ -72,8 +71,8 @@ class Path(type(Path())):
72
71
  Get path to originating module (e.g. directory containing .py file).
73
72
 
74
73
  """
75
- frame_called = stack()[1]
76
- path = cls(frame_called.filename).absolute().parent
74
+ from fmtr.tools.inspection_tools import get_call_path
75
+ path = get_call_path(offset=2).absolute().parent
77
76
  return path
78
77
 
79
78
  @classmethod
@@ -83,8 +82,8 @@ class Path(type(Path())):
83
82
  Get path to originating module (i.e. .py file).
84
83
 
85
84
  """
86
- frame_called = stack()[1]
87
- path = cls(frame_called.filename).absolute()
85
+ from fmtr.tools.inspection_tools import get_call_path
86
+ path = get_call_path(offset=2).absolute()
88
87
  return path
89
88
 
90
89
  @classmethod
@@ -96,29 +95,6 @@ class Path(type(Path())):
96
95
  """
97
96
  return cls(gettempdir())
98
97
 
99
- @classmethod
100
- def data(cls, name='data') -> 'Path':
101
- """
102
-
103
- Fetch canonical "data"/"artifacts" path, whether calling package is regular or namespace package.
104
-
105
- """
106
- from fmtr.tools.inspection_tools import get_call_path
107
- path = get_call_path()
108
- path = path.absolute().parent.parent
109
-
110
- path /= name
111
-
112
- if path.exists():
113
- return path
114
-
115
- path = path.parent.parent / name
116
-
117
- if path.exists():
118
- return path
119
-
120
- raise FileNotFoundError(f'No "{name}" directory found at "{path}"')
121
-
122
98
  def write_json(self, obj) -> int:
123
99
  """
124
100
 
@@ -127,7 +103,7 @@ class Path(type(Path())):
127
103
  """
128
104
  from fmtr.tools import json
129
105
  json_str = json.to_json(obj)
130
- return self.write_text(json_str, encoding=ToolsConfig.ENCODING)
106
+ return self.write_text(json_str, encoding=Constants.ENCODING)
131
107
 
132
108
  def read_json(self) -> Any:
133
109
  """
@@ -136,7 +112,7 @@ class Path(type(Path())):
136
112
 
137
113
  """
138
114
  from fmtr.tools import json
139
- json_str = self.read_text(encoding=ToolsConfig.ENCODING)
115
+ json_str = self.read_text(encoding=Constants.ENCODING)
140
116
  obj = json.from_json(json_str)
141
117
  return obj
142
118
 
@@ -148,7 +124,7 @@ class Path(type(Path())):
148
124
  """
149
125
  from fmtr.tools import yaml
150
126
  yaml_str = yaml.to_yaml(obj)
151
- return self.write_text(yaml_str, encoding=ToolsConfig.ENCODING)
127
+ return self.write_text(yaml_str, encoding=Constants.ENCODING)
152
128
 
153
129
  def read_yaml(self) -> Any:
154
130
  """
@@ -157,7 +133,7 @@ class Path(type(Path())):
157
133
 
158
134
  """
159
135
  from fmtr.tools import yaml
160
- yaml_str = self.read_text(encoding=ToolsConfig.ENCODING)
136
+ yaml_str = self.read_text(encoding=Constants.ENCODING)
161
137
  obj = yaml.from_yaml(yaml_str)
162
138
  return obj
163
139
 
@@ -170,3 +146,107 @@ class Path(type(Path())):
170
146
  return self.mkdir(parents=True, exist_ok=True)
171
147
 
172
148
 
149
+ class PackagePaths:
150
+ """
151
+
152
+ Canonical paths for a package.
153
+
154
+ """
155
+
156
+ FILENAME_CONFIG = 'settings.yaml'
157
+ DIR_NAME_ARTIFACTS = 'artifacts'
158
+ FILENAME_VERSION = 'version'
159
+
160
+ def __init__(self, path=None, org_singleton=None, dir_name_artifacts=DIR_NAME_ARTIFACTS, filename_config=FILENAME_CONFIG, file_version=FILENAME_VERSION):
161
+
162
+ """
163
+
164
+ Use calling module path as default path, if not otherwise specified.
165
+
166
+ """
167
+ if not path:
168
+ from fmtr.tools.inspection_tools import get_call_path
169
+ path = get_call_path(offset=2).parent
170
+
171
+ self.path = Path(path)
172
+ self.org_singleton = org_singleton
173
+ self.dir_name_artifacts = dir_name_artifacts
174
+ self.filename_config = filename_config
175
+ self.filename_version = file_version
176
+
177
+ @property
178
+ def is_namespace(self) -> bool:
179
+ """
180
+
181
+ If organization is not hard-specified, then the package is a namespace.
182
+
183
+ """
184
+ return not bool(self.org_singleton)
185
+
186
+ @property
187
+ def name(self) -> str:
188
+ """
189
+
190
+ Name of package.
191
+
192
+ """
193
+ return self.path.stem
194
+
195
+ @property
196
+ def org(self) -> str:
197
+ """
198
+
199
+ Name of organization.
200
+
201
+ """
202
+ if not self.is_namespace:
203
+ return self.org_singleton
204
+ else:
205
+ return self.path.parent.stem
206
+
207
+ @property
208
+ def repo(self) -> Path:
209
+ """
210
+
211
+ Path of repo (i.e. parent of package base directory).
212
+
213
+ """
214
+ if self.is_namespace:
215
+ return self.path.parent.parent
216
+ else:
217
+ return self.path.parent
218
+
219
+ @property
220
+ def version(self) -> Path:
221
+ """
222
+
223
+ Path of version file.
224
+
225
+ """
226
+ return self.path / self.filename_version
227
+
228
+ @property
229
+ def artifacts(self) -> Path:
230
+ """
231
+
232
+ Path of artifacts directory.
233
+
234
+ """
235
+ return self.repo / self.dir_name_artifacts
236
+
237
+ @property
238
+ def settings(self) -> Path:
239
+ """
240
+
241
+ Path of settings file.
242
+
243
+ """
244
+ return self.artifacts / self.filename_config
245
+
246
+ def __repr__(self) -> str:
247
+ """
248
+
249
+ Show base path in repr.
250
+
251
+ """
252
+ return f'{self.__class__.__name__}("{self.path}")'
@@ -0,0 +1,65 @@
1
+ from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, YamlConfigSettingsSource, EnvSettingsSource, CliSettingsSource
2
+ from typing import ClassVar
3
+
4
+ from fmtr.tools.path_tools import PackagePaths
5
+
6
+
7
+ class Base(BaseSettings):
8
+ """
9
+
10
+ Base class for settings configuration using Pydantic BaseSettings.
11
+ Provides functionality for setting up and customizing sources for retrieving configuration values.
12
+ Defines sources for configuration through environment variables, CLI arguments, YAML files.
13
+
14
+ """
15
+
16
+ paths: ClassVar = PackagePaths()
17
+
18
+ @classmethod
19
+ def settings_customise_sources(
20
+ cls,
21
+ settings_cls: type[BaseSettings],
22
+ init_settings: PydanticBaseSettingsSource,
23
+ env_settings: PydanticBaseSettingsSource,
24
+ dotenv_settings: PydanticBaseSettingsSource,
25
+ file_secret_settings: PydanticBaseSettingsSource,
26
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
27
+ """
28
+
29
+ Define priority and additional sources. Note: the earlier items have higher priority.
30
+
31
+ """
32
+
33
+ sources = (
34
+ init_settings,
35
+ CliSettingsSource(settings_cls, cli_parse_args=True),
36
+ EnvSettingsSource(settings_cls, env_prefix=cls.get_env_prefix()),
37
+ YamlConfigSettingsSource(settings_cls, yaml_file=cls.paths.settings),
38
+ )
39
+
40
+ return sources
41
+
42
+ @classmethod
43
+ def get_env_prefix(cls):
44
+ """
45
+
46
+ Get environment variable prefix, which depends on whether the package is a namespace/singleton.
47
+
48
+ """
49
+ if cls.paths.is_namespace:
50
+ stem = f'{cls.paths.org}_{cls.paths.name}'
51
+ else:
52
+ stem = f'{cls.paths.name}'
53
+
54
+ prefix = f'{stem}_'.upper()
55
+ return prefix
56
+
57
+ @property
58
+ def version(self):
59
+ """
60
+
61
+ Read in version file.
62
+
63
+ """
64
+ from fmtr.tools import version
65
+ return version.read_path(self.paths.version)
@@ -8,11 +8,10 @@ from tokenizers.trainers import BpeTrainer
8
8
  from tokenizers.trainers import WordLevelTrainer
9
9
  from typing import List
10
10
 
11
- from fmtr.tools.config_tools import ConfigClass
12
11
  from fmtr.tools.path_tools import Path
13
12
 
14
13
 
15
- class TokenConfig(ConfigClass):
14
+ class TokenConfig:
16
15
  """
17
16
 
18
17
  Default config for special characters etc.
fmtr/tools/tools.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from fmtr.tools.config import ToolsConfig
3
+ from fmtr.tools.constants import Constants
4
4
 
5
5
 
6
6
  class MissingExtraError(ImportError):
@@ -13,7 +13,7 @@ class MissingExtraError(ImportError):
13
13
  MASK = 'The current module is missing dependencies. To install them, run: `pip install {library}[{extra}] --upgrade`'
14
14
 
15
15
  def __init__(self, extra):
16
- self.message = self.MASK.format(library=ToolsConfig.LIBRARY_NAME, extra=extra)
16
+ self.message = self.MASK.format(library=Constants.LIBRARY_NAME, extra=extra)
17
17
 
18
18
  super().__init__(self.message)
19
19
 
fmtr/tools/version CHANGED
@@ -1 +1 @@
1
- 1.0.55
1
+ 1.1.0
@@ -7,6 +7,8 @@ try:
7
7
  semver = semver
8
8
  parse = semver.VersionInfo.parse
9
9
  except ImportError as exception:
10
+ # Special case to allow module import.
11
+ # Should be slit out into separate version.dev subpackage
10
12
  parse = MissingExtraMockModule('version', exception)
11
13
  semver = MissingExtraMockModule('version', exception)
12
14
 
@@ -18,20 +20,27 @@ def read() -> str:
18
20
 
19
21
  """
20
22
 
21
- from fmtr.tools.tools import ToolsConfig
22
-
23
23
  path = get_call_path(offset=2).parent / 'version'
24
- text = path.read_text(encoding=ToolsConfig.ENCODING).strip()
24
+ return read_path(path)
25
25
 
26
- text = get(text)
27
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)
28
37
  return text
29
38
 
30
39
 
31
40
  def get(text) -> str:
32
41
  """
33
42
 
34
- Optionally add dev build info.
43
+ Optionally add dev build info to raw version string.
35
44
 
36
45
  """
37
46
  import os
@@ -41,9 +50,9 @@ def get(text) -> str:
41
50
 
42
51
  if is_dev:
43
52
  import datetime
44
- from fmtr.tools.tools import ToolsConfig
53
+ from fmtr.tools.tools import Constants
45
54
 
46
- timestamp = datetime.datetime.now(datetime.timezone.utc).strftime(ToolsConfig.DATETIME_SEMVER_BUILD_FORMAT)
55
+ timestamp = datetime.datetime.now(datetime.timezone.utc).strftime(Constants.DATETIME_SEMVER_BUILD_FORMAT)
47
56
 
48
57
  version = parse(text)
49
58
  version = version.bump_patch()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.0.55
3
+ Version: 1.1.0
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
@@ -9,49 +9,50 @@ License: Copyright © 2025 Frontmatter. All rights reserved.
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
11
  Provides-Extra: test
12
- Requires-Dist: distributed; extra == "test"
13
- Requires-Dist: ollama; extra == "test"
12
+ Requires-Dist: flet-webview; extra == "test"
13
+ Requires-Dist: uvicorn; extra == "test"
14
+ Requires-Dist: pymupdf4llm; extra == "test"
15
+ Requires-Dist: pyyaml; extra == "test"
14
16
  Requires-Dist: pytest-cov; extra == "test"
17
+ Requires-Dist: logfire; extra == "test"
15
18
  Requires-Dist: google-auth-httplib2; extra == "test"
16
- Requires-Dist: semver; extra == "test"
17
- Requires-Dist: pyyaml; extra == "test"
18
19
  Requires-Dist: tinynetrc; extra == "test"
19
- Requires-Dist: dask[bag]; extra == "test"
20
- Requires-Dist: peft; extra == "test"
21
- Requires-Dist: openpyxl; extra == "test"
22
- Requires-Dist: google-auth-oauthlib; extra == "test"
23
- Requires-Dist: huggingface_hub; extra == "test"
20
+ Requires-Dist: sre_yield; extra == "test"
24
21
  Requires-Dist: bokeh; extra == "test"
25
- Requires-Dist: Unidecode; extra == "test"
22
+ Requires-Dist: html2text; extra == "test"
23
+ Requires-Dist: sentence_transformers; extra == "test"
26
24
  Requires-Dist: docker; extra == "test"
27
- Requires-Dist: deepmerge; extra == "test"
28
- Requires-Dist: json_repair; extra == "test"
25
+ Requires-Dist: peft; extra == "test"
26
+ Requires-Dist: google-auth; extra == "test"
29
27
  Requires-Dist: fastapi; extra == "test"
30
- Requires-Dist: transformers[sentencepiece]; extra == "test"
31
- Requires-Dist: pydevd-pycharm; extra == "test"
32
- Requires-Dist: tokenizers; extra == "test"
33
- Requires-Dist: diskcache; extra == "test"
34
- Requires-Dist: logfire; extra == "test"
35
- Requires-Dist: contexttimer; extra == "test"
36
- Requires-Dist: flet-video; extra == "test"
28
+ Requires-Dist: pydantic; extra == "test"
29
+ Requires-Dist: pydantic-settings; extra == "test"
30
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "test"
37
31
  Requires-Dist: torchvision; extra == "test"
38
32
  Requires-Dist: google-api-python-client; extra == "test"
39
- Requires-Dist: google-auth; extra == "test"
40
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "test"
41
- Requires-Dist: flet[all]; extra == "test"
42
- Requires-Dist: uvicorn; extra == "test"
43
- Requires-Dist: pydantic; extra == "test"
33
+ Requires-Dist: distributed; extra == "test"
34
+ Requires-Dist: openpyxl; extra == "test"
35
+ Requires-Dist: contexttimer; extra == "test"
36
+ Requires-Dist: huggingface_hub; extra == "test"
37
+ Requires-Dist: dask[bag]; extra == "test"
44
38
  Requires-Dist: tabulate; extra == "test"
45
- Requires-Dist: pymupdf4llm; extra == "test"
46
- Requires-Dist: openai; extra == "test"
39
+ Requires-Dist: tokenizers; extra == "test"
40
+ Requires-Dist: ollama; extra == "test"
47
41
  Requires-Dist: pandas; extra == "test"
42
+ Requires-Dist: flet-video; extra == "test"
43
+ Requires-Dist: flet[all]; extra == "test"
44
+ Requires-Dist: transformers[sentencepiece]; extra == "test"
45
+ Requires-Dist: semver; extra == "test"
46
+ Requires-Dist: openai; extra == "test"
47
+ Requires-Dist: google-auth-oauthlib; extra == "test"
48
+ Requires-Dist: pydevd-pycharm; extra == "test"
48
49
  Requires-Dist: faker; extra == "test"
49
50
  Requires-Dist: pymupdf; extra == "test"
50
- Requires-Dist: sre_yield; extra == "test"
51
- Requires-Dist: flet-webview; extra == "test"
52
- Requires-Dist: sentence_transformers; extra == "test"
51
+ Requires-Dist: deepmerge; extra == "test"
52
+ Requires-Dist: diskcache; extra == "test"
53
+ Requires-Dist: json_repair; extra == "test"
54
+ Requires-Dist: Unidecode; extra == "test"
53
55
  Requires-Dist: torchaudio; extra == "test"
54
- Requires-Dist: html2text; extra == "test"
55
56
  Provides-Extra: yaml
56
57
  Requires-Dist: pyyaml; extra == "yaml"
57
58
  Provides-Extra: logging
@@ -143,6 +144,9 @@ Requires-Dist: pydantic; extra == "pdf"
143
144
  Requires-Dist: pymupdf4llm; extra == "pdf"
144
145
  Provides-Extra: debug
145
146
  Requires-Dist: pydevd-pycharm; extra == "debug"
147
+ Provides-Extra: sets
148
+ Requires-Dist: pydantic-settings; extra == "sets"
149
+ Requires-Dist: pydantic; extra == "sets"
146
150
  Dynamic: author
147
151
  Dynamic: author-email
148
152
  Dynamic: description
@@ -239,6 +243,10 @@ The included modules, plus any extra requirements, are as follows:
239
243
  - Extras: `ai`
240
244
  - `tools.config`: Base config class with overridable field processors.
241
245
  - Extras: None
246
+ -
247
+ `tools.settings`: A base configuration system built on Pydantic Settings that provides a flexible way to manage application settings from multiple sources, based on a standard
248
+ `path.PackagePaths` project layout.
249
+ - Extras: `sets`
242
250
  - `tools.dataclass`: Utilities for extracting and filtering fields and metadata from dataclasses, with support for applying filters and retrieving enabled fields based on metadata attributes.
243
251
  - Extras: None
244
252
  - `tools.datatype`
@@ -269,8 +277,12 @@ The included modules, plus any extra requirements, are as follows:
269
277
  - Extras: None
270
278
  - `tools.openai`: Utilities for interacting with the OpenAI API, simple text-to-text output, etc.
271
279
  - Extras: `openai.api`
272
- - `tools.Path`: Enhanced `pathlib.Path` object with additional functionality for Windows-to-Unix path conversion, reading/writing JSON and YAML files, and convenient directory creation with parent directories. Includes methods for obtaining paths to modules and temporary directories.
280
+ - `tools.Path`: Enhanced
281
+ `pathlib.Path` object with additional functionality for Windows-to-Unix path conversion in WSL environments, reading/writing JSON and YAML files with proper encoding.
273
282
  - Extras: None
283
+ -
284
+ `tools.PackagePaths` class for managing canonical package paths, like settings files, artifact directories, version files.
285
+ - Extras: None
274
286
  - `tools.platform`: Detecting if host is WSL, Docker etc.
275
287
  - Extras: None
276
288
  - `tools.ContextProcess`: Manages a function running in a separate process using a context manager. Provides methods to start, stop, and restart the process, with configurable restart delays. Useful for ensuring clean process management and automatic stopping when the context manager exits.
@@ -1,20 +1,19 @@
1
- fmtr/tools/__init__.py,sha256=6GqFnXOeHOltN96f5UnBHvBoHubPj1CG3Pm7NgugMls,5482
1
+ fmtr/tools/__init__.py,sha256=plBJilu1BB5h3zAqbk572I7ko10jWc7eKZpHQwWjUtY,5627
2
2
  fmtr/tools/api_tools.py,sha256=u5YEdKyKto8MKY8legULLU7xeJ7lY2Bgyaep_xa8iZg,2089
3
3
  fmtr/tools/async_tools.py,sha256=ewz757WcveQJd-G5SVr2JDOQVbdLGecCgl-tsBGVZz4,284
4
4
  fmtr/tools/augmentation_tools.py,sha256=-6ESbO4CDlKqVOV1J1V6qBeoBMzbFIinkDHRHnCBej0,55
5
5
  fmtr/tools/caching_tools.py,sha256=UOCYUNvLQ-NofR_dhqBmZF96-HRPf4At5MmxVk3gAIk,2943
6
- fmtr/tools/config.py,sha256=3jHO3KhRlzJUCdQmJ_j1DFzep00MSD5qTJHfK6i3FZA,1057
7
- fmtr/tools/config_tools.py,sha256=27PbPYj90ClIW4QcRoUoiFM3SbWeMIIZsZR32IPU4V8,805
8
6
  fmtr/tools/console_script_tools.py,sha256=Jcmm4WPhCQdPZfd468xD0epkt29sgcPROwKu79V_ehg,203
7
+ fmtr/tools/constants.py,sha256=aKFFW9iYdUtiuLV0gS5XAZsLmk8DwvydYebc5yJN8NE,993
9
8
  fmtr/tools/data_modelling_tools.py,sha256=0BFm-F_cYzVTxftWQwORkPd0FM2BTLVh9-s0-rTTFoo,1744
10
9
  fmtr/tools/dataclass_tools.py,sha256=0Gt6KeLhtPgubo_2tYkIVqB8oQ91Qzag8OAGZDdjvMU,1209
11
10
  fmtr/tools/datatype_tools.py,sha256=3P4AWIFGkJ-UqvXlj0Jc9IvkIIgTOE9jRrOk3NVbpH8,1508
12
- fmtr/tools/debugging_tools.py,sha256=SUub3Ycp9k5TVx7CI_bah6fgdPr03VrpAvaCUc8eICs,959
11
+ fmtr/tools/debugging_tools.py,sha256=7uWdAAdvnB8bo0gTVwAYGCH1yv_ocFeP_tLk6xhiaPk,950
13
12
  fmtr/tools/docker_tools.py,sha256=rdaZje2xhlmnfQqZnR7IHgRdWncTLjrJcViUTt5oEwk,617
14
- fmtr/tools/environment_tools.py,sha256=34NKG-BJrobYyJeM3FH3VE6G1rv6kQ41bvTxkEYfNi8,1850
13
+ fmtr/tools/environment_tools.py,sha256=ZO2e8pTzbQ8jNXnmKpaZF7_3qkVM6U5iqku5YSwOszE,1849
15
14
  fmtr/tools/function_tools.py,sha256=_oW3-HZXMst2pcU-I-U7KTMmzo0g9MIQKmX-c2_NEoE,858
16
15
  fmtr/tools/google_api_tools.py,sha256=owWE0GlnJjmVbXus8ENxT2PH7Fnd3m_r-14xyR7lAnA,1107
17
- fmtr/tools/hash_tools.py,sha256=WEU2IkVzyEoBfFcHcrK-izy4NeCjC-_rOPKi9kO5ECk,730
16
+ fmtr/tools/hash_tools.py,sha256=tr4HXpeT6rRrDk6TvMlRPUSrLRRaov96y128OI2tzsc,729
18
17
  fmtr/tools/hfh_tools.py,sha256=DCDIWuWlhtmIGCtp9cLcOTTEw_4yN_NocLX8w5NZsbk,2384
19
18
  fmtr/tools/html_tools.py,sha256=0nN8Nz5HtG9bXyApYfHSKEivLlxjsm3Gn6Mg2TK0brI,394
20
19
  fmtr/tools/import_tools.py,sha256=XJmiWLukRncJAcaGReDn4jIz1_IpVBjfYCQHH1hIg7c,588
@@ -22,32 +21,33 @@ fmtr/tools/inspection_tools.py,sha256=tLTRvzy9XVomQPi0dfnF_cgwc7KiDVZAr7gPTk4S_b
22
21
  fmtr/tools/interface_tools.py,sha256=JVYUV7wuMr24BORuUtNaBlTeBFt8VDGJ3HPRajd7Y_4,1341
23
22
  fmtr/tools/iterator_tools.py,sha256=xj5f0c7LgLK53dddRRRJxBoLaBzlZoQS3_GfmpDPMoo,1311
24
23
  fmtr/tools/json_fix_tools.py,sha256=vNSlswVQnujPmKEqDjFJcO901mjMyv59q3awsT7mlhs,477
25
- fmtr/tools/json_tools.py,sha256=IKmrANhcftIz2msCZeItidJ1PcpY_tnbfxbRDnta-c0,349
26
- fmtr/tools/logging_tools.py,sha256=dqD0F6D0gx1zVR7t8TeHfitB6U4asPhfUMjwhKcuXc4,1882
24
+ fmtr/tools/json_tools.py,sha256=WkFc5q7oqMtcFejhN1K5zQFULa9TdLOup83Fr0saDRY,348
25
+ fmtr/tools/logging_tools.py,sha256=EnpiUJh0tOgbR-45aI_EtZsqNW8XFfGwp1_1ULOcZ00,1875
27
26
  fmtr/tools/merging_tools.py,sha256=KDxCEFJEQJEwGw1qGKAgR55uUE2X2S5NWLKcfHRmX_k,227
28
27
  fmtr/tools/metric_tools.py,sha256=Lvia5CGFRIfrDFA8s37btIfTU5zHbo04cPJdAMtbndQ,272
29
28
  fmtr/tools/name_tools.py,sha256=5CB_phqhHjl66iI8oLxOGPF2odC1apdul-M8Fv2xBhs,5514
30
29
  fmtr/tools/netrc_tools.py,sha256=PpNpz_mWlQi6VHGromKwFfTyLpHUXsd4LY6-OKLCbeI,376
31
30
  fmtr/tools/openai_tools.py,sha256=6SUgejgzUzmlKKct2_ePXntvMegu3FJgfk9x7aqtqYc,742
32
- fmtr/tools/parallel_tools.py,sha256=G__ZbLRRx4cP5OyqY1hKwnE-VI3m5prYABB0tnZHnes,3132
33
- fmtr/tools/path_tools.py,sha256=1GeWXdhV5rH99IfLI5ZFEnOJfs4Q4mYTT2R-rA791iQ,4273
31
+ fmtr/tools/parallel_tools.py,sha256=QEb_gN1StkxsqYaH4HSjiJX8Y3gpb2uKNsOzG4uFpaM,3071
32
+ fmtr/tools/path_tools.py,sha256=U8D-NCOSmJuV5fD_OvLoYQQ0Ii_o8zc3_xccePpKkPo,5940
34
33
  fmtr/tools/pdf_tools.py,sha256=xvv9B84uAF81rFJRnXhSsxYuP42vY9ZdPVFrSMVe8G8,4069
35
34
  fmtr/tools/platform_tools.py,sha256=7p69CmAHe_sF68Fx9uVhns1k5EewTHTWgUYzkl6ZQKA,308
36
35
  fmtr/tools/process_tools.py,sha256=Ysh5Dk2QFBhXQerArjKdt7xZd3JrN5Ho02AaOjH0Nnw,1425
37
36
  fmtr/tools/profiling_tools.py,sha256=jpXVjaNKPydTasEQVNXvxzGtMhXPit08AnJddkU8uIc,46
38
37
  fmtr/tools/random_tools.py,sha256=4VlQdk5THbR8ka4pZaLbk_ZO_4yy6PF_lHZes_rgenY,2223
39
38
  fmtr/tools/semantic_tools.py,sha256=cxY9NSAHWj4nEc6Oj4qA1omR3dWbl2OuH7_PkINc6_E,1386
39
+ fmtr/tools/settings_tools.py,sha256=wqLqZ64j3l2WA-yL5Xyl55XKblp1SbxQbB44Z7kF5QU,1952
40
40
  fmtr/tools/spaces_tools.py,sha256=D_he3mve6DruB3OPS6QyzqD05ChHnRTb4buViKPe7To,1099
41
41
  fmtr/tools/string_tools.py,sha256=Q2vv7kuGVMaQlNSUxJYhex6WUQHDus40ht0PGImPjNQ,3879
42
42
  fmtr/tools/tabular_tools.py,sha256=tpIpZzYku1HcJrHZJL6BC39LmN3WUWVhFbK2N7nDVmE,120
43
- fmtr/tools/tokenization_tools.py,sha256=9FP5vgPufWv0XA961eVKObFll0d_2mM0W3ut3rtZyeo,4329
44
- fmtr/tools/tools.py,sha256=xnfUrOnrT4OxFYez6vV5tAhydzCICJFiGVnviiZDEQo,796
43
+ fmtr/tools/tokenization_tools.py,sha256=me-IBzSLyNYejLybwjO9CNB6Mj2NYfKPaOVThXyaGNg,4268
44
+ fmtr/tools/tools.py,sha256=CAsApa1YwVdNE6H66Vjivs_mXYvOas3rh7fPELAnTpk,795
45
45
  fmtr/tools/unicode_tools.py,sha256=yS_9wpu8ogNoiIL7s1G_8bETFFO_YQlo4LNPv1NLDeY,52
46
- fmtr/tools/version,sha256=PSXMF35J29qA7yxbAYVCFS2KwVCgo1LjZ-WN0QfBZFY,6
47
- fmtr/tools/version_tools.py,sha256=axzzHBS9V1n6YuSacsDKG3VfAvRqR8qr6aENCibR8vs,1248
46
+ fmtr/tools/version,sha256=f70hDr7BH2WpcZDvkAeVxLjaOAWvP1objR0nJVaykso,5
47
+ fmtr/tools/version_tools.py,sha256=yNs_CGqWpqE4jbK9wsPIi14peJVXYbhIcMqHAFOw3yE,1480
48
48
  fmtr/tools/yaml_tools.py,sha256=Ol43ZwbnSXGnn1K98Uxx61KPGSqfC4axE-X2q1LKMwk,349
49
49
  fmtr/tools/ai_tools/__init__.py,sha256=JZrLuOFNV1A3wvJgonxOgz_4WS-7MfCuowGWA5uYCjs,372
50
- fmtr/tools/ai_tools/agentic_tools.py,sha256=Y4MhkGqQ9wL1gFXAsaaO8BIYS1mncVcUPsH-iZ0-UY8,2760
50
+ fmtr/tools/ai_tools/agentic_tools.py,sha256=odGzy-VA7hrNJ10VKRb5KIHReBGKZCTkp81V0cDCz6E,2755
51
51
  fmtr/tools/ai_tools/inference_tools.py,sha256=yF8Oxph0L8W2CnK_o-MVztBhWVwBpgOEkx9_m3uqQww,11840
52
52
  fmtr/tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  fmtr/tools/tests/conftest.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -57,9 +57,9 @@ fmtr/tools/tests/test_environment.py,sha256=iHaiMQfECYZPkPKwfuIZV9uHuWe3aE-p_dN_
57
57
  fmtr/tools/tests/test_json.py,sha256=IeSP4ziPvRcmS8kq7k9tHonC9rN5YYq9GSNT2ul6Msk,287
58
58
  fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g,2188
59
59
  fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
60
- fmtr_tools-1.0.55.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
61
- fmtr_tools-1.0.55.dist-info/METADATA,sha256=7JEET3FilYkEqJsZePMIDXim5sbdAzwrfsyHzC3aVpw,14065
62
- fmtr_tools-1.0.55.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
63
- fmtr_tools-1.0.55.dist-info/entry_points.txt,sha256=Zmeyls-zo5S99SlKUmsy9ULUNmk-4B9WQCEjuPIH0Yw,142
64
- fmtr_tools-1.0.55.dist-info/top_level.txt,sha256=t5341a8ii3n4RFizwTeXGmcq_pf4GqL1h9ylE5LIWRk,12
65
- fmtr_tools-1.0.55.dist-info/RECORD,,
60
+ fmtr_tools-1.1.0.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
61
+ fmtr_tools-1.1.0.dist-info/METADATA,sha256=xf-4jS0MbUVkScNzCNAo9fzcDsdMRpY4QtNJJ5q3uqM,14510
62
+ fmtr_tools-1.1.0.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
63
+ fmtr_tools-1.1.0.dist-info/entry_points.txt,sha256=Zmeyls-zo5S99SlKUmsy9ULUNmk-4B9WQCEjuPIH0Yw,142
64
+ fmtr_tools-1.1.0.dist-info/top_level.txt,sha256=t5341a8ii3n4RFizwTeXGmcq_pf4GqL1h9ylE5LIWRk,12
65
+ fmtr_tools-1.1.0.dist-info/RECORD,,
@@ -1,54 +0,0 @@
1
- """
2
-
3
- Config tools for downstream projects
4
-
5
- """
6
- from dataclasses import dataclass, fields, Field as DataclassField
7
-
8
- from typing import List, Type
9
-
10
-
11
- class ConfigClass:
12
- """
13
-
14
- Base class for all config classes.
15
-
16
- """
17
-
18
- @classmethod
19
- def process_field(cls, field):
20
- """
21
-
22
- Post-process field
23
-
24
- """
25
-
26
- @classmethod
27
- def process_fields(cls):
28
- """
29
-
30
- Post-process fields
31
-
32
- """
33
- for field in cls.get_fields():
34
- cls.process_field(field)
35
-
36
- @classmethod
37
- def get_fields(cls) -> List[DataclassField]:
38
- """
39
-
40
- Return fields
41
-
42
- """
43
- return fields(cls)
44
-
45
- def __init_subclass__(cls, **kwargs):
46
- """
47
-
48
- Decorate subclasses as dataclasses
49
-
50
- """
51
- return dataclass(cls)
52
-
53
-
54
- Field = Type