Skip to content
This repository was archived by the owner on Apr 29, 2025. It is now read-only.

Commit 94cc20a

Browse files
committed
v0.0.31
1 parent 974bc43 commit 94cc20a

File tree

4 files changed

+95
-29
lines changed

4 files changed

+95
-29
lines changed

CHANGELOG.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
The format is based on [Keep a Changelog](https://keepachangelog.com/),
6-
and this project adheres to [SimpleTool](https://github.com/nchekwa/simpletool-python/tree/master).
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.0.31] - 2025-03-22
9+
10+
### Fixed
11+
- cleanup TypeVar usage
812

913
## [0.0.30] - 2025-03-22
1014

run_build.sh

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "=== SimpleTool Python Package Build Script ==="
5+
6+
# Check if virtual environment exists and activate it if it does
7+
if [ -d "venv" ]; then
8+
echo "Activating virtual environment..."
9+
source venv/bin/activate
10+
else
11+
echo "Creating virtual environment..."
12+
python3 -m venv venv
13+
source venv/bin/activate
14+
15+
echo "Installing dependencies..."
16+
pip install --upgrade pip
17+
pip install -r requirements.txt
18+
pip install -r requirements-dev.txt
19+
fi
20+
21+
# Install build dependencies if not already installed
22+
echo "Ensuring build dependencies are installed..."
23+
pip install --upgrade build wheel twine setuptools
24+
25+
# Clean previous builds
26+
echo "Cleaning previous builds..."
27+
rm -rf build/ dist/ *.egg-info/
28+
29+
# Run tests to ensure everything is working
30+
echo "Running tests..."
31+
./run_pytest.sh
32+
33+
# Build the package
34+
echo "Building SimpleTool package..."
35+
python -m build
36+
37+
# Show build results
38+
echo "=== Build Complete ==="
39+
echo "Build artifacts:"
40+
ls -l dist/
41+
42+
echo "To upload to PyPI, run:"
43+
echo "> twine upload dist/*"
44+
45+
echo "Do you want to install the package locally? (y/n)"
46+
read answer
47+
if [[ $answer == "y" || $answer == "Y" ]]; then
48+
pip install dist/*.whl
49+
echo "Package installed locally."
50+
else
51+
echo "Skipping local installation."
52+
fi

simpletool/__init__.py

+20-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
name: SimpleTools
33
author: Artur Zdolinski
4-
version: 0.0.30
4+
version: 0.0.31
55
"""
66
# Standard library imports
77
import gc
@@ -17,7 +17,7 @@
1717
from functools import wraps
1818
from pathlib import Path
1919
from typing import get_args, get_origin
20-
from typing import List, Dict, Any, Union, Type, Literal, ClassVar, Sequence, Tuple, TypeVar, Optional, Callable
20+
from typing import List, Dict, Any, Union, Type, Literal, ClassVar, Sequence, Tuple, TypeVar, Optional, Callable, TypeAlias
2121
from typing import AnyStr # noqa: F401, F403
2222
from weakref import WeakMethod, ref, WeakSet
2323

@@ -40,29 +40,32 @@
4040
# Type for input arguments - can be dict or any model inheriting from SimpleInputModel
4141
T = TypeVar('T', Dict[str, Any], SimpleInputModel)
4242

43-
# Type for return value - can be specified by the tool implementation
44-
R = TypeVar('R', bound=Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent])
43+
# Define a type alias for content types instead of using a TypeVar
44+
ContentType: TypeAlias = Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]
45+
46+
# Define a type alias for response types that can be either Sequence or List of ContentType
47+
ResponseType: TypeAlias = Union[Sequence[ContentType], List[ContentType]]
4548

4649
# Threshold for what we consider a "large" object (1MB)
4750
LARGE_OBJECT_THRESHOLD = 1024 * 1024 # 1MB in bytes
4851

4952

5053
def get_valid_content_types() -> Tuple[Type, ...]:
51-
"""Directly return the types from the TypeVar definition as a tuple"""
52-
return (Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent)
54+
"""Directly return the types from the ContentType definition as a tuple"""
55+
return get_args(ContentType)
5356

5457

5558
def validate_tool_output(func):
5659
@wraps(func)
57-
def wrapper(*args: Any, **kwargs: Any) -> Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]:
60+
def wrapper(*args: Any, **kwargs: Any) -> ResponseType:
5861
result = func(*args, **kwargs)
5962

6063
# Handle coroutines for backward compatibility with async code
6164
if asyncio.iscoroutine(result):
6265
async def _async_wrapper():
6366
async_result = await result
64-
if not isinstance(async_result, list):
65-
raise ValidationError("output", "Tool output must be a list")
67+
if not isinstance(async_result, (list, tuple)):
68+
raise ValidationError("output", "Tool output must be a list or tuple")
6669

6770
valid_types = get_valid_content_types()
6871
for item in async_result:
@@ -73,8 +76,8 @@ async def _async_wrapper():
7376
return asyncio.run(_async_wrapper())
7477

7578
# Handle synchronous results
76-
if not isinstance(result, list):
77-
raise ValidationError("output", "Tool output must be a list")
79+
if not isinstance(result, (list, tuple)):
80+
raise ValidationError("output", "Tool output must be a list or tuple")
7881

7982
valid_types = get_valid_content_types()
8083
for item in result:
@@ -200,7 +203,7 @@ def __init__(self):
200203
# Initialize memory management
201204
self._process = psutil.Process()
202205

203-
def __call__(self, arguments: Dict[str, Any]) -> Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]:
206+
def __call__(self, arguments: Dict[str, Any]) -> ResponseType:
204207
"""
205208
Execute the tool with memory management and validation.
206209
This is the main entry point that handles all the memory management.
@@ -261,7 +264,7 @@ def __call__(self, arguments: Dict[str, Any]) -> Sequence[Union[Content, TextCon
261264

262265
@abstractmethod
263266
@validate_tool_output
264-
def run(self, arguments: T) -> Sequence[R]:
267+
def run(self, arguments: T) -> ResponseType:
265268
"""
266269
Execute the tool with the given arguments.
267270
This is the method that tool developers should implement.
@@ -274,7 +277,7 @@ def run(self, arguments: T) -> Sequence[R]:
274277
"""
275278
raise NotImplementedError("Subclass must implement run()")
276279

277-
def arun(self, arguments: T) -> Sequence[R]:
280+
def arun(self, arguments: T) -> ResponseType:
278281
"""
279282
For compatibility with async version. This method simply calls run().
280283
If you need async functionality, use simpletool.asyncio.SimpleTool instead.
@@ -675,7 +678,7 @@ def create(
675678
name: str,
676679
description: str,
677680
input_model: Type[SimpleInputModel],
678-
run_fn: Callable[[SimpleInputModel], Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]]
681+
run_fn: Callable[[SimpleInputModel], ResponseType]
679682
) -> 'SimpleTool':
680683
"""
681684
Create a SimpleTool instance without subclassing.
@@ -728,6 +731,8 @@ def my_run(arguments: MyInputModel) -> List[TextContent]:
728731
'ResourceContent',
729732
'BoolContent',
730733
'ErrorContent',
734+
'ContentType',
735+
'ResponseType',
731736
'List',
732737
'Dict',
733738
'Any',

simpletool/asyncio/__init__.py

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
name: SimpleTools
33
author: Artur Zdolinski
4-
version: 0.0.20
4+
version: 0.0.31
55
"""
66
# Standard library imports
77
import gc
@@ -53,24 +53,27 @@
5353
# Type for input arguments - can be dict or any model inheriting from SimpleInputModel
5454
T = TypeVar('T', Dict[str, Any], SimpleInputModel)
5555

56-
# Type for return value - can be specified by the tool implementation
57-
R = TypeVar('R', bound=Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent])
56+
# Define a type alias for content types instead of using a TypeVar
57+
ContentType: TypeAlias = Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]
58+
59+
# Define a type alias for response types that can be either Sequence or List of ContentType
60+
ResponseType: TypeAlias = Union[Sequence[ContentType], List[ContentType]]
5861

5962
# Threshold for what we consider a "large" object (1MB)
6063
LARGE_OBJECT_THRESHOLD = 1024 * 1024 # 1MB in bytes
6164

6265

6366
def get_valid_content_types() -> Tuple[Type, ...]:
64-
"""Directly return the types from the TypeVar definition as a tuple"""
65-
return (Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent)
67+
"""Directly return the types from the ContentType definition as a tuple"""
68+
return get_args(ContentType)
6669

6770

6871
def validate_tool_output(func):
6972
@wraps(func)
70-
async def wrapper(*args: Any, **kwargs: Any) -> Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]:
73+
async def wrapper(*args: Any, **kwargs: Any) -> ResponseType:
7174
result = await func(*args, **kwargs)
72-
if not isinstance(result, list):
73-
raise ValidationError("output", "Tool output must be a list")
75+
if not isinstance(result, (list, tuple)):
76+
raise ValidationError("output", "Tool output must be a list or tuple")
7477

7578
valid_types = get_valid_content_types()
7679
for item in result:
@@ -223,7 +226,7 @@ def __init__(self, *, timeout: Optional[float] = None):
223226
"""
224227
pass
225228

226-
async def __call__(self, arguments: Dict[str, Any]) -> Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]:
229+
async def __call__(self, arguments: Dict[str, Any]) -> ResponseType:
227230
"""
228231
Execute the tool with memory management and validation.
229232
This is the main entry point that handles all the memory management.
@@ -290,7 +293,7 @@ async def __call__(self, arguments: Dict[str, Any]) -> Sequence[Union[Content, T
290293

291294
@abstractmethod
292295
@validate_tool_output
293-
async def run(self, arguments: T) -> Sequence[R]:
296+
async def run(self, arguments: T) -> ResponseType:
294297
"""
295298
Execute the tool with the given arguments.
296299
This is the method that tool developers should implement.
@@ -698,10 +701,10 @@ def create(
698701
name: str,
699702
description: str,
700703
input_model: Type[SimpleInputModel],
701-
run_fn: Callable[[SimpleInputModel], Awaitable[Sequence[Union[Content, TextContent, ImageContent, FileContent, ResourceContent, BoolContent, ErrorContent]]]]
704+
run_fn: Callable[[SimpleInputModel], Awaitable[ResponseType]]
702705
) -> 'SimpleTool':
703706
"""
704-
Create a SimpleTool instance without subclassing.
707+
Create a SimpleTool instance without subclassing..f
705708
706709
Args:
707710
name: Name of the tool
@@ -750,6 +753,8 @@ async def my_run(arguments: MyInputModel) -> List[TextContent]:
750753
'ResourceContent',
751754
'BoolContent',
752755
'ErrorContent',
756+
'ContentType',
757+
'ResponseType',
753758
'List',
754759
'Dict',
755760
'Any',

0 commit comments

Comments
 (0)