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
    def __repr__(self):
21
        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):
34
    if s == "True" or s == "true":
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
35
        return True
36
    if s == "False" or s == "false":
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
37
        return False
38
    raise ValueError("Not Boolean Value!")
Matias Guijarro's avatar
Matias Guijarro committed
39

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
40

Matias Guijarro's avatar
Matias Guijarro committed
41
def auto_conversion(var):
42
    """guesses the str representation of the variables type"""
Matias Guijarro's avatar
Matias Guijarro committed
43 44
    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)
84 85 86
                if hasattr(self, "default_values") and isinstance(
                    self.default_values, dict
                ):
87 88 89
                    tmp = dict(self._default_values)
                    tmp.update(value)
                    value = tmp
Matias Guijarro's avatar
Matias Guijarro committed
90
            else:
91 92 93
                if isinstance(value, DefaultValue):
                    value = value.value
                elif value is not None:
94
                    value = self._read_type_conversion(value)
95
        if value is None:
96
            if hasattr(self, "_default_value"):
97
                value = self._default_value
98 99 100
            elif hasattr(self, "_default_values") and hasattr(
                self._default_values, "get"
            ):
101
                value = self._default_values.get(args[0])
Matias Guijarro's avatar
Matias Guijarro committed
102
        return value
103

Matias Guijarro's avatar
Matias Guijarro committed
104 105
    return _read

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
106

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

            if values is not None:
114
                new_dict = dict()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
115
                for k, v in values.iteritems():
116 117
                    new_dict[k] = self._write_type_conversion(v)
                values = new_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
118
        return func(self, values, **keys)
119

Matias Guijarro's avatar
Matias Guijarro committed
120 121
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
122

123
def write_decorator_multiple(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
124
    def _write(self, values, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
125
        if self._write_type_conversion:
126 127 128 129 130
            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
131 132
            if values is not None:
                values = [self._write_type_conversion(x) for x in values]
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
133
        return func(self, values, **keys)
134

Matias Guijarro's avatar
Matias Guijarro committed
135 136
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
137

138
def write_decorator(func):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
139
    def _write(self, value, **keys):
Matias Guijarro's avatar
Matias Guijarro committed
140 141
        if self._write_type_conversion and value is not None:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
142
        return func(self, value, **keys)
143

Matias Guijarro's avatar
Matias Guijarro committed
144 145
    return _write

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
146

147
def scan(match="*", count=1000, connection=None):
148 149 150 151
    if connection is None:
        connection = get_cache()
    cursor = 0
    while 1:
152
        cursor, values = connection.scan(cursor=cursor, match=match, count=count)
153 154 155 156
        for val in values:
            yield val
        if int(cursor) == 0:
            break
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
157 158


159
class SimpleSetting(object):
160 161 162 163 164 165 166 167
    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
168 169 170 171 172 173
        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
174
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
175

176 177 178
    @property
    def name(self):
        return self._name
179

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
180
    @read_decorator
181
    def get(self):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
182 183 184 185 186
        cnx = self._cnx()
        value = cnx.get(self._name)
        return value

    @write_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
187
    def set(self, value):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
188
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
189 190 191 192
        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
193

194 195 196
    def clear(self):
        cnx = self._cnx()
        cnx.delete(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
197 198

    def __add__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
199
        value = self.get()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
200
        if isinstance(other, SimpleSetting):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
201 202 203
            other = other.get()
        return value + other

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
204
    def __iadd__(self, other):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
205 206
        cnx = self._cnx()
        if cnx is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
207
            if isinstance(other, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
208 209
                if other == 1:
                    cnx.incr(self._name)
Matias Guijarro's avatar
Matias Guijarro committed
210
                else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
211 212 213
                    cnx.incrby(self._name, other)
            elif isinstance(other, float):
                cnx.incrbyfloat(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
214
            else:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
215
                cnx.append(self._name, other)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
216
            return self
Matias Guijarro's avatar
Matias Guijarro committed
217

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
218 219
    def __isub__(self, other):
        if isinstance(other, basestring):
220 221 222
            raise TypeError(
                "unsupported operand type(s) for -=: %s" % type(other).__name__
            )
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
223
        return self.__iadd__(-other)
Matias Guijarro's avatar
Matias Guijarro committed
224

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
225
    def __getitem__(self, ran):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
226 227 228
        cnx = self._cnx()
        if cnx is not None:
            step = None
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
229 230
            if isinstance(ran, slice):
                i, j = ran.start, ran.stop
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
231
                step = ran.step
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
232
            elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
233 234
                i = j = ran
            else:
235
                raise TypeError("indices must be integers")
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
236

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
237
            value = cnx.getrange(self._name, i, j)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
238 239 240 241 242 243 244
            if step is not None:
                value = value[0:-1:step]
            return value

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

Matias Guijarro's avatar
Matias Guijarro committed
247

248
class SimpleSettingProp(object):
249 250 251 252 253 254 255 256 257
    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
258 259 260 261
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
262
        self._default_value = default_value
Matias Guijarro's avatar
Matias Guijarro committed
263 264
        self._use_object_name = use_object_name

265 266 267 268
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
269
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
270
        if self._use_object_name:
271
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
272 273
        else:
            name = self._name
274 275 276 277 278 279 280
        return SimpleSetting(
            name,
            self._cnx,
            self._read_type_conversion,
            self._write_type_conversion,
            self._default_value,
        )
Matias Guijarro's avatar
Matias Guijarro committed
281

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
282 283 284
    def __set__(self, obj, value):
        if isinstance(value, SimpleSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
285 286

        if self._use_object_name:
287
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
288 289 290 291 292 293 294 295
        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
296 297
            self._cnx.set(name, value)

Matias Guijarro's avatar
Matias Guijarro committed
298 299

class QueueSetting(object):
300 301 302 303 304 305 306
    def __init__(
        self,
        name,
        connection=None,
        read_type_conversion=auto_conversion,
        write_type_conversion=None,
    ):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
307 308
        if connection is None:
            connection = get_cache()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
309 310 311 312
        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
313

314 315 316 317
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
318
    @read_decorator
319 320 321
    def get(self, first=0, last=-1, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
322
        if first == last:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
323
            l = cnx.lindex(self._name, first)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
324
        else:
325 326
            if last != -1:
                last -= 1
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
327
            l = cnx.lrange(self._name, first, last)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
328
        return l
Matias Guijarro's avatar
Matias Guijarro committed
329

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
330
    @write_decorator
331 332 333
    def append(self, value, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
334
        return cnx.rpush(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
335

336 337 338
    def clear(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
339 340
        cnx.delete(self._name)

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

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
347
    @write_decorator_multiple
348
    def extend(self, values, cnx=None):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
349
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
350
        return cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
351

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
352
    @write_decorator
353 354 355
    def remove(self, value, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
356
        cnx.lrem(self._name, value)
Matias Guijarro's avatar
Matias Guijarro committed
357

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
358
    @write_decorator_multiple
359 360 361
    def set(self, values, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
362 363
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
364
            cnx.rpush(self._name, *values)
Matias Guijarro's avatar
Matias Guijarro committed
365

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
366
    @write_decorator
367 368 369
    def set_item(self, value, pos=0, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
370
        cnx.lset(self._name, pos, value)
Matias Guijarro's avatar
Matias Guijarro committed
371

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
372
    @read_decorator
373 374 375
    def pop_front(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
376 377 378 379 380 381
        value = cnx.lpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

    @read_decorator
382 383 384
    def pop_back(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
385 386 387 388 389
        value = cnx.rpop(self._name)
        if self._read_type_conversion:
            value = self._read_type_conversion(value)
        return value

390 391 392 393
    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
394

395 396 397
    def __len__(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
398 399
        return cnx.llen(self._name)

400 401 402
    def __repr__(self, cnx=None):
        if cnx is None:
            cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
403
        value = cnx.lrange(self._name, 0, -1)
404
        return "<QueueSetting name=%s value=%s>" % (self._name, value)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
405

406 407
    def __iadd__(self, other, cnx=None):
        self.extend(other, cnx)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
408 409
        return self

410
    def __getitem__(self, ran, cnx=None):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
411
        if isinstance(ran, slice):
412 413
            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
414
        elif isinstance(ran, int):
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
415 416
            i = j = ran
        else:
417
            raise TypeError("indices must be integers")
418
        value = self.get(first=i, last=j, cnx=cnx)
419
        if value is None:
420
            raise IndexError
421 422
        else:
            return value
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
423

424
    def __iter__(self, cnx=None):
425 426
        if cnx is None:
            cnx = self._cnx()
427
        lsize = cnx.llen(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
428
        for first in xrange(0, lsize, 1024):
429
            last = first + 1024
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
430 431 432
            if last >= lsize:
                last = -1
            for value in self.get(first, last):
433
                yield value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
434

435
    def __setitem__(self, ran, value, cnx=None):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
436 437
        if isinstance(ran, slice):
            for i, v in zip(range(ran.start, ran.stop), value):
438
                self.set_item(v, pos=i, cnx=cnx)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
439
        elif isinstance(ran, int):
440
            self.set_item(value, pos=ran, cnx=cnx)
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
441
        else:
442
            raise TypeError("indices must be integers")
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
443 444
        return self

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
445

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
446
class QueueSettingProp(object):
447 448 449 450 451 452 453 454
    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
455 456 457 458 459 460
        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

461 462 463 464
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
465
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
466
        if self._use_object_name:
467
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
468 469 470
        else:
            name = self._name

471 472 473
        return QueueSetting(
            name, self._cnx, self._read_type_conversion, self._write_type_conversion
        )
Matias Guijarro's avatar
Matias Guijarro committed
474

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
475 476 477
    def __set__(self, obj, values):
        if isinstance(values, QueueSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
478 479

        if self._use_object_name:
480
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
481 482 483
        else:
            name = self._name

484 485 486
        proxy = QueueSetting(
            name, self._cnx, self._read_type_conversion, self._write_type_conversion
        )
Matias Guijarro's avatar
Matias Guijarro committed
487 488
        proxy.set(values)

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
489

Matias Guijarro's avatar
Matias Guijarro committed
490
class HashSetting(object):
491 492 493 494 495 496 497 498
    def __init__(
        self,
        name,
        connection=None,
        read_type_conversion=auto_conversion,
        write_type_conversion=None,
        default_values={},
    ):
Matias Guijarro's avatar
Matias Guijarro committed
499 500 501 502 503 504
        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
505
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
506

507 508 509 510
    @property
    def name(self):
        return self._name

511 512
    def __repr__(self):
        value = self.get_all()
513
        return "<HashSetting name=%s value=%s>" % (self._name, value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
514 515

    def __delitem__(self, key):
516
        cnx = self._cnx()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
517
        cnx.hdel(self._name, key)
Matias Guijarro's avatar
Matias Guijarro committed
518

519
    def __len__(self):
Matias Guijarro's avatar
Matias Guijarro committed
520 521 522
        cnx = self._cnx()
        return cnx.hlen(self._name)

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

526
    def raw_get(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
527
        cnx = self._cnx()
528
        return cnx.hget(self._name, *keys)
Matias Guijarro's avatar
Matias Guijarro committed
529 530

    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
531
    def get(self, key, default=None):
Matias Guijarro's avatar
Matias Guijarro committed
532 533
        v = self.raw_get(key)
        if v is None:
534
            v = DefaultValue(default)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
535
        return v
Matias Guijarro's avatar
Matias Guijarro committed
536

Matias Guijarro's avatar
Matias Guijarro committed
537 538 539
    def _raw_get_all(self):
        cnx = self._cnx()
        return cnx.hgetall(self._name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
540

Matias Guijarro's avatar
Matias Guijarro committed
541 542 543
    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
544 545 546
            v = self._read_type_conversion(raw_v)
            if isinstance(v, InvalidValue):
                raise ValueError(
547 548 549
                    "%s: Invalid value '%s` (cannot deserialize %r)"
                    % (self._name, k, raw_v)
                )
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
550
            all_dict[k] = v
Matias Guijarro's avatar
Matias Guijarro committed
551
        return all_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
552

Matias Guijarro's avatar
Matias Guijarro committed
553
    @read_decorator
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
554
    def pop(self, key, default=Null()):
555
        cnx = self._cnx().pipeline()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
556 557 558
        cnx.hget(self._name, key)
        cnx.hdel(self._name, key)
        (value, worked) = cnx.execute()
559
        if not worked:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
560
            if isinstance(default, Null):
561 562 563
                raise KeyError(key)
            else:
                value = default
Matias Guijarro's avatar
Matias Guijarro committed
564
        return value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
565

Matias Guijarro's avatar
Matias Guijarro committed
566
    def remove(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
567
        cnx = self._cnx()
Matias Guijarro's avatar
Matias Guijarro committed
568
        cnx.hdel(self._name, *keys)
Matias Guijarro's avatar
Matias Guijarro committed
569

570
    def keys(self):
571
        return list(self.iterkeys())
Matias Guijarro's avatar
Matias Guijarro committed
572

573
    def values(self):
574
        return list(self.itervalues())
Matias Guijarro's avatar
Matias Guijarro committed
575

576
    def clear(self):
Matias Guijarro's avatar
Matias Guijarro committed
577 578 579
        cnx = self._cnx()
        cnx.delete(self._name)

580
    def copy(self):
Matias Guijarro's avatar
Matias Guijarro committed
581 582 583
        return self.get()

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
584
    def set(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
585 586 587
        cnx = self._cnx()
        cnx.delete(self._name)
        if values is not None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
588
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
589 590

    @write_decorator_dict
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
591
    def update(self, values):
Matias Guijarro's avatar
Matias Guijarro committed
592
        cnx = self._cnx()
593
        if values:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
594
            cnx.hmset(self._name, values)
Matias Guijarro's avatar
Matias Guijarro committed
595

596
    def items(self):
Matias Guijarro's avatar
Matias Guijarro committed
597
        values = self.get_all()
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
598
        return [(k, v) for k, v in values.iteritems()]
Matias Guijarro's avatar
Matias Guijarro committed
599 600

    @read_decorator
601
    def fromkeys(self, *keys):
Matias Guijarro's avatar
Matias Guijarro committed
602
        cnx = self._cnx()
603
        return cnx.hmget(self._name, *keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
604 605

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

Matias Guijarro's avatar
Matias Guijarro committed
609
    def iterkeys(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
610
        for k, v in self.iteritems():
611 612
            yield k

Matias Guijarro's avatar
Matias Guijarro committed
613
    def itervalues(self):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
614
        for k, v in self.iteritems():
615
            yield v
Matias Guijarro's avatar
Matias Guijarro committed
616

617
    def iteritems(self):
Matias Guijarro's avatar
Matias Guijarro committed
618 619
        cnx = self._cnx()
        next_id = 0
620
        seen_keys = set()
Matias Guijarro's avatar
Matias Guijarro committed
621
        while True:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
622 623
            next_id, pd = cnx.hscan(self._name, next_id)
            for k, v in pd.iteritems():
Matias Guijarro's avatar
Matias Guijarro committed
624 625
                if self._read_type_conversion:
                    v = self._read_type_conversion(v)
626
                seen_keys.add(k)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
627
                yield k, v
628
            if not next_id or next_id is "0":
Matias Guijarro's avatar
Matias Guijarro committed
629 630
                break

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
631 632 633 634
        for k, v in self._default_values.iteritems():
            if k in seen_keys:
                continue
            yield k, v
635

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
636
    def __getitem__(self, key):
Matias Guijarro's avatar
Matias Guijarro committed
637 638
        value = self.get(key)
        if value is None:
639 640
            if not self._default_values.has_key(key):
                raise KeyError(key)
Matias Guijarro's avatar
Matias Guijarro committed
641 642
        return value

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
643
    def __setitem__(self, key, value):
Matias Guijarro's avatar
Matias Guijarro committed
644
        cnx = self._cnx()
645
        if value is None:
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
646
            cnx.hdel(self._name, key)
647
            return
Matias Guijarro's avatar
Matias Guijarro committed
648 649
        if self._write_type_conversion:
            value = self._write_type_conversion(value)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
650
        cnx.hset(self._name, key, value)
Matias Guijarro's avatar
Matias Guijarro committed
651

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
652
    def __contains__(self, key):
653 654 655 656 657 658 659
        try:
            self[key]
            return True
        except KeyError:
            return False


Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
660
class HashSettingProp(object):
661 662 663 664 665 666 667 668 669
    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
670 671 672 673
        self._name = name
        self._cnx = connection or get_cache()
        self._read_type_conversion = read_type_conversion
        self._write_type_conversion = write_type_conversion
674
        self._default_values = default_values
Matias Guijarro's avatar
Matias Guijarro committed
675 676
        self._use_object_name = use_object_name

677 678 679 680
    @property
    def name(self):
        return self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
681
    def __get__(self, obj, type=None):
Matias Guijarro's avatar
Matias Guijarro committed
682
        if self._use_object_name:
683
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
684 685
        else:
            name = self._name
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
686

687 688 689 690 691 692 693
        return HashSetting(
            name,
            self._cnx,
            self._read_type_conversion,
            self._write_type_conversion,
            self._default_values,
        )
Matias Guijarro's avatar
Matias Guijarro committed
694

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
695
    def __set__(self, obj, values):
Matias Guijarro's avatar
Matias Guijarro committed
696
        if self._use_object_name:
697
            name = obj.name + ":" + self._name
Matias Guijarro's avatar
Matias Guijarro committed
698 699 700
        else:
            name = self._name

Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
701 702
        if isinstance(values, HashSetting):
            return
Matias Guijarro's avatar
Matias Guijarro committed
703

704 705 706 707 708 709 710
        proxy = HashSetting(
            name,
            self._cnx,
            self._read_type_conversion,
            self._write_type_conversion,
            self._default_values,
        )
Matias Guijarro's avatar
Matias Guijarro committed
711
        proxy.set(values)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
712

713
    def get_proxy(self):
714 715 716 717 718 719 720 721 722
        return HashSetting(
            self._name,
            self._cnx,
            self._read_type_conversion,
            self._write_type_conversion,
            self._default_values,
        )


Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
723 724
# helper

Matias Guijarro's avatar
Matias Guijarro committed
725

726
def _change_to_obj_marshalling(keys):
727 728 729 730 731 732 733 734
    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
pep8  
Sebastien Petitdemange committed
735

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
736

737
class HashObjSetting(HashSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
738
    def __init__(self, name, **keys):
739
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
740 741
        HashSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
742

743
class HashObjSettingProp(HashSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
744
    def __init__(self, name, **keys):
745
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
746 747
        HashSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
748

749
class QueueObjSetting(QueueSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
750
    def __init__(self, name, **keys):
751
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
752 753
        QueueSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
754 755

class QueueObjSettingProp(QueueSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
756
    def __init__(self, name, **keys):
757
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
758 759
        QueueSettingProp.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
760

761
class SimpleObjSetting(SimpleSetting):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
762
    def __init__(self, name, **keys):
763
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
764 765
        SimpleSetting.__init__(self, name, **keys)

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
766 767

class SimpleObjSettingProp(SimpleSettingProp):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
768
    def __init__(self, name, **keys):
769
        _change_to_obj_marshalling(keys)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
770 771
        SimpleSettingProp.__init__(self, name, **keys)

Matias Guijarro's avatar
Matias Guijarro committed
772

773
class Struct(object):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
774 775
    def __init__(self, name, **keys):
        self._proxy = HashSetting(name, **keys)
776

777 778
    def __dir__(self):
        return self._proxy.keys()
779

780 781
    def __repr__(self):
        return "<Struct with attributes: %s>" % self._proxy.keys()
782

783
    def __getattribute__(self, name):
784
        if name.startswith("_"):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
785
            return object.__getattribute__(self, name)
786 787
        else:
            return self._proxy.get(name)
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
788 789

    def __setattr__(self, name, value):
790
        if name.startswith("_"):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
791
            return object.__setattr__(self, name, value)
792 793
        else:
            self._proxy[name] = value
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
794 795

    def __delattr__(self, name):
796
        if name.startswith("_"):
Sebastien Petitdemange's avatar
pep8  
Sebastien Petitdemange committed
797
            return object.__delattr__(self, name)
798 799
        else:
            self._proxy.remove(name)
800 801


802
class ParametersType(type):