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

2016-08-11 Thread Sylvain Corlay
Hi Martin,

I think that we are on the same page. The differences in the approaches
here makes me think that I should attempt a PEP487-based migration of
traitlets and see if there is a major roadblock.

After all, that would probably be a good test for the PEP if the aim is to
enable usecases like traitlets without a metaclass.

Sylvain
___
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] PEP487: Simpler customization of class creation

2016-07-29 Thread Ethan Furman

On 07/29/2016 08:01 AM, Martin Teichmann wrote:


... Also, while researching other
people's code when I wrote PEP 487, I couldn't find any such code
elsewhere, yet I found a lot of code where people took the wildest
measure to prevent a metaclass in doing its job on the first class it
is used for. One example is enum.EnumMeta, which contains code not to
make enum.Enum an enum ...


Actually, enum.Enum is an enum.  The guards are there because part of creating 
a new
Enum class is searching for the previous Enum classes, and of course the very 
first
time through there is no previous Enum class.

My apologies if I have misunderstood what you were trying to say.

--
~Ethan~
___
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] PEP487: Simpler customization of class creation

2016-07-29 Thread Martin Teichmann
Hi Sylvain,

thanks for the example, it's a great example to illustrate PEP 487 and
its design decisions.

> What it does is setting some class attributes that are required for certain
> types of descriptors to be able to initialize themselves.
>
> class MetaHasTraits(MetaHasDescriptors):
>
> """A metaclass for HasTraits."""
> def setup_class(cls, classdict):
> cls._trait_default_generators = {}
> super(MetaHasTraits, cls).setup_class(classdict)

While in a metaclass solution this does need that the metaclass needs
to execute code on the first class it is used for, in a PEP 487
solution this is not the case. A PEP 487 class HasTraits (no Meta
here) would not have Traits-descriptors itself, the classes inheriting
from it would have traits to be initialized. The PEP 487 HasTraits
takes the role of the metaclass.

A completely different problem shows up here. In your example,
HasTraits needs to initialize things on the class before the
Descriptors are run. This is not possible with PEP 487, where the
descriptors are initialized before __init_subclass__ is even called.

There are two ways to mitigate that problem:

- the first initialized descriptor could do the necessary initialization, or
- the descriptors are initialized from within __init_subclass__

At first sight, the first option seems hackish and the second option
looks much saner. Nonetheless PEP 487 proposes the second solution.
The rationale behind that is that people tend to forget to call
super(), and suddenly descriptors don't work anymore.

I realized later there is another benefit to this: if the first
initialized descriptor is doing the class initialization, often
__init_subclass__ isn't needed at all anymore, which means that those
kind of descriptors can be used on any class, without the need to tell
users that they have to inherit from a certain base class for the
descriptors to work. Only if some finalizing code needs to run after
the last descriptor is initialized one needs to write an
__init_subclass__. This is unavoidable as the last descriptor doesn't
know that it is the last.

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-29 Thread Sylvain Corlay
In the traitlets library I mentioned earlier, we do have a need for this.
The corresponding function is called `setup_class`.

What it does is setting some class attributes that are required for certain
types of descriptors to be able to initialize themselves.

class MetaHasTraits(MetaHasDescriptors):

"""A metaclass for HasTraits."""
def setup_class(cls, classdict):
cls._trait_default_generators = {}
super(MetaHasTraits, cls).setup_class(classdict)


Sylvain

On Fri, Jul 29, 2016 at 5:01 PM, Martin Teichmann 
wrote:

> Hello,
>
> there has been quite some discussion on why PEP 487's
> __init_subclass__  initializes subclasses, and not the class itself. I
> think the most important details have been already thoroughly
> discussed here.
>
> One thing I was missing in the discussion is practical examples. I
> have been using PEP 487-like metaclasses since several years now, and
> I have never come across an application where it would have even been
> nice to initialize the class itself. Also, while researching other
> people's code when I wrote PEP 487, I couldn't find any such code
> elsewhere, yet I found a lot of code where people took the wildest
> measure to prevent a metaclass in doing its job on the first class it
> is used for. One example is enum.EnumMeta, which contains code not to
> make enum.Enum an enum (I do not try to propose that the enum module
> should use PEP 487, it's way to complicated for that).
>
> So once we have a practical example, we could start discussing how to
> mitigate the problem.
>
> Btw, everyone is still invited to review the patch for PEP 487 at
> http://bugs.python.org/issue27366. Many thanks to Nick who already
> reviewed, and also to Guido who left helpful comments!
>
> Greetings
>
> Martin
> ___
> 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/sylvain.corlay%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] PEP487: Simpler customization of class creation

2016-07-29 Thread Martin Teichmann
Hello,

there has been quite some discussion on why PEP 487's
__init_subclass__  initializes subclasses, and not the class itself. I
think the most important details have been already thoroughly
discussed here.

One thing I was missing in the discussion is practical examples. I
have been using PEP 487-like metaclasses since several years now, and
I have never come across an application where it would have even been
nice to initialize the class itself. Also, while researching other
people's code when I wrote PEP 487, I couldn't find any such code
elsewhere, yet I found a lot of code where people took the wildest
measure to prevent a metaclass in doing its job on the first class it
is used for. One example is enum.EnumMeta, which contains code not to
make enum.Enum an enum (I do not try to propose that the enum module
should use PEP 487, it's way to complicated for that).

So once we have a practical example, we could start discussing how to
mitigate the problem.

Btw, everyone is still invited to review the patch for PEP 487 at
http://bugs.python.org/issue27366. Many thanks to Nick who already
reviewed, and also to Guido who left helpful comments!

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-28 Thread Nick Coghlan
On 29 July 2016 at 00:06, Joao S. O. Bueno  wrote:
> Maybe then adding a  `run_init_subclass` class decorator on the stdlib
> to go along with the pep?
> It should be a two liner that would avoid boiler plate done wrong -
> but more important than thatm is that it being documented alog with
> the __init_sublass__ method will make it more obvious it is not run
> where it is defined. (I had missed it in the PEP text and just
> understood that part when re-reading the PEP after being surprised)

The class decorator approach looks like this:

def run_init_subclass(cls, **kwds):
cls.__init_subclass__(**kwds)

However, it's not the right way to do it, as it means super(cls,
cls).__init_subclass__(**kwds) will get called a second time (since
the class machinery will have already done it implicitly before
invoking the class decorators). If the parent class methods are
idempotent then calling them again won't matter, but if you're
supplying extra keyword arguments, you'd need to specify them in both
the decorator call *and* the class header. (I didn't actually realise
this problem until writing the earlier email, so I'll probably tweak
that part of the PEP to be more explicit about this aspect)

So the simplest approach if you want "this class *and* all its
descendants" behaviour is to adhere to the "strict subclasses only"
requirement, and put the __init_subclass__ implementation in a base
class, even if that means creating an additional mixin just to hold
it.

If that recommended approach isn't acceptable for some reason, then
the decorator-centric alternative would be to instead write it this
way:

def decorate_class(cls, **kwds):
...

@decorate_class
class MyClass:
def __init_subclass__(cls, **kwds):
super().__init_subclass__(**kwds)
decorate_class(cls)

So the decorator gets defined outside the class, applied explicitly to
the base class, and then the __init_subclass__ hook applies it
implicitly to all subclasses.

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


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

2016-07-28 Thread Joao S. O. Bueno
On 28 July 2016 at 10:53, Nick Coghlan  wrote:
> On 28 July 2016 at 23:12, Joao S. O. Bueno  wrote:
>>  Although I know it is not straightforward to implement (as the
>> "metaclass" parameter is not passed to the metaclass __new__ or
>> __init__), wouldn't it make sense to make it be passed to
>> __init_subclass__ just like all other keywords?  (the default
>> __init_subclass__ then could swallow it, if it reaches there).
>>
>> I am putting the question now, because it is a matter of "now" or
>> "never" - I can see it can does make sense if it is not passed down.
>
> It would complicate the implementation, and has the potential to be
> confusing (since the explicit metaclass hint and the actual metaclass
> aren't guaranteed to be the same), so I don't think it makes sense to
> pass it down. I'll make sure we note it in the documentation for the
> new protocol method, though.
>
>> Anyway, do you have any remarks on the first issue I raised? About
>> __init_subclass__ being called in the class it is defined in, not just
>> on it's descendant subclasses?
>
> That's already covered in the PEP:
> https://www.python.org/dev/peps/pep-0487/#calling-the-hook-on-the-class-itself
>
> We want to make it easy for mixin classes to use __init_subclass__ to
> define "required attributes" on subclasses, and that's straightforward
> with the current definition:
>
> class MyMixin:
> def __init_subclass__(cls, **kwargs):
> super().__init_subclass__(**kwargs)
> if not hasattr(cls, "mixin_required_attribute"):
> raise TypeError(f"Subclasses of {__class__} must
> define a 'mixin_required_attribute' attribute")
>
> If you actually do want the init_subclass__ method to also run on the
> "base" class, then you'll need to tweak the class hierarchy a bit to
> look like:
>
> class _PrivateInitBase:
> def __init_subclass__(cls, **kwargs):
> super().__init_subclass__(**kwargs)
> ...
>
> def MyOriginalClass(_PrivateInitBase):
> ...
>
> (You don't want to call __init_subclass__ from a class decorator, as
> that would call any parent __init_subclass__ implementations a second
> time)
>
> By contrast, when we had the default the other way around, opting
> *out* of self-application required boilerplate inside of
> __init_subclass__ to special case the situation where "cls is
> __class__":
>
> class MyMixin:
> def __init_subclass__(cls, **kwargs):
> super().__init_subclass__(**kwargs)
> if cls is __class__:
> return # Don't init the base class
> if not getattr(cls, "mixin_required_attribute", None) is None:
> raise TypeError(f"Subclasses of {__class__} must
> define a non-None 'mixin_required_attribute' attribute")
>
> This raises exciting new opportunities for subtle bugs, like bailing
> out *before* calling the parent __init_subclass__ method, and then
> figure out that a later error from an apparently unrelated method is
> because your __init_subclass__ implementation is buggy.
>
> There's still an opportunity for bugs with the current design decision
> (folks expecting __init_subclass__ to be called on the class defining
> it when that isn't the case), but they should be relatively shallow
> ones, and once people learn the rule that __init_subclass__ is only
> called on *strict* subclasses, it's a pretty easy behaviour to
> remember.

Thanks for the extensive reasoning.

Maybe then adding a  `run_init_subclass` class decorator on the stdlib
to go along with the pep?
It should be a two liner that would avoid boiler plate done wrong -
but more important than thatm is that it being documented alog with
the __init_sublass__ method will make it more obvious it is not run
where it is defined. (I had missed it in the PEP text and just
understood that part when re-reading the PEP after being surprised)

  js
 -><-

>
> 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


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

2016-07-28 Thread Nick Coghlan
On 28 July 2016 at 23:12, Joao S. O. Bueno  wrote:
>  Although I know it is not straightforward to implement (as the
> "metaclass" parameter is not passed to the metaclass __new__ or
> __init__), wouldn't it make sense to make it be passed to
> __init_subclass__ just like all other keywords?  (the default
> __init_subclass__ then could swallow it, if it reaches there).
>
> I am putting the question now, because it is a matter of "now" or
> "never" - I can see it can does make sense if it is not passed down.

It would complicate the implementation, and has the potential to be
confusing (since the explicit metaclass hint and the actual metaclass
aren't guaranteed to be the same), so I don't think it makes sense to
pass it down. I'll make sure we note it in the documentation for the
new protocol method, though.

> Anyway, do you have any remarks on the first issue I raised? About
> __init_subclass__ being called in the class it is defined in, not just
> on it's descendant subclasses?

That's already covered in the PEP:
https://www.python.org/dev/peps/pep-0487/#calling-the-hook-on-the-class-itself

We want to make it easy for mixin classes to use __init_subclass__ to
define "required attributes" on subclasses, and that's straightforward
with the current definition:

class MyMixin:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if not hasattr(cls, "mixin_required_attribute"):
raise TypeError(f"Subclasses of {__class__} must
define a 'mixin_required_attribute' attribute")

If you actually do want the init_subclass__ method to also run on the
"base" class, then you'll need to tweak the class hierarchy a bit to
look like:

class _PrivateInitBase:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
...

def MyOriginalClass(_PrivateInitBase):
...

(You don't want to call __init_subclass__ from a class decorator, as
that would call any parent __init_subclass__ implementations a second
time)

By contrast, when we had the default the other way around, opting
*out* of self-application required boilerplate inside of
__init_subclass__ to special case the situation where "cls is
__class__":

class MyMixin:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if cls is __class__:
return # Don't init the base class
if not getattr(cls, "mixin_required_attribute", None) is None:
raise TypeError(f"Subclasses of {__class__} must
define a non-None 'mixin_required_attribute' attribute")

This raises exciting new opportunities for subtle bugs, like bailing
out *before* calling the parent __init_subclass__ method, and then
figure out that a later error from an apparently unrelated method is
because your __init_subclass__ implementation is buggy.

There's still an opportunity for bugs with the current design decision
(folks expecting __init_subclass__ to be called on the class defining
it when that isn't the case), but they should be relatively shallow
ones, and once people learn the rule that __init_subclass__ is only
called on *strict* subclasses, it's a pretty easy behaviour to
remember.

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


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

2016-07-28 Thread Joao S. O. Bueno
On 28 July 2016 at 04:26, Nick Coghlan  wrote:
> On 28 July 2016 at 13:55, Joao S. O. Bueno  wrote:
>> Actually, as documented on the PEP (and I just confirmed at a Python
>> 3.5 prompt),
>> you actually can't use custom keywords for class defintions. This PEP
>> fixes that, but at the same time makes any other class reserved
>> keyword impossible in the future - that is, unless a single line
>> warning against reserved name patterns is added.
>
> We don't warn against people defining new dunder-protocols as methods,
> why would we warn against a similar breach of convention in this case?
> I'm also wondering how you would want such a warning to work if we
> ever claimed a parameter name for a base class in the standard
> library, but didn't claim it as a name supported by type/object.
>
> Note that I'm not denying that it *may* be annoying *if* we define a
> new universal class parameter at some point in the future *and* it
> collides with a custom parameter in a pre-existing API *and* the
> authors of that API miss the related PEP.
>
> However, given that we've come up with exactly one named class
> parameter to date (metaclass), and explicitly decided against adding
> another (namespace, replaced with PEP 520's simpler option of just
> making the standard namespace provide attribute ordering data), the
> odds of actually encountering the posited problematic scenario seem
> pretty remote.

That is alright.
(Even though, I think somewhere around there are remarks against one
putting forth his own dunder methods) .

But that elaves another issue open: the "metaclass" parameter get in
to a very odd position, in which it has nothing distinctive about it,
still is the only parameter that will be swallowed and won't reach
"__init_subclass__".

 Although I know it is not straightforward to implement (as the
"metaclass" parameter is not passed to the metaclass __new__ or
__init__), wouldn't it make sense to make it be passed to
__init_subclass__ just like all other keywords?  (the default
__init_subclass__ then could swallow it, if it reaches there).


I am putting the question now, because it is a matter of "now" or
"never" - I can see it can does make sense if it is not passed down.

Anyway, do you have any remarks on the first issue I raised? About
__init_subclass__ being called in the class it is defined in, not just
on it's descendant subclasses?


>
> Regards,
> 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


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

2016-07-28 Thread Nick Coghlan
On 28 July 2016 at 13:55, Joao S. O. Bueno  wrote:
> Actually, as documented on the PEP (and I just confirmed at a Python
> 3.5 prompt),
> you actually can't use custom keywords for class defintions. This PEP
> fixes that, but at the same time makes any other class reserved
> keyword impossible in the future - that is, unless a single line
> warning against reserved name patterns is added.

We don't warn against people defining new dunder-protocols as methods,
why would we warn against a similar breach of convention in this case?
I'm also wondering how you would want such a warning to work if we
ever claimed a parameter name for a base class in the standard
library, but didn't claim it as a name supported by type/object.

Note that I'm not denying that it *may* be annoying *if* we define a
new universal class parameter at some point in the future *and* it
collides with a custom parameter in a pre-existing API *and* the
authors of that API miss the related PEP.

However, given that we've come up with exactly one named class
parameter to date (metaclass), and explicitly decided against adding
another (namespace, replaced with PEP 520's simpler option of just
making the standard namespace provide attribute ordering data), the
odds of actually encountering the posited problematic scenario seem
pretty remote.

Regards,
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


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

2016-07-27 Thread Joao S. O. Bueno
On 27 July 2016 at 22:30, Nick Coghlan  wrote:
> On 28 July 2016 at 03:56, Joao S. O. Bueno  wrote:
>> Otherwise, I'd suggest at least some PEP rewording to make explicit
>> the fact it is not run on the class it is defined at all.  (I can help
>> with that, but I'd rather see it implemented as above).
>
> This is covered in the PEP:
> https://www.python.org/dev/peps/pep-0487/#calling-the-hook-on-the-class-itself
>
>> 2)
>> I have another higher level concern with the PEP as well:
>> It will pass all class keyword parameters, but for "metaclass" to
>> "__init_subclass__" - thus making it all but impossible to any other
>> keyword to the class creation machinery to ever be defined again. We
>> can't think of any such other keyword now, but what might come in a
>> couple of years?
>
> This isn't a new problem, as it already exists today for custom
> metaclasses. It just means introducing new class construction keywords
> at the language level is something that needs to be handled
> judiciously, and with a view to the fact that it might have knock-on
> effects for other APIs which need to find a new parameter name.
>

Actually, as documented on the PEP (and I just confirmed at a Python
3.5 prompt),
you actually can't use custom keywords for class defintions. This PEP
fixes that, but at the same time makes any other class reserved
keyword impossible in the future - that is, unless a single line
warning against reserved name patterns is added. I think it is low a
cost not to be paid now, blocking too many - yet to be imagined -
future possibilities.


(as for the example in Py 3.5):

In [17]: def M(type):
   ...: def __new__(metacls, name, bases, dict, **kw):
   ...: print(kw)
   ...: return super().__new__(name, bases, dict)
   ...: def __init__(cls, name, bases, dict, **kw):
   ...: print("init...", kw)
   ...: return super().__init__(name, bases, dict)
   ...:

In [18]: class A(metaclass=M, test=23, color="blue"):
   ...: pass
   ...:
---
TypeError Traceback (most recent call last)
 in ()
> 1 class A(metaclass=M, test=23, color="blue"):
 2 pass

TypeError: M() got an unexpected keyword argument 'color'

> Regards,
> 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


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

2016-07-27 Thread Nick Coghlan
On 28 July 2016 at 03:56, Joao S. O. Bueno  wrote:
> Otherwise, I'd suggest at least some PEP rewording to make explicit
> the fact it is not run on the class it is defined at all.  (I can help
> with that, but I'd rather see it implemented as above).

This is covered in the PEP:
https://www.python.org/dev/peps/pep-0487/#calling-the-hook-on-the-class-itself

> 2)
> I have another higher level concern with the PEP as well:
> It will pass all class keyword parameters, but for "metaclass" to
> "__init_subclass__" - thus making it all but impossible to any other
> keyword to the class creation machinery to ever be defined again. We
> can't think of any such other keyword now, but what might come in a
> couple of years?

This isn't a new problem, as it already exists today for custom
metaclasses. It just means introducing new class construction keywords
at the language level is something that needs to be handled
judiciously, and with a view to the fact that it might have knock-on
effects for other APIs which need to find a new parameter name.

Regards,
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


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

2016-07-27 Thread Joao S. O. Bueno
Hi -  sorry for steppign in late - I've just reread the PEP and tried
out the reference implementation, and I have two sugestions/issues
with it as is:

1)
Why does `__init_subclass__` is not run in the class it is defined itself??
That makes no sense to me as in very unpythonic.

I applied the patch at issue, 27366 went to the terminal, and created
a "hello world"
__init_subclass__ with a simple print statement, and was greatly
surprised that it did not printout. Only upon reviewing the PEP text I
inferred that it was supposed to work (as it did) in further
subclasses of my initial class.


After all, issubclass(A, A) is usually True.

I pledge for this behavior to be changed on the PEP. If one does not
want it to run on the baseclass, a simple default argument and an `if
param is None: return` on the method body can do the job, with less
exceptions and surprises.

Otherwise, I'd suggest at least some PEP rewording to make explicit
the fact it is not run on the class it is defined at all.  (I can help
with that, but I'd rather see it implemented as above).

I can see the fact that it woudl have little effect, as any eventual
parameter on the Base class could be hardcoded into the class body
itself - but just imagine a  class hierarchy with cooperative
"__init_subclass__"  methods - it would be rather surprising that each
class has to count on its parents __init_subclass__ being run, without
the one defined in its own body being called - that is rather
surprising.

---
2)
I have another higher level concern with the PEP as well:
It will pass all class keyword parameters, but for "metaclass" to
"__init_subclass__" - thus making it all but impossible to any other
keyword to the class creation machinery to ever be defined again. We
can't think of any such other keyword now, but what might come in a
couple of years?


What about just denoting in the PEP that "double under" keywords
should be reserved and not relied to not be used by "type" itself in
the future? (or any other way of marking reserved class kewyords)  -
actually it would even make sense to make "__metaclass__" an alias for
"metaclass" in the class creation machinery.

Anyway the PEP itself should mention that currently the keyword-arg
"metaclass" is swallowed by the class creation machinery and will
never reach `__init_subclass__` - this behavior is less surprising for
me, but it should be documented)

Or, an  even less exceptional behavior  for the future: make it so
that "metaclass"  specifies a custom metaclass (due to compatibility
issues) AND is passed to __init_subclass__, and  "__metaclass__"
specifies a metaclass and is not passed (along with  other
double-unders as they are defined)).

(as an extra bonus, people migrating from Python 2 to Python 3.6 will
not even be surprised by the keyword argument being __metaclass__)

Best regards,

js
  -><-

On 25 July 2016 at 00:49, Nick Coghlan  wrote:
> On 25 July 2016 at 03:00, Guido van Rossum  wrote:
>> Yes.
>
> OK, we can cover that in the documentation - if folks want to emulate
> what happens during class construction after the fact, they'll need to
> do:
>
> cls.name = attr
> attr.__set_name__(cls, "name")
>
> Semantically, I agree that approach makes sense - by default,
> descriptors created outside a class body won't have a defined owning
> class or attribute name, and if you want to give them one, you'll have
> to do it explicitly.
>
> 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/jsbueno%40python.org.br
___
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] PEP487: Simpler customization of class creation

2016-07-24 Thread Nick Coghlan
On 25 July 2016 at 03:00, Guido van Rossum  wrote:
> Yes.

OK, we can cover that in the documentation - if folks want to emulate
what happens during class construction after the fact, they'll need to
do:

cls.name = attr
attr.__set_name__(cls, "name")

Semantically, I agree that approach makes sense - by default,
descriptors created outside a class body won't have a defined owning
class or attribute name, and if you want to give them one, you'll have
to do it explicitly.

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


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

2016-07-24 Thread Guido van Rossum
Yes.

--Guido (mobile)

On Jul 24, 2016 9:34 AM, "Ethan Furman"  wrote:

> On 07/24/2016 08:20 AM, Guido van Rossum wrote:
>
> I am very much against this. The two are not at all like each other. Also,
>> what's the use case?
>>
>
> To be clear:  you are against the automatic calling of __set_name__ and/or
> __set_owner__ when using
> setattr outside of class creation?  Said another way: class creation
> mechanics should only happen
> during class creation?
>
> --
> ~Ethan~
> ___
> 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/guido%40python.org
>
___
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] PEP487: Simpler customization of class creation

2016-07-24 Thread Ethan Furman

On 07/24/2016 08:20 AM, Guido van Rossum wrote:


I am very much against this. The two are not at all like each other. Also, 
what's the use case?


To be clear:  you are against the automatic calling of __set_name__ and/or 
__set_owner__ when using
setattr outside of class creation?  Said another way: class creation mechanics 
should only happen
during class creation?

--
~Ethan~
___
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] PEP487: Simpler customization of class creation

2016-07-24 Thread Guido van Rossum
I am very much against this. The two are not at all like each other. Also,
what's the use case?

On Sunday, July 24, 2016, Martin Teichmann  wrote:

> Hi list, Hi Nick,
>
> Sorry for my delayed response, it is summer here...
>
> > However, phrasing it that way suggest that it's possible we *did* miss
> > something in the PEP: we haven't specified whether or not __set_name__
> > should be called when someone does someone does "cls.attr = descr".
> > Given the name, I think we *should* call it in that case, and then the
> > semantics during class creation are approximately what would happen if
> > we actually built up the class attributes as:
> >
> > for attr, value in cls_ns.items():
> > setattr(cls, attr, value)
>
> That's a very good point and actually easy to solve: we would just
> need to override type.__setattr__ to do so. Actually, it is already
> overridden, so we just need to add code to type.__setattr__ to also
> call __set_name__.
>
> One could be of the other standpoint that in your above example it's
> the duty of the caller of setattr to also call __set_name__. It would
> be pretty easy to add a line in the loop that also calls
> __set_owner__.
>
> Greetings
>
> Martin
> ___
> 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/guido%40python.org
>


-- 
--Guido (mobile)
___
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] PEP487: Simpler customization of class creation

2016-07-24 Thread Martin Teichmann
Hi list, Hi Nick,

Sorry for my delayed response, it is summer here...

> However, phrasing it that way suggest that it's possible we *did* miss
> something in the PEP: we haven't specified whether or not __set_name__
> should be called when someone does someone does "cls.attr = descr".
> Given the name, I think we *should* call it in that case, and then the
> semantics during class creation are approximately what would happen if
> we actually built up the class attributes as:
>
> for attr, value in cls_ns.items():
> setattr(cls, attr, value)

That's a very good point and actually easy to solve: we would just
need to override type.__setattr__ to do so. Actually, it is already
overridden, so we just need to add code to type.__setattr__ to also
call __set_name__.

One could be of the other standpoint that in your above example it's
the duty of the caller of setattr to also call __set_name__. It would
be pretty easy to add a line in the loop that also calls
__set_owner__.

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-21 Thread Sylvain Corlay
In any case I find this PEP great. If we can implement a library like
traitlets only using these new hooks without a custom metaclass, it will be
a big improvement.

My only concern was that calling the hook __set_name__ was misleading while
it could not set the name at all and do pretty much anything else.

Regards,
Sylvain



On Thu, Jul 21, 2016 at 4:53 AM, Nick Coghlan  wrote:

> On 21 July 2016 at 03:40, Sylvain Corlay  wrote:
> > My point is that in any real-world implementation of traits, __set_name__
> > will do a lot more than setting the name, which makes the name
> misleading.
>
> I suspect the point of disagreement on that front may be in how we
> view the names of the existing __get__, __set__ and __delete__ methods
> in the descriptor protocols - all 3 of those are in the form of event
> notifications to the descriptor to say "someone is getting the
> attribute", "someone is setting the attribute" and "someone is
> deleting the attribute". What the descriptor does in response to those
> notifications is up to the descriptor, with it being *conventional*
> that they be at least plausibly associated with the "obj.attr",
> "obj.attr = value" and "del obj.attr" operations (with folks voting by
> usage as to whether or not they consider a particular API's side
> effects in response to those notifications reasonable).
>
> The new notification is merely "someone is setting the name of the
> attribute", with that taking place when the contents of a class
> namespace are converted into class attributes.
>
> However, phrasing it that way suggest that it's possible we *did* miss
> something in the PEP: we haven't specified whether or not __set_name__
> should be called when someone does someone does "cls.attr = descr".
> Given the name, I think we *should* call it in that case, and then the
> semantics during class creation are approximately what would happen if
> we actually built up the class attributes as:
>
> for attr, value in cls_ns.items():
> setattr(cls, attr, value)
>
> Regards,
> 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


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

2016-07-20 Thread Guido van Rossum
Whoa. That's not how I read it.

--Guido (mobile)
___
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] PEP487: Simpler customization of class creation

2016-07-20 Thread Nick Coghlan
On 21 July 2016 at 03:40, Sylvain Corlay  wrote:
> My point is that in any real-world implementation of traits, __set_name__
> will do a lot more than setting the name, which makes the name misleading.

I suspect the point of disagreement on that front may be in how we
view the names of the existing __get__, __set__ and __delete__ methods
in the descriptor protocols - all 3 of those are in the form of event
notifications to the descriptor to say "someone is getting the
attribute", "someone is setting the attribute" and "someone is
deleting the attribute". What the descriptor does in response to those
notifications is up to the descriptor, with it being *conventional*
that they be at least plausibly associated with the "obj.attr",
"obj.attr = value" and "del obj.attr" operations (with folks voting by
usage as to whether or not they consider a particular API's side
effects in response to those notifications reasonable).

The new notification is merely "someone is setting the name of the
attribute", with that taking place when the contents of a class
namespace are converted into class attributes.

However, phrasing it that way suggest that it's possible we *did* miss
something in the PEP: we haven't specified whether or not __set_name__
should be called when someone does someone does "cls.attr = descr".
Given the name, I think we *should* call it in that case, and then the
semantics during class creation are approximately what would happen if
we actually built up the class attributes as:

for attr, value in cls_ns.items():
setattr(cls, attr, value)

Regards,
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


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

2016-07-20 Thread Sylvain Corlay
Hi Nick,

Thank you for your reply. I understand your argument about using protocol
method names that are
very specific to a particular intended use case.

Interestingly, the one example that is provided in the PEP is that of a
"trait" which is pretty much the same as traitlets. (traitlets started as a
pure python implementation of Enthought's traits library).

My point is that in any real-world implementation of traits, __set_name__
will do a lot more than setting the name, which makes the name misleading.

Cheers,

Sylvain

On Wed, Jul 20, 2016 at 6:22 PM, Nick Coghlan  wrote:

> Hi Sylvain,
>
> Thanks for getting in touch! The traitlets library sounds interesting,
> and provides good additional evidence that this is a capability that
> folks are interested in having available.
>
> On 20 July 2016 at 15:26, Sylvain Corlay  wrote:
> > My understanding is that the proposed __set_name__ in PEP487 exactly
> > corresponds to our class_init, although interestingly we often do much
> more
> > in class_init than setting the name of the descriptor, such as setting a
> > this_class attribute or calling class_init on contained descriptors.
> > Therefore I do not think that the names __set_name__ or __set_owner__ are
> > appropriate for this use case.
> >
> > In a way, the long-form explicit names for our class_init and
> instance_init
> > methods would be something like __init_fom_owner_class__, and
> > __touch_instance__.
>
> It's certainly a reasonable question/concern, but we've learned from
> experience that we're better off using protocol method names that are
> very specific to a particular intended use case, even if they can be
> adapted for other purposes. The trick is that we want educators
> teaching Python to be able to very easily answer the question of "What
> is this special method for?" (even if they later go on to say "And
> it's also used for these other things...")
>
> One previous example of that is the __index__ protocol, where the
> actual semantics are "instances of this type can be losslessly
> converted to integers", but the protocol is named for the particular
> use case "instances of this type can be used as sequence indices".
>
> For PEP 487, the two operations guiding the naming of the methods are
> "notify a base class when a new subclass is defined" and "notify a
> descriptor of its attribute name when assigned to a class". The
> precise verbs then mirror those already used in other parts of the
> related protocols (with __init__ leading to __init_subclass__, and
> __set__ leading to __set_name__).
>
> The main capability that __set_name__ provides that was previously
> difficult is letting a descriptor know its own name in the class
> namespace. The fact a descriptor implementor can do anything else they
> want as a side-effect of that new method being called isn't
> substantially different from the ability to add side-effects to the
> existing __get__, __set__ and __delete__ protocol methods.
>
> 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


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

2016-07-20 Thread Nick Coghlan
Hi Sylvain,

Thanks for getting in touch! The traitlets library sounds interesting,
and provides good additional evidence that this is a capability that
folks are interested in having available.

On 20 July 2016 at 15:26, Sylvain Corlay  wrote:
> My understanding is that the proposed __set_name__ in PEP487 exactly
> corresponds to our class_init, although interestingly we often do much more
> in class_init than setting the name of the descriptor, such as setting a
> this_class attribute or calling class_init on contained descriptors.
> Therefore I do not think that the names __set_name__ or __set_owner__ are
> appropriate for this use case.
>
> In a way, the long-form explicit names for our class_init and instance_init
> methods would be something like __init_fom_owner_class__, and
> __touch_instance__.

It's certainly a reasonable question/concern, but we've learned from
experience that we're better off using protocol method names that are
very specific to a particular intended use case, even if they can be
adapted for other purposes. The trick is that we want educators
teaching Python to be able to very easily answer the question of "What
is this special method for?" (even if they later go on to say "And
it's also used for these other things...")

One previous example of that is the __index__ protocol, where the
actual semantics are "instances of this type can be losslessly
converted to integers", but the protocol is named for the particular
use case "instances of this type can be used as sequence indices".

For PEP 487, the two operations guiding the naming of the methods are
"notify a base class when a new subclass is defined" and "notify a
descriptor of its attribute name when assigned to a class". The
precise verbs then mirror those already used in other parts of the
related protocols (with __init__ leading to __init_subclass__, and
__set__ leading to __set_name__).

The main capability that __set_name__ provides that was previously
difficult is letting a descriptor know its own name in the class
namespace. The fact a descriptor implementor can do anything else they
want as a side-effect of that new method being called isn't
substantially different from the ability to add side-effects to the
existing __get__, __set__ and __delete__ protocol methods.

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


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

2016-07-19 Thread Sylvain Corlay
Hello,

This is my first post on python-dev and I hope that I am not breaking any
rule.

I wanted to react on the discussion regarding PEP487.

This year, we have been working on a refactoring of the `traitlets`
library, an implementation of the descriptor pattern that is used in
Project Jupyter / IPython. The motivations for the refactoring was similar
to those of this PEP: having a more generic metaclass allowing more
flexibility in terms of types of descriptors, in order to avoid conflicts
between meta classes.

We ended up with:
- A metaclass called MetaHasDescriptor
- A base class of meta MetaHasDescriptor named HasDescriptors

Usage:

class MyClass(HasDescriptors):
attr = DesType()

DesType inherits from a base Descriptor type. The key is that their
initialization is done in three stages

 - the main
DesType.__init__

 - the part of the initialization of DesType that depends on the definition
of MyClass
DesType.class_init(self, cls, name)
   which is called from MetaHasDescriptors.__new__

 - a method of DesType that depends on the definition of instances of
MyClass
DesType.instance_init(self, obj)
which is called from HasDescriptors.__new__.

instance_init, may make modifications on the HasDescriptors instance.

My understanding is that the proposed __set_name__ in PEP487 exactly
corresponds to our class_init, although interestingly we often do much more
in class_init than setting the name of the descriptor, such as setting a
this_class attribute or calling class_init on contained descriptors.
Therefore I do not think that the names __set_name__ or __set_owner__ are
appropriate for this use case.

In a way, the long-form explicit names for our class_init and instance_init
methods would be something like __init_fom_owner_class__, and
__touch_instance__.

Thanks,

Sylvain

PS: thanks to Neil Girdhar for the heads up on the traitlets repo.
___
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] PEP487: Simpler customization of class creation

2016-07-19 Thread Neil Girdhar
Thanks for clarifying.

On Tue, Jul 19, 2016 at 10:34 AM Nick Coghlan  wrote:

> On 19 July 2016 at 16:41, Neil Girdhar  wrote:
> > Yes, I see what you're saying.   However, I don't understand why
> > __init_subclass__ (defined on some class C) cannot be used to implement
> the
> > checks required by @abstractmethod instead of doing it in ABCMeta.  This
> > would prevent metaclass conflicts since you could use @abstractmethod
> with
> > any metaclass or no metaclass at all provided you inherit from C.
>
> ABCMeta also changes how __isinstance__ and __issubclass__ work and
> adds additional methods (like register()), so enabling the use of
> @abstractmethod without otherwise making the type an ABC would be very
> confusing behaviour that we wouldn't enable by default.
>
> But yes, this change does make it possible to write a mixin class that
> implements the "@abstractmethod instances must all be overridden to
> allow instances to to be created" logic from ABCMeta without otherwise
> turning the class into an ABC instance.
>
> 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


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

2016-07-19 Thread Nick Coghlan
On 19 July 2016 at 16:41, Neil Girdhar  wrote:
> Yes, I see what you're saying.   However, I don't understand why
> __init_subclass__ (defined on some class C) cannot be used to implement the
> checks required by @abstractmethod instead of doing it in ABCMeta.  This
> would prevent metaclass conflicts since you could use @abstractmethod with
> any metaclass or no metaclass at all provided you inherit from C.

ABCMeta also changes how __isinstance__ and __issubclass__ work and
adds additional methods (like register()), so enabling the use of
@abstractmethod without otherwise making the type an ABC would be very
confusing behaviour that we wouldn't enable by default.

But yes, this change does make it possible to write a mixin class that
implements the "@abstractmethod instances must all be overridden to
allow instances to to be created" logic from ABCMeta without otherwise
turning the class into an ABC instance.

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


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

2016-07-19 Thread Neil Girdhar
Yes, I see what you're saying.   However, I don't understand why
__init_subclass__ (defined on some class C) cannot be used to implement the
checks required by @abstractmethod instead of doing it in ABCMeta.  This
would prevent metaclass conflicts since you could use @abstractmethod with
any metaclass or no metaclass at all provided you inherit from C.

On Tue, Jul 19, 2016 at 12:21 AM Nick Coghlan  wrote:

> On 19 July 2016 at 09:26, Neil Girdhar  wrote:
> > Yes, I'm very excited about this!
> >
> > Will this mean no more metaclass conflicts if using @abstractmethod?
>
> ABCMeta and EnumMeta both create persistent behavioural differences
> rather than only influencing subtype definition, so they'll need to
> remain as custom metaclasses.
>
> What this PEP (especially in combination with PEP 520) is aimed at
> enabling is subclassing APIs designed more around the notion of
> "implicit class decoration" where a common base class or mixin can be
> adjusted to perform certain actions whenever a new subclass is
> defined, without changing the runtime behaviour of those subclasses.
> (For example: a mixin or base class may require that certain
> parameters be set as class attributes - this PEP will allow the base
> class to check for those and throw an error at definition time, rather
> than getting a potentially cryptic error when it attempts to use the
> missing attribute)
>
> 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


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

2016-07-18 Thread Nick Coghlan
On 19 July 2016 at 09:26, Neil Girdhar  wrote:
> Yes, I'm very excited about this!
>
> Will this mean no more metaclass conflicts if using @abstractmethod?

ABCMeta and EnumMeta both create persistent behavioural differences
rather than only influencing subtype definition, so they'll need to
remain as custom metaclasses.

What this PEP (especially in combination with PEP 520) is aimed at
enabling is subclassing APIs designed more around the notion of
"implicit class decoration" where a common base class or mixin can be
adjusted to perform certain actions whenever a new subclass is
defined, without changing the runtime behaviour of those subclasses.
(For example: a mixin or base class may require that certain
parameters be set as class attributes - this PEP will allow the base
class to check for those and throw an error at definition time, rather
than getting a potentially cryptic error when it attempts to use the
missing attribute)

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


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

2016-07-18 Thread Neil Girdhar
Yes, I'm very excited about this!

Will this mean no more metaclass conflicts if using @abstractmethod?

On Sun, Jul 17, 2016 at 12:59 PM Guido van Rossum  wrote:

> This PEP is now accepted for inclusion in Python 3.6. Martin,
> congratulations! Someone (not me) needs to review and commit your
> changes, before September 12, when the 3.6 feature freeze goes into
> effect (see https://www.python.org/dev/peps/pep-0494/#schedule).
>
> On Sun, Jul 17, 2016 at 4:32 AM, Martin Teichmann
>  wrote:
> > Hi Guido, Hi Nick, Hi list,
> >
> > so I just updated PEP 487, you can find it here:
> > https://github.com/python/peps/pull/57 if it hasn't already been
> > merged. There are no substantial updates there, I only updated the
> > wording as suggested, and added some words about backwards
> > compatibility as hinted by Nick.
> >
> > Greetings
> >
> > Martin
> >
> > 2016-07-14 17:47 GMT+02:00 Guido van Rossum :
> >> I just reviewed the changes you made, I like __set_name__(). I'll just
> >> wait for your next update, incorporating Nick's suggestions. Regarding
> >> who merges PRs to the PEPs repo, since you are the author the people
> >> who merge don't pass any judgment on the changes (unless it doesn't
> >> build cleanly or maybe if they see a typo). If you intend a PR as a
> >> base for discussion you can add a comment saying e.g. "Don't merge
> >> yet". If you call out @gvanrossum, GitHub will make sure I get a
> >> message about it.
> >>
> >> I think the substantial discussion about the PEP should remain here in
> >> python-dev; comments about typos, grammar and other minor editorial
> >> issues can go on GitHub. Hope this part of the process makes sense!
> >>
> >> On Thu, Jul 14, 2016 at 6:50 AM, Martin Teichmann
> >>  wrote:
> >>> Hi Guido, Hi list,
> >>>
> >>> Thanks for the nice review! I applied followed up your ideas and put
> >>> it into a github pull request: https://github.com/python/peps/pull/53
> >>>
> >>> Soon we'll be working there, until then, some responses to your
> comments:
> >>>
>  I wonder if this should be renamed to __set_name__ or something else
>  that clarifies we're passing it the name of the attribute? The method
>  name __set_owner__ made me assume this is about the owning object
>  (which is often a useful term in other discussions about objects),
>  whereas it is really about telling the descriptor the name of the
>  attribute for which it applies.
> >>>
> >>> The name for this has been discussed a bit already, __set_owner__ was
> >>> Nick's idea, and indeed, the owner is also set. Technically,
> >>> __set_owner_and_name__ would be correct, but actually I like your idea
> >>> of __set_name__.
> >>>
>  That (inheriting type from type, and object from object) is very
>  confusing. Why not just define new classes e.g. NewType and NewObject
>  here, since it's just pseudo code anyway?
> >>>
> >>> Actually, it's real code. If you drop those lines at the beginning of
> >>> the tests for the implementation (as I have done here:
> >>>
> https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py
> ),
> >>> the test runs on older Pythons.
> >>>
> >>> But I see that my idea to formulate things here in Python was a bad
> >>> idea, I will put the explanation first and turn the code into
> >>> pseudo-code.
> >>>
> > def __init__(self, name, bases, ns, **kwargs):
> > super().__init__(name, bases, ns)
> 
>  What does this definition of __init__ add?
> >>>
> >>> It removes the keyword arguments. I describe that in prose a bit down.
> >>>
> > class object:
> > @classmethod
> > def __init_subclass__(cls):
> > pass
> >
> > class object(object, metaclass=type):
> > pass
> 
>  Eek! Too many things named object.
> >>>
> >>> Well, I had to do that to make the tests run... I'll take that out.
> >>>
> > In the new code, it is not ``__init__`` that complains about keyword
> arguments,
> > but ``__init_subclass__``, whose default implementation takes no
> arguments. In
> > a classical inheritance scheme using the method resolution order,
> each
> > ``__init_subclass__`` may take out it's keyword arguments until none
> are left,
> > which is checked by the default implementation of
> ``__init_subclass__``.
> 
>  I called this out previously, and I am still a bit uncomfortable with
>  the backwards incompatibility here. But I believe what you describe
>  here is the compromise proposed by Nick, and if that's the case I have
>  peace with it.
> >>>
> >>> No, this is not Nick's compromise, this is my original. Nick just sent
> >>> another mail to this list where he goes a bit more into the details,
> >>> I'll respond to that about this topic.
> >>>
> >>> Greetings
> >>>
> >>> Martin
> >>>
> >>> P.S.: I just realized that my 

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

2016-07-18 Thread Eric Snow
Great job, Martin!  Thanks for seeing this through. :)

-eric

On Sun, Jul 17, 2016 at 10:57 AM, Guido van Rossum  wrote:
> This PEP is now accepted for inclusion in Python 3.6. Martin,
> congratulations! Someone (not me) needs to review and commit your
> changes, before September 12, when the 3.6 feature freeze goes into
> effect (see https://www.python.org/dev/peps/pep-0494/#schedule).
>
> On Sun, Jul 17, 2016 at 4:32 AM, Martin Teichmann
>  wrote:
>> Hi Guido, Hi Nick, Hi list,
>>
>> so I just updated PEP 487, you can find it here:
>> https://github.com/python/peps/pull/57 if it hasn't already been
>> merged. There are no substantial updates there, I only updated the
>> wording as suggested, and added some words about backwards
>> compatibility as hinted by Nick.
>>
>> Greetings
>>
>> Martin
>>
>> 2016-07-14 17:47 GMT+02:00 Guido van Rossum :
>>> I just reviewed the changes you made, I like __set_name__(). I'll just
>>> wait for your next update, incorporating Nick's suggestions. Regarding
>>> who merges PRs to the PEPs repo, since you are the author the people
>>> who merge don't pass any judgment on the changes (unless it doesn't
>>> build cleanly or maybe if they see a typo). If you intend a PR as a
>>> base for discussion you can add a comment saying e.g. "Don't merge
>>> yet". If you call out @gvanrossum, GitHub will make sure I get a
>>> message about it.
>>>
>>> I think the substantial discussion about the PEP should remain here in
>>> python-dev; comments about typos, grammar and other minor editorial
>>> issues can go on GitHub. Hope this part of the process makes sense!
>>>
>>> On Thu, Jul 14, 2016 at 6:50 AM, Martin Teichmann
>>>  wrote:
 Hi Guido, Hi list,

 Thanks for the nice review! I applied followed up your ideas and put
 it into a github pull request: https://github.com/python/peps/pull/53

 Soon we'll be working there, until then, some responses to your comments:

> I wonder if this should be renamed to __set_name__ or something else
> that clarifies we're passing it the name of the attribute? The method
> name __set_owner__ made me assume this is about the owning object
> (which is often a useful term in other discussions about objects),
> whereas it is really about telling the descriptor the name of the
> attribute for which it applies.

 The name for this has been discussed a bit already, __set_owner__ was
 Nick's idea, and indeed, the owner is also set. Technically,
 __set_owner_and_name__ would be correct, but actually I like your idea
 of __set_name__.

> That (inheriting type from type, and object from object) is very
> confusing. Why not just define new classes e.g. NewType and NewObject
> here, since it's just pseudo code anyway?

 Actually, it's real code. If you drop those lines at the beginning of
 the tests for the implementation (as I have done here:
 https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py),
 the test runs on older Pythons.

 But I see that my idea to formulate things here in Python was a bad
 idea, I will put the explanation first and turn the code into
 pseudo-code.

>> def __init__(self, name, bases, ns, **kwargs):
>> super().__init__(name, bases, ns)
>
> What does this definition of __init__ add?

 It removes the keyword arguments. I describe that in prose a bit down.

>> class object:
>> @classmethod
>> def __init_subclass__(cls):
>> pass
>>
>> class object(object, metaclass=type):
>> pass
>
> Eek! Too many things named object.

 Well, I had to do that to make the tests run... I'll take that out.

>> In the new code, it is not ``__init__`` that complains about keyword 
>> arguments,
>> but ``__init_subclass__``, whose default implementation takes no 
>> arguments. In
>> a classical inheritance scheme using the method resolution order, each
>> ``__init_subclass__`` may take out it's keyword arguments until none are 
>> left,
>> which is checked by the default implementation of ``__init_subclass__``.
>
> I called this out previously, and I am still a bit uncomfortable with
> the backwards incompatibility here. But I believe what you describe
> here is the compromise proposed by Nick, and if that's the case I have
> peace with it.

 No, this is not Nick's compromise, this is my original. Nick just sent
 another mail to this list where he goes a bit more into the details,
 I'll respond to that about this topic.

 Greetings

 Martin

 P.S.: I just realized that my changes to the PEP were accepted by
 someone else than Guido. I am a bit surprised about that, but I guess
 this is how it 

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

2016-07-17 Thread Martin Teichmann
> This PEP is now accepted for inclusion in Python 3.6. Martin,
> congratulations!

Thank you very much! What a great news!

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-17 Thread Ethan Furman

On 07/17/2016 09:57 AM, Guido van Rossum wrote:


This PEP is now accepted for inclusion in Python 3.6. Martin,
congratulations!


Congratulations, Martin!

I'm looking forward to this feature.  :)

--
~Ethan~
___
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] PEP487: Simpler customization of class creation

2016-07-17 Thread Guido van Rossum
This PEP is now accepted for inclusion in Python 3.6. Martin,
congratulations! Someone (not me) needs to review and commit your
changes, before September 12, when the 3.6 feature freeze goes into
effect (see https://www.python.org/dev/peps/pep-0494/#schedule).

On Sun, Jul 17, 2016 at 4:32 AM, Martin Teichmann
 wrote:
> Hi Guido, Hi Nick, Hi list,
>
> so I just updated PEP 487, you can find it here:
> https://github.com/python/peps/pull/57 if it hasn't already been
> merged. There are no substantial updates there, I only updated the
> wording as suggested, and added some words about backwards
> compatibility as hinted by Nick.
>
> Greetings
>
> Martin
>
> 2016-07-14 17:47 GMT+02:00 Guido van Rossum :
>> I just reviewed the changes you made, I like __set_name__(). I'll just
>> wait for your next update, incorporating Nick's suggestions. Regarding
>> who merges PRs to the PEPs repo, since you are the author the people
>> who merge don't pass any judgment on the changes (unless it doesn't
>> build cleanly or maybe if they see a typo). If you intend a PR as a
>> base for discussion you can add a comment saying e.g. "Don't merge
>> yet". If you call out @gvanrossum, GitHub will make sure I get a
>> message about it.
>>
>> I think the substantial discussion about the PEP should remain here in
>> python-dev; comments about typos, grammar and other minor editorial
>> issues can go on GitHub. Hope this part of the process makes sense!
>>
>> On Thu, Jul 14, 2016 at 6:50 AM, Martin Teichmann
>>  wrote:
>>> Hi Guido, Hi list,
>>>
>>> Thanks for the nice review! I applied followed up your ideas and put
>>> it into a github pull request: https://github.com/python/peps/pull/53
>>>
>>> Soon we'll be working there, until then, some responses to your comments:
>>>
 I wonder if this should be renamed to __set_name__ or something else
 that clarifies we're passing it the name of the attribute? The method
 name __set_owner__ made me assume this is about the owning object
 (which is often a useful term in other discussions about objects),
 whereas it is really about telling the descriptor the name of the
 attribute for which it applies.
>>>
>>> The name for this has been discussed a bit already, __set_owner__ was
>>> Nick's idea, and indeed, the owner is also set. Technically,
>>> __set_owner_and_name__ would be correct, but actually I like your idea
>>> of __set_name__.
>>>
 That (inheriting type from type, and object from object) is very
 confusing. Why not just define new classes e.g. NewType and NewObject
 here, since it's just pseudo code anyway?
>>>
>>> Actually, it's real code. If you drop those lines at the beginning of
>>> the tests for the implementation (as I have done here:
>>> https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py),
>>> the test runs on older Pythons.
>>>
>>> But I see that my idea to formulate things here in Python was a bad
>>> idea, I will put the explanation first and turn the code into
>>> pseudo-code.
>>>
> def __init__(self, name, bases, ns, **kwargs):
> super().__init__(name, bases, ns)

 What does this definition of __init__ add?
>>>
>>> It removes the keyword arguments. I describe that in prose a bit down.
>>>
> class object:
> @classmethod
> def __init_subclass__(cls):
> pass
>
> class object(object, metaclass=type):
> pass

 Eek! Too many things named object.
>>>
>>> Well, I had to do that to make the tests run... I'll take that out.
>>>
> In the new code, it is not ``__init__`` that complains about keyword 
> arguments,
> but ``__init_subclass__``, whose default implementation takes no 
> arguments. In
> a classical inheritance scheme using the method resolution order, each
> ``__init_subclass__`` may take out it's keyword arguments until none are 
> left,
> which is checked by the default implementation of ``__init_subclass__``.

 I called this out previously, and I am still a bit uncomfortable with
 the backwards incompatibility here. But I believe what you describe
 here is the compromise proposed by Nick, and if that's the case I have
 peace with it.
>>>
>>> No, this is not Nick's compromise, this is my original. Nick just sent
>>> another mail to this list where he goes a bit more into the details,
>>> I'll respond to that about this topic.
>>>
>>> Greetings
>>>
>>> Martin
>>>
>>> P.S.: I just realized that my changes to the PEP were accepted by
>>> someone else than Guido. I am a bit surprised about that, but I guess
>>> this is how it works?
>>> ___
>>> 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/guido%40python.org

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

2016-07-17 Thread Martin Teichmann
Hi Guido, Hi Nick, Hi list,

so I just updated PEP 487, you can find it here:
https://github.com/python/peps/pull/57 if it hasn't already been
merged. There are no substantial updates there, I only updated the
wording as suggested, and added some words about backwards
compatibility as hinted by Nick.

Greetings

Martin

2016-07-14 17:47 GMT+02:00 Guido van Rossum :
> I just reviewed the changes you made, I like __set_name__(). I'll just
> wait for your next update, incorporating Nick's suggestions. Regarding
> who merges PRs to the PEPs repo, since you are the author the people
> who merge don't pass any judgment on the changes (unless it doesn't
> build cleanly or maybe if they see a typo). If you intend a PR as a
> base for discussion you can add a comment saying e.g. "Don't merge
> yet". If you call out @gvanrossum, GitHub will make sure I get a
> message about it.
>
> I think the substantial discussion about the PEP should remain here in
> python-dev; comments about typos, grammar and other minor editorial
> issues can go on GitHub. Hope this part of the process makes sense!
>
> On Thu, Jul 14, 2016 at 6:50 AM, Martin Teichmann
>  wrote:
>> Hi Guido, Hi list,
>>
>> Thanks for the nice review! I applied followed up your ideas and put
>> it into a github pull request: https://github.com/python/peps/pull/53
>>
>> Soon we'll be working there, until then, some responses to your comments:
>>
>>> I wonder if this should be renamed to __set_name__ or something else
>>> that clarifies we're passing it the name of the attribute? The method
>>> name __set_owner__ made me assume this is about the owning object
>>> (which is often a useful term in other discussions about objects),
>>> whereas it is really about telling the descriptor the name of the
>>> attribute for which it applies.
>>
>> The name for this has been discussed a bit already, __set_owner__ was
>> Nick's idea, and indeed, the owner is also set. Technically,
>> __set_owner_and_name__ would be correct, but actually I like your idea
>> of __set_name__.
>>
>>> That (inheriting type from type, and object from object) is very
>>> confusing. Why not just define new classes e.g. NewType and NewObject
>>> here, since it's just pseudo code anyway?
>>
>> Actually, it's real code. If you drop those lines at the beginning of
>> the tests for the implementation (as I have done here:
>> https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py),
>> the test runs on older Pythons.
>>
>> But I see that my idea to formulate things here in Python was a bad
>> idea, I will put the explanation first and turn the code into
>> pseudo-code.
>>
 def __init__(self, name, bases, ns, **kwargs):
 super().__init__(name, bases, ns)
>>>
>>> What does this definition of __init__ add?
>>
>> It removes the keyword arguments. I describe that in prose a bit down.
>>
 class object:
 @classmethod
 def __init_subclass__(cls):
 pass

 class object(object, metaclass=type):
 pass
>>>
>>> Eek! Too many things named object.
>>
>> Well, I had to do that to make the tests run... I'll take that out.
>>
 In the new code, it is not ``__init__`` that complains about keyword 
 arguments,
 but ``__init_subclass__``, whose default implementation takes no 
 arguments. In
 a classical inheritance scheme using the method resolution order, each
 ``__init_subclass__`` may take out it's keyword arguments until none are 
 left,
 which is checked by the default implementation of ``__init_subclass__``.
>>>
>>> I called this out previously, and I am still a bit uncomfortable with
>>> the backwards incompatibility here. But I believe what you describe
>>> here is the compromise proposed by Nick, and if that's the case I have
>>> peace with it.
>>
>> No, this is not Nick's compromise, this is my original. Nick just sent
>> another mail to this list where he goes a bit more into the details,
>> I'll respond to that about this topic.
>>
>> Greetings
>>
>> Martin
>>
>> P.S.: I just realized that my changes to the PEP were accepted by
>> someone else than Guido. I am a bit surprised about that, but I guess
>> this is how it works?
>> ___
>> 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/guido%40python.org
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Tres Seaver
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/14/2016 02:10 PM, Brett Cannon wrote:
> On Thu, 14 Jul 2016 at 11:05 Tres Seaver 
> wrote:
> 
>> -BEGIN PGP SIGNED MESSAGE- Hash: SHA1
>> 
>> On 07/14/2016 11:47 AM, Guido van Rossum wrote:
>> 
>>> If you intend a PR as a base for discussion you can add a comment 
>>> saying e.g. "Don't merge yet". If you call out @gvanrossum,
>>> GitHub will make sure I get a message about it.
>> 
>> FWIW, I often use a Github label, "don't merge" (colored red for 
>> urgency), to indicate that PRs are still in discussion stage:
>> removing it is a lightweight way to signify that blocking issues
>> have been resolved (in the opinion of the owner/matintainer,
>> anyway).
>> 
> 
> Just start the title with `[WIP]` and it will be obvious that it's a 
> work-in-progress (it's a GitHub idiom).

De gustibus, I guess:  unlike the title, labels stay visible no matter
how one scrolls the PR / issue, and they are more easily searchable.


Tres.
- -- 
===
Tres Seaver  +1 540-429-0999  tsea...@palladion.com
Palladion Software   "Excellence by Design"http://palladion.com
-BEGIN PGP SIGNATURE-
Version: GnuPG v1

iQIcBAEBAgAGBQJXh90aAAoJEPKpaDSJE9HYeFMP/3r+b6MP4VI+SLnPT6PeZdHU
aVn9/bz4hMb4DtIB1adp6CBEdtxijg0Y2H6BgcmnoFcqhVO0yXquOtJmVfqQr44T
zO8DY+v+eVBcw8KX5MduQt3jLq8fBXviFq0yu55bWYboQRKbUKrfzFwZFlZJ9gH7
AAdieX/26NK4RkFxePYn5dJeJ1EIX7RoRuIB8X5NPve6FA08eRUHvSicQN4Vpvey
Xs+eiLcz+3pOHCu4hiERInu19lztoL5GmdC+cL3mq2A9qpKy9fEAWVRhU84VaDa1
86/jKXgoXfZt2wH7Wj/MC6Z8gXMutIyjcrjVyZEbPQe4zt5o5Vdv/M9nxk1iOnV3
sSqY72HQiiaWvwjWasv0F78LT0nKqt9+bq+aBHrF5PHd0epxInI7KQEScuB+BcaS
aNNVZtSRRQhCEnO8MB6cedBv90sg2FVv8ITBNHac/Zn2ThljMJ8s90gHZZbC3T6/
uP0uvwS8aYzKJoTH5Mmxvt4m4vQCg+tintOwF8/nwN4y4kQFXZcCZqeb4l55XRAE
INal/Khx0eHqd07D7BRZ/a1lKTDuyEuTifJNjZjr9fC704xplMTygJc/kuaTvMfN
4e30iKbMO4oJ3Oyrysr/2E81YlqBe9ZMGdkdBwvyYmGnIKXbmlsHHUQn1asRwF64
l5HJUWDAWxccJ8d83q0g
=NdlU
-END PGP SIGNATURE-

___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Brett Cannon
On Thu, 14 Jul 2016 at 11:05 Tres Seaver  wrote:

> -BEGIN PGP SIGNED MESSAGE-
> Hash: SHA1
>
> On 07/14/2016 11:47 AM, Guido van Rossum wrote:
>
> > If you intend a PR as a base for discussion you can add a comment
> > saying e.g. "Don't merge yet". If you call out @gvanrossum, GitHub
> > will make sure I get a message about it.
>
> FWIW, I often use a Github label, "don't merge" (colored red for
> urgency), to indicate that PRs are still in discussion stage:  removing
> it is a lightweight way to signify that blocking issues have been
> resolved (in the opinion of the owner/matintainer, anyway).
>

Just start the title with `[WIP]` and it will be obvious that it's a
work-in-progress (it's a GitHub idiom).
___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Tres Seaver
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/14/2016 11:47 AM, Guido van Rossum wrote:

> If you intend a PR as a base for discussion you can add a comment
> saying e.g. "Don't merge yet". If you call out @gvanrossum, GitHub
> will make sure I get a message about it.

FWIW, I often use a Github label, "don't merge" (colored red for
urgency), to indicate that PRs are still in discussion stage:  removing
it is a lightweight way to signify that blocking issues have been
resolved (in the opinion of the owner/matintainer, anyway).


Tres.
- -- 
===
Tres Seaver  +1 540-429-0999  tsea...@palladion.com
Palladion Software   "Excellence by Design"http://palladion.com
-BEGIN PGP SIGNATURE-
Version: GnuPG v1

iQIcBAEBAgAGBQJXh9P8AAoJEPKpaDSJE9HYsC0QAMPf/J+n35fg7sMjy07/fE8v
xXXc+JbqnphnZolX1Xjla8sUD6tSpq0dp234VYeGwm4z19p3U5SYpYX4zzNuYCwE
V2AVfdNpY0xwTkoFCbxXTwikZVIGt6o8IQLvqcjlQpCj3wl5A0ggcoaYDnXeKrZd
wE4MF4t9YFgdABZ2i2RVbZNoSRUcMa1kKq9BKpnLnq65dPv2yAYQDDbWIatXLLbi
7kxAfK4CjSWR8BKNzo71uJDeVJVyk6N2nWLuGNOEff8BVZe83cG/2SRjRGALSb0h
kV6FdPhwIhoZ+KrVvkLcbJYpUykBAPK68VSnomXNU14jpY9a3zqEIrirB4YLM3tS
9Ov2GYH+AhDPQ840B197mmkGN4nu/d52jCHPfecgccz2gooy+qoK3FRrMlshTTaD
dbnTlNm/mkEBad8dz7l/u7cGvVG+k5AiFCGkOMikg4So0xXw7C9ulCQhoARWa0DS
J0gTqEGHzGqYAwMXvWxobvlm3HxcxutWuYYx7vD0DRKrPRdpz/ELE7XpOh5bPjjU
sEpt7gaAn/q962QorCDRopvqgd7MeRkrAdPKJzhCIeSUp9+Y/oqolZ/my4uEXSju
W8WHWx41ioDvoUEHFW3pYljSN075STP21SCuxJh+GBDOVS2HsMXEb09wxM81GOAt
V/mBLuZeptsVMiVSQk6J
=/KS/
-END PGP SIGNATURE-

___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Guido van Rossum
I just reviewed the changes you made, I like __set_name__(). I'll just
wait for your next update, incorporating Nick's suggestions. Regarding
who merges PRs to the PEPs repo, since you are the author the people
who merge don't pass any judgment on the changes (unless it doesn't
build cleanly or maybe if they see a typo). If you intend a PR as a
base for discussion you can add a comment saying e.g. "Don't merge
yet". If you call out @gvanrossum, GitHub will make sure I get a
message about it.

I think the substantial discussion about the PEP should remain here in
python-dev; comments about typos, grammar and other minor editorial
issues can go on GitHub. Hope this part of the process makes sense!

On Thu, Jul 14, 2016 at 6:50 AM, Martin Teichmann
 wrote:
> Hi Guido, Hi list,
>
> Thanks for the nice review! I applied followed up your ideas and put
> it into a github pull request: https://github.com/python/peps/pull/53
>
> Soon we'll be working there, until then, some responses to your comments:
>
>> I wonder if this should be renamed to __set_name__ or something else
>> that clarifies we're passing it the name of the attribute? The method
>> name __set_owner__ made me assume this is about the owning object
>> (which is often a useful term in other discussions about objects),
>> whereas it is really about telling the descriptor the name of the
>> attribute for which it applies.
>
> The name for this has been discussed a bit already, __set_owner__ was
> Nick's idea, and indeed, the owner is also set. Technically,
> __set_owner_and_name__ would be correct, but actually I like your idea
> of __set_name__.
>
>> That (inheriting type from type, and object from object) is very
>> confusing. Why not just define new classes e.g. NewType and NewObject
>> here, since it's just pseudo code anyway?
>
> Actually, it's real code. If you drop those lines at the beginning of
> the tests for the implementation (as I have done here:
> https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py),
> the test runs on older Pythons.
>
> But I see that my idea to formulate things here in Python was a bad
> idea, I will put the explanation first and turn the code into
> pseudo-code.
>
>>> def __init__(self, name, bases, ns, **kwargs):
>>> super().__init__(name, bases, ns)
>>
>> What does this definition of __init__ add?
>
> It removes the keyword arguments. I describe that in prose a bit down.
>
>>> class object:
>>> @classmethod
>>> def __init_subclass__(cls):
>>> pass
>>>
>>> class object(object, metaclass=type):
>>> pass
>>
>> Eek! Too many things named object.
>
> Well, I had to do that to make the tests run... I'll take that out.
>
>>> In the new code, it is not ``__init__`` that complains about keyword 
>>> arguments,
>>> but ``__init_subclass__``, whose default implementation takes no arguments. 
>>> In
>>> a classical inheritance scheme using the method resolution order, each
>>> ``__init_subclass__`` may take out it's keyword arguments until none are 
>>> left,
>>> which is checked by the default implementation of ``__init_subclass__``.
>>
>> I called this out previously, and I am still a bit uncomfortable with
>> the backwards incompatibility here. But I believe what you describe
>> here is the compromise proposed by Nick, and if that's the case I have
>> peace with it.
>
> No, this is not Nick's compromise, this is my original. Nick just sent
> another mail to this list where he goes a bit more into the details,
> I'll respond to that about this topic.
>
> Greetings
>
> Martin
>
> P.S.: I just realized that my changes to the PEP were accepted by
> someone else than Guido. I am a bit surprised about that, but I guess
> this is how it works?
> ___
> 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/guido%40python.org



-- 
--Guido van Rossum (python.org/~guido)
___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Martin Teichmann
Hi Nick, hi list,

> It would be worth spelling out the end result of the new behaviour in
> the PEP to make sure it's what we want. Trying to reason about how
> that code works is difficult, but looking at some class definition
> scenarios and seeing how they behave with the old semantics and the
> new semantics should be relatively straightforward (and they can
> become test cases for the revised implementation).

I agree with that. All the examples that Nick gives should work the
same way as they used to. I'll turn them into tests. I hope it is fine
if the error messages change slightly, as long as the error type stays
the same?

Let's look at an example that won't work anymore if my proposal goes throught:

class MyType(type):
def __new__(cls, name, bases, namespace):
return super().__new__(cls, name=name, bases=bases, dict=namespace)

I guess this kind of code is pretty rare. Note that I need to call the
third parameter dict, as this is how it is named. Even if there is
code out there like that, it would be pretty easy to change.

Just in case someone wondered:

def __new__(cls, **kwargs):
return super().__new__(cls, **kwargs)

doesn't work now and won't work afterwards, as the interpreter calls
the metaclass with positional arguments.

That said, it would be possible, at the cost of quite some lines of
code, to make it fully backwards compatible. If the consensus is that
this is needed, I'll change the PEP and code accordingly.

My proposal also has the advantage that name, bases and dict may be
used as class keyword arguments. At least for name I see a usecase:

class MyMangledClass(BaseClass, name="Nice class name"):
 pass

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Martin Teichmann
Hi Guido, Hi list,

Thanks for the nice review! I applied followed up your ideas and put
it into a github pull request: https://github.com/python/peps/pull/53

Soon we'll be working there, until then, some responses to your comments:

> I wonder if this should be renamed to __set_name__ or something else
> that clarifies we're passing it the name of the attribute? The method
> name __set_owner__ made me assume this is about the owning object
> (which is often a useful term in other discussions about objects),
> whereas it is really about telling the descriptor the name of the
> attribute for which it applies.

The name for this has been discussed a bit already, __set_owner__ was
Nick's idea, and indeed, the owner is also set. Technically,
__set_owner_and_name__ would be correct, but actually I like your idea
of __set_name__.

> That (inheriting type from type, and object from object) is very
> confusing. Why not just define new classes e.g. NewType and NewObject
> here, since it's just pseudo code anyway?

Actually, it's real code. If you drop those lines at the beginning of
the tests for the implementation (as I have done here:
https://github.com/tecki/cpython/blob/pep487b/Lib/test/test_subclassinit.py),
the test runs on older Pythons.

But I see that my idea to formulate things here in Python was a bad
idea, I will put the explanation first and turn the code into
pseudo-code.

>> def __init__(self, name, bases, ns, **kwargs):
>> super().__init__(name, bases, ns)
>
> What does this definition of __init__ add?

It removes the keyword arguments. I describe that in prose a bit down.

>> class object:
>> @classmethod
>> def __init_subclass__(cls):
>> pass
>>
>> class object(object, metaclass=type):
>> pass
>
> Eek! Too many things named object.

Well, I had to do that to make the tests run... I'll take that out.

>> In the new code, it is not ``__init__`` that complains about keyword 
>> arguments,
>> but ``__init_subclass__``, whose default implementation takes no arguments. 
>> In
>> a classical inheritance scheme using the method resolution order, each
>> ``__init_subclass__`` may take out it's keyword arguments until none are 
>> left,
>> which is checked by the default implementation of ``__init_subclass__``.
>
> I called this out previously, and I am still a bit uncomfortable with
> the backwards incompatibility here. But I believe what you describe
> here is the compromise proposed by Nick, and if that's the case I have
> peace with it.

No, this is not Nick's compromise, this is my original. Nick just sent
another mail to this list where he goes a bit more into the details,
I'll respond to that about this topic.

Greetings

Martin

P.S.: I just realized that my changes to the PEP were accepted by
someone else than Guido. I am a bit surprised about that, but I guess
this is how it works?
___
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] PEP487: Simpler customization of class creation

2016-07-14 Thread Nick Coghlan
On 14 July 2016 at 08:46, Guido van Rossum  wrote:
> On Wed, Jul 13, 2016 at 7:15 AM, Martin Teichmann  
> wrote:
>> Another small change should be noted here: in the current implementation of
>> CPython, ``type.__init__`` explicitly forbids the use of keyword arguments,
>> while ``type.__new__`` allows for its attributes to be shipped as keyword
>> arguments. This is weirdly incoherent, and thus the above code forbids that.
>> While it would be possible to retain the current behavior, it would be better
>> if this was fixed, as it is probably not used at all: the only use case would
>> be that at metaclass calls its ``super().__new__`` with *name*, *bases* and
>> *dict* (yes, *dict*, not *namespace* or *ns* as mostly used with modern
>> metaclasses) as keyword arguments. This should not be done.
>>
>> As a second change, the new ``type.__init__`` just ignores keyword
>> arguments. Currently, it insists that no keyword arguments are given. This
>> leads to a (wanted) error if one gives keyword arguments to a class 
>> declaration
>> if the metaclass does not process them. Metaclass authors that do want to
>> accept keyword arguments must filter them out by overriding ``__init___``.
>>
>> In the new code, it is not ``__init__`` that complains about keyword 
>> arguments,
>> but ``__init_subclass__``, whose default implementation takes no arguments. 
>> In
>> a classical inheritance scheme using the method resolution order, each
>> ``__init_subclass__`` may take out it's keyword arguments until none are 
>> left,
>> which is checked by the default implementation of ``__init_subclass__``.
>
> I called this out previously, and I am still a bit uncomfortable with
> the backwards incompatibility here. But I believe what you describe
> here is the compromise proposed by Nick, and if that's the case I have
> peace with it.

It would be worth spelling out the end result of the new behaviour in
the PEP to make sure it's what we want. Trying to reason about how
that code works is difficult, but looking at some class definition
scenarios and seeing how they behave with the old semantics and the
new semantics should be relatively straightforward (and they can
become test cases for the revised implementation).

The basic scenario to cover would be defining a metaclass which
*doesn't* accept any additional keyword arguments and seeing how it
fails when passed an unsupported parameter:

class MyMeta(type):
pass

class MyClass(metaclass=MyMeta, otherarg=1):
pass

MyMeta("MyClass", (), otherargs=1)

import types
types.new_class("MyClass", (), dict(metaclass=MyMeta, otherarg=1))
types.prepare_class("MyClass", (), dict(metaclass=MyMeta, otherarg=1))

Current behaviour:

>>> class MyMeta(type):
... pass
...
>>> class MyClass(metaclass=MyMeta, otherarg=1):
... pass
...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: type() takes 1 or 3 arguments
>>> MyMeta("MyClass", (), otherargs=1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: Required argument 'dict' (pos 3) not found
>>> import types
>>> types.new_class("MyClass", (), dict(metaclass=MyMeta, otherarg=1))
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib64/python3.5/types.py", line 57, in new_class
return meta(name, bases, ns, **kwds)
TypeError: type() takes 1 or 3 arguments
>>> types.prepare_class("MyClass", (), dict(metaclass=MyMeta, otherarg=1))
(, {}, {'otherarg': 1})

The error messages may change, but the cases which currently fail
should continue to fail with TypeError

Further scenarios would then cover the changes needed to the
definition of "MyMeta" to make the class creation invocations above
actually work (since the handling of __prepare__ already tolerates
unknown arguments).

First, just defining __new__ (which currently fails):

>>> class MyMeta(type):
... def __new__(cls, name, bases, namespace, otherarg):
... self = super().__new__(cls, name, bases, namespace)
... self.otherarg = otherarg
... return self
...
>>> class MyClass(metaclass=MyMeta, otherarg=1):
... pass
...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: type.__init__() takes no keyword arguments

Making this work would be fine, and that's what I believe will happen
with the PEP's revised semantics.

Then, just defining __init__ (which also fails):

>>> class MyMeta(type):
... def __init__(self, name, bases, namespace, otherarg):
... super().__init__(name, bases, namespace)
... self.otherarg = otherarg
...
>>> class MyClass(metaclass=MyMeta, otherarg=1):
... pass
...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: type() takes 1 or 3 arguments

The PEP shouldn't result in any changes in this case.

And finally defining both of them (which succeeds):

>>> class MyMeta(type):
... def __new__(cls, name, bases, namespace, otherarg):
...

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

2016-07-13 Thread Guido van Rossum
FWIW I copied the version you posted into the peps repo already, since
it provides a significant update to the last version there.

On Wed, Jul 13, 2016 at 2:02 PM, Guido van Rossum  wrote:
> I'm reviewing this now.
>
> Martin, can you please submit the new version of your PEP as a Pull
> Request to the new peps repo on GitHub? https://github.com/python/peps
>
> --Guido
>
> On Wed, Jul 13, 2016 at 7:45 AM, Nick Coghlan  wrote:
>> On 14 July 2016 at 00:15, Martin Teichmann  wrote:
>>> Hi list,
>>>
>>> another round for PEP 487, is there any chance it still makes it into
>>> Python 3.6?
>>>
>>> The PEP should be effectively done, I updated the examples in it,
>>> given that I implemented the PEP I could actually test the examples,
>>> so now they work.
>>>
>>> The implementation is at http://bugs.python.org/issue27366, including
>>> documentation and tests. Unfortunately nobody has reviewed the patch
>>> yet.
>>>
>>> The new version of the PEP is attached.
>>
>> +1 from me for this version - between them, this and PEP 520 address
>> everything I hoped to achieve with PEP 422, and a bit more besides.
>>
>> There's no BDFL delegation in place for this one though, so it's
>> really Guido's +1 that you need :)
>>
>> 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/guido%40python.org
>
>
>
> --
> --Guido van Rossum (python.org/~guido)



-- 
--Guido van Rossum (python.org/~guido)
___
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] PEP487: Simpler customization of class creation

2016-07-13 Thread Guido van Rossum
On Wed, Jul 13, 2016 at 7:15 AM, Martin Teichmann
 wrote:
> Hi list,
>
> another round for PEP 487, is there any chance it still makes it into
> Python 3.6?

Sure, feature freeze isn't until September
(https://www.python.org/dev/peps/pep-0494/).

> The PEP should be effectively done, I updated the examples in it,
> given that I implemented the PEP I could actually test the examples,
> so now they work.

I am +1 on the idea of the PEP; below I am just asking for some
clarifications and pointing out a typo or two. Please submit the next
version to the github peps project as a PR! Re-review should be much
quicker then.

> The implementation is at http://bugs.python.org/issue27366, including
> documentation and tests. Unfortunately nobody has reviewed the patch
> yet.

Sorry, I don't have time for that part, but I'm sure once the PEP is
approved the review will follow.

> The new version of the PEP is attached.
>
> Greetings
>
> Martin
>
> 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, 13-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 of 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

initialization

> 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.

PEP, PEP 520.

> As an example, the first use case looks as follows::
>
>>>> class QuestBase:
>...# this is implicitly a @classmethod

maybe add "(see below for motivation)" ?

>...def __init_subclass__(cls, swallow, **kwargs):
>...cls.swallow = swallow
>...super().__init_subclass__(**kwargs)
>
>>>> class Quest(QuestBase, swallow="african"):
>...pass
>
>>>> Quest.swallow
>'african'
>
> 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 their
> name. This is unfortunate, 

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

2016-07-13 Thread Guido van Rossum
I'm reviewing this now.

Martin, can you please submit the new version of your PEP as a Pull
Request to the new peps repo on GitHub? https://github.com/python/peps

--Guido

On Wed, Jul 13, 2016 at 7:45 AM, Nick Coghlan  wrote:
> On 14 July 2016 at 00:15, Martin Teichmann  wrote:
>> Hi list,
>>
>> another round for PEP 487, is there any chance it still makes it into
>> Python 3.6?
>>
>> The PEP should be effectively done, I updated the examples in it,
>> given that I implemented the PEP I could actually test the examples,
>> so now they work.
>>
>> The implementation is at http://bugs.python.org/issue27366, including
>> documentation and tests. Unfortunately nobody has reviewed the patch
>> yet.
>>
>> The new version of the PEP is attached.
>
> +1 from me for this version - between them, this and PEP 520 address
> everything I hoped to achieve with PEP 422, and a bit more besides.
>
> There's no BDFL delegation in place for this one though, so it's
> really Guido's +1 that you need :)
>
> 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/guido%40python.org



-- 
--Guido van Rossum (python.org/~guido)
___
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] PEP487: Simpler customization of class creation

2016-07-13 Thread Nick Coghlan
On 14 July 2016 at 00:15, Martin Teichmann  wrote:
> Hi list,
>
> another round for PEP 487, is there any chance it still makes it into
> Python 3.6?
>
> The PEP should be effectively done, I updated the examples in it,
> given that I implemented the PEP I could actually test the examples,
> so now they work.
>
> The implementation is at http://bugs.python.org/issue27366, including
> documentation and tests. Unfortunately nobody has reviewed the patch
> yet.
>
> The new version of the PEP is attached.

+1 from me for this version - between them, this and PEP 520 address
everything I hoped to achieve with PEP 422, and a bit more besides.

There's no BDFL delegation in place for this one though, so it's
really Guido's +1 that you need :)

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


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

2016-07-05 Thread Martin Teichmann
> This is an area of exceeding subtlety (and also not very well
> documented/specified, probably). I'd worry that changing anything here
> might break some code. When a metaclass overrides neither __init__ nor
> __new__, keyword args will not work because type.__init__ forbids
> them. However when a metaclass overrides them and calls them using
> super(), it's quite possible that someone ended up calling
> super().__init__() with three positional args but super().__new__()
> with keyword args, since the call sites are distinct (in the overrides
> for __init__ and __new__ respectively).
>
> What's your argument for changing this, apart from a desire for more 
> regularity?

The implementation gets much simpler if __new__ doesn't take keyword
arguments. It's simply that if it does, I have to filter out __new__'s
three arguments.
That's easily done in Python, unfortunately not so much in C.

So we have two options: either type.__new__ is limited to accepting positional
arguments only, possibly breaking some code, but which could be changed
easily. This leads to a pretty simple implementation: pass over
keyword arguments
to __init_subclass__, that's it.

The other option is: filter out name, bases and dict from the keyword arguments
If people think that backwards compatibility is that important, I
could do that. But
that just leaves quite some code in places where there is already a lot of
complicated code.

Nick proposed a compromise, just don't filter for name, bases and dict, and
pass them over to __init_subclass__. Then the default implementation of
__init_subclass__ must support those three keyword arguments and do
nothing with them.

I'm fine with all three solutions, although I have a preference for the first.
I think passing keyword arguments to type.__new__ is already really rare
and if it does exist, it's super easy to fix.

> I'm confused. In the above example it would seem that the keyword args
> {'a': 1, 'b': 2} are passed right on to super9).__init_subclass__().
> Do you mean that it ignores all keyword args? Or that it has no
> positional args? (Both of which would be consistent with the example.)

The example is just wrong. I'll fix it.

> Can you state exactly at which point during class initialization
> __init_class__() is called? (Surely by now, having implemented it, you
> know exactly where. :-)

Further down in the PEP I give the exact

> [This is as far as I got reviewing when the weekend activities
> interrupted me. In the light of ongoing discussion I'm posting this
> now -- I'll continue later.]

I hope you had a good weekend not thinking too much about
metaclasses...

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-03 Thread Guido van Rossum
On Sat, Jul 2, 2016 at 10:50 AM, Martin Teichmann
 wrote:
> 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.

Thanks! Reviewing inline below.

> 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.

This is an area of exceeding subtlety (and also not very well
documented/specified, probably). I'd worry that changing anything here
might break some code. When a metaclass overrides neither __init__ nor
__new__, keyword args will not work because type.__init__ forbids
them. However when a metaclass overrides them and calls them using
super(), it's quite possible that someone ended up calling
super().__init__() with three positional args but super().__new__()
with keyword args, since the call sites are distinct (in the overrides
for __init__ and __new__ respectively).

What's your argument for changing this, apart from a desire for more regularity?

> 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
>  

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

2016-07-03 Thread Martin Teichmann
Hi Nick,

thanks for the nice review!

> I think making __init_subclass__ implicitly a class method is still
> the right thing to do if this proposal gets accepted, we'll just want
> to see if we can do something to tidy up that aspect of the
> documentation at the same time.

I could write some documentation, I just don't know where to put it.
I personally have no strong feelings whether __init_subclass__ should
be implicitly a @classmethod or not - but as the general consensus here
seemed to hint making it implicit is better, this is how I wrote it.

>> 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.
>
> [some discussion cut out]
>
> I think the PEP could be accepted without cleaning this up, though -
> it would just mean __init_subclass__ would see the "name", "bases" and
> "dict" keys when someone attempted to use keyword arguments with the
> dynamic type creation APIs.

Yes, this would be possible, albeit a bit ugly. I'm not so sure whether
backwards compatibility is so important in this case. It is very
easy to change the code to the fully cleaned up version


Looking through old stuff I found http://bugs.python.org/issue23722,
which describes the following problem: at the time __init_subclass__ is
called, super() doesn't work yet for the new class. It does work for
__init_subclass__, because it is called on the base class, but not for
calls to other classmethods it does. This is a pity especially because
also the two argument form of super() cannot be used as the new
class has no name yet.

The problem is solvable though. The initializations necessary for
super() to work properly simply should be moved before the call
to __init_subclass__. I implemented that by putting a new attribute
into the class's namespace to keep the cell which will later be used
by super(). This new attribute would be remove by type.__new__
again, but transiently it would be visible. This technique has already
been used for __qualname__.

The issue contains a patch that fixes that behavior, and back in the
day you proposed I add the problem to the PEP. Should I?

Greetings

Martin
___
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] PEP487: Simpler customization of class creation

2016-07-03 Thread Nick Coghlan
On 2 July 2016 at 10:50, Martin Teichmann  wrote:
> 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.

I'm +1 for this part of the proposal.

One potential documentation issue is that __init_subclass__ adds yet a
third special magic method behaviour:

- __new__ is implicitly a static method
- __prepare__ isn't implicitly anything (but in hindsight should have
implicitly been a class method)
- __init_subclass__ is implicitly a class method

I think making __init_subclass__ implicitly a class method is still
the right thing to do if this proposal gets accepted, we'll just want
to see if we can do something to tidy up that aspect of the
documentation at the same time.

> 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.

I *think* I'm in favour of cleaning this up, but I also think the
explanation of the problem with the status quo could stand to be
clearer, as could the proposed change in behaviour. Some example code
at the interactive prompt may help with that.

Positional arguments already either work properly, or give a helpful
error message:

>>> type("Example", (), {})

>>> type.__new__("Example", (), {})
Traceback (most recent call last):
 File "", line 1, in 
TypeError: type.__new__(X): X is not a type object (str)
>>> type.__new__(type, "Example", (), {})

>>> type.__init__("Example", (), {})
Traceback (most recent call last):
 File "", line 1, in 
TypeError: descriptor '__init__' requires a 'type' object but
received a 'str'
>>> type.__init__(type, "Example", (), {})

By contrast, attempting to use keyword arguments is a fair collection
of implementation defined "Uh, what just happened?":

>>> type(name="Example", bases=(), dict={})
Traceback (most recent call last):
 File "", line 1, in 
TypeError: type.__init__() takes no keyword arguments
>>> type.__new__(name="Example", bases=(), dict={}) # Huh?
Traceback (most recent call last):
 File "", line 1, in 
TypeError: type.__new__(): not enough arguments
>>> type.__new__(type, name="Example", bases=(), dict={})

>>> type.__init__(name="Example", bases=(), dict={}) # Huh?
Traceback (most recent call last):
 File "", line 1, in 
TypeError: descriptor '__init__' of 'type' object needs an argument
>>> type.__init__(type, name="Example", bases=(), dict={}) # Huh?
Traceback (most recent call last):
 File "", line 1, in 
TypeError: type.__init__() takes no keyword arguments

I think the PEP could be accepted without cleaning this up, though -
it would just mean __init_subclass__ would see the "name", "bases" and
"dict" keys when someone attempted to use keyword arguments with the
dynamic type creation APIs.

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