Skip to content
Merged
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
10 changes: 6 additions & 4 deletions docs/content/api-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -226,19 +226,21 @@ External

.. _Extern:

.. autoclass:: pyflow.Extern
.. autoclass:: pyflow.ExternSuite

.. autoclass:: pyflow.ExternNode
.. autoclass:: pyflow.ExternFamily

.. autoclass:: pyflow.ExternTask

.. autoclass:: pyflow.ExternFamily
.. autoclass:: pyflow.ExternVariable

.. autoclass:: pyflow.ExternLimit

.. autoclass:: pyflow.ExternEvent

.. autoclass:: pyflow.ExternMeter

.. autoclass:: pyflow.ExternYMD
.. autoclass:: pyflow.ExternRepeat


Deployment
Expand Down
4 changes: 2 additions & 2 deletions docs/content/introductory-course/flow-control.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": null,
"id": "a2937746-a676-49ea-9332-315e763167ca",
"metadata": {},
"outputs": [
Expand Down Expand Up @@ -1034,7 +1034,7 @@
" etask = pf.ExternTask('/a/b/c/d')\n",
" efamily = pf.ExternFamily('/f/g/h/i')\n",
" \n",
" eymd = pf.ExternYMD('/a/b/c/d:YMD')\n",
" eymd = pf.ExternRepeat('/a/b/c/d:YMD')\n",
" eevent = pf.ExternEvent('/e/f/g/h:ev')\n",
" emeter = pf.ExternMeter('/g/h/i/j:mt')\n",
" \n",
Expand Down
4 changes: 2 additions & 2 deletions docs/content/introductory-course/helper-functionality.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"id": "b2e2a324-3df0-4874-8c69-d3d93ea39bc4",
"metadata": {},
"outputs": [
Expand Down Expand Up @@ -196,7 +196,7 @@
" pf.RepeatDate(\"YMD\", datetime.date(2019, 1, 1), datetime.date(2019, 12, 31))\n",
" with pf.Family('follower') as follower:\n",
" pf.RepeatDate(\"YMD\", datetime.date(2019, 1, 1), datetime.date(2019, 12, 31))\n",
" follower.follow = leader.YMD\n",
" follower.follow = leader\n",
"\n",
"s"
]
Expand Down
6 changes: 5 additions & 1 deletion pyflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@
from .expressions import Deferred, all_complete, sequence
from .extern import (
Extern,
ExternAttribute,
ExternEvent,
ExternFamily,
ExternLimit,
ExternMeter,
ExternNode,
ExternRepeat,
ExternSuite,
ExternTask,
ExternVariable,
ExternYMD,
)
from .header import FileHeader, FileTail, Header, InlineCodeHeader
Expand Down
142 changes: 66 additions & 76 deletions pyflow/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
import re

from . import warn
from .anchor import AnchorMixin
from .base import Base, GenerateError
from .cron import Crontab
Expand Down Expand Up @@ -92,26 +93,6 @@ def generate_stub(self):
shape = "box"


class RepeatDay(Attribute):
"""
An attribute that allows a node to be repeated infinitely.

Parameters:
value(int): The repeat step.

Example::

pyflow.attributes.RepeatDay(1)
"""

def __init__(self, value):
super().__init__("_repeat")
self._value = value

def _build(self, ecflow_parent):
ecflow_parent.add_repeat(ecflow.RepeatDay(int(self.value)))


class Time(Attribute):
"""
An attribute for setting a time dependency of the node.
Expand Down Expand Up @@ -341,7 +322,43 @@ def __init__(self, **kwargs):
Variable(key, val)


class RepeatString(Exportable):
class Repeat(Exportable):
"""
A virtual class that defines a repeat attribute
"""

def __init__(self, name, values=None):
super().__init__(name, values)
if self.parent._repeat is not None:
warn(
"Overwriting an existing repeat value!",
category=UserWarning,
stacklevel=2,
)
self.parent._repeat = self # set the repeat at the node level


class RepeatDay(Repeat):
"""
An attribute that allows a node to be repeated infinitely.

Parameters:
value(int): The repeat step.

Example::

pyflow.attributes.RepeatDay(1)
"""

def __init__(self, value):
super().__init__("_repeat")
self._value = value

def _build(self, ecflow_parent):
ecflow_parent.add_repeat(ecflow.RepeatDay(int(self.value)))


class RepeatString(Repeat):
"""
An attribute that allows a node to be repeated by a string value.

Expand Down Expand Up @@ -412,7 +429,7 @@ def __sub__(self, other):
return Sub(self, other)


class RepeatEnumerated(Exportable):
class RepeatEnumerated(Repeat):
"""
An attribute that allows a node to be repeated by an enumerated list.

Expand All @@ -422,7 +439,7 @@ class RepeatEnumerated(Exportable):

Example::

pyflow.RepeatEnumerated("REPEAT_STRING", ["a", "b", "c", "d", "e"])
pyflow.RepeatEnumerated("REPEAT_STRING", [1, 3, 4, 5])
"""

def __init__(self, name, value):
Expand All @@ -437,17 +454,14 @@ def values(self):
"""*list*: The list of enumerated values."""
return [str(x) for x in self.value]

def settings(self):
return self.value

def __add__(self, other):
return Add(self, other)

def __sub__(self, other):
return Sub(self, other)


class RepeatDateList(Exportable):
class RepeatDateList(Repeat):
"""
An attribute that allows a node to be repeated over a list of dates.

Expand Down Expand Up @@ -479,17 +493,14 @@ def values(self):
v = [int(x) for x in v]
return v

def settings(self):
return self.value

def __add__(self, other):
return Add(self, other)

def __sub__(self, other):
return Sub(self, other)


class RepeatInteger(Exportable):
class RepeatInteger(Repeat):
"""
An attribute that allows a node to be repeated by an integer range.

Expand Down Expand Up @@ -527,7 +538,7 @@ def __sub__(self, other):
return Sub(self, other)


class RepeatDate(Exportable):
class RepeatDate(Repeat):
"""
An attribute that allows a node to be repeated by a date value.

Expand Down Expand Up @@ -580,9 +591,6 @@ def __sub__(self, other):
result = Sub(self.julian, other.julian)
return result

def settings(self):
return self._start, self._end, self._increment

@property
def julian(self):
"""*int*: The Julian date of the repeat date."""
Expand Down Expand Up @@ -681,9 +689,6 @@ def __add__(self, other):
def __sub__(self, other):
return Sub(self, other)

def settings(self):
return self._start, self._end, self._increment

def _delta_to_string(self, delta):
# there is no strftime for timedelta so we make our own
total_seconds = int(delta.total_seconds())
Expand Down Expand Up @@ -712,12 +717,6 @@ def day_of_week(self):
return Mod(Add(Div(self, 86400), 4), 7)


def string_or_enumerated(name, value):
if all(isinstance(v, int) for v in value):
return RepeatEnumerated(name, value)
return RepeatString(name, value)


def is_date(value):
return (
isinstance(value, (datetime.date, datetime.datetime))
Expand Down Expand Up @@ -796,27 +795,9 @@ def make_variable(node, name, value):

with node:
if isinstance(value, (tuple, list)):
if len(value) in [2, 3]:
if is_date(value[0]) and is_date(value[1]):
if len(value) == 3:
if isinstance(value[2], int):
return RepeatDate(
name,
as_date(value[0]),
as_date(value[1]),
value[2],
)
else:
return RepeatDate(name, as_date(value[0]), as_date(value[1]), 1)

if isinstance(value[0], int) and isinstance(value[1], int):
if len(value) == 3:
if isinstance(value[2], int):
return RepeatInteger(name, value[0], value[1], value[2])
else:
return RepeatInteger(name, value[0], value[1], 1)

return string_or_enumerated(name, value)
raise Exception(
"Repeat construction through a list is not supported anymore"
)

if isinstance(value, (str, int, float)):
return Variable(name, value)
Expand Down Expand Up @@ -1242,23 +1223,32 @@ class Follow(_Trigger):
An attribute for setting a condition for running the node behind another repeated node which has completed.

Parameters:
value(RepeatDate_): The repeat date attribute of the followed node.
value(Repeat_ or Task_ or Family_ or Suite_): The followed node or the repeat attribute of the followed node.

Example::

pyflow.attributes.Follow(pyflow.RepeatDate('REPEAT_DATE',
datetime.date(year=2019, month=1, day=1),
datetime.date(year=2019, month=12, day=31)))
t1 = Task("t1", repeat=(RepeatEnumerated, "NUM", [1, 2, 3]))
t2 = Task("t2", repeat=(RepeatEnumerated, "NUM", [1, 2, 3]))
t2.follow = t1
"""

def __init__(self, value):
super().__init__("_follow_%s" % (value,), value)
if not hasattr(value, "settings"):
raise Exception(
"Cannot follow a node of type %s (%r)" % (type(value), value)
super().__init__(f"_follow_{value.name}")
from .nodes import Node # yeah it's bad but there's a circular import

if isinstance(value, Node):
parent = value
repeat = value.repeat
elif isinstance(value, Repeat):
parent = value.parent
repeat = value
else:
raise TypeError(
f"Follow attribute {self.name} requires a Repeat or a Node instance"
)
self.parent[value.name] = value.settings()
self._value = value.parent.complete | (self.parent[value.name] < value)

if repeat is None:
raise TypeError(f"Follow attribute {self.name} requires a repeat")
self._value = parent.complete | (self.parent.repeat < repeat)


###################################################################
Expand Down
4 changes: 4 additions & 0 deletions pyflow/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def remove_node(self, node):
def add_node(self, node):
pass

@property
def repeat(self):
return None

@property
def host(self):
return None
Expand Down
Loading
Loading