Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions pyflow/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,10 @@ class TroikaHost(Host):
Parameters:
name(str): The name of the host.
user(str): The user to use for troika commands to the host.
troika_exec(str): The path to the troika executable, defaults to `%TROIKA:troika%`.
troika_config(str): The path to the troika configuration file, defaults to `%TROIKA_CONFIG%`.
Value False or None will deactivate the config in the command.
troika_version(str): The version of the troika executable, defaults to `0.2.3`.
hostname(str): The hostname of the host, otherwise `name` will be used.
scratch_directory(str): The path in which tasks will be run, unless otherwise specified.
log_directory(str): The directory to use for script output. Normally `ECF_HOME`, but may need to be changed on
Expand All @@ -1051,24 +1055,26 @@ class TroikaHost(Host):
pass
"""

def __init__(self, name, user, **kwargs):
self.troika_exec = kwargs.pop("troika_exec", "troika")
self.troika_config = kwargs.pop("troika_config", "")
self.troika_version = tuple(
map(int, kwargs.pop("troika_version", "0.2.1").split("."))
)
def __init__(
self,
name,
user,
troika_exec="%TROIKA:troika%",
troika_config="%TROIKA_CONFIG%",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the value of TROIKA_CONFIG set somewhere?

Copy link
Collaborator Author

@corentincarton corentincarton Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is set by default on all our ecflow servers. I agree it would break when users don't set this variable at the suite or server level but I can't find a good way of setting it. What I could also do is provide None as default and provide the %TROIKA_CONFIG% value in wellies instead, which is more ECMWF-centric. We could do the same with troika_exec and provide only troika as default.

troika_version="0.2.3",
**kwargs,
):
self.troika_exec = troika_exec
self.troika_config = troika_config
self.troika_version = tuple(map(int, troika_version.split(".")))
super().__init__(name, user=user, **kwargs)

def troika_command(self, command):
cmd = " ".join(
[
f"%TROIKA:{self.troika_exec}%",
f"{self.troika_exec}",
"-vv",
(
f"-c %TROIKA_CONFIG:{self.troika_config}%"
if self.troika_config
else ""
),
(f"-c {self.troika_config}" if self.troika_config else ""),
f"{command}",
f"-u {self.user}",
]
Expand Down
4 changes: 3 additions & 1 deletion tests/test_extern.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def test_extern():

with pytest.raises(AssertionError) as excinfo:
s.ecflow_definition()
assert excinfo.value.args == ("Attempting to add unknown extern reference",)
assert excinfo.value.args == (
"Attempting to add unknown extern reference /a/b/c/d",
)


def test_extern_attributes():
Expand Down
34 changes: 25 additions & 9 deletions tests/test_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,9 @@ def check_pragma(script, pragmas):

def test_troika_host():
host1 = pyflow.TroikaHost(
name="test_host",
user="test_user",
)
host2 = pyflow.TroikaHost(
name="test_host", user="test_user", troika_version="2.2.2"
name="test_host", user="test_user", troika_version="0.2.1"
)
host2 = pyflow.TroikaHost(name="test_host", user="test_user")

submit_args = {
"tasks": 2, # deprecated option, will be translated to total_tasks
Expand All @@ -284,11 +281,11 @@ def test_troika_host():

assert (
s.ECF_JOB_CMD.value
== "%TROIKA:troika% -vv submit -u test_user -o %ECF_JOBOUT% test_host %ECF_JOB%"
== "%TROIKA:troika% -vv -c %TROIKA_CONFIG% submit -u test_user -o %ECF_JOBOUT% test_host %ECF_JOB%"
)
assert (
s.ECF_KILL_CMD.value
== "%TROIKA:troika% -vv kill -u test_user test_host %ECF_JOB%"
== "%TROIKA:troika% -vv -c %TROIKA_CONFIG% kill -u test_user test_host %ECF_JOB%"
)

t1_script = t1.generate_script()
Expand Down Expand Up @@ -385,15 +382,34 @@ def test_troika_host_options():

assert (
s.ECF_JOB_CMD.value
== "%TROIKA:/path/to/troika% -vv -c %TROIKA_CONFIG:/path/to/troika.cfg% submit -u test_user -o %ECF_JOBOUT% test_host %ECF_JOB%" # noqa: E501
== "/path/to/troika -vv -c /path/to/troika.cfg submit -u test_user -o %ECF_JOBOUT% test_host %ECF_JOB%" # noqa: E501
)
assert (
s.ECF_KILL_CMD.value
== "%TROIKA:/path/to/troika% -vv -c %TROIKA_CONFIG:/path/to/troika.cfg% kill -u test_user test_host %ECF_JOB%" # noqa: E501
== "/path/to/troika -vv -c /path/to/troika.cfg kill -u test_user test_host %ECF_JOB%" # noqa: E501
)
assert s.host.troika_version == (2, 1, 3)


def test_troika_host_options_no_config():
host = pyflow.TroikaHost(
name="test_host",
user="test_user",
troika_config=None,
)

s = pyflow.Suite("s", host=host)

assert (
s.ECF_JOB_CMD.value
== "%TROIKA:troika% -vv submit -u test_user -o %ECF_JOBOUT% test_host %ECF_JOB%" # noqa: E501
)
assert (
s.ECF_KILL_CMD.value
== "%TROIKA:troika% -vv kill -u test_user test_host %ECF_JOB%" # noqa: E501
)


def test_traps():
sigs = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13]
with pyflow.Suite("s") as s1:
Expand Down
Loading