settings.py 25.4 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

24 25 26 27 28 29 30
class DefaultValue(object):
    def __init__(self, wrapped_value):
        self.__value = wrapped_value

    @property
    def value(self):
        return self.__value
Matias Guijarro's avatar
Matias Guijarro committed
31

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
32 33

def boolify(s, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
34
    if s == 'True' or s == 'true':
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
35
        return True
Matias Guijarro's avatar
Matias Guijarro committed
36
    if s == 'False' or s == 'false':
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
37
        return False
Matias Guijarro's avatar
Matias Guijarro committed
38 39
    raise ValueError('Not Boolean Value!')

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
40

Matias Guijarro's avatar
Matias Guijarro committed
41 42 43 44
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
45
    for caster in (boolify, int, float):
Matias Guijarro's avatar
Matias Guijarro committed
46 47
        try:
            return caster(var)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
48
        except (ValueError, TypeError):
Matias Guijarro's avatar
Matias Guijarro committed
49 50 51
            pass
    return var

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
52

53
def pickle_loads(var):
Matias Guijarro's avatar
Matias Guijarro committed
54 55
    if var is None:
        return None
Matias Guijarro's avatar
Matias Guijarro committed
56 57 58 59
    try:
        return pickle.loads(var)
    except Exception:
        return InvalidValue()
Matias Guijarro's avatar
Matias Guijarro committed
60

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
61

62 63 64 65
def get_cache():
    return client.get_cache(db=0)


Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
66
def ttl_func(cnx, name, value=-1):
Matias Guijarro's avatar
Matias Guijarro committed
67 68 69 70 71
    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
72 73
        return cnx.expire(name, value)

Matias Guijarro's avatar
Matias Guijarro committed
74

75
def read_decorator(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
76 77
    def _read(self, *args, **keys):
        value = func(self, *args, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
78
        if self._read_type_conversion:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
79
            if isinstance(value, list):
Matias Guijarro's avatar
Matias Guijarro committed
80
                value = [self._read_type_conversion(x) for x in value]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
81 82
            elif isinstance(value, dict):
                for k, v in value.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
83
                    value[k] = self._read_type_conversion(v)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
84
                if hasattr(self, 'default_values') and isinstance(self.default_values, dict):
85 86 87
                    tmp = dict(self._default_values)
                    tmp.update(value)
                    value = tmp
Matias Guijarro's avatar
Matias Guijarro committed
88
            else:
89 90 91
                if isinstance(value, DefaultValue):
                    value = value.value
                elif value is not None:
92
                    value = self._read_type_conversion(value)
93
        if value is None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
94
            if hasattr(self, '_default_value'):
95
                value = self._default_value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
96 97
            elif(hasattr(self, '_default_values') and
                 hasattr(self._default_values, 'get')):
98
                value = self._default_values.get(args[0])
Matias Guijarro's avatar
Matias Guijarro committed
99 100 101
        return value
    return _read

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
102

103
def write_decorator_dict(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
104
    def _write(self, values, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
105
        if self._write_type_conversion:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
106
            if not isinstance(values, dict) and values is not None:
Matias Guijarro's avatar
Matias Guijarro committed
107 108 109
                raise TypeError('can only be dict')

            if values is not None:
110
                new_dict = dict()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
111
                for k, v in values.iteritems():
112 113
                    new_dict[k] = self._write_type_conversion(v)
                values = new_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
114
        return func(self, values, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
115 116
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
117

118
def write_decorator_multiple(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
119
    def _write(self, values, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
120
        if self._write_type_conversion:
121 122
            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
123 124
            if values is not None:
                values = [self._write_type_conversion(x) for x in values]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
125
        return func(self, values, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
126 127
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
128

129
def write_decorator(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
130
    def _write(self, value, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
131 132
        if self._write_type_conversion and value is not None:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
133
        return func(self, value, **keys)
Matias Guijarro's avatar
Matias Guijarro committed
134 135
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
136 137

def scan(match='*', count=1000, connection=None):
138 139 140 141
    if connection is None:
        connection = get_cache()
    cursor = 0
    while 1:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
142 143
        cursor, values = connection.scan(cursor=cursor,
                                         match=match, count=count)
144 145 146 147
        for val in values:
            yield val
        if int(cursor) == 0:
            break
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
148 149


150
class SimpleSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
151 152 153 154
    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
155 156 157 158 159 160
        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
161
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
162

163 164 165 166
    @property
    def name(self):
        return self._name
 
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
167
    @read_decorator
168
    def get(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
169 170 171 172 173
        cnx = self._cnx()
        value = cnx.get(self._name)
        return value

    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
174
    def set(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
175
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
176 177 178 179
        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
180

181 182 183
    def clear(self):
        cnx = self._cnx()
        cnx.delete(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
184 185

    def __add__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
186
        value = self.get()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
187
        if isinstance(other, SimpleSetting):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
188 189 190
            other = other.get()
        return value + other

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
191
    def __iadd__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
192 193
        cnx = self._cnx()
        if cnx is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
194
            if isinstance(other, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
195 196
                if other == 1:
                    cnx.incr(self._name)
Matias Guijarro's avatar
Matias Guijarro committed
197
                else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
198 199 200
                    cnx.incrby(self._name, other)
            elif isinstance(other, float):
                cnx.incrbyfloat(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
201
            else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
202
                cnx.append(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
203
            return self
Matias Guijarro's avatar
Matias Guijarro committed
204

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
205 206 207 208
    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
209
        return self.__iadd__(-other)
Matias Guijarro's avatar
Matias Guijarro committed
210

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
211
    def __getitem__(self, ran):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
212 213 214
        cnx = self._cnx()
        if cnx is not None:
            step = None
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
215 216
            if isinstance(ran, slice):
                i, j = ran.start, ran.stop
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
217
                step = ran.step
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
218
            elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
219 220 221 222
                i = j = ran
            else:
                raise TypeError('indices must be integers')

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
223
            value = cnx.getrange(self._name, i, j)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
224 225 226 227 228 229 230
            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
231 232
        return '<SimpleSetting name=%s value=%s>' % (self._name, value)

Matias Guijarro's avatar
Matias Guijarro committed
233

234
class SimpleSettingProp(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
235 236 237 238 239
    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
240 241 242 243
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
244
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
245 246
        self._use_object_name = use_object_name

247 248 249 250
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
251
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
252 253 254 255
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
256
        return SimpleSetting(name, self._cnx,
257 258 259
                             self._read_type_conversion,
                             self._write_type_conversion,
                             self._default_value)
Matias Guijarro's avatar
Matias Guijarro committed
260

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
261 262 263
    def __set__(self, obj, value):
        if isinstance(value, SimpleSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
264 265 266 267 268 269 270 271 272 273 274

        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
275 276
            self._cnx.set(name, value)

Matias Guijarro's avatar
Matias Guijarro committed
277 278

class QueueSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
279 280 281 282 283
    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
284 285 286 287
        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
288

289 290 291 292
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
293
    @read_decorator
294 295 296
    def get(self, first=0, last=-1, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
297
        if first == last:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
298
            l = cnx.lindex(self._name, first)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
299
        else:
300 301
            if last != -1:
                last -= 1
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
302
            l = cnx.lrange(self._name, first, last)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
303
        return l
Matias Guijarro's avatar
Matias Guijarro committed
304

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
305
    @write_decorator
306 307 308
    def append(self, value, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
309
        return cnx.rpush(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
310

311 312 313
    def clear(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
314 315
        cnx.delete(self._name)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
316
    @write_decorator
317 318 319
    def prepend(self, value, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
320
        return cnx.lpush(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
321

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
322
    @write_decorator_multiple
323
    def extend(self, values, cnx=None):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
324
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
325
        return cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
326

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
327
    @write_decorator
328 329 330
    def remove(self, value, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
331
        cnx.lrem(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
332

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
333
    @write_decorator_multiple
334 335 336
    def set(self, values, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
337 338
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
339
            cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
340

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
341
    @write_decorator
342 343 344
    def set_item(self, value, pos=0, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
345
        cnx.lset(self._name, pos, value)
Matias Guijarro's avatar
Matias Guijarro committed
346

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
347
    @read_decorator
348 349 350
    def pop_front(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
351 352 353 354 355 356
        value = cnx.lpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

    @read_decorator
357 358 359
    def pop_back(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
360 361 362 363 364
        value = cnx.rpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

365 366 367 368
    def ttl(self, value=-1, cnx=None):
        if cnx is None:
            cnx = self._cnx()
        return ttl_func(cnx, self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
369

370 371 372
    def __len__(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
373 374
        return cnx.llen(self._name)

375 376 377
    def __repr__(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
378 379
        value = cnx.lrange(self._name, 0, -1)
        return '<QueueSetting name=%s value=%s>' % (self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
380

381 382
    def __iadd__(self, other, cnx=None):
        self.extend(other, cnx)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
383 384
        return self

385
    def __getitem__(self, ran, cnx=None):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
386
        if isinstance(ran, slice):
387 388
            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
389
        elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
390 391 392
            i = j = ran
        else:
            raise TypeError('indices must be integers')
393
        value = self.get(first=i, last=j, cnx=cnx)
394
        if value is None:
395
            raise IndexError
396 397
        else:
            return value
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
398

399
    def __iter__(self, cnx = None):
400 401
        if cnx is None:
            cnx = self._cnx()
402
        lsize = cnx.llen(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
403
        for first in xrange(0, lsize, 1024):
404
            last = first + 1024
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
405 406 407
            if last >= lsize:
                last = -1
            for value in self.get(first, last):
408
                yield value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
409

410
    def __setitem__(self, ran, value, cnx=None):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
411 412
        if isinstance(ran, slice):
            for i, v in zip(range(ran.start, ran.stop), value):
413
                self.set_item(v, pos=i, cnx=cnx)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
414
        elif isinstance(ran, int):
415
            self.set_item(value, pos=ran, cnx=cnx)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
416 417 418 419
        else:
            raise TypeError('indices must be integers')
        return self

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
420

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
421
class QueueSettingProp(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
422 423 424 425
    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
426 427 428 429 430 431
        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

432 433 434 435
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
436
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
437 438 439 440 441
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
442
        return QueueSetting(name, self._cnx,
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
443 444
                            self._read_type_conversion,
                            self._write_type_conversion)
Matias Guijarro's avatar
Matias Guijarro committed
445

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
446 447 448
    def __set__(self, obj, values):
        if isinstance(values, QueueSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
449 450 451 452 453 454

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

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
455
        proxy = QueueSetting(name, self._cnx,
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
456 457
                             self._read_type_conversion,
                             self._write_type_conversion)
Matias Guijarro's avatar
Matias Guijarro committed
458 459
        proxy.set(values)

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
460

Matias Guijarro's avatar
Matias Guijarro committed
461
class HashSetting(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
462
    def __init__(self, name, connection=None,
Matias Guijarro's avatar
Matias Guijarro committed
463
                 read_type_conversion=auto_conversion,
464
                 write_type_conversion=None,
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
465
                 default_values={}):
Matias Guijarro's avatar
Matias Guijarro committed
466 467 468 469 470 471
        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
472
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
473

474 475 476 477
    @property
    def name(self):
        return self._name

478 479
    def __repr__(self):
        value = self.get_all()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
480 481 482
        return '<HashSetting name=%s value=%s>' % (self._name, value)

    def __delitem__(self, key):
483
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
484
        cnx.hdel(self._name, key)
Matias Guijarro's avatar
Matias Guijarro committed
485

486
    def __len__(self):
Matias Guijarro's avatar
Matias Guijarro committed
487 488 489
        cnx = self._cnx()
        return cnx.hlen(self._name)

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

493
    def raw_get(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
494
        cnx = self._cnx()
495
        return cnx.hget(self._name, *keys)
Matias Guijarro's avatar
Matias Guijarro committed
496 497

    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
498
    def get(self, key, default=None):
Matias Guijarro's avatar
Matias Guijarro committed
499 500
        v = self.raw_get(key)
        if v is None:
501
            v = DefaultValue(default)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
502
        return v
Matias Guijarro's avatar
Matias Guijarro committed
503

Matias Guijarro's avatar
Matias Guijarro committed
504 505 506
    def _raw_get_all(self):
        cnx = self._cnx()
        return cnx.hgetall(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
507

Matias Guijarro's avatar
Matias Guijarro committed
508 509 510
    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
511 512 513 514 515
            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
516
        return all_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
517

Matias Guijarro's avatar
Matias Guijarro committed
518
    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
519
    def pop(self, key, default=Null()):
520
        cnx = self._cnx().pipeline()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
521 522 523
        cnx.hget(self._name, key)
        cnx.hdel(self._name, key)
        (value, worked) = cnx.execute()
524
        if not worked:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
525
            if isinstance(default, Null):
526 527 528
                raise KeyError(key)
            else:
                value = default
Matias Guijarro's avatar
Matias Guijarro committed
529
        return value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
530

Matias Guijarro's avatar
Matias Guijarro committed
531
    def remove(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
532
        cnx = self._cnx()
Matias Guijarro's avatar
Matias Guijarro committed
533
        cnx.hdel(self._name, *keys)
Matias Guijarro's avatar
Matias Guijarro committed
534

535
    def keys(self):
536
        return list(self.iterkeys())
Matias Guijarro's avatar
Matias Guijarro committed
537

538
    def values(self):
539
        return list(self.itervalues())
Matias Guijarro's avatar
Matias Guijarro committed
540

541
    def clear(self):
Matias Guijarro's avatar
Matias Guijarro committed
542 543 544
        cnx = self._cnx()
        cnx.delete(self._name)

545
    def copy(self):
Matias Guijarro's avatar
Matias Guijarro committed
546 547 548
        return self.get()

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
549
    def set(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
550 551 552
        cnx = self._cnx()
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
553
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
554 555

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
556
    def update(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
557
        cnx = self._cnx()
558
        if values:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
559
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
560

561
    def items(self):
Matias Guijarro's avatar
Matias Guijarro committed
562
        values = self.get_all()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
563
        return [(k, v) for k, v in values.iteritems()]
Matias Guijarro's avatar
Matias Guijarro committed
564 565

    @read_decorator
566
    def fromkeys(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
567
        cnx = self._cnx()
568
        return cnx.hmget(self._name, *keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
569 570

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

Matias Guijarro's avatar
Matias Guijarro committed
574
    def iterkeys(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
575
        for k, v in self.iteritems():
576 577
            yield k

Matias Guijarro's avatar
Matias Guijarro committed
578
    def itervalues(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
579
        for k, v in self.iteritems():
580
            yield v
Matias Guijarro's avatar
Matias Guijarro committed
581

582
    def iteritems(self):
Matias Guijarro's avatar
Matias Guijarro committed
583 584
        cnx = self._cnx()
        next_id = 0
585
        seen_keys = set()
Matias Guijarro's avatar
Matias Guijarro committed
586
        while True:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
587 588
            next_id, pd = cnx.hscan(self._name, next_id)
            for k, v in pd.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
589 590
                if self._read_type_conversion:
                    v = self._read_type_conversion(v)
591
                seen_keys.add(k)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
592
                yield k, v
593
            if not next_id or next_id is '0':
Matias Guijarro's avatar
Matias Guijarro committed
594 595
                break

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
596 597 598 599
        for k, v in self._default_values.iteritems():
            if k in seen_keys:
                continue
            yield k, v
600

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
601
    def __getitem__(self, key):
Matias Guijarro's avatar
Matias Guijarro committed
602 603
        value = self.get(key)
        if value is None:
604 605
            if not self._default_values.has_key(key):
                raise KeyError(key)
Matias Guijarro's avatar
Matias Guijarro committed
606 607
        return value

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
608
    def __setitem__(self, key, value):
Matias Guijarro's avatar
Matias Guijarro committed
609
        cnx = self._cnx()
610
        if value is None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
611
            cnx.hdel(self._name, key)
612
            return
Matias Guijarro's avatar
Matias Guijarro committed
613 614
        if self._write_type_conversion:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
615
        cnx.hset(self._name, key, value)
Matias Guijarro's avatar
Matias Guijarro committed
616

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
617
    def __contains__(self, key):
618 619 620 621 622 623 624
        try:
            self[key]
            return True
        except KeyError:
            return False


Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
625 626 627 628 629 630
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
631 632 633 634
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
635
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
636 637
        self._use_object_name = use_object_name

638 639 640 641
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
642
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
643 644 645 646
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
647 648

        return HashSetting(name, self._cnx,
Matias Guijarro's avatar
Matias Guijarro committed
649
                           self._read_type_conversion,
650 651
                           self._write_type_conversion,
                           self._default_values)
Matias Guijarro's avatar
Matias Guijarro committed
652

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
653
    def __set__(self, obj, values):
Matias Guijarro's avatar
Matias Guijarro committed
654 655 656 657 658
        if self._use_object_name:
            name = obj.name + ':' + self._name
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
659 660
        if isinstance(values, HashSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
661

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
662
        proxy = HashSetting(name, self._cnx,
663 664 665
                            self._read_type_conversion,
                            self._write_type_conversion,
                            self._default_values)
Matias Guijarro's avatar
Matias Guijarro committed
666
        proxy.set(values)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
667

668
    def get_proxy(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
669
        return HashSetting(self._name, self._cnx,
Matias Guijarro's avatar
Matias Guijarro committed
670
                           self._read_type_conversion,
671 672
                           self._write_type_conversion,
                           self._default_values)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
673 674
# helper

Matias Guijarro's avatar
Matias Guijarro committed
675

676
def _change_to_obj_marshalling(keys):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
677 678 679 680 681
    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
682

683
class HashObjSetting(HashSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
684
    def __init__(self, name, **keys):
685
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
686 687
        HashSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
688

689
class HashObjSettingProp(HashSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
690
    def __init__(self, name, **keys):
691
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
692 693
        HashSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
694

695
class QueueObjSetting(QueueSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
696
    def __init__(self, name, **keys):
697
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
698 699
        QueueSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
700 701

class QueueObjSettingProp(QueueSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
702
    def __init__(self, name, **keys):
703
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
704 705
        QueueSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
706

707
class SimpleObjSetting(SimpleSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
708
    def __init__(self, name, **keys):
709
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
710 711
        SimpleSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
712 713

class SimpleObjSettingProp(SimpleSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
714
    def __init__(self, name, **keys):
715
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
716 717
        SimpleSettingProp.__init__(self, name, **keys)

Matias Guijarro's avatar
Matias Guijarro committed
718

719
class Struct(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
720 721
    def __init__(self, name, **keys):
        self._proxy = HashSetting(name, **keys)
722

723 724
    def __dir__(self):
        return self._proxy.keys()
725

726 727
    def __repr__(self):
        return "<Struct with attributes: %s>" % self._proxy.keys()
728

729 730
    def __getattribute__(self, name):
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
731
            return object.__getattribute__(self, name)
732 733
        else:
            return self._proxy.get(name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
734 735

    def __setattr__(self, name, value):
736
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
737
            return object.__setattr__(self, name, value)
738 739
        else:
            self._proxy[name] = value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
740 741

    def __delattr__(self, name):
742
        if name.startswith('_'):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
743
            return object.__delattr__(self, name)
744 745
        else:
            self._proxy.remove(name)
746 747


748
class ParametersType(type):
749
    def __call__(cls, *args, **kwargs):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
750
        class_dict = {'__slots__': tuple(cls.SLOTS), 'SLOTS': cls.SLOTS}
751 752 753 754 755 756
        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
757

758

759 760
class ParamDescriptor(object):
    OBJECT_PREFIX = 'object:'
761

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
762 763
    def __init__(self, proxy, name, value, assign=True):
        self.proxy = proxy
764 765 766
        self.name = name
        if assign:
            self.assign(value)
767

768 769 770
    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
771 772 773
        try:
            self.proxy[self.name] = value
        except Exception:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
774 775
            raise ValueError("%s.%s: cannot set value" %
                             (self.proxy._name, self.name))
776 777 778

    def __get__(self, obj, obj_type):
        value = self.proxy[self.name]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
779
        if isinstance(value, (str, unicode)) and value.startswith(ParamDescriptor.OBJECT_PREFIX):
780 781
            value = value[len(ParamDescriptor.OBJECT_PREFIX):]
            return getattr(setup_globals, value)
Matias Guijarro's avatar
Matias Guijarro committed
782
        return value
783

784 785 786 787 788
    def __set__(self, obj, value):
        return self.assign(value)

    def __delete__(self, *args):
        del self.proxy[self.name]
789 790


791 792
class Parameters(object):
    __metaclass__ = ParametersType
793
    DESCRIPTOR = ParamDescriptor
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
794
    SLOTS = ['_proxy', '__current_config']
795

796 797
    def __init__(self, name, **keys):
        self.__current_config = SimpleSetting