taskbadger 1.3.3__tar.gz → 1.4.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.
Files changed (60) hide show
  1. taskbadger-1.4.0/.gitignore +25 -0
  2. {taskbadger-1.3.3 → taskbadger-1.4.0}/PKG-INFO +16 -22
  3. taskbadger-1.4.0/pyproject.toml +97 -0
  4. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/__init__.py +18 -0
  5. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/celery.py +38 -6
  6. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli/__init__.py +2 -0
  7. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli/basics.py +24 -7
  8. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli/list_tasks.py +16 -2
  9. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli/wrapper.py +7 -4
  10. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli_main.py +8 -4
  11. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/config.py +7 -4
  12. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/decorators.py +19 -3
  13. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/integrations.py +2 -2
  14. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/__init__.py +2 -1
  15. taskbadger-1.4.0/taskbadger/internal/api/__init__.py +1 -0
  16. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_cancel.py +7 -10
  17. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_create.py +11 -11
  18. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_get.py +11 -12
  19. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_list.py +17 -17
  20. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_partial_update.py +11 -12
  21. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/action_update.py +11 -12
  22. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_cancel.py +7 -9
  23. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_create.py +11 -10
  24. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_get.py +11 -11
  25. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_list.py +12 -11
  26. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_partial_update.py +11 -11
  27. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/task_update.py +11 -11
  28. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/client.py +19 -17
  29. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/errors.py +3 -2
  30. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/__init__.py +1 -1
  31. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/action.py +7 -7
  32. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/action_config.py +6 -6
  33. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/action_request.py +7 -7
  34. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/action_request_config.py +6 -6
  35. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/paginated_task_list.py +8 -8
  36. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/patched_action_request.py +7 -7
  37. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/patched_action_request_config.py +6 -6
  38. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/patched_task_request.py +7 -7
  39. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/patched_task_request_data.py +6 -6
  40. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/task.py +7 -7
  41. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/task_data.py +6 -6
  42. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/task_request.py +7 -7
  43. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/task_request_data.py +6 -6
  44. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/types.py +5 -3
  45. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/mug.py +2 -2
  46. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/sdk.py +38 -13
  47. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/systems/__init__.py +1 -1
  48. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/systems/celery.py +3 -1
  49. taskbadger-1.3.3/pyproject.toml +0 -87
  50. taskbadger-1.3.3/taskbadger/internal/api/__init__.py +0 -1
  51. {taskbadger-1.3.3 → taskbadger-1.4.0}/LICENSE +0 -0
  52. {taskbadger-1.3.3 → taskbadger-1.4.0}/README.md +0 -0
  53. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/cli/utils.py +0 -0
  54. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/exceptions.py +0 -0
  55. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/action_endpoints/__init__.py +0 -0
  56. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/api/task_endpoints/__init__.py +0 -0
  57. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/models/status_enum.py +0 -0
  58. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/internal/py.typed +0 -0
  59. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/process.py +0 -0
  60. {taskbadger-1.3.3 → taskbadger-1.4.0}/taskbadger/safe_sdk.py +0 -0
@@ -0,0 +1,25 @@
1
+ __pycache__/
2
+ build/
3
+ dist/
4
+ *.egg-info/
5
+ .pytest_cache/
6
+
7
+ # pyenv
8
+ .python-version
9
+
10
+ # Environments
11
+ .env
12
+ .venv
13
+ .envrc
14
+ .env.integration
15
+
16
+ # mypy
17
+ .mypy_cache/
18
+ .dmypy.json
19
+ dmypy.json
20
+
21
+ # JetBrains
22
+ .idea/
23
+
24
+ /coverage.xml
25
+ /.coverage
@@ -1,37 +1,32 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: taskbadger
3
- Version: 1.3.3
3
+ Version: 1.4.0
4
4
  Summary: The official Python SDK for Task Badger
5
- Home-page: https://taskbadger.net/
6
- License: Apache-2.0
7
- Requires-Python: >=3.8,<4.0
5
+ Project-URL: Changelog, https://github.com/taskbadger/taskbadger-python/releases
6
+ Project-URL: homepage, https://taskbadger.net/
7
+ Project-URL: repository, https://github.com/taskbadger/taskbadger-python
8
+ Project-URL: documentation, https://docs.taskbadger.net/
9
+ License-File: LICENSE
8
10
  Classifier: Development Status :: 4 - Beta
9
11
  Classifier: Environment :: Web Environment
10
12
  Classifier: Intended Audience :: Developers
11
- Classifier: License :: OSI Approved :: Apache Software License
12
13
  Classifier: Operating System :: OS Independent
13
14
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.8
16
15
  Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Programming Language :: Python :: 3.6
21
- Classifier: Programming Language :: Python :: 3.7
22
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.9
21
+ Requires-Dist: attrs>=21.3.0
22
+ Requires-Dist: httpx<0.28.0,>=0.20.0
23
+ Requires-Dist: importlib-metadata>=1.0; python_version < '3.8'
24
+ Requires-Dist: python-dateutil>=2.8.0
25
+ Requires-Dist: tomlkit>=0.12.5
26
+ Requires-Dist: typer[all]<0.10.0
27
+ Requires-Dist: typing-extensions>=4.7.1; python_version <= '3.9'
23
28
  Provides-Extra: celery
24
- Requires-Dist: attrs (>=21.3.0)
25
- Requires-Dist: celery (>=4.0.0,<6.0.0) ; extra == "celery"
26
- Requires-Dist: httpx (>=0.20.0,<0.28.0)
27
- Requires-Dist: importlib-metadata (>=1.0,<2.0) ; python_version < "3.8"
28
- Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
29
- Requires-Dist: tomlkit (>=0.12.5,<0.13.0)
30
- Requires-Dist: typer[all] (<0.10.0)
31
- Requires-Dist: typing-extensions (>=4.7.1,<5.0.0) ; python_version == "3.9"
32
- Project-URL: Changelog, https://github.com/taskbadger/taskbadger-python/releases
33
- Project-URL: Documentation, https://docs.taskbadger.net/
34
- Project-URL: Repository, https://github.com/taskbadger/taskbadger-python
29
+ Requires-Dist: celery<6.0.0,>=4.0.0; extra == 'celery'
35
30
  Description-Content-Type: text/markdown
36
31
 
37
32
  # Task Badger Python Client
@@ -143,4 +138,3 @@ $ taskbadger run "demo task" --action error email to:me@test.com -- path/to/scri
143
138
 
144
139
  Task created: https://taskbadger.net/public/tasks/xyz/
145
140
  ```
146
-
@@ -0,0 +1,97 @@
1
+ [project]
2
+ name = "taskbadger"
3
+ version = "1.4.0"
4
+ description = "The official Python SDK for Task Badger"
5
+ requires-python = ">=3.9"
6
+ authors = []
7
+ readme = "README.md"
8
+ classifiers = [
9
+ "Development Status :: 4 - Beta",
10
+ "Environment :: Web Environment",
11
+ "Intended Audience :: Developers",
12
+ "Operating System :: OS Independent",
13
+ "Programming Language :: Python",
14
+ "Programming Language :: Python :: 3.9",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Topic :: Software Development :: Libraries :: Python Modules",
19
+ ]
20
+
21
+ dependencies = [
22
+ "httpx >=0.20.0,<0.28.0",
23
+ "attrs >=21.3.0",
24
+ "python-dateutil >=2.8.0",
25
+ "typer[all] <0.10.0",
26
+ "tomlkit >=0.12.5",
27
+ "importlib-metadata >=1.0; python_version < '3.8'",
28
+ "typing-extensions >=4.7.1; python_version <= '3.9'",
29
+ ]
30
+
31
+ [build-system]
32
+ requires = ["hatchling"]
33
+ build-backend = "hatchling.build"
34
+
35
+ [tool.hatch.build.targets.sdist]
36
+ include = [
37
+ "taskbadger",
38
+ "taskbadger/internal/py.typed",
39
+ ]
40
+
41
+ [project.optional-dependencies]
42
+ celery = [
43
+ "celery>=4.0.0,<6.0.0",
44
+ ]
45
+
46
+ [tool.uv]
47
+ package = true
48
+
49
+ [project.urls]
50
+ "Changelog" = "https://github.com/taskbadger/taskbadger-python/releases"
51
+ homepage = "https://taskbadger.net/"
52
+ repository = "https://github.com/taskbadger/taskbadger-python"
53
+ documentation = "https://docs.taskbadger.net/"
54
+
55
+
56
+ [dependency-groups]
57
+ dev = [
58
+ "black",
59
+ "isort",
60
+ "pre-commit",
61
+ "pytest",
62
+ "pytest-httpx",
63
+ "invoke",
64
+ "pytest-celery",
65
+ "redis",
66
+ "openapi-python-client",
67
+ ]
68
+
69
+ [project.scripts]
70
+ taskbadger = "taskbadger.cli_main:app"
71
+
72
+ [tool.pytest.ini_options]
73
+ # don't run integration tests unless specifically requested
74
+ norecursedirs = ".* integration_tests"
75
+
76
+
77
+ [tool.ruff]
78
+ exclude = [
79
+ ".venv",
80
+ ".git",
81
+ ".ruff_cache",
82
+ ]
83
+ line-length = 120
84
+ indent-width = 4
85
+ target-version = "py39"
86
+
87
+ [tool.ruff.lint]
88
+ select = ["E", "F", "I", "UP", "DJ", "PT"]
89
+ fixable = ["ALL"]
90
+ unfixable = []
91
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
92
+
93
+ [tool.ruff.format]
94
+ quote-style = "double"
95
+ indent-style = "space"
96
+ skip-magic-trailing-comma = false
97
+ line-ending = "auto"
@@ -5,6 +5,24 @@ from .mug import Badger, Session
5
5
  from .safe_sdk import create_task_safe, update_task_safe
6
6
  from .sdk import DefaultMergeStrategy, Task, create_task, get_task, init, update_task
7
7
 
8
+ __all__ = [
9
+ "track",
10
+ "Action",
11
+ "EmailIntegration",
12
+ "WebhookIntegration",
13
+ "StatusEnum",
14
+ "Badger",
15
+ "Session",
16
+ "create_task_safe",
17
+ "update_task_safe",
18
+ "DefaultMergeStrategy",
19
+ "Task",
20
+ "create_task",
21
+ "get_task",
22
+ "init",
23
+ "update_task",
24
+ ]
25
+
8
26
  try:
9
27
  import importlib.metadata as importlib_metadata
10
28
  except ModuleNotFoundError:
@@ -1,9 +1,17 @@
1
1
  import collections
2
2
  import functools
3
+ import json
3
4
  import logging
4
5
 
5
6
  import celery
6
- from celery.signals import before_task_publish, task_failure, task_prerun, task_retry, task_success
7
+ from celery.signals import (
8
+ before_task_publish,
9
+ task_failure,
10
+ task_prerun,
11
+ task_retry,
12
+ task_success,
13
+ )
14
+ from kombu import serialization
7
15
 
8
16
  from .internal.models import StatusEnum
9
17
  from .mug import Badger
@@ -12,10 +20,15 @@ from .sdk import DefaultMergeStrategy, get_task
12
20
 
13
21
  KWARG_PREFIX = "taskbadger_"
14
22
  TB_KWARGS_ARG = f"{KWARG_PREFIX}kwargs"
15
- IGNORE_ARGS = {TB_KWARGS_ARG, f"{KWARG_PREFIX}task", f"{KWARG_PREFIX}task_id"}
23
+ IGNORE_ARGS = {TB_KWARGS_ARG, f"{KWARG_PREFIX}task", f"{KWARG_PREFIX}task_id", f"{KWARG_PREFIX}record_task_args"}
16
24
  TB_TASK_ID = f"{KWARG_PREFIX}task_id"
17
25
 
18
- TERMINAL_STATES = {StatusEnum.SUCCESS, StatusEnum.ERROR, StatusEnum.CANCELLED, StatusEnum.STALE}
26
+ TERMINAL_STATES = {
27
+ StatusEnum.SUCCESS,
28
+ StatusEnum.ERROR,
29
+ StatusEnum.CANCELLED,
30
+ StatusEnum.STALE,
31
+ }
19
32
 
20
33
  log = logging.getLogger("taskbadger")
21
34
 
@@ -102,7 +115,6 @@ class Task(celery.Task):
102
115
 
103
116
  def apply_async(self, *args, **kwargs):
104
117
  headers = kwargs.setdefault("headers", {})
105
- headers["taskbadger_track"] = True
106
118
  tb_kwargs = self._get_tb_kwargs(kwargs)
107
119
  if kwargs.get("kwargs"):
108
120
  # extract taskbadger options from task kwargs when supplied as keyword argument
@@ -110,7 +122,13 @@ class Task(celery.Task):
110
122
  elif len(args) > 1 and isinstance(args[1], dict):
111
123
  # extract taskbadger options from task kwargs when supplied as positional argument
112
124
  tb_kwargs.update(self._get_tb_kwargs(args[1]))
113
- headers[TB_KWARGS_ARG] = tb_kwargs
125
+
126
+ if Badger.is_configured():
127
+ headers["taskbadger_track"] = True
128
+ headers[TB_KWARGS_ARG] = tb_kwargs
129
+ if "record_task_args" in tb_kwargs:
130
+ headers["taskbadger_record_task_args"] = tb_kwargs.pop("record_task_args")
131
+
114
132
  result = super().apply_async(*args, **kwargs)
115
133
 
116
134
  tb_task_id = result.info.get(TB_TASK_ID) if result.info else None
@@ -150,13 +168,13 @@ class Task(celery.Task):
150
168
  @before_task_publish.connect
151
169
  def task_publish_handler(sender=None, headers=None, body=None, **kwargs):
152
170
  headers = headers if "task" in headers else body
171
+ header_kwargs = headers.pop(TB_KWARGS_ARG, {}) # always remove TB headers
153
172
  if sender.startswith("celery.") or not Badger.is_configured():
154
173
  return
155
174
 
156
175
  celery_system = Badger.current.settings.get_system_by_id("celery")
157
176
  auto_track = celery_system and celery_system.track_task(sender)
158
177
  manual_track = headers.get("taskbadger_track")
159
- header_kwargs = headers.pop(TB_KWARGS_ARG, {})
160
178
  if not manual_track and not auto_track:
161
179
  return
162
180
 
@@ -173,6 +191,20 @@ def task_publish_handler(sender=None, headers=None, body=None, **kwargs):
173
191
  kwargs["status"] = StatusEnum.PENDING
174
192
  name = kwargs.pop("name", headers["task"])
175
193
 
194
+ global_record_task_args = celery_system and celery_system.record_task_args
195
+ if headers.get("taskbadger_record_task_args", global_record_task_args):
196
+ data = {
197
+ "celery_task_args": body[0],
198
+ "celery_task_kwargs": body[1],
199
+ }
200
+ try:
201
+ _, _, value = serialization.dumps(data, serializer="json")
202
+ data = json.loads(value)
203
+ except Exception:
204
+ log.error("Error serializing task arguments for task '%s'", name)
205
+ else:
206
+ kwargs.setdefault("data", {}).update(data)
207
+
176
208
  task = create_task_safe(name, **kwargs)
177
209
  if task:
178
210
  meta = {TB_TASK_ID: task.id}
@@ -1,3 +1,5 @@
1
1
  from .basics import create, get, update
2
2
  from .list_tasks import list_tasks_command
3
3
  from .wrapper import run
4
+
5
+ __all__ = ["create", "get", "update", "list_tasks_command", "run"]
@@ -1,13 +1,18 @@
1
1
  import csv
2
2
  import json
3
3
  import sys
4
- from typing import Tuple
5
4
 
6
5
  import typer
7
6
  from rich import print
8
7
 
9
8
  from taskbadger import StatusEnum, create_task, get_task, update_task
10
- from taskbadger.cli.utils import OutputFormat, configure_api, err_console, get_actions, get_metadata
9
+ from taskbadger.cli.utils import (
10
+ OutputFormat,
11
+ configure_api,
12
+ err_console,
13
+ get_actions,
14
+ get_metadata,
15
+ )
11
16
 
12
17
 
13
18
  def get(
@@ -29,14 +34,22 @@ def get(
29
34
  elif output_format == OutputFormat.csv:
30
35
  writer = csv.writer(sys.stdout)
31
36
  writer.writerow("Task ID,Created,Name,Status,Percent".split(","))
32
- writer.writerow([task.id, task.created.isoformat(), task.name, task.status, str(task.value_percent)])
37
+ writer.writerow(
38
+ [
39
+ task.id,
40
+ task.created.isoformat(),
41
+ task.name,
42
+ task.status,
43
+ str(task.value_percent),
44
+ ]
45
+ )
33
46
 
34
47
 
35
48
  def create(
36
49
  ctx: typer.Context,
37
50
  name: str = typer.Argument(..., show_default=False, help="The task name."),
38
51
  monitor_id: str = typer.Option(None, help="Associate this task with a monitor."),
39
- action_def: Tuple[str, str, str] = typer.Option(
52
+ action_def: tuple[str, str, str] = typer.Option(
40
53
  (None, None, None),
41
54
  "--action",
42
55
  "-a",
@@ -52,7 +65,9 @@ def create(
52
65
  help="Metadata 'key=value' pair to associate with the task. Can be specified multiple times.",
53
66
  ),
54
67
  metadata_json: str = typer.Option(
55
- None, show_default=False, help="Metadata to associate with the task. Must be valid JSON."
68
+ None,
69
+ show_default=False,
70
+ help="Metadata to associate with the task. Must be valid JSON.",
56
71
  ),
57
72
  quiet: bool = typer.Option(False, "--quiet", "-q", help="Minimal output. Only the Task ID."),
58
73
  ):
@@ -83,7 +98,7 @@ def update(
83
98
  ctx: typer.Context,
84
99
  task_id: str = typer.Argument(..., show_default=False, help="The ID of the task to update."),
85
100
  name: str = typer.Option(None, show_default=False, help="Update the name of the task."),
86
- action_def: Tuple[str, str, str] = typer.Option(
101
+ action_def: tuple[str, str, str] = typer.Option(
87
102
  (None, None, None),
88
103
  "--action",
89
104
  "-a",
@@ -100,7 +115,9 @@ def update(
100
115
  help="Metadata 'key=value' pair to associate with the task. Can be specified multiple times.",
101
116
  ),
102
117
  metadata_json: str = typer.Option(
103
- None, show_default=False, help="Metadata to associate with the task. Must be valid JSON."
118
+ None,
119
+ show_default=False,
120
+ help="Metadata to associate with the task. Must be valid JSON.",
104
121
  ),
105
122
  quiet: bool = typer.Option(False, "--quiet", "-q", help="No output."),
106
123
  ):
@@ -47,7 +47,13 @@ def _render_pretty(ctx, result):
47
47
  table.add_column("Percent", no_wrap=True)
48
48
 
49
49
  for task in result.results:
50
- table.add_row(task.id, task.created.isoformat(), task.name, task.status, str(task.value_percent))
50
+ table.add_row(
51
+ task.id,
52
+ task.created.isoformat(),
53
+ task.name,
54
+ task.status,
55
+ str(task.value_percent),
56
+ )
51
57
  Console().print(table)
52
58
 
53
59
  cursor = _get_cursor(result.next_)
@@ -59,7 +65,15 @@ def _render_csv(ctx, result):
59
65
  writer = csv.writer(sys.stdout)
60
66
  writer.writerow("Task ID,Created,Name,Status,Percent".split(","))
61
67
  for task in result.results:
62
- writer.writerow([task.id, task.created.isoformat(), task.name, task.status, str(task.value_percent)])
68
+ writer.writerow(
69
+ [
70
+ task.id,
71
+ task.created.isoformat(),
72
+ task.name,
73
+ task.status,
74
+ str(task.value_percent),
75
+ ]
76
+ )
63
77
 
64
78
  cursor = _get_cursor(result.next_)
65
79
  if cursor:
@@ -1,5 +1,3 @@
1
- from typing import Tuple
2
-
3
1
  import typer
4
2
  from rich import print
5
3
 
@@ -13,7 +11,7 @@ def run(
13
11
  name: str = typer.Argument(..., show_default=False, help="The task name"),
14
12
  monitor_id: str = typer.Option(None, help="Associate this task with a monitor."),
15
13
  update_frequency: int = typer.Option(5, metavar="SECONDS", min=5, max=300, help="Seconds between updates."),
16
- action_def: Tuple[str, str, str] = typer.Option(
14
+ action_def: tuple[str, str, str] = typer.Option(
17
15
  (None, None, None),
18
16
  "--action",
19
17
  "-a",
@@ -53,7 +51,12 @@ def run(
53
51
  print(f"Task created: {task.public_url}")
54
52
  env = {"TASKBADGER_TASK_ID": task.id} if task else None
55
53
  try:
56
- process = ProcessRunner(ctx.args, env, capture_output=capture_output, update_frequency=update_frequency)
54
+ process = ProcessRunner(
55
+ ctx.args,
56
+ env,
57
+ capture_output=capture_output,
58
+ update_frequency=update_frequency,
59
+ )
57
60
  for output in process.run():
58
61
  _update_task(task, **(output or {}))
59
62
  except Exception as e:
@@ -30,9 +30,9 @@ def version_callback(value: bool):
30
30
  def configure(ctx: typer.Context):
31
31
  """Update CLI configuration."""
32
32
  config = ctx.meta["tb_config"]
33
- config.organization_slug = typer.prompt(f"Organization slug", default=config.organization_slug)
34
- config.project_slug = typer.prompt(f"Project slug", default=config.project_slug)
35
- config.token = typer.prompt(f"API Key", default=config.token)
33
+ config.organization_slug = typer.prompt("Organization slug", default=config.organization_slug)
34
+ config.project_slug = typer.prompt("Project slug", default=config.project_slug)
35
+ config.token = typer.prompt("API Key", default=config.token)
36
36
  path = write_config(config)
37
37
  print(f"Config written to [green]{path}[/green]")
38
38
 
@@ -71,7 +71,11 @@ def main(
71
71
  help="Project Slug. This will override values from the config file and environment variables.",
72
72
  ),
73
73
  version: Optional[bool] = typer.Option( # noqa
74
- None, "--version", callback=version_callback, is_eager=True, help="Show CLI Version"
74
+ None,
75
+ "--version",
76
+ callback=version_callback,
77
+ is_eager=True,
78
+ help="Show CLI Version",
75
79
  ),
76
80
  ):
77
81
  """
@@ -59,9 +59,9 @@ class Config:
59
59
  host = f"\n Host: {self.host}"
60
60
  return inspect.cleandoc(
61
61
  f"""
62
- Organization slug: {self.organization_slug or '-'}
63
- Project slug: {self.project_slug or '-'}
64
- Auth token: {self.token or '-'}{host}
62
+ Organization slug: {self.organization_slug or "-"}
63
+ Project slug: {self.project_slug or "-"}
64
+ Auth token: {self.token or "-"}{host}
65
65
  """
66
66
  )
67
67
 
@@ -73,7 +73,10 @@ def _from_env(name, default=None, prefix="TASKBADGER_"):
73
73
  def write_config(config):
74
74
  doc = document()
75
75
 
76
- doc.add("defaults", table().add("org", config.organization_slug).add("project", config.project_slug))
76
+ doc.add(
77
+ "defaults",
78
+ table().add("org", config.organization_slug).add("project", config.project_slug),
79
+ )
77
80
 
78
81
  doc.add("auth", table().add("token", config.token))
79
82
 
@@ -8,7 +8,14 @@ from .sdk import StatusEnum
8
8
  log = logging.getLogger("taskbadger")
9
9
 
10
10
 
11
- def track(func=None, *, name: str = None, monitor_id: str = None, max_runtime: int = None, **kwargs):
11
+ def track(
12
+ func=None,
13
+ *,
14
+ name: str = None,
15
+ monitor_id: str = None,
16
+ max_runtime: int = None,
17
+ **kwargs,
18
+ ):
12
19
  """
13
20
  Decorator to track a function as a task.
14
21
 
@@ -39,12 +46,21 @@ def track(func=None, *, name: str = None, monitor_id: str = None, max_runtime: i
39
46
  @Session()
40
47
  def _inner(*args, **kwargs):
41
48
  task = create_task_safe(
42
- task_name, status=StatusEnum.PROCESSING, max_runtime=max_runtime, monitor_id=monitor_id, **kwargs
49
+ task_name,
50
+ status=StatusEnum.PROCESSING,
51
+ max_runtime=max_runtime,
52
+ monitor_id=monitor_id,
53
+ **kwargs,
43
54
  )
44
55
  try:
45
56
  result = func(*args, **kwargs)
46
57
  except Exception as e:
47
- _update_task(task, status=StatusEnum.ERROR, data={"exception": str(e)}, data_merge_strategy="default")
58
+ _update_task(
59
+ task,
60
+ status=StatusEnum.ERROR,
61
+ data={"exception": str(e)},
62
+ data_merge_strategy="default",
63
+ )
48
64
  raise
49
65
 
50
66
  _update_task(task, status=StatusEnum.SUCCESS)
@@ -1,5 +1,5 @@
1
1
  import dataclasses
2
- from typing import Any, Dict
2
+ from typing import Any
3
3
 
4
4
  from taskbadger.exceptions import TaskbadgerException
5
5
  from taskbadger.internal.models import ActionRequest, ActionRequestConfig
@@ -37,7 +37,7 @@ class Action:
37
37
  trigger: str
38
38
  integration: Integration
39
39
 
40
- def to_dict(self) -> Dict[str, Any]:
40
+ def to_dict(self) -> dict[str, Any]:
41
41
  return ActionRequest(self.trigger, self.integration.id, self.integration.request_config()).to_dict()
42
42
 
43
43
 
@@ -1,4 +1,5 @@
1
- """ A client library for accessing Taskbadger API """
1
+ """A client library for accessing Taskbadger API"""
2
+
2
3
  from .client import AuthenticatedClient, Client
3
4
 
4
5
  __all__ = (
@@ -0,0 +1 @@
1
+ """Contains methods for accessing the API"""
@@ -1,5 +1,5 @@
1
1
  from http import HTTPStatus
2
- from typing import Any, Dict, Optional, Union
2
+ from typing import Any, Optional, Union
3
3
 
4
4
  import httpx
5
5
 
@@ -13,17 +13,12 @@ def _get_kwargs(
13
13
  project_slug: str,
14
14
  task_id: str,
15
15
  id: str,
16
- ) -> Dict[str, Any]:
16
+ ) -> dict[str, Any]:
17
17
  pass
18
18
 
19
19
  return {
20
20
  "method": "delete",
21
- "url": "/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/{id}/".format(
22
- organization_slug=organization_slug,
23
- project_slug=project_slug,
24
- task_id=task_id,
25
- id=id,
26
- ),
21
+ "url": f"/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/{id}/",
27
22
  }
28
23
 
29
24
 
@@ -64,7 +59,8 @@ def sync_detailed(
64
59
  id (str):
65
60
 
66
61
  Raises:
67
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
62
+ errors.UnexpectedStatus: If the server returns an undocumented status code
63
+ and Client.raise_on_unexpected_status is True.
68
64
  httpx.TimeoutException: If the request takes longer than Client.timeout.
69
65
 
70
66
  Returns:
@@ -104,7 +100,8 @@ async def asyncio_detailed(
104
100
  id (str):
105
101
 
106
102
  Raises:
107
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
103
+ errors.UnexpectedStatus: If the server returns an undocumented status code
104
+ and Client.raise_on_unexpected_status is True.
108
105
  httpx.TimeoutException: If the request takes longer than Client.timeout.
109
106
 
110
107
  Returns:
@@ -1,5 +1,5 @@
1
1
  from http import HTTPStatus
2
- from typing import Any, Dict, Optional, Union
2
+ from typing import Any, Optional, Union
3
3
 
4
4
  import httpx
5
5
 
@@ -16,18 +16,14 @@ def _get_kwargs(
16
16
  task_id: str,
17
17
  *,
18
18
  json_body: ActionRequest,
19
- ) -> Dict[str, Any]:
19
+ ) -> dict[str, Any]:
20
20
  pass
21
21
 
22
22
  json_json_body = json_body.to_dict()
23
23
 
24
24
  return {
25
25
  "method": "post",
26
- "url": "/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/".format(
27
- organization_slug=organization_slug,
28
- project_slug=project_slug,
29
- task_id=task_id,
30
- ),
26
+ "url": f"/api/{organization_slug}/{project_slug}/tasks/{task_id}/actions/",
31
27
  "json": json_json_body,
32
28
  }
33
29
 
@@ -71,7 +67,8 @@ def sync_detailed(
71
67
  json_body (ActionRequest):
72
68
 
73
69
  Raises:
74
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
70
+ errors.UnexpectedStatus: If the server returns an undocumented status code
71
+ and Client.raise_on_unexpected_status is True.
75
72
  httpx.TimeoutException: If the request takes longer than Client.timeout.
76
73
 
77
74
  Returns:
@@ -111,7 +108,8 @@ def sync(
111
108
  json_body (ActionRequest):
112
109
 
113
110
  Raises:
114
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
111
+ errors.UnexpectedStatus: If the server returns an undocumented status code
112
+ and Client.raise_on_unexpected_status is True.
115
113
  httpx.TimeoutException: If the request takes longer than Client.timeout.
116
114
 
117
115
  Returns:
@@ -146,7 +144,8 @@ async def asyncio_detailed(
146
144
  json_body (ActionRequest):
147
145
 
148
146
  Raises:
149
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
147
+ errors.UnexpectedStatus: If the server returns an undocumented status code
148
+ and Client.raise_on_unexpected_status is True.
150
149
  httpx.TimeoutException: If the request takes longer than Client.timeout.
151
150
 
152
151
  Returns:
@@ -184,7 +183,8 @@ async def asyncio(
184
183
  json_body (ActionRequest):
185
184
 
186
185
  Raises:
187
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
186
+ errors.UnexpectedStatus: If the server returns an undocumented status code
187
+ and Client.raise_on_unexpected_status is True.
188
188
  httpx.TimeoutException: If the request takes longer than Client.timeout.
189
189
 
190
190
  Returns: