Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
Robert Bradshaw, 18.02.2011 23:08: On Thu, Feb 17, 2011 at 8:38 PM, W. Trevor King wrote: On Thu, Feb 17, 2011 at 3:53 PM, Robert Bradshaw wrote: On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: Compilation is an issue. I think that .pxd files should be able to be cythoned directly, since then they Cython can build any wrappers they request. If the file has a matching .pyx file, cythoning either one should compile both together, since they'll produce a single Python .so module. In this case, I think it may make more sense to consider cimporting stuff from .pyx files if no .pxd file is present. Can you cimport .pyx files that lack matching .pxd files? In any case, this is a big change. I don't like the idea of always creating such a module (it may be empty, or have name conflicts) It shouldn't take to long to compile an empty module ;). And odds are noone will waste time importing it either. nor the idea of conditionally compiling it (does one have to look at the contents and really understand Cython to see if a Python shadow will be created?) I agree here. Under the mantra "explicit is better than implicit", we could have users add something like cdef module "modname" to any .pxd files that should be inflated into Python modules. .pxd files without such a tag would receive the current treatment, error on any cpdef, etc. The drawback of this approach is that it makes Cython more complicated, but if both behaviors are reasonable, there's probably no getting around that. The other drawback is that it subverts the usual filename<-> module name convention that one usually expects. +1 A side effect of this cpdef change would be that now even bare .pxd files (no matching .pyx) would have a Python presence, Where would it live? Would we just create this module (in essence, acting as if there was an empty .pyx file sitting there as well)? On this note, it may be worth pursuing the idea of a "cython helper" module where common code and objects could live. I'm not sure exactly what you mean by "cython helper", but this sounds like my 'bare .pyx can create a Python .so module idea above. I'm thinking of a place to put, e.g. the generator and bind-able function classes, which are now re-implemented in every module that uses them. I think there will be more cases like this in the future rather than less. C-level code could be #included and linked from "global" stores as well. However, that's somewhat tangential. If you generate more than one file from a .pyx, including files that are shared between compiler runs (or even readily built as .so files), you'd quickly end up in dependency hell. When to regenerate that file? With what compiler version and config? C/C++? With/out cleanup code? And where to put it? Are you sure that place will be writable for all compiler runs? And will the result be guaranteed to be reproducible, regardless of how many compiler runs there were in between? Unions don't really have a Python parallel, They can be a cdef class wrapping the union type. But I would think coercion would be difficult. Unions are usually (in my limited experience) for "don't worry about the type, just make sure it fits in X bytes". How would union->Python conversion work? There would be a wrapping type, e.g. cdef class MyUnion: cdef union_type value Wouldn't that have to be a pointer to the real thing instead? with a bunch of setters/getters for the values, just like there are for structs. (In fact the same code would handle structs and unions). This is getting into the wrapper-generator territory, but I'm starting to think for simple things that might be worth it. I think that if Cython will automatically generate a wrapper for cdef public int x it should generate a wrapper for cdef struct X: cdef public int x Or cdef public struct X: int x readonly int z private int z I would perhaps say that non-Pythonable non-private members in public structs would be a compile error. +1, keep it safe at the beginning. There really aren't that metatypes in C, so it doesn't seem like a slippery slope to me. Maybe I'm just missing something... Ok, I think we're pretty much agreed ;). I think that the next step is to start working on implementations of: * Stand alone .pxd -> Python module I'm not sure we're agreed on this one. Same from here. To me, that doesn't make much sense for code that wraps a library. And if it doesn't wrap a library, there isn't much benefit in writing a stand-alone .pxd in the first place. A .pyx is much more explicit and obvious in this case. Especially having some .pxd files that generate .so files and others that don't will make this very ugly. I'd prefer adding support for cimporting from .pyx files instead, potentially with an automated caching generation of corresponding .pxd files (maybe as ".pxdg" files to make them easier to handle for users). Howeve
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 1:24 AM, Stefan Behnel wrote: >>> A side effect of this cpdef change would be that now even bare .pxd >>> files (no matching .pyx) would have a Python presence, >> >> Where would it live? Would we just create this module (in essence, >> acting as if there was an empty .pyx file sitting there as well)? On >> this note, it may be worth pursuing the idea of a "cython helper" >> module where common code and objects could live. > > I'm not sure exactly what you mean by "cython helper", but this sounds > like my 'bare .pyx can create a Python .so module idea above. I'm thinking of a place to put, e.g. the generator and bind-able function classes, which are now re-implemented in every module that uses them. I think there will be more cases like this in the future rather than less. C-level code could be #included and linked from "global" stores as well. However, that's somewhat tangential. > > If you generate more than one file from a .pyx, including files that are > shared between compiler runs (or even readily built as .so files), you'd > quickly end up in dependency hell. When to regenerate that file? With what > compiler version and config? C/C++? With/out cleanup code? And where to put > it? Are you sure that place will be writable for all compiler runs? And will > the result be guaranteed to be reproducible, regardless of how many compiler > runs there were in between? I'd probably make it an option to the cythonize(...) command, so all the regeneration/dependency information would be computed based on the whole fileset rather than trying to figure that out for each individual module compilation. I'm thinking this would be an optimization, not a requirement. >>> Unions don't really have a Python parallel, >> >> They can be a cdef class wrapping the union type. > > But I would think coercion would be difficult. Unions are usually (in > my limited experience) for "don't worry about the type, just make sure > it fits in X bytes". How would union->Python conversion work? There would be a wrapping type, e.g. cdef class MyUnion: cdef union_type value > > Wouldn't that have to be a pointer to the real thing instead? Why? This would be a lot messier to get right, and structs and unions already have pass-by-value semantics. with a bunch of setters/getters for the values, just like there are for structs. (In fact the same code would handle structs and unions). This is getting into the wrapper-generator territory, but I'm starting to think for simple things that might be worth it. >>> >>> I think that if Cython will automatically generate a wrapper for >>> >>> cdef public int x >>> >>> it should generate a wrapper for >>> >>> cdef struct X: cdef public int x >> >> Or >> >> cdef public struct X: >> int x >> readonly int z >> private int z >> >> I would perhaps say that non-Pythonable non-private members in public >> structs would be a compile error. > > +1, keep it safe at the beginning. > > >>> There really aren't that metatypes in C, so it doesn't seem like a >>> slippery slope to me. Maybe I'm just missing something... >>> > Ok, I think we're pretty much agreed ;). I think that the next step > is to start working on implementations of: > > * Stand alone .pxd -> Python module I'm not sure we're agreed on this one. > > Same from here. To me, that doesn't make much sense for code that wraps a > library. And if it doesn't wrap a library, there isn't much benefit in > writing a stand-alone .pxd in the first place. A .pyx is much more explicit > and obvious in this case. Especially having some .pxd files that generate > .so files and others that don't will make this very ugly. > > I'd prefer adding support for cimporting from .pyx files instead, > potentially with an automated caching generation of corresponding .pxd files > (maybe as ".pxdg" files to make them easier to handle for users). However, > cyclic dependencies would be tricky to handle automatically then. We could put the in the new __pycache__. > * Extending class cdef/cdpef/public/readonly handling to cover enums, > stucts, and possibly unions. This seems like the best first step. > > +1 > > > * I don't know how to handle things like dummy enums (perhaps by > requiring all cdef-ed enums to be named). All enums in C are named. >>> >>> But my Cython declaration (exposing a C `#define CONST_A 1`): >>> >>> cdef extern from 'mylib.h': >>> enum: CONST_A >>> >>> is not a named enum. >> >> Ah, yes. Maybe we require a name (that would only be used in Python >> space). > > ... require it for cpdef enums, you mean? > > OTOH, the "enum: NAME" scheme is ugly by itself. There should be a way to > declare external constants correctly. After all, we loose all type > information that way
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Fri, Feb 18, 2011 at 02:08:04PM -0800, Robert Bradshaw wrote: > On Thu, Feb 17, 2011 at 8:38 PM, W. Trevor King wrote: > > On Thu, Feb 17, 2011 at 3:53 PM, Robert Bradshaw wrote: > >> On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: > >>> On Thu, Feb 17, 2011 at 01:25:10PM -0800, Robert Bradshaw wrote: > On Thu, Feb 17, 2011 at 5:29 AM, W. Trevor King wrote: > > On Wed, Feb 16, 2011 at 03:55:19PM -0800, Robert Bradshaw wrote: > >> On Wed, Feb 16, 2011 at 8:17 AM, W. Trevor King wrote: > >> > What I'm missing is a way to bind the ModuleScope namespace to a > >> > name > >> > in expose.pyx so that commands like `dir(mylib)` and `getattr(mylib, > >> > name)` will work in expose.pyx. > >> > >> You have also hit into the thorny issue that .pxd files are used for > >> many things. They may be pure C library declarations with no Python > >> module backing, they may be declarations of (externally implemented) > >> Python modules (such as numpy.pxd), or they may be declarations for > >> Cython-implemented modules. > >> > >> Here's another idea, what if extern blocks could contain cpdef > >> declarations, which would automatically generate a Python-level > >> wrappers for the declared members (if possible, otherwise an error)? > > > > Ah, this sounds good! Of the three .pxd roles you list above, > > external Python modules (e.g. numpy) and Cython-implemented modules > > (e.g. matched .pxd/.pyx) both already have a presence in Python-space. > > What's missing is a way to give (where possible) declarations of > > external C libraries a Python presence. cpdef fills this hole nicely, > > since its whole purpose is to expose Python interfaces to > > C-based elements. > > In the case of external Python modules, I'm not so sure we want to > monkey-patch our stuff in > >>> > >>> I don't think any of the changes we are suggesting would require > >>> changes to existing code, so .pxd-s with external implementations > >>> wouldn't be affected unless they brough the changes upon themselves. > >> > >> Say, in numpy.pxd, I have > >> > >> cdef extern from "...": > >>cpdef struct obscure_internal_struct: > >>... > >> > >> Do we add an "obscure_internal_struct" onto the (global) numpy module? > >> What if it conflicts with a (runtime) name? This is the issue I'm > >> bringing up. > > > > Defining a cpdef *and* a non-matching external implementation should > > raise a compile-time error. I agree that there is a useful > > distinction between external-C-library and external-Python-module .pxd > > wrappers. Perhaps your matching blank .py or .pyx file could serve as > > a marker that the .pxd file should be inflated into its own full > > fledged python module. I'm not even sure how you would go about > > adding attributes to the numpy module. When/how would the > > Cython-created attributes get added? > > Yes, this is exactly the issue. Ah, I'm retracting my agreement on the external-C-library and external-Python-module .pxd wrappers. There is no difference in how their .pxd files should be treated, and I now agree that .pxd files should not generate .so modules unless they have a paried .py/.pyx file. > > If you try to override anything in a .so compiled module at runtime, > > you'd get the same kind of error you currently do trying to rebind a > > compiled class' method. > > That's the desired behavior for statically-bound globals, but > implementing it is not so trivial. It's currently implemented for classes. Are modules that different from classes? >>> import types >>> types.ModuleType.__class__.__mro__ (, ) So you've got your standard __setattr__ to override with an error-message generator. What is the implementation difficulty? I am also unclear about the distinction between cdef and cpdef (perhaps this should be a new thread?). cpdef means "I'm declaring something with C and Python interfaces. The Python interface is a thin wrapper which can be rebound to an object of any type, leaving the static C interface inaccessible from Python." cdef [private] means "I'm declaring something that only has a C interface." cdef public means "I'm declaring something with C and Python interfaces backed by C data. Python code can alter the C data." cdef readonly means "I'm declaring something with C and Python interfaces backed by C data. Python code cannot alter the C data." This seems to be broken in Cython at the module level, since I can rebind a cdef-ed class but not a cpdef-ed method: $ cat square.pyx cdef class A (object): cdef public int value cpdef square(self): return self.value**2 $ python -c 'import pyximport; pyximport.install(); import xx; a = xx.A(); a.value = 3; print a.square(); a.square = lambda self: self.value' Traceback (most recent call last):
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Thu, Feb 17, 2011 at 03:53:13PM -0800, Robert Bradshaw wrote: > On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: > > * Extending class cdef/cdpef/public/readonly handling to cover enums, > > stucts, and possibly unions. > > This seems like the best first step. > > > Problems with me getting started now: > > > > * I don't know where I should start mucking about in the source. > > ...The other files to look at would be Parsing.py,.. I've got the the Parsing pretty much working, but portions of the test suite are now failing with things like === Expected errors: === 1:5: function definition in pxd file must be declared 'cdef inline' 4:5: inline function definition in pxd file cannot be 'public' 7:5: inline function definition in pxd file cannot be 'api' === Got errors: === 1:5: function definition in pxd file must be declared 'cdef inline' 4:12: inline function definition in pxd file cannot be 'public' 7:5: inline function definition in pxd file cannot be 'api' while cythoning tests/errors/e_func_in_pxd_support.pxd: cdef foo(): return 1 cdef public inline foo2(): return 1 cdef api inline foo3(): return 1 The current Cython implementation does not consider 'cdef' to be part of the node code, and my current implementation does not consider any qualifiers to be part of the node code. It's unclear to me what the "right" position is for the start of a function (or variable, class, ...) should be, or how errors should be formatted. My initial impression is that Node.pos should point to the beginning of the def (here 1:1, 4:1, and 7:1), but that positions of the various qualifiers (cdef, public, inline, api, ...) should be cached so that the error points to the offending qualifier. Thoughs? -- This email may be signed or encrypted with GPG (http://www.gnupg.org). The GPG signature (if present) will be attached as 'signature.asc'. For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy My public key is at http://www.physics.drexel.edu/~wking/pubkey.txt pgpWK2nBwsk8N.pgp Description: PGP signature ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King wrote: >> > If you try to override anything in a .so compiled module at runtime, >> > you'd get the same kind of error you currently do trying to rebind a >> > compiled class' method. >> >> That's the desired behavior for statically-bound globals, but >> implementing it is not so trivial. > > It's currently implemented for classes. Are modules that different > from classes? > > >>> import types > >>> types.ModuleType.__class__.__mro__ > (, ) > > So you've got your standard __setattr__ to override with an > error-message generator. What is the implementation difficulty? You can't just add a __setattr__ to a module and have it work, it's a class-level slot. And you don't want to modify all module classes. To do this you have to subclass module itself and insert that in place during import. > I am also unclear about the distinction between cdef and cpdef > (perhaps this should be a new thread?). > > cpdef means "I'm declaring something with C and Python interfaces. > The Python interface is a thin wrapper which can be rebound to an > object of any type, leaving the static C interface inaccessible from > Python." No, you can't re-bind cdef class methods. Despite Cython's attempt to homogenize things for the user, extension classes are quite different than "normal" Python classes. This is a Python C/API issue. > cdef [private] means "I'm declaring something that only has a C > interface." > cdef public means "I'm declaring something with C and Python > interfaces backed by C data. Python code can alter the C data." > cdef readonly means "I'm declaring something with C and Python > interfaces backed by C data. Python code cannot alter the C data." cdef means "back this by a C variable" > This seems to be broken in Cython at the module level, since I can > rebind a cdef-ed class but not a cpdef-ed method: Yes, we don't currently control the module's set/getattr. And classes are "public" by default. > $ cat square.pyx > cdef class A (object): > cdef public int value > > cpdef square(self): > return self.value**2 > $ python -c 'import pyximport; pyximport.install(); import xx; > a = xx.A(); a.value = 3; print a.square(); > a.square = lambda self: self.value' > Traceback (most recent call last): > File "", line 3, in > AttributeError: 'square.A' object attribute 'square' is read-only > $ python -c 'import pyximport; pyximport.install(); import square; > square.A = object; print square.A; a = square.A(); a.value = 3' > > Traceback (most recent call last): > File "", line 2, in > AttributeError: 'object' object has no attribute 'value' > > So the cdef-ed A currently has a rebindable Python interface (acting > like a hypothetical cpdef-ed class), but it's square method is not > rebindable (acting like a hypothetical `cdef readonly`-ed method). > >> (and where would we do it--on the first import of a cimporting >> module?) >> >>> >> >>> Compilation is an issue. I think that .pxd files should be able to be >> >>> cythoned directly, since then they Cython can build any wrappers they >> >>> request. If the file has a matching .pyx file, cythoning either one >> >>> should compile both together, since they'll produce a single Python >> >>> .so module. >> >> >> >> ... >> > >> > Under the mantra "explicit is better than implicit", we could have >> > users add something like >> > >> > cdef module "modname" >> > >> > to any .pxd files that should be inflated into Python modules. .pxd >> > files without such a tag would receive the current treatment, error on >> > any cpdef, etc. The drawback of this approach is that it makes Cython >> > more complicated, but if both behaviors are reasonable, there's >> > probably no getting around that. >> >> The other drawback is that it subverts the usual filename <-> module >> name convention that one usually expects. > > I've been convinced that the `cimport .pyx file` route is a better way > to go. > > However, the filename <-> module mapping is troublesome for backing > externally-implemented Python modules (e.g. numpy). If you wanted to > write a .pxd file backing numpy.random, how would you go about getting > your module installed in Cython/Includes/numpy/random.pxd or another > path that cython would successfully match with `cimport numpy.random`? Note that extern blocks (by definition) declare where things come from. > On Sat, Feb 19, 2011 at 10:24:05AM +0100, Stefan Behnel wrote: >> Robert Bradshaw, 18.02.2011 23:08: >> > On Thu, Feb 17, 2011 at 8:38 PM, W. Trevor King wrote: >> >> On Thu, Feb 17, 2011 at 3:53 PM, Robert Bradshaw wrote: >> >>> On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: >> >> A side effect of this cpdef change would be that now even bare .pxd >> >> files (no matching .pyx) would have a Python presence, >> > >> > Where would it live? Would we just create this mo
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 11:35 AM, W. Trevor King wrote: > On Thu, Feb 17, 2011 at 03:53:13PM -0800, Robert Bradshaw wrote: >> On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: >> > * Extending class cdef/cdpef/public/readonly handling to cover enums, >> > stucts, and possibly unions. >> >> This seems like the best first step. >> >> > Problems with me getting started now: >> > >> > * I don't know where I should start mucking about in the source. >> >> ...The other files to look at would be Parsing.py,.. > > I've got the the Parsing pretty much working, but portions of the test > suite are now failing with things like > > === Expected errors: === > 1:5: function definition in pxd file must be declared 'cdef inline' > 4:5: inline function definition in pxd file cannot be 'public' > 7:5: inline function definition in pxd file cannot be 'api' > > > === Got errors: === > 1:5: function definition in pxd file must be declared 'cdef inline' > 4:12: inline function definition in pxd file cannot be 'public' > 7:5: inline function definition in pxd file cannot be 'api' > > while cythoning tests/errors/e_func_in_pxd_support.pxd: > > cdef foo(): > return 1 > > cdef public inline foo2(): > return 1 > > cdef api inline foo3(): > return 1 > > The current Cython implementation does not consider 'cdef' to be part > of the node code, and my current implementation does not consider any > qualifiers to be part of the node code. > > It's unclear to me what the "right" position is for the start of a > function (or variable, class, ...) should be, or how errors should be > formatted. My initial impression is that Node.pos should point to the > beginning of the def (here 1:1, 4:1, and 7:1), but that positions of > the various qualifiers (cdef, public, inline, api, ...) should be > cached so that the error points to the offending qualifier. For better or for worse, Cython follows the same inane declarator rules as C, so cdef int a, *b, c[5], (*d)(int) is valid. This colors how c function declarations are expressed in the tree. Qualifiers don't really live in the tree and I'm not sure plumbing the "qualifier node" positions around would be worth the added complexity. - Robert ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 1:06 PM, W. Trevor King wrote: > So should I go ahead and update the expected error messages in my branch? Yes. ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 12:52:38PM -0800, Robert Bradshaw wrote: > On Sat, Feb 19, 2011 at 11:35 AM, W. Trevor King wrote: > > On Thu, Feb 17, 2011 at 03:53:13PM -0800, Robert Bradshaw wrote: > >> On Thu, Feb 17, 2011 at 3:12 PM, W. Trevor King wrote: > >> > * Extending class cdef/cdpef/public/readonly handling to cover enums, > >> > stucts, and possibly unions. > >> > >> This seems like the best first step. > >> > >> > Problems with me getting started now: > >> > > >> > * I don't know where I should start mucking about in the source. > >> > >> ...The other files to look at would be Parsing.py,.. > > > > I've got the the Parsing pretty much working, but portions of the test > > suite are now failing with things like > > > >=== Expected errors: === > >1:5: function definition in pxd file must be declared 'cdef inline' > >4:5: inline function definition in pxd file cannot be 'public' > >7:5: inline function definition in pxd file cannot be 'api' > > > > > >=== Got errors: === > >1:5: function definition in pxd file must be declared 'cdef inline' > >4:12: inline function definition in pxd file cannot be 'public' > >7:5: inline function definition in pxd file cannot be 'api' > > > > while cythoning tests/errors/e_func_in_pxd_support.pxd: > > > >cdef foo(): > >return 1 > > > >cdef public inline foo2(): > >return 1 > > > >cdef api inline foo3(): > >return 1 > > > > The current Cython implementation does not consider 'cdef' to be part > > of the node code, and my current implementation does not consider any > > qualifiers to be part of the node code. > > > > It's unclear to me what the "right" position is for the start of a > > function (or variable, class, ...) should be, or how errors should be > > formatted. My initial impression is that Node.pos should point to the > > beginning of the def (here 1:1, 4:1, and 7:1), but that positions of > > the various qualifiers (cdef, public, inline, api, ...) should be > > cached so that the error points to the offending qualifier. > > For better or for worse, Cython follows the same inane declarator > rules as C, so > > cdef int a, *b, c[5], (*d)(int) > > is valid. This colors how c function declarations are expressed in the > tree. Qualifiers don't really live in the tree and I'm not sure > plumbing the "qualifier node" positions around would be worth the > added complexity. So should I go ahead and update the expected error messages in my branch? -- This email may be signed or encrypted with GPG (http://www.gnupg.org). The GPG signature (if present) will be attached as 'signature.asc'. For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy My public key is at http://www.physics.drexel.edu/~wking/pubkey.txt pgpb5IXeiawOW.pgp Description: PGP signature ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: > On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King wrote: > > >> > If you try to override anything in a .so compiled module at runtime, > >> > you'd get the same kind of error you currently do trying to rebind a > >> > compiled class' method. > >> > >> That's the desired behavior for statically-bound globals, but > >> implementing it is not so trivial. > > > > It's currently implemented for classes. Are modules that different > > from classes? > > > >>>> import types > >>>> types.ModuleType.__class__.__mro__ > >(, ) > > > > So you've got your standard __setattr__ to override with an > > error-message generator. What is the implementation difficulty? > > You can't just add a __setattr__ to a module and have it work, it's a > class-level slot. And you don't want to modify all module classes. To > do this you have to subclass module itself and insert that in place > during import. So annoying but possible? Not particularly critical either way, though, since you could always say "don't rebind module-level stuff" in a project's docs, even if you don't enforce that at the Cython level. > > I am also unclear about the distinction between cdef and cpdef > > (perhaps this should be a new thread?). > > > > cpdef means "I'm declaring something with C and Python interfaces. > > The Python interface is a thin wrapper which can be rebound to an > > object of any type, leaving the static C interface inaccessible from > > Python." > > No, you can't re-bind cdef class methods. Despite Cython's attempt to > homogenize things for the user, extension classes are quite different > than "normal" Python classes. This is a Python C/API issue. Do you mean `cpdef class methods`? If so, you're right: $ cat square.pyx cdef class A (object): cdef public int value cpdef square(self): return self.value**2 $ python -c 'import pyximport; pyximport.install(); import square; square.A.square = lambda self: self.value' Traceback (most recent call last): File "", line 1, in TypeError: can't set attributes of built-in/extension type 'square.A' You can't override them in instances either: $ python -c 'import pyximport; pyximport.install(); import square; a = square.A(); a.square = lambda self: self.value' Traceback (most recent call last): File "", line 1, in AttributeError: 'square.A' object attribute 'square' is read-only But you can override them in subclasses, which is, I suppose, the point of cpdef for methods. > > cdef [private] means "I'm declaring something that only has a C > > interface." > > cdef public means "I'm declaring something with C and Python > > interfaces backed by C data. Python code can alter the C data." > > cdef readonly means "I'm declaring something with C and Python > > interfaces backed by C data. Python code cannot alter the C data." > > cdef means "back this by a C variable" Ah, ok. That makes more sense. > > However, the filename <-> module mapping is troublesome for backing > > externally-implemented Python modules (e.g. numpy). If you wanted to > > write a .pxd file backing numpy.random, how would you go about getting > > your module installed in Cython/Includes/numpy/random.pxd or another > > path that cython would successfully match with `cimport numpy.random`? > > Note that extern blocks (by definition) declare where things come from. They declare where the .pxd file looks for .h files, but not where .pyx files look for the .pxd file. > >> > cdef public struct X: > >> > int x > >> > readonly int z > >> > private int z > >> > > >> > I would perhaps say that non-Pythonable non-private members in public > >> > structs would be a compile error. > >> > >> +1, keep it safe at the beginning. > > > > -1, keep the code clean and the interface consistent ;). I think the > > struct syntax should be identical to the class syntax, with the > > exception that you can't bind methods to structs. That's the only > > real difference between structs and classes, isn't it? > > In C++, the only difference between structs and classes is that struct > members are public by default. (Not saying that C++ is always the > model to follow, but it gives precedent). And structs can have > function members, that's how to do OOP in C. Oh. Even more reason to have identical struct and class handling in Cython ;). It is unclear to me what `cdef public struct` means. I think it should mean "Python bindings can alter this struct's definition", which doesn't make sense. Shouldn't the syntax for public members be cdef struct X: cdef public: int x readonly int y private int z > > If safety with a new feature is a concern, a warning like > > "EXPERIMENTAL FEATURE" in the associated docs and compiler output > > should be sufficient. > > I thi
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 1:45 PM, W. Trevor King wrote: > On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: >> On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King wrote: >> >> >> > If you try to override anything in a .so compiled module at runtime, >> >> > you'd get the same kind of error you currently do trying to rebind a >> >> > compiled class' method. >> >> >> >> That's the desired behavior for statically-bound globals, but >> >> implementing it is not so trivial. >> > >> > It's currently implemented for classes. Are modules that different >> > from classes? >> > >> > >>> import types >> > >>> types.ModuleType.__class__.__mro__ >> > (, ) >> > >> > So you've got your standard __setattr__ to override with an >> > error-message generator. What is the implementation difficulty? >> >> You can't just add a __setattr__ to a module and have it work, it's a >> class-level slot. And you don't want to modify all module classes. To >> do this you have to subclass module itself and insert that in place >> during import. > > So annoying but possible? Not particularly critical either way, > though, since you could always say "don't rebind module-level stuff" > in a project's docs, even if you don't enforce that at the Cython > level. It's still something I'd like to do. This could also be used to allow fast access to module globals and easier sharing of declarations. >> > I am also unclear about the distinction between cdef and cpdef >> > (perhaps this should be a new thread?). >> > >> > cpdef means "I'm declaring something with C and Python interfaces. >> > The Python interface is a thin wrapper which can be rebound to an >> > object of any type, leaving the static C interface inaccessible from >> > Python." >> >> No, you can't re-bind cdef class methods. Despite Cython's attempt to >> homogenize things for the user, extension classes are quite different >> than "normal" Python classes. This is a Python C/API issue. > > Do you mean `cpdef class methods`? If so, you're right: > > $ cat square.pyx > cdef class A (object): > cdef public int value > > cpdef square(self): > return self.value**2 > $ python -c 'import pyximport; pyximport.install(); import square; > square.A.square = lambda self: self.value' > Traceback (most recent call last): > File "", line 1, in > TypeError: can't set attributes of built-in/extension type 'square.A' > > You can't override them in instances either: > > $ python -c 'import pyximport; pyximport.install(); import square; > a = square.A(); a.square = lambda self: self.value' > Traceback (most recent call last): > File "", line 1, in > AttributeError: 'square.A' object attribute 'square' is read-only > > But you can override them in subclasses, which is, I suppose, the > point of cpdef for methods. Yes, otherwise they would have been pretty easy to implement :). >> > cdef [private] means "I'm declaring something that only has a C >> > interface." >> > cdef public means "I'm declaring something with C and Python >> > interfaces backed by C data. Python code can alter the C data." >> > cdef readonly means "I'm declaring something with C and Python >> > interfaces backed by C data. Python code cannot alter the C data." >> >> cdef means "back this by a C variable" > > Ah, ok. That makes more sense. > >> > However, the filename <-> module mapping is troublesome for backing >> > externally-implemented Python modules (e.g. numpy). If you wanted to >> > write a .pxd file backing numpy.random, how would you go about getting >> > your module installed in Cython/Includes/numpy/random.pxd or another >> > path that cython would successfully match with `cimport numpy.random`? >> >> Note that extern blocks (by definition) declare where things come from. > > They declare where the .pxd file looks for .h files, but not where > .pyx files look for the .pxd file. Sorry, I should have said extern blocks that make cdef class declarations (such as our numpy.pxd). >> >> > cdef public struct X: >> >> > int x >> >> > readonly int z >> >> > private int z >> >> > >> >> > I would perhaps say that non-Pythonable non-private members in public >> >> > structs would be a compile error. >> >> >> >> +1, keep it safe at the beginning. >> > >> > -1, keep the code clean and the interface consistent ;). I think the >> > struct syntax should be identical to the class syntax, with the >> > exception that you can't bind methods to structs. That's the only >> > real difference between structs and classes, isn't it? >> >> In C++, the only difference between structs and classes is that struct >> members are public by default. (Not saying that C++ is always the >> model to follow, but it gives precedent). And structs can have >> function members, that's how to do OOP in C. > > Oh. Even more reason to have identical struct and class handling in > Cython ;). > > It is unc
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 02:04:16PM -0800, Robert Bradshaw wrote: > On Sat, Feb 19, 2011 at 1:45 PM, W. Trevor King wrote: > > On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: > >> On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King wrote: > >> > However, the filename <-> module mapping is troublesome for backing > >> > externally-implemented Python modules (e.g. numpy). If you wanted to > >> > write a .pxd file backing numpy.random, how would you go about getting > >> > your module installed in Cython/Includes/numpy/random.pxd or another > >> > path that cython would successfully match with `cimport numpy.random`? > >> > >> Note that extern blocks (by definition) declare where things come from. > > > > They declare where the .pxd file looks for .h files, but not where > > .pyx files look for the .pxd file. > > Sorry, I should have said extern blocks that make cdef class > declarations (such as our numpy.pxd). It doesn't look like there are cdef class declarations in numpy.pxd: cython $ grep class Cython/Includes/numpy.pxd ctypedef class numpy.dtype [object PyArray_Descr]: ctypedef extern class numpy.flatiter [object PyArrayIterObject]: ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]: ctypedef class numpy.ndarray [object PyArrayObject]: ctypedef extern class numpy.ufunc [object PyUFuncObject]: This still doesn't explain how .pxd files specify which external implemented Python modules they correspond to. > >> >> > cdef public struct X: > >> >> > int x > >> >> > readonly int z > >> >> > private int z > >> >> > > >> >> > I would perhaps say that non-Pythonable non-private members in public > >> >> > structs would be a compile error. > >> >> > >> >> +1, keep it safe at the beginning. > >> > > >> > -1, keep the code clean and the interface consistent ;). I think the > >> > struct syntax should be identical to the class syntax, with the > >> > exception that you can't bind methods to structs. That's the only > >> > real difference between structs and classes, isn't it? > >> > >> In C++, the only difference between structs and classes is that struct > >> members are public by default. (Not saying that C++ is always the > >> model to follow, but it gives precedent). And structs can have > >> function members, that's how to do OOP in C. > > > > Oh. Even more reason to have identical struct and class handling in > > Cython ;). > > > > It is unclear to me what `cdef public struct` means. I think it > > should mean "Python bindings can alter this struct's definition", > > which doesn't make sense. > > I think it should mean "this struct is accessible from Python (as X)" Wouldn't that be "cdef readonly struct X"? > > Shouldn't the syntax for public members be > > > >cdef struct X: > >cdef public: > >int x > >readonly int y > >private int z > > -1 on nesting things like this. Rather than make a struct visible from > Python iff any of its members are, A struct is visible from python iff it is declared public or readonly: cdef public struct X: ... or cdef readonly struct X: ... I don't think the visibility of the struct as a whole should have any effect over the visibility of its members, so you should be able to specify member visibility explicitly with per-member granularity (as you currently can for classes). I was assuming that structs would be public by default (like classes), but that is obviously configurable. > I think it makes more sense to put > the declaration on the struct itself. We could support > > cdef public struct X: > int x # public > > cdef readonly struct Y: > int y # readonly > > cdef [private] struct Z: > int z # private, as we don't even have Z in the Python namespace, > and no wrapper is created. The problems with this are: * It's differnent from how we handle the almost identical class case. * It makes it impossible to define, for example a public struct with C-only attributes: cdef public struct X: cdef public int a cdef private void* ptr Obviously, public attributes of private structs should raise compile-time Cython errors. > >> > If safety with a new feature is a concern, a warning like > >> > "EXPERIMENTAL FEATURE" in the associated docs and compiler output > >> > should be sufficient. > >> > >> I think the point of "safe" is to start out with a compiler error, and > >> we can change our minds later, which is better than trying to make > >> legal statements illegal in the future. > > > > Ok, but I still don't understand why the cdefs were removed from the > > proposed structure members, when they are required for class > > definitions. > > Because structs can only have c members, so the cdef was entirely > redundant. They weren't really removed per say, it's just that with > the exception of cdef classes, "cdef ..." meant "a c declaration > follow
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 3:31 PM, W. Trevor King wrote: > On Sat, Feb 19, 2011 at 02:04:16PM -0800, Robert Bradshaw wrote: >> On Sat, Feb 19, 2011 at 1:45 PM, W. Trevor King wrote: >> > On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: >> >> On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King wrote: >> >> > However, the filename <-> module mapping is troublesome for backing >> >> > externally-implemented Python modules (e.g. numpy). If you wanted to >> >> > write a .pxd file backing numpy.random, how would you go about getting >> >> > your module installed in Cython/Includes/numpy/random.pxd or another >> >> > path that cython would successfully match with `cimport numpy.random`? >> >> >> >> Note that extern blocks (by definition) declare where things come from. >> > >> > They declare where the .pxd file looks for .h files, but not where >> > .pyx files look for the .pxd file. >> >> Sorry, I should have said extern blocks that make cdef class >> declarations (such as our numpy.pxd). > > It doesn't look like there are cdef class declarations in numpy.pxd: > > cython $ grep class Cython/Includes/numpy.pxd > ctypedef class numpy.dtype [object PyArray_Descr]: > ctypedef extern class numpy.flatiter [object PyArrayIterObject]: > ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]: > ctypedef class numpy.ndarray [object PyArrayObject]: > ctypedef extern class numpy.ufunc [object PyUFuncObject]: > > This still doesn't explain how .pxd files specify which external > implemented Python modules they correspond to. "numpy.dtype" is the fully qualified name of the class it's declaring--the module is "numpy." >> >> >> > cdef public struct X: >> >> >> > int x >> >> >> > readonly int z >> >> >> > private int z >> >> >> > >> >> >> > I would perhaps say that non-Pythonable non-private members in public >> >> >> > structs would be a compile error. >> >> >> >> >> >> +1, keep it safe at the beginning. >> >> > >> >> > -1, keep the code clean and the interface consistent ;). I think the >> >> > struct syntax should be identical to the class syntax, with the >> >> > exception that you can't bind methods to structs. That's the only >> >> > real difference between structs and classes, isn't it? >> >> >> >> In C++, the only difference between structs and classes is that struct >> >> members are public by default. (Not saying that C++ is always the >> >> model to follow, but it gives precedent). And structs can have >> >> function members, that's how to do OOP in C. >> > >> > Oh. Even more reason to have identical struct and class handling in >> > Cython ;). >> > >> > It is unclear to me what `cdef public struct` means. I think it >> > should mean "Python bindings can alter this struct's definition", >> > which doesn't make sense. >> >> I think it should mean "this struct is accessible from Python (as X)" > > Wouldn't that be "cdef readonly struct X"? > >> > Shouldn't the syntax for public members be >> > >> > cdef struct X: >> > cdef public: >> > int x >> > readonly int y >> > private int z >> >> -1 on nesting things like this. Rather than make a struct visible from >> Python iff any of its members are, > > A struct is visible from python iff it is declared public or readonly: > > cdef public struct X: > ... > > or > > cdef readonly struct X: > ... > > I don't think the visibility of the struct as a whole should have any > effect over the visibility of its members, so you should be able to > specify member visibility explicitly with per-member granularity (as > you currently can for classes). > > I was assuming that structs would be public by default (like classes), > but that is obviously configurable. > >> I think it makes more sense to put >> the declaration on the struct itself. We could support >> >> cdef public struct X: >> int x # public >> >> cdef readonly struct Y: >> int y # readonly >> >> cdef [private] struct Z: >> int z # private, as we don't even have Z in the Python namespace, >> and no wrapper is created. > > The problems with this are: > > * It's differnent from how we handle the almost identical class case. True it's different, but there are significant differences between classes and structs in Cython, and this is the way things are now. > * It makes it impossible to define, for example a public struct with > C-only attributes: > > cdef public struct X: > cdef public int a > cdef private void* ptr ? The above would work just fine. I was proposing that it would be semantically equivalent to cdef public struct X: cdef int a cdef private void* ptr Perhaps that was not clear. Consider the currently valid cdef struct X: int a void* ptr We can't make everything public by default, as this would break valid code. (I don't think it's a good idea to make the default visibility of a member b
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 04:41:27PM -0800, Robert Bradshaw wrote: > On Sat, Feb 19, 2011 at 3:31 PM, W. Trevor King wrote: > > On Sat, Feb 19, 2011 at 02:04:16PM -0800, Robert Bradshaw wrote: > >> On Sat, Feb 19, 2011 at 1:45 PM, W. Trevor King wrote: > >> > On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: > >> >> On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King > >> >> wrote: > >> >> > However, the filename <-> module mapping is troublesome for backing > >> >> > externally-implemented Python modules (e.g. numpy). If you wanted to > >> >> > write a .pxd file backing numpy.random, how would you go about getting > >> >> > your module installed in Cython/Includes/numpy/random.pxd or another > >> >> > path that cython would successfully match with `cimport numpy.random`? > >> >> > >> >> Note that extern blocks (by definition) declare where things come from. > >> > > >> > They declare where the .pxd file looks for .h files, but not where > >> > .pyx files look for the .pxd file. > >> > >> Sorry, I should have said extern blocks that make cdef class > >> declarations (such as our numpy.pxd). > > > > It doesn't look like there are cdef class declarations in numpy.pxd: > > > >cython $ grep class Cython/Includes/numpy.pxd > >ctypedef class numpy.dtype [object PyArray_Descr]: > >ctypedef extern class numpy.flatiter [object PyArrayIterObject]: > >ctypedef extern class numpy.broadcast [object > > PyArrayMultiIterObject]: > >ctypedef class numpy.ndarray [object PyArrayObject]: > >ctypedef extern class numpy.ufunc [object PyUFuncObject]: > > > > This still doesn't explain how .pxd files specify which external > > implemented Python modules they correspond to. > > "numpy.dtype" is the fully qualified name of the class it's > declaring--the module is "numpy." Hmm, that means that cimport numpy a = numpy.numpy.ndarray also compiles. Wouldn't it make more sense to mirror numpy's module structure when backing it? You do have nested .pxd modules for cpython, libc, etc. > >> >> >> > cdef public struct X: > >> >> >> > int x > >> >> >> > readonly int z > >> >> >> > private int z > >> >> >> > > >> >> >> > I would perhaps say that non-Pythonable non-private members in > >> >> >> > public > >> >> >> > structs would be a compile error. > >> >> >> > >> >> >> +1, keep it safe at the beginning. > >> >> > > >> >> > -1, keep the code clean and the interface consistent ;). I think the > >> >> > struct syntax should be identical to the class syntax, with the > >> >> > exception that you can't bind methods to structs. That's the only > >> >> > real difference between structs and classes, isn't it? > >> >> > >> >> In C++, the only difference between structs and classes is that struct > >> >> members are public by default. (Not saying that C++ is always the > >> >> model to follow, but it gives precedent). And structs can have > >> >> function members, that's how to do OOP in C. > >> > > >> > Oh. Even more reason to have identical struct and class handling in > >> > Cython ;). > >> > > >> > It is unclear to me what `cdef public struct` means. I think it > >> > should mean "Python bindings can alter this struct's definition", > >> > which doesn't make sense. > >> > >> I think it should mean "this struct is accessible from Python (as X)" > > > > Wouldn't that be "cdef readonly struct X"? > > > >> > Shouldn't the syntax for public members be > >> > > >> >cdef struct X: > >> >cdef public: > >> >int x > >> >readonly int y > >> >private int z > >> > >> -1 on nesting things like this. Rather than make a struct visible from > >> Python iff any of its members are, > > > > A struct is visible from python iff it is declared public or readonly: > > > >cdef public struct X: > >... > > > > or > > > >cdef readonly struct X: > >... > > > > I don't think the visibility of the struct as a whole should have any > > effect over the visibility of its members, so you should be able to > > specify member visibility explicitly with per-member granularity (as > > you currently can for classes). > > > > I was assuming that structs would be public by default (like classes), > > but that is obviously configurable. > > > >> I think it makes more sense to put > >> the declaration on the struct itself. We could support > >> > >> cdef public struct X: > >> int x # public > >> > >> cdef readonly struct Y: > >> int y # readonly > >> > >> cdef [private] struct Z: > >> int z # private, as we don't even have Z in the Python namespace, > >> and no wrapper is created. > > > > The problems with this are: > > > > * It's differnent from how we handle the almost identical class case. > > True it's different, but there are significant differences between > classes and structs in Cython, and this is the way things are now. Ah, well. I suppose I'll leave the Parser pretty much alone. Cl
Re: [Cython] [cython-users] Cython .pxd introspection: listing defined constants
On Sat, Feb 19, 2011 at 6:32 PM, W. Trevor King wrote: > On Sat, Feb 19, 2011 at 04:41:27PM -0800, Robert Bradshaw wrote: >> On Sat, Feb 19, 2011 at 3:31 PM, W. Trevor King wrote: >> > On Sat, Feb 19, 2011 at 02:04:16PM -0800, Robert Bradshaw wrote: >> >> On Sat, Feb 19, 2011 at 1:45 PM, W. Trevor King wrote: >> >> > On Sat, Feb 19, 2011 at 12:47:41PM -0800, Robert Bradshaw wrote: >> >> >> On Sat, Feb 19, 2011 at 11:22 AM, W. Trevor King >> >> >> wrote: >> >> >> > However, the filename <-> module mapping is troublesome for backing >> >> >> > externally-implemented Python modules (e.g. numpy). If you wanted to >> >> >> > write a .pxd file backing numpy.random, how would you go about >> >> >> > getting >> >> >> > your module installed in Cython/Includes/numpy/random.pxd or another >> >> >> > path that cython would successfully match with `cimport >> >> >> > numpy.random`? >> >> >> >> >> >> Note that extern blocks (by definition) declare where things come from. >> >> > >> >> > They declare where the .pxd file looks for .h files, but not where >> >> > .pyx files look for the .pxd file. >> >> >> >> Sorry, I should have said extern blocks that make cdef class >> >> declarations (such as our numpy.pxd). >> > >> > It doesn't look like there are cdef class declarations in numpy.pxd: >> > >> > cython $ grep class Cython/Includes/numpy.pxd >> > ctypedef class numpy.dtype [object PyArray_Descr]: >> > ctypedef extern class numpy.flatiter [object PyArrayIterObject]: >> > ctypedef extern class numpy.broadcast [object >> > PyArrayMultiIterObject]: >> > ctypedef class numpy.ndarray [object PyArrayObject]: >> > ctypedef extern class numpy.ufunc [object PyUFuncObject]: >> > >> > This still doesn't explain how .pxd files specify which external >> > implemented Python modules they correspond to. >> >> "numpy.dtype" is the fully qualified name of the class it's >> declaring--the module is "numpy." > > Hmm, that means that > > cimport numpy > a = numpy.numpy.ndarray > > also compiles. As does a = numpy.foo.x.y.z though perhaps that should be a compile-time error. To get the type, you have to write cimport numpy a = numpy.ndarray. > Wouldn't it make more sense to mirror numpy's module > structure when backing it? You do have nested .pxd modules for > cpython, libc, etc. Yes, in fact that's what we do, but that's not required (e.g. you can have these extern declarations in .pyx files) >> >> >> >> > cdef public struct X: >> >> >> >> > int x >> >> >> >> > readonly int z >> >> >> >> > private int z >> >> >> >> > >> >> >> >> > I would perhaps say that non-Pythonable non-private members in >> >> >> >> > public >> >> >> >> > structs would be a compile error. >> >> >> >> >> >> >> >> +1, keep it safe at the beginning. >> >> >> > >> >> >> > -1, keep the code clean and the interface consistent ;). I think the >> >> >> > struct syntax should be identical to the class syntax, with the >> >> >> > exception that you can't bind methods to structs. That's the only >> >> >> > real difference between structs and classes, isn't it? >> >> >> >> >> >> In C++, the only difference between structs and classes is that struct >> >> >> members are public by default. (Not saying that C++ is always the >> >> >> model to follow, but it gives precedent). And structs can have >> >> >> function members, that's how to do OOP in C. >> >> > >> >> > Oh. Even more reason to have identical struct and class handling in >> >> > Cython ;). >> >> > >> >> > It is unclear to me what `cdef public struct` means. I think it >> >> > should mean "Python bindings can alter this struct's definition", >> >> > which doesn't make sense. >> >> >> >> I think it should mean "this struct is accessible from Python (as X)" >> > >> > Wouldn't that be "cdef readonly struct X"? >> > >> >> > Shouldn't the syntax for public members be >> >> > >> >> > cdef struct X: >> >> > cdef public: >> >> > int x >> >> > readonly int y >> >> > private int z >> >> >> >> -1 on nesting things like this. Rather than make a struct visible from >> >> Python iff any of its members are, >> > >> > A struct is visible from python iff it is declared public or readonly: >> > >> > cdef public struct X: >> > ... >> > >> > or >> > >> > cdef readonly struct X: >> > ... >> > >> > I don't think the visibility of the struct as a whole should have any >> > effect over the visibility of its members, so you should be able to >> > specify member visibility explicitly with per-member granularity (as >> > you currently can for classes). >> > >> > I was assuming that structs would be public by default (like classes), >> > but that is obviously configurable. >> > >> >> I think it makes more sense to put >> >> the declaration on the struct itself. We could support >> >> >> >> cdef public struct X: >> >> int x # public >> >> >> >> cdef readonly struct Y: >> >>