File: reference.py

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (203 lines) | stat: -rw-r--r-- 7,646 bytes parent folder | download | duplicates (8)
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
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from .composition_parts import DebugInfo
from .composition_parts import WithIdentifier


class Proxy(object):
    """
    Proxies attribute access on this object to the target object.
    """

    def __init__(self,
                 target_object=None,
                 target_attrs=None,
                 target_attrs_with_priority=None):
        """
        Creates a new proxy to |target_object|.

        Args:
            target_object: The object to which attribute access is proxied.
                This can be set later by set_target_object.
            target_attrs: None or list of attribute names to be proxied.  If
                None, all the attribute access is proxied.
            target_attrs_with_priority: None or list of attribute names to be
                unconditionally proxied with priority over attributes defined on
                |self|.  If None, no attribute has priority over own attributes.
        """
        if target_attrs is not None:
            assert isinstance(target_attrs, (list, set, tuple))
            assert all(isinstance(attr, str) for attr in target_attrs)
        self._target_object = target_object
        self._target_attrs = target_attrs
        self._target_attrs_with_priority = target_attrs_with_priority

    def __getattr__(self, attribute):
        try:
            target_object = object.__getattribute__(self, '_target_object')
            target_attrs = object.__getattribute__(self, '_target_attrs')
        except AttributeError:
            # When unpickling, __init__ does not get called.  _target_object is
            # not defined yet during unpickling.  Then, just fallback to the
            # default access.
            return object.__getattribute__(self, attribute)
        assert target_object is not None
        if target_attrs is None or attribute in target_attrs:
            return getattr(target_object, attribute)
        raise AttributeError

    def __getattribute__(self, attribute):
        try:
            target_object = object.__getattribute__(self, '_target_object')
            target_attrs = object.__getattribute__(
                self, '_target_attrs_with_priority')
        except AttributeError:
            # When unpickling, __init__ does not get called.  _target_object is
            # not defined yet during unpickling.  Then, just fallback to the
            # default access.
            return object.__getattribute__(self, attribute)
        # It's okay to access own attributes, such as 'identifier', even when
        # the target object is not yet resolved.
        if target_object is None:
            return object.__getattribute__(self, attribute)
        if target_attrs is not None and attribute in target_attrs:
            return getattr(target_object, attribute)
        return object.__getattribute__(self, attribute)

    @staticmethod
    def get_all_attributes(target_class):
        """
        Returns all the attributes of |target_class| including its ancestors'
        attributes.  Protected attributes (starting with an underscore,
        including two underscores) are excluded.
        """

        def collect_attrs_recursively(target_class):
            attrs_sets = [set(vars(target_class).keys())]
            for base_class in target_class.__bases__:
                attrs_sets.append(collect_attrs_recursively(base_class))
            return set.union(*attrs_sets)

        assert isinstance(target_class, type)
        return sorted([
            attr for attr in collect_attrs_recursively(target_class)
            if not attr.startswith('_')
        ])

    def make_copy(self, memo):
        return self

    def set_target_object(self, target_object):
        assert self._target_object is None
        assert isinstance(target_object, object)
        self._target_object = target_object

    @property
    def target_object(self):
        assert self._target_object is not None
        return self._target_object


_REF_BY_ID_PASS_KEY = object()


class RefById(Proxy, WithIdentifier):
    """
    Represents a reference to an object specified with the given identifier,
    which reference will be resolved later.

    This reference is also a proxy to the object for convenience so that you
    can treat this reference as if the object itself.
    """

    def __init__(self,
                 identifier,
                 debug_info=None,
                 target_attrs=None,
                 target_attrs_with_priority=None,
                 pass_key=None):
        assert debug_info is None or isinstance(debug_info, DebugInfo)
        assert pass_key is _REF_BY_ID_PASS_KEY

        Proxy.__init__(
            self,
            target_attrs=target_attrs,
            target_attrs_with_priority=target_attrs_with_priority)
        WithIdentifier.__init__(self, identifier)
        self._ref_own_debug_info = debug_info

    @property
    def ref_own_debug_info(self):
        """This reference's own DebugInfo."""
        return self._ref_own_debug_info


class RefByIdFactory(object):
    """
    Creates a group of references that are later resolvable.

    All the references created by this factory are grouped per factory, and you
    can apply a function to all the references.  This allows you to resolve all
    the references at very end of the compilation phases.
    """

    def __init__(self, target_attrs=None, target_attrs_with_priority=None):
        self._references = []
        # |_is_frozen| is initially False and you can create new references.
        # The first invocation of |for_each| freezes the factory and you can no
        # longer create a new reference
        self._is_frozen = False
        self._target_attrs = target_attrs
        self._target_attrs_with_priority = target_attrs_with_priority

    def create(self, identifier, debug_info=None):
        """
        Creates a new instance of RefById.

            Args:
                identifier: An identifier to be resolved later.
                debug_info: Where the reference is created, which is useful
                    especially when the reference is unresolvable.
        """
        assert not self._is_frozen
        ref = RefById(
            identifier,
            debug_info=debug_info,
            target_attrs=self._target_attrs,
            target_attrs_with_priority=self._target_attrs_with_priority,
            pass_key=_REF_BY_ID_PASS_KEY)
        self._references.append(ref)
        return ref

    def init_subclass_instance(self, instance, identifier, debug_info=None):
        """
        Initializes an instance of a subclass of RefById.
        """
        assert type(instance) is not RefById
        assert isinstance(instance, RefById)
        assert not self._is_frozen
        RefById.__init__(
            instance,
            identifier,
            debug_info=debug_info,
            target_attrs=self._target_attrs,
            target_attrs_with_priority=self._target_attrs_with_priority,
            pass_key=_REF_BY_ID_PASS_KEY)
        self._references.append(instance)

    def for_each(self, callback):
        """
        Applies |callback| to all the references created by this factory.

        You can no longer create a new reference.

        Args:
            callback: A callable that takes a reference as only the argument.
                Return value is not used.
        """
        assert callable(callback)
        self._is_frozen = True
        for ref in self._references:
            callback(ref)