PyProtocols API forward incompatibile with Python 3

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

PyProtocols API forward incompatibile with Python 3

Burnpanck
There is a Python 3 compatibility issue in the PyProtocols API. It makes
extensive use of so-called class advisors, which are function calls that
one issues from within the class-body to annotate some information about
the class that is beeing built. All these functions in fact install a
callback which is beeing run after the class creation is finished. These
callbacks are installed using the `addClassAdvisor` function from
PyProtocols.

#### The Problem with `addClassAdvisor`
`addClassAdvisor` works by installing a special handler function into
the the class body's `__metaclass__` attribute, which then gets invoked
during class creation. However, in Python 3, the metaclass is declared
differently and `__metaclass__` is ignored completely.

#### The more general problem
Unfortunately, I think there is no general solution possible at all, at
least without changing the declaration syntax. The aim is to run a
function on the newly created class, but declare the function to run
from within the class body, which is run before the class is created.
This was achieved by installing a callback-mechanism into the metaclass
functionality, since the metaclass is what gets run at class creation
time. However, in Python 3, the metaclass is already selected at the
point the function body is run, so there is no way to insert any hooks
at this point without the help of the (already selected, unknown) metaclass.

#### Possible solutions
I see two solutions, none of them is perfect.
 1. Use the decorator syntax, which in Python 3 is extended to class
declarations. Decorators are run after class creation, thus they would
be able to implement the required functionality. Disadvantage: It is a
change in syntax, which means user code needs to be adapted.
Furthermore, class decoration is a syntax error in pre-Python 3, so code
that should run unchanged in both worlds would need to resort to the
very old and ugly manual invocation of the decorator after class creation.
 2. Provide help from within the metaclass. Define a hook attribute in
the class dict that gets run class creation. In Python 3, the metaclass
gets a chance to access the dict even before the class body is run, thus
it could signal the advisor-installer the presence of the hook. However,
if the installer finds the hook missing, the only thing it can do is to
complain with an exception. Disadvantage: It only works with conforming
metaclasses. This is less an issue for adaption, since Adapters
typically are classes specially created for that purpose, and thus will
often anyway derive from some generic Adapter base class (i.e.
traits.api.Adapter). It is worse for the "implements(IInterface)" advisor.

Right now, in my Python 3 branch, all functionality based on class
advisors is unavailable.
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: PyProtocols API forward incompatibile with Python 3

Pietro Berkes
Hi,

my preference would be to introduce new decorators for the 'implements' and 'adapts' functionality. Class decorators were introduced in Python 2.6, so it would be fine for gradually migrating user code. I would keep the 'implements' and 'adapts' pseudo-decorators available for use in Python 2 code, and have them raise an exception in Python 3.

FYI we're working on a replacement for PyProtocols that should be ready for public review soon (I estimate one week). It will be backward compatible with PyProtocols, including the 'implements' and 'adapts' pseudo-decorators, but will allow users to use Python ABCs as well, which means that they could sidestep the need to use 'implements'. It should also be Python 3-ready, so maybe it's not worth spending too much effort porting PyProtocols.

Best,
Pietro




On Fri, Apr 26, 2013 at 11:49 AM, Burnpanck <[hidden email]> wrote:
There is a Python 3 compatibility issue in the PyProtocols API. It makes
extensive use of so-called class advisors, which are function calls that
one issues from within the class-body to annotate some information about
the class that is beeing built. All these functions in fact install a
callback which is beeing run after the class creation is finished. These
callbacks are installed using the `addClassAdvisor` function from
PyProtocols.

#### The Problem with `addClassAdvisor`
`addClassAdvisor` works by installing a special handler function into
the the class body's `__metaclass__` attribute, which then gets invoked
during class creation. However, in Python 3, the metaclass is declared
differently and `__metaclass__` is ignored completely.

#### The more general problem
Unfortunately, I think there is no general solution possible at all, at
least without changing the declaration syntax. The aim is to run a
function on the newly created class, but declare the function to run
from within the class body, which is run before the class is created.
This was achieved by installing a callback-mechanism into the metaclass
functionality, since the metaclass is what gets run at class creation
time. However, in Python 3, the metaclass is already selected at the
point the function body is run, so there is no way to insert any hooks
at this point without the help of the (already selected, unknown) metaclass.

#### Possible solutions
I see two solutions, none of them is perfect.
 1. Use the decorator syntax, which in Python 3 is extended to class
declarations. Decorators are run after class creation, thus they would
be able to implement the required functionality. Disadvantage: It is a
change in syntax, which means user code needs to be adapted.
Furthermore, class decoration is a syntax error in pre-Python 3, so code
that should run unchanged in both worlds would need to resort to the
very old and ugly manual invocation of the decorator after class creation.
 2. Provide help from within the metaclass. Define a hook attribute in
the class dict that gets run class creation. In Python 3, the metaclass
gets a chance to access the dict even before the class body is run, thus
it could signal the advisor-installer the presence of the hook. However,
if the installer finds the hook missing, the only thing it can do is to
complain with an exception. Disadvantage: It only works with conforming
metaclasses. This is less an issue for adaption, since Adapters
typically are classes specially created for that purpose, and thus will
often anyway derive from some generic Adapter base class (i.e.
traits.api.Adapter). It is worse for the "implements(IInterface)" advisor.

Right now, in my Python 3 branch, all functionality based on class
advisors is unavailable.
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev



--
Pietro Berkes
Scientific software developer
Enthought UK


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev