Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve xtrigger validation #60

Merged
merged 3 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
wall_clock: use placeholder function for signature validation & autodocs
  • Loading branch information
MetRonnie committed Feb 19, 2024
commit 82be8e34d29d54dec52d6ad1d25a437868733e7d
19 changes: 6 additions & 13 deletions cylc/flow/xtrigger_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from contextlib import suppress
from enum import Enum
from inspect import Parameter, Signature, signature
from inspect import signature
import json
import re
from copy import deepcopy
Expand All @@ -28,7 +28,7 @@
import cylc.flow.flags
from cylc.flow.hostuserutil import get_user
from cylc.flow.subprocpool import get_xtrig_func
from cylc.flow.xtriggers.wall_clock import wall_clock
from cylc.flow.xtriggers.wall_clock import _wall_clock

if TYPE_CHECKING:
from inspect import BoundArguments
Expand Down Expand Up @@ -287,18 +287,11 @@ def check_xtrigger(
)

# Validate args and kwargs against the function signature
sig = signature(func)
sig_str = fctx.get_signature()
if func is wall_clock:
# wall_clock is a special case where the Python function signature
# is different to the xtrigger signature
sig = Signature([
Parameter(
'offset', Parameter.POSITIONAL_OR_KEYWORD, default='P0Y'
)
])
try:
bound_args = sig.bind(*fctx.func_args, **fctx.func_kwargs)
bound_args = signature(func).bind(
*fctx.func_args, **fctx.func_kwargs
)
except TypeError as exc:
raise XtriggerConfigError(label, f"{sig_str}: {exc}")
# Specific xtrigger.validate(), if available.
Expand Down Expand Up @@ -484,7 +477,7 @@ def call_xtriggers_async(self, itask: 'TaskProxy'):
if sig in self.sat_xtrig:
# Already satisfied, just update the task
itask.state.xtriggers[label] = True
elif wall_clock(*ctx.func_args, **ctx.func_kwargs):
elif _wall_clock(*ctx.func_args, **ctx.func_kwargs):
# Newly satisfied
itask.state.xtriggers[label] = True
self.sat_xtrig[sig] = {}
Expand Down
24 changes: 22 additions & 2 deletions cylc/flow/xtriggers/wall_clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,28 @@
from cylc.flow.exceptions import WorkflowConfigError


def wall_clock(trigger_time: int) -> bool:
"""Return True after the desired wall clock time, False.
def wall_clock(offset: str = 'PT0S'):
"""Trigger at a specific real "wall clock" time relative to the cycle point
in the graph.

Clock triggers, unlike other trigger functions, are executed synchronously
in the main process.

Args:
offset:
ISO 8601 interval to wait after the cycle point is reached in real
time before triggering. May be negative, in which case it will
trigger before the real time reaches the cycle point.
"""
# NOTE: This is just a placeholder for the actual implementation.
# This is only used for validating the signature and for autodocs.
...


def _wall_clock(trigger_time: int) -> bool:
"""Actual implementation of wall_clock.

Return True after the desired wall clock time, or False before.

Args:
trigger_time:
Expand Down
16 changes: 14 additions & 2 deletions tests/unit/xtriggers/test_wall_clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from cylc.flow.exceptions import WorkflowConfigError
from cylc.flow.xtriggers.wall_clock import validate
from cylc.flow.xtriggers.wall_clock import _wall_clock, validate
from metomi.isodatetime.parsers import DurationParser
import pytest
from pytest import param


@pytest.mark.parametrize('trigger_time, expected', [
(499, True),
(500, False),
])
def test_wall_clock(
monkeypatch: pytest.MonkeyPatch, trigger_time: int, expected: bool
):
monkeypatch.setattr(
'cylc.flow.xtriggers.wall_clock.time', lambda: 500
)
assert _wall_clock(trigger_time) == expected


@pytest.fixture
def monkeypatch_interval_parser(monkeypatch):
"""Interval parse only works normally if a WorkflowSpecifics
Expand Down
Loading