Skip to content

Commit ca4a4b3

Browse files
committed
fix baseCommand for docker runtime
1 parent 6603311 commit ca4a4b3

File tree

5 files changed

+148
-79
lines changed

5 files changed

+148
-79
lines changed

src/goldfinch/processes/indicator/hdd.cwl

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,45 @@ $namespaces:
22
s: https://schema.org/
33
$schemas:
44
- http://schema.org/version/9.0/schemaorg-current-http.rdf
5-
baseCommand: python /home/francis/dev/goldfinch/src/goldfinch/processes/indicator/hdd.py
5+
baseCommand: python -m goldfinch.processes.indicator.hdd
66
class: CommandLineTool
77
cwlVersion: v1.2
88
hints:
99
DockerRequirement:
1010
dockerPull: ghcr.io/bird-house/goldfinch:0.1.0
1111
id: hdd
1212
inputs:
13+
chunks:
14+
inputBinding:
15+
position: 8
16+
prefix: --chunks
17+
type: string?
18+
dask_maxmem:
19+
inputBinding:
20+
position: 7
21+
prefix: --dask-maxmem
22+
type: string?
23+
dask_nthreads:
24+
inputBinding:
25+
position: 6
26+
prefix: --dask-nthreads
27+
type: None?
28+
engine:
29+
inputBinding:
30+
position: 9
31+
prefix: --engine
32+
type: string?
33+
help:
34+
inputBinding:
35+
position: 2
36+
prefix: -h
37+
type: boolean?
1338
indicator:
1439
inputBinding:
1540
position: 1
1641
prefix: --indicator
1742
type:
18-
- symbols: !!python/tuple
43+
- symbols:
1944
- HUMIDEX
2045
- HEAT_INDEX
2146
- TG
@@ -353,11 +378,6 @@ inputs:
353378
- cf.TXX
354379
- cf.VDTR
355380
type: enum
356-
help:
357-
inputBinding:
358-
position: 2
359-
prefix: -h
360-
type: boolean?
361381
input:
362382
type:
363383
- 'null'
@@ -376,26 +396,6 @@ inputs:
376396
position: 5
377397
prefix: -v
378398
type: None?
379-
dask_nthreads:
380-
inputBinding:
381-
position: 6
382-
prefix: --dask-nthreads
383-
type: None?
384-
dask_maxmem:
385-
inputBinding:
386-
position: 7
387-
prefix: --dask-maxmem
388-
type: string?
389-
chunks:
390-
inputBinding:
391-
position: 8
392-
prefix: --chunks
393-
type: string?
394-
engine:
395-
inputBinding:
396-
position: 9
397-
prefix: --engine
398-
type: string?
399399
outputs:
400400
results:
401401
outputBinding:

src/goldfinch/processes/indicator/hdd.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import click
22
import warnings
3-
import xclim.cli
43
import xclim.core.indicator
54

65
"""
@@ -21,31 +20,10 @@
2120
The CLI's output is a user input. We'll probably want to change this to a default output path.
2221
"""
2322

24-
# WARNING: this does not work,
25-
# the click2cwl tool cannot be aware of subcommands, since they are not instantiated until invocation runtime
26-
# however, the tool purposely avoids command invocation to avoid triggering the operations
27-
class Cli(click.Group):
28-
"""Main cli class."""
29-
30-
def list_commands(self, ctx):
31-
"""Return the available commands (other than the indicators)."""
32-
return (
33-
"heating_degree_days",
34-
)
35-
36-
def get_command(self, ctx, cmd_name):
37-
"""Return the requested command."""
38-
if cmd_name in self.list_commands(ctx):
39-
command = xclim.cli._create_command(cmd_name)
40-
return command
41-
4223

4324
@click.command(
44-
#cls=Cli,
45-
#chain=True,
4625
help="Command line tool to compute indices on netCDF datasets. Indicators are referred to by their "
4726
"(case-insensitive) identifier, as in xclim.core.indicator.registry.",
48-
#invoke_without_command=True,
4927
)
5028
@click.option( # WARNING: click.argument(help='...') is not supported, but click2cwl requires an 'help'
5129
"--indicator",
@@ -102,7 +80,7 @@ def cli(ctx, **kwargs):
10280
kwargs["input"] = kwargs["input"][0]
10381

10482
if kwargs["dask_nthreads"] is not None:
105-
if not distributed:
83+
if not distributed: # FIXME: undefined
10684
raise click.BadOptionUsage(
10785
"dask_nthreads",
10886
"Dask's distributed scheduler is not installed, only the "
@@ -116,7 +94,7 @@ def cli(ctx, **kwargs):
11694
ctx,
11795
)
11896

119-
client = Client(
97+
client = Client( # FIXME: undefined
12098
n_workers=1,
12199
threads_per_worker=kwargs["dask_nthreads"],
122100
memory_limit=kwargs["dask_maxmem"],
@@ -136,8 +114,6 @@ def cli(ctx, **kwargs):
136114
}
137115
ctx.obj = kwargs
138116

139-
#cli.result_callback()(click.pass_context(xclim.cli.write_file))
140-
141117

142118
if __name__ == "__main__":
143119
cli() # pylint: disable=no-value-for-parameter

src/goldfinch/processes/subset/poly_subset.cwl

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,29 @@ $namespaces:
22
s: https://schema.org/
33
$schemas:
44
- http://schema.org/version/9.0/schemaorg-current-http.rdf
5-
baseCommand: python /home/francis/dev/goldfinch/src/goldfinch/processes/subset/poly_subset.py
5+
baseCommand: python -m goldfinch.processes.subset.poly_subset
66
class: CommandLineTool
77
cwlVersion: v1.2
88
hints:
99
DockerRequirement:
1010
dockerPull: ghcr.io/bird-house/goldfinch:0.1.0
1111
id: poly_subset
1212
inputs:
13+
buffer:
14+
inputBinding:
15+
position: 5
16+
prefix: -b
17+
type: None?
18+
end:
19+
inputBinding:
20+
position: 7
21+
prefix: -e
22+
type: string?
23+
first_level:
24+
inputBinding:
25+
position: 8
26+
prefix: -f
27+
type: string?
1328
help:
1429
inputBinding:
1530
position: 1
@@ -20,41 +35,26 @@ inputs:
2035
position: 2
2136
prefix: -i
2237
type: string?
38+
last_level:
39+
inputBinding:
40+
position: 9
41+
prefix: -l
42+
type: string?
2343
output:
2444
inputBinding:
2545
position: 3
2646
prefix: -o
27-
type: Directory?
47+
type: File?
2848
poly:
2949
inputBinding:
3050
position: 4
3151
prefix: -p
32-
type: Directory?
33-
buffer:
34-
inputBinding:
35-
position: 5
36-
prefix: -b
37-
type: None?
52+
type: File?
3853
start:
3954
inputBinding:
4055
position: 6
4156
prefix: -s
4257
type: string?
43-
end:
44-
inputBinding:
45-
position: 7
46-
prefix: -e
47-
type: string?
48-
first_level:
49-
inputBinding:
50-
position: 8
51-
prefix: -f
52-
type: string?
53-
last_level:
54-
inputBinding:
55-
position: 9
56-
prefix: -l
57-
type: string?
5858
verbose:
5959
inputBinding:
6060
position: 10

src/goldfinch/utils/click2cwl_cli.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,40 @@ def yaml_dump(data: dict[str, Any], *args: Any, **kwargs: Any) -> str:
6767
"""
6868
Custom YAML dump function to ensure consistent formatting.
6969
"""
70-
represent_dict_order = lambda self, _data: self.represent_mapping("tag:yaml.org,2002:map", _data.items())
70+
represent_dict_order = lambda self, _data: self.represent_mapping("tag:yaml.org,2002:map", dict(_data))
7171
yaml.add_representer(OrderedDict, represent_dict_order)
7272
return yaml.dump(data, *args, **kwargs)
7373

7474

75+
def resolve_cli_command(
76+
process: str | None = None,
77+
docker: str | None = None,
78+
docker_module: str | None = None,
79+
**_,
80+
) -> str:
81+
"""
82+
Resolve the command line interface program call.
83+
84+
If running inside docker, patch the command with **installed** module or the overridden script/module reference.
85+
Otherwise, employ the absolute path of the python script directly for local execution (not within docker).
86+
"""
87+
if not docker:
88+
return f"python {process}"
89+
90+
if docker_module and os.path.sep in str(docker_module):
91+
return f"python {process}"
92+
93+
# allow directly invoking other modules if they are installed, or resolve current package
94+
parent_mod_name = "goldfinch"
95+
parent_module = f"{parent_mod_name}{os.path.sep}"
96+
docker_module = docker_module or process
97+
if f"{os.path.sep}{parent_module}" in docker_module or docker_module.startswith(parent_module):
98+
docker_module = docker_module.rstrip(".py").rsplit(parent_module, 1)[-1].replace(os.path.sep, ".")
99+
docker_module = f"{parent_mod_name}.{docker_module}"
100+
101+
return f"python -m {docker_module}"
102+
103+
75104
@click.command(
76105
"click2cwl",
77106
context_settings={"allow_extra_args": True}, # pass down job parameters to context
@@ -184,7 +213,7 @@ def main(ctx: click.Context, **kwargs: str) -> None:
184213
"""
185214
# resolve the module containing the Click command
186215
cli_file = kwargs["process"]
187-
cli_path = os.path.abspath(cli_file)
216+
cli_path = kwargs["process"] = os.path.abspath(cli_file)
188217
cli_spec = importlib.util.spec_from_file_location("click2cwl.program", cli_path)
189218
sys.modules["click2cwl.program"] = cli_spec # type: ignore
190219
cli_mod = importlib.util.module_from_spec(cli_spec)
@@ -204,7 +233,7 @@ def main(ctx: click.Context, **kwargs: str) -> None:
204233
f"Use the --command option to specify a specific one to convert or make sure the module defines one."
205234
)
206235
cli_name, cli_cmd = click_functions[0]
207-
cli_prog_call = f"python {cli_file}"
236+
cli_prog_call = resolve_cli_command(**kwargs)
208237

209238
# add context arguments to generate the CWL contents
210239
cli_ctx = cli_cmd.context_class(info_name=cli_prog_call, command=cli_cmd)

tests/utils/test_click2clw_cli.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import pytest
5+
6+
from goldfinch.utils.click2cwl_cli import resolve_cli_command
7+
8+
9+
@pytest.mark.parametrize(
10+
["expected_command", "process", "docker", "docker_module"],
11+
[
12+
(
13+
"python -m xclim.cli",
14+
"xclim.cli",
15+
"bird-house/goldfinch:latest",
16+
None,
17+
),
18+
(
19+
"python -m goldfinch.processes.subset.poly_subset",
20+
"goldfinch.processes.subset.poly_subset",
21+
"bird-house/goldfinch:latest",
22+
None,
23+
),
24+
(
25+
"python -m goldfinch.processes.subset.poly_subset",
26+
"goldfinch/processes/subset/poly_subset.py",
27+
"bird-house/goldfinch:latest",
28+
None,
29+
),
30+
(
31+
"python -m goldfinch.processes.subset.poly_subset",
32+
"src/goldfinch/processes/subset/poly_subset.py",
33+
"bird-house/goldfinch:latest",
34+
None,
35+
),
36+
(
37+
"python -m goldfinch.processes.subset.poly_subset",
38+
"/home/user/goldfinch/processes/subset/poly_subset.py",
39+
"bird-house/goldfinch:latest",
40+
None,
41+
),
42+
(
43+
"python -m goldfinch.processes.subset.poly_subset",
44+
"poly_subset.py",
45+
"bird-house/goldfinch:latest",
46+
"goldfinch.processes.subset.poly_subset",
47+
),
48+
(
49+
"python -m xclim.cli",
50+
"goldfinch.processes.indicator.hdd",
51+
"bird-house/goldfinch:latest",
52+
"xclim.cli",
53+
),
54+
(
55+
"python /home/user/goldfinch/processes/subset/poly_subset.py",
56+
"/home/user/goldfinch/processes/subset/poly_subset.py",
57+
None,
58+
None,
59+
),
60+
]
61+
)
62+
def test_resolve_cli_command(expected_command, process, docker, docker_module):
63+
result = resolve_cli_command(process, docker, docker_module)
64+
assert result == expected_command

0 commit comments

Comments
 (0)