nodekit 0.0.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nodekit might be problematic. Click here for more details.
- nodekit/__init__.py +46 -0
- nodekit/_internal/__init__.py +0 -0
- nodekit/_internal/compilers/__init__.py +0 -0
- nodekit/_internal/compilers/events.py +59 -0
- nodekit/_internal/compilers/html_rendering.py +44 -0
- nodekit/_internal/compilers/node_graph_site_template.j2 +109 -0
- nodekit/_internal/models/__init__.py +0 -0
- nodekit/_internal/models/assets/__init__.py +0 -0
- nodekit/_internal/models/assets/base.py +43 -0
- nodekit/_internal/models/fields.py +60 -0
- nodekit/_internal/models/node_engine/__init__.py +0 -0
- nodekit/_internal/models/node_engine/base.py +22 -0
- nodekit/_internal/models/node_engine/board.py +9 -0
- nodekit/_internal/models/node_engine/bonus_policy.py +50 -0
- nodekit/_internal/models/node_engine/cards/__init__.py +0 -0
- nodekit/_internal/models/node_engine/cards/base.py +25 -0
- nodekit/_internal/models/node_engine/cards/cards.py +60 -0
- nodekit/_internal/models/node_engine/effects/__init__.py +0 -0
- nodekit/_internal/models/node_engine/effects/base.py +30 -0
- nodekit/_internal/models/node_engine/fields.py +85 -0
- nodekit/_internal/models/node_engine/node_graph.py +118 -0
- nodekit/_internal/models/node_engine/reinforcer_maps/__init__.py +0 -0
- nodekit/_internal/models/node_engine/reinforcer_maps/base.py +14 -0
- nodekit/_internal/models/node_engine/reinforcer_maps/reinforcer/__init__.py +0 -0
- nodekit/_internal/models/node_engine/reinforcer_maps/reinforcer/reinforcer.py +14 -0
- nodekit/_internal/models/node_engine/reinforcer_maps/reinforcer_maps.py +43 -0
- nodekit/_internal/models/node_engine/runtime_metrics.py +24 -0
- nodekit/_internal/models/node_engine/sensors/__init__.py +0 -0
- nodekit/_internal/models/node_engine/sensors/actions/__init__.py +0 -0
- nodekit/_internal/models/node_engine/sensors/actions/actions.py +48 -0
- nodekit/_internal/models/node_engine/sensors/actions/base.py +18 -0
- nodekit/_internal/models/node_engine/sensors/base.py +25 -0
- nodekit/_internal/models/node_engine/sensors/sensors.py +49 -0
- nodekit/_internal/rule_engine/__init__.py +0 -0
- nodekit/_internal/rule_engine/compute_bonus.py +32 -0
- nodekit/actions/__init__.py +13 -0
- nodekit/assets/__init__.py +9 -0
- nodekit/bonus_rules/__init__.py +10 -0
- nodekit/cards/__init__.py +13 -0
- nodekit/compile/__init__.py +10 -0
- nodekit/effects/__init__.py +7 -0
- nodekit/events/__init__.py +23 -0
- nodekit/reinforcer_maps/__init__.py +10 -0
- nodekit/sensors/__init__.py +12 -0
- nodekit/types/__init__.py +27 -0
- nodekit-0.0.1a1.dist-info/METADATA +217 -0
- nodekit-0.0.1a1.dist-info/RECORD +50 -0
- nodekit-0.0.1a1.dist-info/WHEEL +5 -0
- nodekit-0.0.1a1.dist-info/licenses/LICENSE +201 -0
- nodekit-0.0.1a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from typing import List, Self
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
import pydantic
|
|
5
|
+
|
|
6
|
+
from nodekit._internal.models.fields import (
|
|
7
|
+
PayableMonetaryAmountUsd, DatetimeUTC
|
|
8
|
+
)
|
|
9
|
+
from nodekit._internal.models.node_engine.board import Board
|
|
10
|
+
from nodekit._internal.models.node_engine.bonus_policy import BonusRule
|
|
11
|
+
from nodekit._internal.models.node_engine.cards.cards import Card
|
|
12
|
+
from nodekit._internal.models.node_engine.effects.base import Effect
|
|
13
|
+
from nodekit._internal.models.node_engine.fields import NodeId
|
|
14
|
+
from nodekit._internal.models.node_engine.reinforcer_maps.reinforcer_maps import ReinforcerMap
|
|
15
|
+
from nodekit._internal.models.node_engine.runtime_metrics import RuntimeMetrics
|
|
16
|
+
from nodekit._internal.models.node_engine.sensors.actions.actions import Action
|
|
17
|
+
from nodekit._internal.models.node_engine.sensors.sensors import Sensor
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# %% Node
|
|
21
|
+
class Node(pydantic.BaseModel):
|
|
22
|
+
node_id: NodeId = pydantic.Field(default_factory=uuid4)
|
|
23
|
+
|
|
24
|
+
board: Board = pydantic.Field(
|
|
25
|
+
default_factory=Board
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
cards: List[Card] = pydantic.Field(
|
|
29
|
+
description="List of Cards that will be placed on the Board, in back-to-front order (i.e. the first Card is at the bottom of the Board, in the z-direction)",
|
|
30
|
+
min_length=1,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
sensors: List[Sensor] = pydantic.Field(min_length=1)
|
|
34
|
+
reinforcer_maps: List[ReinforcerMap] = pydantic.Field(default_factory=list)
|
|
35
|
+
effects: List[Effect] = pydantic.Field(default_factory=list)
|
|
36
|
+
|
|
37
|
+
@pydantic.model_validator(mode='after')
|
|
38
|
+
def check_node_is_well_formed(self) -> Self:
|
|
39
|
+
|
|
40
|
+
# Run basic checks
|
|
41
|
+
# Check Cards have unique IDs
|
|
42
|
+
card_id_to_card = {card.card_id: card for card in self.cards}
|
|
43
|
+
if len(card_id_to_card) != len(self.cards):
|
|
44
|
+
raise ValueError("Cards must have unique IDs.")
|
|
45
|
+
|
|
46
|
+
# Check Sensors:
|
|
47
|
+
sensor_id_to_sensor = {sensor.sensor_id: sensor for sensor in self.sensors}
|
|
48
|
+
if len(sensor_id_to_sensor) != len(self.sensors):
|
|
49
|
+
raise ValueError("Sensors must have unique IDs.")
|
|
50
|
+
for sensor in self.sensors:
|
|
51
|
+
|
|
52
|
+
# Ensure Sensor references a valid target
|
|
53
|
+
if sensor.card_id and sensor.card_id not in card_id_to_card:
|
|
54
|
+
raise ValueError(f"Sensor {sensor.sensor_id} is not attached to a valid Card or the Board.")
|
|
55
|
+
|
|
56
|
+
# Todo: check that the Sensor and Target type are compatible:
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
# Check Reinforcer Maps
|
|
60
|
+
for rmap in self.reinforcer_maps:
|
|
61
|
+
if rmap.sensor_id not in sensor_id_to_sensor:
|
|
62
|
+
raise ValueError(f"ReinforcerMap {rmap.reinforcer_map_id} is not attached to a valid Sensor.")
|
|
63
|
+
|
|
64
|
+
# Todo: apply rules for ReinforcerMap-Sensor compatibility
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
return self
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# %% NodeGraph
|
|
71
|
+
class NodeGraph(pydantic.BaseModel):
|
|
72
|
+
nodes: List[Node]
|
|
73
|
+
|
|
74
|
+
# Payment information
|
|
75
|
+
base_payment_usd: PayableMonetaryAmountUsd = pydantic.Field(
|
|
76
|
+
description="The base payment (in USD) that a Participant receives upon successfully completing a TaskRun. Explicitly disclosed to the Participant ahead of time.",
|
|
77
|
+
)
|
|
78
|
+
bonus_rules: List[BonusRule] = pydantic.Field(
|
|
79
|
+
default_factory=list,
|
|
80
|
+
description='A list of bonus rules that apply to the TaskRun. These rules determine additional payments based on Participant behavior during the TaskRun.'
|
|
81
|
+
'These are not disclosed to the Participant by default, but might be described elsewhere, like the description or in a Node.'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Duration
|
|
85
|
+
max_duration_sec: int = pydantic.Field(
|
|
86
|
+
gt=0,
|
|
87
|
+
description="The maximum of time in seconds a Participant has to complete a TaskRun, before it is marked as failed."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Metadata that is disclosed to the Participant:
|
|
91
|
+
title: str = pydantic.Field(
|
|
92
|
+
min_length=1,
|
|
93
|
+
description='The title of the Recruitment Platform posting for the task.'
|
|
94
|
+
)
|
|
95
|
+
description: str = pydantic.Field(
|
|
96
|
+
min_length=1,
|
|
97
|
+
description='A detailed description of the task in the Recruitment Platform posting.'
|
|
98
|
+
)
|
|
99
|
+
keywords: List[str] = pydantic.Field(
|
|
100
|
+
description='Keywords that Participants may use to discover this task on the Recruitment Platform.'
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# %%
|
|
106
|
+
class NodeResult(pydantic.BaseModel):
|
|
107
|
+
"""
|
|
108
|
+
Describes the result of a NodePlay.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
node_id: str = pydantic.Field(description='The ID of the Node from which this NodeResult was produced.')
|
|
112
|
+
node_execution_index: int = pydantic.Field(description='The index of the Node execution in the NodeGraph. This is used to identify the order of Node executions in a TaskRun.')
|
|
113
|
+
|
|
114
|
+
timestamp_start: DatetimeUTC
|
|
115
|
+
timestamp_end: DatetimeUTC
|
|
116
|
+
|
|
117
|
+
action: Action
|
|
118
|
+
runtime_metrics: RuntimeMetrics
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from nodekit._internal.models.node_engine.base import DslModel
|
|
5
|
+
from nodekit._internal.models.node_engine.fields import SensorId
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseReinforcerMap(DslModel, ABC):
|
|
9
|
+
"""
|
|
10
|
+
Represents a map from a fully qualified Action emitted by a particular Sensor to an Outcome.
|
|
11
|
+
"""
|
|
12
|
+
reinforcer_map_type: str
|
|
13
|
+
reinforcer_map_parameters: Any
|
|
14
|
+
sensor_id: SensorId
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
import pydantic
|
|
5
|
+
|
|
6
|
+
from nodekit._internal.models.node_engine.base import DslModel
|
|
7
|
+
from nodekit._internal.models.node_engine.cards.cards import Card
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Reinforcer(DslModel):
|
|
11
|
+
|
|
12
|
+
reinforcer_cards: List[Card] = pydantic.Field(
|
|
13
|
+
description='Cards which configure the (noninteractive) Reinforcer delivery phase.'
|
|
14
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from nodekit._internal.models.node_engine.base import DslModel, NullParameters
|
|
4
|
+
from nodekit._internal.models.node_engine.reinforcer_maps.base import BaseReinforcerMap
|
|
5
|
+
from nodekit._internal.models.node_engine.reinforcer_maps.reinforcer.reinforcer import Reinforcer
|
|
6
|
+
|
|
7
|
+
from typing import Annotated, Union
|
|
8
|
+
|
|
9
|
+
import pydantic
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# %%
|
|
13
|
+
class ConstantReinforcerMap(BaseReinforcerMap):
|
|
14
|
+
class Parameters(DslModel):
|
|
15
|
+
reinforcer: Reinforcer = pydantic.Field(description='The Outcome to return for any Action emitted by the Sensor it is attached to.')
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
An OutcomeMap which always returns the same Outcome for any Action emitted by the Sensor it is attached to.
|
|
19
|
+
"""
|
|
20
|
+
reinforcer_map_type: Literal['ConstantReinforcerMap'] = 'ConstantReinforcerMap'
|
|
21
|
+
reinforcer_map_parameters: Parameters
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# %%
|
|
25
|
+
class NullReinforcerMap(BaseReinforcerMap):
|
|
26
|
+
"""
|
|
27
|
+
A convenience class which represents an ReinforcerMap which yields a NullReinforcer.
|
|
28
|
+
"""
|
|
29
|
+
reinforcer_map_type: Literal['NullReinforcerMap'] = 'NullReinforcerMap'
|
|
30
|
+
reinforcer_map_parameters: NullParameters = pydantic.Field(
|
|
31
|
+
default_factory=NullParameters, frozen=True
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# %%
|
|
36
|
+
ReinforcerMap = Annotated[
|
|
37
|
+
Union[
|
|
38
|
+
NullReinforcerMap,
|
|
39
|
+
ConstantReinforcerMap,
|
|
40
|
+
# Add other OutcomeMap types here as needed
|
|
41
|
+
],
|
|
42
|
+
pydantic.Field(discriminator='reinforcer_map_type')
|
|
43
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pydantic
|
|
2
|
+
|
|
3
|
+
from nodekit._internal.models.node_engine.base import DslModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# %% Measurements
|
|
7
|
+
class PixelArea(DslModel):
|
|
8
|
+
width_px: int = pydantic.Field(description="Width of the area in pixels.", ge=0)
|
|
9
|
+
height_px: int = pydantic.Field(description="Height of the area in pixels.", ge=0)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RuntimeMetrics(DslModel):
|
|
13
|
+
model_config = pydantic.ConfigDict(
|
|
14
|
+
extra='allow',
|
|
15
|
+
frozen=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Board
|
|
19
|
+
display_area: PixelArea = pydantic.Field(description="Metrics of the display area in which the board is rendered.")
|
|
20
|
+
viewport_area: PixelArea = pydantic.Field(description="Metrics of the viewport in which the board is rendered.")
|
|
21
|
+
board_area: PixelArea = pydantic.Field(description="Metrics of the board area in which the cards are rendered.")
|
|
22
|
+
|
|
23
|
+
# User agent string
|
|
24
|
+
user_agent: str = pydantic.Field(description="User agent string of the browser or application rendering the board.")
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Literal, Union, Annotated
|
|
2
|
+
|
|
3
|
+
import pydantic
|
|
4
|
+
|
|
5
|
+
from nodekit._internal.models.node_engine.base import DslModel, NullValue
|
|
6
|
+
from nodekit._internal.models.node_engine.sensors.actions.base import BaseAction
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# %%
|
|
10
|
+
|
|
11
|
+
class ClickAction(BaseAction):
|
|
12
|
+
"""
|
|
13
|
+
A fully-qualified description of a Sensor emission.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
class Value(DslModel):
|
|
17
|
+
"""
|
|
18
|
+
A fully-qualified description of a Sensor emission.
|
|
19
|
+
"""
|
|
20
|
+
click_x: float = pydantic.Field(description='The x-coordinate of the click, in Board units.')
|
|
21
|
+
click_y: float = pydantic.Field(description='The y-coordinate of the click, in Board units.')
|
|
22
|
+
|
|
23
|
+
action_type: Literal['ClickAction'] = 'ClickAction'
|
|
24
|
+
action_value: Value
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# %%
|
|
28
|
+
class DoneAction(BaseAction):
|
|
29
|
+
action_type: Literal['DoneAction'] = 'DoneAction'
|
|
30
|
+
action_value: NullValue = pydantic.Field(default_factory=NullValue, frozen=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# %%
|
|
34
|
+
class TimeoutAction(BaseAction):
|
|
35
|
+
action_type: Literal['TimeoutAction'] = 'TimeoutAction'
|
|
36
|
+
action_value: NullValue = pydantic.Field(default_factory=NullValue, frozen=True)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# %%
|
|
40
|
+
Action = Annotated[
|
|
41
|
+
Union[
|
|
42
|
+
ClickAction,
|
|
43
|
+
DoneAction,
|
|
44
|
+
TimeoutAction,
|
|
45
|
+
# Add other Action types here as needed
|
|
46
|
+
],
|
|
47
|
+
pydantic.Field(discriminator='action_type')
|
|
48
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import pydantic
|
|
5
|
+
|
|
6
|
+
from nodekit._internal.models.node_engine.base import DslModel
|
|
7
|
+
from nodekit._internal.models.node_engine.fields import TimePointMsec, SensorId
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BaseAction(DslModel, ABC):
|
|
11
|
+
sensor_id: SensorId = pydantic.Field(
|
|
12
|
+
description='Identifier of the Sensor that emitted this Action.'
|
|
13
|
+
)
|
|
14
|
+
action_type: str
|
|
15
|
+
action_value: Any
|
|
16
|
+
reaction_time_msec: TimePointMsec = pydantic.Field(
|
|
17
|
+
description='Measured from the onset of the earliest possible time the Action could be emitted.'
|
|
18
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import pydantic
|
|
5
|
+
|
|
6
|
+
from nodekit._internal.models.node_engine.base import DslModel
|
|
7
|
+
from nodekit._internal.models.node_engine.fields import Timespan, SensorId, CardId
|
|
8
|
+
from uuid import uuid4
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseSensor(DslModel, ABC):
|
|
12
|
+
"""
|
|
13
|
+
A Sensor represents a listener for Participant behavior. Sensors are bound to a specific Card, or to the Board.
|
|
14
|
+
When a Sensor is triggered, it emits a fully qualified Action.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Sensor
|
|
18
|
+
sensor_id: SensorId = pydantic.Field(default_factory=uuid4)
|
|
19
|
+
sensor_type: str
|
|
20
|
+
sensor_parameters: Any
|
|
21
|
+
# Temporal
|
|
22
|
+
sensor_timespan: Timespan
|
|
23
|
+
|
|
24
|
+
# Sensor target
|
|
25
|
+
card_id: CardId | None = pydantic.Field(description='Identifier of the Entity (Card or Board) that this Sensor is attached to.')
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Literal, Union, Annotated
|
|
2
|
+
|
|
3
|
+
import pydantic
|
|
4
|
+
|
|
5
|
+
from nodekit._internal.models.node_engine.base import DslModel, NullParameters
|
|
6
|
+
from nodekit._internal.models.node_engine.fields import TimeDurationMsec
|
|
7
|
+
from nodekit._internal.models.node_engine.sensors.base import BaseSensor
|
|
8
|
+
|
|
9
|
+
from nodekit._internal.models.node_engine.fields import CardId
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# %%
|
|
13
|
+
class TimeoutSensor(BaseSensor):
|
|
14
|
+
"""
|
|
15
|
+
Attaches to the Board and triggers an Action after a specified timeout period.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
class TimeoutSensorParameters(DslModel):
|
|
19
|
+
timeout_msec: TimeDurationMsec
|
|
20
|
+
|
|
21
|
+
sensor_type: Literal['TimeoutSensor'] = 'TimeoutSensor'
|
|
22
|
+
sensor_parameters: TimeoutSensorParameters
|
|
23
|
+
card_id: None = pydantic.Field(default=None, frozen=True) # Only binds to Board
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# %%
|
|
27
|
+
class DoneSensor(BaseSensor):
|
|
28
|
+
sensor_type: Literal['DoneSensor'] = 'DoneSensor'
|
|
29
|
+
sensor_parameters: NullParameters = pydantic.Field(default_factory=NullParameters, frozen=True)
|
|
30
|
+
card_id: CardId = pydantic.Field(default=None, frozen=True) # Only binds to Card
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# %%
|
|
34
|
+
class ClickSensor(BaseSensor):
|
|
35
|
+
sensor_type: Literal['ClickSensor'] = pydantic.Field(default='ClickSensor', frozen=True)
|
|
36
|
+
sensor_parameters: NullParameters = pydantic.Field(default_factory=NullParameters, frozen=True)
|
|
37
|
+
card_id: CardId = pydantic.Field(default=None, frozen=True) # Only binds to Card
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# %%
|
|
41
|
+
Sensor = Annotated[
|
|
42
|
+
Union[
|
|
43
|
+
TimeoutSensor,
|
|
44
|
+
DoneSensor,
|
|
45
|
+
ClickSensor,
|
|
46
|
+
# Add other Sensor types here as needed
|
|
47
|
+
],
|
|
48
|
+
pydantic.Field(discriminator='sensor_type')
|
|
49
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from nodekit._internal.models.node_engine.bonus_policy import BonusRule, ConstantBonusRule
|
|
5
|
+
from nodekit._internal.models.node_engine.node_graph import NodeResult
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# %% BonusPolicy Rule Engine
|
|
9
|
+
def compute_bonus(
|
|
10
|
+
bonus_rules: List[BonusRule],
|
|
11
|
+
node_results: List[NodeResult]
|
|
12
|
+
) -> Decimal:
|
|
13
|
+
|
|
14
|
+
calculated_amount = Decimal('0')
|
|
15
|
+
|
|
16
|
+
for node_result in node_results:
|
|
17
|
+
action = node_result.action
|
|
18
|
+
|
|
19
|
+
# Perform scan through rules
|
|
20
|
+
for rule in bonus_rules:
|
|
21
|
+
# Dynamic dispatch
|
|
22
|
+
if isinstance(rule, ConstantBonusRule):
|
|
23
|
+
rule: ConstantBonusRule
|
|
24
|
+
if action.sensor_id == rule.bonus_rule_parameters.sensor_id:
|
|
25
|
+
# Check currency match
|
|
26
|
+
calculated_amount += Decimal(rule.bonus_rule_parameters.bonus_amount_usd)
|
|
27
|
+
|
|
28
|
+
# Clip at minimum of 0:
|
|
29
|
+
if calculated_amount < Decimal('0'):
|
|
30
|
+
calculated_amount = Decimal('0.00')
|
|
31
|
+
|
|
32
|
+
return calculated_amount
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"EventTypeEnum",
|
|
3
|
+
"Event",
|
|
4
|
+
|
|
5
|
+
# Concrete classes:
|
|
6
|
+
"StartEvent",
|
|
7
|
+
"EndEvent",
|
|
8
|
+
"NodeResultEvent",
|
|
9
|
+
|
|
10
|
+
# Client-server models:
|
|
11
|
+
"SubmitEventRequest",
|
|
12
|
+
"SubmitEventResponse",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
from nodekit._internal.compilers.events import (
|
|
16
|
+
Event,
|
|
17
|
+
StartEvent,
|
|
18
|
+
EndEvent,
|
|
19
|
+
NodeResultEvent,
|
|
20
|
+
SubmitEventRequest,
|
|
21
|
+
SubmitEventResponse,
|
|
22
|
+
EventTypeEnum,
|
|
23
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
# Reusable structural types used as field values in models:
|
|
3
|
+
'TextContent',
|
|
4
|
+
'Board',
|
|
5
|
+
'BoardRectangle',
|
|
6
|
+
'BoardLocation',
|
|
7
|
+
'Timespan',
|
|
8
|
+
|
|
9
|
+
'RuntimeMetrics',
|
|
10
|
+
'PixelArea',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
from nodekit._internal.models.node_engine.fields import (
|
|
14
|
+
TextContent,
|
|
15
|
+
BoardRectangle,
|
|
16
|
+
BoardLocation,
|
|
17
|
+
Timespan,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from nodekit._internal.models.node_engine.runtime_metrics import (
|
|
21
|
+
PixelArea,
|
|
22
|
+
RuntimeMetrics,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from nodekit._internal.models.node_engine.board import Board
|
|
26
|
+
|
|
27
|
+
|