taskbadger 1.6.2__tar.gz → 1.7.0__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.
- {taskbadger-1.6.2 → taskbadger-1.7.0}/PKG-INFO +1 -1
- {taskbadger-1.6.2 → taskbadger-1.7.0}/pyproject.toml +1 -1
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/celery.py +85 -1
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli_main.py +13 -3
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/config.py +14 -4
- taskbadger-1.7.0/taskbadger/internal/api/action_endpoints/__init__.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_cancel.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_create.py +2 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_get.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_list.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_partial_update.py +2 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_update.py +2 -2
- taskbadger-1.7.0/taskbadger/internal/api/task_endpoints/__init__.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_cancel.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_create.py +2 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_get.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_list.py +1 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_partial_update.py +2 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_update.py +2 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/action.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/action_request.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/paginated_task_list.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/patched_action_request.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/patched_task_request.py +24 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/patched_task_request_tags.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/task.py +24 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/task_request.py +24 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/task_request_tags.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/task_tags.py +3 -2
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/types.py +13 -5
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/sdk.py +41 -2
- taskbadger-1.6.2/taskbadger/internal/api/action_endpoints/__init__.py +0 -0
- taskbadger-1.6.2/taskbadger/internal/api/task_endpoints/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/.gitignore +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/LICENSE +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/README.md +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli/basics.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli/list_tasks.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli/utils.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/cli/wrapper.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/decorators.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/exceptions.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/integrations.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/client.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/errors.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/status_enum.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/py.typed +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/mug.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/process.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/safe_sdk.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/systems/__init__.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/systems/celery.py +0 -0
- {taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/utils.py +0 -0
|
@@ -131,7 +131,8 @@ class Task(celery.Task):
|
|
|
131
131
|
|
|
132
132
|
result = super().apply_async(*args, **kwargs)
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
info = result.info
|
|
135
|
+
tb_task_id = info.get(TB_TASK_ID) if isinstance(info, dict) else None
|
|
135
136
|
setattr(result, TB_TASK_ID, tb_task_id)
|
|
136
137
|
|
|
137
138
|
_get_task = functools.partial(get_task, tb_task_id) if tb_task_id else lambda: None
|
|
@@ -212,8 +213,91 @@ def task_publish_handler(sender=None, headers=None, body=None, **kwargs):
|
|
|
212
213
|
ctask.update_state(task_id=headers["id"], state="PENDING", meta=meta)
|
|
213
214
|
|
|
214
215
|
|
|
216
|
+
def _maybe_create_task(signal_sender):
|
|
217
|
+
"""Create a TaskBadger task if one doesn't exist yet.
|
|
218
|
+
|
|
219
|
+
This handles cases where before_task_publish didn't fire or was skipped:
|
|
220
|
+
- Eager mode (before_task_publish doesn't fire)
|
|
221
|
+
- Canvas primitives like map/starmap/chunks (fire for celery.* tasks)
|
|
222
|
+
"""
|
|
223
|
+
# Check if task was already created FIRST (before accessing Badger)
|
|
224
|
+
# This avoids initializing thread-local Badger state for tasks like celery.ping
|
|
225
|
+
task_id = _get_taskbadger_task_id(signal_sender.request)
|
|
226
|
+
if task_id:
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
task_name = signal_sender.name
|
|
230
|
+
|
|
231
|
+
# Skip built-in celery tasks that we don't track (like celery.ping)
|
|
232
|
+
# Only handle celery.map and celery.starmap specially
|
|
233
|
+
if task_name.startswith("celery.") and task_name not in ("celery.map", "celery.starmap"):
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
# For non-canvas tasks, only create if there was an explicit intent to track
|
|
237
|
+
# (indicated by taskbadger_track header). This prevents creating tasks when
|
|
238
|
+
# Badger wasn't configured at publish time but has stale config in worker.
|
|
239
|
+
headers = signal_sender.request.headers or {}
|
|
240
|
+
is_canvas_task = task_name in ("celery.map", "celery.starmap")
|
|
241
|
+
if not is_canvas_task and not headers.get("taskbadger_track"):
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
# NOW it's safe to check Badger configuration
|
|
245
|
+
if not Badger.is_configured():
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
celery_system = Badger.current.settings.get_system_by_id("celery")
|
|
249
|
+
data = None
|
|
250
|
+
inner_task = None
|
|
251
|
+
|
|
252
|
+
# Handle celery.map and celery.starmap - extract the inner task name
|
|
253
|
+
if task_name in ("celery.map", "celery.starmap"):
|
|
254
|
+
canvas_type = task_name.split(".")[-1] # "map" or "starmap"
|
|
255
|
+
inner_task_info = signal_sender.request.kwargs.get("task")
|
|
256
|
+
if inner_task_info:
|
|
257
|
+
# inner_task_info can be a dict (serialized signature) or a Signature object
|
|
258
|
+
if isinstance(inner_task_info, dict):
|
|
259
|
+
task_name = inner_task_info.get("task", task_name)
|
|
260
|
+
elif hasattr(inner_task_info, "name"):
|
|
261
|
+
task_name = inner_task_info.name
|
|
262
|
+
# Get the actual task class to check if it uses Task base
|
|
263
|
+
inner_task = celery.current_app.tasks.get(task_name)
|
|
264
|
+
items = signal_sender.request.kwargs.get("it", [])
|
|
265
|
+
# Convert to list if needed for counting and potential recording
|
|
266
|
+
items_list = list(items) if not isinstance(items, (list, tuple)) else items
|
|
267
|
+
item_count = len(items_list)
|
|
268
|
+
# Append canvas type and item count to task name
|
|
269
|
+
task_name = f"{task_name} ({canvas_type} {item_count})"
|
|
270
|
+
data = {"canvas_type": signal_sender.name, "item_count": item_count}
|
|
271
|
+
|
|
272
|
+
# Include task items if record_task_args is enabled
|
|
273
|
+
if celery_system and celery_system.record_task_args:
|
|
274
|
+
try:
|
|
275
|
+
_, _, value = serialization.dumps({"items": items_list}, serializer="json")
|
|
276
|
+
items_data = json.loads(value)
|
|
277
|
+
data["celery_task_items"] = items_data["items"]
|
|
278
|
+
except Exception:
|
|
279
|
+
log.warning("Error serializing canvas items for task '%s'", task_name)
|
|
280
|
+
|
|
281
|
+
# Check if we should track this task
|
|
282
|
+
auto_track = celery_system and celery_system.track_task(task_name)
|
|
283
|
+
# Check if the task (or inner task for map/starmap) uses our Task base class
|
|
284
|
+
task_to_check = inner_task if inner_task else signal_sender
|
|
285
|
+
manual_track = isinstance(task_to_check, Task)
|
|
286
|
+
if not manual_track and not auto_track:
|
|
287
|
+
return
|
|
288
|
+
|
|
289
|
+
enter_session()
|
|
290
|
+
|
|
291
|
+
task = create_task_safe(task_name, status=StatusEnum.PENDING, data=data)
|
|
292
|
+
if task:
|
|
293
|
+
# Store the task ID in the request so _update_task can find it
|
|
294
|
+
signal_sender.request.update({TB_TASK_ID: task.id})
|
|
295
|
+
safe_get_task.cache.set((task.id,), task)
|
|
296
|
+
|
|
297
|
+
|
|
215
298
|
@task_prerun.connect
|
|
216
299
|
def task_prerun_handler(sender=None, **kwargs):
|
|
300
|
+
_maybe_create_task(sender)
|
|
217
301
|
_update_task(sender, StatusEnum.PROCESSING)
|
|
218
302
|
|
|
219
303
|
|
|
@@ -6,6 +6,7 @@ from rich import print
|
|
|
6
6
|
from taskbadger import __version__
|
|
7
7
|
from taskbadger.cli import create, get, list_tasks_command, run, update
|
|
8
8
|
from taskbadger.config import get_config, write_config
|
|
9
|
+
from taskbadger.sdk import _parse_token
|
|
9
10
|
|
|
10
11
|
app = typer.Typer(
|
|
11
12
|
rich_markup_mode="rich",
|
|
@@ -30,9 +31,18 @@ def version_callback(value: bool):
|
|
|
30
31
|
def configure(ctx: typer.Context):
|
|
31
32
|
"""Update CLI configuration."""
|
|
32
33
|
config = ctx.meta["tb_config"]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
token = typer.prompt("API Key", default=config.token)
|
|
35
|
+
parsed = _parse_token(token)
|
|
36
|
+
if parsed:
|
|
37
|
+
org_slug, project_slug, api_key = parsed
|
|
38
|
+
print(f"Project key detected — organization: [green]{org_slug}[/green], project: [green]{project_slug}[/green]")
|
|
39
|
+
config.organization_slug = org_slug
|
|
40
|
+
config.project_slug = project_slug
|
|
41
|
+
config.token = token
|
|
42
|
+
else:
|
|
43
|
+
config.organization_slug = typer.prompt("Organization slug", default=config.organization_slug)
|
|
44
|
+
config.project_slug = typer.prompt("Project slug", default=config.project_slug)
|
|
45
|
+
config.token = token
|
|
36
46
|
path = write_config(config)
|
|
37
47
|
print(f"Config written to [green]{path}[/green]")
|
|
38
48
|
|
|
@@ -7,7 +7,7 @@ import tomlkit
|
|
|
7
7
|
import typer
|
|
8
8
|
from tomlkit import document, table
|
|
9
9
|
|
|
10
|
-
from taskbadger.sdk import _TB_HOST, _init
|
|
10
|
+
from taskbadger.sdk import _TB_HOST, _init, _parse_token
|
|
11
11
|
|
|
12
12
|
APP_NAME = "taskbadger"
|
|
13
13
|
|
|
@@ -47,10 +47,20 @@ class Config:
|
|
|
47
47
|
"""
|
|
48
48
|
defaults = config_dict.get("defaults", {})
|
|
49
49
|
auth = config_dict.get("auth", {})
|
|
50
|
+
token = overrides.get("token") or _from_env("API_KEY", auth.get("token"))
|
|
51
|
+
organization_slug = overrides.get("org") or _from_env("ORG", defaults.get("org"))
|
|
52
|
+
project_slug = overrides.get("project") or _from_env("PROJECT", defaults.get("project"))
|
|
53
|
+
|
|
54
|
+
if token:
|
|
55
|
+
parsed = _parse_token(token)
|
|
56
|
+
if parsed:
|
|
57
|
+
organization_slug = parsed[0]
|
|
58
|
+
project_slug = parsed[1]
|
|
59
|
+
|
|
50
60
|
return Config(
|
|
51
|
-
token=
|
|
52
|
-
organization_slug=
|
|
53
|
-
project_slug=
|
|
61
|
+
token=token,
|
|
62
|
+
organization_slug=organization_slug,
|
|
63
|
+
project_slug=project_slug,
|
|
54
64
|
host=overrides.get("host") or auth.get("host"),
|
|
55
65
|
tags=config_dict.get("tags", {}),
|
|
56
66
|
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Contains endpoint functions for accessing the API"""
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_cancel.py
RENAMED
|
@@ -26,6 +26,7 @@ def _get_kwargs(
|
|
|
26
26
|
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
|
|
27
27
|
if response.status_code == 204:
|
|
28
28
|
return None
|
|
29
|
+
|
|
29
30
|
if client.raise_on_unexpected_status:
|
|
30
31
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
31
32
|
else:
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_create.py
RENAMED
|
@@ -24,9 +24,8 @@ def _get_kwargs(
|
|
|
24
24
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/",
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
_kwargs["json"] = body.to_dict()
|
|
28
28
|
|
|
29
|
-
_kwargs["json"] = _body
|
|
30
29
|
headers["Content-Type"] = "application/json"
|
|
31
30
|
|
|
32
31
|
_kwargs["headers"] = headers
|
|
@@ -38,6 +37,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
38
37
|
response_201 = Action.from_dict(response.json())
|
|
39
38
|
|
|
40
39
|
return response_201
|
|
40
|
+
|
|
41
41
|
if client.raise_on_unexpected_status:
|
|
42
42
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
43
43
|
else:
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_get.py
RENAMED
|
@@ -29,6 +29,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
29
29
|
response_200 = Action.from_dict(response.json())
|
|
30
30
|
|
|
31
31
|
return response_200
|
|
32
|
+
|
|
32
33
|
if client.raise_on_unexpected_status:
|
|
33
34
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
34
35
|
else:
|
|
@@ -26,9 +26,8 @@ def _get_kwargs(
|
|
|
26
26
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/{id}/",
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
_kwargs["json"] = body.to_dict()
|
|
30
30
|
|
|
31
|
-
_kwargs["json"] = _body
|
|
32
31
|
headers["Content-Type"] = "application/json"
|
|
33
32
|
|
|
34
33
|
_kwargs["headers"] = headers
|
|
@@ -40,6 +39,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
40
39
|
response_200 = Action.from_dict(response.json())
|
|
41
40
|
|
|
42
41
|
return response_200
|
|
42
|
+
|
|
43
43
|
if client.raise_on_unexpected_status:
|
|
44
44
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
45
45
|
else:
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/action_endpoints/action_update.py
RENAMED
|
@@ -26,9 +26,8 @@ def _get_kwargs(
|
|
|
26
26
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/{id}/",
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
_kwargs["json"] = body.to_dict()
|
|
30
30
|
|
|
31
|
-
_kwargs["json"] = _body
|
|
32
31
|
headers["Content-Type"] = "application/json"
|
|
33
32
|
|
|
34
33
|
_kwargs["headers"] = headers
|
|
@@ -40,6 +39,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
40
39
|
response_200 = Action.from_dict(response.json())
|
|
41
40
|
|
|
42
41
|
return response_200
|
|
42
|
+
|
|
43
43
|
if client.raise_on_unexpected_status:
|
|
44
44
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
45
45
|
else:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Contains endpoint functions for accessing the API"""
|
|
@@ -25,6 +25,7 @@ def _get_kwargs(
|
|
|
25
25
|
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
|
|
26
26
|
if response.status_code == 204:
|
|
27
27
|
return None
|
|
28
|
+
|
|
28
29
|
if client.raise_on_unexpected_status:
|
|
29
30
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
30
31
|
else:
|
|
@@ -27,9 +27,8 @@ def _get_kwargs(
|
|
|
27
27
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/",
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
_kwargs["json"] = body.to_dict()
|
|
31
31
|
|
|
32
|
-
_kwargs["json"] = _body
|
|
33
32
|
headers["Content-Type"] = "application/json"
|
|
34
33
|
|
|
35
34
|
_kwargs["headers"] = headers
|
|
@@ -41,6 +40,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
41
40
|
response_201 = Task.from_dict(response.json())
|
|
42
41
|
|
|
43
42
|
return response_201
|
|
43
|
+
|
|
44
44
|
if client.raise_on_unexpected_status:
|
|
45
45
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
46
46
|
else:
|
|
@@ -28,6 +28,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
28
28
|
response_200 = Task.from_dict(response.json())
|
|
29
29
|
|
|
30
30
|
return response_200
|
|
31
|
+
|
|
31
32
|
if client.raise_on_unexpected_status:
|
|
32
33
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
33
34
|
else:
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/api/task_endpoints/task_partial_update.py
RENAMED
|
@@ -25,9 +25,8 @@ def _get_kwargs(
|
|
|
25
25
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/{id}/",
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
_kwargs["json"] = body.to_dict()
|
|
29
29
|
|
|
30
|
-
_kwargs["json"] = _body
|
|
31
30
|
headers["Content-Type"] = "application/json"
|
|
32
31
|
|
|
33
32
|
_kwargs["headers"] = headers
|
|
@@ -39,6 +38,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
39
38
|
response_200 = Task.from_dict(response.json())
|
|
40
39
|
|
|
41
40
|
return response_200
|
|
41
|
+
|
|
42
42
|
if client.raise_on_unexpected_status:
|
|
43
43
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
44
44
|
else:
|
|
@@ -25,9 +25,8 @@ def _get_kwargs(
|
|
|
25
25
|
"url": f"/api/{organization_slug}/{project_slug}/tasks/{id}/",
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
_kwargs["json"] = body.to_dict()
|
|
29
29
|
|
|
30
|
-
_kwargs["json"] = _body
|
|
31
30
|
headers["Content-Type"] = "application/json"
|
|
32
31
|
|
|
33
32
|
_kwargs["headers"] = headers
|
|
@@ -39,6 +38,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
|
|
|
39
38
|
response_200 = Task.from_dict(response.json())
|
|
40
39
|
|
|
41
40
|
return response_200
|
|
41
|
+
|
|
42
42
|
if client.raise_on_unexpected_status:
|
|
43
43
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
44
44
|
else:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
from typing import Any, TypeVar, Union
|
|
3
4
|
|
|
4
5
|
from attrs import define as _attrs_define
|
|
@@ -70,8 +71,8 @@ class Action:
|
|
|
70
71
|
return field_dict
|
|
71
72
|
|
|
72
73
|
@classmethod
|
|
73
|
-
def from_dict(cls: type[T], src_dict:
|
|
74
|
-
d = src_dict
|
|
74
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
75
|
+
d = dict(src_dict)
|
|
75
76
|
id = d.pop("id")
|
|
76
77
|
|
|
77
78
|
task = d.pop("task")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, TypeVar, Union
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -43,8 +44,8 @@ class ActionRequest:
|
|
|
43
44
|
return field_dict
|
|
44
45
|
|
|
45
46
|
@classmethod
|
|
46
|
-
def from_dict(cls: type[T], src_dict:
|
|
47
|
-
d = src_dict
|
|
47
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
48
|
+
d = dict(src_dict)
|
|
48
49
|
trigger = d.pop("trigger")
|
|
49
50
|
|
|
50
51
|
integration = d.pop("integration")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -59,10 +60,10 @@ class PaginatedTaskList:
|
|
|
59
60
|
return field_dict
|
|
60
61
|
|
|
61
62
|
@classmethod
|
|
62
|
-
def from_dict(cls: type[T], src_dict:
|
|
63
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
63
64
|
from ..models.task import Task
|
|
64
65
|
|
|
65
|
-
d = src_dict
|
|
66
|
+
d = dict(src_dict)
|
|
66
67
|
results = []
|
|
67
68
|
_results = d.pop("results")
|
|
68
69
|
for results_item_data in _results:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, TypeVar, Union
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -42,8 +43,8 @@ class PatchedActionRequest:
|
|
|
42
43
|
return field_dict
|
|
43
44
|
|
|
44
45
|
@classmethod
|
|
45
|
-
def from_dict(cls: type[T], src_dict:
|
|
46
|
-
d = src_dict
|
|
46
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
47
|
+
d = dict(src_dict)
|
|
47
48
|
trigger = d.pop("trigger", UNSET)
|
|
48
49
|
|
|
49
50
|
integration = d.pop("integration", UNSET)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
|
3
4
|
|
|
4
5
|
from attrs import define as _attrs_define
|
|
@@ -35,6 +36,8 @@ class PatchedTaskRequest:
|
|
|
35
36
|
set via the API.
|
|
36
37
|
end_time (Union[None, Unset, datetime.datetime]): Datetime when status is set to a terminal value.Can be set via
|
|
37
38
|
the API.
|
|
39
|
+
time_to_start (Union[None, Unset, str]): Duration between task creation and when status first changes from
|
|
40
|
+
pending. (seconds)
|
|
38
41
|
max_runtime (Union[None, Unset, int]): Maximum duration the task can be running for before being considered
|
|
39
42
|
failed. (seconds)
|
|
40
43
|
stale_timeout (Union[None, Unset, int]): Maximum time to allow between task updates before considering the task
|
|
@@ -50,6 +53,7 @@ class PatchedTaskRequest:
|
|
|
50
53
|
data: Union[Unset, Any] = UNSET
|
|
51
54
|
start_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
52
55
|
end_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
56
|
+
time_to_start: Union[None, Unset, str] = UNSET
|
|
53
57
|
max_runtime: Union[None, Unset, int] = UNSET
|
|
54
58
|
stale_timeout: Union[None, Unset, int] = UNSET
|
|
55
59
|
tags: Union[Unset, "PatchedTaskRequestTags"] = UNSET
|
|
@@ -88,6 +92,12 @@ class PatchedTaskRequest:
|
|
|
88
92
|
else:
|
|
89
93
|
end_time = self.end_time
|
|
90
94
|
|
|
95
|
+
time_to_start: Union[None, Unset, str]
|
|
96
|
+
if isinstance(self.time_to_start, Unset):
|
|
97
|
+
time_to_start = UNSET
|
|
98
|
+
else:
|
|
99
|
+
time_to_start = self.time_to_start
|
|
100
|
+
|
|
91
101
|
max_runtime: Union[None, Unset, int]
|
|
92
102
|
if isinstance(self.max_runtime, Unset):
|
|
93
103
|
max_runtime = UNSET
|
|
@@ -121,6 +131,8 @@ class PatchedTaskRequest:
|
|
|
121
131
|
field_dict["start_time"] = start_time
|
|
122
132
|
if end_time is not UNSET:
|
|
123
133
|
field_dict["end_time"] = end_time
|
|
134
|
+
if time_to_start is not UNSET:
|
|
135
|
+
field_dict["time_to_start"] = time_to_start
|
|
124
136
|
if max_runtime is not UNSET:
|
|
125
137
|
field_dict["max_runtime"] = max_runtime
|
|
126
138
|
if stale_timeout is not UNSET:
|
|
@@ -131,10 +143,10 @@ class PatchedTaskRequest:
|
|
|
131
143
|
return field_dict
|
|
132
144
|
|
|
133
145
|
@classmethod
|
|
134
|
-
def from_dict(cls: type[T], src_dict:
|
|
146
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
135
147
|
from ..models.patched_task_request_tags import PatchedTaskRequestTags
|
|
136
148
|
|
|
137
|
-
d = src_dict
|
|
149
|
+
d = dict(src_dict)
|
|
138
150
|
name = d.pop("name", UNSET)
|
|
139
151
|
|
|
140
152
|
_status = d.pop("status", UNSET)
|
|
@@ -191,6 +203,15 @@ class PatchedTaskRequest:
|
|
|
191
203
|
|
|
192
204
|
end_time = _parse_end_time(d.pop("end_time", UNSET))
|
|
193
205
|
|
|
206
|
+
def _parse_time_to_start(data: object) -> Union[None, Unset, str]:
|
|
207
|
+
if data is None:
|
|
208
|
+
return data
|
|
209
|
+
if isinstance(data, Unset):
|
|
210
|
+
return data
|
|
211
|
+
return cast(Union[None, Unset, str], data)
|
|
212
|
+
|
|
213
|
+
time_to_start = _parse_time_to_start(d.pop("time_to_start", UNSET))
|
|
214
|
+
|
|
194
215
|
def _parse_max_runtime(data: object) -> Union[None, Unset, int]:
|
|
195
216
|
if data is None:
|
|
196
217
|
return data
|
|
@@ -224,6 +245,7 @@ class PatchedTaskRequest:
|
|
|
224
245
|
data=data,
|
|
225
246
|
start_time=start_time,
|
|
226
247
|
end_time=end_time,
|
|
248
|
+
time_to_start=time_to_start,
|
|
227
249
|
max_runtime=max_runtime,
|
|
228
250
|
stale_timeout=stale_timeout,
|
|
229
251
|
tags=tags,
|
{taskbadger-1.6.2 → taskbadger-1.7.0}/taskbadger/internal/models/patched_task_request_tags.py
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, TypeVar
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -19,8 +20,8 @@ class PatchedTaskRequestTags:
|
|
|
19
20
|
return field_dict
|
|
20
21
|
|
|
21
22
|
@classmethod
|
|
22
|
-
def from_dict(cls: type[T], src_dict:
|
|
23
|
-
d = src_dict
|
|
23
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
24
|
+
d = dict(src_dict)
|
|
24
25
|
patched_task_request_tags = cls()
|
|
25
26
|
|
|
26
27
|
patched_task_request_tags.additional_properties = d
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
|
3
4
|
|
|
4
5
|
from attrs import define as _attrs_define
|
|
@@ -43,6 +44,8 @@ class Task:
|
|
|
43
44
|
set via the API.
|
|
44
45
|
end_time (Union[None, Unset, datetime.datetime]): Datetime when status is set to a terminal value.Can be set via
|
|
45
46
|
the API.
|
|
47
|
+
time_to_start (Union[None, Unset, str]): Duration between task creation and when status first changes from
|
|
48
|
+
pending. (seconds)
|
|
46
49
|
max_runtime (Union[None, Unset, int]): Maximum duration the task can be running for before being considered
|
|
47
50
|
failed. (seconds)
|
|
48
51
|
stale_timeout (Union[None, Unset, int]): Maximum time to allow between task updates before considering the task
|
|
@@ -65,6 +68,7 @@ class Task:
|
|
|
65
68
|
data: Union[Unset, Any] = UNSET
|
|
66
69
|
start_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
67
70
|
end_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
71
|
+
time_to_start: Union[None, Unset, str] = UNSET
|
|
68
72
|
max_runtime: Union[None, Unset, int] = UNSET
|
|
69
73
|
stale_timeout: Union[None, Unset, int] = UNSET
|
|
70
74
|
tags: Union[Unset, "TaskTags"] = UNSET
|
|
@@ -120,6 +124,12 @@ class Task:
|
|
|
120
124
|
else:
|
|
121
125
|
end_time = self.end_time
|
|
122
126
|
|
|
127
|
+
time_to_start: Union[None, Unset, str]
|
|
128
|
+
if isinstance(self.time_to_start, Unset):
|
|
129
|
+
time_to_start = UNSET
|
|
130
|
+
else:
|
|
131
|
+
time_to_start = self.time_to_start
|
|
132
|
+
|
|
123
133
|
max_runtime: Union[None, Unset, int]
|
|
124
134
|
if isinstance(self.max_runtime, Unset):
|
|
125
135
|
max_runtime = UNSET
|
|
@@ -163,6 +173,8 @@ class Task:
|
|
|
163
173
|
field_dict["start_time"] = start_time
|
|
164
174
|
if end_time is not UNSET:
|
|
165
175
|
field_dict["end_time"] = end_time
|
|
176
|
+
if time_to_start is not UNSET:
|
|
177
|
+
field_dict["time_to_start"] = time_to_start
|
|
166
178
|
if max_runtime is not UNSET:
|
|
167
179
|
field_dict["max_runtime"] = max_runtime
|
|
168
180
|
if stale_timeout is not UNSET:
|
|
@@ -173,10 +185,10 @@ class Task:
|
|
|
173
185
|
return field_dict
|
|
174
186
|
|
|
175
187
|
@classmethod
|
|
176
|
-
def from_dict(cls: type[T], src_dict:
|
|
188
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
177
189
|
from ..models.task_tags import TaskTags
|
|
178
190
|
|
|
179
|
-
d = src_dict
|
|
191
|
+
d = dict(src_dict)
|
|
180
192
|
id = d.pop("id")
|
|
181
193
|
|
|
182
194
|
organization = d.pop("organization")
|
|
@@ -254,6 +266,15 @@ class Task:
|
|
|
254
266
|
|
|
255
267
|
end_time = _parse_end_time(d.pop("end_time", UNSET))
|
|
256
268
|
|
|
269
|
+
def _parse_time_to_start(data: object) -> Union[None, Unset, str]:
|
|
270
|
+
if data is None:
|
|
271
|
+
return data
|
|
272
|
+
if isinstance(data, Unset):
|
|
273
|
+
return data
|
|
274
|
+
return cast(Union[None, Unset, str], data)
|
|
275
|
+
|
|
276
|
+
time_to_start = _parse_time_to_start(d.pop("time_to_start", UNSET))
|
|
277
|
+
|
|
257
278
|
def _parse_max_runtime(data: object) -> Union[None, Unset, int]:
|
|
258
279
|
if data is None:
|
|
259
280
|
return data
|
|
@@ -295,6 +316,7 @@ class Task:
|
|
|
295
316
|
data=data,
|
|
296
317
|
start_time=start_time,
|
|
297
318
|
end_time=end_time,
|
|
319
|
+
time_to_start=time_to_start,
|
|
298
320
|
max_runtime=max_runtime,
|
|
299
321
|
stale_timeout=stale_timeout,
|
|
300
322
|
tags=tags,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
|
3
4
|
|
|
4
5
|
from attrs import define as _attrs_define
|
|
@@ -35,6 +36,8 @@ class TaskRequest:
|
|
|
35
36
|
set via the API.
|
|
36
37
|
end_time (Union[None, Unset, datetime.datetime]): Datetime when status is set to a terminal value.Can be set via
|
|
37
38
|
the API.
|
|
39
|
+
time_to_start (Union[None, Unset, str]): Duration between task creation and when status first changes from
|
|
40
|
+
pending. (seconds)
|
|
38
41
|
max_runtime (Union[None, Unset, int]): Maximum duration the task can be running for before being considered
|
|
39
42
|
failed. (seconds)
|
|
40
43
|
stale_timeout (Union[None, Unset, int]): Maximum time to allow between task updates before considering the task
|
|
@@ -49,6 +52,7 @@ class TaskRequest:
|
|
|
49
52
|
data: Union[Unset, Any] = UNSET
|
|
50
53
|
start_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
51
54
|
end_time: Union[None, Unset, datetime.datetime] = UNSET
|
|
55
|
+
time_to_start: Union[None, Unset, str] = UNSET
|
|
52
56
|
max_runtime: Union[None, Unset, int] = UNSET
|
|
53
57
|
stale_timeout: Union[None, Unset, int] = UNSET
|
|
54
58
|
tags: Union[Unset, "TaskRequestTags"] = UNSET
|
|
@@ -87,6 +91,12 @@ class TaskRequest:
|
|
|
87
91
|
else:
|
|
88
92
|
end_time = self.end_time
|
|
89
93
|
|
|
94
|
+
time_to_start: Union[None, Unset, str]
|
|
95
|
+
if isinstance(self.time_to_start, Unset):
|
|
96
|
+
time_to_start = UNSET
|
|
97
|
+
else:
|
|
98
|
+
time_to_start = self.time_to_start
|
|
99
|
+
|
|
90
100
|
max_runtime: Union[None, Unset, int]
|
|
91
101
|
if isinstance(self.max_runtime, Unset):
|
|
92
102
|
max_runtime = UNSET
|
|
@@ -122,6 +132,8 @@ class TaskRequest:
|
|
|
122
132
|
field_dict["start_time"] = start_time
|
|
123
133
|
if end_time is not UNSET:
|
|
124
134
|
field_dict["end_time"] = end_time
|
|
135
|
+
if time_to_start is not UNSET:
|
|
136
|
+
field_dict["time_to_start"] = time_to_start
|
|
125
137
|
if max_runtime is not UNSET:
|
|
126
138
|
field_dict["max_runtime"] = max_runtime
|
|
127
139
|
if stale_timeout is not UNSET:
|
|
@@ -132,10 +144,10 @@ class TaskRequest:
|
|
|
132
144
|
return field_dict
|
|
133
145
|
|
|
134
146
|
@classmethod
|
|
135
|
-
def from_dict(cls: type[T], src_dict:
|
|
147
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
136
148
|
from ..models.task_request_tags import TaskRequestTags
|
|
137
149
|
|
|
138
|
-
d = src_dict
|
|
150
|
+
d = dict(src_dict)
|
|
139
151
|
name = d.pop("name")
|
|
140
152
|
|
|
141
153
|
_status = d.pop("status", UNSET)
|
|
@@ -192,6 +204,15 @@ class TaskRequest:
|
|
|
192
204
|
|
|
193
205
|
end_time = _parse_end_time(d.pop("end_time", UNSET))
|
|
194
206
|
|
|
207
|
+
def _parse_time_to_start(data: object) -> Union[None, Unset, str]:
|
|
208
|
+
if data is None:
|
|
209
|
+
return data
|
|
210
|
+
if isinstance(data, Unset):
|
|
211
|
+
return data
|
|
212
|
+
return cast(Union[None, Unset, str], data)
|
|
213
|
+
|
|
214
|
+
time_to_start = _parse_time_to_start(d.pop("time_to_start", UNSET))
|
|
215
|
+
|
|
195
216
|
def _parse_max_runtime(data: object) -> Union[None, Unset, int]:
|
|
196
217
|
if data is None:
|
|
197
218
|
return data
|
|
@@ -225,6 +246,7 @@ class TaskRequest:
|
|
|
225
246
|
data=data,
|
|
226
247
|
start_time=start_time,
|
|
227
248
|
end_time=end_time,
|
|
249
|
+
time_to_start=time_to_start,
|
|
228
250
|
max_runtime=max_runtime,
|
|
229
251
|
stale_timeout=stale_timeout,
|
|
230
252
|
tags=tags,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, TypeVar
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -19,8 +20,8 @@ class TaskRequestTags:
|
|
|
19
20
|
return field_dict
|
|
20
21
|
|
|
21
22
|
@classmethod
|
|
22
|
-
def from_dict(cls: type[T], src_dict:
|
|
23
|
-
d = src_dict
|
|
23
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
24
|
+
d = dict(src_dict)
|
|
24
25
|
task_request_tags = cls()
|
|
25
26
|
|
|
26
27
|
task_request_tags.additional_properties = d
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, TypeVar
|
|
2
3
|
|
|
3
4
|
from attrs import define as _attrs_define
|
|
@@ -19,8 +20,8 @@ class TaskTags:
|
|
|
19
20
|
return field_dict
|
|
20
21
|
|
|
21
22
|
@classmethod
|
|
22
|
-
def from_dict(cls: type[T], src_dict:
|
|
23
|
-
d = src_dict
|
|
23
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
24
|
+
d = dict(src_dict)
|
|
24
25
|
task_tags = cls()
|
|
25
26
|
|
|
26
27
|
task_tags.additional_properties = d
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Contains some shared types for properties"""
|
|
2
2
|
|
|
3
|
-
from collections.abc import MutableMapping
|
|
3
|
+
from collections.abc import Mapping, MutableMapping
|
|
4
4
|
from http import HTTPStatus
|
|
5
|
-
from typing import BinaryIO, Generic, Literal, Optional, TypeVar
|
|
5
|
+
from typing import IO, BinaryIO, Generic, Literal, Optional, TypeVar, Union
|
|
6
6
|
|
|
7
7
|
from attrs import define
|
|
8
8
|
|
|
@@ -14,7 +14,15 @@ class Unset:
|
|
|
14
14
|
|
|
15
15
|
UNSET: Unset = Unset()
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
# The types that `httpx.Client(files=)` can accept, copied from that library.
|
|
18
|
+
FileContent = Union[IO[bytes], bytes, str]
|
|
19
|
+
FileTypes = Union[
|
|
20
|
+
# (filename, file (or bytes), content_type)
|
|
21
|
+
tuple[Optional[str], FileContent, Optional[str]],
|
|
22
|
+
# (filename, file (or bytes), content_type, headers)
|
|
23
|
+
tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
|
|
24
|
+
]
|
|
25
|
+
RequestFiles = list[tuple[str, FileTypes]]
|
|
18
26
|
|
|
19
27
|
|
|
20
28
|
@define
|
|
@@ -25,7 +33,7 @@ class File:
|
|
|
25
33
|
file_name: Optional[str] = None
|
|
26
34
|
mime_type: Optional[str] = None
|
|
27
35
|
|
|
28
|
-
def to_tuple(self) ->
|
|
36
|
+
def to_tuple(self) -> FileTypes:
|
|
29
37
|
"""Return a tuple representation that httpx will accept for multipart/form-data"""
|
|
30
38
|
return self.file_name, self.payload, self.mime_type
|
|
31
39
|
|
|
@@ -43,4 +51,4 @@ class Response(Generic[T]):
|
|
|
43
51
|
parsed: Optional[T]
|
|
44
52
|
|
|
45
53
|
|
|
46
|
-
__all__ = ["UNSET", "File", "
|
|
54
|
+
__all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import datetime
|
|
2
3
|
import logging
|
|
3
4
|
import os
|
|
@@ -35,6 +36,26 @@ log = logging.getLogger("taskbadger")
|
|
|
35
36
|
_TB_HOST = "https://taskbadger.net"
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
def _parse_token(token):
|
|
40
|
+
"""Try to decode a project API key.
|
|
41
|
+
|
|
42
|
+
Project keys are base64-encoded strings in the format ``org/project/key``.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
A tuple of ``(organization_slug, project_slug, api_key)`` if *token*
|
|
46
|
+
is a valid project key, otherwise ``None``.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
decoded = base64.b64decode(token, validate=True).decode("utf-8")
|
|
50
|
+
except Exception:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
parts = decoded.split("/")
|
|
54
|
+
if len(parts) == 3 and all(parts):
|
|
55
|
+
return tuple(parts)
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
38
59
|
def init(
|
|
39
60
|
organization_slug: str = None,
|
|
40
61
|
project_slug: str = None,
|
|
@@ -43,9 +64,16 @@ def init(
|
|
|
43
64
|
tags: dict[str, str] = None,
|
|
44
65
|
before_create: Callback = None,
|
|
45
66
|
):
|
|
46
|
-
"""Initialize Task Badger client
|
|
67
|
+
"""Initialize Task Badger client.
|
|
68
|
+
|
|
69
|
+
If *token* is a project API key (base64-encoded ``org/project/key``),
|
|
70
|
+
the organization and project slugs are extracted automatically and
|
|
71
|
+
*organization_slug* / *project_slug* are ignored.
|
|
47
72
|
|
|
48
|
-
|
|
73
|
+
For legacy API keys, *organization_slug* and *project_slug* are
|
|
74
|
+
required and a deprecation warning is emitted.
|
|
75
|
+
|
|
76
|
+
Call this function once per thread.
|
|
49
77
|
"""
|
|
50
78
|
_init(_TB_HOST, organization_slug, project_slug, token, systems, tags, before_create)
|
|
51
79
|
|
|
@@ -64,6 +92,17 @@ def _init(
|
|
|
64
92
|
project_slug = project_slug or os.environ.get("TASKBADGER_PROJECT")
|
|
65
93
|
token = token or os.environ.get("TASKBADGER_API_KEY")
|
|
66
94
|
|
|
95
|
+
if token:
|
|
96
|
+
parsed = _parse_token(token)
|
|
97
|
+
if parsed:
|
|
98
|
+
organization_slug, project_slug, token = parsed
|
|
99
|
+
else:
|
|
100
|
+
warnings.warn(
|
|
101
|
+
"Legacy API keys are deprecated. Please switch to a project API key.",
|
|
102
|
+
DeprecationWarning,
|
|
103
|
+
stacklevel=3,
|
|
104
|
+
)
|
|
105
|
+
|
|
67
106
|
if before_create and isinstance(before_create, str):
|
|
68
107
|
try:
|
|
69
108
|
before_create = import_string(before_create)
|
|
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
|
|
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
|
|
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
|