toolslm 0.1.3__py3-none-any.whl → 0.2.1__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.3"
1
+ __version__ = "0.2.1"
toolslm/download.py CHANGED
@@ -7,10 +7,6 @@ __all__ = ['clean_md', 'read_md', 'html2md', 'read_html', 'get_llmstxt', 'split_
7
7
  from fastcore.utils import *
8
8
  from httpx import get
9
9
  from fastcore.meta import delegates
10
- from llms_txt import *
11
-
12
- from html2text import HTML2Text
13
- from bs4 import BeautifulSoup
14
10
  from urllib.parse import urlparse, urljoin
15
11
 
16
12
  # %% ../03_download.ipynb 4
@@ -29,7 +25,8 @@ def read_md(url, rm_comments=True, rm_details=True, **kwargs):
29
25
  # %% ../03_download.ipynb 7
30
26
  def html2md(s:str, ignore_links=True):
31
27
  "Convert `s` from HTML to markdown"
32
- o = HTML2Text(bodywidth=5000)
28
+ import html2text
29
+ o = html2text.HTML2Text(bodywidth=5000)
33
30
  o.ignore_links = ignore_links
34
31
  o.mark_code = True
35
32
  o.ignore_images = True
@@ -47,6 +44,7 @@ def read_html(url, # URL to read
47
44
  "Get `url`, optionally selecting CSS selector `sel`, and convert to clean markdown"
48
45
  page = get(url).text
49
46
  if sel:
47
+ from bs4 import BeautifulSoup
50
48
  soup = BeautifulSoup(page, 'html.parser')
51
49
  if multi:
52
50
  page = [str(el) for el in soup.select(sel)]
@@ -56,14 +54,14 @@ def read_html(url, # URL to read
56
54
  if wrap_tag: return '\n'.join([f"\n<{wrap_tag}>\n{o}</{wrap_tag}>\n" for o in mds])
57
55
  else: return'\n'.join(mds)
58
56
 
59
-
60
57
  # %% ../03_download.ipynb 13
61
58
  def get_llmstxt(url, optional=False, n_workers=None):
62
59
  "Get llms.txt file from and expand it with `llms_txt.create_ctx()`"
63
60
  if not url.endswith('llms.txt'): return None
61
+ import llms_txt
64
62
  resp = get(url)
65
63
  if resp.status_code!=200: return None
66
- return create_ctx(resp.text, optional=optional, n_workers=n_workers)
64
+ return llms_txt.create_ctx(resp.text, optional=optional, n_workers=n_workers)
67
65
 
68
66
  # %% ../03_download.ipynb 15
69
67
  def split_url(url):
toolslm/funccall.py CHANGED
@@ -11,10 +11,10 @@ from fastcore.docments import docments
11
11
  from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union
12
12
  from types import UnionType
13
13
 
14
- # %% ../01_funccall.ipynb 3
14
+ # %% ../01_funccall.ipynb 4
15
15
  empty = inspect.Parameter.empty
16
16
 
17
- # %% ../01_funccall.ipynb 11
17
+ # %% ../01_funccall.ipynb 12
18
18
  def _types(t:type)->tuple[str,Optional[str]]:
19
19
  "Tuple of json schema type name and (if appropriate) array item name."
20
20
  if t is empty: raise TypeError('Missing type')
@@ -31,7 +31,7 @@ def _types(t:type)->tuple[str,Optional[str]]:
31
31
  # if t is the type itself like int, use the __name__ representation as the key
32
32
  else: return tmap.get(t.__name__, "object"), None
33
33
 
34
- # %% ../01_funccall.ipynb 18
34
+ # %% ../01_funccall.ipynb 19
35
35
  def _param(name, info):
36
36
  "json schema parameter given `name` and `info` from docments full dict."
37
37
  paramt,itemt = _types(info.anno)
@@ -40,7 +40,7 @@ def _param(name, info):
40
40
  if info.default is not empty: pschema["default"] = info.default
41
41
  return pschema
42
42
 
43
- # %% ../01_funccall.ipynb 21
43
+ # %% ../01_funccall.ipynb 22
44
44
  custom_types = {Path}
45
45
 
46
46
  def _handle_type(t, defs):
@@ -52,7 +52,7 @@ def _handle_type(t, defs):
52
52
  return {'$ref': f'#/$defs/{t.__name__}'}
53
53
  return {'type': _types(t)[0]}
54
54
 
55
- # %% ../01_funccall.ipynb 23
55
+ # %% ../01_funccall.ipynb 24
56
56
  def _is_container(t):
57
57
  "Check if type is a container (list, dict, tuple, set, Union)"
58
58
  origin = get_origin(t)
@@ -62,7 +62,7 @@ def _is_parameterized(t):
62
62
  "Check if type has arguments (e.g. list[int] vs list, dict[str, int] vs dict)"
63
63
  return _is_container(t) and (get_args(t) != ())
64
64
 
65
- # %% ../01_funccall.ipynb 29
65
+ # %% ../01_funccall.ipynb 30
66
66
  def _handle_container(origin, args, defs):
67
67
  "Handle container types like dict, list, tuple, set, and Union"
68
68
  if origin is Union or origin is UnionType:
@@ -83,7 +83,7 @@ def _handle_container(origin, args, defs):
83
83
  return schema
84
84
  return None
85
85
 
86
- # %% ../01_funccall.ipynb 30
86
+ # %% ../01_funccall.ipynb 31
87
87
  def _process_property(name, obj, props, req, defs):
88
88
  "Process a single property of the schema"
89
89
  p = _param(name, obj)
@@ -96,7 +96,7 @@ def _process_property(name, obj, props, req, defs):
96
96
  # Non-container type or container without arguments
97
97
  p.update(_handle_type(obj.anno, defs))
98
98
 
99
- # %% ../01_funccall.ipynb 31
99
+ # %% ../01_funccall.ipynb 32
100
100
  def _get_nested_schema(obj):
101
101
  "Generate nested JSON schema for a class or function"
102
102
  d = docments(obj, full=True)
@@ -111,9 +111,10 @@ def _get_nested_schema(obj):
111
111
  if defs: schema['$defs'] = defs
112
112
  return schema
113
113
 
114
- # %% ../01_funccall.ipynb 35
115
- def get_schema(f:callable, pname='input_schema')->dict:
114
+ # %% ../01_funccall.ipynb 36
115
+ def get_schema(f:Union[callable,dict], pname='input_schema')->dict:
116
116
  "Generate JSON schema for a class, function, or method"
117
+ if isinstance(f, dict): return f
117
118
  schema = _get_nested_schema(f)
118
119
  desc = f.__doc__
119
120
  assert desc, "Docstring missing!"
@@ -122,16 +123,16 @@ def get_schema(f:callable, pname='input_schema')->dict:
122
123
  if ret.anno is not empty: desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
123
124
  return {"name": f.__name__, "description": desc, pname: schema}
124
125
 
125
- # %% ../01_funccall.ipynb 46
126
+ # %% ../01_funccall.ipynb 47
126
127
  def PathArg(
127
128
  path: str # A filesystem path
128
129
  ): return Path(path)
129
130
 
130
- # %% ../01_funccall.ipynb 66
131
+ # %% ../01_funccall.ipynb 67
131
132
  import ast, time, signal, traceback
132
133
  from fastcore.utils import *
133
134
 
134
- # %% ../01_funccall.ipynb 67
135
+ # %% ../01_funccall.ipynb 68
135
136
  def _copy_loc(new, orig):
136
137
  "Copy location information from original node to new node and all children."
137
138
  new = ast.copy_location(new, orig)
@@ -140,7 +141,7 @@ def _copy_loc(new, orig):
140
141
  elif isinstance(o, list): setattr(new, field, [_copy_loc(value, orig) for value in o])
141
142
  return new
142
143
 
143
- # %% ../01_funccall.ipynb 69
144
+ # %% ../01_funccall.ipynb 70
144
145
  def _run(code:str, glb:dict=None, loc:dict=None):
145
146
  "Run `code`, returning final expression (similar to IPython)"
146
147
  tree = ast.parse(code)
@@ -163,7 +164,7 @@ def _run(code:str, glb:dict=None, loc:dict=None):
163
164
  if _result is not None: return _result
164
165
  return stdout_buffer.getvalue().strip()
165
166
 
166
- # %% ../01_funccall.ipynb 74
167
+ # %% ../01_funccall.ipynb 75
167
168
  def python(code:str, # Code to execute
168
169
  glb:Optional[dict]=None, # Globals namespace
169
170
  loc:Optional[dict]=None, # Locals namespace
@@ -180,7 +181,7 @@ def python(code:str, # Code to execute
180
181
  except Exception as e: return traceback.format_exc()
181
182
  finally: signal.alarm(0)
182
183
 
183
- # %% ../01_funccall.ipynb 85
184
+ # %% ../01_funccall.ipynb 86
184
185
  def mk_ns(*funcs_or_objs):
185
186
  merged = {}
186
187
  for o in funcs_or_objs:
@@ -189,16 +190,23 @@ def mk_ns(*funcs_or_objs):
189
190
  if callable(o) and hasattr(o, '__name__'): merged |= {o.__name__: o}
190
191
  return merged
191
192
 
192
- # %% ../01_funccall.ipynb 94
193
- def call_func(fc_name, fc_inputs, ns):
193
+ # %% ../01_funccall.ipynb 95
194
+ def call_func(fc_name, fc_inputs, ns, raise_on_err=True):
194
195
  "Call the function `fc_name` with the given `fc_inputs` using namespace `ns`."
195
196
  if not isinstance(ns, abc.Mapping): ns = mk_ns(*ns)
196
197
  func = ns[fc_name]
197
- return func(**fc_inputs)
198
+ try: return func(**fc_inputs)
199
+ except Exception as e:
200
+ if raise_on_err: raise e
201
+ else: return traceback.format_exc()
198
202
 
199
- # %% ../01_funccall.ipynb 101
200
- async def call_func_async(fc_name, fc_inputs, ns):
203
+ # %% ../01_funccall.ipynb 106
204
+ async def call_func_async(fc_name, fc_inputs, ns, raise_on_err=True):
201
205
  "Awaits the function `fc_name` with the given `fc_inputs` using namespace `ns`."
202
- if not isinstance(ns, abc.Mapping): ns = mk_ns(*ns)
203
- func = ns[fc_name]
204
- return await func(**fc_inputs)
206
+ res = call_func(fc_name, fc_inputs, ns, raise_on_err=raise_on_err)
207
+ if inspect.iscoroutine(res):
208
+ try: res = await res
209
+ except Exception as e:
210
+ if raise_on_err: raise e
211
+ else: return traceback.format_exc()
212
+ return res
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toolslm
3
- Version: 0.1.3
3
+ Version: 0.2.1
4
4
  Summary: Tools to make language models a bit easier to use
5
5
  Home-page: https://github.com/AnswerDotAI/toolslm
6
6
  Author: Jeremy Howard
@@ -17,10 +17,7 @@ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: fastcore>=1.5.47
20
- Requires-Dist: beautifulsoup4
21
- Requires-Dist: html2text
22
20
  Requires-Dist: httpx
23
- Requires-Dist: llms_txt
24
21
  Provides-Extra: dev
25
22
  Dynamic: author
26
23
  Dynamic: author-email
@@ -0,0 +1,13 @@
1
+ toolslm/__init__.py,sha256=HfjVOrpTnmZ-xVFCYSVmX50EXaBQeJteUHG-PD6iQs8,22
2
+ toolslm/_modidx.py,sha256=-D-B5o30VGs11gBKf96lpADVXnZhdiVEshJpLzmUnDs,4378
3
+ toolslm/download.py,sha256=Ak7xzzCplU4RFW2cvUiuvhnL0agQqwF4lVH2hQhNNmc,4476
4
+ toolslm/funccall.py,sha256=mGe_wsvcF3jYIbi3WbgQrVHcgZpGUMVtJlh5PW9XFcY,8806
5
+ toolslm/md_hier.py,sha256=4uC12443tPBduYJgIZZIcEat2VG0x7JYC8-SwDdS2JY,6360
6
+ toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
7
+ toolslm/xml.py,sha256=QNwUavoMkFK84D7dMwnBjqlYJwN-pJ7u3BxOeDuNAmk,4088
8
+ toolslm-0.2.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
+ toolslm-0.2.1.dist-info/METADATA,sha256=uLhalwynGQDQNencJKfWnv2pyMdkvvJ4Im5j8RTzvOg,2404
10
+ toolslm-0.2.1.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
11
+ toolslm-0.2.1.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
12
+ toolslm-0.2.1.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
13
+ toolslm-0.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,13 +0,0 @@
1
- toolslm/__init__.py,sha256=XEqb2aiIn8fzGE68Mph4ck1FtQqsR_am0wRWvrYPffQ,22
2
- toolslm/_modidx.py,sha256=-D-B5o30VGs11gBKf96lpADVXnZhdiVEshJpLzmUnDs,4378
3
- toolslm/download.py,sha256=d84O8PCX7uAbLg0HTbNNfCdANPcnhXFu4qzOtcfJfHU,4465
4
- toolslm/funccall.py,sha256=bzVlcTpgQuuBIG-I1HRidnXV5mp0FfGV10_Mk1DSQuc,8460
5
- toolslm/md_hier.py,sha256=4uC12443tPBduYJgIZZIcEat2VG0x7JYC8-SwDdS2JY,6360
6
- toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
7
- toolslm/xml.py,sha256=QNwUavoMkFK84D7dMwnBjqlYJwN-pJ7u3BxOeDuNAmk,4088
8
- toolslm-0.1.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
- toolslm-0.1.3.dist-info/METADATA,sha256=8MXaP61NyBqYuRyFe3IC49I0TYcZdZHniN17MJWHxB0,2483
10
- toolslm-0.1.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
11
- toolslm-0.1.3.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
12
- toolslm-0.1.3.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
13
- toolslm-0.1.3.dist-info/RECORD,,