trafficmorph 0.3.0__py3-none-any.whl

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 (70) hide show
  1. trafficmorph/__init__.py +30 -0
  2. trafficmorph/api/__init__.py +1 -0
  3. trafficmorph/api/captures/__init__.py +1 -0
  4. trafficmorph/api/captures/analyse.py +132 -0
  5. trafficmorph/api/captures/import_capture.py +158 -0
  6. trafficmorph/api/domains/__init__.py +1 -0
  7. trafficmorph/api/domains/add.py +131 -0
  8. trafficmorph/api/domains/list_domains.py +107 -0
  9. trafficmorph/api/domains/remove.py +124 -0
  10. trafficmorph/api/domains/verify_dns.py +124 -0
  11. trafficmorph/api/domains/verify_http.py +122 -0
  12. trafficmorph/api/history/__init__.py +1 -0
  13. trafficmorph/api/history/get_history_item.py +122 -0
  14. trafficmorph/api/history/list_history.py +210 -0
  15. trafficmorph/api/profiles/__init__.py +1 -0
  16. trafficmorph/api/profiles/create_profile.py +143 -0
  17. trafficmorph/api/profiles/delete_profile.py +124 -0
  18. trafficmorph/api/profiles/get_profile.py +122 -0
  19. trafficmorph/api/profiles/list_profiles.py +107 -0
  20. trafficmorph/api/profiles/update_profile.py +162 -0
  21. trafficmorph/api/runs/__init__.py +1 -0
  22. trafficmorph/api/runs/pause.py +122 -0
  23. trafficmorph/api/runs/resume.py +120 -0
  24. trafficmorph/api/runs/start.py +120 -0
  25. trafficmorph/api/runs/stop.py +122 -0
  26. trafficmorph/api/variables_sets/__init__.py +1 -0
  27. trafficmorph/api/variables_sets/change_mode.py +142 -0
  28. trafficmorph/api/variables_sets/create.py +157 -0
  29. trafficmorph/api/variables_sets/delete.py +132 -0
  30. trafficmorph/api/variables_sets/get.py +120 -0
  31. trafficmorph/api/variables_sets/list_variables_sets.py +109 -0
  32. trafficmorph/api/variables_sets/rename.py +134 -0
  33. trafficmorph/client.py +271 -0
  34. trafficmorph/errors.py +14 -0
  35. trafficmorph/models/__init__.py +63 -0
  36. trafficmorph/models/add_domain_request.py +76 -0
  37. trafficmorph/models/analyse_body.py +102 -0
  38. trafficmorph/models/api_profile_request.py +257 -0
  39. trafficmorph/models/api_profile_response.py +313 -0
  40. trafficmorph/models/capture_analysis_response.py +122 -0
  41. trafficmorph/models/capture_import_result.py +152 -0
  42. trafficmorph/models/change_variables_set_mode_request.py +80 -0
  43. trafficmorph/models/change_variables_set_mode_request_mode.py +9 -0
  44. trafficmorph/models/create_variables_set_request.py +96 -0
  45. trafficmorph/models/create_variables_set_request_mode.py +9 -0
  46. trafficmorph/models/created_profile.py +87 -0
  47. trafficmorph/models/curve_point.py +87 -0
  48. trafficmorph/models/group.py +197 -0
  49. trafficmorph/models/import_capture_body.py +101 -0
  50. trafficmorph/models/rename_variables_set_request.py +76 -0
  51. trafficmorph/models/schedule_block.py +125 -0
  52. trafficmorph/models/scheduled_run_response.py +150 -0
  53. trafficmorph/models/skipped_selection.py +96 -0
  54. trafficmorph/models/slot_input.py +87 -0
  55. trafficmorph/models/slot_response.py +127 -0
  56. trafficmorph/models/stats.py +123 -0
  57. trafficmorph/models/traffic_profile_point_request.py +84 -0
  58. trafficmorph/models/traffic_profile_point_response.py +87 -0
  59. trafficmorph/models/traffic_profile_summary_response.py +109 -0
  60. trafficmorph/models/traffic_run_control_response.py +96 -0
  61. trafficmorph/models/variable.py +129 -0
  62. trafficmorph/models/variables_set_response.py +190 -0
  63. trafficmorph/models/variables_set_response_mode.py +9 -0
  64. trafficmorph/models/verified_domain_response.py +173 -0
  65. trafficmorph/sdk.py +360 -0
  66. trafficmorph/types.py +53 -0
  67. trafficmorph-0.3.0.dist-info/METADATA +278 -0
  68. trafficmorph-0.3.0.dist-info/RECORD +70 -0
  69. trafficmorph-0.3.0.dist-info/WHEEL +4 -0
  70. trafficmorph-0.3.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,124 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, cast
3
+ from urllib.parse import quote
4
+
5
+ import httpx
6
+
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response, UNSET
9
+ from ... import errors
10
+
11
+
12
+
13
+
14
+ def _get_kwargs(
15
+ id: int,
16
+
17
+ ) -> dict[str, Any]:
18
+
19
+
20
+
21
+
22
+
23
+
24
+ _kwargs: dict[str, Any] = {
25
+ "method": "post",
26
+ "url": "/api/v1/domains/{id}/verify/dns".format(id=quote(str(id), safe=""),),
27
+ }
28
+
29
+
30
+ return _kwargs
31
+
32
+
33
+
34
+ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None:
35
+ if client.raise_on_unexpected_status:
36
+ raise errors.UnexpectedStatus(response.status_code, response.content)
37
+ else:
38
+ return None
39
+
40
+
41
+ def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
42
+ return Response(
43
+ status_code=HTTPStatus(response.status_code),
44
+ content=response.content,
45
+ headers=response.headers,
46
+ parsed=_parse_response(client=client, response=response),
47
+ )
48
+
49
+
50
+ def sync_detailed(
51
+ id: int,
52
+ *,
53
+ client: AuthenticatedClient | Client,
54
+
55
+ ) -> Response[Any]:
56
+ """ Run the DNS-TXT verification check
57
+
58
+ Looks up the configured TXT record at `_trafficmorph-verify.{domain}` and matches it against the
59
+ challenge value issued when the domain was added. On match, the domain flips to `VERIFIED` and can
60
+ be used as a profile target. **On miss**, returns 400 with a remediation message — the call is
61
+ treated as a failed verification attempt rather than a polling no-op, so CI flows fail fast instead
62
+ of looping on always-`PENDING` 200s.
63
+
64
+ Args:
65
+ id (int):
66
+
67
+ Raises:
68
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
69
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
70
+
71
+ Returns:
72
+ Response[Any]
73
+ """
74
+
75
+
76
+ kwargs = _get_kwargs(
77
+ id=id,
78
+
79
+ )
80
+
81
+ response = client.get_httpx_client().request(
82
+ **kwargs,
83
+ )
84
+
85
+ return _build_response(client=client, response=response)
86
+
87
+
88
+ async def asyncio_detailed(
89
+ id: int,
90
+ *,
91
+ client: AuthenticatedClient | Client,
92
+
93
+ ) -> Response[Any]:
94
+ """ Run the DNS-TXT verification check
95
+
96
+ Looks up the configured TXT record at `_trafficmorph-verify.{domain}` and matches it against the
97
+ challenge value issued when the domain was added. On match, the domain flips to `VERIFIED` and can
98
+ be used as a profile target. **On miss**, returns 400 with a remediation message — the call is
99
+ treated as a failed verification attempt rather than a polling no-op, so CI flows fail fast instead
100
+ of looping on always-`PENDING` 200s.
101
+
102
+ Args:
103
+ id (int):
104
+
105
+ Raises:
106
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
107
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
108
+
109
+ Returns:
110
+ Response[Any]
111
+ """
112
+
113
+
114
+ kwargs = _get_kwargs(
115
+ id=id,
116
+
117
+ )
118
+
119
+ response = await client.get_async_httpx_client().request(
120
+ **kwargs
121
+ )
122
+
123
+ return _build_response(client=client, response=response)
124
+
@@ -0,0 +1,122 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, cast
3
+ from urllib.parse import quote
4
+
5
+ import httpx
6
+
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response, UNSET
9
+ from ... import errors
10
+
11
+
12
+
13
+
14
+ def _get_kwargs(
15
+ id: int,
16
+
17
+ ) -> dict[str, Any]:
18
+
19
+
20
+
21
+
22
+
23
+
24
+ _kwargs: dict[str, Any] = {
25
+ "method": "post",
26
+ "url": "/api/v1/domains/{id}/verify/http".format(id=quote(str(id), safe=""),),
27
+ }
28
+
29
+
30
+ return _kwargs
31
+
32
+
33
+
34
+ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None:
35
+ if client.raise_on_unexpected_status:
36
+ raise errors.UnexpectedStatus(response.status_code, response.content)
37
+ else:
38
+ return None
39
+
40
+
41
+ def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
42
+ return Response(
43
+ status_code=HTTPStatus(response.status_code),
44
+ content=response.content,
45
+ headers=response.headers,
46
+ parsed=_parse_response(client=client, response=response),
47
+ )
48
+
49
+
50
+ def sync_detailed(
51
+ id: int,
52
+ *,
53
+ client: AuthenticatedClient | Client,
54
+
55
+ ) -> Response[Any]:
56
+ """ Run the HTTP-token verification check
57
+
58
+ Fetches `https://{domain}/.well-known/trafficmorph-verify.txt` (falling back to HTTP if HTTPS fails)
59
+ and matches its body against the challenge token. Alternative to DNS verification for users without
60
+ DNS control. **On miss**, returns 400 with a remediation message — same fail-fast contract as
61
+ `/verify/dns`.
62
+
63
+ Args:
64
+ id (int):
65
+
66
+ Raises:
67
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
68
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
69
+
70
+ Returns:
71
+ Response[Any]
72
+ """
73
+
74
+
75
+ kwargs = _get_kwargs(
76
+ id=id,
77
+
78
+ )
79
+
80
+ response = client.get_httpx_client().request(
81
+ **kwargs,
82
+ )
83
+
84
+ return _build_response(client=client, response=response)
85
+
86
+
87
+ async def asyncio_detailed(
88
+ id: int,
89
+ *,
90
+ client: AuthenticatedClient | Client,
91
+
92
+ ) -> Response[Any]:
93
+ """ Run the HTTP-token verification check
94
+
95
+ Fetches `https://{domain}/.well-known/trafficmorph-verify.txt` (falling back to HTTP if HTTPS fails)
96
+ and matches its body against the challenge token. Alternative to DNS verification for users without
97
+ DNS control. **On miss**, returns 400 with a remediation message — same fail-fast contract as
98
+ `/verify/dns`.
99
+
100
+ Args:
101
+ id (int):
102
+
103
+ Raises:
104
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
105
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
106
+
107
+ Returns:
108
+ Response[Any]
109
+ """
110
+
111
+
112
+ kwargs = _get_kwargs(
113
+ id=id,
114
+
115
+ )
116
+
117
+ response = await client.get_async_httpx_client().request(
118
+ **kwargs
119
+ )
120
+
121
+ return _build_response(client=client, response=response)
122
+
@@ -0,0 +1 @@
1
+ """ Contains endpoint functions for accessing the API """
@@ -0,0 +1,122 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, cast
3
+ from urllib.parse import quote
4
+
5
+ import httpx
6
+
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response, UNSET
9
+ from ... import errors
10
+
11
+
12
+
13
+
14
+ def _get_kwargs(
15
+ id: int,
16
+
17
+ ) -> dict[str, Any]:
18
+
19
+
20
+
21
+
22
+
23
+
24
+ _kwargs: dict[str, Any] = {
25
+ "method": "get",
26
+ "url": "/api/v1/history/{id}".format(id=quote(str(id), safe=""),),
27
+ }
28
+
29
+
30
+ return _kwargs
31
+
32
+
33
+
34
+ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None:
35
+ if client.raise_on_unexpected_status:
36
+ raise errors.UnexpectedStatus(response.status_code, response.content)
37
+ else:
38
+ return None
39
+
40
+
41
+ def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
42
+ return Response(
43
+ status_code=HTTPStatus(response.status_code),
44
+ content=response.content,
45
+ headers=response.headers,
46
+ parsed=_parse_response(client=client, response=response),
47
+ )
48
+
49
+
50
+ def sync_detailed(
51
+ id: int,
52
+ *,
53
+ client: AuthenticatedClient | Client,
54
+
55
+ ) -> Response[Any]:
56
+ """ Get a single run's full detail
57
+
58
+ Returns the run's complete metric set: response-code distribution, latency quantiles, RPS / latency
59
+ time series, secondary stats from response scripts, the auto-comparison snapshot against baseline,
60
+ and the verdict reasoning. This is the endpoint a CI step polls after `/profiles/{id}/start` to
61
+ decide pass/fail.
62
+
63
+ Args:
64
+ id (int):
65
+
66
+ Raises:
67
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
68
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
69
+
70
+ Returns:
71
+ Response[Any]
72
+ """
73
+
74
+
75
+ kwargs = _get_kwargs(
76
+ id=id,
77
+
78
+ )
79
+
80
+ response = client.get_httpx_client().request(
81
+ **kwargs,
82
+ )
83
+
84
+ return _build_response(client=client, response=response)
85
+
86
+
87
+ async def asyncio_detailed(
88
+ id: int,
89
+ *,
90
+ client: AuthenticatedClient | Client,
91
+
92
+ ) -> Response[Any]:
93
+ """ Get a single run's full detail
94
+
95
+ Returns the run's complete metric set: response-code distribution, latency quantiles, RPS / latency
96
+ time series, secondary stats from response scripts, the auto-comparison snapshot against baseline,
97
+ and the verdict reasoning. This is the endpoint a CI step polls after `/profiles/{id}/start` to
98
+ decide pass/fail.
99
+
100
+ Args:
101
+ id (int):
102
+
103
+ Raises:
104
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
105
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
106
+
107
+ Returns:
108
+ Response[Any]
109
+ """
110
+
111
+
112
+ kwargs = _get_kwargs(
113
+ id=id,
114
+
115
+ )
116
+
117
+ response = await client.get_async_httpx_client().request(
118
+ **kwargs
119
+ )
120
+
121
+ return _build_response(client=client, response=response)
122
+
@@ -0,0 +1,210 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, cast
3
+ from urllib.parse import quote
4
+
5
+ import httpx
6
+
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response, UNSET
9
+ from ... import errors
10
+
11
+ from ...types import UNSET, Unset
12
+ from dateutil.parser import isoparse
13
+ from typing import cast
14
+ import datetime
15
+
16
+
17
+
18
+ def _get_kwargs(
19
+ *,
20
+ page: int | Unset = 0,
21
+ size: int | Unset = 20,
22
+ profile_id: int | Unset = UNSET,
23
+ triggered_by: str | Unset = UNSET,
24
+ region: str | Unset = UNSET,
25
+ auto_verdict: str | Unset = UNSET,
26
+ tag: str | Unset = UNSET,
27
+ from_: datetime.datetime | Unset = UNSET,
28
+ to: datetime.datetime | Unset = UNSET,
29
+
30
+ ) -> dict[str, Any]:
31
+
32
+
33
+
34
+
35
+ params: dict[str, Any] = {}
36
+
37
+ params["page"] = page
38
+
39
+ params["size"] = size
40
+
41
+ params["profileId"] = profile_id
42
+
43
+ params["triggeredBy"] = triggered_by
44
+
45
+ params["region"] = region
46
+
47
+ params["autoVerdict"] = auto_verdict
48
+
49
+ params["tag"] = tag
50
+
51
+ json_from_: str | Unset = UNSET
52
+ if not isinstance(from_, Unset):
53
+ json_from_ = from_.isoformat()
54
+ params["from"] = json_from_
55
+
56
+ json_to: str | Unset = UNSET
57
+ if not isinstance(to, Unset):
58
+ json_to = to.isoformat()
59
+ params["to"] = json_to
60
+
61
+
62
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
63
+
64
+
65
+ _kwargs: dict[str, Any] = {
66
+ "method": "get",
67
+ "url": "/api/v1/history",
68
+ "params": params,
69
+ }
70
+
71
+
72
+ return _kwargs
73
+
74
+
75
+
76
+ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None:
77
+ if client.raise_on_unexpected_status:
78
+ raise errors.UnexpectedStatus(response.status_code, response.content)
79
+ else:
80
+ return None
81
+
82
+
83
+ def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
84
+ return Response(
85
+ status_code=HTTPStatus(response.status_code),
86
+ content=response.content,
87
+ headers=response.headers,
88
+ parsed=_parse_response(client=client, response=response),
89
+ )
90
+
91
+
92
+ def sync_detailed(
93
+ *,
94
+ client: AuthenticatedClient | Client,
95
+ page: int | Unset = 0,
96
+ size: int | Unset = 20,
97
+ profile_id: int | Unset = UNSET,
98
+ triggered_by: str | Unset = UNSET,
99
+ region: str | Unset = UNSET,
100
+ auto_verdict: str | Unset = UNSET,
101
+ tag: str | Unset = UNSET,
102
+ from_: datetime.datetime | Unset = UNSET,
103
+ to: datetime.datetime | Unset = UNSET,
104
+
105
+ ) -> Response[Any]:
106
+ """ List past runs with optional filters
107
+
108
+ Paginated run history. Filters narrow by profile, trigger source (`api` / `ui` / `scheduled`),
109
+ region, regression verdict (`PASS` / `WARN` / `FAIL` / `NO_BASELINE`), tag, and date range. All
110
+ filters are AND-combined. Use `autoVerdict=FAIL` to fetch the runs a CI gate should care about.
111
+
112
+ Args:
113
+ page (int | Unset): Default: 0.
114
+ size (int | Unset): Default: 20.
115
+ profile_id (int | Unset):
116
+ triggered_by (str | Unset):
117
+ region (str | Unset):
118
+ auto_verdict (str | Unset):
119
+ tag (str | Unset):
120
+ from_ (datetime.datetime | Unset):
121
+ to (datetime.datetime | Unset):
122
+
123
+ Raises:
124
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
125
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
126
+
127
+ Returns:
128
+ Response[Any]
129
+ """
130
+
131
+
132
+ kwargs = _get_kwargs(
133
+ page=page,
134
+ size=size,
135
+ profile_id=profile_id,
136
+ triggered_by=triggered_by,
137
+ region=region,
138
+ auto_verdict=auto_verdict,
139
+ tag=tag,
140
+ from_=from_,
141
+ to=to,
142
+
143
+ )
144
+
145
+ response = client.get_httpx_client().request(
146
+ **kwargs,
147
+ )
148
+
149
+ return _build_response(client=client, response=response)
150
+
151
+
152
+ async def asyncio_detailed(
153
+ *,
154
+ client: AuthenticatedClient | Client,
155
+ page: int | Unset = 0,
156
+ size: int | Unset = 20,
157
+ profile_id: int | Unset = UNSET,
158
+ triggered_by: str | Unset = UNSET,
159
+ region: str | Unset = UNSET,
160
+ auto_verdict: str | Unset = UNSET,
161
+ tag: str | Unset = UNSET,
162
+ from_: datetime.datetime | Unset = UNSET,
163
+ to: datetime.datetime | Unset = UNSET,
164
+
165
+ ) -> Response[Any]:
166
+ """ List past runs with optional filters
167
+
168
+ Paginated run history. Filters narrow by profile, trigger source (`api` / `ui` / `scheduled`),
169
+ region, regression verdict (`PASS` / `WARN` / `FAIL` / `NO_BASELINE`), tag, and date range. All
170
+ filters are AND-combined. Use `autoVerdict=FAIL` to fetch the runs a CI gate should care about.
171
+
172
+ Args:
173
+ page (int | Unset): Default: 0.
174
+ size (int | Unset): Default: 20.
175
+ profile_id (int | Unset):
176
+ triggered_by (str | Unset):
177
+ region (str | Unset):
178
+ auto_verdict (str | Unset):
179
+ tag (str | Unset):
180
+ from_ (datetime.datetime | Unset):
181
+ to (datetime.datetime | Unset):
182
+
183
+ Raises:
184
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
185
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
186
+
187
+ Returns:
188
+ Response[Any]
189
+ """
190
+
191
+
192
+ kwargs = _get_kwargs(
193
+ page=page,
194
+ size=size,
195
+ profile_id=profile_id,
196
+ triggered_by=triggered_by,
197
+ region=region,
198
+ auto_verdict=auto_verdict,
199
+ tag=tag,
200
+ from_=from_,
201
+ to=to,
202
+
203
+ )
204
+
205
+ response = await client.get_async_httpx_client().request(
206
+ **kwargs
207
+ )
208
+
209
+ return _build_response(client=client, response=response)
210
+
@@ -0,0 +1 @@
1
+ """ Contains endpoint functions for accessing the API """