Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
28fa84b4
Commit
28fa84b4
authored
Feb 14, 2015
by
stijn
Committed by
Damien George
Mar 26, 2015
Browse files
py: Add optional support for descriptors' __get__ and __set__ methods.
Disabled by default. Enabled on unix and windows ports.
parent
c260836b
Changes
7
Show whitespace changes
Inline
Side-by-side
py/mpconfig.h
View file @
28fa84b4
...
...
@@ -364,6 +364,12 @@ typedef double mp_float_t;
#define MICROPY_PY_FUNCTION_ATTRS (0)
#endif
// Whether to support descriptors (__get__ and __set__)
// This costs some code size and makes all load attrs and store attrs slow
#ifndef MICROPY_PY_DESCRIPTORS
#define MICROPY_PY_DESCRIPTORS (0)
#endif
// Whether str object is proper unicode
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
...
...
py/objtype.c
View file @
28fa84b4
...
...
@@ -461,20 +461,38 @@ void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_class_lookup
(
&
lookup
,
self
->
base
.
type
);
mp_obj_t
member
=
dest
[
0
];
if
(
member
!=
MP_OBJ_NULL
)
{
#if MICROPY_PY_BUILTINS_PROPERTY
#if MICROPY_PY_BUILTINS_PROPERTY
if
(
MP_OBJ_IS_TYPE
(
member
,
&
mp_type_property
))
{
// object member is a property
// delegate the store to the property
// TODO should this be part of mp_convert_member_lookup?
// object member is a property; delegate the load to the property
// Note: This is an optimisation for code size and execution time.
// The proper way to do it is have the functionality just below
// in a __get__ method of the property object, and then it would
// be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const
mp_obj_t
*
proxy
=
mp_obj_property_get
(
member
);
if
(
proxy
[
0
]
==
mp_const_none
)
{
// TODO
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_AttributeError
,
"unreadable attribute"
));
}
else
{
dest
[
0
]
=
mp_call_function_n_kw
(
proxy
[
0
],
1
,
0
,
&
self_in
);
// TODO should we convert the returned value using mp_convert_member_lookup?
}
return
;
}
#endif
#endif
#if MICROPY_PY_DESCRIPTORS
// found a class attribute; if it has a __get__ method then call it with the
// class instance and class as arguments and return the result
// Note that this is functionally correct but very slow: each load_attr
// requires an extra mp_load_method_maybe to check for the __get__.
mp_obj_t
attr_get_method
[
4
];
mp_load_method_maybe
(
member
,
MP_QSTR___get__
,
attr_get_method
);
if
(
attr_get_method
[
0
]
!=
MP_OBJ_NULL
)
{
attr_get_method
[
2
]
=
self_in
;
attr_get_method
[
3
]
=
mp_obj_get_type
(
self_in
);
dest
[
0
]
=
mp_call_method_n_kw
(
2
,
0
,
attr_get_method
);
}
#endif
return
;
}
...
...
@@ -495,9 +513,11 @@ void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
bool
mp_obj_instance_store_attr
(
mp_obj_t
self_in
,
qstr
attr
,
mp_obj_t
value
)
{
mp_obj_instance_t
*
self
=
self_in
;
#if MICROPY_PY_BUILTINS_PROPERTY
// for property, we need to do a lookup first in the class dict
// this makes all stores slow... how to fix?
#if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS
// With property and/or descriptors enabled we need to do a lookup
// first in the class dict for the attribute to see if the store should
// be delegated.
// Note: this makes all stores slow... how to fix?
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
struct
class_lookup_data
lookup
=
{
.
obj
=
self
,
...
...
@@ -507,12 +527,20 @@ bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
.
is_type
=
false
,
};
mp_obj_class_lookup
(
&
lookup
,
self
->
base
.
type
);
if
(
member
[
0
]
!=
MP_OBJ_NULL
&&
MP_OBJ_IS_TYPE
(
member
[
0
],
&
mp_type_property
))
{
// attribute already exists and is a property
// delegate the store to the property
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
#if MICROPY_PY_BUILTINS_PROPERTY
if
(
MP_OBJ_IS_TYPE
(
member
[
0
],
&
mp_type_property
))
{
// attribute exists and is a property; delegate the store
// Note: This is an optimisation for code size and execution time.
// The proper way to do it is have the functionality just below
// in a __set__ method of the property object, and then it would
// be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const
mp_obj_t
*
proxy
=
mp_obj_property_get
(
member
[
0
]);
if
(
proxy
[
1
]
==
mp_const_none
)
{
// TODO better error message
// TODO better error message
?
return
false
;
}
else
{
mp_obj_t
dest
[
2
]
=
{
self_in
,
value
};
...
...
@@ -520,7 +548,22 @@ bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
return
true
;
}
}
#endif
#endif
#if MICROPY_PY_DESCRIPTORS
// found a class attribute; if it has a __set__ method then call it with the
// class instance and value as arguments
mp_obj_t
attr_set_method
[
4
];
mp_load_method_maybe
(
member
[
0
],
MP_QSTR___set__
,
attr_set_method
);
if
(
attr_set_method
[
0
]
!=
MP_OBJ_NULL
)
{
attr_set_method
[
2
]
=
self_in
;
attr_set_method
[
3
]
=
value
;
mp_call_method_n_kw
(
2
,
0
,
attr_set_method
);
return
true
;
}
#endif
}
#endif
if
(
value
==
MP_OBJ_NULL
)
{
// delete attribute
...
...
py/qstrdefs.h
View file @
28fa84b4
...
...
@@ -66,6 +66,10 @@ Q(__add__)
Q
(
__sub__
)
Q
(
__repr__
)
Q
(
__str__
)
#if MICROPY_PY_DESCRIPTORS
Q
(
__get__
)
Q
(
__set__
)
#endif
Q
(
__getattr__
)
Q
(
__del__
)
Q
(
__call__
)
...
...
py/vm.c
View file @
28fa84b4
...
...
@@ -393,8 +393,9 @@ dispatch_loop:
DISPATCH
();
}
#else
// This caching code works with MICROPY_PY_BUILTINS_PROPERTY enabled because
// if the attr exists in self->members then it can't be a property. A
// This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or
// MICROPY_PY_DESCRIPTORS enabled because if the attr exists in
// self->members then it can't be a property or have descriptors. A
// consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND
// in the fast-path below, because that store could override a property.
ENTRY
(
MP_BC_STORE_ATTR
)
:
{
...
...
tests/basics/class_descriptor.py
0 → 100644
View file @
28fa84b4
class
Descriptor
:
def
__get__
(
self
,
obj
,
cls
):
print
(
type
(
obj
)
is
Main
)
print
(
cls
is
Main
)
return
'result'
def
__set__
(
self
,
obj
,
val
):
print
(
type
(
obj
)
is
Main
)
print
(
val
)
class
Main
:
Forward
=
Descriptor
()
m
=
Main
()
r
=
m
.
Forward
if
'Descriptor'
in
repr
(
r
.
__class__
):
print
(
'SKIP'
)
else
:
print
(
r
)
m
.
Forward
=
'a'
unix/mpconfigport.h
View file @
28fa84b4
...
...
@@ -58,6 +58,7 @@
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
...
...
windows/mpconfigport.h
View file @
28fa84b4
...
...
@@ -51,6 +51,7 @@
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment