Model module¶
¶
Context
¶
Contexts are used to store the state machine execution context.
They can either be a custom defined pydantic model or Dict[str, Any]
.
StatemachineConfig
¶
Placeholder generic type for state machine configurations.
ActivePeriod
pydantic-model
¶
Active period union type.
This class can be used in pydantic models to allow
loading of ComplexActivePeriod
or SimpleActivePeriod
.
in_active_period(self, to_check)
¶
Checks wether the given datetime is within this active period.
The actual check is delegated to the underlying sub types own checking logic.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to check |
required |
Returns:
Type | Description |
---|---|
bool |
bool: |
Source code in simulation/model.py
def in_active_period(self, to_check: datetime) -> bool:
"""Checks wether the given datetime is within this active period.
The actual check is delegated to the underlying sub types own
checking logic.
Args:
to_check (datetime): The datetime to check
Returns:
bool: `True` if inside the active period `False` otherwise
"""
return self.__root__.in_active_period(to_check)
ApproximateFloat
pydantic-model
¶
Approximate float value within a given open interval
max: float
pydantic-field
required
¶
The upper boundary for the float value
min: float
pydantic-field
required
¶
The lower boundary for the float value
value: float
property
readonly
¶
Gets a random float within the approximate float range
Returns:
Type | Description |
---|---|
float |
A float x for which |
convert(value)
classmethod
¶
Coerces a single float value to its ApproximateFloat equivalent.
i.e., value = min = max
Parameters:
Name | Type | Description | Default |
---|---|---|---|
value |
float |
The float value to convert |
required |
Returns:
Type | Description |
---|---|
ApproximateFloat |
|
Source code in simulation/model.py
@classmethod
def convert(cls, value: float) -> "ApproximateFloat":
"""Coerces a single float value to its ApproximateFloat equivalent.
i.e., value = min = max
Args:
value: The float value to convert
Returns:
`Approximate(min=value, max=value)`
"""
return ApproximateFloat(min=value, max=value)
validate_min_le_max(v, values, **kwargs)
classmethod
¶
Custom validator to ensure min <= max
Source code in simulation/model.py
@validator("max")
def validate_min_le_max(cls, v: float, values, **kwargs) -> float:
"""Custom validator to ensure min <= max"""
assert values["min"] <= v, "Invalid boundaries must be min <= max"
return v
ComplexActivePeriod
pydantic-model
¶
A ComplexActivePeriod
is defined by a set of
WeekdayActivePeriod
.
This makes it possible to configure active times for each week day separately.
week_days: WeekdayActivePeriod
pydantic-field
required
¶
Set of active periods, each week day can only have one configuration
in_active_period(self, to_check)
¶
Checks wether the given datetime is within this active period.
This is True
if the datetime is within the scope of one of
the WeekdayActivePeriods
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to check |
required |
Returns:
Type | Description |
---|---|
bool |
bool: |
Source code in simulation/model.py
def in_active_period(self, to_check: datetime) -> bool:
"""Checks wether the given datetime is within this active period.
This is `True` if the datetime is within the scope of **one** of
the [`WeekdayActivePeriods`][cr_kyoushi.simulation.model.WeekdayActivePeriod].
Args:
to_check (datetime): The datetime to check
Returns:
bool: `True` if inside the active period `False` otherwise
"""
return any(period.in_active_period(to_check) for period in self.week_days)
LogLevel
¶
An enumeration.
SimpleActivePeriod
pydantic-model
¶
Similar to ComplexActivePeriod
,
but each week day has the same active time period.
time_period: TimePeriod
pydantic-field
¶
The daylie active time period (if this is not set the whole days are considered active).
week_days: Weekday
pydantic-field
required
¶
A set of active week days.
in_active_period(self, to_check)
¶
Checks wether the given datetime is within this active period.
This is True
if the datetime matches one of the active week days
and the active time period.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to check |
required |
Returns:
Type | Description |
---|---|
bool |
bool: |
Source code in simulation/model.py
def in_active_period(self, to_check: datetime) -> bool:
"""Checks wether the given datetime is within this active period.
This is `True` if the datetime matches **one** of the active week days
and the active time period.
Args:
to_check (datetime): The datetime to check
Returns:
bool: `True` if inside the active period `False` otherwise
"""
return Weekday(to_check.weekday()) in self.week_days and (
self.time_period is None or self.time_period.in_period(to_check.time())
)
TimePeriod
pydantic-model
¶
A time period as defined by a start and end time.
end_time: time
pydantic-field
required
¶
The end time of the period
start_time: time
pydantic-field
required
¶
The start time of the period
in_period(self, to_check)
¶
Checks wether the given time of the day is within the scope of this time period.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
time |
The time of the day to check |
required |
Returns:
Type | Description |
---|---|
bool |
bool: |
Source code in simulation/model.py
def in_period(self, to_check: time) -> bool:
"""Checks wether the given time of the day is within the scope of this time period.
Args:
to_check (time): The time of the day to check
Returns:
bool: `True` if within the time period `False` otherwise
"""
if self.start_time <= self.end_time:
return self.start_time <= to_check and self.end_time > to_check
# start > end means our time period is between two days
return self.start_time <= to_check or self.end_time > to_check
Weekday
¶
Enumeration for representing the days of the week.
Weekdays are represented as the integers 0-6 and can be constructed from either their int representations or their english names.
WeekdayActivePeriod
pydantic-model
¶
A WeekdayActivePeriod
defines its active time based on the configure week day
and time period.
time_period: TimePeriod
pydantic-field
¶
The active time period (if this is not set the whole day is considered active)
week_day: Weekday
pydantic-field
required
¶
The active day of the week
__eq__(self, other)
special
¶
Return self==value.
Source code in simulation/model.py
def __eq__(self, other) -> bool:
return self.__class__ == other.__class__ and self.week_day == other.week_day
__hash__(self)
special
¶
Return hash(self).
Source code in simulation/model.py
def __hash__(self):
return hash(self.week_day)
in_active_period(self, to_check)
¶
Checks wether the given datetime is within the scope of this active period.
This will be True if the week day matches and given time of the day is within the time period.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to check |
required |
Returns:
Type | Description |
---|---|
bool |
bool: |
Source code in simulation/model.py
def in_active_period(self, to_check: datetime) -> bool:
"""Checks wether the given datetime is within the scope of this active period.
This will be True if the week day matches and given time of the day is
within the time period.
Args:
to_check (datetime): The datetime to check
Returns:
bool: `True` if inside the active period `False` otherwise
"""
return Weekday(to_check.weekday()) is self.week_day and (
self.time_period is None or self.time_period.in_period(to_check.time())
)
WorkHours
pydantic-model
¶
A special type of time period that does not allow over night periods
validate_start_before_end(v, values, **kwargs)
classmethod
¶
Validates that the start time is before the end time.
This restricts work hours to be within a single day i.e., work hours can not be defined to start on one day and end on the following day.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
v |
time |
The parsed end time to check |
required |
values |
Dict[str, Any] |
A dictionary containing previously parsed and validated fields. See Pydantic for details. |
required |
Returns:
Type | Description |
---|---|
time |
The end time if it is valid |
Source code in simulation/model.py
@validator("end_time")
def validate_start_before_end(
cls,
v: time,
values: Dict[str, Any],
**kwargs,
) -> time:
"""Validates that the start time is before the end time.
This restricts work hours to be within a single day i.e., work hours
can not be defined to start on one day and end on the following day.
Args:
v: The parsed end time to check
values: A dictionary containing previously parsed and validated fields.
See [Pydantic](https://pydantic-docs.helpmanual.io/usage/validators/) for details.
Returns:
The end time if it is valid
"""
# if start time is not in values it failed to validate
# so we skip the check and let validation fail
if "start_time" in values:
assert values["start_time"] < v, "End time must be after start time"
return v
WorkSchedule
pydantic-model
¶
A weekly work schedule represented by the week days and work hours for each day
work_days: WorkHours
pydantic-field
required
¶
Dictionary containing the work hours for each weekday
is_work_day(self, weekday)
¶
Checks wether the given weekday is a work day.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
weekday |
Weekday |
The weekday to check encoded as integer (0-6) |
required |
Returns:
Type | Description |
---|---|
bool |
|
Source code in simulation/model.py
def is_work_day(self, weekday: Weekday) -> bool:
"""Checks wether the given weekday is a work day.
Args:
weekday: The weekday to check encoded as integer (0-6)
Returns:
`True` if it is a work day `False` otherwise
"""
return weekday in self.work_days
is_work_time(self, to_check)
¶
Checks wether the given datetime is work time.
Something is considered to be work time if it is a work day and the time is within the work hours of that work day.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to check |
required |
Returns:
Type | Description |
---|---|
bool |
|
Source code in simulation/model.py
def is_work_time(self, to_check: datetime) -> bool:
"""Checks wether the given datetime is work time.
Something is considered to be work time if it is a work day
and the time is within the work hours of that work day.
Args:
to_check: The datetime to check
Returns:
`True` if the given datetime is work time `False` otherwise
"""
weekday: Weekday = Weekday(to_check.weekday())
# check if the datetime is on a work day
if self.is_work_day(weekday):
# if its on a workday check if its with the days work hours
return self.work_days[weekday].in_period(to_check.time())
return False
next_work_start(self, to_check)
¶
Gets the next work time, relative to the given datetime.
If the given datetime is within work hours the start time of that work day is returned.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
to_check |
datetime |
The datetime to find the next work time for |
required |
Returns:
Type | Description |
---|---|
Optional[datetime.datetime] |
The next work time or |
Source code in simulation/model.py
def next_work_start(self, to_check: datetime) -> Optional[datetime]:
"""Gets the next work time, relative to the given datetime.
If the given datetime is within work hours the start time
of that work day is returned.
Args:
to_check: The datetime to find the next work time for
Returns:
The next work time or `None` if there is no work time
"""
weekday: Weekday = Weekday(to_check.weekday())
if (
# if the given datetime is a workday
self.is_work_day(weekday)
and (
# and work has not begun yet
to_check.time() <= self.work_days[weekday].start_time
# or if we are still within work time
# we return the given days start time
or self.is_work_time(to_check)
)
):
return datetime.combine(to_check.date(), self.work_days[weekday].start_time)
# otherwise next work start must be some day after
# the given day so we check the next 7 days
# (we might only work once a week)
for i in range(1, 8):
# increment weekday and be sure to start from 0 once we pass sunday (int: 6)
weekday = Weekday((weekday + 1) % 7)
if self.is_work_day(weekday):
# add the days till the next work day to the given date
next_work: datetime = to_check + timedelta(i)
# get the start time for that day
start_time = self.work_days[weekday].start_time
return datetime.combine(next_work.date(), start_time)
# if we got here then no workday is set so we will never start
return None