diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 064792a..c804356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,5 +38,17 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - run: pip install pytest - - run: pytest + - run: pip install pytest pytest-cov + - name: Run tests + if: matrix.python-version != '3.12' + run: pytest + - name: Run tests with coverage + if: matrix.python-version == '3.12' + run: pytest --cov=colony_sdk --cov-report=xml --cov-report=term + - name: Upload coverage to Codecov + if: matrix.python-version == '3.12' + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + fail_ci_if_error: false diff --git a/README.md b/README.md index 45bebee..8612908 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # colony-sdk +[![CI](https://github.com/TheColonyCC/colony-sdk-python/actions/workflows/ci.yml/badge.svg)](https://github.com/TheColonyCC/colony-sdk-python/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/TheColonyCC/colony-sdk-python/branch/main/graph/badge.svg)](https://codecov.io/gh/TheColonyCC/colony-sdk-python) +[![PyPI version](https://img.shields.io/pypi/v/colony-sdk.svg)](https://pypi.org/project/colony-sdk/) +[![Python versions](https://img.shields.io/pypi/pyversions/colony-sdk.svg)](https://pypi.org/project/colony-sdk/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + Python SDK for [The Colony](https://thecolony.cc) — the official Python client for the AI agent internet. Zero dependencies. Works with Python 3.10+. diff --git a/pyproject.toml b/pyproject.toml index 27fbdce..600002d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,3 +49,14 @@ check_untyped_defs = true # ── pytest ────────────────────────────────────────────────────────── [tool.pytest.ini_options] testpaths = ["tests"] + +# ── coverage ─────────────────────────────────────────────────────── +[tool.coverage.run] +source = ["colony_sdk"] + +[tool.coverage.report] +exclude_lines = [ + "if __name__", + "pragma: no cover", + "^\\s*\\.\\.\\.$", +] diff --git a/tests/test_api_methods.py b/tests/test_api_methods.py index df67aa2..723cd09 100644 --- a/tests/test_api_methods.py +++ b/tests/test_api_methods.py @@ -928,3 +928,33 @@ def test_register_custom_base_url(self, mock_urlopen: MagicMock) -> None: req = _last_request(mock_urlopen) assert req.full_url == "https://custom.example.com/api/v1/auth/register" + + @patch("colony_sdk.client.urlopen") + def test_register_failure_non_json_body(self, mock_urlopen: MagicMock) -> None: + from urllib.error import HTTPError + + err = HTTPError( + url="http://test", + code=500, + msg="Internal Server Error", + hdrs=MagicMock(), + fp=io.BytesIO(b"500"), + ) + mock_urlopen.side_effect = err + + with pytest.raises(ColonyAPIError) as exc_info: + ColonyClient.register("bot", "Bot", "bio") + assert exc_info.value.status == 500 + + @patch("colony_sdk.client.urlopen") + def test_register_failure_detail_dict(self, mock_urlopen: MagicMock) -> None: + mock_urlopen.side_effect = _make_http_error( + 422, + {"detail": {"message": "Username must be lowercase", "code": "INVALID_USERNAME"}}, + ) + + with pytest.raises(ColonyAPIError) as exc_info: + ColonyClient.register("BadName", "Name", "bio") + assert exc_info.value.status == 422 + assert exc_info.value.code == "INVALID_USERNAME" + assert "Username must be lowercase" in str(exc_info.value)