toolslm 0.3.4__py3-none-any.whl → 0.3.5__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.
- toolslm/__init__.py +1 -1
- toolslm/_modidx.py +5 -3
- toolslm/funccall.py +54 -24
- toolslm/md_hier.py +35 -6
- {toolslm-0.3.4.dist-info → toolslm-0.3.5.dist-info}/METADATA +1 -1
- toolslm-0.3.5.dist-info/RECORD +13 -0
- toolslm-0.3.4.dist-info/RECORD +0 -13
- {toolslm-0.3.4.dist-info → toolslm-0.3.5.dist-info}/WHEEL +0 -0
- {toolslm-0.3.4.dist-info → toolslm-0.3.5.dist-info}/entry_points.txt +0 -0
- {toolslm-0.3.4.dist-info → toolslm-0.3.5.dist-info}/licenses/LICENSE +0 -0
- {toolslm-0.3.4.dist-info → toolslm-0.3.5.dist-info}/top_level.txt +0 -0
toolslm/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.5"
|
toolslm/_modidx.py
CHANGED
|
@@ -14,11 +14,10 @@ d = { 'settings': { 'branch': 'main',
|
|
|
14
14
|
'toolslm.download.read_html': ('download.html#read_html', 'toolslm/download.py'),
|
|
15
15
|
'toolslm.download.read_md': ('download.html#read_md', 'toolslm/download.py'),
|
|
16
16
|
'toolslm.download.split_url': ('download.html#split_url', 'toolslm/download.py')},
|
|
17
|
-
'toolslm.funccall': { 'toolslm.funccall.
|
|
17
|
+
'toolslm.funccall': { 'toolslm.funccall._coerce_inputs': ('funccall.html#_coerce_inputs', 'toolslm/funccall.py'),
|
|
18
18
|
'toolslm.funccall._copy_loc': ('funccall.html#_copy_loc', 'toolslm/funccall.py'),
|
|
19
19
|
'toolslm.funccall._get_nested_schema': ('funccall.html#_get_nested_schema', 'toolslm/funccall.py'),
|
|
20
20
|
'toolslm.funccall._handle_container': ('funccall.html#_handle_container', 'toolslm/funccall.py'),
|
|
21
|
-
'toolslm.funccall._handle_type': ('funccall.html#_handle_type', 'toolslm/funccall.py'),
|
|
22
21
|
'toolslm.funccall._is_container': ('funccall.html#_is_container', 'toolslm/funccall.py'),
|
|
23
22
|
'toolslm.funccall._is_parameterized': ('funccall.html#_is_parameterized', 'toolslm/funccall.py'),
|
|
24
23
|
'toolslm.funccall._param': ('funccall.html#_param', 'toolslm/funccall.py'),
|
|
@@ -29,7 +28,10 @@ d = { 'settings': { 'branch': 'main',
|
|
|
29
28
|
'toolslm.funccall.call_func_async': ('funccall.html#call_func_async', 'toolslm/funccall.py'),
|
|
30
29
|
'toolslm.funccall.get_schema': ('funccall.html#get_schema', 'toolslm/funccall.py'),
|
|
31
30
|
'toolslm.funccall.mk_ns': ('funccall.html#mk_ns', 'toolslm/funccall.py'),
|
|
32
|
-
'toolslm.funccall.
|
|
31
|
+
'toolslm.funccall.mk_param': ('funccall.html#mk_param', 'toolslm/funccall.py'),
|
|
32
|
+
'toolslm.funccall.mk_tool': ('funccall.html#mk_tool', 'toolslm/funccall.py'),
|
|
33
|
+
'toolslm.funccall.python': ('funccall.html#python', 'toolslm/funccall.py'),
|
|
34
|
+
'toolslm.funccall.schema2sig': ('funccall.html#schema2sig', 'toolslm/funccall.py')},
|
|
33
35
|
'toolslm.md_hier': {},
|
|
34
36
|
'toolslm.shell': { 'toolslm.shell.TerminalInteractiveShell.run_cell': ( 'shell.html#terminalinteractiveshell.run_cell',
|
|
35
37
|
'toolslm/shell.py'),
|
toolslm/funccall.py
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../01_funccall.ipynb.
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
|
-
__all__ = ['empty', '
|
|
4
|
+
__all__ = ['empty', 'get_schema', 'python', 'mk_ns', 'call_func', 'call_func_async', 'mk_param', 'schema2sig', 'mk_tool']
|
|
5
5
|
|
|
6
6
|
# %% ../01_funccall.ipynb
|
|
7
|
-
import inspect
|
|
7
|
+
import inspect, json
|
|
8
8
|
from collections import abc
|
|
9
9
|
from fastcore.utils import *
|
|
10
10
|
from fastcore.docments import docments
|
|
11
|
-
from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union
|
|
11
|
+
from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union, Any
|
|
12
12
|
from types import UnionType
|
|
13
|
+
from typing import get_type_hints
|
|
14
|
+
from inspect import Parameter, Signature
|
|
15
|
+
from decimal import Decimal
|
|
16
|
+
from uuid import UUID
|
|
13
17
|
|
|
14
18
|
# %% ../01_funccall.ipynb
|
|
15
19
|
empty = inspect.Parameter.empty
|
|
@@ -40,19 +44,6 @@ def _param(name, info):
|
|
|
40
44
|
if info.default is not empty: pschema["default"] = info.default
|
|
41
45
|
return pschema
|
|
42
46
|
|
|
43
|
-
# %% ../01_funccall.ipynb
|
|
44
|
-
custom_types = {Path}
|
|
45
|
-
|
|
46
|
-
def _handle_type(t, defs):
|
|
47
|
-
"Handle a single type, creating nested schemas if necessary"
|
|
48
|
-
if t is NoneType: return {'type': 'null'}
|
|
49
|
-
if t in custom_types: return {'type':'string', 'format':t.__name__}
|
|
50
|
-
if t in (dict, list, tuple, set): return {'type': _types(t)[0]}
|
|
51
|
-
if isinstance(t, type) and not issubclass(t, (int, float, str, bool)) or inspect.isfunction(t):
|
|
52
|
-
defs[t.__name__] = _get_nested_schema(t)
|
|
53
|
-
return {'$ref': f'#/$defs/{t.__name__}'}
|
|
54
|
-
return {'type': _types(t)[0]}
|
|
55
|
-
|
|
56
47
|
# %% ../01_funccall.ipynb
|
|
57
48
|
def _is_container(t):
|
|
58
49
|
"Check if type is a container (list, dict, tuple, set, Union)"
|
|
@@ -123,14 +114,9 @@ def get_schema(f:Union[callable,dict], pname='input_schema')->dict:
|
|
|
123
114
|
assert desc, "Docstring missing!"
|
|
124
115
|
d = docments(f, full=True)
|
|
125
116
|
ret = d.pop('return')
|
|
126
|
-
if ret.anno is not empty: desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
|
|
117
|
+
if (ret.anno is not empty) and (ret.anno is not None): desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
|
|
127
118
|
return {"name": f.__name__, "description": desc, pname: schema}
|
|
128
119
|
|
|
129
|
-
# %% ../01_funccall.ipynb
|
|
130
|
-
def PathArg(
|
|
131
|
-
path: str # A filesystem path
|
|
132
|
-
): return Path(path)
|
|
133
|
-
|
|
134
120
|
# %% ../01_funccall.ipynb
|
|
135
121
|
import ast, time, signal, traceback
|
|
136
122
|
from fastcore.utils import *
|
|
@@ -193,14 +179,26 @@ def mk_ns(fs):
|
|
|
193
179
|
elif callable(o) and hasattr(o, '__name__'): merged |= {o.__name__: o}
|
|
194
180
|
return merged
|
|
195
181
|
|
|
182
|
+
# %% ../01_funccall.ipynb
|
|
183
|
+
def _coerce_inputs(func, inputs):
|
|
184
|
+
"Coerce inputs based on function type annotations"
|
|
185
|
+
hints = get_type_hints(func) if hasattr(func, '__annotations__') else {}
|
|
186
|
+
res = {}
|
|
187
|
+
for k,v in inputs.items():
|
|
188
|
+
ann = hints.get(k)
|
|
189
|
+
if ann in custom_types: res[k] = ann(v)
|
|
190
|
+
elif isinstance(v, dict) and callable(ann): res[k] = ann(**v)
|
|
191
|
+
else: res[k] = v
|
|
192
|
+
return res
|
|
193
|
+
|
|
196
194
|
# %% ../01_funccall.ipynb
|
|
197
195
|
def call_func(fc_name, fc_inputs, ns, raise_on_err=True):
|
|
198
196
|
"Call the function `fc_name` with the given `fc_inputs` using namespace `ns`."
|
|
199
197
|
if not isinstance(ns, abc.Mapping): ns = mk_ns(ns)
|
|
200
198
|
func = ns[fc_name]
|
|
201
|
-
# Clean up bad param names
|
|
202
199
|
inps = {re.sub(r'\W', '', k):v for k,v in fc_inputs.items()}
|
|
203
|
-
|
|
200
|
+
inps = _coerce_inputs(func, inps)
|
|
201
|
+
try: return func(**inps)
|
|
204
202
|
except Exception as e:
|
|
205
203
|
if raise_on_err: raise e from None
|
|
206
204
|
else: return traceback.format_exc()
|
|
@@ -215,3 +213,35 @@ async def call_func_async(fc_name, fc_inputs, ns, raise_on_err=True):
|
|
|
215
213
|
if raise_on_err: raise e from None
|
|
216
214
|
else: return traceback.format_exc()
|
|
217
215
|
return res
|
|
216
|
+
|
|
217
|
+
# %% ../01_funccall.ipynb
|
|
218
|
+
def mk_param(nm, props, req):
|
|
219
|
+
"Create a `Parameter` for `nm` with schema `props`"
|
|
220
|
+
kind = Parameter.POSITIONAL_OR_KEYWORD if nm in req else Parameter.KEYWORD_ONLY
|
|
221
|
+
default = Parameter.empty if nm in req else props.get('default')
|
|
222
|
+
if props.get('type') == 'array' and 'items' in props:
|
|
223
|
+
item_type = type_map.get(props['items'].get('type'), Any)
|
|
224
|
+
anno = list[item_type]
|
|
225
|
+
else: anno = type_map.get(props.get('type'), Any)
|
|
226
|
+
return Parameter(nm, kind, default=default, annotation=anno)
|
|
227
|
+
|
|
228
|
+
# %% ../01_funccall.ipynb
|
|
229
|
+
def schema2sig(tool):
|
|
230
|
+
"Convert json schema `tool` to a `Signature`"
|
|
231
|
+
props, req = tool.inputSchema['properties'], tool.inputSchema.get('required', [])
|
|
232
|
+
params = sorted([mk_param(k, v, req) for k, v in props.items()], key=lambda p: p.kind)
|
|
233
|
+
return Signature(params)
|
|
234
|
+
|
|
235
|
+
# %% ../01_funccall.ipynb
|
|
236
|
+
def mk_tool(dispfn, tool):
|
|
237
|
+
"Create a callable function from a JSON schema tool definition"
|
|
238
|
+
sig = schema2sig(tool)
|
|
239
|
+
props = tool.inputSchema['properties']
|
|
240
|
+
def fn(*args, **kwargs):
|
|
241
|
+
bound = sig.bind(*args, **kwargs)
|
|
242
|
+
return dispfn(tool.name, **bound.arguments)
|
|
243
|
+
fn.__doc__ = tool.description
|
|
244
|
+
fn.__signature__ = sig
|
|
245
|
+
fn.__name__ = fn.__qualname__ = tool.name
|
|
246
|
+
fn.__annotations__ = {k: p.annotation for k, p in sig.parameters.items()}
|
|
247
|
+
return fn
|
toolslm/md_hier.py
CHANGED
|
@@ -14,20 +14,32 @@ def create_heading_dict(text, rm_fenced=True):
|
|
|
14
14
|
original_text = text
|
|
15
15
|
original_lines = text.splitlines()
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
# Build line mapping when removing fenced blocks
|
|
18
|
+
if rm_fenced:
|
|
19
|
+
filtered_lines,original_line_map,in_fenced = [],{},False
|
|
20
|
+
for i, line in enumerate(original_lines):
|
|
21
|
+
if line.strip().startswith('```'):
|
|
22
|
+
in_fenced = not in_fenced
|
|
23
|
+
continue
|
|
24
|
+
if not in_fenced:
|
|
25
|
+
original_line_map[len(filtered_lines)] = i
|
|
26
|
+
filtered_lines.append(line)
|
|
27
|
+
|
|
28
|
+
lines_for_headings = filtered_lines
|
|
29
|
+
else:
|
|
30
|
+
lines_for_headings = original_lines
|
|
31
|
+
original_line_map = {i: i for i in range(len(original_lines))}
|
|
20
32
|
|
|
21
|
-
lines_for_headings = text_for_headings.splitlines()
|
|
22
33
|
headings = []
|
|
23
34
|
|
|
24
|
-
# Parse headings with their levels and line numbers
|
|
35
|
+
# Parse headings with their levels and original line numbers
|
|
25
36
|
for idx, line in enumerate(lines_for_headings):
|
|
26
37
|
match = re.match(r'^(#{1,6})\s+\S.*', line)
|
|
27
38
|
if match:
|
|
28
39
|
level = len(match.group(1))
|
|
29
40
|
title = line.strip('#').strip()
|
|
30
|
-
|
|
41
|
+
original_line_idx = original_line_map[idx]
|
|
42
|
+
headings.append({'level': level, 'title': title, 'line': original_line_idx})
|
|
31
43
|
|
|
32
44
|
# Assign text content to each heading using original lines
|
|
33
45
|
for i, h in enumerate(headings):
|
|
@@ -270,9 +282,26 @@ More content after code."""
|
|
|
270
282
|
assert '💻 Computer' in result['🚀 Rocket Heading']
|
|
271
283
|
assert result.text == md_content
|
|
272
284
|
|
|
285
|
+
def test_fenced_blocks_between_headings():
|
|
286
|
+
md_content = """# First Header
|
|
287
|
+
Content here.
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
# A comment that should be ignored for structure
|
|
291
|
+
def example():
|
|
292
|
+
pass
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
# Second Header
|
|
296
|
+
This content belongs to Second Header."""
|
|
297
|
+
result = create_heading_dict(md_content)
|
|
298
|
+
assert "def example():" not in result['Second Header'].text
|
|
299
|
+
assert result['Second Header'].text == "# Second Header\nThis content belongs to Second Header."
|
|
300
|
+
|
|
273
301
|
test_empty_input()
|
|
274
302
|
test_whitespace_only()
|
|
275
303
|
test_malformed_headings()
|
|
276
304
|
test_unicode_and_emojis()
|
|
305
|
+
test_fenced_blocks_between_headings()
|
|
277
306
|
print('tests passed')
|
|
278
307
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
toolslm/__init__.py,sha256=ThnCuF3X7rsQSd5PAea_jfYA70ZmhLvkFcLBxBPwZnY,22
|
|
2
|
+
toolslm/_modidx.py,sha256=DWmzODG1IzXmJBQmOC89s6m0evOg4NeXgS_6KPVWYSA,5092
|
|
3
|
+
toolslm/download.py,sha256=g3BxUSxylC_575M7RFSJ1GI3Co3EwPDdEeWzxaf2Czk,4451
|
|
4
|
+
toolslm/funccall.py,sha256=z35-r1uzmI83zD5f6zapaHTlidA64KFvdwiSShcNkdM,9812
|
|
5
|
+
toolslm/md_hier.py,sha256=r_NPezhgfxjRmSYFlu_ND42hXt1qSbaPWHTcjbviOn4,11010
|
|
6
|
+
toolslm/shell.py,sha256=dGInuRKvexu21VmtZkw_0S3BGiTsbAongUG-yG4YHpc,1566
|
|
7
|
+
toolslm/xml.py,sha256=2QGVGrTWfyyf0duBDn_Of5kFzYFoBjvl8PrZKgNxbUU,5806
|
|
8
|
+
toolslm-0.3.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
+
toolslm-0.3.5.dist-info/METADATA,sha256=yh3pgKcJ98EFN3CY7bRFx4AJsrEWzJ2f55gHuQNVuDs,2404
|
|
10
|
+
toolslm-0.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
toolslm-0.3.5.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
+
toolslm-0.3.5.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
+
toolslm-0.3.5.dist-info/RECORD,,
|
toolslm-0.3.4.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
toolslm/__init__.py,sha256=oYLGMpySamd16KLiaBTfRyrAS7_oyp-TOEHmzmeumwg,22
|
|
2
|
-
toolslm/_modidx.py,sha256=KeI16uj9ZfA5ZWlmov5ATQwf3291dayJ42Bp1dh69gU,4856
|
|
3
|
-
toolslm/download.py,sha256=g3BxUSxylC_575M7RFSJ1GI3Co3EwPDdEeWzxaf2Czk,4451
|
|
4
|
-
toolslm/funccall.py,sha256=PSmQ9kZsJvYh3egH7k1vQPYFn-XBm5E_CCKDVdX9tfg,8506
|
|
5
|
-
toolslm/md_hier.py,sha256=Havk9Hf0t2Xt67n_r7ZxCsS0pciR85iLcE5quShvkTg,10032
|
|
6
|
-
toolslm/shell.py,sha256=dGInuRKvexu21VmtZkw_0S3BGiTsbAongUG-yG4YHpc,1566
|
|
7
|
-
toolslm/xml.py,sha256=2QGVGrTWfyyf0duBDn_Of5kFzYFoBjvl8PrZKgNxbUU,5806
|
|
8
|
-
toolslm-0.3.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
-
toolslm-0.3.4.dist-info/METADATA,sha256=y9ERYYAn6SAv_ozBqAeoiMgGjorCUGHQA1eLPWDSdlA,2404
|
|
10
|
-
toolslm-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
toolslm-0.3.4.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
-
toolslm-0.3.4.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
-
toolslm-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|