Completed
Pull Request — master (#68)
by Jace
03:27
created

mine/models/status.py (3 issues)

1
"""Data structures for application/computer status."""
2
3 1
import functools
4 1
import logging
5
6 1
import yorm
0 ignored issues
show
The import yorm could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
7
8 1
from .timestamp import Timestamp
9
10 1
log = logging.getLogger(__name__)
11
12
13 1
def log_running(func):
14
    """Decorator for methods that return application status."""
15 1
    @functools.wraps(func)
16
    def wrapped(self, application, computer):
17
        """Wrapped method to log if an application is running."""
18 1
        running = func(self, application, computer)
19 1
        log.debug("%s marked as %s on: %s",
20
                  application, "started" if running else "stopped", computer)
21 1
        return running
22 1
    return wrapped
23
24
25 1
def log_starting(func):
26
    """Decorator for methods that mark an application as started."""
27 1
    @functools.wraps(func)
28
    def wrapped(self, application, computer):
29
        """Wrapped method to log that an application is started."""
30 1
        log.debug("Marking %s as started on %s...", application, computer)
31 1
        result = func(self, application, computer)
32 1
        log.debug("%s marked as started on: %s", application, computer)
33 1
        return result
34 1
    return wrapped
35
36
37 1
def log_stopping(func):
38
    """Decorator for methods that mark an application as stopped."""
39 1
    @functools.wraps(func)
40
    def wrapped(self, application, computer):
41
        """Wrapped method to log that an application is stopped."""
42 1
        log.debug("Marking %s as stopped on %s...", application, computer)
43 1
        result = func(self, application, computer)
44 1
        log.debug("%s marked as stopped on: %s", application, computer)
45 1
        return result
46 1
    return wrapped
47
48
49 1
@yorm.attr(computer=yorm.types.String)
50 1
@yorm.attr(timestamp=Timestamp)
51 1
class State(yorm.types.AttributeDictionary):
52
    """Dictionary of computer state."""
53
54 1
    def __init__(self, computer, timestamp=None):
55 1
        super().__init__()
56 1
        self.computer = computer
57 1
        self.timestamp = timestamp or Timestamp()
58
59 1
    def __str__(self):
60 1
        return str(self.computer)
61
62 1
    def __lt__(self, other):
63 1
        return str(self.computer).lower() < str(other.computer).lower()
64
65
66 1
@yorm.attr(all=State)
0 ignored issues
show
This class has no __init__ method.
Loading history...
67 1
class StateList(yorm.types.SortedList):
68
    """List of computer states for an application."""
69
70
71 1
@yorm.attr(application=yorm.types.String)
72 1
@yorm.attr(computers=StateList)
73 1
@yorm.attr(next=yorm.types.NullableString)
74 1
class Status(yorm.types.AttributeDictionary):
75
    """Dictionary of computers using an application."""
76
77 1
    def __init__(self, application, computers=None, next=None):  # pylint: disable=redefined-builtin
78 1
        super().__init__()
79 1
        self.application = application
80 1
        self.computers = computers or StateList()
81 1
        self.next = next
82
83 1
    def __str__(self):
84 1
        return str(self.application)
85
86 1
    def __lt__(self, other):
87 1
        return str(self.application).lower() < str(other.application).lower()
88
89
90 1
@yorm.attr(all=Status)
0 ignored issues
show
This class has no __init__ method.
Loading history...
91 1
class StatusList(yorm.types.SortedList):
92
    """List of application statuses."""
93
94
95 1
@yorm.attr(applications=StatusList)
96 1
@yorm.attr(counter=yorm.types.Integer)
97 1
class ProgramStatus(yorm.types.AttributeDictionary):
98
    """Dictionary of current program status."""
99
100 1
    def __init__(self, applications=None, counter=0):
101 1
        super().__init__()
102 1
        self.applications = applications or StatusList()
103 1
        self.counter = counter
104
105 1
    def find(self, application):
106
        """Return the application status for an application."""
107 1
        for app_status in self.applications:
108 1
            if app_status.application == application.name:
109 1
                break
110
        else:
111 1
            app_status = Status(application.name)
112 1
            self.applications.append(app_status)
113 1
        return app_status
114
115 1
    def get_latest(self, application):
116
        """Get the last computer's name logged as running an application."""
117 1
        for status in self.applications:
118 1
            if status.application == application.name:
119 1
                states = [s for s in status.computers if s.timestamp.active]
120 1
                if states:
121 1
                    states.sort(key=lambda s: s.timestamp, reverse=True)
122 1
                    log.debug("%s marked as started on: %s", application,
123
                              ', '.join(str(s) for s in states))
124
                    # TODO: consider returning the computer instance?
125 1
                    return states[0].computer
126
127 1
        log.debug("marked as started on: nothing")
128 1
        return None
129
130 1
    @log_running
131
    def is_running(self, application, computer):
132
        """Determine if an application is logged as running on a computer."""
133 1
        for status in self.applications:
134 1
            if status.application == application.name:
135 1
                for state in status.computers:
136 1
                    if state.computer == computer.name:
137 1
                        return state.timestamp.active
138
139
        # Status not found, assume the application is not running
140 1
        return False
141
142 1
    def queue(self, application, computer):
143
        """Record an application as queued for launch on a computer."""
144 1
        status = self.find(application)
145 1
        status.next = computer.name
146
147 1
    @log_starting
148
    def start(self, application, computer):
149
        """Record an application as running on a computer."""
150 1
        for status in self.applications:
151 1
            if status.application == application.name:
152 1
                for state in status.computers:
153 1
                    if state.computer == computer.name:
154 1
                        self.counter += 1
155 1
                        state.timestamp.started = self.counter
156 1
                        return
157 1
                break
158
        else:
159 1
            status = None
160
161
        # Status not found, add the application/computer as started
162 1
        self.counter += 1
163 1
        state = State(computer.name)
164 1
        state.timestamp.started = self.counter
165 1
        if status is None:
166 1
            status = Status(application.name)
167 1
            status.computers.append(state)
168 1
            self.applications.append(status)
169
        else:
170 1
            status.computers.append(state)
171
172 1
    @log_stopping
173
    def stop(self, application, computer):
174
        """Record an application as no longer running on a computer."""
175 1
        for status in self.applications:
176 1
            if status.application == application.name:
177 1
                for state in status.computers:
178 1
                    if state.computer == computer.name:
179 1
                        self.counter += 1
180 1
                        state.timestamp.stopped = self.counter
181 1
                        return
182 1
                break
183
        else:
184 1
            status = None
185
186
        # Status not found, add the application/computer as stopped
187 1
        self.counter += 1
188 1
        state = State(computer.name)
189 1
        state.timestamp.stopped = self.counter
190 1
        if status is None:
191 1
            status = Status(application.name)
192 1
            status.computers.append(state)
193 1
            self.applications.append(status)
194
        else:
195
            status.computers.append(state)
196