root/masterdriverz/snakeoil-formatters/snakeoil/caching.py @ marienz%2540gentoo.org-20070404040619-7wsy2u0m1yctyvdx

Revision marienz%2540gentoo.org-20070404040619-7wsy2u0m1yctyvdx, 2.8 kB (checked in by Marien Zwart <marienz@…>, 21 months ago)

Update demandload calling convention.

Line 
1# Copyright: 2006 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4"""
5instance caching metaclass
6"""
7
8from snakeoil.demandload import demandload
9demandload(
10    globals(),
11    'warnings',
12    'weakref:WeakValueDictionary',
13    )
14
15class native_WeakInstMeta(type):
16    """metaclass for instance caching, resulting in reuse of unique instances
17
18    few notes-
19      - instances must be immutable (or effectively so).
20        Since creating a new instance may return a preexisting instance,
21        this requirement B{must} be honored.
22      - due to the potential for mishap, each subclass of a caching class must
23        assign __inst_caching__ = True to enable caching for the derivative.
24      - conversely, __inst_caching__ = False does nothing
25        (although it's useful as a sign of
26        I{do not enable caching for this class}
27      - instance caching can be disabled per instantiation via passing
28        disabling_inst_caching=True into the class constructor.
29
30    Being a metaclass, the voodoo used doesn't require modification of
31    the class itself.
32
33    Examples of usage is the restrictions subsystem for
34    U{pkgcore project<http://pkgcore.org>}
35    """
36    def __new__(cls, name, bases, d):
37        if d.get("__inst_caching__", False):
38            d["__inst_caching__"] = True
39            d["__inst_dict__"]  = WeakValueDictionary()
40        else:
41            d["__inst_caching__"] = False
42        slots = d.get('__slots__')
43        if slots is not None:
44            for base in bases:
45                if getattr(base, '__weakref__', False):
46                    break
47            else:
48                d['__slots__'] = tuple(slots) + ('__weakref__',)
49        return type.__new__(cls, name, bases, d)
50
51    def __call__(cls, *a, **kw):
52        """disable caching via disable_inst_caching=True"""
53        if cls.__inst_caching__ and not kw.pop("disable_inst_caching", False):
54            kwlist = kw.items()
55            kwlist.sort()
56            key = (a, tuple(kwlist))
57            try:
58                instance = cls.__inst_dict__.get(key)
59            except (NotImplementedError, TypeError), t:
60                warnings.warn(
61                    "caching keys for %s, got %s for a=%s, kw=%s" % (
62                        cls, t, a, kw))
63                del t
64                key = instance = None
65
66            if instance is None:
67                instance = super(native_WeakInstMeta, cls).__call__(*a, **kw)
68
69                if key is not None:
70                    cls.__inst_dict__[key] = instance
71        else:
72            instance = super(native_WeakInstMeta, cls).__call__(*a, **kw)
73
74        return instance
75
76# "Invalid name"
77# pylint: disable-msg=C0103
78
79try:
80    # No name in module
81    # pylint: disable-msg=E0611
82    from snakeoil._caching import WeakInstMeta
83    cpy_WeakInstMeta = WeakInstMeta
84except ImportError:
85    cpy_WeakInstMeta = None
86    WeakInstMeta = native_WeakInstMeta
Note: See TracBrowser for help on using the browser.