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

@@ -1,3 +1,4 @@
1
+ import inspect
1
2
  from functools import cached_property
2
3
  from typing import ClassVar, List, Any, Dict
3
4
 
@@ -9,7 +10,7 @@ from pydantic_core import PydanticUndefined, PydanticUndefinedType
9
10
  from fmtr.tools.datatype_tools import is_optional
10
11
  from fmtr.tools.iterator_tools import get_class_lookup
11
12
  from fmtr.tools.string_tools import camel_to_snake
12
- from fmtr.tools.tools import Auto, Required
13
+ from fmtr.tools.tools import Auto, Required, Empty
13
14
 
14
15
 
15
16
  class Field(FieldInfo):
@@ -19,27 +20,35 @@ class Field(FieldInfo):
19
20
 
20
21
  """
21
22
  NAME = Auto
22
- ANNOTATION = None
23
+ ANNOTATION = Empty
23
24
  DEFAULT = Auto
24
25
  FILLS = None
25
26
  DESCRIPTION = None
26
27
  TITLE = Auto
27
28
  CONFIG = None
28
29
 
29
- def __init__(self):
30
+ def __init__(self, annotation=Empty, default=Empty, description=None, title=None, fills=None, **kwargs):
30
31
  """
31
32
 
32
33
  Infer default from type annotation, if enabled, use class/argument fills to create titles/descriptions, etc.
33
34
 
34
35
  """
35
- title = self.get_title_auto()
36
- description = self.get_desc()
37
- default = self.get_default_auto()
38
- kwargs = self.CONFIG or {}
39
36
 
37
+ fills_super = getattr(super(), 'FILLS', None)
38
+ self.fills = (fills_super or {}) | (self.FILLS or {}) | (fills or {})
39
+
40
+ self.annotation = self.ANNOTATION if annotation is Empty else annotation
41
+ if self.annotation is Empty:
42
+ raise ValueError("Annotation must be specified.")
43
+
44
+ default = self.get_default_auto(default)
40
45
  if default is Required:
41
46
  default = PydanticUndefined
42
47
 
48
+ description = self.get_desc(description)
49
+ title = self.get_title_auto(title)
50
+ kwargs |= (self.CONFIG or {})
51
+
43
52
  super().__init__(default=default, title=title, description=description, **kwargs)
44
53
 
45
54
  @classmethod
@@ -63,46 +72,55 @@ class Field(FieldInfo):
63
72
  Get fills with filled title merged in
64
73
 
65
74
  """
66
- return (self.FILLS or {}) | dict(title=self.get_title_auto())
67
75
 
68
- def get_default_auto(self) -> type[Any] | None | PydanticUndefinedType:
76
+ fills_super = getattr(super(), 'FILLS', None)
77
+
78
+ return (fills_super or {}) | (self.FILLS or {}) | dict(title=self.get_title_auto())
79
+
80
+ def get_default_auto(self, default) -> type[Any] | None | PydanticUndefinedType:
69
81
  """
70
82
 
71
83
  Infer default, if not specified.
72
84
 
73
85
  """
86
+
87
+ if default is not Empty:
88
+ return default
89
+
74
90
  if self.DEFAULT is not Auto:
75
91
  return self.DEFAULT
76
92
 
77
- if is_optional(self.ANNOTATION):
93
+ if is_optional(self.annotation):
78
94
  return None
79
95
  else:
80
96
  return Required
81
97
 
82
- def get_title_auto(self) -> str | None:
98
+ def get_title_auto(self, mask) -> str | None:
83
99
  """
84
100
 
85
101
  Get title from classname/mask
86
102
 
87
103
  """
88
104
 
89
- mask = self.__class__.__name__ if self.TITLE is Auto else self.TITLE
90
- fills = (self.FILLS or {})
105
+ if not mask:
106
+ mask = self.__class__.__name__ if self.TITLE is Auto else self.TITLE
91
107
 
92
108
  if mask:
93
- return mask.format(**fills)
109
+ return mask.format(**self.fills)
94
110
 
95
111
  return None
96
112
 
97
- def get_desc(self) -> str | None:
113
+ def get_desc(self, mask) -> str | None:
98
114
  """
99
115
 
100
- Get description from classname/mask
116
+ Fill description mask, if specified
101
117
 
102
118
  """
103
119
 
104
- if self.DESCRIPTION:
105
- return self.DESCRIPTION.format(**self.fills)
120
+ mask = mask or self.DESCRIPTION
121
+
122
+ if mask:
123
+ return mask.format(**self.fills)
106
124
 
107
125
  return None
108
126
 
@@ -189,14 +207,16 @@ class Base(BaseModel, MixinFromJson):
189
207
 
190
208
  cls.FIELDS = fields
191
209
 
192
- for name, FieldInfoType in fields.items():
210
+ for name, field in fields.items():
193
211
  if name in cls.__annotations__:
194
212
  continue
195
213
 
196
- field = FieldInfoType()
214
+ if inspect.isclass(field):
215
+ field = field()
216
+
197
217
  setattr(cls, name, field)
198
218
 
199
- annotation = FieldInfoType.ANNOTATION
219
+ annotation = field.annotation
200
220
  cls.__annotations__[name] = annotation
201
221
 
202
222
  def to_df(self, name_value='value'):
@@ -2,13 +2,23 @@ from functools import cached_property
2
2
  from typing import List
3
3
 
4
4
  import beanie
5
+ from beanie.odm import actions
5
6
  from motor.motor_asyncio import AsyncIOMotorClient
6
7
 
8
+ from fmtr.tools import data_modelling_tools
7
9
  from fmtr.tools.constants import Constants
8
10
  from fmtr.tools.logging_tools import logger
9
11
 
12
+ ModifyEvents = [
13
+ actions.Insert,
14
+ actions.Replace,
15
+ actions.Save,
16
+ actions.SaveChanges,
17
+ actions.Update
18
+ ]
10
19
 
11
- class Document(beanie.Document):
20
+
21
+ class Document(beanie.Document, data_modelling_tools.Base):
12
22
  """
13
23
 
14
24
  Document stub.
@@ -93,6 +93,9 @@ def is_optional(annotation) -> bool:
93
93
  Is type/annotation optional? todo should be in typing_tools?
94
94
 
95
95
  """
96
+ if annotation is None:
97
+ return True
98
+
96
99
  origin = get_origin(annotation)
97
100
  args = get_args(annotation)
98
101
  is_opt = origin is UnionType and NoneType in args
fmtr/tools/version CHANGED
@@ -1 +1 @@
1
- 1.3.65
1
+ 1.3.67
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.65
3
+ Version: 1.3.67
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
@@ -168,68 +168,68 @@ Provides-Extra: db-document
168
168
  Requires-Dist: beanie[odm]; extra == "db-document"
169
169
  Requires-Dist: motor; extra == "db-document"
170
170
  Provides-Extra: all
171
+ Requires-Dist: tabulate; extra == "all"
171
172
  Requires-Dist: pydantic; extra == "all"
172
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
173
- Requires-Dist: uvicorn[standard]; extra == "all"
174
- Requires-Dist: google-auth; extra == "all"
175
- Requires-Dist: pymupdf4llm; extra == "all"
176
- Requires-Dist: contexttimer; extra == "all"
177
- Requires-Dist: google-auth-oauthlib; extra == "all"
173
+ Requires-Dist: sentence_transformers; extra == "all"
174
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
175
+ Requires-Dist: openpyxl; extra == "all"
176
+ Requires-Dist: google-api-python-client; extra == "all"
177
+ Requires-Dist: bokeh; extra == "all"
178
+ Requires-Dist: cachetools; extra == "all"
179
+ Requires-Dist: fastapi; extra == "all"
178
180
  Requires-Dist: python-on-whales; extra == "all"
181
+ Requires-Dist: flet-video; extra == "all"
182
+ Requires-Dist: google-auth-oauthlib; extra == "all"
183
+ Requires-Dist: pydantic-settings; extra == "all"
184
+ Requires-Dist: dask[bag]; extra == "all"
185
+ Requires-Dist: openai; extra == "all"
179
186
  Requires-Dist: httpx_retries; extra == "all"
187
+ Requires-Dist: playwright; extra == "all"
188
+ Requires-Dist: ollama; extra == "all"
189
+ Requires-Dist: google-auth; extra == "all"
180
190
  Requires-Dist: distributed; extra == "all"
191
+ Requires-Dist: sre_yield; extra == "all"
192
+ Requires-Dist: huggingface_hub; extra == "all"
193
+ Requires-Dist: yamlscript; extra == "all"
194
+ Requires-Dist: deepmerge; extra == "all"
195
+ Requires-Dist: logfire; extra == "all"
196
+ Requires-Dist: torchaudio; extra == "all"
197
+ Requires-Dist: faker; extra == "all"
198
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
181
199
  Requires-Dist: beanie[odm]; extra == "all"
200
+ Requires-Dist: logfire[httpx]; extra == "all"
201
+ Requires-Dist: regex; extra == "all"
202
+ Requires-Dist: odfpy; extra == "all"
182
203
  Requires-Dist: diskcache; extra == "all"
183
- Requires-Dist: transformers[sentencepiece]; extra == "all"
204
+ Requires-Dist: pyyaml; extra == "all"
205
+ Requires-Dist: json_repair; extra == "all"
184
206
  Requires-Dist: appdirs; extra == "all"
185
- Requires-Dist: torchaudio; extra == "all"
207
+ Requires-Dist: httpx; extra == "all"
208
+ Requires-Dist: setuptools; extra == "all"
209
+ Requires-Dist: peft; extra == "all"
210
+ Requires-Dist: Unidecode; extra == "all"
186
211
  Requires-Dist: filetype; extra == "all"
187
- Requires-Dist: flet-webview; extra == "all"
188
- Requires-Dist: motor; extra == "all"
189
- Requires-Dist: openai; extra == "all"
190
- Requires-Dist: ollama; extra == "all"
212
+ Requires-Dist: contexttimer; extra == "all"
191
213
  Requires-Dist: pytest-cov; extra == "all"
192
- Requires-Dist: pydantic-settings; extra == "all"
193
- Requires-Dist: Unidecode; extra == "all"
194
- Requires-Dist: huggingface_hub; extra == "all"
195
- Requires-Dist: bokeh; extra == "all"
196
- Requires-Dist: logfire; extra == "all"
197
- Requires-Dist: semver; extra == "all"
198
- Requires-Dist: logfire[fastapi]; extra == "all"
199
- Requires-Dist: tinynetrc; extra == "all"
200
- Requires-Dist: torchvision; extra == "all"
201
- Requires-Dist: pymupdf; extra == "all"
202
- Requires-Dist: peft; extra == "all"
203
- Requires-Dist: yamlscript; extra == "all"
204
- Requires-Dist: logfire[httpx]; extra == "all"
205
214
  Requires-Dist: pycountry; extra == "all"
206
- Requires-Dist: setuptools; extra == "all"
207
- Requires-Dist: playwright; extra == "all"
208
- Requires-Dist: sentence_transformers; extra == "all"
209
- Requires-Dist: faker; extra == "all"
210
- Requires-Dist: deepmerge; extra == "all"
211
- Requires-Dist: httpx; extra == "all"
212
- Requires-Dist: tabulate; extra == "all"
213
- Requires-Dist: openpyxl; extra == "all"
214
- Requires-Dist: deepdiff; extra == "all"
215
+ Requires-Dist: uvicorn[standard]; extra == "all"
216
+ Requires-Dist: pandas; extra == "all"
217
+ Requires-Dist: pymupdf; extra == "all"
218
+ Requires-Dist: tokenizers; extra == "all"
219
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
220
+ Requires-Dist: semver; extra == "all"
215
221
  Requires-Dist: flet[all]; extra == "all"
216
- Requires-Dist: sre_yield; extra == "all"
222
+ Requires-Dist: logfire[fastapi]; extra == "all"
223
+ Requires-Dist: dnspython[doh]; extra == "all"
217
224
  Requires-Dist: pydantic-extra-types; extra == "all"
218
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
219
- Requires-Dist: json_repair; extra == "all"
220
- Requires-Dist: tokenizers; extra == "all"
221
- Requires-Dist: pandas; extra == "all"
222
- Requires-Dist: fastapi; extra == "all"
223
225
  Requires-Dist: html2text; extra == "all"
224
- Requires-Dist: flet-video; extra == "all"
225
- Requires-Dist: pyyaml; extra == "all"
226
- Requires-Dist: google-api-python-client; extra == "all"
227
- Requires-Dist: dask[bag]; extra == "all"
226
+ Requires-Dist: flet-webview; extra == "all"
227
+ Requires-Dist: tinynetrc; extra == "all"
228
+ Requires-Dist: deepdiff; extra == "all"
228
229
  Requires-Dist: google-auth-httplib2; extra == "all"
229
- Requires-Dist: cachetools; extra == "all"
230
- Requires-Dist: dnspython[doh]; extra == "all"
231
- Requires-Dist: regex; extra == "all"
232
- Requires-Dist: odfpy; extra == "all"
230
+ Requires-Dist: torchvision; extra == "all"
231
+ Requires-Dist: pymupdf4llm; extra == "all"
232
+ Requires-Dist: motor; extra == "all"
233
233
  Dynamic: author
234
234
  Dynamic: author-email
235
235
  Dynamic: description
@@ -5,9 +5,9 @@ fmtr/tools/augmentation_tools.py,sha256=-6ESbO4CDlKqVOV1J1V6qBeoBMzbFIinkDHRHnCB
5
5
  fmtr/tools/caching_tools.py,sha256=74p7m2GLFfeP41LX69wxgfkilxEAoWkMIfFMjKsYpyg,4976
6
6
  fmtr/tools/constants.py,sha256=90wCirUpw4bWMAbjhip0LL6k57eS5VmxRUP9pLCChBg,1812
7
7
  fmtr/tools/context_tools.py,sha256=4UvIHYgLqAh7dXMX9EBrLEpYp81qfzhSVrkffOSAoGA,350
8
- fmtr/tools/data_modelling_tools.py,sha256=vD7nbqeQh_azoNZUiVWvK8GuyNE-Qagcqg_RE7wYNBk,5303
8
+ fmtr/tools/data_modelling_tools.py,sha256=XLteLdfihxey8_nDbLsOWlycSj4r5DRVpgH6VdaZwRs,5945
9
9
  fmtr/tools/dataclass_tools.py,sha256=0Gt6KeLhtPgubo_2tYkIVqB8oQ91Qzag8OAGZDdjvMU,1209
10
- fmtr/tools/datatype_tools.py,sha256=1XznVwlY4-DkYa6FwhHMstD8qz27vCcV64IvCrcJgMA,1830
10
+ fmtr/tools/datatype_tools.py,sha256=89QmlQ_fANqFQKsEMzhhRftfby-1PcrR3cylfbQNt9U,1878
11
11
  fmtr/tools/datetime_tools.py,sha256=L7wmBoQbD9h_pJIL92WQOX32r_vrXgRvE-_0PVPRAGY,232
12
12
  fmtr/tools/debugging_tools.py,sha256=_xzqS0V5BpL8d06j-jVQjGgI7T020QsqVXKAKMz7Du8,2082
13
13
  fmtr/tools/environment_tools.py,sha256=43uqfj1G1bNX0IwKz-NKbu3AbFYSdbBuGN9rlThe030,1845
@@ -45,14 +45,14 @@ fmtr/tools/tabular_tools.py,sha256=mw6vOij1Ch-pVAyHMPtm5zj__ULZN_TKeBYOfj33wFM,1
45
45
  fmtr/tools/tokenization_tools.py,sha256=me-IBzSLyNYejLybwjO9CNB6Mj2NYfKPaOVThXyaGNg,4268
46
46
  fmtr/tools/tools.py,sha256=sLMXk8juOL8_n_D776cJ-kzjyMHqFI_fctDEjy6PIKs,1115
47
47
  fmtr/tools/unicode_tools.py,sha256=yS_9wpu8ogNoiIL7s1G_8bETFFO_YQlo4LNPv1NLDeY,52
48
- fmtr/tools/version,sha256=jSMjAm19YQafVxIPX-mu0uNeQjDY56c4NghzH2KMxTY,6
48
+ fmtr/tools/version,sha256=Q_Iz5eCc4ybT-tWgBcfd4BENxHt_W707uGCdp8EvsCs,6
49
49
  fmtr/tools/webhook_tools.py,sha256=q3pVJ1NCem2SrMuFcLxiWd7DibFs7Q-uGtojfXd3Qcg,380
50
50
  fmtr/tools/yaml_tools.py,sha256=Bhhyd6GQVKO72Lp8ky7bAUjIB_65Hdh0Q45SKIEe6S8,1901
51
51
  fmtr/tools/ai_tools/__init__.py,sha256=O8VRlPnnQCncg2ZZ2l_VdWLJf4jkKH6dkZFVbv6o7IM,388
52
52
  fmtr/tools/ai_tools/agentic_tools.py,sha256=Zj6WcbDc1yLFi3raTSD0BeOkWR3l5RmmccFYGx8-0XE,5534
53
53
  fmtr/tools/ai_tools/inference_tools.py,sha256=2UP2gXEyOJUjyyV6zmFIYmIxUsh1rXkRH0IbFvr2bRs,11908
54
54
  fmtr/tools/database_tools/__init__.py,sha256=-YXEs3P4nwg7hdvALpaW4K2Pg9FIc49rD53smqnBgT4,221
55
- fmtr/tools/database_tools/document.py,sha256=YciaSNYyLSPRFZbHQEVwN-G_7RXgXFaq27IN62--fDA,989
55
+ fmtr/tools/database_tools/document.py,sha256=uGmyznAKqshv8yjFoVRlkPmnSVao3oPJ7iaxvZSpi3g,1214
56
56
  fmtr/tools/dns_tools/__init__.py,sha256=HP0Qcwyi1C6vBH_ejuWrGJOWdp-GZ_cmH-QofjD6Mmg,266
57
57
  fmtr/tools/dns_tools/client.py,sha256=IBbd7Xgx9ExTn_EPoL7ts9JfXokHHuOiD9m4K6tl1Q0,2817
58
58
  fmtr/tools/dns_tools/dm.py,sha256=Lp1HaF7rpVtL_Ji4Bd32B29105H9ZKQ8AcVj_AB7nsA,6678
@@ -85,9 +85,9 @@ fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g
85
85
  fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
86
86
  fmtr/tools/version_tools/__init__.py,sha256=cjE6nO6AoVOUp3RwgTbqL9wiw8J1l2pHJOz6Gn6bxjA,326
87
87
  fmtr/tools/version_tools/version_tools.py,sha256=Hcc6yferZS1hHbugRTdiHhSNmXEEG0hjCiTTXKna-YY,1127
88
- fmtr_tools-1.3.65.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
89
- fmtr_tools-1.3.65.dist-info/METADATA,sha256=GU4COvHnYDWpDNeNy4PX0q3x6dxqRjxj0Ps0s_tCLX4,18035
90
- fmtr_tools-1.3.65.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
- fmtr_tools-1.3.65.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
92
- fmtr_tools-1.3.65.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
93
- fmtr_tools-1.3.65.dist-info/RECORD,,
88
+ fmtr_tools-1.3.67.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
89
+ fmtr_tools-1.3.67.dist-info/METADATA,sha256=WEZSR3WZEPJ6LggCgFD6yt-M0qiAgWNdZ8lxkAyeKaA,18035
90
+ fmtr_tools-1.3.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
+ fmtr_tools-1.3.67.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
92
+ fmtr_tools-1.3.67.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
93
+ fmtr_tools-1.3.67.dist-info/RECORD,,