diff --git a/.github/workflows/check-version-bump.yaml b/.github/workflows/check-version-bump.yaml index 8bbb923b..3db4af42 100644 --- a/.github/workflows/check-version-bump.yaml +++ b/.github/workflows/check-version-bump.yaml @@ -25,12 +25,12 @@ jobs: CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA") - if echo "$CHANGED_FILES" | grep -q "^src/"; then + if echo "$CHANGED_FILES" | grep -qE "^src/.*\.(py|pyi|proto)$"; then BASE_VERSION=$(git show "$BASE_SHA:pyproject.toml" | grep "^version = " | cut -d'"' -f2) HEAD_VERSION=$(git show "$HEAD_SHA:pyproject.toml" | grep "^version = " | cut -d'"' -f2) if [ "$BASE_VERSION" = "$HEAD_VERSION" ]; then - echo "ERROR: Files under src/ were modified but the version in pyproject.toml was not bumped (still $HEAD_VERSION)." + echo "ERROR: Source files under src/ were modified but the version in pyproject.toml was not bumped (still $HEAD_VERSION)." exit 1 fi @@ -42,5 +42,5 @@ jobs: echo "Version bump OK: $BASE_VERSION → $HEAD_VERSION" else - echo "No src/ changes. Version bump not required." + echo "No source file changes under src/. Version bump not required." fi diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 012883e8..f6409323 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -32,11 +32,8 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} - - name: "Run Ruff Linter" - run: uv run ruff check --output-format=github . + - name: "Install dependencies" + run: uv sync --all-extras - - name: "Run Ruff Formatter Check" - run: uv run ruff format --check --diff . - - - name: "Run ty Type Check" - run: uv run ty check --output-format github --python-version ${{ env.PYTHON_VERSION }} . + - name: "Run pre-commit hooks" + run: uvx pre-commit run --all-files diff --git a/.gitignore b/.gitignore index 70111605..e4e2b91c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,4 @@ mocks/ # Generated files PULL_REQUEST.md -RELEASE.md \ No newline at end of file +RELEASE.md diff --git a/pyproject.toml b/pyproject.toml index 35a660e7..c41737f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sap-cloud-sdk" -version = "0.25.1" +version = "0.25.2" description = "SAP Cloud SDK for Python" readme = "README.md" license = "Apache-2.0" diff --git a/src/sap_cloud_sdk/agent_memory/py.typed b/src/sap_cloud_sdk/agent_memory/py.typed index 7f8a6b09..14305056 100644 --- a/src/sap_cloud_sdk/agent_memory/py.typed +++ b/src/sap_cloud_sdk/agent_memory/py.typed @@ -1 +1 @@ -# Marker file for PEP 561 to indicate the 'agent_memory' package is typed. \ No newline at end of file +# Marker file for PEP 561 to indicate the 'agent_memory' package is typed. diff --git a/src/sap_cloud_sdk/agentgateway/user-guide.md b/src/sap_cloud_sdk/agentgateway/user-guide.md index 67c3b59f..d33629ea 100644 --- a/src/sap_cloud_sdk/agentgateway/user-guide.md +++ b/src/sap_cloud_sdk/agentgateway/user-guide.md @@ -157,5 +157,3 @@ class AgentGatewayClient: **kwargs, ) -> str ``` - - diff --git a/tests/agent_memory/integration/agentmemory.feature b/tests/agent_memory/integration/agentmemory.feature index dbe3c566..e6804f2d 100644 --- a/tests/agent_memory/integration/agentmemory.feature +++ b/tests/agent_memory/integration/agentmemory.feature @@ -88,4 +88,4 @@ Feature: Agent Memory Service Integration (v1 API) Scenario: Filter messages by metadata substring Given a message exists with agent "test-agent" invoker "test-user" group "conv-filter" role "USER" content "filter-test-message" and metadata "filter-marker" When I list messages filtered by metadata containing "filter-marker" - Then the result should contain the message with content "filter-test-message" \ No newline at end of file + Then the result should contain the message with content "filter-test-message" diff --git a/tests/agent_memory/integration/test_agentmemory_bdd.py b/tests/agent_memory/integration/test_agentmemory_bdd.py index fb7c4508..41460b68 100644 --- a/tests/agent_memory/integration/test_agentmemory_bdd.py +++ b/tests/agent_memory/integration/test_agentmemory_bdd.py @@ -17,6 +17,7 @@ from pytest_bdd import given, scenario, then, when from sap_cloud_sdk.agent_memory.client import AgentMemoryClient +from sap_cloud_sdk.agent_memory import MessageRole # -- Scenarios ----------------------------------------------------------------- @@ -258,7 +259,7 @@ def add_message(context): "test-agent", "test-user", "conv-1", - "USER", + MessageRole.USER, "Hello!", ) diff --git a/tests/agentgateway/integration/test_agw_bdd.py b/tests/agentgateway/integration/test_agw_bdd.py index 37704b07..0d6799da 100644 --- a/tests/agentgateway/integration/test_agw_bdd.py +++ b/tests/agentgateway/integration/test_agw_bdd.py @@ -101,6 +101,7 @@ def call_get_user_auth(context: ScenarioContext, agw_client: AgentGatewayClient) def call_get_user_auth_callable(context: ScenarioContext, agw_client: AgentGatewayClient): """Call get_user_auth with a callable and store the result.""" token = context.user_token + assert token is not None context.last_result = run( agw_client.get_user_auth(user_token=lambda: token) ) diff --git a/tests/core/integration/telemetry/_agent.py b/tests/core/integration/telemetry/_agent.py index df211f74..b44ada81 100644 --- a/tests/core/integration/telemetry/_agent.py +++ b/tests/core/integration/telemetry/_agent.py @@ -1,19 +1,9 @@ """LangGraph test agent used by the telemetry integration tests.""" import os -from dataclasses import dataclass -from typing import Annotated import pytest -from langchain_core.messages import BaseMessage -from langgraph.graph.message import add_messages - - -@dataclass -class State: - messages: Annotated[list[BaseMessage], add_messages] - def build_langgraph_agent(): """Build a minimal single-node LangGraph agent backed by LiteLLM via AI Core. @@ -23,11 +13,20 @@ def build_langgraph_agent(): "sap/" prefix to route through the SAP AI Core provider. """ try: - from langchain_litellm import ChatLiteLLM - from langgraph.graph import END, StateGraph + from dataclasses import dataclass + from typing import Annotated + + from langchain_core.messages import BaseMessage + from langchain_litellm import ChatLiteLLM # ty: ignore[unresolved-import] + from langgraph.graph import END, StateGraph # ty: ignore[unresolved-import] + from langgraph.graph.message import add_messages # ty: ignore[unresolved-import] except ImportError: pytest.skip("langchain-litellm or langgraph not installed") + @dataclass + class State: + messages: Annotated[list[BaseMessage], add_messages] + model_name = os.environ.get("AICORE_MODEL") or "anthropic--claude-4.5-sonnet" llm = ChatLiteLLM(model=f"sap/{model_name}") diff --git a/tests/core/integration/telemetry/test_telemetry_bdd.py b/tests/core/integration/telemetry/test_telemetry_bdd.py index aecbc017..d53e1464 100644 --- a/tests/core/integration/telemetry/test_telemetry_bdd.py +++ b/tests/core/integration/telemetry/test_telemetry_bdd.py @@ -127,7 +127,7 @@ def _llm_call(): Uses ChatLiteLLM so Traceloop's LangChain instrumentor fires and emits a span with gen_ai.usage.* token counts. """ - from langchain_litellm import ChatLiteLLM + from langchain_litellm import ChatLiteLLM # ty: ignore[unresolved-import] from langchain_core.messages import HumanMessage as LCHumanMessage model_name = os.environ.get("AICORE_MODEL", "anthropic--claude-4.5-sonnet") llm = ChatLiteLLM(model=f"sap/{model_name}") diff --git a/tests/core/unit/data_anonymization/test_http_transport.py b/tests/core/unit/data_anonymization/test_http_transport.py index 2b328ca4..afd67c8f 100644 --- a/tests/core/unit/data_anonymization/test_http_transport.py +++ b/tests/core/unit/data_anonymization/test_http_transport.py @@ -1,6 +1,7 @@ """Unit tests for the HTTP transport.""" import base64 +from collections.abc import Mapping from pathlib import Path import importlib import types @@ -55,7 +56,7 @@ def __init__( self.status_code = status_code self._json_data = json_data self.text = text - self.headers = headers or {} + self.headers: Mapping[str, str] = headers or {} self.content = content def json(self): diff --git a/tests/destination/integration/destination.feature b/tests/destination/integration/destination.feature index 9a489b39..45cbb3ef 100644 --- a/tests/destination/integration/destination.feature +++ b/tests/destination/integration/destination.feature @@ -316,4 +316,3 @@ Feature: Destination Service Integration # Then the destination creation should be successful # When I get subaccount destination "test-dest-sub-isolation" with "PROVIDER_ONLY" access strategy # Then the destination should not be found - diff --git a/tests/dms/integration/conftest.py b/tests/dms/integration/conftest.py index 254a83b7..e26d4dec 100644 --- a/tests/dms/integration/conftest.py +++ b/tests/dms/integration/conftest.py @@ -14,7 +14,7 @@ def dms_client(): client = create_client(instance="default") return client except Exception as e: - pytest.skip(f"DMS integration tests require credentials: {e}") # ty: ignore[invalid-argument-type, too-many-positional-arguments] + pytest.skip(f"DMS integration tests require credentials: {e}") def _setup_cloud_mode(): diff --git a/tests/dms/integration/test_dms_bdd.py b/tests/dms/integration/test_dms_bdd.py index 3abe4e8b..f68753d5 100644 --- a/tests/dms/integration/test_dms_bdd.py +++ b/tests/dms/integration/test_dms_bdd.py @@ -128,7 +128,7 @@ def select_version_repo(context: DMSTestContext, dms_client: DMSClient): version_repo = r break if version_repo is None: - pytest.skip("No version-enabled repository available") # ty: ignore[invalid-argument-type, too-many-positional-arguments] + pytest.skip("No version-enabled repository available") context.repo = version_repo context.repo_id = version_repo.id diff --git a/tests/extensibility/unit/test_ums_caching.py b/tests/extensibility/unit/test_ums_caching.py index 9af3c302..fa1ee6ef 100644 --- a/tests/extensibility/unit/test_ums_caching.py +++ b/tests/extensibility/unit/test_ums_caching.py @@ -334,4 +334,3 @@ def test_cache_hit_refreshes_lru_position(self): assert ("tenant-new", "default") in transport._cache finally: patcher.stop() - diff --git a/tests/extensibility/unit/test_ums_pagination.py b/tests/extensibility/unit/test_ums_pagination.py index c79a6edb..39198bf6 100644 --- a/tests/extensibility/unit/test_ums_pagination.py +++ b/tests/extensibility/unit/test_ums_pagination.py @@ -340,4 +340,3 @@ def test_missing_page_info_stops_pagination(self): def test_max_pages_constant(self): """Safety limit constant is 100.""" assert _MAX_PAGES == 100 - diff --git a/tests/extensibility/unit/test_ums_parsing.py b/tests/extensibility/unit/test_ums_parsing.py index 542e9720..0cb2af6b 100644 --- a/tests/extensibility/unit/test_ums_parsing.py +++ b/tests/extensibility/unit/test_ums_parsing.py @@ -459,4 +459,3 @@ def test_tools_key_missing(self): } result = _transform_ums_response(data, "default") assert result.mcp_servers == [] -