StateMachine   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 141
rs 10
wmc 24

11 Methods

Rating   Name   Duplication   Size   Complexity  
A is_succeeded() 0 3 1
A eval() 0 14 2
A __init__() 0 4 1
A is_failed() 0 3 1
A __ev_start() 0 20 4
A __ev_abort() 0 5 2
A __ev_skip() 0 2 1
B _run_event() 0 33 5
A __ev_scheduled() 0 12 2
A __ev_completed() 0 9 2
A __ev_load() 0 6 3
1
from __future__ import (
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
    absolute_import,
3
    division,
4
    print_function
5
)
6
7
import json
8
import logging
9
10
from .schema import ValidationError
11
from .state import State
12
from .step_results import (
13
    ActivityStepResult,
14
    TemplatedStepResult,
15
)
16
17
_LOGGER = logging.getLogger(__name__)
18
19
20
class StateMachine(object):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
21
22
    __slots__ = ('plan', 'state', '_event_ids')
23
24
    def __init__(self, plan):
25
        self.plan = plan
26
        self.state = None
27
        self._event_ids = {}
28
29
    ###########################################################################
30
    # Accessors
31
    @property
32
    def is_failed(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
33
        return self.state.is_in_state('failed')
34
35
    @property
36
    def is_succeeded(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
37
        return self.state.is_in_state('succeeded')
38
39
    ###########################################################################
40
    def eval(self, events):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
41
        # First clear the state
42
        self.state = State()
43
        self._event_ids.clear()
44
45
        # Inject a load plan event
46
        self._run_event({'eventId': 0, 'eventType': 'PlanLoad'})
47
48
        # Then, replay the state from the events
49
        for event in events:
50
            results = self._run_event(event)
51
52
        _LOGGER.info('State replayed from events: %r', self.state)
53
        return results
54
55
    ###########################################################################
56
    def _run_event(self, event):
57
        """Process a given event and return a list of results.
58
        """
59
        _LOGGER.info('Processing event %r', event['eventType'])
60
61
        handler_fun = getattr(
62
            self,
63
            'EVENT_%s' % event['eventType'],
64
            self.__ev_abort
65
        )
66
        handler_fun(event)
67
68
        # If there is nothing left to do, stop here
69
        if self.state.is_in_state('completed'):
70
            return []
71
72
        _LOGGER.info('Running all "ready" steps')
73
        ready_steps = self.state.step_next()
74
        _LOGGER.info('Next steps: %r', ready_steps)
75
76
        results = []
77
        for step in ready_steps:
78
            step_result = step.run()
79
            _LOGGER.info('step_result: %r', step_result)
80
            if isinstance(step_result, ActivityStepResult):
81
                results.append(step_result)
82
83
            elif isinstance(step_result, TemplatedStepResult):
84
                #results.append(step_result)
85
                raise Exception('Not implemented')
86
87
        _LOGGER.info('Results: %r', results)
88
        return results
89
90
    ###########################################################################
91
    # Events and handlers
92
    def __ev_load(self, event):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
93
        # Create loading time steps from the plan
94
        with self.state(event['eventId']):
95
            # Import all predefined steps from the plan
96
            for step in self.plan.steps:
97
                self.state.step_insert(step)
98
99
    def __ev_skip(self, event):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
100
        _LOGGER.info('Skipping event: %r', event['eventType'])
101
102
    def __ev_abort(self, event):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
103
        _LOGGER.error('Unknown event: %r', event)
104
        with self.state(event['eventId']):
105
            # Set the input
106
            self.state.set_abort()
107
108
    def __ev_start(self, event):
109
        """Import input data"""
110
        _LOGGER.info('%r', event)
111
        start_attrs = event['workflowExecutionStartedEventAttributes']
112
        # Note that if no input was provided, the 'input' key will not be there
113
        wf_input = start_attrs.get('input', 'null')
114
        try:
115
            input_data = json.loads(wf_input)
116
            self.plan.check_input(input_data)
117
118
        except (ValueError, ValidationError):
119
            _LOGGER.exception('Invalid workflow input: %r', wf_input)
120
            # We cannot do anything, just abort
121
            with self.state(event['eventId']):
122
                self.state.set_abort()
123
            return
124
125
        with self.state(event['eventId']):
126
            # Set the input
127
            self.state.set_input(input_data)
128
129
    def __ev_scheduled(self, event):
130
        """Record the eventId associated with activities we scheduled."""
131
        _LOGGER.info('%r', event)
132
        step_name = event['activityTaskScheduledEventAttributes']['activityId']
133
        event_id = event['eventId']
134
135
        with self.state(event['eventId']):
136
            self.state.step_update(step_name, 'running')
137
138
        _LOGGER.info('Associating step %r with event_id %r',
139
                      step_name, event_id)
140
        self._event_ids[event_id] = step_name
141
142
    def __ev_completed(self, event):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
143
        _LOGGER.info('%r', event)
144
        completed_event = event['activityTaskCompletedEventAttributes']
145
        output_json = completed_event.get('result', 'null')
146
        output = json.loads(output_json)
147
        sched_event_id = completed_event['scheduledEventId']
148
        step_name = self._event_ids[sched_event_id]
149
        with self.state(event['eventId']):
150
            self.state.step_update(step_name, 'succeeded', output)
151
152
    EVENT_PlanLoad = __ev_load
153
    EVENT_WorkflowExecutionStarted = __ev_start
154
    EVENT_DecisionTaskScheduled = __ev_skip
155
    EVENT_DecisionTaskStarted = __ev_skip
156
    EVENT_DecisionTaskCompleted = __ev_skip
157
    EVENT_DecisionTaskTimedOut = __ev_skip
158
    EVENT_ActivityTaskScheduled = __ev_scheduled
159
    EVENT_ActivityTaskStarted = __ev_skip
160
    EVENT_ActivityTaskCompleted = __ev_completed
161