fmtr.tools 1.2.6__py3-none-any.whl → 1.3.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/dns_tools/server.py +1 -1
- fmtr/tools/pattern_tools.py +124 -67
- fmtr/tools/setup_tools/setup_tools.py +147 -47
- fmtr/tools/version +1 -1
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/METADATA +43 -43
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/RECORD +10 -10
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/WHEEL +0 -0
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/entry_points.txt +0 -0
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {fmtr_tools-1.2.6.dist-info → fmtr_tools-1.3.0.dist-info}/top_level.txt +0 -0
fmtr/tools/dns_tools/server.py
CHANGED
|
@@ -66,7 +66,7 @@ class ServerBaseDoHProxy(ServerBasePlain):
|
|
|
66
66
|
|
|
67
67
|
request = exchange.request
|
|
68
68
|
|
|
69
|
-
with logger.span(f'Handling request for {request.name_text} from {exchange.client}...'):
|
|
69
|
+
with logger.span(f'Handling request ID {request.message.id} for {request.name_text} from {exchange.client}...'):
|
|
70
70
|
|
|
71
71
|
if not request.is_valid:
|
|
72
72
|
raise ValueError(f'Only one question per request is supported. Got {len(request.question)} questions.')
|
fmtr/tools/pattern_tools.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import regex as re
|
|
2
|
-
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import dataclass, asdict
|
|
3
3
|
from functools import cached_property
|
|
4
|
-
from typing import List
|
|
4
|
+
from typing import List, Any
|
|
5
5
|
|
|
6
6
|
from fmtr.tools.logging_tools import logger
|
|
7
|
+
from fmtr.tools.string_tools import join
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class RewriteCircularLoopError(Exception):
|
|
@@ -14,59 +15,101 @@ class RewriteCircularLoopError(Exception):
|
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
MASK_GROUP = '(?:{pattern})'
|
|
19
|
+
MASK_NAMED = r"(?P<{key}>{pattern})"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def alt(*patterns):
|
|
23
|
+
patterns = sorted(patterns, key=len, reverse=True)
|
|
24
|
+
pattern = '|'.join(patterns)
|
|
25
|
+
pattern = MASK_GROUP.format(pattern=pattern)
|
|
26
|
+
return pattern
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
17
33
|
@dataclass
|
|
18
|
-
class
|
|
19
|
-
|
|
20
|
-
Represents a single rule for pattern matching and target string replacement.
|
|
34
|
+
class Key:
|
|
35
|
+
RECORD_SEP = '␞'
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
The `target` allows rewriting the identified matches with a formatted string.
|
|
25
|
-
It provides properties for generating a unique identifier for use as a regex group name and compiling the provided pattern into a regular expression object.
|
|
37
|
+
def flatten(self, data):
|
|
38
|
+
"""
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
Flatten/serialise dictionary data
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
pairs = [f'{value}' for key, value in data.items()]
|
|
44
|
+
string = self.RECORD_SEP.join(pairs)
|
|
45
|
+
return string
|
|
30
46
|
|
|
31
47
|
@cached_property
|
|
32
|
-
def
|
|
48
|
+
def pattern(self):
|
|
33
49
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
|
|
51
|
+
Serialise to pattern
|
|
52
|
+
|
|
37
53
|
"""
|
|
38
|
-
|
|
54
|
+
data = {key: MASK_NAMED.format(key=key, pattern=value) for key, value in asdict(self).items()}
|
|
55
|
+
pattern = self.flatten(data)
|
|
56
|
+
return pattern
|
|
39
57
|
|
|
40
58
|
@cached_property
|
|
41
59
|
def rx(self):
|
|
42
60
|
"""
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
Compile to Regular Expression
|
|
45
63
|
|
|
46
64
|
"""
|
|
47
65
|
return re.compile(self.pattern)
|
|
48
66
|
|
|
49
|
-
|
|
67
|
+
@cached_property
|
|
68
|
+
def string(self):
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
Serialise to string
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
string = self.flatten(asdict(self))
|
|
75
|
+
return string
|
|
76
|
+
|
|
77
|
+
def transform(self, match: re.Match):
|
|
50
78
|
"""
|
|
51
79
|
|
|
52
|
-
|
|
80
|
+
Transform match object into a new object of the same type.
|
|
53
81
|
|
|
54
82
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
groupdict = match.groupdict()
|
|
84
|
+
data = {key: value.format(**groupdict) for key, value in asdict(self).items()}
|
|
85
|
+
obj = self.__class__(**data)
|
|
86
|
+
return obj
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass
|
|
90
|
+
class Item:
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
Key-value pair
|
|
57
94
|
|
|
95
|
+
"""
|
|
96
|
+
key: Key
|
|
97
|
+
value: Key
|
|
58
98
|
|
|
59
99
|
@dataclass
|
|
60
|
-
class
|
|
100
|
+
class Mapper:
|
|
61
101
|
"""
|
|
62
102
|
|
|
63
|
-
|
|
103
|
+
Pattern-based, dictionary-like mapper.
|
|
64
104
|
Compiles a single regex pattern from a list of rules, and determines which rule matched.
|
|
65
|
-
It supports initialization from structured rule data, execution of a single
|
|
66
|
-
recursive
|
|
105
|
+
It supports initialization from structured rule data, execution of a single lookup pass, and
|
|
106
|
+
recursive lookups until a stable state is reached.
|
|
67
107
|
|
|
68
108
|
"""
|
|
69
|
-
|
|
109
|
+
PREFIX_GROUP = '__'
|
|
110
|
+
items: List[Item]
|
|
111
|
+
default: Any = None
|
|
112
|
+
is_recursive: bool = False
|
|
70
113
|
|
|
71
114
|
@cached_property
|
|
72
115
|
def pattern(self):
|
|
@@ -75,71 +118,90 @@ class Rewriter:
|
|
|
75
118
|
Provides a dynamically generated regex pattern based on the rules provided.
|
|
76
119
|
|
|
77
120
|
"""
|
|
78
|
-
patterns = [
|
|
79
|
-
|
|
80
|
-
|
|
121
|
+
patterns = [
|
|
122
|
+
MASK_NAMED.format(key=f'{self.PREFIX_GROUP}{i}', pattern=item.key.pattern)
|
|
123
|
+
for i, item in enumerate(self.items)
|
|
124
|
+
]
|
|
125
|
+
pattern = alt(*patterns)
|
|
81
126
|
return pattern
|
|
82
127
|
|
|
83
128
|
@cached_property
|
|
84
|
-
def
|
|
129
|
+
def rx(self):
|
|
85
130
|
"""
|
|
86
131
|
|
|
87
|
-
|
|
132
|
+
Regex object.
|
|
133
|
+
|
|
88
134
|
"""
|
|
135
|
+
return re.compile(self.pattern)
|
|
89
136
|
|
|
90
|
-
|
|
137
|
+
def get_default(self, key: Key):
|
|
138
|
+
if self.is_recursive:
|
|
139
|
+
return key
|
|
140
|
+
else:
|
|
141
|
+
return self.default
|
|
91
142
|
|
|
92
|
-
|
|
93
|
-
def rx(self):
|
|
143
|
+
def get(self, key: Key) -> Key:
|
|
94
144
|
"""
|
|
95
145
|
|
|
96
|
-
|
|
146
|
+
Use recursive or single lookup pass, depending on whether recursive lookups have been specified.
|
|
97
147
|
|
|
98
148
|
"""
|
|
99
|
-
|
|
149
|
+
if self.is_recursive:
|
|
150
|
+
return self.get_recursive(key)
|
|
151
|
+
else:
|
|
152
|
+
return self.get_one(key)
|
|
100
153
|
|
|
101
|
-
def
|
|
154
|
+
def get_one(self, key: Key):
|
|
102
155
|
"""
|
|
103
156
|
|
|
104
|
-
Single
|
|
105
|
-
|
|
157
|
+
Single lookup pass.
|
|
158
|
+
Lookup the source string based on the matching rule.
|
|
106
159
|
|
|
107
160
|
"""
|
|
108
161
|
|
|
109
|
-
match = self.rx.fullmatch(
|
|
162
|
+
match = self.rx.fullmatch(key.string)
|
|
110
163
|
|
|
111
164
|
if not match:
|
|
112
|
-
|
|
165
|
+
value = self.get_default(key)
|
|
166
|
+
logger.debug(f'No match for {key=}.')
|
|
167
|
+
else:
|
|
168
|
+
|
|
169
|
+
match_ids = {name: v for name, v in match.groupdict().items() if v}
|
|
170
|
+
rule_ids = {
|
|
171
|
+
int(id.removeprefix(self.PREFIX_GROUP))
|
|
172
|
+
for id in match_ids.keys() if id.startswith(self.PREFIX_GROUP)
|
|
173
|
+
}
|
|
113
174
|
|
|
114
|
-
|
|
115
|
-
|
|
175
|
+
if len(rule_ids) != 1:
|
|
176
|
+
msg = f'Multiple group matches: {rule_ids}'
|
|
177
|
+
raise ValueError(msg)
|
|
116
178
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
raise ValueError(msg)
|
|
179
|
+
rule_id = next(iter(rule_ids))
|
|
180
|
+
rule = self.items[rule_id]
|
|
120
181
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
182
|
+
if isinstance(rule.value, Key):
|
|
183
|
+
value = rule.value.transform(match)
|
|
184
|
+
else:
|
|
185
|
+
value = rule.value
|
|
124
186
|
|
|
125
|
-
|
|
187
|
+
logger.debug(f'Matched using {rule_id=}: {key=} → {value=}')
|
|
126
188
|
|
|
127
|
-
return
|
|
189
|
+
return value
|
|
128
190
|
|
|
129
|
-
def
|
|
191
|
+
def get_recursive(self, key: Key) -> Key:
|
|
130
192
|
"""
|
|
131
193
|
|
|
132
|
-
|
|
194
|
+
Lookup the provided text by continuously applying lookup rules until no changes are made
|
|
133
195
|
or a circular loop is detected.
|
|
134
196
|
|
|
135
197
|
"""
|
|
136
198
|
history = []
|
|
137
|
-
previous =
|
|
199
|
+
previous = key
|
|
138
200
|
|
|
139
201
|
def get_history_str():
|
|
140
|
-
return '
|
|
202
|
+
return join(history, sep=' → ')
|
|
141
203
|
|
|
142
|
-
with logger.span(f'
|
|
204
|
+
with logger.span(f'Matching {key=}...'):
|
|
143
205
|
while True:
|
|
144
206
|
if previous in history:
|
|
145
207
|
history.append(previous)
|
|
@@ -150,7 +212,7 @@ class Rewriter:
|
|
|
150
212
|
|
|
151
213
|
new = previous
|
|
152
214
|
|
|
153
|
-
new = self.
|
|
215
|
+
new = self.get_one(new)
|
|
154
216
|
|
|
155
217
|
if new == previous:
|
|
156
218
|
break
|
|
@@ -158,18 +220,13 @@ class Rewriter:
|
|
|
158
220
|
previous = new
|
|
159
221
|
|
|
160
222
|
if len(history) == 1:
|
|
161
|
-
history_str = 'No
|
|
223
|
+
history_str = 'No matching performed.'
|
|
162
224
|
else:
|
|
163
225
|
history_str = get_history_str()
|
|
164
|
-
logger.debug(f'Finished
|
|
226
|
+
logger.debug(f'Finished matching: {history_str}')
|
|
165
227
|
|
|
166
228
|
return previous
|
|
167
229
|
|
|
168
|
-
@classmethod
|
|
169
|
-
def from_data(cls, data):
|
|
170
|
-
rules = [Rewrite(*pair) for pair in data.items()]
|
|
171
|
-
self = cls(rules=rules)
|
|
172
|
-
return self
|
|
173
|
-
|
|
174
|
-
|
|
175
230
|
|
|
231
|
+
if __name__ == '__main__':
|
|
232
|
+
...
|
|
@@ -3,7 +3,7 @@ from datetime import datetime
|
|
|
3
3
|
from fnmatch import fnmatch
|
|
4
4
|
from functools import cached_property
|
|
5
5
|
from itertools import chain
|
|
6
|
-
from typing import List, Dict
|
|
6
|
+
from typing import List, Dict, Any, Callable, Optional
|
|
7
7
|
|
|
8
8
|
from fmtr.tools.constants import Constants
|
|
9
9
|
from fmtr.tools.path_tools import Path
|
|
@@ -18,7 +18,6 @@ class SetupPaths(FromCallerMixin):
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
def __init__(self, path=None, org=Constants.ORG_NAME):
|
|
21
|
-
|
|
22
21
|
"""
|
|
23
22
|
|
|
24
23
|
Use calling module path as default path, if not otherwise specified.
|
|
@@ -31,15 +30,30 @@ class SetupPaths(FromCallerMixin):
|
|
|
31
30
|
self.repo = Path(path)
|
|
32
31
|
|
|
33
32
|
@property
|
|
34
|
-
def readme(self):
|
|
33
|
+
def readme(self) -> Path:
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
Path of the README file.
|
|
37
|
+
|
|
38
|
+
"""
|
|
35
39
|
return self.repo / 'README.md'
|
|
36
40
|
|
|
37
41
|
@property
|
|
38
|
-
def version(self):
|
|
42
|
+
def version(self) -> Path:
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
Path of the version file
|
|
46
|
+
|
|
47
|
+
"""
|
|
39
48
|
return self.path / Constants.FILENAME_VERSION
|
|
40
49
|
|
|
41
50
|
@cached_property
|
|
42
|
-
def path(self):
|
|
51
|
+
def path(self) -> Path:
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
Infer the package path. It should be the only non-excluded package in the repo/org Path.
|
|
55
|
+
|
|
56
|
+
"""
|
|
43
57
|
|
|
44
58
|
if self.is_namespace:
|
|
45
59
|
base = self.org
|
|
@@ -61,7 +75,12 @@ class SetupPaths(FromCallerMixin):
|
|
|
61
75
|
return package
|
|
62
76
|
|
|
63
77
|
@property
|
|
64
|
-
def org(self):
|
|
78
|
+
def org(self) -> bool | Path:
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
Get the org path, i.e. the namespace parent directory.
|
|
82
|
+
|
|
83
|
+
"""
|
|
65
84
|
if not self.org_name:
|
|
66
85
|
return False
|
|
67
86
|
org = self.repo / self.org_name
|
|
@@ -70,7 +89,12 @@ class SetupPaths(FromCallerMixin):
|
|
|
70
89
|
return org
|
|
71
90
|
|
|
72
91
|
@property
|
|
73
|
-
def entrypoints(self):
|
|
92
|
+
def entrypoints(self) -> Path:
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
Path of entrypoints sub-package.
|
|
96
|
+
|
|
97
|
+
"""
|
|
74
98
|
return self.path / Constants.ENTRYPOINTS_DIR
|
|
75
99
|
|
|
76
100
|
@property
|
|
@@ -83,6 +107,11 @@ class SetupPaths(FromCallerMixin):
|
|
|
83
107
|
|
|
84
108
|
|
|
85
109
|
class Setup(FromCallerMixin):
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
Abstract canonical pacakge setup for setuptools.
|
|
113
|
+
|
|
114
|
+
"""
|
|
86
115
|
AUTHOR = 'Frontmatter'
|
|
87
116
|
AUTHOR_EMAIL = 'innovative.fowler@mask.pro.fmtr.dev'
|
|
88
117
|
|
|
@@ -93,8 +122,12 @@ class Setup(FromCallerMixin):
|
|
|
93
122
|
ENTRYPOINT_FUNC_NAME = 'main'
|
|
94
123
|
|
|
95
124
|
def __init__(self, dependencies, paths=None, org=Constants.ORG_NAME, client=None, do_setup=True, **kwargs):
|
|
125
|
+
"""
|
|
96
126
|
|
|
127
|
+
First check if commandline arguments for requirements output exist. If so, print them and return early.
|
|
128
|
+
Otherwise, continue generating data to pass to setuptools.
|
|
97
129
|
|
|
130
|
+
"""
|
|
98
131
|
self.kwargs = kwargs
|
|
99
132
|
|
|
100
133
|
if type(dependencies) is not Dependencies:
|
|
@@ -115,11 +148,15 @@ class Setup(FromCallerMixin):
|
|
|
115
148
|
|
|
116
149
|
self.client = client
|
|
117
150
|
|
|
118
|
-
|
|
119
151
|
if do_setup:
|
|
120
152
|
self.setup()
|
|
121
153
|
|
|
122
|
-
def get_requirements_extras(self):
|
|
154
|
+
def get_requirements_extras(self) -> Optional[List[str]]:
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
Get list of extras from command line arguments.
|
|
158
|
+
|
|
159
|
+
"""
|
|
123
160
|
if self.REQUIREMENTS_ARG not in sys.argv:
|
|
124
161
|
return None
|
|
125
162
|
|
|
@@ -128,6 +165,11 @@ class Setup(FromCallerMixin):
|
|
|
128
165
|
return extras
|
|
129
166
|
|
|
130
167
|
def print_requirements(self):
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
Output flat list of requirements for specified extras
|
|
171
|
+
|
|
172
|
+
"""
|
|
131
173
|
reqs = []
|
|
132
174
|
reqs += self.dependencies.install
|
|
133
175
|
|
|
@@ -137,12 +179,17 @@ class Setup(FromCallerMixin):
|
|
|
137
179
|
print(reqs)
|
|
138
180
|
|
|
139
181
|
@property
|
|
140
|
-
def console_scripts(self):
|
|
182
|
+
def console_scripts(self) -> List[str]:
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
Generate console scripts for any modules in the `entrypoints` sub-package.
|
|
186
|
+
|
|
187
|
+
"""
|
|
141
188
|
|
|
142
189
|
if not self.paths.entrypoints.exists():
|
|
143
|
-
return
|
|
190
|
+
return []
|
|
144
191
|
|
|
145
|
-
names_mods = [path.stem for path in self.paths.entrypoints.iterdir() if path.is_file() and
|
|
192
|
+
names_mods = [path.stem for path in self.paths.entrypoints.iterdir() if path.is_file() and path.name != Constants.INIT_FILENAME]
|
|
146
193
|
command_prefix = self.name.replace('.', self.ENTRYPOINT_COMMAND_SEP)
|
|
147
194
|
command_suffixes = [name_mod.replace(self.ENTRYPOINT_FUNCTION_SEP, self.ENTRYPOINT_COMMAND_SEP) for name_mod in names_mods]
|
|
148
195
|
commands = [f'{command_prefix}-{command_suffix}' for command_suffix in command_suffixes]
|
|
@@ -153,35 +200,63 @@ class Setup(FromCallerMixin):
|
|
|
153
200
|
return console_scripts
|
|
154
201
|
|
|
155
202
|
@property
|
|
156
|
-
def name(self):
|
|
203
|
+
def name(self) -> str:
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
Full library name
|
|
207
|
+
|
|
208
|
+
"""
|
|
157
209
|
if self.paths.is_namespace:
|
|
158
210
|
return f'{self.paths.org_name}.{self.paths.name}'
|
|
159
211
|
return self.paths.name
|
|
160
212
|
|
|
161
213
|
@property
|
|
162
|
-
def author(self):
|
|
214
|
+
def author(self) -> str:
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
Create appropriate author string
|
|
218
|
+
|
|
219
|
+
"""
|
|
163
220
|
if self.client:
|
|
164
221
|
return f'{self.AUTHOR} on behalf of {self.client}'
|
|
165
222
|
return self.AUTHOR
|
|
166
223
|
|
|
167
224
|
@property
|
|
168
|
-
def copyright(self):
|
|
225
|
+
def copyright(self) -> str:
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
Create appropriate copyright string
|
|
229
|
+
|
|
230
|
+
"""
|
|
169
231
|
if self.client:
|
|
170
232
|
return self.client
|
|
171
233
|
return self.AUTHOR
|
|
172
234
|
|
|
173
235
|
@property
|
|
174
|
-
def long_description(self):
|
|
236
|
+
def long_description(self) -> str:
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
Read in README.md
|
|
175
240
|
|
|
241
|
+
"""
|
|
176
242
|
return self.paths.readme.read_text()
|
|
177
243
|
|
|
178
244
|
@property
|
|
179
|
-
def version(self):
|
|
245
|
+
def version(self) -> str:
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
Read in the version string from file
|
|
249
|
+
|
|
250
|
+
"""
|
|
180
251
|
return self.paths.version.read_text().strip()
|
|
181
252
|
|
|
182
253
|
@property
|
|
183
|
-
def find(self):
|
|
254
|
+
def find(self) -> Callable:
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
Use the appropriate package finding function from setuptools
|
|
184
258
|
|
|
259
|
+
"""
|
|
185
260
|
from fmtr.tools import setup
|
|
186
261
|
|
|
187
262
|
if self.paths.is_namespace:
|
|
@@ -190,13 +265,23 @@ class Setup(FromCallerMixin):
|
|
|
190
265
|
return setup.find_packages
|
|
191
266
|
|
|
192
267
|
@property
|
|
193
|
-
def packages(self):
|
|
268
|
+
def packages(self) -> List[str]:
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
Fetch list of packages excluding canonical paths
|
|
272
|
+
|
|
273
|
+
"""
|
|
194
274
|
excludes = list(Constants.PACKAGE_EXCLUDE_DIRS) + [f'{name}.*' for name in Constants.PACKAGE_EXCLUDE_DIRS if '*' not in name]
|
|
195
275
|
packages = self.find(where=str(self.paths.repo), exclude=excludes)
|
|
196
276
|
return packages
|
|
197
277
|
|
|
198
278
|
@property
|
|
199
279
|
def package_dir(self):
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
Needs to be relative apparently as absolute paths break during packaging
|
|
283
|
+
|
|
284
|
+
"""
|
|
200
285
|
if self.paths.is_namespace:
|
|
201
286
|
return {'': '.'}
|
|
202
287
|
else:
|
|
@@ -204,14 +289,29 @@ class Setup(FromCallerMixin):
|
|
|
204
289
|
|
|
205
290
|
@property
|
|
206
291
|
def package_data(self):
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
Default package data is just the version file
|
|
295
|
+
|
|
296
|
+
"""
|
|
207
297
|
return {self.name: [Constants.FILENAME_VERSION]}
|
|
208
298
|
|
|
209
299
|
@property
|
|
210
|
-
def url(self):
|
|
211
|
-
|
|
300
|
+
def url(self) -> str:
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
Default to GitHub URL
|
|
304
|
+
|
|
305
|
+
"""
|
|
306
|
+
return f'https://github.com/{self.org}/{self.name}'
|
|
212
307
|
|
|
213
308
|
@property
|
|
214
|
-
def data(self):
|
|
309
|
+
def data(self) -> Dict[str, Any]:
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
Generate data for use by setuptools
|
|
313
|
+
|
|
314
|
+
"""
|
|
215
315
|
data = dict(
|
|
216
316
|
name=self.name,
|
|
217
317
|
version=self.version,
|
|
@@ -233,13 +333,30 @@ class Setup(FromCallerMixin):
|
|
|
233
333
|
return data
|
|
234
334
|
|
|
235
335
|
def setup(self):
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
Call setuptools.setup using generated data
|
|
339
|
+
|
|
340
|
+
"""
|
|
236
341
|
|
|
237
342
|
from fmtr.tools import setup
|
|
238
343
|
|
|
239
344
|
return setup.setup_setuptools(**self.data)
|
|
240
345
|
|
|
346
|
+
def __repr__(self) -> str:
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
Show library name
|
|
350
|
+
|
|
351
|
+
"""
|
|
352
|
+
return f'{self.__class__.__name__}("{self.name}")'
|
|
241
353
|
|
|
242
354
|
class Tools:
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
Helper for downstream libraries to specify lists of `fmtr.tools` extras
|
|
358
|
+
|
|
359
|
+
"""
|
|
243
360
|
MASK = f'{Constants.LIBRARY_NAME}[{{extras}}]'
|
|
244
361
|
|
|
245
362
|
def __init__(self, *extras):
|
|
@@ -261,7 +378,7 @@ class Dependencies:
|
|
|
261
378
|
def resolve_values(self, key) -> List[str]:
|
|
262
379
|
"""
|
|
263
380
|
|
|
264
|
-
Flatten a list of
|
|
381
|
+
Flatten a list of dependencies.
|
|
265
382
|
|
|
266
383
|
"""
|
|
267
384
|
values_resolved = []
|
|
@@ -290,7 +407,12 @@ class Dependencies:
|
|
|
290
407
|
return resolved
|
|
291
408
|
|
|
292
409
|
@cached_property
|
|
293
|
-
def install(self):
|
|
410
|
+
def install(self) -> List[str]:
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
Get install_requires
|
|
414
|
+
|
|
415
|
+
"""
|
|
294
416
|
if self.INSTALL in self.dependencies:
|
|
295
417
|
return self.resolve_values(self.INSTALL)
|
|
296
418
|
else:
|
|
@@ -298,26 +420,4 @@ class Dependencies:
|
|
|
298
420
|
|
|
299
421
|
|
|
300
422
|
if __name__ == '__main__':
|
|
301
|
-
|
|
302
|
-
install=['version', 'yaml'],
|
|
303
|
-
|
|
304
|
-
yaml=['yamlscript', 'pyyaml'],
|
|
305
|
-
logging=['logfire', 'version'],
|
|
306
|
-
version=['semver', 'av'],
|
|
307
|
-
av=['av']
|
|
308
|
-
# Add the rest of your dependencies...
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
ds
|
|
312
|
-
|
|
313
|
-
setup = Setup(
|
|
314
|
-
# client='Acme',
|
|
315
|
-
dependencies=ds,
|
|
316
|
-
description='some tools test',
|
|
317
|
-
console_scripts=dict(
|
|
318
|
-
cache_hfh='console_script_tools',
|
|
319
|
-
test=None,
|
|
320
|
-
)
|
|
321
|
-
)
|
|
322
|
-
data = setup.get_data_setup()
|
|
323
|
-
data
|
|
423
|
+
...
|
fmtr/tools/version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.3.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmtr.tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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/tools
|
|
6
6
|
Author: Frontmatter
|
|
@@ -130,60 +130,60 @@ Requires-Dist: logfire[httpx]; extra == "http"
|
|
|
130
130
|
Provides-Extra: setup
|
|
131
131
|
Requires-Dist: setuptools; extra == "setup"
|
|
132
132
|
Provides-Extra: all
|
|
133
|
-
Requires-Dist: uvicorn[standard]; extra == "all"
|
|
134
|
-
Requires-Dist: google-auth-httplib2; extra == "all"
|
|
135
|
-
Requires-Dist: html2text; extra == "all"
|
|
136
|
-
Requires-Dist: distributed; extra == "all"
|
|
137
|
-
Requires-Dist: tabulate; extra == "all"
|
|
138
|
-
Requires-Dist: pydantic; extra == "all"
|
|
139
|
-
Requires-Dist: openpyxl; extra == "all"
|
|
140
|
-
Requires-Dist: httpx; extra == "all"
|
|
141
133
|
Requires-Dist: tokenizers; extra == "all"
|
|
142
|
-
Requires-Dist: fastapi; extra == "all"
|
|
143
|
-
Requires-Dist: logfire; extra == "all"
|
|
144
|
-
Requires-Dist: ollama; extra == "all"
|
|
145
|
-
Requires-Dist: flet[all]; extra == "all"
|
|
146
134
|
Requires-Dist: flet-webview; extra == "all"
|
|
135
|
+
Requires-Dist: logfire; extra == "all"
|
|
147
136
|
Requires-Dist: flet-video; extra == "all"
|
|
148
|
-
Requires-Dist:
|
|
149
|
-
Requires-Dist:
|
|
150
|
-
Requires-Dist:
|
|
151
|
-
Requires-Dist: docker; extra == "all"
|
|
137
|
+
Requires-Dist: logfire[httpx]; extra == "all"
|
|
138
|
+
Requires-Dist: pydantic-settings; extra == "all"
|
|
139
|
+
Requires-Dist: ollama; extra == "all"
|
|
152
140
|
Requires-Dist: setuptools; extra == "all"
|
|
153
|
-
Requires-Dist:
|
|
154
|
-
Requires-Dist:
|
|
155
|
-
Requires-Dist:
|
|
156
|
-
Requires-Dist:
|
|
141
|
+
Requires-Dist: docker; extra == "all"
|
|
142
|
+
Requires-Dist: regex; extra == "all"
|
|
143
|
+
Requires-Dist: json_repair; extra == "all"
|
|
144
|
+
Requires-Dist: pandas; extra == "all"
|
|
145
|
+
Requires-Dist: google-api-python-client; extra == "all"
|
|
146
|
+
Requires-Dist: google-auth-httplib2; extra == "all"
|
|
147
|
+
Requires-Dist: httpx; extra == "all"
|
|
148
|
+
Requires-Dist: tabulate; extra == "all"
|
|
149
|
+
Requires-Dist: uvicorn[standard]; extra == "all"
|
|
150
|
+
Requires-Dist: bokeh; extra == "all"
|
|
151
|
+
Requires-Dist: peft; extra == "all"
|
|
152
|
+
Requires-Dist: html2text; extra == "all"
|
|
153
|
+
Requires-Dist: flet[all]; extra == "all"
|
|
154
|
+
Requires-Dist: contexttimer; extra == "all"
|
|
155
|
+
Requires-Dist: pymupdf4llm; extra == "all"
|
|
156
|
+
Requires-Dist: openpyxl; extra == "all"
|
|
157
|
+
Requires-Dist: huggingface_hub; extra == "all"
|
|
158
|
+
Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
|
|
159
|
+
Requires-Dist: pymupdf; extra == "all"
|
|
160
|
+
Requires-Dist: google-auth; extra == "all"
|
|
161
|
+
Requires-Dist: pydantic; extra == "all"
|
|
162
|
+
Requires-Dist: dask[bag]; extra == "all"
|
|
163
|
+
Requires-Dist: torchaudio; extra == "all"
|
|
157
164
|
Requires-Dist: sentence_transformers; extra == "all"
|
|
165
|
+
Requires-Dist: dnspython[doh]; extra == "all"
|
|
158
166
|
Requires-Dist: semver; extra == "all"
|
|
159
|
-
Requires-Dist:
|
|
160
|
-
Requires-Dist:
|
|
167
|
+
Requires-Dist: filetype; extra == "all"
|
|
168
|
+
Requires-Dist: pytest-cov; extra == "all"
|
|
161
169
|
Requires-Dist: sre_yield; extra == "all"
|
|
162
|
-
Requires-Dist: regex; extra == "all"
|
|
163
170
|
Requires-Dist: openai; extra == "all"
|
|
164
|
-
Requires-Dist:
|
|
171
|
+
Requires-Dist: transformers[sentencepiece]; extra == "all"
|
|
172
|
+
Requires-Dist: distributed; extra == "all"
|
|
173
|
+
Requires-Dist: torchvision; extra == "all"
|
|
174
|
+
Requires-Dist: google-auth-oauthlib; extra == "all"
|
|
175
|
+
Requires-Dist: Unidecode; extra == "all"
|
|
176
|
+
Requires-Dist: httpx_retries; extra == "all"
|
|
177
|
+
Requires-Dist: tinynetrc; extra == "all"
|
|
165
178
|
Requires-Dist: yamlscript; extra == "all"
|
|
166
|
-
Requires-Dist: bokeh; extra == "all"
|
|
167
|
-
Requires-Dist: contexttimer; extra == "all"
|
|
168
|
-
Requires-Dist: json_repair; extra == "all"
|
|
169
|
-
Requires-Dist: peft; extra == "all"
|
|
170
|
-
Requires-Dist: google-api-python-client; extra == "all"
|
|
171
|
-
Requires-Dist: deepmerge; extra == "all"
|
|
172
|
-
Requires-Dist: torchaudio; extra == "all"
|
|
173
|
-
Requires-Dist: google-auth; extra == "all"
|
|
174
179
|
Requires-Dist: pyyaml; extra == "all"
|
|
175
|
-
Requires-Dist: pydantic-ai[logfire,openai]; extra == "all"
|
|
176
180
|
Requires-Dist: appdirs; extra == "all"
|
|
177
|
-
Requires-Dist:
|
|
178
|
-
Requires-Dist: pandas; extra == "all"
|
|
179
|
-
Requires-Dist: diskcache; extra == "all"
|
|
180
|
-
Requires-Dist: logfire[httpx]; extra == "all"
|
|
181
|
-
Requires-Dist: filetype; extra == "all"
|
|
181
|
+
Requires-Dist: logfire[fastapi]; extra == "all"
|
|
182
182
|
Requires-Dist: pydevd-pycharm; extra == "all"
|
|
183
|
-
Requires-Dist:
|
|
184
|
-
Requires-Dist:
|
|
185
|
-
Requires-Dist:
|
|
186
|
-
Requires-Dist:
|
|
183
|
+
Requires-Dist: deepmerge; extra == "all"
|
|
184
|
+
Requires-Dist: faker; extra == "all"
|
|
185
|
+
Requires-Dist: fastapi; extra == "all"
|
|
186
|
+
Requires-Dist: diskcache; extra == "all"
|
|
187
187
|
Dynamic: author
|
|
188
188
|
Dynamic: author-email
|
|
189
189
|
Dynamic: description
|
|
@@ -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=
|
|
33
|
+
fmtr/tools/pattern_tools.py,sha256=GzdhKt-nIHuKCGI9y3aGUaD5k9thbqbA9UXJoPPIcIY,5328
|
|
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,7 +44,7 @@ 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=
|
|
47
|
+
fmtr/tools/version,sha256=WSltI9YjzgrfdnXSIVboOxJIyFCBNaZd2KnjjEl-lKg,5
|
|
48
48
|
fmtr/tools/version_tools.py,sha256=yNs_CGqWpqE4jbK9wsPIi14peJVXYbhIcMqHAFOw3yE,1480
|
|
49
49
|
fmtr/tools/yaml_tools.py,sha256=9kuYChqJelWQIjGlSnK4iDdOWWH06P0gp9jIcRrC3UI,1903
|
|
50
50
|
fmtr/tools/ai_tools/__init__.py,sha256=JZrLuOFNV1A3wvJgonxOgz_4WS-7MfCuowGWA5uYCjs,372
|
|
@@ -53,7 +53,7 @@ fmtr/tools/ai_tools/inference_tools.py,sha256=2UP2gXEyOJUjyyV6zmFIYmIxUsh1rXkRH0
|
|
|
53
53
|
fmtr/tools/dns_tools/__init__.py,sha256=PwHxnpiy6_isQfUmz_5V1hL0dcPaA6ItqvoGWW8MOfk,222
|
|
54
54
|
fmtr/tools/dns_tools/client.py,sha256=omHdk9bA_8u2-VMQhh0c9r9e-oG4mZ0MWA9lfbtSEIc,2371
|
|
55
55
|
fmtr/tools/dns_tools/dm.py,sha256=mvXacq6QJ86G0S0tkzJFhU7bOaSJytvsMNlxs5X9hfE,2236
|
|
56
|
-
fmtr/tools/dns_tools/server.py,sha256=
|
|
56
|
+
fmtr/tools/dns_tools/server.py,sha256=X6-4pC8u5BG_BnOHTPcmkT3455Cd10CddwrDUYrGUOw,2353
|
|
57
57
|
fmtr/tools/entrypoints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
58
|
fmtr/tools/entrypoints/cache_hfh.py,sha256=fQNs4J9twQuZH_Yj98-oOvEX7-LrSUP3kO8nzw2HrHs,60
|
|
59
59
|
fmtr/tools/entrypoints/ep_test.py,sha256=B8HfWISfSgw_xVX475CbJGh_QnpOe9MH65H8qGjTWbY,46
|
|
@@ -64,7 +64,7 @@ fmtr/tools/path_tools/app_path_tools.py,sha256=JrJvtTDd_gkCKcZtBCDTMktsM77PZwGV_
|
|
|
64
64
|
fmtr/tools/path_tools/path_tools.py,sha256=8WBzNctpds5tVT1-FcizAORrBCGlkUbPcfOel-Js7ps,7878
|
|
65
65
|
fmtr/tools/path_tools/type_path_tools.py,sha256=Zgs-ek-GXRKDIlVDGdg3muB0PIxTg2ba0NeHw6y8FWQ,40
|
|
66
66
|
fmtr/tools/setup_tools/__init__.py,sha256=fUCjzyE4JBPEOZhC4B--VPj_eOCkQb1QG5PIgiGj03U,386
|
|
67
|
-
fmtr/tools/setup_tools/setup_tools.py,sha256=
|
|
67
|
+
fmtr/tools/setup_tools/setup_tools.py,sha256=7Z6jlU6UE8P4cntGQ_hJR7hGvoqwh15xzZY63cnxG7E,10363
|
|
68
68
|
fmtr/tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
69
|
fmtr/tools/tests/conftest.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
70
|
fmtr/tools/tests/helpers.py,sha256=N5sf9YoZV93a7tf_UxpLeyQ9vp6Ec0teNIimFDvc054,1091
|
|
@@ -73,9 +73,9 @@ fmtr/tools/tests/test_environment.py,sha256=iHaiMQfECYZPkPKwfuIZV9uHuWe3aE-p_dN_
|
|
|
73
73
|
fmtr/tools/tests/test_json.py,sha256=IeSP4ziPvRcmS8kq7k9tHonC9rN5YYq9GSNT2ul6Msk,287
|
|
74
74
|
fmtr/tools/tests/test_path.py,sha256=AkZQa6_8BQ-VaCyL_J-iKmdf2ZaM-xFYR37Kun3k4_g,2188
|
|
75
75
|
fmtr/tools/tests/test_yaml.py,sha256=jc0TwwKu9eC0LvFGNMERdgBue591xwLxYXFbtsRwXVM,287
|
|
76
|
-
fmtr_tools-1.
|
|
77
|
-
fmtr_tools-1.
|
|
78
|
-
fmtr_tools-1.
|
|
79
|
-
fmtr_tools-1.
|
|
80
|
-
fmtr_tools-1.
|
|
81
|
-
fmtr_tools-1.
|
|
76
|
+
fmtr_tools-1.3.0.dist-info/licenses/LICENSE,sha256=FW9aa6vVN5IjRQWLT43hs4_koYSmpcbIovlKeAJ0_cI,10757
|
|
77
|
+
fmtr_tools-1.3.0.dist-info/METADATA,sha256=-R7R2iLGtkCyDxaQtfFl2gjeiyw6NmZEiG2OPxcqM0Q,16025
|
|
78
|
+
fmtr_tools-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
79
|
+
fmtr_tools-1.3.0.dist-info/entry_points.txt,sha256=fSQrDGNctdQXbUxpMWYVfVQ0mhZMDyaEDG3D3a0zOSc,278
|
|
80
|
+
fmtr_tools-1.3.0.dist-info/top_level.txt,sha256=LXem9xCgNOD72tE2gRKESdiQTL902mfFkwWb6-dlwEE,5
|
|
81
|
+
fmtr_tools-1.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|