-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathStorage.py
More file actions
203 lines (163 loc) · 5.87 KB
/
Storage.py
File metadata and controls
203 lines (163 loc) · 5.87 KB
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
pyDKB.storages.Storage
"""
import sys
from datetime import datetime
from exceptions import (StorageNotConfigured,
QueryError)
class Storage(object):
""" Interface class for external and internal DKB storages. """
# Storage name (identifier)
name = None
# Storage type (storageType member)
type = None
# Storage client
c = None
# Stored queries
stored_queries = {}
def __init__(self, name):
""" Initialize Storage object.
Raise ``StorageException`` in case of error.
:param name: storage identifier
:type name: str
"""
self.name = name
def log(self, level, message):
""" Output log message. """
if level not in ('TRACE', 'DEBUG', 'INFO', 'WARN', 'WARNING', 'ERROR',
'CRITICAL'):
level = 'INFO'
dt = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
sys.stderr.write('(%s) %s (%s) %s\n' % (level, dt,
self.__class__.__name__,
message))
def log_cfg(self, cfg, defaults={}):
""" Log storage configuration.
:param cfg: configuration to be logged
:type cfg: dict
:param defaults: default parameter values, if any (will be logged only
if the parameter is missed in ``cfg``)
:type defaults: dict
"""
fname = ''
if cfg.get('__file'):
fname = ' (%s)' % cfg['__file']
self.log("INFO", "'%s' storage configuration%s:" % (self.name, fname))
key_len = len(max(cfg.keys() + defaults.keys(), key=len))
pattern = "%%-%ds : '%%s'" % key_len
self.log("INFO", "---")
for key in set(cfg.keys() + defaults.keys()):
if key.startswith('__'):
continue
self.log("INFO", pattern % (key, cfg.get(key, defaults.get(key))))
self.log("INFO", "---")
def configure(self, cfg):
""" Apply storage configuration (initialize client).
:param cfg: configuration parameters
:type cfg: dict
"""
raise NotImplementedError
def client(self):
""" Get storage client.
Raise ``StorageNotConfigured`` if called before configuration.
:return: client object, corresponding given storage type.
:rtype: object
"""
if not self.c:
raise StorageNotConfigured(self.name)
return self.c
def get(self, id, **kwargs):
""" Get object / record from storage by ID.
Raise ``NotFound`` exception if object / record not found.
:param id: object / record identfier
:type id: str, int
:return: record with given ID
:rtype: dict
"""
raise NotImplementedError
def read_query(self, fname, qname=None):
""" Read query from file and save it.
:param fname: file name
:type fname: str
:param qname: query name (for futher usage)
:type qname: str
"""
raise NotImplementedError
def query_is_raw(self, query):
""" Check if given query is not compiled ("raw").
:param query: query body
:type query: obj
:return: True/False
:rtype: bool
"""
raise NotImplementedError
def save_query(self, query, qname=None, raw=False):
""" Save query for further usage.
:param query: query content
:type query: object
:param qname: query name (must not start with '__')
:type qname: str
:param raw: store "raw" (not compiled) version of query
:type raw: bool
"""
if qname and qname.startswith('__'):
raise ValueError("Query name must not start with '__'"
" (reserved for service needs).")
if not raw:
try:
raw = self.query_is_raw(query)
except NotImplementedError:
pass
prefix = ''
if not qname:
qname = '__last'
if raw:
prefix = '__raw'
self.stored_queries[prefix + qname] = query
self.stored_queries[prefix + '__last'] = query
def get_query(self, qname):
""" Get query by name.
Raise ``QueryError`` if query not found.
:param qname: query name (if None, last stored/used query will be used)
:type qnmae: str
:return: stored query
:rtype: object
"""
if not qname:
qname = '__last'
try:
q = self.stored_queries[qname]
self.stored_queries['__last'] = q
except KeyError:
# There still may be raw version of the query
try:
q = self.stored_queries['__raw' + qname]
except KeyError:
raise QueryError("Query used before saving: '%s'"
% qname)
self.stored_queries['__last'] = q
return q
def exec_query(self, qname=None, **kwargs):
""" Execute stored query with given parameters.
:param qname: query name (if None, last used/read
one will be used)
:type qname: str, NoneType
:param kwargs: query parameters (applied with old-style
string formatting operator '%')
:type kwargs: dict
:return: storage response
:rtype: object
"""
raise NotImplementedError
def execute(self, query, **kwargs):
""" Execute query with given parameters.
:param query: query content
:type query: object
:param kwargs: query parameters (applied with old-style
string formatting operator '%')
:type kwargs: dict
:return: storage response
:rtype: object
"""
self.save_query(query)
return self.exec_query(**kwargs)