dwho 0.3.60__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dwho/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ __all__ = []
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ __all__ = []
dwho/adapters/redis.py ADDED
@@ -0,0 +1,289 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ """dwho.adapters.redis"""
5
+
6
+ from __future__ import absolute_import
7
+
8
+ from six import iteritems, iterkeys
9
+ from six.moves.urllib.parse import urlparse, parse_qs
10
+
11
+ from redis import Redis
12
+
13
+
14
+ class DWhoAdapterRedis(object): # pylint: disable=useless-object-inheritance
15
+ def __init__(self, config, prefix = None, load = True):
16
+ self.config = config
17
+ self.servers = {}
18
+
19
+ if load:
20
+ self.load(prefix)
21
+
22
+ def load(self, prefix = None):
23
+ for name in iterkeys(self.config['general']['redis']):
24
+ if not prefix or name.startswith(prefix):
25
+ self.connect(name)
26
+
27
+ def connect(self, name):
28
+ if name not in self.servers:
29
+ self.servers[name] = {'conn': None, 'options': {}}
30
+
31
+ if self.servers[name]['conn']:
32
+ return self.servers[name]
33
+
34
+ has_from_url = hasattr(Redis, 'from_url')
35
+ for key, value in iteritems(self.config['general']['redis'][name]):
36
+ if key != 'url':
37
+ self.servers[name]['options'][key] = value
38
+ continue
39
+ elif has_from_url:
40
+ self.servers[name]['conn'] = Redis().from_url(value)
41
+ continue
42
+
43
+ p = urlparse(value)
44
+ rconf = {'host': p.hostname,
45
+ 'port': int(p.port or 6379),
46
+ 'db': 0}
47
+
48
+ if p.query:
49
+ q = parse_qs(p.query)
50
+ if 'db' in q:
51
+ rconf['db'] = int(q['db'][0])
52
+
53
+ self.servers[name]['conn'] = Redis(**rconf)
54
+
55
+ return self.servers[name]
56
+
57
+ def ping(self, servers = None, prefix = None):
58
+ r = {}
59
+
60
+ if not servers:
61
+ servers = self.servers
62
+
63
+ for name, server in iteritems(servers):
64
+ if not prefix or name.startswith(prefix):
65
+ r[name] = server['conn'].ping()
66
+
67
+ return r
68
+
69
+ def set_key(self, key, val, expire = None, servers = None, prefix = None):
70
+ r = {}
71
+
72
+ if not servers:
73
+ servers = self.servers
74
+
75
+ if expire is not None:
76
+ for name, server in iteritems(servers):
77
+ if not prefix or name.startswith(prefix):
78
+ r[name] = server['conn'].setex(name = key, time = expire, value = val)
79
+ else:
80
+ for name, server in iteritems(servers):
81
+ if not prefix or name.startswith(prefix):
82
+ r[name] = server['conn'].set(key, val)
83
+
84
+ return r
85
+
86
+ def get_key(self, key, servers = None, prefix = None):
87
+ if not servers:
88
+ servers = self.servers
89
+
90
+ for name, server in iteritems(servers):
91
+ if (not prefix or name.startswith(prefix)) \
92
+ and server['conn'].exists(key):
93
+ return server['conn'].get(key)
94
+
95
+ return None
96
+
97
+ def del_key(self, key, servers = None, prefix = None):
98
+ r = {}
99
+
100
+ if not servers:
101
+ servers = self.servers
102
+
103
+ if not isinstance(key, (list, tuple)):
104
+ key = [key]
105
+
106
+ for name, server in iteritems(servers):
107
+ if not prefix or name.startswith(prefix):
108
+ r[name] = server['conn'].delete(*key)
109
+
110
+ return r
111
+
112
+ def exists(self, key, servers = None, prefix = None):
113
+ r = {}
114
+
115
+ if not servers:
116
+ servers = self.servers
117
+
118
+ if not isinstance(key, (list, tuple)):
119
+ key = [key]
120
+
121
+ for name, server in iteritems(servers):
122
+ if not prefix or name.startswith(prefix):
123
+ r[name] = server['conn'].exists(*key)
124
+
125
+ return r
126
+
127
+ def expire(self, key, xtime, servers = None, prefix = None):
128
+ r = {}
129
+
130
+ if not servers:
131
+ servers = self.servers
132
+
133
+ for name, server in iteritems(servers):
134
+ if (not prefix or name.startswith(prefix)) \
135
+ and server['conn'].exists(key):
136
+ r[name] = server['conn'].expire(key, xtime)
137
+
138
+ return r
139
+
140
+ def hset_key(self, key, field, val, expire = None, servers = None, prefix = None):
141
+ r = {}
142
+
143
+ if not servers:
144
+ servers = self.servers
145
+
146
+ if expire is not None:
147
+ for name, server in iteritems(servers):
148
+ if not prefix or name.startswith(prefix):
149
+ r[name] = server['conn'].hset(key, field, val)
150
+ server['conn'].expire(key, expire)
151
+ else:
152
+ for name, server in iteritems(servers):
153
+ if not prefix or name.startswith(prefix):
154
+ r[name] = server['conn'].hset(key, field, val)
155
+
156
+ return r
157
+
158
+ def hget_key(self, key, field, servers = None, prefix = None):
159
+ if not servers:
160
+ servers = self.servers
161
+
162
+ for name, server in iteritems(servers):
163
+ if (not prefix or name.startswith(prefix)) \
164
+ and server['conn'].exists(key):
165
+ return server['conn'].hget(key, field)
166
+
167
+ return None
168
+
169
+ def hdel_key(self, key, field, servers = None, prefix = None):
170
+ r = {}
171
+
172
+ if not servers:
173
+ servers = self.servers
174
+
175
+ if not isinstance(field, (list, tuple)):
176
+ field = [field]
177
+
178
+ for name, server in iteritems(servers):
179
+ if not prefix or name.startswith(prefix):
180
+ r[name] = server['conn'].hdel(key, *field)
181
+
182
+ return r
183
+
184
+ def has_key(self, key, servers = None, prefix = None):
185
+ if not servers:
186
+ servers = self.servers
187
+
188
+ for name, server in iteritems(servers):
189
+ if not prefix or name.startswith(prefix):
190
+ return server['conn'].exists(key)
191
+
192
+ return None
193
+
194
+ def keys(self, pattern = '*', servers = None, prefix = None):
195
+ r = {}
196
+
197
+ if not servers:
198
+ servers = self.servers
199
+
200
+ for name, server in iteritems(servers):
201
+ if not prefix or name.startswith(prefix):
202
+ r[name] = server['conn'].keys(pattern)
203
+
204
+ return r
205
+
206
+ def sadd(self, key, member, servers = None, prefix = None):
207
+ r = {}
208
+
209
+ if not servers:
210
+ servers = self.servers
211
+
212
+ if not isinstance(member, (list, tuple)):
213
+ member = [member]
214
+
215
+ for name, server in iteritems(servers):
216
+ if not prefix or name.startswith(prefix):
217
+ r[name] = server['conn'].sadd(key, *member)
218
+
219
+ return r
220
+
221
+ def srem(self, key, member, servers = None, prefix = None):
222
+ r = {}
223
+
224
+ if not servers:
225
+ servers = self.servers
226
+
227
+ if not isinstance(member, (list, tuple)):
228
+ member = [member]
229
+
230
+ for name, server in iteritems(servers):
231
+ if not prefix or name.startswith(prefix):
232
+ r[name] = server['conn'].srem(key, *member)
233
+
234
+ return r
235
+
236
+ # pylint: disable=too-many-arguments
237
+ def sort(self, key, start = None, num = None, by = None, get = None,
238
+ desc = False, alpha = False, store = None,
239
+ servers = None, prefix = None):
240
+
241
+ r = {}
242
+
243
+ if not servers:
244
+ servers = self.servers
245
+
246
+ for name, server in iteritems(servers):
247
+ if not prefix or name.startswith(prefix):
248
+ r[name] = server['conn'].sort(name = key,
249
+ start = start,
250
+ num = num,
251
+ by = by,
252
+ get = get,
253
+ desc = desc,
254
+ alpha = alpha,
255
+ store = store)
256
+
257
+ return r
258
+
259
+ def disconnect(self, name = None, prefix = None, servers = None):
260
+ if not servers:
261
+ servers = self.servers
262
+
263
+ if name:
264
+ if not servers.get(name) or not servers[name]['conn']:
265
+ return self
266
+
267
+ try:
268
+ servers[name]['conn'].connection_pool.disconnect()
269
+ except Exception:
270
+ pass
271
+
272
+ servers[name]['conn'] = None
273
+
274
+ return self
275
+
276
+ for cname in iterkeys(self.config['general']['redis']):
277
+ if prefix and not cname.startswith(prefix):
278
+ continue
279
+ elif not servers.get(cname) or not servers[cname]['conn']:
280
+ continue
281
+
282
+ try:
283
+ servers[cname]['conn'].connection_pool.disconnect()
284
+ except Exception:
285
+ pass
286
+
287
+ servers[cname]['conn'] = None
288
+
289
+ return self
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ __all__ = []
@@ -0,0 +1,237 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ """dwho.classes.abstract"""
5
+
6
+ import abc
7
+ import re
8
+
9
+ try:
10
+ from threading import _get_ident as thread_get_ident
11
+ except ImportError:
12
+ from threading import get_ident as thread_get_ident
13
+
14
+ from threading import _active_limbo_lock, _active
15
+ from six import iterkeys, iteritems, string_types
16
+
17
+ from sonicprobe.libs import anysql
18
+
19
+ _RE_MATCH_OBJECT_FUNCS = ('match', 'search')
20
+ _PARAMS_DICT_MODIFIERS_MATCH = re.compile(r'^(?:(?P<modifiers>[\+\-~=%]+)\s)?(?P<key>.+)$').match
21
+ _PARAM_REGEX_OPTS = ('default', 'func', 'return', 'return_args')
22
+
23
+
24
+ class DWhoAbstractHelper(object): # pylint: disable=useless-object-inheritance,too-few-public-methods
25
+ __metaclass__ = abc.ABCMeta
26
+
27
+ @classmethod
28
+ def _parse_re_flags(cls, flags):
29
+ if isinstance(flags, int):
30
+ return flags
31
+
32
+ if isinstance(flags, list):
33
+ r = 0
34
+ for x in flags:
35
+ r |= cls._parse_re_flags(x)
36
+ return r
37
+
38
+ if isinstance(flags, string_types):
39
+ if flags.isdigit():
40
+ return int(flags)
41
+ return getattr(re, flags)
42
+
43
+ return 0
44
+
45
+ @classmethod
46
+ def _param_regex(cls, args, value):
47
+ args = args.copy()
48
+ func = args.get('func') or 'sub'
49
+ rfunc = args.get('return')
50
+ rargs = args.get('return_args')
51
+ is_match_obj = func in _RE_MATCH_OBJECT_FUNCS
52
+
53
+ if is_match_obj and not rfunc:
54
+ rfunc = 'group'
55
+ rargs = [1]
56
+
57
+ if is_match_obj and not rargs:
58
+ rargs = [1]
59
+
60
+ for x in _PARAM_REGEX_OPTS:
61
+ if x in args:
62
+ del args[x]
63
+
64
+ if 'pattern' in args:
65
+ flags = 0
66
+ if 'flags' in args:
67
+ flags = cls._parse_re_flags(args.pop('flags'))
68
+ func = getattr(re.compile(pattern = args.pop('pattern'),
69
+ flags = flags),
70
+ func)
71
+ else:
72
+ func = getattr(re, func)
73
+
74
+ args['string'] = value
75
+ ret = func(**args)
76
+
77
+ if ret is None:
78
+ return ''
79
+
80
+ if not rfunc:
81
+ return ret
82
+
83
+ if rargs:
84
+ return getattr(ret, rfunc)(*rargs)
85
+
86
+ return getattr(ret, rfunc)()
87
+
88
+ @classmethod
89
+ def _build_params_dict(cls, name, cfg, values = None, xvars = None, r = None):
90
+ if not isinstance(values, dict):
91
+ values = {}
92
+
93
+ if not isinstance(r, dict):
94
+ r = {}
95
+
96
+ if not cfg or not isinstance(cfg, list):
97
+ return r
98
+
99
+ fkwargs = {name: values.copy()}
100
+
101
+ if isinstance(xvars, dict):
102
+ fkwargs.update(xvars)
103
+
104
+ for elt in cfg:
105
+ ename = list(elt.keys())[0]
106
+ m = _PARAMS_DICT_MODIFIERS_MATCH(ename)
107
+ if m:
108
+ modifiers = m.group('modifiers') or '+'
109
+ key = m.group('key')
110
+ else:
111
+ modifiers = '+'
112
+ key = ename
113
+
114
+ if '+' in modifiers:
115
+ r[key] = elt[ename]
116
+ elif '-' in modifiers:
117
+ if key not in r:
118
+ continue
119
+ if elt[ename] in (None, r[key]):
120
+ del r[key]
121
+ elif '~' in modifiers:
122
+ args = elt[ename]
123
+
124
+ if key not in r:
125
+ r[key] = args.get('default') or ''
126
+ else:
127
+ r[key] = cls._param_regex(args, r[key])
128
+ elif '=' in modifiers:
129
+ if key in r:
130
+ r[elt[ename]] = r[key]
131
+
132
+ if '{' in modifiers and '}' in modifiers:
133
+ r[key] = r[key].format(**fkwargs)
134
+
135
+ return r
136
+
137
+
138
+ class DWhoAbstractDB(object): # pylint: disable=useless-object-inheritance
139
+ __metaclass__ = abc.ABCMeta
140
+
141
+ def __init__(self):
142
+ self.config = {}
143
+ self._db = {}
144
+
145
+ @property
146
+ def db(self):
147
+ thread_id = thread_get_ident()
148
+ if thread_id not in self._db:
149
+ self._db[thread_id] = {}
150
+
151
+ return self._db[thread_id]
152
+
153
+ @db.setter
154
+ def db(self, value):
155
+ with _active_limbo_lock:
156
+ for tid, db in iteritems(self._db):
157
+ if tid in _active:
158
+ continue
159
+
160
+ for name in iterkeys(db):
161
+ self.db_disconnect(name, db)
162
+
163
+ thread_id = thread_get_ident()
164
+ if thread_id not in self._db:
165
+ self._db[thread_id] = {}
166
+
167
+ self._db[thread_id] = value
168
+
169
+ def db_connect(self, name):
170
+ if name not in self.db:
171
+ self.db[name] = {'conn': None, 'cursor': None}
172
+
173
+ if not self.db[name]['conn'] or not self.db[name]['conn'].is_connected(self.db[name]['cursor']):
174
+ if self.db[name]['cursor']:
175
+ try:
176
+ self.db[name]['cursor'].close()
177
+ except Exception:
178
+ pass
179
+ self.db[name]['cursor'] = None
180
+
181
+ if self.db[name]['conn']:
182
+ try:
183
+ self.db[name]['conn'].close()
184
+ except Exception:
185
+ pass
186
+
187
+ self.db[name]['conn'] = anysql.connect_by_uri(self.config['general']["db_uri_%s" % name])
188
+
189
+ if not self.db[name]['cursor']:
190
+ self.db[name]['cursor'] = self.db[name]['conn'].cursor()
191
+
192
+ return self.db[name]
193
+
194
+ @staticmethod
195
+ def get_column_name(column):
196
+ return (".%s" % column).split('.', 2)[-1]
197
+
198
+ def db_prepare_column(self, res, column = None):
199
+ if column:
200
+ prep_method = "_prepcol_%s" % self.get_column_name(column)
201
+ if hasattr(self, prep_method):
202
+ return getattr(self, prep_method)(column, res)
203
+
204
+ if not isinstance(res, object) \
205
+ or res is None \
206
+ or isinstance(res, string_types):
207
+ return res
208
+
209
+ return "%s" % res
210
+
211
+ def db_disconnect(self, name, db = None):
212
+ if not db:
213
+ if not self.db:
214
+ self.db = {name: {'conn': None,
215
+ 'cursor': None}}
216
+ db = self.db
217
+
218
+ if not db:
219
+ return self
220
+
221
+ if db[name]['cursor']:
222
+ try:
223
+ db[name]['cursor'].close()
224
+ except Exception:
225
+ pass
226
+
227
+ db[name]['cursor'] = None
228
+
229
+ if db[name]['conn']:
230
+ try:
231
+ db[name]['conn'].close()
232
+ except Exception:
233
+ pass
234
+
235
+ db[name]['conn'] = None
236
+
237
+ return self
dwho/classes/errors.py ADDED
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2015-2019 Adrien Delle Cave
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ """dwho.classes.errors"""
5
+
6
+ from pyinotify import PyinotifyError
7
+
8
+
9
+ class DWhoError(Exception):
10
+ pass
11
+
12
+ class DWhoConfigurationError(DWhoError):
13
+ pass
14
+
15
+ class DWhoInotifyError(PyinotifyError):
16
+ pass