Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
# Release Notes

## 2.0.0

### ⚠️ Breaking Change

`ExecutionContext.fetch()` now returns a `FetchResponse` object instead of the raw parsed body.

**Before (1.x):**
```python
data = await context.fetch("https://api.example.com/items")
# data was the parsed JSON dict/list or text string directly
items = data["results"]
```

**After (2.0):**
```python
response = await context.fetch("https://api.example.com/items")
# response is a FetchResponse with .status, .headers, and .data
items = response.data["results"]
```

`FetchResponse` attributes:
- `status` — HTTP status code (e.g. `200`, `201`)
- `headers` — response headers as a plain `dict`
- `data` — parsed JSON (`dict`/`list`) for `application/json` responses, raw text otherwise, `None` for empty 200/201/204 responses

### Migration Guide

1. **Find all `context.fetch()` calls** in your integration code
2. **Access the response body via `.data`** — the return value is now a `FetchResponse` object, not the raw body:
```python
# Before
result = await context.fetch(url)
return ActionResult(data=result)

# After
result = await context.fetch(url)
return ActionResult(data=result.data)
```
3. **Optional: use `.status` and `.headers`** for richer error handling or response inspection:
```python
response = await context.fetch(url)
if response.status == 201:
log.info(f"Created, location: {response.headers.get('Location')}")
```

### Other Changes
- Add `FetchResponse` class, exported from the package
- Add pytest test suite (72 tests, 99% coverage) with `pytest-asyncio` and `aioresponses`
- Add GitHub Actions CI workflow with coverage reporting on PRs
- Add coverage badge and CI status badges to READMEs

## 1.1.1
- Export HTTPError and RateLimitError from package for direct import
- Added PyPI-optimised README with absolute links and best practices
Expand Down
2 changes: 1 addition & 1 deletion docs/apidocs/autohive_integrations_sdk.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ <h1 class="modulename">
<label class="view-source-button" for="mod-autohive_integrations_sdk-view-source"><span>View Source</span></label>

<div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">1</span></a><span class="c1"># Version</span>
</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;1.1.1&quot;</span>
</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;2.0.0&quot;</span>
</span><span id="L-3"><a href="#L-3"><span class="linenos">3</span></a>
</span><span id="L-4"><a href="#L-4"><span class="linenos">4</span></a><span class="c1"># Re-export classes from integration module</span>
</span><span id="L-5"><a href="#L-5"><span class="linenos">5</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">autohive_integrations_sdk.integration</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
Expand Down
4,442 changes: 2,224 additions & 2,218 deletions docs/apidocs/autohive_integrations_sdk/integration.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/apidocs/search.js

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ build-backend = "hatchling.build"

[project]
name = "autohive_integrations_sdk"
version = "1.1.1"
version = "2.0.0"
authors = [
{ name="Hamish Taylor", email="hamish@autohive.com" },
{ name="Reilly Oldham", email="reilly@autohive.com" },
{ name="Kai Koenig", email="kai@autohive.com" },
{ name="Ninos Awas", email="ninos@raygun.com" }
Expand Down
2 changes: 1 addition & 1 deletion src/autohive_integrations_sdk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Version
__version__ = "1.1.1"
__version__ = "2.0.0"

# Re-export classes from integration module
from autohive_integrations_sdk.integration import (
Expand Down
36 changes: 36 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,3 +550,39 @@ async def execute(self, inputs, context):
return ActionResult(data={"greeting": "second"})

assert integration._action_handlers["test_action"] is Second


# ── Abstract base class pass-through ───────────────────────────────────────


async def test_action_handler_abstract_execute_returns_none():
"""super().execute() on the ABC body executes the `pass` and returns None."""

class Concrete(ActionHandler):
async def execute(self, inputs, context):
return await super().execute(inputs, context)

result = await Concrete().execute({}, None)
assert result is None


async def test_polling_trigger_handler_abstract_poll_returns_none():
"""super().poll() on the ABC body executes the `pass` and returns None."""

class Concrete(PollingTriggerHandler):
async def poll(self, inputs, last_poll_ts, context):
return await super().poll(inputs, last_poll_ts, context)

result = await Concrete().poll({}, None, None)
assert result is None


async def test_connected_account_handler_abstract_get_account_info_returns_none():
"""super().get_account_info() on the ABC body executes the `pass` and returns None."""

class Concrete(ConnectedAccountHandler):
async def get_account_info(self, context):
return await super().get_account_info(context)

result = await Concrete().get_account_info(None)
assert result is None
Loading