common-python-tasks 0.12.1__py3-none-any.whl → 0.13.1__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.
- common_python_tasks/_task_registry.py +163 -0
- common_python_tasks/container_tasks.py +609 -0
- common_python_tasks/dependency_tasks.py +180 -0
- common_python_tasks/development_tasks.py +211 -0
- common_python_tasks/docker.py +12 -12
- common_python_tasks/env.py +19 -16
- common_python_tasks/git.py +47 -30
- common_python_tasks/github.py +4 -2
- common_python_tasks/packaging_tasks.py +161 -0
- common_python_tasks/project.py +0 -2
- common_python_tasks/release_tasks.py +433 -0
- common_python_tasks/tasks.py +87 -1976
- common_python_tasks/utils.py +27 -15
- {common_python_tasks-0.12.1.dist-info → common_python_tasks-0.13.1.dist-info}/METADATA +7 -8
- common_python_tasks-0.13.1.dist-info/RECORD +29 -0
- {common_python_tasks-0.12.1.dist-info → common_python_tasks-0.13.1.dist-info}/WHEEL +1 -1
- common_python_tasks/data/fastapi/alembic.ini.j2 +0 -51
- common_python_tasks/data/fastapi/compose-base.yml.j2 +0 -40
- common_python_tasks/data/fastapi/compose-db-debug.yml.j2 +0 -45
- common_python_tasks/data/fastapi/compose-db.yml.j2 +0 -80
- common_python_tasks/data/fastapi/compose-debug.yml.j2 +0 -30
- common_python_tasks/docker_compose.py +0 -643
- common_python_tasks-0.12.1.dist-info/RECORD +0 -29
- {common_python_tasks-0.12.1.dist-info → common_python_tasks-0.13.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import contextvars
|
|
2
|
+
import inspect
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import shlex
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from functools import partial, wraps
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import ClassVar
|
|
10
|
+
|
|
11
|
+
from poethepoet_tasks import TaskCollection
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _ColoredFormatter(logging.Formatter):
|
|
15
|
+
COLORS: ClassVar = {
|
|
16
|
+
"WARNING": "\033[93m",
|
|
17
|
+
"ERROR": "\033[91m",
|
|
18
|
+
"CRITICAL": "\033[91m",
|
|
19
|
+
"RESET": "\033[0m",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
23
|
+
log_color = self.COLORS.get(record.levelname, "")
|
|
24
|
+
record.levelname = f"\033[1m{log_color}{record.levelname}{self.COLORS['RESET'] if log_color else ''}\033[0m"
|
|
25
|
+
return super().format(record)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
LOGGER = logging.getLogger("common_python_tasks")
|
|
29
|
+
handler = logging.StreamHandler()
|
|
30
|
+
handler.setFormatter(_ColoredFormatter("[%(asctime)s] %(levelname)s: %(message)s"))
|
|
31
|
+
LOGGER.addHandler(handler)
|
|
32
|
+
LOGGER.setLevel(
|
|
33
|
+
{
|
|
34
|
+
"DEBUG": logging.DEBUG,
|
|
35
|
+
"INFO": logging.INFO,
|
|
36
|
+
"WARNING": logging.WARNING,
|
|
37
|
+
"ERROR": logging.ERROR,
|
|
38
|
+
"CRITICAL": logging.CRITICAL,
|
|
39
|
+
}[os.getenv("COMMON_PYTHON_TASKS_LOG_LEVEL", "INFO").upper()]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
tasks = TaskCollection(
|
|
44
|
+
envfile=[
|
|
45
|
+
f
|
|
46
|
+
for f in [
|
|
47
|
+
".env.defaults",
|
|
48
|
+
"project.properties",
|
|
49
|
+
".env",
|
|
50
|
+
]
|
|
51
|
+
if Path(f).exists()
|
|
52
|
+
]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
_task_call_depth: contextvars.ContextVar[int] = contextvars.ContextVar(
|
|
56
|
+
"common_python_tasks_task_call_depth", default=0
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
_original_script = tasks.script
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _make_var_positional_task_args_optional(
|
|
63
|
+
func: callable, resolved_task_name: str
|
|
64
|
+
) -> None:
|
|
65
|
+
var_positional_arg_names = {
|
|
66
|
+
param.name
|
|
67
|
+
for param in inspect.signature(func).parameters.values()
|
|
68
|
+
if param.kind == inspect.Parameter.VAR_POSITIONAL
|
|
69
|
+
}
|
|
70
|
+
if not var_positional_arg_names:
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
for task_config in tasks._tasks.get(resolved_task_name, []):
|
|
74
|
+
for arg_config in task_config.options.get("args", []):
|
|
75
|
+
if arg_config.get("name") in var_positional_arg_names:
|
|
76
|
+
arg_config["required"] = False
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _wrap_task_function(func: callable, task_name: str | None) -> callable:
|
|
80
|
+
resolved_task_name = task_name or func.__name__.replace("_", "-").lower()
|
|
81
|
+
var_positional_arg_names = [
|
|
82
|
+
param.name
|
|
83
|
+
for param in inspect.signature(func).parameters.values()
|
|
84
|
+
if param.kind == inspect.Parameter.VAR_POSITIONAL
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
@wraps(func)
|
|
88
|
+
def wrapped(*args, **kwargs):
|
|
89
|
+
for arg_name in var_positional_arg_names:
|
|
90
|
+
if arg_name not in kwargs:
|
|
91
|
+
continue
|
|
92
|
+
values = kwargs.pop(arg_name)
|
|
93
|
+
if values is None:
|
|
94
|
+
continue
|
|
95
|
+
if isinstance(values, list | tuple):
|
|
96
|
+
args = (*args, *values)
|
|
97
|
+
else:
|
|
98
|
+
args = (*args, values)
|
|
99
|
+
|
|
100
|
+
if var_positional_arg_names and (
|
|
101
|
+
poe_extra_args := os.environ.pop("POE_EXTRA_ARGS", None)
|
|
102
|
+
):
|
|
103
|
+
args = (*args, *shlex.split(poe_extra_args))
|
|
104
|
+
|
|
105
|
+
current_depth = _task_call_depth.get()
|
|
106
|
+
if current_depth > 0:
|
|
107
|
+
LOGGER.log(
|
|
108
|
+
(
|
|
109
|
+
logging.INFO
|
|
110
|
+
if not resolved_task_name.startswith("_")
|
|
111
|
+
else logging.DEBUG
|
|
112
|
+
),
|
|
113
|
+
"Running task %s",
|
|
114
|
+
resolved_task_name,
|
|
115
|
+
)
|
|
116
|
+
token = _task_call_depth.set(current_depth + 1)
|
|
117
|
+
try:
|
|
118
|
+
return func(*args, **kwargs)
|
|
119
|
+
finally:
|
|
120
|
+
_task_call_depth.reset(token)
|
|
121
|
+
|
|
122
|
+
return wrapped
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _script(
|
|
126
|
+
func: Callable | None = None,
|
|
127
|
+
task_name: str | None = None,
|
|
128
|
+
help: str | None = None,
|
|
129
|
+
task_args: bool = True,
|
|
130
|
+
options: dict | None = None,
|
|
131
|
+
tags: tuple[str, ...] | None = None,
|
|
132
|
+
):
|
|
133
|
+
|
|
134
|
+
if tags is None:
|
|
135
|
+
tags = ()
|
|
136
|
+
|
|
137
|
+
if func is None:
|
|
138
|
+
return partial(
|
|
139
|
+
_script,
|
|
140
|
+
task_name=task_name,
|
|
141
|
+
help=help,
|
|
142
|
+
task_args=task_args,
|
|
143
|
+
options=options,
|
|
144
|
+
tags=tags,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
resolved_task_name = task_name or func.__name__.replace("_", "-").lower()
|
|
148
|
+
wrapped = _wrap_task_function(func, resolved_task_name)
|
|
149
|
+
decorated = _original_script(
|
|
150
|
+
wrapped,
|
|
151
|
+
task_name=resolved_task_name,
|
|
152
|
+
help=help,
|
|
153
|
+
task_args=task_args,
|
|
154
|
+
options=options,
|
|
155
|
+
tags=tags,
|
|
156
|
+
)
|
|
157
|
+
_make_var_positional_task_args_optional(wrapped, resolved_task_name)
|
|
158
|
+
return decorated
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
tasks.script = _script
|
|
162
|
+
|
|
163
|
+
NO_PROMPT_ENV_VAR = "COMMON_PYTHON_TASKS_NO_PROMPT"
|