fmtr.tools 1.0.30__py3-none-any.whl → 1.0.32__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/api_tools.py +5 -0
- fmtr/tools/interface_tools.py +30 -184
- fmtr/tools/path_tools.py +23 -0
- fmtr/tools/string_tools.py +7 -0
- fmtr/tools/version +1 -1
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/METADATA +8 -4
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/RECORD +11 -11
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/LICENSE +0 -0
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/WHEEL +0 -0
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/entry_points.txt +0 -0
- {fmtr.tools-1.0.30.dist-info → fmtr.tools-1.0.32.dist-info}/top_level.txt +0 -0
fmtr/tools/api_tools.py
CHANGED
fmtr/tools/interface_tools.py
CHANGED
|
@@ -1,218 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
from
|
|
1
|
+
import flet as ft
|
|
2
|
+
from flet.core.event import Event
|
|
3
|
+
from flet.core.types import AppView
|
|
4
|
+
from flet.core.view import View
|
|
3
5
|
|
|
4
|
-
from fmtr.tools.data_modelling_tools import Base
|
|
5
6
|
from fmtr.tools.logging_tools import logger
|
|
6
|
-
from fmtr.tools.path_tools import Path
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
class Interface:
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Simple interface base class.
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
|
-
|
|
15
|
+
TITLE = 'Base Interface'
|
|
16
|
+
HOST = '0.0.0.0'
|
|
17
|
+
PORT = 8080
|
|
18
|
+
APPVIEW = AppView.WEB_BROWSER
|
|
19
|
+
PATH_ASSETS = None
|
|
20
|
+
ROUTE_ROOT = '/'
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
def color(name, text):
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
Get markdown coloured text
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
return f":{name}[{text}]"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def get_streamlit():
|
|
28
|
-
import streamlit
|
|
29
|
-
return streamlit
|
|
30
|
-
|
|
31
|
-
class Interface(Base):
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
Base for using streamlit via classes
|
|
35
|
-
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
PATH: ClassVar = __file__
|
|
39
|
-
LAYOUT: ClassVar = 'centered'
|
|
40
|
-
NAME: ClassVar = None
|
|
41
|
-
IS_ASYNC: ClassVar = False
|
|
42
|
-
|
|
43
|
-
parent: Base = None
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def st(self):
|
|
47
|
-
return get_streamlit()
|
|
48
|
-
|
|
49
|
-
@classmethod
|
|
50
|
-
def get_name(cls):
|
|
51
|
-
return cls.NAME or cls.__name__
|
|
52
|
-
|
|
53
|
-
def set_title(self):
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
Set page title and layout when root interface
|
|
57
|
-
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
self.st.set_page_config(page_title=self.get_name(), layout=self.LAYOUT)
|
|
61
|
-
self.st.title(self.get_name())
|
|
62
|
-
|
|
63
|
-
def render(self):
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
Render the Interface
|
|
67
|
-
|
|
68
|
-
"""
|
|
69
|
-
raise NotImplementedError()
|
|
70
|
-
|
|
71
|
-
def get_key(self, seg=None):
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
Get a structure-friendly unique ID
|
|
75
|
-
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
suffix = f'{self.__class__.__name__}({self.get_key_self()})'
|
|
79
|
-
|
|
80
|
-
if self.parent is None:
|
|
81
|
-
base = Path(suffix)
|
|
82
|
-
else:
|
|
83
|
-
base = self.parent.get_key() / suffix
|
|
84
|
-
|
|
85
|
-
if seg:
|
|
86
|
-
path = base / seg
|
|
87
|
-
else:
|
|
88
|
-
path = base
|
|
89
|
-
|
|
90
|
-
return path
|
|
91
|
-
|
|
92
|
-
def get_url_data(self):
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
Get URL params data pertaining to the current object
|
|
96
|
-
|
|
97
|
-
"""
|
|
98
|
-
|
|
99
|
-
if self.parent is None:
|
|
100
|
-
data = {}
|
|
101
|
-
else:
|
|
102
|
-
data = self.parent.get_url_data()
|
|
103
|
-
|
|
104
|
-
url_self = self.get_url_self()
|
|
105
|
-
|
|
106
|
-
if url_self:
|
|
107
|
-
data |= {self.__class__.__name__.lower(): url_self}
|
|
108
|
-
|
|
109
|
-
return data
|
|
110
|
-
|
|
111
|
-
def get_url_self(self):
|
|
112
|
-
"""
|
|
113
|
-
|
|
114
|
-
Get URL params ID pertaining to the current object
|
|
115
|
-
|
|
116
|
-
"""
|
|
117
|
-
return str(id(self))
|
|
118
|
-
|
|
119
|
-
def get_key_self(self):
|
|
22
|
+
def render(self, page: ft.Page):
|
|
120
23
|
"""
|
|
121
24
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"""
|
|
125
|
-
return str(id(self))
|
|
25
|
+
Interface entry point.
|
|
126
26
|
|
|
127
|
-
def get_url(self):
|
|
128
27
|
"""
|
|
129
28
|
|
|
130
|
-
|
|
29
|
+
if not page.on_route_change:
|
|
30
|
+
page.on_route_change = lambda e, page=page: self.route(page, e)
|
|
31
|
+
page.on_view_pop = lambda view, page=page: self.pop(page, view)
|
|
131
32
|
|
|
132
|
-
|
|
133
|
-
import urllib
|
|
134
|
-
return urllib.parse.urlencode(self.get_url_data())
|
|
33
|
+
page.go(self.ROUTE_ROOT)
|
|
135
34
|
|
|
136
|
-
def
|
|
35
|
+
def route(self, page: ft.Page, event: Event):
|
|
137
36
|
"""
|
|
138
37
|
|
|
139
|
-
|
|
38
|
+
Overridable router.
|
|
140
39
|
|
|
141
40
|
"""
|
|
142
|
-
|
|
143
|
-
tabs = st.tabs(tab_names)
|
|
144
|
-
|
|
145
|
-
for cls, tab in zip(classes, tabs):
|
|
146
|
-
with tab:
|
|
147
|
-
cls()
|
|
41
|
+
raise NotImplementedError
|
|
148
42
|
|
|
149
|
-
|
|
150
|
-
def is_streamlit(cls):
|
|
43
|
+
def pop(self, page: ft.Page, view: View):
|
|
151
44
|
"""
|
|
152
45
|
|
|
153
|
-
|
|
46
|
+
Overridable view pop.
|
|
154
47
|
|
|
155
48
|
"""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
@classmethod
|
|
159
|
-
def get_state(cls):
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
Initialise this Interface and keep cached. This needs to be a cached_resource to avoid serialisation/copying.
|
|
163
|
-
This is global, so session handling needs to happen downstream.
|
|
164
|
-
|
|
165
|
-
"""
|
|
166
|
-
msg = f'Initialising State "{cls.get_name()}"...'
|
|
167
|
-
logger.info(msg)
|
|
168
|
-
self = cls()
|
|
169
|
-
return self
|
|
49
|
+
raise NotImplementedError
|
|
170
50
|
|
|
171
51
|
@classmethod
|
|
172
52
|
def launch(cls):
|
|
173
53
|
"""
|
|
174
54
|
|
|
175
|
-
|
|
55
|
+
Initialise self and launch.
|
|
176
56
|
|
|
177
57
|
"""
|
|
58
|
+
self = cls()
|
|
59
|
+
logger.info(f"Launching {self.TITLE} at http://{self.HOST}:{self.PORT}")
|
|
60
|
+
ft.app(self.render, view=self.APPVIEW, host=self.HOST, port=self.PORT, assets_dir=self.PATH_ASSETS)
|
|
178
61
|
|
|
179
|
-
st = get_streamlit()
|
|
180
|
-
|
|
181
|
-
if cls.is_streamlit():
|
|
182
|
-
|
|
183
|
-
if cls.IS_ASYNC:
|
|
184
|
-
from fmtr.tools import async_tools
|
|
185
|
-
async_tools.ensure_loop()
|
|
186
|
-
|
|
187
|
-
self = st.cache_resource(show_spinner=False)(cls.get_state)()
|
|
188
|
-
logger.debug(f'Rendering Interface "{self.get_name()}" with state: {st.session_state}...')
|
|
189
|
-
self.set_title()
|
|
190
|
-
self.render()
|
|
191
|
-
else:
|
|
192
|
-
logger.info(f'Launching Streamlit interface "{cls.get_name()}"...')
|
|
193
|
-
from streamlit.web import bootstrap
|
|
194
|
-
bootstrap.run(cls.PATH, False, [], {})
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class InterfaceTest(Interface):
|
|
198
|
-
NAME: ClassVar = 'Test Interface'
|
|
199
|
-
|
|
200
|
-
parent: Base = None
|
|
201
|
-
|
|
202
|
-
def render(self):
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
Render the Interface
|
|
206
|
-
|
|
207
|
-
"""
|
|
208
|
-
if not self.st.button('Run Test'):
|
|
209
|
-
return
|
|
210
|
-
msg = 'Running test...'
|
|
211
|
-
with self.st.spinner(msg):
|
|
212
|
-
sleep(3)
|
|
213
|
-
self.st.success("Success!")
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if __name__ == '__main__':
|
|
217
|
-
InterfaceTest.launch()
|
|
218
62
|
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
Interface.launch()
|
fmtr/tools/path_tools.py
CHANGED
|
@@ -96,6 +96,29 @@ class Path(type(Path())):
|
|
|
96
96
|
"""
|
|
97
97
|
return cls(gettempdir())
|
|
98
98
|
|
|
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
|
+
|
|
99
122
|
def write_json(self, obj) -> int:
|
|
100
123
|
"""
|
|
101
124
|
|
fmtr/tools/string_tools.py
CHANGED
fmtr/tools/version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.32
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fmtr.tools
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.32
|
|
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
|
|
@@ -46,8 +46,10 @@ Requires-Dist: huggingface-hub ; extra == 'hfh'
|
|
|
46
46
|
Provides-Extra: html
|
|
47
47
|
Requires-Dist: html2text ; extra == 'html'
|
|
48
48
|
Provides-Extra: interface
|
|
49
|
+
Requires-Dist: flet-video ; extra == 'interface'
|
|
50
|
+
Requires-Dist: flet-webview ; extra == 'interface'
|
|
51
|
+
Requires-Dist: flet[all] ; extra == 'interface'
|
|
49
52
|
Requires-Dist: pydantic ; extra == 'interface'
|
|
50
|
-
Requires-Dist: streamlit ; extra == 'interface'
|
|
51
53
|
Provides-Extra: json-fix
|
|
52
54
|
Requires-Dist: json-repair ; extra == 'json-fix'
|
|
53
55
|
Provides-Extra: logging
|
|
@@ -86,6 +88,9 @@ Requires-Dist: distributed ; extra == 'test'
|
|
|
86
88
|
Requires-Dist: docker ; extra == 'test'
|
|
87
89
|
Requires-Dist: faker ; extra == 'test'
|
|
88
90
|
Requires-Dist: fastapi ; extra == 'test'
|
|
91
|
+
Requires-Dist: flet-video ; extra == 'test'
|
|
92
|
+
Requires-Dist: flet-webview ; extra == 'test'
|
|
93
|
+
Requires-Dist: flet[all] ; extra == 'test'
|
|
89
94
|
Requires-Dist: google-api-python-client ; extra == 'test'
|
|
90
95
|
Requires-Dist: google-auth ; extra == 'test'
|
|
91
96
|
Requires-Dist: google-auth-httplib2 ; extra == 'test'
|
|
@@ -105,7 +110,6 @@ Requires-Dist: pyyaml ; extra == 'test'
|
|
|
105
110
|
Requires-Dist: semver ; extra == 'test'
|
|
106
111
|
Requires-Dist: sentence-transformers ; extra == 'test'
|
|
107
112
|
Requires-Dist: sre-yield ; extra == 'test'
|
|
108
|
-
Requires-Dist: streamlit ; extra == 'test'
|
|
109
113
|
Requires-Dist: tinynetrc ; extra == 'test'
|
|
110
114
|
Requires-Dist: tokenizers ; extra == 'test'
|
|
111
115
|
Requires-Dist: torchaudio ; extra == 'test'
|
|
@@ -225,7 +229,7 @@ The included modules, plus any extra requirements, are as follows:
|
|
|
225
229
|
- Extras: `hfh`
|
|
226
230
|
- `tools.html`: Utilities for converting HTML documents to plain text.
|
|
227
231
|
- Extras: `html`
|
|
228
|
-
- `tools.interface`: Provides a base class for building
|
|
232
|
+
- `tools.interface`: Provides a base class for building Flutter/Flet apps.
|
|
229
233
|
- Extras: `interface`
|
|
230
234
|
- `tools.iterator`: Pivoting/unpivoting data structures
|
|
231
235
|
- Extras: None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
fmtr/tools/__init__.py,sha256=imKjjZg5HypnRy5bD4Xe6HBkQhavg6BOkwIeFzItG_8,5052
|
|
2
2
|
fmtr/tools/ai_tools.py,sha256=hN7DzuATXfurCDHugaluUsbmF_PzeKu3BTc2WXhG59g,11806
|
|
3
|
-
fmtr/tools/api_tools.py,sha256=
|
|
3
|
+
fmtr/tools/api_tools.py,sha256=u5YEdKyKto8MKY8legULLU7xeJ7lY2Bgyaep_xa8iZg,2089
|
|
4
4
|
fmtr/tools/async_tools.py,sha256=ewz757WcveQJd-G5SVr2JDOQVbdLGecCgl-tsBGVZz4,284
|
|
5
5
|
fmtr/tools/augmentation_tools.py,sha256=-6ESbO4CDlKqVOV1J1V6qBeoBMzbFIinkDHRHnCBej0,55
|
|
6
6
|
fmtr/tools/caching_tools.py,sha256=UOCYUNvLQ-NofR_dhqBmZF96-HRPf4At5MmxVk3gAIk,2943
|
|
@@ -19,7 +19,7 @@ fmtr/tools/hfh_tools.py,sha256=DCDIWuWlhtmIGCtp9cLcOTTEw_4yN_NocLX8w5NZsbk,2384
|
|
|
19
19
|
fmtr/tools/html_tools.py,sha256=0nN8Nz5HtG9bXyApYfHSKEivLlxjsm3Gn6Mg2TK0brI,394
|
|
20
20
|
fmtr/tools/import_tools.py,sha256=XJmiWLukRncJAcaGReDn4jIz1_IpVBjfYCQHH1hIg7c,588
|
|
21
21
|
fmtr/tools/inspection_tools.py,sha256=tLTRvzy9XVomQPi0dfnF_cgwc7KiDVZAr7gPTk4S_bQ,278
|
|
22
|
-
fmtr/tools/interface_tools.py,sha256=
|
|
22
|
+
fmtr/tools/interface_tools.py,sha256=JVYUV7wuMr24BORuUtNaBlTeBFt8VDGJ3HPRajd7Y_4,1341
|
|
23
23
|
fmtr/tools/iterator_tools.py,sha256=xj5f0c7LgLK53dddRRRJxBoLaBzlZoQS3_GfmpDPMoo,1311
|
|
24
24
|
fmtr/tools/json_fix_tools.py,sha256=vNSlswVQnujPmKEqDjFJcO901mjMyv59q3awsT7mlhs,477
|
|
25
25
|
fmtr/tools/json_tools.py,sha256=IKmrANhcftIz2msCZeItidJ1PcpY_tnbfxbRDnta-c0,349
|
|
@@ -30,18 +30,18 @@ fmtr/tools/name_tools.py,sha256=5CB_phqhHjl66iI8oLxOGPF2odC1apdul-M8Fv2xBhs,5514
|
|
|
30
30
|
fmtr/tools/netrc_tools.py,sha256=PpNpz_mWlQi6VHGromKwFfTyLpHUXsd4LY6-OKLCbeI,376
|
|
31
31
|
fmtr/tools/openai_tools.py,sha256=6SUgejgzUzmlKKct2_ePXntvMegu3FJgfk9x7aqtqYc,742
|
|
32
32
|
fmtr/tools/parallel_tools.py,sha256=G__ZbLRRx4cP5OyqY1hKwnE-VI3m5prYABB0tnZHnes,3132
|
|
33
|
-
fmtr/tools/path_tools.py,sha256=
|
|
33
|
+
fmtr/tools/path_tools.py,sha256=1GeWXdhV5rH99IfLI5ZFEnOJfs4Q4mYTT2R-rA791iQ,4273
|
|
34
34
|
fmtr/tools/platform_tools.py,sha256=7p69CmAHe_sF68Fx9uVhns1k5EewTHTWgUYzkl6ZQKA,308
|
|
35
35
|
fmtr/tools/process_tools.py,sha256=Ysh5Dk2QFBhXQerArjKdt7xZd3JrN5Ho02AaOjH0Nnw,1425
|
|
36
36
|
fmtr/tools/profiling_tools.py,sha256=jpXVjaNKPydTasEQVNXvxzGtMhXPit08AnJddkU8uIc,46
|
|
37
37
|
fmtr/tools/random_tools.py,sha256=4VlQdk5THbR8ka4pZaLbk_ZO_4yy6PF_lHZes_rgenY,2223
|
|
38
38
|
fmtr/tools/semantic_tools.py,sha256=cxY9NSAHWj4nEc6Oj4qA1omR3dWbl2OuH7_PkINc6_E,1386
|
|
39
39
|
fmtr/tools/spaces_tools.py,sha256=D_he3mve6DruB3OPS6QyzqD05ChHnRTb4buViKPe7To,1099
|
|
40
|
-
fmtr/tools/string_tools.py,sha256=
|
|
40
|
+
fmtr/tools/string_tools.py,sha256=U2EptMWR6KDOP22ZQ4ReUHV4i25SP7xwCmZScI1sy4M,3233
|
|
41
41
|
fmtr/tools/tokenization_tools.py,sha256=9FP5vgPufWv0XA961eVKObFll0d_2mM0W3ut3rtZyeo,4329
|
|
42
42
|
fmtr/tools/tools.py,sha256=xnfUrOnrT4OxFYez6vV5tAhydzCICJFiGVnviiZDEQo,796
|
|
43
43
|
fmtr/tools/unicode_tools.py,sha256=yS_9wpu8ogNoiIL7s1G_8bETFFO_YQlo4LNPv1NLDeY,52
|
|
44
|
-
fmtr/tools/version,sha256=
|
|
44
|
+
fmtr/tools/version,sha256=lJlaFE-y4dFjsYr6jbTGb5uzUQ_dp_LO5e9G4R2TeMk,6
|
|
45
45
|
fmtr/tools/version_tools.py,sha256=axzzHBS9V1n6YuSacsDKG3VfAvRqR8qr6aENCibR8vs,1248
|
|
46
46
|
fmtr/tools/yaml_tools.py,sha256=Ol43ZwbnSXGnn1K98Uxx61KPGSqfC4axE-X2q1LKMwk,349
|
|
47
47
|
fmtr/tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -52,9 +52,9 @@ fmtr/tools/tests/test_environment.py,sha256=iHaiMQfECYZPkPKwfuIZV9uHuWe3aE-p_dN_
|
|
|
52
52
|
fmtr/tools/tests/test_json.py,sha256=IeSP4ziPvRcmS8kq7k9tHonC9rN5YYq9GSNT2ul6Msk,287
|
|
53
53
|
fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g,2188
|
|
54
54
|
fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
|
|
55
|
-
fmtr.tools-1.0.
|
|
56
|
-
fmtr.tools-1.0.
|
|
57
|
-
fmtr.tools-1.0.
|
|
58
|
-
fmtr.tools-1.0.
|
|
59
|
-
fmtr.tools-1.0.
|
|
60
|
-
fmtr.tools-1.0.
|
|
55
|
+
fmtr.tools-1.0.32.dist-info/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
|
|
56
|
+
fmtr.tools-1.0.32.dist-info/METADATA,sha256=iPCoZOCJ1UbUM0x2NVVcWQiEg-Co8RZNSQIy1cgHErQ,13207
|
|
57
|
+
fmtr.tools-1.0.32.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
58
|
+
fmtr.tools-1.0.32.dist-info/entry_points.txt,sha256=CEStVkwJ1mTFvhN1WV5RdW83SkNW1d5Syj-KZ6A19ng,72
|
|
59
|
+
fmtr.tools-1.0.32.dist-info/top_level.txt,sha256=t5341a8ii3n4RFizwTeXGmcq_pf4GqL1h9ylE5LIWRk,12
|
|
60
|
+
fmtr.tools-1.0.32.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|