From 8e1fa7a55144218fe58038326448372a66bc32db Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Mon, 2 Dec 2024 20:06:57 -0600 Subject: [PATCH] fix warning and flake --- pyproject.toml | 1 + tests/test_cli.py | 84 ++++++++++++++++++++----------------- tests/test_func_metadata.py | 18 ++++---- uv.lock | 30 ++++++++++++- 4 files changed, 85 insertions(+), 48 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8c3c4152d..15f0848ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ tests = [ "pre-commit", "pytest>=8.3.3", "pytest-asyncio>=0.23.5", + "pytest-flakefinder", "pytest-xdist>=3.6.1", "ruff", ] diff --git a/tests/test_cli.py b/tests/test_cli.py index f81538148..a26874a59 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,12 +3,12 @@ import json import sys from pathlib import Path -from unittest.mock import patch, call +from unittest.mock import call, patch import pytest from typer.testing import CliRunner -from fastmcp.cli.cli import app, _parse_env_var, _parse_file_path +from fastmcp.cli.cli import _parse_env_var, _parse_file_path, app @pytest.fixture @@ -297,47 +297,53 @@ mcp = FastMCP("test", dependencies=["pandas", "numpy"]) assert mock_run.call_args_list[0] == call( ["npx.cmd", "--version"], check=True, capture_output=True, shell=True ) - assert mock_run.call_args_list[1] == call( - [ - "npx.cmd", - "@modelcontextprotocol/inspector", - "uv", - "run", - "--with", - "fastmcp", - "--with", - "numpy", - "--with", - "pandas", - "fastmcp", - "run", - str(server_file), - ], - check=True, - shell=True, + + # get the actual command and expected command without dependencies + actual_cmd = mock_run.call_args_list[1][0][0] + expected_start = [ + "npx.cmd", + "@modelcontextprotocol/inspector", + "uv", + "run", + "--with", + "fastmcp", + ] + expected_end = ["fastmcp", "run", str(server_file)] + + # verify start and end of command + assert actual_cmd[: len(expected_start)] == expected_start + assert actual_cmd[-len(expected_end) :] == expected_end + + # verify dependencies are present (order-independent) + deps_section = actual_cmd[len(expected_start) : -len(expected_end)] + assert all( + x in deps_section for x in ["--with", "numpy", "--with", "pandas"] ) + + assert mock_run.call_args_list[1][1] == {"check": True, "shell": True} else: - # On Unix, expect one call - mock_run.assert_called_once_with( - [ - "npx", - "@modelcontextprotocol/inspector", - "uv", - "run", - "--with", - "fastmcp", - "--with", - "numpy", - "--with", - "pandas", - "fastmcp", - "run", - str(server_file), - ], - check=True, - shell=False, # Note: shell=False on Unix + # same verification for unix, just with different command prefix + actual_cmd = mock_run.call_args_list[0][0][0] + expected_start = [ + "npx", + "@modelcontextprotocol/inspector", + "uv", + "run", + "--with", + "fastmcp", + ] + expected_end = ["fastmcp", "run", str(server_file)] + + assert actual_cmd[: len(expected_start)] == expected_start + assert actual_cmd[-len(expected_end) :] == expected_end + + deps_section = actual_cmd[len(expected_start) : -len(expected_end)] + assert all( + x in deps_section for x in ["--with", "numpy", "--with", "pandas"] ) + assert mock_run.call_args_list[0][1] == {"check": True, "shell": False} + def test_run_with_dependencies(mock_config, server_file): """Test that run command does not handle dependencies.""" diff --git a/tests/test_func_metadata.py b/tests/test_func_metadata.py index 69cf0ddf6..91a102e40 100644 --- a/tests/test_func_metadata.py +++ b/tests/test_func_metadata.py @@ -1,15 +1,17 @@ -from pydantic import BaseModel, Field from typing import Annotated + import annotated_types -from fastmcp.utilities.func_metadata import func_metadata import pytest +from pydantic import BaseModel, Field + +from fastmcp.utilities.func_metadata import func_metadata -class TestInputModelA(BaseModel): +class SomeInputModelA(BaseModel): pass -class TestInputModelB(BaseModel): +class SomeInputModelB(BaseModel): class InnerModel(BaseModel): x: int @@ -44,15 +46,15 @@ def complex_arguments_fn( int, Field(1) ], unannotated, - my_model_a: TestInputModelA, - my_model_a_forward_ref: "TestInputModelA", - my_model_b: TestInputModelB, + my_model_a: SomeInputModelA, + my_model_a_forward_ref: "SomeInputModelA", + my_model_b: SomeInputModelB, an_int_annotated_with_field_default: Annotated[ int, Field(1, description="An int with a field"), ], unannotated_with_default=5, - my_model_a_with_default: TestInputModelA = TestInputModelA(), # noqa: B008 + my_model_a_with_default: SomeInputModelA = SomeInputModelA(), # noqa: B008 an_int_with_default: int = 1, must_be_none_with_default: None = None, an_int_with_equals_field: int = Field(1, ge=0), diff --git a/uv.lock b/uv.lock index 46183dd81..748660de0 100644 --- a/uv.lock +++ b/uv.lock @@ -228,7 +228,7 @@ wheels = [ [[package]] name = "fastmcp" -version = "0.3.2.dev0+g5656200.d20241201" +version = "0.3.6.dev0+gf03184b.d20241203" source = { editable = "." } dependencies = [ { name = "httpx" }, @@ -247,6 +247,15 @@ dev = [ { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-asyncio" }, + { name = "pytest-flakefinder" }, + { name = "pytest-xdist" }, + { name = "ruff" }, +] +tests = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-flakefinder" }, { name = "pytest-xdist" }, { name = "ruff" }, ] @@ -259,13 +268,20 @@ requires-dist = [ { name = "mcp", specifier = ">=1.0.0,<2.0.0" }, { name = "pdbpp", marker = "extra == 'dev'", specifier = ">=0.10.3" }, { name = "pre-commit", marker = "extra == 'dev'" }, + { name = "pre-commit", marker = "extra == 'tests'" }, { name = "pydantic", specifier = ">=2.5.3,<3.0.0" }, { name = "pydantic-settings", specifier = ">=2.6.1" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.3" }, + { name = "pytest", marker = "extra == 'tests'", specifier = ">=8.3.3" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.5" }, + { name = "pytest-asyncio", marker = "extra == 'tests'", specifier = ">=0.23.5" }, + { name = "pytest-flakefinder", marker = "extra == 'dev'" }, + { name = "pytest-flakefinder", marker = "extra == 'tests'" }, { name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=3.6.1" }, + { name = "pytest-xdist", marker = "extra == 'tests'", specifier = ">=3.6.1" }, { name = "python-dotenv", specifier = ">=1.0.1" }, { name = "ruff", marker = "extra == 'dev'" }, + { name = "ruff", marker = "extra == 'tests'" }, { name = "typer", specifier = ">=0.9.0" }, ] @@ -743,6 +759,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, ] +[[package]] +name = "pytest-flakefinder" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/53/69c56a93ea057895b5761c5318455804873a6cd9d796d7c55d41c2358125/pytest-flakefinder-1.1.0.tar.gz", hash = "sha256:e2412a1920bdb8e7908783b20b3d57e9dad590cc39a93e8596ffdd493b403e0e", size = 6795 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/8b/06787150d0fd0cbd3a8054262b56f91631c7778c1bc91bf4637e47f909ad/pytest_flakefinder-1.1.0-py2.py3-none-any.whl", hash = "sha256:741e0e8eea427052f5b8c89c2b3c3019a50c39a59ce4df6a305a2c2d9ba2bd13", size = 4644 }, +] + [[package]] name = "pytest-xdist" version = "3.6.1"