File: descriptor.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (281 lines) | stat: -rw-r--r-- 10,957 bytes parent folder | download
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
275
276
277
278
279
280
281
from rpython.rlib import jit
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
from pypy.interpreter.typedef import (
    GetSetProperty, TypeDef, generic_new_descr, interp_attrproperty_w)
from pypy.objspace.descroperation import object_getattribute


class W_Super(W_Root):

    def __init__(self, space):
        self.w_starttype = None
        self.w_objtype = None
        self.w_self = None

    def descr_init(self, space, w_starttype=None, w_obj_or_type=None):
        if space.is_none(w_starttype):
            frame = space.getexecutioncontext().gettopframe()
            w_starttype, w_obj_or_type = _super_from_frame(space, frame)

        if space.is_none(w_obj_or_type):
            w_type = None  # unbound super object
            w_obj_or_type = None
        else:
            w_type = _super_check(space, w_starttype, w_obj_or_type)
        self.w_starttype = w_starttype
        self.w_objtype = w_type
        self.w_self = w_obj_or_type      # may be None

    def descr_repr(self, space):
        if self.w_objtype is not None:
            objtype_name = u"<%s object>" % self.w_objtype.getname(space)
        else:
            objtype_name = u'NULL'
        if self.w_starttype is not None:
            starttype_name = self.w_starttype.getname(space)
        else:
            starttype_name = u'NULL'
        return space.newunicode(u"<super: <class '%s'>, %s>" % (
            starttype_name, objtype_name))

    def get(self, space, w_obj, w_type=None):
        if self.w_self is not None or space.is_w(w_obj, space.w_None):
            return self
        if self.w_starttype is None:
            raise oefmt(space.w_TypeError,
                "__get__(x) is invalid on an uninitialized instance of 'super'")
        else:
            # if type(self) is W_Super:
            #     XXX write a fast path for this common case
            w_selftype = space.type(self)
            return space.call_function(w_selftype, self.w_starttype, w_obj)

    def getattribute(self, space, w_name):
        name = space.text_w(w_name)
        # only use a special logic for bound super objects and not for
        # getting the __class__ of the super object itself.
        if self.w_objtype is not None and name != '__class__':
            assert self.w_starttype is not None
            w_value = space.lookup_in_type_starting_at(self.w_objtype,
                                                       self.w_starttype,
                                                       name)
            if w_value is not None:
                w_get = space.lookup(w_value, '__get__')
                if w_get is None:
                    return w_value
                # Only pass 'obj' param if this is instance-mode super
                # (see CPython sourceforge id #743627)
                w_obj = self.w_self
                if w_obj is None or w_obj is self.w_objtype:
                    w_obj = space.w_None
                return space.get_and_call_function(w_get, w_value,
                                                   w_obj, self.w_objtype)
        # fallback to object.__getattribute__()
        return space.call_function(object_getattribute(space), self, w_name)

@jit.elidable
def _get_self_location(space, code):
    if code.co_argcount == 0:
        raise oefmt(space.w_RuntimeError, "super(): no arguments")
    args_to_copy = code._args_as_cellvars
    for i in range(len(args_to_copy)):
        if args_to_copy[i] == 0:
            self_cell = i
            break
    else:
        self_cell = -1

    for index, name in enumerate(code.co_freevars):
        if name == '__class__':
            break
    else:
        raise oefmt(space.w_RuntimeError, "super(): __class__ cell not found")
    class_cell = len(code.co_cellvars) + index
    return self_cell, class_cell

def _super_from_frame(space, frame):
    """super() without args -- fill in from __class__ and first local
    variable on the stack.
    """
    if frame is None:
        raise oefmt(space.w_RuntimeError, "super(): no frame object")
    self_cell, class_cell = _get_self_location(space, frame.getcode())
    if self_cell < 0:
        w_obj = frame.locals_cells_stack_w[0]
    else:
        w_obj = frame._getcell(self_cell).w_value
    if not w_obj:
        raise oefmt(space.w_RuntimeError, "super(): arg[0] deleted")

    # a kind of LOAD_DEREF
    w_starttype = frame._getcell(class_cell).w_value
    if w_starttype is None:
        raise oefmt(space.w_RuntimeError, "super(): empty __class__ cell")
    return w_starttype, w_obj

def _super_check(space, w_starttype, w_obj_or_type):
    """Check that the super() call makes sense. Returns a type"""
    w_objtype = space.type(w_obj_or_type)

    if (space.issubtype_w(w_objtype, space.w_type) and
        space.issubtype_w(w_obj_or_type, w_starttype)):
        # special case for class methods
        return w_obj_or_type

    if space.issubtype_w(w_objtype, w_starttype):
        # normal case
        return w_objtype

    try:
        w_type = space.getattr(w_obj_or_type, space.newtext('__class__'))
    except OperationError as e:
        if not e.match(space, space.w_AttributeError):
            raise
        w_type = w_objtype

    if space.issubtype_w(w_type, w_starttype):
        return w_type
    raise oefmt(space.w_TypeError,
                "super(type, obj): obj must be an instance or subtype of type")

W_Super.typedef = TypeDef(
    'super',
    __new__          = generic_new_descr(W_Super),
    __init__         = interp2app(W_Super.descr_init),
    __repr__         = interp2app(W_Super.descr_repr),
    __thisclass__    = interp_attrproperty_w("w_starttype", W_Super),
    __self__         = interp_attrproperty_w("w_self", W_Super),
    __self_class__   = interp_attrproperty_w("w_objtype", W_Super),
    __getattribute__ = interp2app(W_Super.getattribute),
    __get__          = interp2app(W_Super.get),
    __doc__          =     """\
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)

Typical use to call a cooperative superclass method:

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)"""
)


class W_Property(W_Root):
    _immutable_fields_ = ["w_fget", "w_fset", "w_fdel"]

    def __init__(self, space):
        self.w_fget = space.w_None
        self.w_fset = space.w_None
        self.w_fdel = space.w_None
        self.w_doc = space.w_None
        self.getter_doc = False

    @unwrap_spec(w_fget=WrappedDefault(None),
                 w_fset=WrappedDefault(None),
                 w_fdel=WrappedDefault(None),
                 w_doc=WrappedDefault(None))
    def init(self, space, w_fget=None, w_fset=None, w_fdel=None, w_doc=None):
        self.w_fget = w_fget
        self.w_fset = w_fset
        self.w_fdel = w_fdel
        self.w_doc = w_doc
        self.getter_doc = False
        # our __doc__ comes from the getter if we don't have an explicit one
        if (space.is_w(self.w_doc, space.w_None) and
            not space.is_w(self.w_fget, space.w_None)):
            w_getter_doc = space.findattr(self.w_fget, space.newtext('__doc__'))
            if w_getter_doc is not None:
                if type(self) is W_Property:
                    self.w_doc = w_getter_doc
                else:
                    space.setattr(self, space.newtext('__doc__'), w_getter_doc)
                self.getter_doc = True

    def get(self, space, w_obj, w_objtype=None):
        if space.is_w(w_obj, space.w_None):
            return self
        if space.is_w(self.w_fget, space.w_None):
            raise oefmt(space.w_AttributeError, "unreadable attribute")
        return space.call_function(self.w_fget, w_obj)

    def set(self, space, w_obj, w_value):
        if space.is_w(self.w_fset, space.w_None):
            raise oefmt(space.w_AttributeError, "can't set attribute")
        space.call_function(self.w_fset, w_obj, w_value)
        return space.w_None

    def delete(self, space, w_obj):
        if space.is_w(self.w_fdel, space.w_None):
            raise oefmt(space.w_AttributeError, "can't delete attribute")
        space.call_function(self.w_fdel, w_obj)
        return space.w_None

    def getter(self, space, w_getter):
        return self._copy(space, w_getter=w_getter)

    def setter(self, space, w_setter):
        return self._copy(space, w_setter=w_setter)

    def deleter(self, space, w_deleter):
        return self._copy(space, w_deleter=w_deleter)

    def get_doc(self, space):
        return self.w_doc

    def set_doc(self, space, w_doc):
        self.w_doc = w_doc
        self.getter_doc = False

    def _copy(self, space, w_getter=None, w_setter=None, w_deleter=None):
        if w_getter is None:
            w_getter = self.w_fget
        if w_setter is None:
            w_setter = self.w_fset
        if w_deleter is None:
            w_deleter = self.w_fdel
        if self.getter_doc and w_getter is not None:
            w_doc = space.w_None
        else:
            w_doc = self.w_doc
        w_type = self.getclass(space)
        return space.call_function(w_type, w_getter, w_setter, w_deleter,
                                   w_doc)

    def descr_isabstract(self, space):
        return space.newbool(space.isabstractmethod_w(self.w_fget) or
                             space.isabstractmethod_w(self.w_fset) or
                             space.isabstractmethod_w(self.w_fdel))

W_Property.typedef = TypeDef(
    'property',
    __doc__ = '''\
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

fget is a function to be used for getting an attribute value, and likewise
fset is a function for setting, and fdel a function for deleting, an
attribute.  Typical use is to define a managed attribute x:
class C(object):
    def getx(self): return self.__x
    def setx(self, value): self.__x = value
    def delx(self): del self.__x
    x = property(getx, setx, delx, "I am the 'x' property.")''',
    __new__ = generic_new_descr(W_Property),
    __init__ = interp2app(W_Property.init),
    __get__ = interp2app(W_Property.get),
    __set__ = interp2app(W_Property.set),
    __delete__ = interp2app(W_Property.delete),
    __isabstractmethod__ = GetSetProperty(W_Property.descr_isabstract),
    fdel = interp_attrproperty_w('w_fdel', W_Property),
    fget = interp_attrproperty_w('w_fget', W_Property),
    fset = interp_attrproperty_w('w_fset', W_Property),
    getter = interp2app(W_Property.getter),
    setter = interp2app(W_Property.setter),
    deleter = interp2app(W_Property.deleter),
)
# This allows there to be a __doc__ of the property type and a __doc__
# descriptor for the instances.
W_Property.typedef.rawdict['__doc__'] = GetSetProperty(
    W_Property.get_doc, W_Property.set_doc)