fmtr.tools 1.3.63__py3-none-any.whl → 1.3.64__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,4 +1,94 @@
1
- from pydantic import BaseModel, RootModel, ConfigDict
1
+ from functools import cached_property
2
+ from typing import ClassVar, List, Any, Dict
3
+
4
+ from pydantic import BaseModel
5
+ from pydantic import RootModel, ConfigDict
6
+ from pydantic.fields import FieldInfo
7
+ from pydantic_core import PydanticUndefined, PydanticUndefinedType
8
+
9
+ from fmtr.tools.datatype_tools import is_optional
10
+ from fmtr.tools.iterator_tools import get_class_lookup
11
+ from fmtr.tools.tools import Auto, Required
12
+
13
+
14
+ class Field(FieldInfo):
15
+ """
16
+
17
+ Allow DRYer field definitions, set annotation and defaults at the same time, easier field inheritance, etc.
18
+
19
+ """
20
+ ANNOTATION = None
21
+ DEFAULT = Auto
22
+ FILLS = None
23
+ DESCRIPTION = None
24
+ TITLE = Auto
25
+ KWARGS = None
26
+
27
+ def __init__(self):
28
+ """
29
+
30
+ Infer default from type annotation, if enabled, use class/argument fills to create titles/descriptions, etc.
31
+
32
+ """
33
+ title = self.get_title_auto()
34
+ description = self.get_desc()
35
+ default = self.get_default_auto()
36
+ kwargs = self.KWARGS or {}
37
+
38
+ if default is Required:
39
+ default = PydanticUndefined
40
+
41
+ super().__init__(default=default, title=title, description=description, **kwargs)
42
+
43
+ @cached_property
44
+ def fills(self) -> Dict[str, str]:
45
+ """
46
+
47
+ Get fills with filled title merged in
48
+
49
+ """
50
+ return (self.FILLS or {}) | dict(title=self.get_title_auto())
51
+
52
+ def get_default_auto(self) -> type[Any] | None | PydanticUndefinedType:
53
+ """
54
+
55
+ Infer default, if not specified.
56
+
57
+ """
58
+ if self.DEFAULT is not Auto:
59
+ return self.DEFAULT
60
+
61
+ if is_optional(self.ANNOTATION):
62
+ return None
63
+ else:
64
+ return Required
65
+
66
+ def get_title_auto(self) -> str | None:
67
+ """
68
+
69
+ Get title from classname/mask
70
+
71
+ """
72
+
73
+ mask = self.__class__.__name__ if self.TITLE is Auto else self.TITLE
74
+ fills = (self.FILLS or {})
75
+
76
+ if mask:
77
+ return mask.format(**fills)
78
+
79
+ return None
80
+
81
+ def get_desc(self) -> str | None:
82
+ """
83
+
84
+ Get description from classname/mask
85
+
86
+ """
87
+
88
+ if self.DESCRIPTION:
89
+ return self.DESCRIPTION.format(**self.fills)
90
+
91
+ return None
2
92
 
3
93
 
4
94
  def to_df(*objs, name_value='value'):
@@ -51,12 +141,47 @@ class MixinFromJson:
51
141
  return self
52
142
 
53
143
 
144
+
54
145
  class Base(BaseModel, MixinFromJson):
55
146
  """
56
147
 
57
- Base model
148
+ Base model allowing model definition via a list of custom Field objects.
58
149
 
59
150
  """
151
+ FIELDS: ClassVar[List[Field] | Dict[str, Field]] = []
152
+
153
+ def __init_subclass__(cls, **kwargs):
154
+ """
155
+
156
+ Fetch aggregated fields metadata from the hierarchy and set annotations and FieldInfo objects in the class.
157
+
158
+ """
159
+ super().__init_subclass__(**kwargs)
160
+
161
+ fields = {}
162
+ for base in reversed(cls.__mro__):
163
+
164
+ try:
165
+ raw = base.FIELDS
166
+ except AttributeError:
167
+ raw = {}
168
+
169
+ if isinstance(raw, dict):
170
+ fields |= raw
171
+ else:
172
+ fields |= get_class_lookup(*raw, name_function=str.lower)
173
+
174
+ cls.FIELDS = fields
175
+
176
+ for name, FieldInfoType in fields.items():
177
+ if name in cls.__annotations__:
178
+ continue
179
+
180
+ field = FieldInfoType()
181
+ setattr(cls, name, field)
182
+
183
+ annotation = FieldInfoType.ANNOTATION
184
+ cls.__annotations__[name] = annotation
60
185
 
61
186
  def to_df(self, name_value='value'):
62
187
  """
@@ -1,4 +1,5 @@
1
- from typing import Any
1
+ from types import UnionType, NoneType
2
+ from typing import Any, get_origin, get_args
2
3
 
3
4
  from fmtr.tools.tools import Raise
4
5
 
@@ -84,3 +85,15 @@ def none_else(value: Any, default: Any) -> Any:
84
85
  if is_none(value):
85
86
  return default
86
87
  return value
88
+
89
+
90
+ def is_optional(annotation) -> bool:
91
+ """
92
+
93
+ Is type/annotation optional? todo should be in typing_tools?
94
+
95
+ """
96
+ origin = get_origin(annotation)
97
+ args = get_args(annotation)
98
+ is_opt = origin is UnionType and NoneType in args
99
+ return is_opt
@@ -1,8 +1,8 @@
1
1
  from itertools import chain, batched
2
-
3
2
  from typing import List, Dict, Any
4
3
 
5
4
  from fmtr.tools.datatype_tools import is_none
5
+ from fmtr.tools.tools import identity
6
6
 
7
7
 
8
8
  def enlist(value) -> List[Any]:
@@ -73,3 +73,12 @@ def dedupe(items):
73
73
 
74
74
  """
75
75
  return list(dict.fromkeys(items))
76
+
77
+
78
+ def get_class_lookup(*classes, name_function=identity):
79
+ """
80
+
81
+ Dictionary of class names to classes
82
+
83
+ """
84
+ return {name_function(cls.__name__): cls for cls in classes}
@@ -1,11 +1,10 @@
1
1
  import re
2
+ from collections import namedtuple
2
3
  from dataclasses import dataclass
4
+ from string import Formatter
3
5
  from textwrap import dedent
4
6
  from typing import List
5
7
 
6
- from collections import namedtuple
7
- from string import Formatter
8
-
9
8
  from fmtr.tools.datatype_tools import is_none
10
9
 
11
10
  ELLIPSIS = '…'
@@ -182,6 +181,7 @@ def join_natural(items, sep=', ', conj='and'):
182
181
 
183
182
  """
184
183
 
184
+ items = list(items)
185
185
  if not items:
186
186
  return ""
187
187
  if len(items) == 1:
fmtr/tools/tools.py CHANGED
@@ -27,7 +27,15 @@ def identity(x: Any) -> Any:
27
27
  return x
28
28
 
29
29
 
30
- class Empty:
30
+ class Special:
31
+ """
32
+
33
+ Classes to differentiate special arguments from primitive arguments.
34
+
35
+ """
36
+
37
+
38
+ class Empty(Special):
31
39
  """
32
40
 
33
41
  Class to denote an unspecified object (e.g. argument) when `None` cannot be used.
@@ -35,7 +43,7 @@ class Empty:
35
43
  """
36
44
 
37
45
 
38
- class Raise:
46
+ class Raise(Special):
39
47
  """
40
48
 
41
49
  Class to denote when a function should raise instead of e.g. returning a default.
@@ -43,4 +51,21 @@ class Raise:
43
51
  """
44
52
 
45
53
 
54
+ class Auto(Special):
55
+ """
56
+
57
+ Class to denote when an argument should be inferred.
58
+
59
+ """
60
+
61
+
62
+ class Required(Special):
63
+ """
64
+
65
+ Class to denote when an argument is required.
66
+
67
+ """
68
+
69
+
70
+
46
71
  EMPTY = Empty()
fmtr/tools/version CHANGED
@@ -1 +1 @@
1
- 1.3.63
1
+ 1.3.64
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmtr.tools
3
- Version: 1.3.63
3
+ Version: 1.3.64
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
@@ -8,6 +8,20 @@ Author-email: innovative.fowler@mask.pro.fmtr.dev
8
8
  License: Copyright © 2025 Frontmatter. All rights reserved.
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
+ Provides-Extra: dev
12
+ Requires-Dist: logfire; extra == "dev"
13
+ Requires-Dist: semver; extra == "dev"
14
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "dev"
15
+ Requires-Dist: pydantic-settings; extra == "dev"
16
+ Requires-Dist: pydantic; extra == "dev"
17
+ Requires-Dist: pydantic-extra-types; extra == "dev"
18
+ Requires-Dist: pycountry; extra == "dev"
19
+ Requires-Dist: yamlscript; extra == "dev"
20
+ Requires-Dist: pyyaml; extra == "dev"
21
+ Requires-Dist: yamlscript; extra == "dev"
22
+ Requires-Dist: pyyaml; extra == "dev"
23
+ Requires-Dist: beanie[odm]; extra == "dev"
24
+ Requires-Dist: motor; extra == "dev"
11
25
  Provides-Extra: test
12
26
  Requires-Dist: pytest-cov; extra == "test"
13
27
  Provides-Extra: yaml
@@ -154,68 +168,68 @@ Provides-Extra: db-document
154
168
  Requires-Dist: beanie[odm]; extra == "db-document"
155
169
  Requires-Dist: motor; extra == "db-document"
156
170
  Provides-Extra: all
157
- Requires-Dist: uvicorn[standard]; extra == "all"
158
- Requires-Dist: contexttimer; extra == "all"
159
- Requires-Dist: pymupdf; extra == "all"
160
- Requires-Dist: motor; extra == "all"
161
- Requires-Dist: huggingface_hub; extra == "all"
162
- Requires-Dist: google-auth-httplib2; extra == "all"
171
+ Requires-Dist: diskcache; extra == "all"
163
172
  Requires-Dist: sre_yield; extra == "all"
164
- Requires-Dist: json_repair; extra == "all"
165
- Requires-Dist: fastapi; extra == "all"
173
+ Requires-Dist: setuptools; extra == "all"
166
174
  Requires-Dist: tabulate; extra == "all"
167
- Requires-Dist: flet-webview; extra == "all"
168
- Requires-Dist: beanie[odm]; extra == "all"
169
- Requires-Dist: openai; extra == "all"
170
- Requires-Dist: pydantic-extra-types; extra == "all"
171
- Requires-Dist: torchaudio; extra == "all"
172
- Requires-Dist: flet-video; extra == "all"
173
- Requires-Dist: tinynetrc; extra == "all"
174
- Requires-Dist: flet[all]; extra == "all"
175
- Requires-Dist: pycountry; extra == "all"
176
- Requires-Dist: torchvision; extra == "all"
177
- Requires-Dist: deepdiff; extra == "all"
178
- Requires-Dist: pydantic; extra == "all"
179
- Requires-Dist: httpx_retries; extra == "all"
180
- Requires-Dist: logfire[fastapi]; extra == "all"
181
- Requires-Dist: diskcache; extra == "all"
182
- Requires-Dist: dask[bag]; extra == "all"
183
- Requires-Dist: yamlscript; extra == "all"
184
- Requires-Dist: Unidecode; extra == "all"
185
- Requires-Dist: openpyxl; extra == "all"
186
175
  Requires-Dist: httpx; extra == "all"
187
- Requires-Dist: transformers[sentencepiece]; extra == "all"
188
- Requires-Dist: html2text; extra == "all"
189
- Requires-Dist: pytest-cov; extra == "all"
190
- Requires-Dist: logfire; extra == "all"
191
- Requires-Dist: appdirs; extra == "all"
192
- Requires-Dist: python-on-whales; extra == "all"
176
+ Requires-Dist: pymupdf; extra == "all"
177
+ Requires-Dist: flet-video; extra == "all"
178
+ Requires-Dist: cachetools; extra == "all"
193
179
  Requires-Dist: semver; extra == "all"
194
- Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
195
- Requires-Dist: pandas; extra == "all"
180
+ Requires-Dist: pydantic-extra-types; extra == "all"
181
+ Requires-Dist: beanie[odm]; extra == "all"
182
+ Requires-Dist: google-auth; extra == "all"
183
+ Requires-Dist: google-auth-oauthlib; extra == "all"
184
+ Requires-Dist: uvicorn[standard]; extra == "all"
185
+ Requires-Dist: yamlscript; extra == "all"
186
+ Requires-Dist: dask[bag]; extra == "all"
187
+ Requires-Dist: json_repair; extra == "all"
188
+ Requires-Dist: peft; extra == "all"
196
189
  Requires-Dist: distributed; extra == "all"
197
- Requires-Dist: filetype; extra == "all"
198
- Requires-Dist: faker; extra == "all"
199
- Requires-Dist: sentence_transformers; extra == "all"
200
- Requires-Dist: regex; extra == "all"
201
- Requires-Dist: deepmerge; extra == "all"
190
+ Requires-Dist: tokenizers; extra == "all"
191
+ Requires-Dist: motor; extra == "all"
192
+ Requires-Dist: odfpy; extra == "all"
193
+ Requires-Dist: pycountry; extra == "all"
194
+ Requires-Dist: fastapi; extra == "all"
202
195
  Requires-Dist: google-api-python-client; extra == "all"
203
- Requires-Dist: setuptools; extra == "all"
204
- Requires-Dist: google-auth; extra == "all"
205
- Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
196
+ Requires-Dist: html2text; extra == "all"
197
+ Requires-Dist: transformers[sentencepiece]; extra == "all"
206
198
  Requires-Dist: pydantic-settings; extra == "all"
207
- Requires-Dist: dnspython[doh]; extra == "all"
208
- Requires-Dist: ollama; extra == "all"
209
- Requires-Dist: cachetools; extra == "all"
199
+ Requires-Dist: deepdiff; extra == "all"
200
+ Requires-Dist: logfire; extra == "all"
201
+ Requires-Dist: sentence_transformers; extra == "all"
210
202
  Requires-Dist: pymupdf4llm; extra == "all"
211
- Requires-Dist: pyyaml; extra == "all"
212
203
  Requires-Dist: logfire[httpx]; extra == "all"
204
+ Requires-Dist: flet[all]; extra == "all"
205
+ Requires-Dist: httpx_retries; extra == "all"
206
+ Requires-Dist: tinynetrc; extra == "all"
207
+ Requires-Dist: pytest-cov; extra == "all"
208
+ Requires-Dist: torchvision; extra == "all"
209
+ Requires-Dist: dnspython[doh]; extra == "all"
210
+ Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
211
+ Requires-Dist: google-auth-httplib2; extra == "all"
212
+ Requires-Dist: regex; extra == "all"
213
+ Requires-Dist: huggingface_hub; extra == "all"
214
+ Requires-Dist: logfire[fastapi]; extra == "all"
213
215
  Requires-Dist: playwright; extra == "all"
214
- Requires-Dist: odfpy; extra == "all"
215
- Requires-Dist: tokenizers; extra == "all"
216
+ Requires-Dist: pyyaml; extra == "all"
217
+ Requires-Dist: pandas; extra == "all"
218
+ Requires-Dist: torchaudio; extra == "all"
219
+ Requires-Dist: python-on-whales; extra == "all"
220
+ Requires-Dist: flet-webview; extra == "all"
221
+ Requires-Dist: deepmerge; extra == "all"
222
+ Requires-Dist: openai; extra == "all"
223
+ Requires-Dist: appdirs; extra == "all"
224
+ Requires-Dist: pydevd-pycharm~=251.25410.159; extra == "all"
225
+ Requires-Dist: ollama; extra == "all"
226
+ Requires-Dist: faker; extra == "all"
227
+ Requires-Dist: openpyxl; extra == "all"
228
+ Requires-Dist: pydantic; extra == "all"
216
229
  Requires-Dist: bokeh; extra == "all"
217
- Requires-Dist: google-auth-oauthlib; extra == "all"
218
- Requires-Dist: peft; extra == "all"
230
+ Requires-Dist: filetype; extra == "all"
231
+ Requires-Dist: Unidecode; extra == "all"
232
+ Requires-Dist: contexttimer; extra == "all"
219
233
  Dynamic: author
220
234
  Dynamic: author-email
221
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=0BFm-F_cYzVTxftWQwORkPd0FM2BTLVh9-s0-rTTFoo,1744
8
+ fmtr/tools/data_modelling_tools.py,sha256=pSAnf-pt-c4RGqDMCkDb_XGxsmEEQqLmBMlMTVU76yg,4916
9
9
  fmtr/tools/dataclass_tools.py,sha256=0Gt6KeLhtPgubo_2tYkIVqB8oQ91Qzag8OAGZDdjvMU,1209
10
- fmtr/tools/datatype_tools.py,sha256=3P4AWIFGkJ-UqvXlj0Jc9IvkIIgTOE9jRrOk3NVbpH8,1508
10
+ fmtr/tools/datatype_tools.py,sha256=1XznVwlY4-DkYa6FwhHMstD8qz27vCcV64IvCrcJgMA,1830
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
@@ -20,7 +20,7 @@ fmtr/tools/http_tools.py,sha256=RVwGrBNMyjfbpgAPCSnxEkXfSzXXWARb3ayq981ONQE,464
20
20
  fmtr/tools/import_tools.py,sha256=XJmiWLukRncJAcaGReDn4jIz1_IpVBjfYCQHH1hIg7c,588
21
21
  fmtr/tools/inherit_tools.py,sha256=gTGL4mRm5RsbFW76s25AbuAJ2vlymbh1c8Q4Hl2uJGU,646
22
22
  fmtr/tools/inspection_tools.py,sha256=tLTRvzy9XVomQPi0dfnF_cgwc7KiDVZAr7gPTk4S_bQ,278
23
- fmtr/tools/iterator_tools.py,sha256=ymxo2U9MrPhouIhWCVvh1TrP1bXJPm_p0Lqwgi5Jr6w,1628
23
+ fmtr/tools/iterator_tools.py,sha256=IwHdRj72oP3e191h7gs15g0HEW6haP28t8CmB0R8qbo,1847
24
24
  fmtr/tools/json_fix_tools.py,sha256=vNSlswVQnujPmKEqDjFJcO901mjMyv59q3awsT7mlhs,477
25
25
  fmtr/tools/json_tools.py,sha256=WkFc5q7oqMtcFejhN1K5zQFULa9TdLOup83Fr0saDRY,348
26
26
  fmtr/tools/logging_tools.py,sha256=jZFKnL-7HHOaPkn7F3fT9DyffIgwY-g7SEQ0p1RhzBo,2673
@@ -40,12 +40,12 @@ fmtr/tools/random_tools.py,sha256=4VlQdk5THbR8ka4pZaLbk_ZO_4yy6PF_lHZes_rgenY,22
40
40
  fmtr/tools/semantic_tools.py,sha256=cxY9NSAHWj4nEc6Oj4qA1omR3dWbl2OuH7_PkINc6_E,1386
41
41
  fmtr/tools/settings_tools.py,sha256=o11W3T60UZSvCTkh_eEQq1Mx74GycQ6JxUr0plBDbsk,2356
42
42
  fmtr/tools/spaces_tools.py,sha256=D_he3mve6DruB3OPS6QyzqD05ChHnRTb4buViKPe7To,1099
43
- fmtr/tools/string_tools.py,sha256=Lz_H9l25OOoxE48QBJ_Upkk5nno7dPA6G2Gc0Wo8rOk,5275
43
+ fmtr/tools/string_tools.py,sha256=fVJADFWHtGStakgPNOPn_lmnRC94v1VYE1ETCmsvJVA,5298
44
44
  fmtr/tools/tabular_tools.py,sha256=mw6vOij1Ch-pVAyHMPtm5zj__ULZN_TKeBYOfj33wFM,1634
45
45
  fmtr/tools/tokenization_tools.py,sha256=me-IBzSLyNYejLybwjO9CNB6Mj2NYfKPaOVThXyaGNg,4268
46
- fmtr/tools/tools.py,sha256=CAsApa1YwVdNE6H66Vjivs_mXYvOas3rh7fPELAnTpk,795
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=1-w7DNphgnwgQa3EckgnbD0Qx9ULcbjMgAOknBRyoWI,6
48
+ fmtr/tools/version,sha256=PN6bG6VIuodXixpV8uCQygcpWuLKFNtVOv7BZZS_XrQ,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
@@ -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.63.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
89
- fmtr_tools-1.3.63.dist-info/METADATA,sha256=nSjkJECziz3f5ss_9fCnnyyVJCoAKvOl0LzYDPShNzo,17455
90
- fmtr_tools-1.3.63.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
- fmtr_tools-1.3.63.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
92
- fmtr_tools-1.3.63.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
93
- fmtr_tools-1.3.63.dist-info/RECORD,,
88
+ fmtr_tools-1.3.64.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
89
+ fmtr_tools-1.3.64.dist-info/METADATA,sha256=8h7PBKhUZ_hxyfZ1P8NA4z4J2qspewCV8Q4GnePKL2M,18035
90
+ fmtr_tools-1.3.64.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
+ fmtr_tools-1.3.64.dist-info/entry_points.txt,sha256=h-r__Xh5njtFqreMLg6cGuTFS4Qh-QqJPU1HB-_BS-Q,357
92
+ fmtr_tools-1.3.64.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
93
+ fmtr_tools-1.3.64.dist-info/RECORD,,