climate-ref-celery 0.6.3__py3-none-any.whl → 0.6.4__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.
- climate_ref_celery/cli.py +88 -26
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/METADATA +1 -1
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/RECORD +7 -7
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/WHEEL +0 -0
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/entry_points.txt +0 -0
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/licenses/LICENCE +0 -0
- {climate_ref_celery-0.6.3.dist-info → climate_ref_celery-0.6.4.dist-info}/licenses/NOTICE +0 -0
climate_ref_celery/cli.py
CHANGED
|
@@ -3,11 +3,15 @@ Managing remote celery workers
|
|
|
3
3
|
|
|
4
4
|
This module is used to manage remote execution workers for the Climate REF project.
|
|
5
5
|
It is added to the `ref` command line interface if the `climate-ref-celery` package is installed.
|
|
6
|
+
|
|
7
|
+
A celery worker should be run for each diagnostic provider.
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
|
-
import importlib
|
|
10
|
+
import importlib.metadata
|
|
11
|
+
from warnings import warn
|
|
9
12
|
|
|
10
13
|
import typer
|
|
14
|
+
from loguru import logger
|
|
11
15
|
|
|
12
16
|
from climate_ref_celery.app import create_celery_app
|
|
13
17
|
from climate_ref_celery.tasks import register_celery_tasks
|
|
@@ -16,14 +20,32 @@ from climate_ref_core.providers import DiagnosticProvider
|
|
|
16
20
|
app = typer.Typer(help=__doc__)
|
|
17
21
|
|
|
18
22
|
|
|
19
|
-
def import_provider(
|
|
23
|
+
def import_provider(provider_name: str) -> DiagnosticProvider:
|
|
20
24
|
"""
|
|
21
|
-
Import the provider
|
|
25
|
+
Import the provider using the name of a registered provider.
|
|
22
26
|
|
|
23
27
|
Parameters
|
|
24
28
|
----------
|
|
25
|
-
|
|
26
|
-
The
|
|
29
|
+
provider_name:
|
|
30
|
+
The name of a registered provider.
|
|
31
|
+
|
|
32
|
+
Packages can register a provider by defining an
|
|
33
|
+
[entry point](https://packaging.python.org/en/latest/specifications/entry-points/)
|
|
34
|
+
in its `pyproject.toml` file under the group `"climate-ref.providers"`.
|
|
35
|
+
|
|
36
|
+
Example: 'climate_ref_esmvaltool:provider' would require a section in the `pyproject.toml` for the
|
|
37
|
+
`climate_ref_esmvaltool` package like this:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
[project.entry-points."climate-ref.providers"]
|
|
41
|
+
esmvaltool = "climate_ref_esmvaltool:provider"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`"esmvaltool"` or ("climate_ref_esmvaltool:provider")
|
|
45
|
+
can then be used as the `provider_name` argument.
|
|
46
|
+
|
|
47
|
+
If the entry point is not found, an error will be raised
|
|
48
|
+
and the list of available providers will be shown.
|
|
27
49
|
|
|
28
50
|
Raises
|
|
29
51
|
------
|
|
@@ -37,18 +59,37 @@ def import_provider(provider_package: str) -> DiagnosticProvider:
|
|
|
37
59
|
:
|
|
38
60
|
The provider instance
|
|
39
61
|
"""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
provider_entry_points = importlib.metadata.entry_points(group="climate-ref.providers")
|
|
63
|
+
for entry_point in provider_entry_points:
|
|
64
|
+
logger.debug(f"found entry point: {entry_point}")
|
|
65
|
+
|
|
66
|
+
# Also support the case where the entrypoint definition ('name:provider') is supplied
|
|
67
|
+
if entry_point.name == provider_name or entry_point.value == provider_name: # noqa: PLR1714
|
|
68
|
+
break
|
|
69
|
+
else:
|
|
70
|
+
found_entry_points = ", ".join(f"{ep.name} ({ep.value})" for ep in provider_entry_points)
|
|
71
|
+
if len(found_entry_points) == 0:
|
|
72
|
+
found_entry_points = "[]"
|
|
73
|
+
|
|
74
|
+
typer.echo(
|
|
75
|
+
f"No entry point named {provider_name!r} was found. Found entry points: {found_entry_points}."
|
|
76
|
+
)
|
|
44
77
|
raise typer.Abort()
|
|
45
78
|
|
|
46
79
|
# Get the provider from the provider_package
|
|
47
80
|
try:
|
|
48
|
-
provider =
|
|
81
|
+
provider = entry_point.load()
|
|
82
|
+
except ModuleNotFoundError:
|
|
83
|
+
_split = entry_point.value.split(":", 1)
|
|
84
|
+
typer.echo(f"Invalid entrypoint {entry_point}: Package {_split[0]!r} not found.")
|
|
85
|
+
raise typer.Abort()
|
|
49
86
|
except AttributeError:
|
|
50
|
-
|
|
87
|
+
_split = entry_point.value.split(":", 1)
|
|
88
|
+
typer.echo(
|
|
89
|
+
f"Invalid entrypoint {entry_point}: {_split[0]!r} does not define a {_split[1]!r} attribute."
|
|
90
|
+
)
|
|
51
91
|
raise typer.Abort()
|
|
92
|
+
|
|
52
93
|
if not isinstance(provider, DiagnosticProvider):
|
|
53
94
|
typer.echo(f"Expected DiagnosticProvider, got {type(provider)}")
|
|
54
95
|
raise typer.Abort()
|
|
@@ -59,40 +100,61 @@ def import_provider(provider_package: str) -> DiagnosticProvider:
|
|
|
59
100
|
def start_worker(
|
|
60
101
|
ctx: typer.Context,
|
|
61
102
|
loglevel: str = typer.Option("info", help="Log level for the worker"),
|
|
62
|
-
|
|
103
|
+
provider: list[str] | None = typer.Option(
|
|
104
|
+
help="Name of the provider to start a worker for. This argument may be supplied multiple times. "
|
|
105
|
+
"If no provider is given, the worker will consume the default queue.",
|
|
106
|
+
default=None,
|
|
107
|
+
),
|
|
108
|
+
package: str | None = typer.Option(help="Deprecated. Use provider instead", default=None),
|
|
63
109
|
extra_args: list[str] = typer.Argument(None, help="Additional arguments for the worker"),
|
|
64
110
|
) -> None:
|
|
65
111
|
"""
|
|
66
|
-
Start a Celery worker for the given
|
|
112
|
+
Start a Celery worker for the given provider.
|
|
67
113
|
|
|
68
114
|
A celery worker enables the execution of tasks in the background on multiple different nodes.
|
|
69
115
|
This worker will register a celery task for each diagnostic in the provider.
|
|
70
116
|
The worker tasks can be executed by sending a celery task with the name
|
|
71
117
|
'{package_slug}_{diagnostic_slug}'.
|
|
72
118
|
|
|
73
|
-
|
|
119
|
+
Providers must be registered as entry points in the `pyproject.toml` file of the package.
|
|
120
|
+
The entry point should be defined under the group `climate-ref.providers`
|
|
121
|
+
(See `import_provider` for details).
|
|
74
122
|
"""
|
|
75
123
|
# Create a new celery app
|
|
76
124
|
celery_app = create_celery_app("climate_ref_celery")
|
|
77
125
|
|
|
78
126
|
if package:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
127
|
+
msg = "The '--package' argument is deprecated. Use '--provider' instead."
|
|
128
|
+
# Deprecation warning for package argument
|
|
129
|
+
warn(
|
|
130
|
+
msg,
|
|
131
|
+
DeprecationWarning,
|
|
132
|
+
stacklevel=2,
|
|
133
|
+
)
|
|
134
|
+
typer.echo(msg)
|
|
135
|
+
# Assume the package is the provider
|
|
136
|
+
provider = [package + ":provider"]
|
|
137
|
+
|
|
138
|
+
queues = []
|
|
139
|
+
if provider:
|
|
140
|
+
for p in provider:
|
|
141
|
+
# Attempt to import the provider
|
|
142
|
+
provider_instance = import_provider(p)
|
|
143
|
+
|
|
144
|
+
if hasattr(ctx.obj, "config"):
|
|
145
|
+
# Configure the provider so that it knows where the conda environments are
|
|
146
|
+
provider_instance.configure(ctx.obj.config)
|
|
147
|
+
|
|
148
|
+
# Wrap each diagnostics in the provider with a celery tasks
|
|
149
|
+
register_celery_tasks(celery_app, provider_instance)
|
|
150
|
+
queues.append(provider_instance.slug)
|
|
89
151
|
else:
|
|
90
152
|
# This might need some tweaking in later PRs to pull in the appropriate tasks
|
|
91
153
|
import climate_ref_celery.worker_tasks # noqa: F401
|
|
92
154
|
|
|
93
|
-
|
|
155
|
+
queues.append("celery")
|
|
94
156
|
|
|
95
|
-
argv = ["worker", "-E", f"--loglevel={loglevel}", f"--queues={
|
|
157
|
+
argv = ["worker", "-E", f"--loglevel={loglevel}", f"--queues={','.join(queues)}", *(extra_args or [])]
|
|
96
158
|
celery_app.worker_main(argv=argv)
|
|
97
159
|
|
|
98
160
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
climate_ref_celery/__init__.py,sha256=f-dS4JxMLmTCobZtftGDi6bUbtYCv_9iWqxSpC74tWw,129
|
|
2
2
|
climate_ref_celery/app.py,sha256=KtDX8-6cye9RzJL5rXbJH1Us_pGYONawYAkOnxTcBmI,1527
|
|
3
|
-
climate_ref_celery/cli.py,sha256=
|
|
3
|
+
climate_ref_celery/cli.py,sha256=7cQjB836xIuQ8flwnh8_gJmoVJUcHhqwcaH5d1N9Yg4,6022
|
|
4
4
|
climate_ref_celery/executor.py,sha256=Qsx1bvM_-H3eMeg5VsJAV6ghHuGK3WnYyIRAd0-1DG4,4764
|
|
5
5
|
climate_ref_celery/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
climate_ref_celery/tasks.py,sha256=6Ra2H48edbcklsf6pAj1JNfzi67n6WQCUXJs-tloE80,1941
|
|
@@ -9,9 +9,9 @@ climate_ref_celery/celeryconf/__init__.py,sha256=xKcHhnECGZAxrjnMtfaPBU_vgqwRbRL
|
|
|
9
9
|
climate_ref_celery/celeryconf/base.py,sha256=uXaz9S_1hCdwKpvyWBDWE69YVIXHD3Ar7egNKLk9Gx8,484
|
|
10
10
|
climate_ref_celery/celeryconf/dev.py,sha256=um7hvEhlTBfwey9ler_vAHAln_DrpqAP3fbbO2wdmUQ,217
|
|
11
11
|
climate_ref_celery/celeryconf/prod.py,sha256=HyGTfwTZD8MjIkfkb3qyfzjjTPE9sKAoXNq3fJDFO9Q,231
|
|
12
|
-
climate_ref_celery-0.6.
|
|
13
|
-
climate_ref_celery-0.6.
|
|
14
|
-
climate_ref_celery-0.6.
|
|
15
|
-
climate_ref_celery-0.6.
|
|
16
|
-
climate_ref_celery-0.6.
|
|
17
|
-
climate_ref_celery-0.6.
|
|
12
|
+
climate_ref_celery-0.6.4.dist-info/METADATA,sha256=k-EzKWFU77223JpuGYjHWRjpR6hJTGBBmyYB38eBjzs,3693
|
|
13
|
+
climate_ref_celery-0.6.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
climate_ref_celery-0.6.4.dist-info/entry_points.txt,sha256=U9b-T6EpLV3ZXmHUpEzp8x5TZnCjQ1ynncIkFMwDuPE,58
|
|
15
|
+
climate_ref_celery-0.6.4.dist-info/licenses/LICENCE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
16
|
+
climate_ref_celery-0.6.4.dist-info/licenses/NOTICE,sha256=4qTlax9aX2-mswYJuVrLqJ9jK1IkN5kSBqfVvYLF3Ws,128
|
|
17
|
+
climate_ref_celery-0.6.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|