Skip to content

Commit 37cf0c8

Browse files
agpitukpeteski22
andauthored
Added tests to sdk (#13)
* Added tests to SDK * uv run pre-commit run --all-files * fixed pyproject.toml build system settings for running tests * added py.typed file for PEP 561 * added 'make setup' to Makefile * added 'make test' to Makefile * updated README * added scripts/ to handle install/upgrade of uv * tests: added conftest, matched test folder structure of projects like AnyAgent --------- Co-authored-by: Peter Wilson <peter@mozilla.ai>
1 parent a2189a5 commit 37cf0c8

16 files changed

+1039
-9
lines changed

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.PHONY: ensure-scripts-exec setup test
2+
3+
ensure-scripts-exec:
4+
@chmod +x scripts/* || true
5+
6+
setup: ensure-scripts-exec
7+
@scripts/setup_uv.sh
8+
9+
test:
10+
@uv run $(DEBUGPY_ARGS) -m pytest tests

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,39 @@ dependencies = [
3131
Then run:
3232

3333
```bash
34+
uv venv
35+
source .venv/bin/activate
3436
uv sync
3537
```
3638

39+
## Dev Setup
40+
41+
Use the `Makefile` target to ensure `uv` is installed, and your virtual environment is active and sync'd.
42+
43+
```bash
44+
make setup
45+
```
46+
47+
## Testing
48+
49+
Ensure you have the correct dependencies installed for testing:
50+
51+
```bash
52+
uv sync --group tests
53+
```
54+
55+
Then to run all tests:
56+
57+
```bash
58+
uv run pytest tests
59+
```
60+
61+
... or via `Makefile`:
62+
63+
```bash
64+
make test
65+
```
66+
3767
## Quick Start
3868

3969
```python

examples/readme_maker/readme_maker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
If a template README file from an original repository ({input_repo_readme}) is provided:
3131
3232
- Template Utilization: Use the structure and style of the original README file as a guide.
33-
- Content Adaptation: Modify the content to accurately describe the target repository.
34-
This step requires analyzing the entire codebase of the target repository ({target_repo})
33+
- Content Adaptation: Modify the content to accurately describe the target repository.
34+
This step requires analyzing the entire codebase of the target repository ({target_repo})
3535
to understand its functionality, features, and any other relevant details that should be included in the README.
3636
3737
If no template README file is provided:
@@ -45,7 +45,7 @@
4545
-License information
4646
-Acknowledgements (if applicable)
4747
48-
To create the README, analyze the entire codebase of the target repository ({target_repo})
48+
To create the README, analyze the entire codebase of the target repository ({target_repo})
4949
to understand its functionality, features, and any other relevant details.
5050
5151
After creating the new README file:
@@ -55,8 +55,8 @@
5555
commit message that clearly indicates the addition of the new README.
5656
3. Pull Request (PR) Creation: Open a Pull Request against the main branch of the target
5757
repository, including the new README file.
58-
4. PR Description: In the Pull Request description, mention that the README was generated
59-
by an AI agent of the model {agent_model}. If a template was used, include a link to
58+
4. PR Description: In the Pull Request description, mention that the README was generated
59+
by an AI agent of the model {agent_model}. If a template was used, include a link to
6060
the original README template ({input_repo_readme}) used for generating the new README.
6161
6262
When providing code snippets for this task, follow the guidelines for code modifications:

pyproject.toml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mcpd-sdk"
3-
version = "0.0.1"
3+
dynamic = ["version"]
44
description = "mcpd Python SDK"
55
readme = "README.md"
66
license = {text = "Apache-2.0"}
@@ -23,6 +23,8 @@ lint = [
2323

2424
tests = [
2525
"pytest>=8.3.5",
26+
"setuptools>=80.9.0",
27+
"setuptools-scm[toml]>=8.3.1",
2628
]
2729

2830
all = [
@@ -31,6 +33,18 @@ all = [
3133
{ include-group = "tests" },
3234
]
3335

36+
[build-system]
37+
requires = ["setuptools>=48", "setuptools_scm[toml]>=6.3.1"]
38+
build-backend = "setuptools.build_meta"
39+
40+
[tool.setuptools.packages.find]
41+
exclude = ["tests", "tests.*"]
42+
where = ["src"]
43+
namespaces = false
44+
45+
[tool.setuptools.package-data]
46+
"*" = ["py.typed"]
47+
3448
[tool.ruff]
3549
fix = true
3650
line-length=120

scripts/setup_uv.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
5+
# ##########
6+
# Install UV
7+
# ##########
8+
9+
# Expected installation path for uv
10+
# See: https://docs.astral.sh/uv/configuration/installer/#changing-the-install-path
11+
LOCAL_BIN="${LOCAL_BIN:-$HOME/.local/bin}"
12+
13+
# Ensure LOCAL_BIN exists and is on PATH
14+
mkdir -p "$LOCAL_BIN"
15+
if [[ ":$PATH:" != *":$LOCAL_BIN:"* ]]; then
16+
export PATH="$LOCAL_BIN:$PATH"
17+
fi
18+
19+
VENV_DIR=".venv"
20+
21+
# Install or update uv
22+
if ! command -v uv &>/dev/null; then
23+
echo "uv not found – installing to $LOCAL_BIN"
24+
curl -fsSL https://astral.sh/uv/install.sh | UV_INSTALL_DIR="$LOCAL_BIN" sh
25+
else
26+
current=$(uv --version | awk '{print $2}')
27+
echo "Found uv v$current"
28+
if command -v jq &>/dev/null; then
29+
latest=$(curl -fsS https://api.github.com/repos/astral-sh/uv/releases/latest \
30+
| jq -r .tag_name)
31+
if [[ "$current" != "$latest" ]]; then
32+
echo "Updating uv: $current$latest"
33+
uv self update
34+
fi
35+
fi
36+
fi
37+
38+
# Bootstrap root .venv
39+
echo "Bootstrapping root .venv in folder $VENV_DIR"
40+
uv venv "$VENV_DIR"
41+
uv sync --group all --active
42+
43+
echo "Done! Root environment is ready in: $VENV_DIR"
44+
45+
# After detecting PATH lacked LOCAL_BIN…
46+
if [[ ":$PATH:" != *":$LOCAL_BIN:"* ]]; then
47+
echo "Note: added $LOCAL_BIN to PATH for this session."
48+
echo "To make it permanent, add to your shell profile:"
49+
echo " export PATH=\"$LOCAL_BIN:\$PATH\""
50+
fi

src/mcpd_sdk/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
1+
from importlib.metadata import PackageNotFoundError, version
2+
13
from .mcpd_client import McpdClient, McpdError
4+
5+
try:
6+
__version__ = version("mcpd_sdk")
7+
except PackageNotFoundError:
8+
# In the case of local development
9+
# i.e., running directly from the source directory without package being installed
10+
__version__ = "0.0.0-dev"
11+
12+
__all__ = [
13+
"McpdClient",
14+
"McpdError",
15+
"__version__",
16+
]

src/mcpd_sdk/py.typed

Whitespace-only changes.

tests/__init__.py

Whitespace-only changes.

tests/conftest.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from unittest.mock import Mock
2+
3+
import pytest
4+
5+
from mcpd_sdk import McpdClient, McpdError
6+
7+
8+
@pytest.fixture(scope="function")
9+
def mock_client():
10+
client = Mock()
11+
client._perform_call = Mock(return_value={"result": "success"})
12+
client.has_tool = Mock(return_value=True)
13+
return client
14+
15+
16+
@pytest.fixture(scope="function")
17+
def mock_response():
18+
response = Mock()
19+
response.json.return_value = {"result": "success"}
20+
response.raise_for_status.return_value = None
21+
return response
22+
23+
24+
@pytest.fixture(scope="session")
25+
def basic_schema():
26+
return {
27+
"name": "test_tool",
28+
"description": "A test tool",
29+
"inputSchema": {
30+
"type": "object",
31+
"properties": {
32+
"param1": {"type": "string", "description": "First parameter"},
33+
"param2": {"type": "integer", "description": "Second parameter"},
34+
},
35+
"required": ["param1"],
36+
},
37+
}
38+
39+
40+
@pytest.fixture(scope="session")
41+
def fqdn() -> str:
42+
return "http://localhost:8090"
43+
44+
45+
@pytest.fixture(scope="session")
46+
def api_url(fqdn) -> str:
47+
return fqdn + "/api/v1"
48+
49+
50+
@pytest.fixture(scope="function")
51+
def client(fqdn):
52+
return McpdClient(api_endpoint=fqdn)
53+
54+
55+
@pytest.fixture(scope="function")
56+
def client_with_auth(fqdn):
57+
return McpdClient(api_endpoint=fqdn, api_key="test-key") # pragma: allowlist secret

tests/unit/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)