/
models.py
173 lines (134 loc) · 5.8 KB
/
models.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
170
171
172
173
#!/usr/bin/env python
# * coding: utf8 *
'''
models.py
A module that contains the model classes for forklift
'''
import logging
import settings
from pprint import PrettyPrinter
from os.path import join
pprinter = PrettyPrinter()
class Pallet(object):
'''A module that contains the base class that should be inherited from when building new pallet classes.
Pallets are plugins for the forklift main process. They define a list of crates and
any post processing that needs to happen.
'''
def __init__(self):
#: the logging module to keep track of the pallet
self.log = logging.getLogger(settings.LOGGER)
#: the table names for all dependent data for an application
self._crates = []
def process(self):
'''This method will be called by forklift if any of the crates data is modified
'''
return NotImplemented
def ship(self):
'''this method fires whether the crates have any updates or not
'''
return NotImplemented
def get_crates(self):
'''returns an array of crates affected by the pallet. This is a self documenting way to know what layers an
application is using.
set `self.crates` in your child pallet.
'''
return self._crates
def add_crates(self, crate_infos, defaults={}):
crate_param_names = ['source_name', 'source_workspace', 'destination_workspace', 'destination_name']
for info in crate_infos:
params = defaults.copy()
#: info can be a table name here instead of a tuple
if isinstance(info, basestring):
params['source_name'] = info
else:
for i, val in enumerate(info):
params[crate_param_names[i]] = val
self._crates.append(Crate(**params))
def add_crate(self, crate_info):
self.add_crates([crate_info])
def validate_crate(self, crate):
'''override to provide your own validation to determine whether the data within
a create is ready to be updated
this method should return a boolean indicating if the crate is ready for an update
if this method is not overriden then the default validate within core is used
'''
return NotImplemented
def is_ready_to_ship(self):
'''checks to see if there are any schema changes or errors within the crates
associated with this pallet
returns: Boolean
Returns True if there are no crates defined
'''
for crate in self._crates:
if crate.result in [Crate.INVALID_DATA, Crate.UNHANDLED_EXCEPTION]:
return False
return True
def requires_processing(self):
'''checks to see if any of the crates were updated
returns: Boolean
Returns False if there are no crates defined
'''
has_updated = False
for crate in self._crates:
if crate.result in [Crate.INVALID_DATA, Crate.UNHANDLED_EXCEPTION]:
return False
if not has_updated:
has_updated = crate.result == Crate.UPDATED
return has_updated
def get_report(self):
'''returns a message about the result of each crate in the plugin'''
return ['{}: {}'.format(c.destination, c.result) for c in self.get_crates()]
def __repr__(self):
return pprinter.pformat({
'crates': self._crates,
'is_ready_to_ship': self.is_ready_to_ship(),
'requires_processing': self.requires_processing()
})
class Crate(object):
'''A module that defines a source and destination dataset that is a dependency of a pallet
'''
#: possible results returned from core.update_crate
CREATED = 'Created table successfully.'
UPDATED = 'Data updated successfully.'
INVALID_DATA = 'Data is invalid.'
NO_CHANGES = 'No changes found.'
UNHANDLED_EXCEPTION = 'Unhandled exception during update.'
UNINITIALIZED = 'This crate was never processed.'
def __init__(self,
source_name,
source_workspace,
destination_workspace,
destination_name=None,
destination_coordinate_system=None,
geographic_transformation=None):
#: the name of the source data table
self.source_name = source_name
#: the name of the source database
self.source_workspace = source_workspace
#: the name of the destination database
self.destination_workspace = destination_workspace
#: the name of the output data table
self.destination_name = destination_name or source_name
#: the result of the core.update method being called on this crate
self.result = self.UNINITIALIZED
#: optional definition of destination coordinate system to support reprojecting
self.destination_coordinate_system = destination_coordinate_system
#: optional geographic transformation to support reprojecting
self.geographic_transformation = geographic_transformation
self.source = join(source_workspace, source_name)
self.destination = join(destination_workspace, self.destination_name)
def set_result(self, value):
self.result = value
return value
def __repr__(self):
return pprinter.pformat({
'source': self.source,
'destination': self.destination,
'result': self.result,
'source_name': self.source_name,
'source_workspace': self.source_workspace,
'destination_name': self.destination_name,
'destination_workspace': self.destination_workspace,
'destination_coordinate_system': self.destination_coordinate_system,
'geographic_transformation': self.geographic_transformation
})