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

Update isodatetime to 3.2 #5928

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions changes.d/5928.break.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed behaviour of `initial cycle point = next(...)` which could result in a time in the past, and equivalently for `previous()`. E.g. if the current time is `2024-01-01T12:30Z`, `next(--01-01)` now evaluates to `2025-01-01T00:00Z` instead of `2024-01-01T00:00Z`.
2 changes: 1 addition & 1 deletion conda-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies:
- graphviz # for static graphing
# Note: can't pin jinja2 any higher than this until we give up on Cylc 7 back-compat
- jinja2 >=3.0,<3.1
- metomi-isodatetime >=1!3.0.0, <1!3.2.0
- metomi-isodatetime >=1!3.2.0, <1!3.3.0
- packaging
# Constrain protobuf version for compatible Scheduler-UIS comms across hosts
- protobuf >=4.24.4,<4.25.0
Expand Down
14 changes: 7 additions & 7 deletions cylc/flow/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,33 @@
from contextlib import suppress
from time import sleep, time
from typing import (
TYPE_CHECKING,
AsyncGenerator,
Callable,
Dict,
Iterable,
List,
Optional,
TYPE_CHECKING,
Union,
)

from cylc.flow import LOG
from metomi.isodatetime.parsers import TimePointParser

import cylc.flow.command_validation as validate
import cylc.flow.flags
from cylc.flow import LOG
from cylc.flow.exceptions import (
CommandFailedError,
CyclingError,
CylcConfigError,
)
import cylc.flow.flags
from cylc.flow.log_level import log_level_to_verbosity
from cylc.flow.network.schema import WorkflowStopMode
from cylc.flow.parsec.exceptions import ParsecError
from cylc.flow.task_id import TaskID
from cylc.flow.task_state import TASK_STATUSES_ACTIVE, TASK_STATUS_FAILED
from cylc.flow.task_state import TASK_STATUS_FAILED, TASK_STATUSES_ACTIVE
from cylc.flow.workflow_status import RunMode, StopMode

from metomi.isodatetime.parsers import TimePointParser

if TYPE_CHECKING:
from cylc.flow.scheduler import Scheduler

Expand Down Expand Up @@ -194,7 +194,7 @@ async def stop(
# schedule shutdown after wallclock time passes provided time
parser = TimePointParser()
schd.set_stop_clock(
int(parser.parse(clock_time).seconds_since_unix_epoch)
parser.parse(clock_time).seconds_since_unix_epoch
)
schd._update_workflow_state()
elif task is not None:
Expand Down
32 changes: 1 addition & 31 deletions cylc/flow/cycling/iso8601.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import re
from typing import List, Optional, TYPE_CHECKING, Tuple

from metomi.isodatetime.data import Calendar, CALENDAR, Duration
from metomi.isodatetime.data import Calendar, CALENDAR
from metomi.isodatetime.dumpers import TimePointDumper
from metomi.isodatetime.timezone import (
get_local_time_zone, get_local_time_zone_format, TimeZoneFormatMode)
Expand Down Expand Up @@ -699,14 +699,6 @@ def ingest_time(value: str, now: Optional[str] = None) -> str:
now = get_current_time_string()
now_point = parser.parse(now)

# correct for year in 'now' if year is the only date unit specified -
# https://github.com/cylc/cylc-flow/issues/4805#issuecomment-1103928604
if re.search(r"\(-\d{2}[);T]", value):
now_point += Duration(years=1)
# likewise correct for month if year and month are the only date units
elif re.search(r"\(-\d{4}[);T]", value):
now_point += Duration(months=1)

# perform whatever transformation is required
offset = None
if is_prev_next:
Expand Down Expand Up @@ -799,28 +791,6 @@ def prev_next(

cycle_point = timepoints[my_diff.index(min(my_diff))]

# ensure truncated dates do not have time from 'now' included' -
# https://github.com/metomi/isodatetime/issues/212
if 'T' not in value.split(')')[0]:
# NOTE: Strictly speaking we shouldn't forcefully mutate TimePoints
# in this way as they're meant to be immutable since
# https://github.com/metomi/isodatetime/pull/165, however it
# should be ok as long as the TimePoint is not used as a dict key and
# we don't call any of the TimePoint's cached methods until after we've
# finished mutating it.
cycle_point._hour_of_day = 0
cycle_point._minute_of_hour = 0
cycle_point._second_of_minute = 0
# likewise ensure month and day from 'now' are not included
# where they did not appear in the truncated datetime
if re.search(r"\(-\d{2}[);T]", value):
# case 1 - year only
cycle_point._month_of_year = 1
cycle_point._day_of_month = 1
elif re.search(r"\(-(-\d{2}|\d{4})[;T)]", value):
# case 2 - month only or year and month
cycle_point._day_of_month = 1

return cycle_point, offset


Expand Down
60 changes: 34 additions & 26 deletions cylc/flow/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,24 @@
"""Cylc scheduler server."""

import asyncio
import os
import sys
import traceback
from collections import deque
from contextlib import suppress
import os
from pathlib import Path
from queue import Empty, Queue
from shlex import quote
from socket import gaierror
from subprocess import DEVNULL, PIPE, Popen
import sys
from subprocess import (
DEVNULL,
PIPE,
Popen,
)
from threading import Barrier, Thread
from time import sleep, time
import traceback
from typing import (
TYPE_CHECKING,
Any,
AsyncGenerator,
Callable,
Expand All @@ -38,36 +43,36 @@
NoReturn,
Optional,
Set,
TYPE_CHECKING,
Tuple,
Union,
)
from uuid import uuid4

import psutil

import cylc.flow.flags
from cylc.flow import LOG
from cylc.flow import __version__ as CYLC_VERSION
from cylc.flow import (
LOG,
__version__ as CYLC_VERSION,
commands,
main_loop,
workflow_files,
)
from cylc.flow import workflow_files
from cylc.flow.broadcast_mgr import BroadcastMgr
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.config import WorkflowConfig
from cylc.flow import commands
from cylc.flow.data_store_mgr import DataStoreMgr
from cylc.flow.exceptions import (
CommandFailedError,
CylcError,
InputError,
)
import cylc.flow.flags
from cylc.flow.flow_mgr import FLOW_NEW, FLOW_NONE, FlowMgr
from cylc.flow.host_select import (
HostSelectException,
select_workflow_host,
from cylc.flow.flow_mgr import (
FLOW_NEW,
FLOW_NONE,
FlowMgr,
)
from cylc.flow.host_select import HostSelectException, select_workflow_host
from cylc.flow.hostuserutil import (
get_host,
get_user,
Expand All @@ -86,8 +91,8 @@
from cylc.flow.network import API
from cylc.flow.network.authentication import key_housekeeping
from cylc.flow.network.server import WorkflowRuntimeServer
from cylc.flow.parsec.OrderedDict import DictTree
from cylc.flow.parsec.exceptions import ParsecError
from cylc.flow.parsec.OrderedDict import DictTree
from cylc.flow.parsec.validate import DurationFloat
from cylc.flow.pathutil import (
get_workflow_name_from_id,
Expand Down Expand Up @@ -121,34 +126,37 @@
REMOTE_INIT_FAILED,
)
from cylc.flow.task_state import (
TASK_STATUSES_ACTIVE,
TASK_STATUSES_NEVER_ACTIVE,
TASK_STATUS_PREPARING,
TASK_STATUS_RUNNING,
TASK_STATUS_SUBMITTED,
TASK_STATUS_WAITING,
TASK_STATUSES_ACTIVE,
TASK_STATUSES_NEVER_ACTIVE,
)
from cylc.flow.taskdef import TaskDef
from cylc.flow.templatevars import eval_var
from cylc.flow.templatevars import get_template_vars
from cylc.flow.templatevars import eval_var, get_template_vars
from cylc.flow.timer import Timer
from cylc.flow.util import cli_format
from cylc.flow.wallclock import (
get_current_time_string,
get_time_string_from_unix_time as time2str,
get_utc_mode,
)
from cylc.flow.wallclock import get_current_time_string
from cylc.flow.wallclock import get_time_string_from_unix_time as time2str
from cylc.flow.wallclock import get_utc_mode
from cylc.flow.workflow_db_mgr import WorkflowDatabaseManager
from cylc.flow.workflow_events import WorkflowEventHandler
from cylc.flow.workflow_status import AutoRestartMode, RunMode, StopMode
from cylc.flow.workflow_status import (
AutoRestartMode,
RunMode,
StopMode,
)
from cylc.flow.xtrigger_mgr import XtriggerManager

if TYPE_CHECKING:
# BACK COMPAT: typing_extensions.Literal
# FROM: Python 3.7
# TO: Python 3.8
from typing_extensions import Literal
from optparse import Values

from typing_extensions import Literal

from cylc.flow.network.resolvers import TaskMsg


Expand Down
5 changes: 2 additions & 3 deletions cylc/flow/task_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def get_point_as_seconds(self):
"""Compute and store my cycle point as seconds since epoch."""
if self.point_as_seconds is None:
iso_timepoint = point_parse(str(self.point))
self.point_as_seconds = int(iso_timepoint.seconds_since_unix_epoch)
self.point_as_seconds = iso_timepoint.seconds_since_unix_epoch
if iso_timepoint.time_zone.unknown:
utc_offset_hours, utc_offset_minutes = (
get_local_time_zone())
Expand Down Expand Up @@ -429,8 +429,7 @@ def get_clock_trigger_time(
else:
trigger_time = point + ISO8601Interval(offset_str)

offset = int(
point_parse(str(trigger_time)).seconds_since_unix_epoch)
offset = point_parse(str(trigger_time)).seconds_since_unix_epoch
self.clock_trigger_times[offset_str] = offset
return self.clock_trigger_times[offset_str]

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ install_requires =
graphene>=2.1,<3
# Note: can't pin jinja2 any higher than this until we give up on Cylc 7 back-compat
jinja2==3.0.*
metomi-isodatetime>=1!3.0.0,<1!3.2.0
metomi-isodatetime>=1!3.2.0,<1!3.3.0
# Constrain protobuf version for compatible Scheduler-UIS comms across hosts
packaging
protobuf>=4.24.4,<4.25.0
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/cycling/test_iso8601.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ def test_simple(set_cycling_type):
('next(--0325)', '20110325T0000Z'),
('next(---10)', '20100810T0000Z'),
('next(---05T1200Z)', '20100905T1200Z'),
param('next(--08-08)', '20110808T0000Z', marks=pytest.mark.xfail),
('next(--08-08)', '20110808T0000Z'),
('next(T15)', '20100809T1500Z'),
('next(T-41)', '20100808T1541Z'),
]
Expand All @@ -709,7 +709,7 @@ def test_next_simple(value: str, expected: str, set_cycling_type):
('previous(--0325)', '20100325T0000Z'),
('previous(---10)', '20100710T0000Z'),
('previous(---05T1200Z)', '20100805T1200Z'),
param('previous(--08-08)', '20100808T0000Z', marks=pytest.mark.xfail),
('previous(--08-08)', '20100808T0000Z'),
('previous(T15)', '20100808T1500Z'),
('previous(T-41)', '20100808T1441Z'),
]
Expand Down Expand Up @@ -856,7 +856,7 @@ def test_weeks_days(set_cycling_type):
('previous(--1225)', '20171225T0000Z'),
('next(-2006)', '20200601T0000Z'),
('previous(-W101)', '20180305T0000Z'),
('next(-W-1; -W-3; -W-5)', '20180314T0000Z'),
('next(-W-1; -W-3; -W-5)', '20180316T0000Z'),
('next(-001; -091; -181; -271)', '20180401T0000Z'),
('previous(-365T12Z)', '20171231T1200Z'),
]
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_workflow_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def schd(
WORKFLOW_STATUS_RUNNING_TO_STOP % 4
),
(
{'stop_clock_time': int(STOP_TIME.seconds_since_unix_epoch)},
{'stop_clock_time': STOP_TIME.seconds_since_unix_epoch},
WorkflowStatus.RUNNING,
WORKFLOW_STATUS_RUNNING_TO_STOP % str(STOP_TIME)
),
Expand Down