New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: allow @property decorator on external ctypedef classes #2640
Conversation
xref #2498 and numpy/numpy#11803 |
2d60950
to
83d5bdd
Compare
I added a The |
It seems the "magic" is in getting from the |
The |
83d5bdd
to
3b931f1
Compare
Rebased off master to get the I needed to add a Other than that, I added a pass to mark the function entry that it is a cgetter function. The |
btw, the |
tests pass |
Is there something more I should do to move this forward? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the (end of year) silence. There seem to be some problems with the implementation that I commented on.
Cython/Compiler/Nodes.py
Outdated
property = False | ||
if self.decorators: | ||
for _node in self.decorators: | ||
if _node.decorator.is_name and _node.decorator.name == 'property': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The repetition of this looping code seems to scream for a helper function, e.g. one that searches for a specific decorator (and maybe applies some safety checks internally).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged with decorator analysis at the beginning of the function. Did you mean that I should refactor that into a helper function?
261ad4d
to
ccb6708
Compare
Cython/Compiler/ExprNodes.py
Outdated
@@ -7146,6 +7146,8 @@ def calculate_result_code(self): | |||
obj_code = obj.result_as(obj.type) | |||
#print "...obj_code =", obj_code ### | |||
if self.entry and self.entry.is_cmethod: | |||
if self.entry.is_cgetter: | |||
return "%s(%s)" %(self.entry.func_cname, obj_code) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace missing after "%".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
elif func.name == 'staticmethod': | ||
pass | ||
else: | ||
error(self.pos, "Cannot handle %s decorators yet" % func.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we must also reject decorators that are not plain names, e.g. attributes or function calls. Anything that's not @property
or @staticmethod
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, extra test added. Since I want to print the type
of the unhandled instance, I needed to rename type
-> type
in that function.
if is_property: | ||
self.entry.is_property = 1 | ||
env.property_entries.append(self.entry) | ||
env.cfunc_entries.remove(self.entry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me wonder why we shouldn't be calling declare_property()
here in the first place, instead of declare_cfunction()
. What do you think? It seems to do the right thing, pretty much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CClassScope.declare_property
does not dive into the wrapped function the way CClassScope.declare_cfuntion
does. I played with this for a while but could not get it to work cleanly, without in the end calling declare_cfunction
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, extra test added. Since I want to print the type
of the unhandled instance, I needed to rename type
-> type
in that function.
Edit: wrong comment
Cython/Compiler/Symtab.py
Outdated
@@ -752,7 +754,8 @@ def register_pyfunction(self, entry): | |||
|
|||
def declare_cfunction(self, name, type, pos, | |||
cname=None, visibility='private', api=0, in_pxd=0, | |||
defining=0, modifiers=(), utility_code=None, overridable=False): | |||
defining=0, modifiers=(), utility_code=None, | |||
overridable=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are now unfortunate, unnecessary changes. Could you undo the signature reformatting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
How do you easily tell which test is failing on travis? I ended up rerunning the failing build locally Edit: ... and it passed :( |
Looks ok now, thanks! |
darn, this isn't quite good enough. It doesn't handle Or maybe this is beyond the scope of where you want cython to go, and the whole thing should be reverted? |
Yeah, that sounds wrong. We should reuse the property infrastructure that we have. IIUC, the only difference is that these properties are resolved at compile time and the underlying method gets called. They are essentially "inline" properties. |
Is there any assumption Property nodes are on python classes and not c classes? Or maybe that's what you mean about "inline". |
They are always on |
(BTW, thanks for asking the right questions and digging into the details of this feature. I think we are slowly getting an idea of where this is really going.) |
I want to get back to this and finish it up.
I am not sure what you mean by this. Looking at the implementation of |
* Rewrite C property support (GH-2640) based on inline C methods. Supersedes GH-2640 and GH-3095. Closes GH-3521. * Test fix for `numpy_parallel.pyx`: avoid depending on whether "nd.shape" requires the GIL or not. * Turn NumPy's "ndarray.data" into a property to avoid direct struct access. * Make "ndarray.size" accessible without the GIL.
Following up the discussion on the mailing list. I got to the point where I can use the new syntax:
Write a srctree test that creates various types of external ctypedef classes, add one that overrides a python-level @Property with a cython one. This is a continuation of the test added in DOC, TST: test and document external extension type attribute aliasing #2629
Add
decorator
child and outer attributes toCFuncDefNode
.I simply copied this from- yes, seems to be requiredDefNode
, is it required?Add aDecoratorTransform.visit_CFuncDefNode
function based onDecoratorTransform.visit_DefNode
and verify it is reached while parsing thectypedef class
.Found the point at which the attribute lookup should become a property function call (I think) is inAttributeNode.analyse_attribute
. But it seems the entry is wrong, I need to eitherfix the entry inPropertyNode.analyse_declarations
and somehow make sure it is used instead of the old entrychange the code inCFuncDefNode.analyse_declarations
and remove theDecoratorTransform.visit_CFuncDefNode
functionAny hints would be welcome.
Edit: added a new pass,
still not working