mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-22 13:34:17 +02:00
Merge pull request #2914 from jlowin/jlowin/version-spec-in-enabled
This commit is contained in:
commit
837038677d
4 changed files with 53 additions and 12 deletions
|
|
@ -511,7 +511,7 @@ class Provider:
|
|||
*,
|
||||
names: set[str] | None = None,
|
||||
keys: set[str] | None = None,
|
||||
version: str | None = None,
|
||||
version: VersionSpec | None = None,
|
||||
tags: set[str] | None = None,
|
||||
components: list[Literal["tool", "resource", "template", "prompt"]]
|
||||
| None = None,
|
||||
|
|
@ -529,7 +529,8 @@ class Provider:
|
|||
Args:
|
||||
names: Component names or URIs to enable.
|
||||
keys: Component keys to enable (e.g., {"tool:my_tool@v1"}).
|
||||
version: Component version to enable.
|
||||
version: Component version spec to enable (e.g., VersionSpec(eq="v1") or
|
||||
VersionSpec(gte="v2")). Unversioned components will not match.
|
||||
tags: Enable components with these tags.
|
||||
components: Component types to include (e.g., ["tool", "prompt"]).
|
||||
only: If True, ONLY enable matching components (allowlist mode).
|
||||
|
|
@ -559,7 +560,7 @@ class Provider:
|
|||
*,
|
||||
names: set[str] | None = None,
|
||||
keys: set[str] | None = None,
|
||||
version: str | None = None,
|
||||
version: VersionSpec | None = None,
|
||||
tags: set[str] | None = None,
|
||||
components: list[Literal["tool", "resource", "template", "prompt"]]
|
||||
| None = None,
|
||||
|
|
@ -573,7 +574,8 @@ class Provider:
|
|||
Args:
|
||||
names: Component names or URIs to disable.
|
||||
keys: Component keys to disable (e.g., {"tool:my_tool@v1"}).
|
||||
version: Component version to disable.
|
||||
version: Component version spec to disable (e.g., VersionSpec(eq="v1") or
|
||||
VersionSpec(gte="v2")). Unversioned components will not match.
|
||||
tags: Disable components with these tags.
|
||||
components: Component types to include (e.g., ["tool", "prompt"]).
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class Enabled(Transform):
|
|||
*,
|
||||
names: set[str] | None = None,
|
||||
keys: set[str] | None = None,
|
||||
version: str | None = None,
|
||||
version: VersionSpec | None = None,
|
||||
tags: frozenset[str] | None = None,
|
||||
components: frozenset[str] | None = None,
|
||||
match_all: bool = False,
|
||||
|
|
@ -75,7 +75,8 @@ class Enabled(Transform):
|
|||
enabled: If True, mark matching as enabled; if False, mark as disabled.
|
||||
names: Component names or URIs to match.
|
||||
keys: Component keys to match (e.g., {"tool:my_tool@v1"}).
|
||||
version: Component version to match.
|
||||
version: Component version spec to match. Unversioned components (version=None)
|
||||
will NOT match a version spec.
|
||||
tags: Tags to match (component must have at least one).
|
||||
components: Component types to match (e.g., frozenset({"tool", "prompt"})).
|
||||
match_all: If True, matches all components regardless of other criteria.
|
||||
|
|
@ -160,7 +161,10 @@ class Enabled(Transform):
|
|||
return False
|
||||
|
||||
# Check version if specified
|
||||
if self.version is not None and component.version != self.version:
|
||||
# Note: match_none=False means unversioned components don't match a version spec
|
||||
if self.version is not None and not self.version.matches(
|
||||
component.version, match_none=False
|
||||
):
|
||||
return False
|
||||
|
||||
# Check tags if specified (component must have at least one matching tag)
|
||||
|
|
|
|||
|
|
@ -42,18 +42,21 @@ class VersionSpec:
|
|||
lt: str | None = None
|
||||
eq: str | None = None
|
||||
|
||||
def matches(self, version: str | None) -> bool:
|
||||
def matches(self, version: str | None, *, match_none: bool = True) -> bool:
|
||||
"""Check if a version matches this spec.
|
||||
|
||||
Args:
|
||||
version: The version to check, or None for unversioned.
|
||||
match_none: Whether unversioned (None) components match. Defaults to True
|
||||
for backward compatibility with retrieval operations. Set to False
|
||||
when filtering (e.g., enable/disable) to exclude unversioned components
|
||||
from version-specific rules.
|
||||
|
||||
Returns:
|
||||
True if the version matches the spec.
|
||||
"""
|
||||
if version is None:
|
||||
# Unversioned components always match
|
||||
return True
|
||||
return match_none
|
||||
|
||||
if self.eq is not None:
|
||||
return version == self.eq
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import pytest
|
|||
|
||||
from fastmcp.server.transforms.enabled import Enabled, is_enabled
|
||||
from fastmcp.tools.tool import Tool
|
||||
from fastmcp.utilities.versions import VersionSpec
|
||||
|
||||
|
||||
class TestMatching:
|
||||
|
|
@ -27,10 +28,41 @@ class TestMatching:
|
|||
|
||||
def test_match_by_version(self):
|
||||
"""Matches component by version."""
|
||||
t = Enabled(False, version="v1")
|
||||
t = Enabled(False, version=VersionSpec(eq="v1"))
|
||||
assert t._matches(Tool(name="foo", version="v1", parameters={})) is True
|
||||
assert t._matches(Tool(name="foo", version="v2", parameters={})) is False
|
||||
|
||||
def test_match_by_version_spec_exact(self):
|
||||
"""VersionSpec(eq="v1") matches v1 only."""
|
||||
t = Enabled(False, version=VersionSpec(eq="v1"))
|
||||
assert t._matches(Tool(name="foo", version="v1", parameters={})) is True
|
||||
assert t._matches(Tool(name="foo", version="v2", parameters={})) is False
|
||||
assert t._matches(Tool(name="foo", version="v0", parameters={})) is False
|
||||
|
||||
def test_match_by_version_spec_gte(self):
|
||||
"""VersionSpec(gte="v2") matches v2, v3, but not v1."""
|
||||
t = Enabled(False, version=VersionSpec(gte="v2"))
|
||||
assert t._matches(Tool(name="foo", version="v1", parameters={})) is False
|
||||
assert t._matches(Tool(name="foo", version="v2", parameters={})) is True
|
||||
assert t._matches(Tool(name="foo", version="v3", parameters={})) is True
|
||||
|
||||
def test_match_by_version_spec_range(self):
|
||||
"""VersionSpec(gte="v1", lt="v3") matches v1, v2, but not v3."""
|
||||
t = Enabled(False, version=VersionSpec(gte="v1", lt="v3"))
|
||||
assert t._matches(Tool(name="foo", version="v0", parameters={})) is False
|
||||
assert t._matches(Tool(name="foo", version="v1", parameters={})) is True
|
||||
assert t._matches(Tool(name="foo", version="v2", parameters={})) is True
|
||||
assert t._matches(Tool(name="foo", version="v3", parameters={})) is False
|
||||
assert t._matches(Tool(name="foo", version="v4", parameters={})) is False
|
||||
|
||||
def test_unversioned_does_not_match_version_spec(self):
|
||||
"""Unversioned components (version=None) don't match a VersionSpec."""
|
||||
t = Enabled(False, version=VersionSpec(eq="v1"))
|
||||
assert t._matches(Tool(name="foo", parameters={})) is False
|
||||
|
||||
t2 = Enabled(False, version=VersionSpec(gte="v1"))
|
||||
assert t2._matches(Tool(name="foo", parameters={})) is False
|
||||
|
||||
def test_match_by_tag(self):
|
||||
"""Matches if component has any of the specified tags."""
|
||||
t = Enabled(False, tags=frozenset({"internal", "deprecated"}))
|
||||
|
|
@ -48,7 +80,7 @@ class TestMatching:
|
|||
t = Enabled(
|
||||
False,
|
||||
names={"foo"},
|
||||
version="v1",
|
||||
version=VersionSpec(eq="v1"),
|
||||
tags=frozenset({"internal"}),
|
||||
)
|
||||
# All match
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue