diff --git a/pyproject.toml b/pyproject.toml index 387fef3..f96876a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,6 @@ dependencies = [ "httpx>=0.27,<1.0", "pydantic>=2.6,<3.0", "pydantic-settings>=2.2,<3.0", - "requests>=2.33.0,<3.0", "sqlalchemy>=2.0,<3.0", "sse-starlette>=2.1,<4.0", "uvicorn>=0.29,<1.0", @@ -72,6 +71,9 @@ package = true fallback_version = "0+unknown" tag_regex = "^v?(?P.+)$" +[tool.setuptools.package-data] +opencode_a2a = ["py.typed"] + [tool.mypy] python_version = "3.11" files = ["src/opencode_a2a"] diff --git a/scripts/smoke_test_built_cli.sh b/scripts/smoke_test_built_cli.sh index 7619278..c3d3c45 100644 --- a/scripts/smoke_test_built_cli.sh +++ b/scripts/smoke_test_built_cli.sh @@ -77,6 +77,18 @@ UV_TOOL_DIR="${tool_dir}" \ UV_TOOL_BIN_DIR="${tool_bin_dir}" \ uv tool install "${artifact_path}" --python "${python_bin}" +mapfile -t installed_python_paths < <( + find "${tool_dir}" \( -type f -o -type l \) -path '*/bin/python' | sort +) +if [[ "${#installed_python_paths[@]}" -ne 1 ]]; then + echo "Expected exactly one installed tool python, found ${#installed_python_paths[@]}" >&2 + printf ' - %s\n' "${installed_python_paths[@]}" >&2 || true + exit 1 +fi +installed_python="${installed_python_paths[0]}" + +"${installed_python}" -c "import opencode_a2a; print(opencode_a2a.__version__)" >/dev/null + port="$( "${python_bin}" - <<'PY' import socket diff --git a/src/opencode_a2a/__init__.py b/src/opencode_a2a/__init__.py index 78b3fca..7f17035 100644 --- a/src/opencode_a2a/__init__.py +++ b/src/opencode_a2a/__init__.py @@ -1,8 +1,11 @@ """A2A wrapper for opencode.""" +import logging from importlib.metadata import PackageNotFoundError, version UNKNOWN_VERSION = "0+unknown" +logger = logging.getLogger("opencode_a2a") +logger.addHandler(logging.NullHandler()) def get_package_version() -> str: diff --git a/src/opencode_a2a/py.typed b/src/opencode_a2a/py.typed new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/opencode_a2a/py.typed @@ -0,0 +1 @@ + diff --git a/tests/package/test_logging.py b/tests/package/test_logging.py new file mode 100644 index 0000000..80c5a58 --- /dev/null +++ b/tests/package/test_logging.py @@ -0,0 +1,9 @@ +import logging + +from opencode_a2a import logger + + +def test_package_logger_installs_null_handler() -> None: + handlers = logger.handlers + + assert any(isinstance(handler, logging.NullHandler) for handler in handlers) diff --git a/tests/package/test_typing_contract.py b/tests/package/test_typing_contract.py new file mode 100644 index 0000000..071694f --- /dev/null +++ b/tests/package/test_typing_contract.py @@ -0,0 +1,9 @@ +from pathlib import Path + +PYPROJECT_TEXT = Path("pyproject.toml").read_text() + + +def test_package_declares_py_typed_marker() -> None: + assert Path("src/opencode_a2a/py.typed").is_file() + assert "[tool.setuptools.package-data]" in PYPROJECT_TEXT + assert 'opencode_a2a = ["py.typed"]' in PYPROJECT_TEXT diff --git a/tests/scripts/test_script_health_contract.py b/tests/scripts/test_script_health_contract.py index fd5b9d1..238b6e9 100644 --- a/tests/scripts/test_script_health_contract.py +++ b/tests/scripts/test_script_health_contract.py @@ -58,6 +58,13 @@ def test_smoke_test_requires_explicit_wheel_selection_when_dist_is_ambiguous() - assert 'uv tool install "${artifact_path}" --python "${python_bin}"' in SMOKE_TEST_TEXT +def test_smoke_test_imports_installed_package_before_health_check() -> None: + assert "find \"${tool_dir}\" \\( -type f -o -type l \\) -path '*/bin/python'" in SMOKE_TEST_TEXT + assert '"${installed_python}" -c "import opencode_a2a; print(opencode_a2a.__version__)"' in ( + SMOKE_TEST_TEXT + ) + + def test_coverage_policy_tracks_overall_and_critical_file_thresholds() -> None: assert "OVERALL_MINIMUM = 90.0" in COVERAGE_GATE_TEXT assert '"src/opencode_a2a/execution/executor.py": 90.0' in COVERAGE_GATE_TEXT diff --git a/uv.lock b/uv.lock index 004867f..50b06a6 100644 --- a/uv.lock +++ b/uv.lock @@ -751,7 +751,6 @@ dependencies = [ { name = "httpx" }, { name = "pydantic" }, { name = "pydantic-settings" }, - { name = "requests" }, { name = "sqlalchemy" }, { name = "sse-starlette" }, { name = "uvicorn" }, @@ -782,7 +781,6 @@ requires-dist = [ { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0,<10.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23,<2.0" }, { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=7.0.0,<8.0.0" }, - { name = "requests", specifier = ">=2.33.0,<3.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5,<0.16" }, { name = "sqlalchemy", specifier = ">=2.0,<3.0" }, { name = "sse-starlette", specifier = ">=2.1,<4.0" },