mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 21:14:17 +02:00
Merge branch 'main' into windows
This commit is contained in:
commit
f5bc5cea98
4 changed files with 32 additions and 37 deletions
17
.github/workflows/run-tests.yml
vendored
17
.github/workflows/run-tests.yml
vendored
|
|
@ -12,12 +12,14 @@ on:
|
|||
- "tests/**"
|
||||
- "uv.lock"
|
||||
- "pyproject.toml"
|
||||
- ".github/workflows/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
- "uv.lock"
|
||||
- "pyproject.toml"
|
||||
- ".github/workflows/**"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
|
|
@ -26,8 +28,13 @@ permissions:
|
|||
|
||||
jobs:
|
||||
run_tests:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
name: "Run tests: Python ${{ matrix.python-version }} on ${{ matrix.os }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.10"]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -35,11 +42,11 @@ jobs:
|
|||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
|
||||
- name: Set up Python
|
||||
run: uv python install 3.11
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
run: uv python install ${{ matrix.python-version }}
|
||||
|
||||
- name: Install FastMCP
|
||||
run: uv sync --extra dev
|
||||
run: uv sync --extra tests
|
||||
|
||||
- name: Run tests
|
||||
run: uv run pytest -vv
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -464,23 +464,20 @@ FastMCP requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).
|
|||
|
||||
### Installation
|
||||
|
||||
Create a fork of this repository, then clone it:
|
||||
For development, we recommend installing FastMCP with development dependencies, which includes various utilities the maintainers find useful.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YouFancyUserYou/fastmcp.git
|
||||
git clone https://github.com/jlowin/fastmcp.git
|
||||
cd fastmcp
|
||||
uv sync --frozen --extra dev
|
||||
```
|
||||
|
||||
Next, create a virtual environment and install FastMCP:
|
||||
For running tests only (e.g., in CI), you only need the testing dependencies:
|
||||
|
||||
```bash
|
||||
uv venv
|
||||
source .venv/bin/activate
|
||||
uv sync --frozen --all-extras --dev
|
||||
uv sync --frozen --extra tests
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Testing
|
||||
|
||||
Please make sure to test any new functionality. Your tests should be simple and atomic and anticipate change rather than cement complex patterns.
|
||||
|
|
|
|||
|
|
@ -23,16 +23,14 @@ requires = ["hatchling>=1.21.0", "hatch-vcs>=0.4.0"]
|
|||
build-backend = "hatchling.build"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"copychat>=0.5.2",
|
||||
"ipython>=8.12.3",
|
||||
"pdbpp>=0.10.3",
|
||||
tests = [
|
||||
"pre-commit",
|
||||
"pytest-xdist>=3.6.1",
|
||||
"pytest>=8.3.3",
|
||||
"pytest-asyncio>=0.23.5",
|
||||
"pytest-xdist>=3.6.1",
|
||||
"ruff",
|
||||
]
|
||||
dev = ["fastmcp[tests]", "copychat>=0.5.2", "ipython>=8.12.3", "pdbpp>=0.10.3"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
|
|
|
|||
|
|
@ -1,34 +1,17 @@
|
|||
"""Base classes and interfaces for FastMCP resources."""
|
||||
|
||||
import abc
|
||||
from typing import Annotated, Union
|
||||
from typing import Union
|
||||
|
||||
from pydantic import (
|
||||
AnyUrl,
|
||||
BaseModel,
|
||||
BeforeValidator,
|
||||
ConfigDict,
|
||||
Field,
|
||||
FileUrl,
|
||||
ValidationInfo,
|
||||
field_validator,
|
||||
)
|
||||
from pydantic.networks import _BaseUrl # TODO: remove this once pydantic is updated
|
||||
|
||||
|
||||
def maybe_cast_str_to_any_url(x) -> AnyUrl:
|
||||
if isinstance(x, FileUrl):
|
||||
return x
|
||||
elif isinstance(x, AnyUrl):
|
||||
return x
|
||||
elif isinstance(x, str):
|
||||
if x.startswith("file://"):
|
||||
return FileUrl(x)
|
||||
return AnyUrl(x)
|
||||
raise ValueError(f"Expected str or AnyUrl, got {type(x)}")
|
||||
|
||||
|
||||
LaxAnyUrl = Annotated[_BaseUrl | str, BeforeValidator(maybe_cast_str_to_any_url)]
|
||||
|
||||
|
||||
class Resource(BaseModel, abc.ABC):
|
||||
|
|
@ -36,7 +19,8 @@ class Resource(BaseModel, abc.ABC):
|
|||
|
||||
model_config = ConfigDict(validate_default=True)
|
||||
|
||||
uri: LaxAnyUrl = Field(default=..., description="URI of the resource")
|
||||
# uri: Annotated[AnyUrl, BeforeValidator(maybe_cast_str_to_any_url)] = Field(
|
||||
uri: AnyUrl = Field(default=..., description="URI of the resource")
|
||||
name: str | None = Field(description="Name of the resource", default=None)
|
||||
description: str | None = Field(
|
||||
description="Description of the resource", default=None
|
||||
|
|
@ -47,6 +31,15 @@ class Resource(BaseModel, abc.ABC):
|
|||
pattern=r"^[a-zA-Z0-9]+/[a-zA-Z0-9\-+.]+$",
|
||||
)
|
||||
|
||||
@field_validator("uri", mode="before")
|
||||
def validate_uri(cls, uri: AnyUrl | str) -> AnyUrl:
|
||||
if isinstance(uri, str):
|
||||
# AnyUrl doesn't support triple-slashes, but files do ("file:///absolute/path")
|
||||
if uri.startswith("file://"):
|
||||
return FileUrl(uri)
|
||||
return AnyUrl(uri)
|
||||
return uri
|
||||
|
||||
@field_validator("name", mode="before")
|
||||
@classmethod
|
||||
def set_default_name(cls, name: str | None, info: ValidationInfo) -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue