settings.py 23.9 KB
Newer Older
1 2 3 4 5 6 7
# -*- coding: utf-8 -*-
#
# This file is part of the bliss project
#
# Copyright (c) 2016 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.

8
from .conductor import client
9
from bliss.common.utils import Null
10
from bliss import setup_globals
Matias Guijarro's avatar
Matias Guijarro committed
11 12
import weakref
import pickle
13
import numpy
Matias Guijarro's avatar
Matias Guijarro committed
14

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
15

Matias Guijarro's avatar
Matias Guijarro committed
16 17 18
class InvalidValue(Null):
    def __str__(self):
        raise ValueError
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
19

Matias Guijarro's avatar
Matias Guijarro committed
20 21
    def __repr__(self):
        return '#ERR'
22

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
23

Matias Guijarro's avatar
Matias Guijarro committed
24
def get_cache():
25
    return client.get_cache(db=0)
Matias Guijarro's avatar
Matias Guijarro committed
26

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
27 28

def boolify(s, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
29
    if s == 'True' or s == 'true':
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
30
        return True
Matias Guijarro's avatar
Matias Guijarro committed
31
    if s == 'False' or s == 'false':
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
32
        return False
Matias Guijarro's avatar
Matias Guijarro committed
33 34
    raise ValueError('Not Boolean Value!')

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
35

Matias Guijarro's avatar
Matias Guijarro committed
36 37 38 39
def auto_conversion(var):
    '''guesses the str representation of the variables type'''
    if var is None:
        return None
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
40
    for caster in (boolify, int, float):
Matias Guijarro's avatar
Matias Guijarro committed
41 42
        try:
            return caster(var)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
43
        except (ValueError, TypeError):
Matias Guijarro's avatar
Matias Guijarro committed
44 45 46
            pass
    return var

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
47

48
def pickle_loads(var):
Matias Guijarro's avatar
Matias Guijarro committed
49 50
    if var is None:
        return None
Matias Guijarro's avatar
Matias Guijarro committed
51 52 53 54
    try:
        return pickle.loads(var)
    except Exception:
        return InvalidValue()
Matias Guijarro's avatar
Matias Guijarro committed
55

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
56 57

def ttl_func(cnx, name, value=-1):
Matias Guijarro's avatar
Matias Guijarro committed
58 59 60 61 62
    if value is None:
        return cnx.persist(name)
    elif value is -1:
        return cnx.ttl(name)
    else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
63 64
        return cnx.expire(name, value)

Matias Guijarro's avatar
Matias Guijarro committed
65

66
def read_decorator(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
67 68
    def _read(self, *args, **keys):
        value = func(self, *args, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
69
        if self._read_type_conversion:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
70
            if isinstance(value, list):
Matias Guijarro's avatar
Matias Guijarro committed
71
                value = [self._read_type_conversion(x) for x in value]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
72 73
            elif isinstance(value, dict):
                for k, v in value.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
74
                    value[k] = self._read_type_conversion(v)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
75
                if hasattr(self, 'default_values') and isinstance(self.default_values, dict):
76 77 78
                    tmp = dict(self._default_values)
                    tmp.update(value)
                    value = tmp
Matias Guijarro's avatar
Matias Guijarro committed
79
            else:
80 81
                if value is not None:
                    value = self._read_type_conversion(value)
82
        if value is None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
83
            if hasattr(self, '_default_value'):
84
                value = self._default_value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
85 86
            elif(hasattr(self, '_default_values') and
                 hasattr(self._default_values, 'get')):
87
                value = self._default_values.get(args[0])
Matias Guijarro's avatar
Matias Guijarro committed
88 89 90
        return value
    return _read

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
91

92
def write_decorator_dict(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
93
    def _write(self, values, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
94
        if self._write_type_conversion:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
95
            if not isinstance(values, dict) and values is not None:
Matias Guijarro's avatar
Matias Guijarro committed
96 97 98
                raise TypeError('can only be dict')

            if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
99
                for k, v in values.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
100
                    values[k] = self._write_type_conversion(v)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
101
        return func(self, values, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
102 103
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
104

105
def write_decorator_multiple(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
106
    def _write(self, values, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
107
        if self._write_type_conversion:
108 109
            if not isinstance(values, (list, tuple, numpy.ndarray)) and values is not None:
                raise TypeError('Can only be tuple, list or numpy array')
Matias Guijarro's avatar
Matias Guijarro committed
110 111
            if values is not None:
                values = [self._write_type_conversion(x) for x in values]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
112
        return func(self, values, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
113 114
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
115

116
def write_decorator(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
117
    def _write(self, value, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
118 119
        if self._write_type_conversion and value is not None:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
120
        return func(self, value, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
121 122
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
123 124

def scan(match='*', count=1000, connection=None):
125 126 127 128
    if connection is None:
        connection = get_cache()
    cursor = 0
    while 1:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
129 130
        cursor, values = connection.scan(cursor=cursor,
                                         match=match, count=count)
131 132 133 134
        for val in values:
            yield val
        if int(cursor) == 0:
            break
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
135 136


137
class SimpleSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
138 139 140 141
    def __init__(self, name, connection=None,
                 read_type_conversion=auto_conversion,
                 write_type_conversion=None,
                 default_value=None):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
142 143 144 145 146 147
        if connection is None:
            connection = get_cache()
        self._cnx = weakref.ref(connection)
        self._name = name
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
148
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
149

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
150
    @read_decorator
151
    def get(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
152 153 154 155 156
        cnx = self._cnx()
        value = cnx.get(self._name)
        return value

    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
157
    def set(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
158
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
159 160 161 162
        cnx.set(self._name, value)

    def ttl(self, value=-1):
        return ttl_func(self._cnx(), self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
163

164 165 166
    def clear(self):
        cnx = self._cnx()
        cnx.delete(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
167 168

    def __add__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
169
        value = self.get()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
170
        if isinstance(other, SimpleSetting):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
171 172 173
            other = other.get()
        return value + other

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
174
    def __iadd__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
175 176
        cnx = self._cnx()
        if cnx is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
177
            if isinstance(other, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
178 179
                if other == 1:
                    cnx.incr(self._name)
Matias Guijarro's avatar
Matias Guijarro committed
180
                else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
181 182 183
                    cnx.incrby(self._name, other)
            elif isinstance(other, float):
                cnx.incrbyfloat(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
184
            else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
185
                cnx.append(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
186
            return self
Matias Guijarro's avatar
Matias Guijarro committed
187

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
188 189 190 191
    def __isub__(self, other):
        if isinstance(other, basestring):
            raise TypeError("unsupported operand type(s) for -=: %s" %
                            type(other).__name__)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
192
        return self.__iadd__(-other)
Matias Guijarro's avatar
Matias Guijarro committed
193

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
194
    def __getitem__(self, ran):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
195 196 197
        cnx = self._cnx()
        if cnx is not None:
            step = None
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
198 199
            if isinstance(ran, slice):
                i, j = ran.start, ran.stop
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
200
                step = ran.step
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
201
            elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
202 203 204 205
                i = j = ran
            else:
                raise TypeError('indices must be integers')

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
206
            value = cnx.getrange(self._name, i, j)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
207 208 209 210 211 212 213
            if step is not None:
                value = value[0:-1:step]
            return value

    def __repr__(self):
        cnx = self._cnx()
        value = cnx.get(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
214 215
        return '<SimpleSetting name=%s value=%s>' % (self._name, value)

Matias Guijarro's avatar
Matias Guijarro committed
216

217
class SimpleSettingProp(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
218 219 220 221 222
    def __init__(self, name, connection=None,
                 read_type_conversion=auto_conversion,
                 write_type_conversion=None,
                 default_value=None,
                 use_object_name=True):
Matias Guijarro's avatar
Matias Guijarro committed
223 224 225 226
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
227
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
228 229
        self._use_object_name = use_object_name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
230
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
231 232 233 234
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
235
        return SimpleSetting(name, self._cnx,
236 237 238
                             self._read_type_conversion,
                             self._write_type_conversion,
                             self._default_value)
Matias Guijarro's avatar
Matias Guijarro committed
239

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
240 241 242
    def __set__(self, obj, value):
        if isinstance(value, SimpleSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
243 244 245 246 247 248 249 250 251 252 253

        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

        if value is None:
            self._cnx.delete(name)
        else:
            if self._write_type_conversion:
                value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
254 255
            self._cnx.set(name, value)

Matias Guijarro's avatar
Matias Guijarro committed
256 257

class QueueSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
258 259 260 261 262
    def __init__(self, name, connection=None,
                 read_type_conversion=auto_conversion,
                 write_type_conversion=None):
        if connection is None:
            connection = get_cache()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
263 264 265 266
        self._cnx = weakref.ref(connection)
        self._name = name
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
Matias Guijarro's avatar
Matias Guijarro committed
267

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
268
    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
269
    def get(self, first=0, last=-1):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
270 271
        cnx = self._cnx()
        if first == last:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
272
            l = cnx.lindex(self._name, first)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
273
        else:
274 275
            if last != -1:
                last -= 1
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
276
            l = cnx.lrange(self._name, first, last)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
277
        return l
Matias Guijarro's avatar
Matias Guijarro committed
278

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
279
    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
280
    def append(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
281
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
282
        return cnx.rpush(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
283

284 285 286 287
    def clear(self):
        cnx = self._cnx()
        cnx.delete(self._name)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
288
    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
289
    def prepend(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
290
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
291
        return cnx.lpush(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
292

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
293
    @write_decorator_multiple
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
294
    def extend(self, values):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
295
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
296
        return cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
297

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
298
    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
299
    def remove(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
300
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
301
        cnx.lrem(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
302

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
303
    @write_decorator_multiple
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
304
    def set(self, values):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
305 306 307
        cnx = self._cnx()
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
308
            cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
309

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
310
    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
311
    def set_item(self, value, pos=0):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
312
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
313
        cnx.lset(self._name, pos, value)
Matias Guijarro's avatar
Matias Guijarro committed
314

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
315
    @read_decorator
316
    def pop_front(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
317 318 319 320 321 322 323
        cnx = self._cnx()
        value = cnx.lpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

    @read_decorator
324
    def pop_back(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
325 326 327 328 329 330
        cnx = self._cnx()
        value = cnx.rpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
331 332
    def ttl(self, value=-1):
        return ttl_func(self._cnx(), self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
333

334
    def __len__(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
335 336 337
        cnx = self._cnx()
        return cnx.llen(self._name)

338
    def __repr__(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
339
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
340 341
        value = cnx.lrange(self._name, 0, -1)
        return '<QueueSetting name=%s value=%s>' % (self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
342

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
343
    def __iadd__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
344 345 346
        self.extend(other)
        return self

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
347 348
    def __getitem__(self, ran):
        if isinstance(ran, slice):
349 350
            i = ran.start is not None and ran.start or 0
            j = ran.stop is not None and ran.stop or -1
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
351
        elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
352 353 354
            i = j = ran
        else:
            raise TypeError('indices must be integers')
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
355
        value = self.get(first=i, last=j)
356 357 358 359
        if value is None:
            raise StopIteration
        else:
            return value
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
360

361
    def __iter__(self):
362 363
        cnx = self._cnx()
        lsize = cnx.llen(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
364
        for first in xrange(0, lsize, 1024):
365
            last = first + 1024
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
366 367 368
            if last >= lsize:
                last = -1
            for value in self.get(first, last):
369
                yield value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
370 371 372 373 374 375 376

    def __setitem__(self, ran, value):
        if isinstance(ran, slice):
            for i, v in zip(range(ran.start, ran.stop), value):
                self.set_item(v, pos=i)
        elif isinstance(ran, int):
            self.set_item(value, pos=ran)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
377 378 379 380
        else:
            raise TypeError('indices must be integers')
        return self

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
381

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
382
class QueueSettingProp(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
383 384 385 386
    def __init__(self, name, connection=None,
                 read_type_conversion=auto_conversion,
                 write_type_conversion=None,
                 use_object_name=True):
Matias Guijarro's avatar
Matias Guijarro committed
387 388 389 390 391 392
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
        self._use_object_name = use_object_name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
393
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
394 395 396 397 398
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
399
        return QueueSetting(name, self._cnx,
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
400 401
                            self._read_type_conversion,
                            self._write_type_conversion)
Matias Guijarro's avatar
Matias Guijarro committed
402

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
403 404 405
    def __set__(self, obj, values):
        if isinstance(values, QueueSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
406 407 408 409 410 411

        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
412
        proxy = QueueSetting(name, self._cnx,
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
413 414
                             self._read_type_conversion,
                             self._write_type_conversion)
Matias Guijarro's avatar
Matias Guijarro committed
415 416
        proxy.set(values)

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
417

Matias Guijarro's avatar
Matias Guijarro committed
418
class HashSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
419
    def __init__(self, name, connection=None,
Matias Guijarro's avatar
Matias Guijarro committed
420
                 read_type_conversion=auto_conversion,
421
                 write_type_conversion=None,
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
422
                 default_values={}):
Matias Guijarro's avatar
Matias Guijarro committed
423 424 425 426 427 428
        if connection is None:
            connection = get_cache()
        self._cnx = weakref.ref(connection)
        self._name = name
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
429
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
430

431 432
    def __repr__(self):
        value = self.get_all()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
433 434 435
        return '<HashSetting name=%s value=%s>' % (self._name, value)

    def __delitem__(self, key):
436
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
437
        cnx.hdel(self._name, key)
Matias Guijarro's avatar
Matias Guijarro committed
438

439
    def __len__(self):
Matias Guijarro's avatar
Matias Guijarro committed
440 441 442
        cnx = self._cnx()
        return cnx.hlen(self._name)

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
443 444
    def ttl(self, value=-1):
        return ttl_func(self._cnx(), self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
445

Matias Guijarro's avatar
Matias Guijarro committed
446
    def raw_get(self, key):
Matias Guijarro's avatar
Matias Guijarro committed
447
        cnx = self._cnx()
Matias Guijarro's avatar
Matias Guijarro committed
448 449 450
        return cnx.hget(self._name, key)

    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
451
    def get(self, key, default=None):
Matias Guijarro's avatar
Matias Guijarro committed
452 453
        v = self.raw_get(key)
        if v is None:
454 455 456 457
            if self._write_type_conversion:
                v = self._write_type_conversion(default)
            else:
                v = default
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
458
        return v
Matias Guijarro's avatar
Matias Guijarro committed
459

Matias Guijarro's avatar
Matias Guijarro committed
460 461 462
    def _raw_get_all(self):
        cnx = self._cnx()
        return cnx.hgetall(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
463

Matias Guijarro's avatar
Matias Guijarro committed
464 465 466
    def get_all(self):
        all_dict = dict(self._default_values)
        for k, raw_v in self._raw_get_all().iteritems():
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
467 468 469 470 471
            v = self._read_type_conversion(raw_v)
            if isinstance(v, InvalidValue):
                raise ValueError(
                    "%s: Invalid value '%s` (cannot deserialize %r)" % (self._name, k, raw_v))
            all_dict[k] = v
Matias Guijarro's avatar
Matias Guijarro committed
472
        return all_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
473

Matias Guijarro's avatar
Matias Guijarro committed
474
    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
475
    def pop(self, key, default=Null()):
476
        cnx = self._cnx().pipeline()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
477 478 479
        cnx.hget(self._name, key)
        cnx.hdel(self._name, key)
        (value, worked) = cnx.execute()
480
        if not worked:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
481
            if isinstance(default, Null):
482 483 484
                raise KeyError(key)
            else:
                value = default
Matias Guijarro's avatar
Matias Guijarro committed
485
        return value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
486

Matias Guijarro's avatar
Matias Guijarro committed
487
    def remove(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
488
        cnx = self._cnx()
Matias Guijarro's avatar
Matias Guijarro committed
489
        cnx.hdel(self._name, *keys)
Matias Guijarro's avatar
Matias Guijarro committed
490

491
    def keys(self):
492
        return list(self.iterkeys())
Matias Guijarro's avatar
Matias Guijarro committed
493

494
    def values(self):
495
        return list(self.itervalues())
Matias Guijarro's avatar
Matias Guijarro committed
496

497
    def clear(self):
Matias Guijarro's avatar
Matias Guijarro committed
498 499 500
        cnx = self._cnx()
        cnx.delete(self._name)

501
    def copy(self):
Matias Guijarro's avatar
Matias Guijarro committed
502 503 504
        return self.get()

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
505
    def set(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
506 507 508
        cnx = self._cnx()
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
509
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
510 511

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
512
    def update(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
513
        cnx = self._cnx()
514
        if values:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
515
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
516

517
    def items(self):
Matias Guijarro's avatar
Matias Guijarro committed
518
        values = self.get_all()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
519
        return [(k, v) for k, v in values.iteritems()]
Matias Guijarro's avatar
Matias Guijarro committed
520 521

    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
522
    def fromkeys(self, keys):
Matias Guijarro's avatar
Matias Guijarro committed
523
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
524 525 526
        return cnx.hmget(self._name, keys)

    def has_key(self, key):
Matias Guijarro's avatar
Matias Guijarro committed
527
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
528 529
        return cnx.hexists(self._name, key) or self._default_values.has_key(key)

Matias Guijarro's avatar
Matias Guijarro committed
530
    def iterkeys(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
531
        for k, v in self.iteritems():
532 533
            yield k

Matias Guijarro's avatar
Matias Guijarro committed
534
    def itervalues(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
535
        for k, v in self.iteritems():
536
            yield v
Matias Guijarro's avatar
Matias Guijarro committed
537

538
    def iteritems(self):
Matias Guijarro's avatar
Matias Guijarro committed
539 540
        cnx = self._cnx()
        next_id = 0
541
        seen_keys = set()
Matias Guijarro's avatar
Matias Guijarro committed
542
        while True:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
543 544
            next_id, pd = cnx.hscan(self._name, next_id)
            for k, v in pd.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
545 546
                if self._read_type_conversion:
                    v = self._read_type_conversion(v)
547
                seen_keys.add(k)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
548
                yield k, v
549
            if not next_id or next_id is '0':
Matias Guijarro's avatar
Matias Guijarro committed
550 551
                break

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
552 553 554 555
        for k, v in self._default_values.iteritems():
            if k in seen_keys:
                continue
            yield k, v
556

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
557
    def __getitem__(self, key):
Matias Guijarro's avatar
Matias Guijarro committed
558 559
        value = self.get(key)
        if value is None:
560 561
            if not self._default_values.has_key(key):
                raise KeyError(key)
Matias Guijarro's avatar
Matias Guijarro committed
562 563
        return value

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
564
    def __setitem__(self, key, value):
Matias Guijarro's avatar
Matias Guijarro committed
565
        cnx = self._cnx()
566
        if value is None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
567
            cnx.hdel(self._name, key)
568
            return
Matias Guijarro's avatar
Matias Guijarro committed
569 570
        if self._write_type_conversion:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
571
        cnx.hset(self._name, key, value)
Matias Guijarro's avatar
Matias Guijarro committed
572

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
573
    def __contains__(self, key):
574 575 576 577 578 579 580
        try:
            self[key]
            return True
        except KeyError:
            return False


Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
581 582 583 584 585 586
class HashSettingProp(object):
    def __init__(self, name, connection=None,
                 read_type_conversion=auto_conversion,
                 write_type_conversion=None,
                 default_values={},
                 use_object_name=True):
Matias Guijarro's avatar
Matias Guijarro committed
587 588 589 590
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
591
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
592 593
        self._use_object_name = use_object_name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
594
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
595 596 597 598
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
599 600

        return HashSetting(name, self._cnx,
Matias Guijarro's avatar
Matias Guijarro committed
601
                           self._read_type_conversion,
602 603
                           self._write_type_conversion,
                           self._default_values)
Matias Guijarro's avatar
Matias Guijarro committed
604

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
605
    def __set__(self, obj, values):
Matias Guijarro's avatar
Matias Guijarro committed
606 607 608 609 610
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
611 612
        if isinstance(values, HashSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
613

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
614
        proxy = HashSetting(name, self._cnx,
615 616 617
                            self._read_type_conversion,
                            self._write_type_conversion,
                            self._default_values)
Matias Guijarro's avatar
Matias Guijarro committed
618
        proxy.set(values)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
619

620
    def get_proxy(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
621
        return HashSetting(self._name, self._cnx,
Matias Guijarro's avatar
Matias Guijarro committed
622
                           self._read_type_conversion,
623 624
                           self._write_type_conversion,
                           self._default_values)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
625 626
# helper

Matias Guijarro's avatar
Matias Guijarro committed
627

628
def _change_to_obj_marshalling(keys):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
629 630 631 632 633
    read_type_conversion = keys.pop('read_type_conversion', pickle_loads)
    write_type_conversion = keys.pop('write_type_conversion', pickle.dumps)
    keys.update({'read_type_conversion': read_type_conversion,
                 'write_type_conversion': write_type_conversion})

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
634

635
class HashObjSetting(HashSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
636
    def __init__(self, name, **keys):
637
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
638 639
        HashSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
640

641
class HashObjSettingProp(HashSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
642
    def __init__(self, name, **keys):
643
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
644 645
        HashSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
646

647
class QueueObjSetting(QueueSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
648
    def __init__(self, name, **keys):
649
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
650 651
        QueueSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
652 653

class QueueObjSettingProp(QueueSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
654
    def __init__(self, name, **keys):
655
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
656 657
        QueueSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
658

659
class SimpleObjSetting(SimpleSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
660
    def __init__(self, name, **keys):
661
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
662 663
        SimpleSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
664 665

class SimpleObjSettingProp(SimpleSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
666
    def __init__(self, name, **keys):
667
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
668 669
        SimpleSettingProp.__init__(self, name, **keys)

Matias Guijarro's avatar
Matias Guijarro committed
670

671
class Struct(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
672 673
    def __init__(self, name, **keys):
        self._proxy = HashSetting(name, **keys)
674

675 676
    def __dir__(self):
        return self._proxy.keys()
677

678 679
    def __repr__(self):
        return "<Struct with attributes: %s>" % self._proxy.keys()
680

681 682
    def __getattribute__(self, name):
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
683
            return object.__getattribute__(self, name)
684 685
        else:
            return self._proxy.get(name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
686 687

    def __setattr__(self, name, value):
688
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
689
            return object.__setattr__(self, name, value)
690 691
        else:
            self._proxy[name] = value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
692 693

    def __delattr__(self, name):
694
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
695
            return object.__delattr__(self, name)
696 697
        else:
            self._proxy.remove(name)
698 699


700
class ParametersType(type):
701
    def __call__(cls, *args, **kwargs):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
702
        class_dict = {'__slots__': tuple(cls.SLOTS), 'SLOTS': cls.SLOTS}
703 704 705 706 707 708
        new_cls = type(cls.__name__, (cls,), class_dict)
        return type.__call__(new_cls, *args, **kwargs)

    def __new__(cls, name, bases, attrs):
        attrs['__slots__'] = tuple(attrs['SLOTS'])
        return type.__new__(cls, name, bases, attrs)
Matias Guijarro's avatar
Matias Guijarro committed
709

710

711 712
class ParamDescriptor(object):
    OBJECT_PREFIX = 'object:'
713

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
714 715
    def __init__(self, proxy, name, value, assign=True):
        self.proxy = proxy
716 717 718
        self.name = name
        if assign:
            self.assign(value)
719

720 721 722
    def assign(self, value):
        if hasattr(value, 'name') and hasattr(setup_globals, value.name):
            value = '%s%s' % (ParamDescriptor.OBJECT_PREFIX, value.name)
Matias Guijarro's avatar
Matias Guijarro committed
723 724 725
        try:
            self.proxy[self.name] = value
        except Exception:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
726 727
            raise ValueError("%s.%s: cannot set value" %
                             (self.proxy._name, self.name))
728 729 730

    def __get__(self, obj, obj_type):
        value = self.proxy[self.name]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
731
        if isinstance(value, (str, unicode)) and value.startswith(ParamDescriptor.OBJECT_PREFIX):
732 733
            value = value[len(ParamDescriptor.OBJECT_PREFIX):]
            return getattr(setup_globals, value)
Matias Guijarro's avatar
Matias Guijarro committed
734
        return value
735

736 737 738 739 740
    def __set__(self, obj, value):
        return self.assign(value)

    def __delete__(self, *args):
        del self.proxy[self.name]
741 742


743 744
class Parameters(object):
    __metaclass__ = ParametersType
745
    DESCRIPTOR = ParamDescriptor
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
746
    SLOTS = ['_proxy', '__current_config']
747

748 749
    def __init__(self, name, **keys):
        self.__current_config = SimpleSetting(name, default_value='default')
750 751 752 753
        hash_name = '%s:%s' % (name, self.__current_config.get())
        self._proxy = HashSetting(hash_name, **keys)
        for key in self._proxy.iterkeys():
            self.add(key)
754 755

    def __dir__(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
756 757
        return self._proxy.keys() + ['add', 'remove', 'switch', 'configs']

758
    def __repr__(self):
759
        rep_str = "Parameters (%s)\n" % self.__current_config.get()
760 761
        d = dict(self._proxy.iteritems())
        max_len = max((len(x) for x in d.keys()))
762
        str_format = '  .%-' + '%ds' % max_len + ' = %r\n'
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
763 764
        for key, value in sorted(d.iteritems()):
            rep_str += str_format % (key, value)
765
        return rep_str
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
766 767

    def add(self, name, value=None):
768 769 770 771 772 773
        setattr(self.__class__, name, self.DESCRIPTOR(self._proxy, name, value,
                                                      value is not None))

    def remove(self, name):
        self._proxy.remove(name)
        delattr(self.__class__, name)
774

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
775 776
    def switch(self, name):
        for key, value in dict(self.__class__.__dict__).iteritems():
777
            if isinstance(value, self.DESCRIPTOR):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
778 779
                delattr(self.__class__, key)

780 781 782 783
        self.__current_config.set(name)

        basename = ":".join(self._proxy._name.split(':')[:-1])
        self._proxy._name = '%s:%s' % (basename, name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
784

785 786
        for key in self._proxy.keys():
            self.add(key)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
787

Sebastien Petitdemange's avatar