[Python-Dev] PEP487: Simpler customization of class creation

2016-07-02 Thread Martin Teichmann
Hi list,

so this is the next round for PEP 487. During the last round, most of
the comments were in the direction that a two step approach for
integrating into Python, first in pure Python, later in C, was not a
great idea and everything should be in C directly. So I implemented it
in C, put it onto the issue tracker here:
http://bugs.python.org/issue27366, and also modified the PEP
accordingly.

For those who had not been in the discussion, PEP 487 proposes to add
two hooks, __init_subclass__ which is a classmethod called whenever a
class is subclassed, and __set_owner__, a hook in descriptors which
gets called once the class the descriptor is part of is created.

While implementing PEP 487 I realized that there is and oddity in the
type base class: type.__init__ forbids to use keyword arguments, even
for the usual three arguments it has (name, base and dict), while
type.__new__ allows for keyword arguments. As I plan to forward any
keyword arguments to the new __init_subclass__, I stumbled over that.
As I write in the PEP, I think it would be a good idea to forbid using
keyword arguments for type.__new__ as well. But if people think this
would be to big of a change, it would be possible to do it
differently.

Hoping for good comments

Greetings

Martin

The PEP follows:

PEP: 487
Title: Simpler customisation of class creation
Version: $Revision$
Last-Modified: $Date$
Author: Martin Teichmann ,
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 27-Feb-2015
Python-Version: 3.6
Post-History: 27-Feb-2015, 5-Feb-2016, 24-Jun-2016, 2-Jul-2016
Replaces: 422


Abstract


Currently, customising class creation requires the use of a custom metaclass.
This custom metaclass then persists for the entire lifecycle of the class,
creating the potential for spurious metaclass conflicts.

This PEP proposes to instead support a wide range of customisation
scenarios through a new ``__init_subclass__`` hook in the class body,
and a hook to initialize attributes.

The new mechanism should be easier to understand and use than
implementing a custom metaclass, and thus should provide a gentler
introduction to the full power Python's metaclass machinery.


Background
==

Metaclasses are a powerful tool to customize class creation. They have,
however, the problem that there is no automatic way to combine metaclasses.
If one wants to use two metaclasses for a class, a new metaclass combining
those two needs to be created, typically manually.

This need often occurs as a surprise to a user: inheriting from two base
classes coming from two different libraries suddenly raises the necessity
to manually create a combined metaclass, where typically one is not
interested in those details about the libraries at all. This becomes
even worse if one library starts to make use of a metaclass which it
has not done before. While the library itself continues to work perfectly,
suddenly every code combining those classes with classes from another library
fails.

Proposal


While there are many possible ways to use a metaclass, the vast majority
of use cases falls into just three categories: some initialization code
running after class creation, the initalization of descriptors and
keeping the order in which class attributes were defined.

The first two categories can easily be achieved by having simple hooks
into the class creation:

1. An ``__init_subclass__`` hook that initializes
   all subclasses of a given class.
2. upon class creation, a ``__set_owner__`` hook is called on all the
   attribute (descriptors) defined in the class, and

The third category is the topic of another PEP 520.

As an example, the first use case looks as follows::

   >>> class SpamBase:
   ...# this is implicitly a @classmethod
   ...def __init_subclass__(cls, **kwargs):
   ...cls.class_args = kwargs
   ...super().__init_subclass__(cls, **kwargs)

   >>> class Spam(SpamBase, a=1, b="b"):
   ...pass

   >>> Spam.class_args
   {'a': 1, 'b': 'b'}

The base class ``object`` contains an empty ``__init_subclass__``
method which serves as an endpoint for cooperative multiple inheritance.
Note that this method has no keyword arguments, meaning that all
methods which are more specialized have to process all keyword
arguments.

This general proposal is not a new idea (it was first suggested for
inclusion in the language definition `more than 10 years ago`_, and a
similar mechanism has long been supported by `Zope's ExtensionClass`_),
but the situation has changed sufficiently in recent years that
the idea is worth reconsidering for inclusion.

The second part of the proposal adds an ``__set_owner__``
initializer for class attributes, especially if they are descriptors.
Descriptors are defined in the body of a
class, but they do not know anything about that class, they do not
even know the name they are accessed with. They do get to know their
owner once ``__get__`` is called, but still they do not know thei

Re: [Python-Dev] Request for CPython 3.5.3 release

2016-07-02 Thread Ludovic Gasc
Hi everybody,

I fully understand that AsyncIO is a drop in the ocean of CPython, you're
working to prepare the entire 3.5.3 release for December, not yet ready.
However, you might create a 3.5.2.1 release with only this AsyncIO fix ?

PEP 440 doesn't seem to forbid that even if I see only 3 digits examples in
PEP, I only find an example with 4 digits:
https://www.python.org/dev/peps/pep-0440/#version-specifiers

If 3.5.2.1 or 3.5.3 are impossible to release before december, what are the
alternative solutions for AsyncIO users ?
1. Use 3.5.1 and hope that Linux distributions won't use 3.5.2 ?
2. Patch by hand asyncio source code ?
3. Remove asyncio folder in CPython, and install asyncio via github
repository ?
4. Anything else ?

To be honest, I'm migrating an AsyncIO application from 3.4.3 to 3.5.1 with
more than 10 000 lines of code, I'm really interested in to know if it's
better to keep 3.4.3 for now, or if 3.5 branch is enough stable ?

Have a nice week-end.
--
Ludovic Gasc (GMLudo)
http://www.gmludo.eu/

2016-06-30 9:41 GMT+02:00 Larry Hastings :

> On 06/28/2016 02:51 PM, Larry Hastings wrote:
>
>
> On 06/28/2016 02:05 PM, Yury Selivanov wrote:
>
> Larry and the release team: would it be possible to make an
> "emergency" 3.5.3 release?
>
>
> I'd like to hear from the other asyncio reviewers: is this bug bad enough
> to merit such an "emergency" release?
>
>
> Thanks,
>
>
> */arry*
>
>
> There has been a distinct lack of "dear god yes Larry" emails so far.
> This absence suggests that, no, it is not a bad enough bug to merit such a
> release.
>
> If we stay to our usual schedule, I expect 3.5.3 to ship December-ish.
>
>
> */arry*
>
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/gmludo%40gmail.com
>
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Request for CPython 3.5.3 release

2016-07-02 Thread Nick Coghlan
On 2 July 2016 at 16:17, Ludovic Gasc  wrote:
> Hi everybody,
>
> I fully understand that AsyncIO is a drop in the ocean of CPython, you're
> working to prepare the entire 3.5.3 release for December, not yet ready.
> However, you might create a 3.5.2.1 release with only this AsyncIO fix ?

That would be more work than just doing a 3.5.3 release, though - the
problem isn't with the version number bump, it's with asking the
release team to do additional work without clearly explaining the
rationale for the request (more on that below). While some parts of
the release process are automated, there's still a lot of steps to run
through by a number of different people:
https://www.python.org/dev/peps/pep-0101/.

The first key question to answer in this kind of situation is: "Is
there code that will run correctly on 3.5.1 that will now fail on
3.5.2?" (i.e. it's a regression introduced by the asyncio and
coroutine changes in the point release rather than something that was
already broken in 3.5.0 and 3.5.1).

If the answer is "No", then it doesn't inhibit the 3.5.2 rollout in
any way, and folks can wait until 3.5.3 for the fix.

However, if the answer is "Yes, it's a new regression in 3.5.2" (as in
this case), then the next question becomes "Is there an agreed
resolution for the regression?"

The answer to that is currently "No" - Yury's PR against the asyncio
repo is still being discussed.

Once the answer to that question is "Yes", *then* the question of
releasing a high priority fix in a Python 3.5.3 release can be
properly considered by answering the question "Of the folks using
asyncio, what proportion of them are likely to encounter problems in
upgrading to Python 3.5.2, and is there a workaround they can apply or
alternate approach they can use to avoid the problem?".

At the moment, Yury's explanation of the fix in the PR is
(understandably) addressed at getting the problem resolved within the
context of asyncio, and hence just describes the particular APIs
affected, and the details of the incorrect behaviour. While that's an
important step in the process, it doesn't provide a clear assessment
of the *consequences* of the bug aimed at folks that aren't themselves
deeply immersed in using asyncio, so we can't tell if the problem is
"Some idiomatic code frequently recommended in user facing examples
and used in third party asyncio based libraries may hang client
processes" (which would weigh in favour of an early 3.5.3 release
before people start encountering the regression in practice) or "Some
low level API's not recommended for general use may hang if used in a
particular non-idiomatic combination only likely to be encountered by
event loop implementors" (which would suggest it may be OK to stick
with the normal maintenance release cadence).

> If 3.5.2.1 or 3.5.3 are impossible to release before december,

Early maintenance releases are definitely possible, but the
consequences of particular regressions need to be put into terms that
make sense to the release team, which generally means stepping up from
"APIs X, Y, and Z broke in this way" to "Users doing A, B, and C will
be affected in this way".

As an example of a case where an early maintenance release took place:
several years ago, Python 2.6.3 happened to break both "from logging
import *" (due to a missing entry in test___all__ letting an error in
logging.__all__ through) and building extension modules with
setuptools (due to a change in a private API that setuptools was
monkeypatching). Those were considered significant enough for the
2.6.4 release to happen early.

> what are the
> alternative solutions for AsyncIO users ?
> 1. Use 3.5.1 and hope that Linux distributions won't use 3.5.2 ?

Linux distributions have mechanisms to carry patches (indeed,
selective application of patches is one of the main benefits of using
system packages over upstream ones), so any distro that rebases on
3.5.2 can be encouraged to add the fix once it lands regardless of
whether or not Larry approves an additional maintenance release
outside the normal cadence.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com