hookbase 2.0.0__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. hookbase-2.1.1/.github/workflows/python-publish.yml +86 -0
  2. {hookbase-2.0.0 → hookbase-2.1.1}/PKG-INFO +2 -1
  3. {hookbase-2.0.0 → hookbase-2.1.1}/pyproject.toml +1 -0
  4. hookbase-2.1.1/src/hookbase/_version.py +1 -0
  5. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/deliveries.py +4 -2
  6. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/events.py +1 -1
  7. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/portal_tokens.py +0 -2
  8. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/sources.py +4 -1
  9. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/test_sources.py +79 -0
  10. hookbase-2.0.0/src/hookbase/_version.py +0 -1
  11. {hookbase-2.0.0 → hookbase-2.1.1}/.gitignore +0 -0
  12. {hookbase-2.0.0 → hookbase-2.1.1}/LICENSE +0 -0
  13. {hookbase-2.0.0 → hookbase-2.1.1}/README.md +0 -0
  14. {hookbase-2.0.0 → hookbase-2.1.1}/examples/async_usage.py +0 -0
  15. {hookbase-2.0.0 → hookbase-2.1.1}/examples/basic_inbound.py +0 -0
  16. {hookbase-2.0.0 → hookbase-2.1.1}/examples/error_handling.py +0 -0
  17. {hookbase-2.0.0 → hookbase-2.1.1}/examples/send_webhooks.py +0 -0
  18. {hookbase-2.0.0 → hookbase-2.1.1}/examples/verify_webhooks.py +0 -0
  19. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/__init__.py +0 -0
  20. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/_client.py +0 -0
  21. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/_constants.py +0 -0
  22. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/_pagination.py +0 -0
  23. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/client.py +0 -0
  24. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/errors.py +0 -0
  25. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/__init__.py +0 -0
  26. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/_base.py +0 -0
  27. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/analytics.py +0 -0
  28. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/api_keys.py +0 -0
  29. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/applications.py +0 -0
  30. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/common.py +0 -0
  31. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/cron_jobs.py +0 -0
  32. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/destinations.py +0 -0
  33. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/dlq.py +0 -0
  34. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/endpoints.py +0 -0
  35. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/event_types.py +0 -0
  36. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/filters.py +0 -0
  37. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/messages.py +0 -0
  38. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/organizations.py +0 -0
  39. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/routes.py +0 -0
  40. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/schemas.py +0 -0
  41. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/subscriptions.py +0 -0
  42. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/transforms.py +0 -0
  43. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/models/tunnels.py +0 -0
  44. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/py.typed +0 -0
  45. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/__init__.py +0 -0
  46. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/_base.py +0 -0
  47. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/analytics.py +0 -0
  48. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/api_keys.py +0 -0
  49. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/applications.py +0 -0
  50. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/cron_jobs.py +0 -0
  51. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/deliveries.py +0 -0
  52. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/destinations.py +0 -0
  53. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/dlq.py +0 -0
  54. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/endpoints.py +0 -0
  55. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/event_types.py +0 -0
  56. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/events.py +0 -0
  57. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/filters.py +0 -0
  58. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/message_log.py +0 -0
  59. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/messages.py +0 -0
  60. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/organizations.py +0 -0
  61. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/portal_tokens.py +0 -0
  62. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/routes.py +0 -0
  63. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/schemas.py +0 -0
  64. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/sources.py +0 -0
  65. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/subscriptions.py +0 -0
  66. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/transforms.py +0 -0
  67. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/resources/tunnels.py +0 -0
  68. {hookbase-2.0.0 → hookbase-2.1.1}/src/hookbase/webhook.py +0 -0
  69. {hookbase-2.0.0 → hookbase-2.1.1}/tests/__init__.py +0 -0
  70. {hookbase-2.0.0 → hookbase-2.1.1}/tests/conftest.py +0 -0
  71. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/__init__.py +0 -0
  72. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/test_applications.py +0 -0
  73. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/test_destinations.py +0 -0
  74. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/test_dlq.py +0 -0
  75. {hookbase-2.0.0 → hookbase-2.1.1}/tests/resources/test_messages.py +0 -0
  76. {hookbase-2.0.0 → hookbase-2.1.1}/tests/test_client.py +0 -0
  77. {hookbase-2.0.0 → hookbase-2.1.1}/tests/test_errors.py +0 -0
  78. {hookbase-2.0.0 → hookbase-2.1.1}/tests/test_pagination.py +0 -0
  79. {hookbase-2.0.0 → hookbase-2.1.1}/tests/test_webhook.py +0 -0
@@ -0,0 +1,86 @@
1
+ name: CI / Publish
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+ release:
9
+ types: [published]
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ matrix:
19
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ python -m pip install --upgrade pip
31
+ pip install -e ".[dev]"
32
+
33
+ - name: Lint with ruff
34
+ run: ruff check src/ tests/
35
+
36
+ - name: Type check with mypy
37
+ run: mypy src/hookbase
38
+
39
+ - name: Run tests
40
+ run: pytest -v
41
+
42
+ release-build:
43
+ if: github.event_name == 'release'
44
+ runs-on: ubuntu-latest
45
+ needs: test
46
+
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+
50
+ - uses: actions/setup-python@v5
51
+ with:
52
+ python-version: "3.x"
53
+
54
+ - name: Build release distributions
55
+ run: |
56
+ python -m pip install build
57
+ python -m build
58
+
59
+ - name: Upload distributions
60
+ uses: actions/upload-artifact@v4
61
+ with:
62
+ name: release-dists
63
+ path: dist/
64
+
65
+ pypi-publish:
66
+ if: github.event_name == 'release'
67
+ runs-on: ubuntu-latest
68
+ needs: release-build
69
+ permissions:
70
+ id-token: write
71
+
72
+ environment:
73
+ name: pypi
74
+ url: https://pypi.org/project/hookbase/${{ github.event.release.tag_name }}
75
+
76
+ steps:
77
+ - name: Retrieve release distributions
78
+ uses: actions/download-artifact@v4
79
+ with:
80
+ name: release-dists
81
+ path: dist/
82
+
83
+ - name: Publish release distributions to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
85
+ with:
86
+ packages-dir: dist/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hookbase
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: Official Python SDK for the Hookbase webhook management platform
5
5
  Project-URL: Homepage, https://hookbase.app
6
6
  Project-URL: Documentation, https://docs.hookbase.app/sdk/python
@@ -22,6 +22,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Classifier: Typing :: Typed
24
24
  Requires-Python: >=3.9
25
+ Requires-Dist: eval-type-backport>=0.2.0; python_version < '3.10'
25
26
  Requires-Dist: httpx<1.0.0,>=0.25.0
26
27
  Requires-Dist: pydantic<3.0.0,>=2.0.0
27
28
  Provides-Extra: dev
@@ -29,6 +29,7 @@ classifiers = [
29
29
  dependencies = [
30
30
  "httpx>=0.25.0,<1.0.0",
31
31
  "pydantic>=2.0.0,<3.0.0",
32
+ "eval_type_backport>=0.2.0; python_version < '3.10'",
32
33
  ]
33
34
 
34
35
  [project.optional-dependencies]
@@ -0,0 +1 @@
1
+ __version__ = "2.1.1"
@@ -1,10 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Literal
3
+ from typing import Any
4
4
 
5
5
  from ._base import HookbaseModel
6
6
 
7
- DeliveryStatus = str # API may return: pending, success, failed, retrying, delivered, failed_over, schema_failed, exhausted, etc.
7
+ # API may return: pending, success, failed, retrying, delivered,
8
+ # failed_over, schema_failed, exhausted, etc.
9
+ DeliveryStatus = str
8
10
 
9
11
 
10
12
  class Delivery(HookbaseModel):
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- from typing import Any, Literal
4
+ from typing import Any
5
5
 
6
6
  from pydantic import field_validator
7
7
 
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any
4
-
5
3
  from ._base import HookbaseModel
6
4
 
7
5
 
@@ -34,12 +34,13 @@ class Source(HookbaseModel):
34
34
  ip_denylist: list[str] | None = None
35
35
  rate_limit: int | None = None
36
36
  rate_limit_window: int | None = None
37
+ transient_mode: bool = False
37
38
  event_count: int = 0
38
39
  last_event_at: str | None = None
39
40
  created_at: str = ""
40
41
  updated_at: str = ""
41
42
 
42
- @field_validator("is_active", "verify_signature", mode="before")
43
+ @field_validator("is_active", "verify_signature", "transient_mode", mode="before")
43
44
  @classmethod
44
45
  def parse_bool_from_int(cls, v: Any) -> Any:
45
46
  if isinstance(v, int):
@@ -76,6 +77,7 @@ class CreateSourceParams(HookbaseModel):
76
77
  ip_denylist: list[str] | None = None
77
78
  rate_limit: int | None = None
78
79
  rate_limit_window: int | None = None
80
+ transient_mode: bool | None = None
79
81
 
80
82
 
81
83
  class UpdateSourceParams(HookbaseModel):
@@ -91,3 +93,4 @@ class UpdateSourceParams(HookbaseModel):
91
93
  ip_denylist: list[str] | None = None
92
94
  rate_limit: int | None = None
93
95
  rate_limit_window: int | None = None
96
+ transient_mode: bool | None = None
@@ -5,6 +5,7 @@ import respx
5
5
 
6
6
  from hookbase import Hookbase
7
7
  from hookbase.models import Source, SourceWithSecret
8
+ from hookbase.models.sources import CreateSourceParams, UpdateSourceParams
8
9
 
9
10
  from ..conftest import make_paginated_response
10
11
 
@@ -110,3 +111,81 @@ def test_import_sources(mock_api, client):
110
111
  })
111
112
  result = client.sources.import_sources([SOURCE_DATA])
112
113
  assert result.imported == 1
114
+
115
+
116
+ # --- transient_mode tests ---
117
+
118
+
119
+ def test_source_transient_mode_defaults_false():
120
+ src = Source(**SOURCE_DATA)
121
+ assert src.transient_mode is False
122
+
123
+
124
+ def test_source_transient_mode_true():
125
+ data = {**SOURCE_DATA, "transientMode": True}
126
+ src = Source(**data)
127
+ assert src.transient_mode is True
128
+
129
+
130
+ def test_source_transient_mode_from_int():
131
+ """D1/SQLite returns booleans as 0/1 integers."""
132
+ data = {**SOURCE_DATA, "transientMode": 1}
133
+ src = Source(**data)
134
+ assert src.transient_mode is True
135
+
136
+ data_off = {**SOURCE_DATA, "transientMode": 0}
137
+ src_off = Source(**data_off)
138
+ assert src_off.transient_mode is False
139
+
140
+
141
+ def test_source_transient_mode_serializes_as_camel():
142
+ src = Source(**{**SOURCE_DATA, "transientMode": True})
143
+ dumped = src.model_dump(by_alias=True)
144
+ assert "transientMode" in dumped
145
+ assert dumped["transientMode"] is True
146
+
147
+
148
+ def test_create_source_with_transient_mode(mock_api, client):
149
+ resp_data = {**SOURCE_DATA, "transientMode": True, "signingSecret": "whsec_abc"}
150
+ mock_api.post("/api/sources").respond(200, json={"source": resp_data})
151
+ src = client.sources.create({
152
+ "name": "HIPAA Source",
153
+ "slug": "hipaa",
154
+ "transient_mode": True,
155
+ })
156
+ assert isinstance(src, SourceWithSecret)
157
+ assert src.transient_mode is True
158
+
159
+
160
+ def test_create_source_params_serialization():
161
+ params = CreateSourceParams(name="test", transient_mode=True)
162
+ dumped = params.model_dump(by_alias=True, exclude_none=True)
163
+ assert dumped["transientMode"] is True
164
+
165
+
166
+ def test_update_source_with_transient_mode(mock_api, client):
167
+ mock_api.patch("/api/sources/src_1").respond(204)
168
+ client.sources.update("src_1", {"transient_mode": True})
169
+
170
+
171
+ def test_update_source_params_serialization():
172
+ params = UpdateSourceParams(transient_mode=True)
173
+ dumped = params.model_dump(by_alias=True, exclude_none=True)
174
+ assert dumped["transientMode"] is True
175
+ assert "name" not in dumped
176
+
177
+
178
+ def test_get_source_with_transient_mode(mock_api, client):
179
+ data = {**SOURCE_DATA, "transientMode": True}
180
+ mock_api.get("/api/sources/src_1").respond(200, json={"source": data})
181
+ src = client.sources.get("src_1")
182
+ assert src.transient_mode is True
183
+
184
+
185
+ def test_list_sources_with_transient_mode(mock_api, client):
186
+ data = {**SOURCE_DATA, "transientMode": True}
187
+ mock_api.get("/api/sources").respond(200, json=make_paginated_response(
188
+ [data], data_key="sources", total=1,
189
+ ))
190
+ page = client.sources.list()
191
+ assert page.data[0].transient_mode is True
@@ -1 +0,0 @@
1
- __version__ = "2.0.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes