Skip to content

Commit 84b9624

Browse files
committed
Linter fixes
1 parent 2883df3 commit 84b9624

File tree

3 files changed

+105
-34
lines changed

3 files changed

+105
-34
lines changed

azure/durable_functions/models/DurableOrchestrationContext.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from uuid import UUID, uuid5, NAMESPACE_URL, NAMESPACE_OID
2727
from datetime import timezone
2828

29-
from azure.durable_functions.models.utils.json_utils import parse_datetime_attrib_timespan
29+
from azure.durable_functions.models.utils.json_utils import parse_timespan_attrib
3030

3131
from .RetryOptions import RetryOptions
3232
from .FunctionContext import FunctionContext
@@ -51,18 +51,20 @@ class DurableOrchestrationContext:
5151
def __init__(self,
5252
history: List[Dict[Any, Any]], instanceId: str, isReplaying: bool,
5353
parentInstanceId: str, input: Any = None, upperSchemaVersion: int = 0,
54-
maximumShortTimerDuration=None, longRunningTimerIntervalDuration=None,
55-
upperSchemaVersionNew = None, **kwargs):
54+
maximumShortTimerDuration:str = None, longRunningTimerIntervalDuration:str = None,
55+
upperSchemaVersionNew:int = None, **kwargs):
5656
self._histories: List[HistoryEvent] = [HistoryEvent(**he) for he in history]
5757
self._instance_id: str = instanceId
5858
self._is_replaying: bool = isReplaying
5959
self._parent_instance_id: str = parentInstanceId
6060
self._maximum_short_timer_duration: datetime.timedelta
6161
if maximumShortTimerDuration is not None:
62-
self._maximum_short_timer_duration = parse_datetime_attrib_timespan(maximumShortTimerDuration)
63-
self._long_running_timer_interval_duration: datetime.timedelta
62+
max_short_duration = parse_timespan_attrib(maximumShortTimerDuration)
63+
self._maximum_short_timer_duration = max_short_duration
64+
self._long_timer_interval_duration: datetime.timedelta
6465
if longRunningTimerIntervalDuration is not None:
65-
self._long_running_timer_interval_duration = parse_datetime_attrib_timespan(longRunningTimerIntervalDuration)
66+
long_interval_duration = parse_timespan_attrib(longRunningTimerIntervalDuration)
67+
self._long_timer_interval_duration = long_interval_duration
6668
self._custom_status: Any = None
6769
self._new_uuid_counter: int = 0
6870
self._sub_orchestrator_counter: int = 0
@@ -485,7 +487,7 @@ def parent_instance_id(self) -> str:
485487

486488
@property
487489
def maximum_short_timer_duration(self) -> datetime.timedelta:
488-
"""Get the maximum duration for a short timer
490+
"""Get the maximum duration for a short timer.
489491
490492
The maximum length of a "short timer" is defined by the storage backend.
491493
Some storage backends have a maximum future date for scheduled tasks, and
@@ -500,7 +502,7 @@ def maximum_short_timer_duration(self) -> datetime.timedelta:
500502
return self._maximum_short_timer_duration
501503

502504
@property
503-
def long_running_timer_interval_duration(self) -> datetime.timedelta:
505+
def long_timer_interval_duration(self) -> datetime.timedelta:
504506
"""Get the interval for long timers.
505507
506508
When a timer is scheduled for a duration longer than the maximum short timer
@@ -512,7 +514,7 @@ def long_running_timer_interval_duration(self) -> datetime.timedelta:
512514
str
513515
Duration for intervals of a long-running timer
514516
"""
515-
return self._long_running_timer_interval_duration
517+
return self._long_timer_interval_duration
516518

517519
@property
518520
def current_utc_datetime(self) -> datetime.datetime:
@@ -624,18 +626,21 @@ def create_timer(self, fire_at: datetime.datetime) -> TaskBase:
624626
A Durable Timer Task that schedules the timer to wake up the activity
625627
"""
626628
if self._replay_schema.value >= ReplaySchema.V3.value:
627-
if not self.maximum_short_timer_duration or not self.long_running_timer_interval_duration:
629+
if not self.maximum_short_timer_duration or not self.long_timer_interval_duration:
628630
raise Exception(
629-
"A framework-internal error was detected: replay schema version >= V3 is being used, " +
630-
"but one or more of the properties `maximumShortTimerDuration` and `longRunningTimerIntervalDuration` are not defined. " +
631+
"A framework-internal error was detected: " +
632+
"replay schema version >= V3 is being used, " +
633+
"but one or more of the properties `maximumShortTimerDuration`" +
634+
"and `longRunningTimerIntervalDuration` are not defined. " +
631635
"This is likely an issue with the Durable Functions Extension. " +
632-
"Please report this bug here: https://github.com/Azure/azure-functions-durable-js/issues\n" +
636+
"Please report this bug here: " +
637+
"https://github.com/Azure/azure-functions-durable-python/issues\n" +
633638
f"maximumShortTimerDuration: {self.maximum_short_timer_duration}\n" +
634-
f"longRunningTimerIntervalDuration: {self.long_running_timer_interval_duration}"
639+
f"longRunningTimerIntervalDuration: {self.long_timer_interval_duration}"
635640
)
636641
if fire_at > self.current_utc_datetime + self.maximum_short_timer_duration:
637642
action = CreateTimerAction(fire_at)
638-
return LongTimerTask(None, action, self, None, self.maximum_short_timer_duration, self.long_running_timer_interval_duration)
643+
return LongTimerTask(None, action, self)
639644

640645
action = CreateTimerAction(fire_at)
641646
task = self._generate_task(action, task_constructor=TimerTask)
@@ -713,7 +718,8 @@ def _add_to_actions(self, action_repr: Union[List[Action], Action]):
713718

714719
if self._replay_schema is ReplaySchema.V1 and isinstance(action_repr, list):
715720
self._action_payload_v1.append(action_repr)
716-
elif self._replay_schema.value >= ReplaySchema.V2.value and isinstance(action_repr, Action):
721+
elif (self._replay_schema.value >= ReplaySchema.V2.value
722+
and isinstance(action_repr, Action)):
717723
self._action_payload_v2.append(action_repr)
718724
else:
719725
raise Exception(f"DF-internal exception: ActionRepr of signature {type(action_repr)}"

azure/durable_functions/models/Task.py

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -319,13 +319,26 @@ def try_set_value(self, child: TaskBase):
319319

320320

321321
class LongTimerTask(WhenAllTask):
322-
def __init__(self, id, action: CreateTimerAction, orchestration_context, executor, maximum_timer_length, long_running_timer_duration):
322+
"""A Timer Task for intervals longer than supported by the storage backend."""
323+
324+
def __init__(self, id, action: CreateTimerAction, orchestration_context):
325+
"""Initialize a LongTimerTask.
326+
327+
Parameters
328+
----------
329+
id_ : int
330+
An ID for the task
331+
action : CreateTimerAction
332+
The action this task represents
333+
orchestration_context: DurableOrchestrationContext
334+
The orchestration context this task was created in
335+
"""
323336
current_time = orchestration_context.current_utc_datetime
324337
final_fire_time = action.fire_at
325338
duration_until_fire = final_fire_time - current_time
326339

327-
if duration_until_fire > maximum_timer_length:
328-
next_fire_time = current_time + long_running_timer_duration
340+
if duration_until_fire > self.orchestration_context.maximum_timer_length:
341+
next_fire_time = current_time + self.orchestration_context.long_running_timer_duration
329342
else:
330343
next_fire_time = final_fire_time
331344

@@ -336,35 +349,79 @@ def __init__(self, id, action: CreateTimerAction, orchestration_context, executo
336349
self.id = id
337350
self.action = action
338351
self.orchestration_context = orchestration_context
339-
self.executor = executor
340-
self.maximum_timer_length = maximum_timer_length
341-
self.long_running_timer_duration = long_running_timer_duration
352+
self.maximum_timer_length = self.orchestration_context.maximum_timer_length
353+
self.long_running_timer_duration = self.orchestration_context.long_running_timer_duration
342354

343355
def is_canceled(self) -> bool:
356+
"""Check if the LongTimer is cancelled.
357+
358+
Returns
359+
-------
360+
bool
361+
Returns whether the timer has been cancelled or not
362+
"""
344363
return self.action.is_cancelled
345-
364+
346365
def cancel(self):
366+
"""Cancel a timer.
367+
368+
Raises
369+
------
370+
ValueError
371+
Raises an error if the task is already completed and an attempt is made to cancel it
372+
"""
347373
if (self.result):
348374
raise Exception("Cannot cancel a completed task.")
349375
self.action.is_cancelled = True
350376

351377
def try_set_value(self, child: TimerTask):
378+
"""Transition this LongTimer Task to a terminal state and set its value.
379+
380+
If the LongTimer has not yet reached the designated completion time, starts a new
381+
TimerTask for the next interval and does not close.
382+
383+
Parameters
384+
----------
385+
child : TimerTask
386+
A timer sub-task that just completed
387+
"""
352388
current_time = self.orchestration_context.current_utc_datetime
353389
final_fire_time = self.action.fire_at
354390
if final_fire_time > current_time:
355391
next_timer = self.get_next_timer_task(final_fire_time, current_time)
356392
self.add_new_child(next_timer)
357393
return super().try_set_value(child)
358-
359-
def get_next_timer_task(self, final_fire_time:datetime, current_time:datetime):
394+
395+
def get_next_timer_task(self, final_fire_time: datetime, current_time: datetime) -> TimerTask:
396+
"""Creates a TimerTask that represents the next interval of the LongTimer
397+
398+
Parameters
399+
----------
400+
final_fire_time : datetime.datetime
401+
The final firing time of the LongTimer
402+
current_time : datetime.datetime
403+
The current time
404+
405+
Returns
406+
-------
407+
TimerTask
408+
A TimerTask representing the next interval of the LongTimer
409+
"""
360410
duration_until_fire = final_fire_time - current_time
361411
if duration_until_fire > self.maximum_timer_length:
362412
next_fire_time = current_time + self.long_running_timer_duration
363413
else:
364414
next_fire_time = final_fire_time
365415
return TimerTask(None, CreateTimerAction(next_fire_time))
366-
416+
367417
def add_new_child(self, child_timer: TimerTask):
418+
"""Adds the TimerTask to this Task's children and schedules it in the orchestrationcontext
419+
420+
Parameters
421+
----------
422+
child_timer : TimerTask
423+
The newly created TimerTask to add
424+
"""
368425
child_timer.parent = self
369426
self.pending_tasks.add(child_timer)
370427
self.orchestration_context._add_to_open_tasks(child_timer)

azure/durable_functions/models/utils/json_utils.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ def add_datetime_attrib(json_dict: Dict[str, Any], object_,
3838
json_dict[alt_name or attribute_name] = \
3939
getattr(object_, attribute_name).strftime(DATETIME_STRING_FORMAT)
4040

41-
# When we recieve properties from WebJobs extension originally parsed as TimeSpan objects through Newtonsoft,
42-
# the format complies with the constant format specifier for TimeSpan in .NET.
43-
# See https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings#the-constant-c-format-specifier
44-
# Python offers no convenient way to parse these back into timedeltas, so we use this regex method instead
45-
def parse_datetime_attrib_timespan(from_str: str) -> datetime.timedelta:
46-
"""Converts a string originally produced by TimeSpan.ToString("c") in .NET into python's timespan.timedelta
41+
# When we recieve properties from WebJobs extension originally parsed as
42+
# TimeSpan objects through Newtonsoft, the format complies with the constant
43+
# format specifier for TimeSpan in .NET.
44+
# Python offers no convenient way to parse these back into timedeltas,
45+
# so we use this regex method instead
46+
def parse_timespan_attrib(from_str: str) -> datetime.timedelta:
47+
"""Converts a string representing TimeSpan.ToString("c") in .NET to python timespan.timedelta
4748
4849
Parameters
4950
----------
@@ -55,9 +56,16 @@ def parse_datetime_attrib_timespan(from_str: str) -> datetime.timedelta:
5556
The TimeSpan expressed as a Python datetime.timedelta
5657
5758
"""
58-
match = re.match(r"^(-)?(?:([0-9]*)\.)?([0-9]{2}):([0-9]{2}):([0-9]{2})(?:\.([0-9]{7}))?$", from_str)
59+
expr = r"^(-)?(?:([0-9]*)\.)?([0-9]{2}):([0-9]{2}):([0-9]{2})(?:\.([0-9]{7}))?$"
60+
match = re.match(expr, from_str)
5961
if match:
60-
span = datetime.timedelta(days=int(match.group(2) or "0"), hours=int(match.group(3)), minutes=int(match.group(4)), seconds=int(match.group(5)), microseconds=int(match.group(6) or "0") // 10)
62+
span = datetime.timedelta(
63+
days=int(match.group(2) or "0"),
64+
hours=int(match.group(3)),
65+
minutes=int(match.group(4)),
66+
seconds=int(match.group(5)),
67+
microseconds=int(match.group(6) or "0") // 10)
68+
6169
if match.group(1):
6270
span = -span
6371
return span

0 commit comments

Comments
 (0)