-
Notifications
You must be signed in to change notification settings - Fork 4
/
strategy.py
executable file
·169 lines (140 loc) · 5.19 KB
/
strategy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from Engine.common import *
class StrategyError(PeachException):
"""Strategy Exception"""
pass
class RouteDescriptor(object):
"""Used to describe the route."""
def __init__(self):
self.paths = []
self.index = 0
def addPath(self, path):
if path is None:
raise PeachException("Argument 'path' cannot be None!")
self.paths.append(path)
def reset(self):
self.index = 0
def clear(self):
del self.paths[:]
def hasNextSingle(self):
"""
This method is handy when there is no pair but only a path.
"""
return len(self.paths) == 1 and self.index < len(self.paths)
def nextSingle(self):
"""
To get the current path.
"""
if not self.hasNextSingle():
raise PeachException("End of the route description is reached!")
self.index += 1
return self.paths[self.index - 1]
def hasNextPair(self):
"""
Returns True when it has two paths more to visit otherwise False.
"""
return self.index < len(self.paths) - 1
def nextPair(self):
"""
Returns the next pair which strategy will find a proper path in
between. If hasNextPair() returns False then this method completes
the pair to be returned with a None and yields the result.
"""
if not self.hasNextPair():
raise PeachException("End of the route-pairs is reached!")
self.index += 1
return [self.paths[self.index - 1], self.paths[self.index]]
class Strategy(object):
"""
Strategy is an abstract class that is used to define a method to find out
a route between start and destination paths.
"""
def __init__(self, stateMachine, routeDescriptor, params=None):
self.params = {}
if params is not None:
self.params = params
if routeDescriptor is None:
raise PeachException("Argument 'routeDescriptor' cannot be None!")
self.routeDesc = routeDescriptor
self.stateMachine = stateMachine
def getRoute(self):
"""
This method invokes abstract _findRoute method for each pair taken
from routeDescriptor to obtain a proper route and finally returns
the route.
"""
route = []
while self.routeDesc.hasNextPair():
start, destination = self.routeDesc.nextPair()
partialRoute = self._findRoute(start, destination)
if len(route) == 0:
route.extend(partialRoute)
else:
route.extend(partialRoute[1:])
if self.routeDesc.hasNextSingle():
lastPath = self.routeDesc.nextSingle()
route.extend(self._findRoute(lastPath, None))
return route
def _findRoute(self, start, destination):
"""
This method is used to explore a route(list of paths) in between
start and destination paths.
:param start: start path
:param destination: destination path
:returns: a list of paths starting with parameter start and ending
with parameter destination.
"""
pass
def _reset(self):
"""
Used to reset a strategy especially when re-discovering the route.
"""
self.routeDesc.reset()
class StrategyCollection(Strategy):
"""
This class behaves like a proxy between strategies defined in XML file,
which is used to run all the strategies respectively to produce a
resultant route.
"""
def __init__(self):
Strategy.__init__(self, None, RouteDescriptor())
self.strategies = []
self.route = None
def addStrategy(self, strategy):
self.strategies.append(strategy)
# Re-explore the route as we have a new strategy.
self._reset()
def getRoute(self):
if self.route is not None:
return self.route
self.route = []
for strategy in self.strategies:
self.route.extend(strategy.getRoute())
return self.route
def _reset(self):
self.route = None
for strategy in self.strategies:
strategy._reset()
class StrategyFactory(object):
"""
To centralize the creation of strategies.
"""
def __init__(self, defStrategy="default.StaticStrategy"):
self.defStrategy = defStrategy
def createStrategy(self, stateMachine, routeDescriptor,
clazz=None, params=None):
if clazz is None:
clazz = self.defStrategy
try:
code = clazz + "(stateMachine, routeDescriptor, params)"
print("StrategyFactory.createStrategy: {}".format(code))
strategy = eval(code)
if strategy is None:
raise PeachException("Unable to create Strategy [{}]"
.format(clazz))
return strategy
except:
raise PeachException("Unable to create Strategy [{}]"
.format(clazz))