/usr/share/pyshared/kiwi/model.py is in python-kiwi 1.9.22-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274  | #
# Kiwi: a Framework and Enhanced Widgets for Python
#
# Copyright (C) 2002-2003, 2005-2006 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
# USA
#
# Author(s): Christian Reis <kiko@async.com.br>
#            Johan Dahlin <jdahlin@async.com.br>
#
"""Holds the models part of the Kiwi Framework"""
import os
import pickle
from kiwi import ValueUnset
from kiwi.log import Logger
log = Logger('model')
#
# A model that implements half of an observer pattern; when its
# attributes are changed, it notifies any proxies of the change.
#
class Model:
    """
    The Model is a mixin to be used by domain classes when attached to
    Proxies.  It also provides autonotification of changes to the
    attached proxies. Note that if using setters, a specific call to
    notify_proxies() may be necessary; see the doc for __setattr__."""
    def __init__(self):
        self.ensure_init()
    def ensure_init(self):
        """
        Sets up the variables so the Model's getattr hook and proxy
        notification work properly.
        """
        # Work around setattr hook. The _v prefixes to the variables let
        # the ZODB know that there are non-persistant values. This
        # workaround is fine because the API protects them and it
        # doesn't affect any other persistence mechanism I know of.
        self.__dict__["_v_blocked_proxies"] = []
        self.__dict__["_v_proxies"] = {}
        self.__dict__["_v_autonotify"] = 1
    def disable_autonotify(self):
        """
        disable automatic notification to proxies based on __setattr__.
        All changes to the model must be followed by a call to
        notify_proxies() to allow the proxies to notice the change."""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        self._v_autonotify = 0
    def notify_proxies(self, attr):
        """Notify proxies that an attribute value has changed."""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        for proxy in self._v_proxies.get(attr, []):
            if proxy not in self._v_blocked_proxies:
                proxy.update(attr, ValueUnset, block=True)
    def register_proxy_for_attribute(self, attr, proxy):
        """
        Attach a proxy to an attribute. The proxy will be notified of
        changes to that particular attribute (my means of
        Proxy.notify())."""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        # XXX: should use weakref if possible, and if not, warn of leaks
        proxies = self._v_proxies
        if not proxies.has_key(attr):
            proxies[attr] = [proxy]
        else:
            if proxy in proxies[attr]:
                raise AssertionError, ("Tried to attach proxy %s "
                                       "twice to attribute `%s'."
                                       % ( proxy, attr ))
            proxies[attr].append(proxy)
    def unregister_proxy_for_attribute(self, attr, proxy):
        """Detach a proxy from an attribute."""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        proxies = self._v_proxies
        if proxies.has_key(attr) and proxy in proxies[attr]:
            # Only one listener per attribute per proxy, so remove()
            # works
            proxies[attr].remove(proxy)
    def unregister_proxy(self, proxy):
        """Deattach a proxy completely from the model"""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        proxies = self._v_proxies
        for attribute in proxies.keys():
            if proxy in proxies[attribute]:
                # Only one listener per attribute per proxy, so remove()
                # works
                proxies[attribute].remove(proxy)
    def flush_proxies(self):
        """Removes all proxies attached to Model"""
        self._v_proxies = {}
        self._v_blocked_proxies = []
    def block_proxy(self, proxy):
        """
        Temporarily block a proxy from receiving any notification. See
        unblock_proxy()"""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        blocked_proxies = self._v_blocked_proxies
        if proxy not in blocked_proxies:
            blocked_proxies.append(proxy)
    def unblock_proxy(self, proxy):
        """Re-enable notifications to a proxy"""
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        blocked_proxies = self._v_blocked_proxies
        if proxy in blocked_proxies:
            blocked_proxies.remove(proxy)
    def __setattr__(self, attr, value):
        """
        A special setattr hook that notifies the registered proxies that
        the model has changed. Work around it setting attributes
        directly to self.__dict__.
        Note that setattr() assumes that the name of the attribute being
        changed and the proxy attribute are the same. If this is not the
        case (as may happen when using setters) you must call
        notify_proxies() manually from the subclass' setter.
        """
        # XXX: this should be done last, since the proxy notification
        # may raise an exception. Or do we ignore this fact?
        self.__dict__[attr] = value
        if not hasattr(self, "_v_proxies"):
            self.ensure_init()
        if self._v_autonotify and self._v_proxies.has_key(attr):
            self.notify_proxies(attr)
#
# A sample model that pickles itself into a file
#
class PickledModel(Model):
    """
    PickledModel is a model that is able to save itself into a pickle
    using save().  This has all the limitations of a pickle: its
    instance variables must be picklable, or pickle.dump() will raise
    exceptions. You can prefix variables with an underscore to make them
    non-persistent (and you can restore them accordingly by overriding
    __setstate__, but don't forget to call PickledModel.__setstate__)
    """
    def __init__(self):
        self._filename = None
    def __getstate__(self):
        """Gets the state from the instance to be pickled"""
        odict = self.__dict__
        for key in odict.keys():
            if key.startswith("_"):
                del odict[key]
        return odict
    def __setstate__(self, dict):
        """Sets the state to the instance when being unpickled"""
        Model.__dict__["__init__"](self)
        self.__dict__.update(dict)
    def save(self, filename=None):
        """
        Saves the instance to a pickle filename. If no filename argument is
        provided, will try to use the internal _filename attribute that is
        set using set_filename()
        @param filename: optional filename to pass in
        """
        filename = filename or self._filename
        if not filename:
            raise AttributeError(
                "No pickle specified, don't know where to save myself")
        fh = open(filename, "w")
        try:
            try:
                pickle.dump(self, fh)
            except pickle.PicklingError, e:
                raise AttributeError(
                    "Tried to pickle an instance variable that isn't "
                    "supported by pickle.dump(). To work around this, you "
                    "can prefix the variable name with an underscore "
                    " and it will be ignored by the pickle machinery "
                    "in PickledModel. The original error "
                    "follows:\n\n%s" % e)
        finally:
            fh.close()
    def set_filename(self, filename):
        """
        Sets the name of the file which will be used to pickle the
        model"""
        self._filename = filename
    #@unpickle
    def unpickle(cls, filename=None):
        """
        Loads an instance from a pickle file; if it fails for some reason,
        create a new instance.
            - filename: the file from which the pickle should be loaded.
              If file is not provided, the name of the class suffixed by
              ".pickle" is used (i.e.  "FooClass.pickle" for the
              class FooClass).
        If the pickle file is damaged, it will be saved with the extension
        ".err"; if a file with that name also exists, it will use ".err.1"
        and so on. This is to avoid the damaged file being clobbered by an
        instance calling save() unsuspectingly.
        """
        if not filename:
            filename = cls.__name__ + ".pickle"
        if not os.path.exists(filename):
            ret = cls()
            ret.set_filename(filename)
            return ret
        fh = open(filename, "r")
        try:
            data = fh.read()
            ret = pickle.loads(data)
        except (EOFError, KeyError):
            # save backup of original pickle with an extension of
            # .err, .err.1, .err.2, etc.
            stem = filename + ".err"
            i = 0
            backup = stem
            while os.path.exists(backup):
                i = i + 1
                backup = stem + ".%d" % i
            open(backup, "w").write(data)
            log.warn(
                "pickle in %r was broken, saving backup in %r and creating "
                "new <%s> instance\n""" % (filename, backup, cls.__name__))
            ret = cls()
        fh.close()
        ret.set_filename(filename)
        return ret
    unpickle = classmethod(unpickle)
# TODO: implement a Model that saves itself as CSV/XML?
 |