Spaces:
Running
Running
zzstoatzz commited on
Commit ·
b23a78c
1
Parent(s): 7e68225
fix warning and flake
Browse files- pyproject.toml +1 -0
- tests/test_cli.py +45 -39
- tests/test_func_metadata.py +10 -8
- uv.lock +29 -1
pyproject.toml
CHANGED
|
@@ -27,6 +27,7 @@ tests = [
|
|
| 27 |
"pre-commit",
|
| 28 |
"pytest>=8.3.3",
|
| 29 |
"pytest-asyncio>=0.23.5",
|
|
|
|
| 30 |
"pytest-xdist>=3.6.1",
|
| 31 |
"ruff",
|
| 32 |
]
|
|
|
|
| 27 |
"pre-commit",
|
| 28 |
"pytest>=8.3.3",
|
| 29 |
"pytest-asyncio>=0.23.5",
|
| 30 |
+
"pytest-flakefinder",
|
| 31 |
"pytest-xdist>=3.6.1",
|
| 32 |
"ruff",
|
| 33 |
]
|
tests/test_cli.py
CHANGED
|
@@ -3,12 +3,12 @@
|
|
| 3 |
import json
|
| 4 |
import sys
|
| 5 |
from pathlib import Path
|
| 6 |
-
from unittest.mock import
|
| 7 |
|
| 8 |
import pytest
|
| 9 |
from typer.testing import CliRunner
|
| 10 |
|
| 11 |
-
from fastmcp.cli.cli import
|
| 12 |
|
| 13 |
|
| 14 |
@pytest.fixture
|
|
@@ -297,47 +297,53 @@ mcp = FastMCP("test", dependencies=["pandas", "numpy"])
|
|
| 297 |
assert mock_run.call_args_list[0] == call(
|
| 298 |
["npx.cmd", "--version"], check=True, capture_output=True, shell=True
|
| 299 |
)
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
| 318 |
)
|
|
|
|
|
|
|
| 319 |
else:
|
| 320 |
-
#
|
| 321 |
-
mock_run.
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
shell=False, # Note: shell=False on Unix
|
| 339 |
)
|
| 340 |
|
|
|
|
|
|
|
| 341 |
|
| 342 |
def test_run_with_dependencies(mock_config, server_file):
|
| 343 |
"""Test that run command does not handle dependencies."""
|
|
|
|
| 3 |
import json
|
| 4 |
import sys
|
| 5 |
from pathlib import Path
|
| 6 |
+
from unittest.mock import call, patch
|
| 7 |
|
| 8 |
import pytest
|
| 9 |
from typer.testing import CliRunner
|
| 10 |
|
| 11 |
+
from fastmcp.cli.cli import _parse_env_var, _parse_file_path, app
|
| 12 |
|
| 13 |
|
| 14 |
@pytest.fixture
|
|
|
|
| 297 |
assert mock_run.call_args_list[0] == call(
|
| 298 |
["npx.cmd", "--version"], check=True, capture_output=True, shell=True
|
| 299 |
)
|
| 300 |
+
|
| 301 |
+
# get the actual command and expected command without dependencies
|
| 302 |
+
actual_cmd = mock_run.call_args_list[1][0][0]
|
| 303 |
+
expected_start = [
|
| 304 |
+
"npx.cmd",
|
| 305 |
+
"@modelcontextprotocol/inspector",
|
| 306 |
+
"uv",
|
| 307 |
+
"run",
|
| 308 |
+
"--with",
|
| 309 |
+
"fastmcp",
|
| 310 |
+
]
|
| 311 |
+
expected_end = ["fastmcp", "run", str(server_file)]
|
| 312 |
+
|
| 313 |
+
# verify start and end of command
|
| 314 |
+
assert actual_cmd[: len(expected_start)] == expected_start
|
| 315 |
+
assert actual_cmd[-len(expected_end) :] == expected_end
|
| 316 |
+
|
| 317 |
+
# verify dependencies are present (order-independent)
|
| 318 |
+
deps_section = actual_cmd[len(expected_start) : -len(expected_end)]
|
| 319 |
+
assert all(
|
| 320 |
+
x in deps_section for x in ["--with", "numpy", "--with", "pandas"]
|
| 321 |
)
|
| 322 |
+
|
| 323 |
+
assert mock_run.call_args_list[1][1] == {"check": True, "shell": True}
|
| 324 |
else:
|
| 325 |
+
# same verification for unix, just with different command prefix
|
| 326 |
+
actual_cmd = mock_run.call_args_list[0][0][0]
|
| 327 |
+
expected_start = [
|
| 328 |
+
"npx",
|
| 329 |
+
"@modelcontextprotocol/inspector",
|
| 330 |
+
"uv",
|
| 331 |
+
"run",
|
| 332 |
+
"--with",
|
| 333 |
+
"fastmcp",
|
| 334 |
+
]
|
| 335 |
+
expected_end = ["fastmcp", "run", str(server_file)]
|
| 336 |
+
|
| 337 |
+
assert actual_cmd[: len(expected_start)] == expected_start
|
| 338 |
+
assert actual_cmd[-len(expected_end) :] == expected_end
|
| 339 |
+
|
| 340 |
+
deps_section = actual_cmd[len(expected_start) : -len(expected_end)]
|
| 341 |
+
assert all(
|
| 342 |
+
x in deps_section for x in ["--with", "numpy", "--with", "pandas"]
|
|
|
|
| 343 |
)
|
| 344 |
|
| 345 |
+
assert mock_run.call_args_list[0][1] == {"check": True, "shell": False}
|
| 346 |
+
|
| 347 |
|
| 348 |
def test_run_with_dependencies(mock_config, server_file):
|
| 349 |
"""Test that run command does not handle dependencies."""
|
tests/test_func_metadata.py
CHANGED
|
@@ -1,15 +1,17 @@
|
|
| 1 |
-
from pydantic import BaseModel, Field
|
| 2 |
from typing import Annotated
|
|
|
|
| 3 |
import annotated_types
|
| 4 |
-
from fastmcp.utilities.func_metadata import func_metadata
|
| 5 |
import pytest
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
|
| 8 |
-
class
|
| 9 |
pass
|
| 10 |
|
| 11 |
|
| 12 |
-
class
|
| 13 |
class InnerModel(BaseModel):
|
| 14 |
x: int
|
| 15 |
|
|
@@ -44,15 +46,15 @@ def complex_arguments_fn(
|
|
| 44 |
int, Field(1)
|
| 45 |
],
|
| 46 |
unannotated,
|
| 47 |
-
my_model_a:
|
| 48 |
-
my_model_a_forward_ref: "
|
| 49 |
-
my_model_b:
|
| 50 |
an_int_annotated_with_field_default: Annotated[
|
| 51 |
int,
|
| 52 |
Field(1, description="An int with a field"),
|
| 53 |
],
|
| 54 |
unannotated_with_default=5,
|
| 55 |
-
my_model_a_with_default:
|
| 56 |
an_int_with_default: int = 1,
|
| 57 |
must_be_none_with_default: None = None,
|
| 58 |
an_int_with_equals_field: int = Field(1, ge=0),
|
|
|
|
|
|
|
| 1 |
from typing import Annotated
|
| 2 |
+
|
| 3 |
import annotated_types
|
|
|
|
| 4 |
import pytest
|
| 5 |
+
from pydantic import BaseModel, Field
|
| 6 |
+
|
| 7 |
+
from fastmcp.utilities.func_metadata import func_metadata
|
| 8 |
|
| 9 |
|
| 10 |
+
class SomeInputModelA(BaseModel):
|
| 11 |
pass
|
| 12 |
|
| 13 |
|
| 14 |
+
class SomeInputModelB(BaseModel):
|
| 15 |
class InnerModel(BaseModel):
|
| 16 |
x: int
|
| 17 |
|
|
|
|
| 46 |
int, Field(1)
|
| 47 |
],
|
| 48 |
unannotated,
|
| 49 |
+
my_model_a: SomeInputModelA,
|
| 50 |
+
my_model_a_forward_ref: "SomeInputModelA",
|
| 51 |
+
my_model_b: SomeInputModelB,
|
| 52 |
an_int_annotated_with_field_default: Annotated[
|
| 53 |
int,
|
| 54 |
Field(1, description="An int with a field"),
|
| 55 |
],
|
| 56 |
unannotated_with_default=5,
|
| 57 |
+
my_model_a_with_default: SomeInputModelA = SomeInputModelA(), # noqa: B008
|
| 58 |
an_int_with_default: int = 1,
|
| 59 |
must_be_none_with_default: None = None,
|
| 60 |
an_int_with_equals_field: int = Field(1, ge=0),
|
uv.lock
CHANGED
|
@@ -228,7 +228,7 @@ wheels = [
|
|
| 228 |
|
| 229 |
[[package]]
|
| 230 |
name = "fastmcp"
|
| 231 |
-
version = "0.3.
|
| 232 |
source = { editable = "." }
|
| 233 |
dependencies = [
|
| 234 |
{ name = "httpx" },
|
|
@@ -247,6 +247,15 @@ dev = [
|
|
| 247 |
{ name = "pre-commit" },
|
| 248 |
{ name = "pytest" },
|
| 249 |
{ name = "pytest-asyncio" },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
{ name = "pytest-xdist" },
|
| 251 |
{ name = "ruff" },
|
| 252 |
]
|
|
@@ -259,13 +268,20 @@ requires-dist = [
|
|
| 259 |
{ name = "mcp", specifier = ">=1.0.0,<2.0.0" },
|
| 260 |
{ name = "pdbpp", marker = "extra == 'dev'", specifier = ">=0.10.3" },
|
| 261 |
{ name = "pre-commit", marker = "extra == 'dev'" },
|
|
|
|
| 262 |
{ name = "pydantic", specifier = ">=2.5.3,<3.0.0" },
|
| 263 |
{ name = "pydantic-settings", specifier = ">=2.6.1" },
|
| 264 |
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.3" },
|
|
|
|
| 265 |
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.5" },
|
|
|
|
|
|
|
|
|
|
| 266 |
{ name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=3.6.1" },
|
|
|
|
| 267 |
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
| 268 |
{ name = "ruff", marker = "extra == 'dev'" },
|
|
|
|
| 269 |
{ name = "typer", specifier = ">=0.9.0" },
|
| 270 |
]
|
| 271 |
|
|
@@ -743,6 +759,18 @@ wheels = [
|
|
| 743 |
{ url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 },
|
| 744 |
]
|
| 745 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 746 |
[[package]]
|
| 747 |
name = "pytest-xdist"
|
| 748 |
version = "3.6.1"
|
|
|
|
| 228 |
|
| 229 |
[[package]]
|
| 230 |
name = "fastmcp"
|
| 231 |
+
version = "0.3.6.dev0+gf03184b.d20241203"
|
| 232 |
source = { editable = "." }
|
| 233 |
dependencies = [
|
| 234 |
{ name = "httpx" },
|
|
|
|
| 247 |
{ name = "pre-commit" },
|
| 248 |
{ name = "pytest" },
|
| 249 |
{ name = "pytest-asyncio" },
|
| 250 |
+
{ name = "pytest-flakefinder" },
|
| 251 |
+
{ name = "pytest-xdist" },
|
| 252 |
+
{ name = "ruff" },
|
| 253 |
+
]
|
| 254 |
+
tests = [
|
| 255 |
+
{ name = "pre-commit" },
|
| 256 |
+
{ name = "pytest" },
|
| 257 |
+
{ name = "pytest-asyncio" },
|
| 258 |
+
{ name = "pytest-flakefinder" },
|
| 259 |
{ name = "pytest-xdist" },
|
| 260 |
{ name = "ruff" },
|
| 261 |
]
|
|
|
|
| 268 |
{ name = "mcp", specifier = ">=1.0.0,<2.0.0" },
|
| 269 |
{ name = "pdbpp", marker = "extra == 'dev'", specifier = ">=0.10.3" },
|
| 270 |
{ name = "pre-commit", marker = "extra == 'dev'" },
|
| 271 |
+
{ name = "pre-commit", marker = "extra == 'tests'" },
|
| 272 |
{ name = "pydantic", specifier = ">=2.5.3,<3.0.0" },
|
| 273 |
{ name = "pydantic-settings", specifier = ">=2.6.1" },
|
| 274 |
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.3" },
|
| 275 |
+
{ name = "pytest", marker = "extra == 'tests'", specifier = ">=8.3.3" },
|
| 276 |
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.5" },
|
| 277 |
+
{ name = "pytest-asyncio", marker = "extra == 'tests'", specifier = ">=0.23.5" },
|
| 278 |
+
{ name = "pytest-flakefinder", marker = "extra == 'dev'" },
|
| 279 |
+
{ name = "pytest-flakefinder", marker = "extra == 'tests'" },
|
| 280 |
{ name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=3.6.1" },
|
| 281 |
+
{ name = "pytest-xdist", marker = "extra == 'tests'", specifier = ">=3.6.1" },
|
| 282 |
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
| 283 |
{ name = "ruff", marker = "extra == 'dev'" },
|
| 284 |
+
{ name = "ruff", marker = "extra == 'tests'" },
|
| 285 |
{ name = "typer", specifier = ">=0.9.0" },
|
| 286 |
]
|
| 287 |
|
|
|
|
| 759 |
{ url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 },
|
| 760 |
]
|
| 761 |
|
| 762 |
+
[[package]]
|
| 763 |
+
name = "pytest-flakefinder"
|
| 764 |
+
version = "1.1.0"
|
| 765 |
+
source = { registry = "https://pypi.org/simple" }
|
| 766 |
+
dependencies = [
|
| 767 |
+
{ name = "pytest" },
|
| 768 |
+
]
|
| 769 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ec/53/69c56a93ea057895b5761c5318455804873a6cd9d796d7c55d41c2358125/pytest-flakefinder-1.1.0.tar.gz", hash = "sha256:e2412a1920bdb8e7908783b20b3d57e9dad590cc39a93e8596ffdd493b403e0e", size = 6795 }
|
| 770 |
+
wheels = [
|
| 771 |
+
{ url = "https://files.pythonhosted.org/packages/33/8b/06787150d0fd0cbd3a8054262b56f91631c7778c1bc91bf4637e47f909ad/pytest_flakefinder-1.1.0-py2.py3-none-any.whl", hash = "sha256:741e0e8eea427052f5b8c89c2b3c3019a50c39a59ce4df6a305a2c2d9ba2bd13", size = 4644 },
|
| 772 |
+
]
|
| 773 |
+
|
| 774 |
[[package]]
|
| 775 |
name = "pytest-xdist"
|
| 776 |
version = "3.6.1"
|