~doctormo/+junk/css-parser

« back to all changes in this revision

Viewing changes to property.py

  • Committer: Martin Owens
  • Date: 2014-07-13 19:16:11 UTC
  • Revision ID: doctormo@gmail.com-20140713191611-48dkgp1dklvh8bq2
Inital addition of working css files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright 2012-2014 Martin Owens <doctormo@gmail.com>
 
3
# Copyright      2014 Ian Denhardt <ian@zenhack.net>
 
4
#
 
5
# This program is free software: you can redistribute it and/or modify
 
6
#  it under the terms of the GNU General Public License as published by
 
7
#  the Free Software Foundation, either version 3 of the License, or
 
8
#  (at your option) any later version.
 
9
#
 
10
#  This program is distributed in the hope that it will be useful,
 
11
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#  GNU General Public License for more details.
 
14
#
 
15
#  You should have received a copy of the GNU General Public License
 
16
#  along with this program.  If not, see <http://www.gnu.org/licenses/>
 
17
#
 
18
"""
 
19
The idea here is to provide a machanism for getting attributes at the right time.
 
20
 
 
21
Should provide stateful attribute access and some signal support for changes.
 
22
"""
 
23
 
 
24
 
 
25
from collections import OrderedDict, Callable
 
26
 
 
27
 
 
28
class DefaultOrderedDict(OrderedDict):
 
29
    """Copied from: http://stackoverflow.com/questions/6190331/can-i-do-an-ordered-default-dict-in-python"""
 
30
    def __init__(self, default_factory=None, *a, **kw):
 
31
        if (default_factory is not None and
 
32
            not isinstance(default_factory, Callable)):
 
33
            raise TypeError('first argument must be callable')
 
34
        OrderedDict.__init__(self, *a, **kw)
 
35
        self.default_factory = default_factory
 
36
 
 
37
    def __getitem__(self, key):
 
38
        try:
 
39
            return OrderedDict.__getitem__(self, key)
 
40
        except KeyError:
 
41
            return self.__missing__(key)
 
42
 
 
43
    def __missing__(self, key):
 
44
        if self.default_factory is None:
 
45
            raise KeyError(key)
 
46
        self[key] = value = self.default_factory()
 
47
        return value
 
48
 
 
49
    def __reduce__(self):
 
50
        if self.default_factory is None:
 
51
            args = tuple()
 
52
        else:
 
53
            args = self.default_factory,
 
54
        return type(self), args, None, None, self.items()
 
55
 
 
56
    def copy(self):
 
57
        return self.__copy__()
 
58
 
 
59
    def __copy__(self):
 
60
        return type(self)(self.default_factory, self)
 
61
 
 
62
    def __deepcopy__(self, memo):
 
63
        import copy
 
64
        return type(self)(self.default_factory,
 
65
                          copy.deepcopy(self.items()))
 
66
    def __repr__(self):
 
67
        return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
 
68
                                        OrderedDict.__repr__(self))
 
69
 
 
70
    def sort_to_end(self, name):
 
71
        if name in self:
 
72
            self[name] = self.pop(name)
 
73
 
 
74
    def super_keys(self):
 
75
        ret = set()
 
76
        for v in self.values():
 
77
            ret.update(v.keys())
 
78
        return ret
 
79
 
 
80
    def super_gets(self, keys):
 
81
        for key in keys:
 
82
            yield (key, self.super_get(key))
 
83
 
 
84
    def super_get(self, key):
 
85
        for d in reversed(self):
 
86
            if key in self[d]:
 
87
                return self[d][key]
 
88
        return None
 
89
 
 
90
 
 
91
 
 
92
class PropertyObject(object):
 
93
    """Property objects control system of layered property dictionaries,
 
94
       attributes returned are from the top most stack with that item key
 
95
 
 
96
    ! Keeping the user attributes ahead of the pack is trouble. Is this useful?
 
97
 
 
98
    """
 
99
    def __new__(cls, *p, **k):
 
100
        inst = object.__new__(cls)
 
101
        inst.__attrs__ = DefaultOrderedDict(dict)
 
102
        return inst
 
103
 
 
104
    def __setattr__(self, name, value):
 
105
        if name[0] != '_':
 
106
            self.__attrs__['user'][name] = value
 
107
        object.__setattr__(self, name, value)
 
108
 
 
109
    def __delattr__(self, name):
 
110
        if name[0] != '_' and name in self.__attrs__['user']:
 
111
            self.__attrs__['user'].pop(name)
 
112
        self.refresh([name])
 
113
 
 
114
    def add_to(self, d, name='base'):
 
115
        reorder = name not in self.__attrs__
 
116
 
 
117
        self.__attrs__[name].update(d)
 
118
        if reorder:
 
119
            self.__attrs__.sort_to_end('user')
 
120
 
 
121
        self.__dict__.update(d)
 
122
 
 
123
        if 'user' in self.__attrs__:
 
124
            self.__dict__.update(self.__attrs__['user'])
 
125
 
 
126
    def remove(self, name):
 
127
        old = self.__attrs__.pop(name)
 
128
        self.refresh(old.keys())
 
129
 
 
130
    def refresh(self, keys=None):
 
131
        keys = keys or self.__attrs__.super_keys()
 
132
        self.__dict__.update(self.__attrs__.super_gets(keys))
 
133
 
 
134