From a7dc8cb417913184fd8962230d4282fd3ae15b70 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 10 Feb 2013 21:47:22 +1000 Subject: [PATCH 1/4] Reference implementation for PEP 422 --- pep-0422.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pep-0422.txt b/pep-0422.txt index e564eed6f..6f09fc024 100644 --- a/pep-0422.txt +++ b/pep-0422.txt @@ -325,6 +325,12 @@ relied on the ``__class__`` reference (or used the zero-argument form of ``super()``), and could not make use of those features themselves. +Reference Implementation +======================== + +Daniel Urban has posted a reference implementation to the `issue tracker`_. + + References ========== @@ -337,12 +343,15 @@ References .. _Zope's ExtensionClass: http://docs.zope.org/zope_secrets/extensionclass.html +.. _issue tracker: + http://bugs.python.org/issue17044 + Copyright ========= This document has been placed in the public domain. - + .. Local Variables: mode: indented-text From 9a660dde6b4295c449b9824652766415c7697ce8 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 10 Feb 2013 22:13:58 +1000 Subject: [PATCH 2/4] Add Daniel as PEP 422 co-author, misc fixes --- pep-0422.txt | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/pep-0422.txt b/pep-0422.txt index 6f09fc024..f1f2f81d5 100644 --- a/pep-0422.txt +++ b/pep-0422.txt @@ -2,7 +2,8 @@ PEP: 422 Title: Simple class initialisation hook Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan +Author: Nick Coghlan , + Daniel Urban Status: Draft Type: Standards Track Content-Type: text/x-rst @@ -19,7 +20,7 @@ was created (or simply arrange to run other code after the class was created) by setting the ``__metaclass__`` attribute in the class body. While doing this implicitly from called code required the use of an implementation detail (specifically, ``sys._getframes()``), it could also be done explicitly in a -fully supported fashion (for example, by passing ``locals()`` to an +fully supported fashion (for example, by passing ``locals()`` to a function that calculated a suitable ``__metaclass__`` value) There is currently no corresponding mechanism in Python 3 that allows the @@ -44,7 +45,7 @@ the metaclass hint that may be provided as part of the class definition. While in many cases these two meanings end up referring to one and the same object, there are two situations where that is not the case: -* If the metaclass hint refers to a subclass of ``type``, then it is +* If the metaclass hint refers to an instance of ``type``, then it is considered as a candidate metaclass along with the metaclasses of all of the parents of the class being defined. If a more appropriate metaclass is found amongst the candidates, then it will be used instead of the one @@ -114,7 +115,7 @@ class initialisation hook as follows:: # This is invoked after the class is created, but before any # explicit decorators are called # The usual super() mechanisms are used to correctly support - # multiple inheritance. The decorator style invocation helps + # multiple inheritance. The class decorator style signature helps # ensure that invoking the parent class is as simple as possible. If present on the created object, this new hook will be called by the class @@ -125,10 +126,17 @@ returning the created class object. If a metaclass wishes to block class initialisation for some reason, it must arrange for ``cls.__init_class__`` to trigger ``AttributeError``. +Note, that when ``__init_class__`` is called, the name of the class is not +bound to the new class object yet. As a consequence, the two argument form +of ``super()`` cannot be used to call methods (e.g., ``super(Example, cls)`` +wouldn't work in the example above). However, the zero argument form of +``super()`` works as expected, since the ``__class__`` reference is already +initialised. + 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 I believe the situation has changed sufficiently in recent years that +but the situation has changed sufficiently in recent years that the idea is worth reconsidering. @@ -156,7 +164,7 @@ the metaclass hint, the actual metaclass, the class object, instances of the class object) clearly distinct in your mind. Even when you know the rules, it's still easy to make a mistake if you're not being extremely careful. An earlier version of this PEP actually included such a mistake: it -stated "instance of type" for a constraint that is actually "subclass of +stated "subclass of type" for a constraint that is actually "instance of type". Understanding the proposed class initialisation hook only requires @@ -278,17 +286,24 @@ iterable ``__decorators__`` attributes. Using the current version of the PEP, the scheme originally proposed could be implemented as:: - class DynamicDecorators: + class DynamicDecorators(Base): @classmethod def __init_class__(cls): - super(DynamicDecorators, cls).__init_class__() + # Process any classes later in the MRO + try: + mro_chain = super().__init_class__ + except AttributeError: + pass + else: + mro_chain() + # Process any __decorators__ attributes in the MRO for entry in reversed(cls.mro()): decorators = entry.__dict__.get("__decorators__", ()) for deco in reversed(decorators): cls = deco(cls) -Any subclasses of this type would automatically have the contents of any -``__decorators__`` attributes processed and invoked. +Any subclasses of ``DynamicDecorators`` would then automatically have the +contents of any ``__decorators__`` attributes processed and invoked. The mechanism in the current PEP is considered superior, as many issues to do with ordering and the same decorator being invoked multiple times @@ -328,7 +343,7 @@ relied on the ``__class__`` reference (or used the zero-argument form of Reference Implementation ======================== -Daniel Urban has posted a reference implementation to the `issue tracker`_. +The reference implementation has been posted to the `issue tracker`_. References From c0a1e03125dbbd0bb596b05de0f29a35225b30b7 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 10 Feb 2013 22:25:46 +1000 Subject: [PATCH 3/4] Update PEP 422 post history --- pep-0422.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0422.txt b/pep-0422.txt index f1f2f81d5..37087e6d4 100644 --- a/pep-0422.txt +++ b/pep-0422.txt @@ -9,7 +9,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 5-Jun-2012 Python-Version: 3.4 -Post-History: 5-Jun-2012 +Post-History: 5-Jun-2012, 10-Feb-2012 Abstract From f30a4815250823d3a0b03127b2aad36b77859bb5 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 10 Feb 2013 14:34:41 -0500 Subject: [PATCH 4/4] Update from Lennart --- pep-0431.txt | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/pep-0431.txt b/pep-0431.txt index 250b2df4d..48cb6cdd2 100644 --- a/pep-0431.txt +++ b/pep-0431.txt @@ -8,7 +8,7 @@ Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 11-Dec-2012 -Post-History: 11-Dec-2012, 28-Dec-2012 +Post-History: 11-Dec-2012, 28-Dec-2012, 28-Jan-2013 Abstract @@ -94,7 +94,7 @@ Ambiguous times When changing over from daylight savings time (DST) the clock is turned back one hour. This means that the times during that hour happens twice, once -without DST and then once with DST. Similarly, when changing to daylight +with DST and then once without DST. Similarly, when changing to daylight savings time, one hour goes missing. The current time zone API can not differentiate between the two ambiguous @@ -156,10 +156,10 @@ The public API of the new time zone support contains one new class, one new function, one new exception and four new collections. In addition to this, several methods on the datetime object gets a new ``is_dst`` parameter. -New class ``DstTzInfo`` -^^^^^^^^^^^^^^^^^^^^^^^^ +New class ``dsttimezone`` +^^^^^^^^^^^^^^^^^^^^^^^^^ -This class provides a concrete implementation of the ``zoneinfo`` base +This class provides a concrete implementation of the ``tzinfo`` base class that implements DST support. @@ -176,11 +176,11 @@ The function also takes an optional path to the location of the zoneinfo database which should be used. If not specified, the function will look for databases in the following order: -1. Use the database in ``/usr/share/zoneinfo``, if it exists. - -2. Check if the `tzdata-update` module is installed, and then use that +1. Check if the `tzdata-update` module is installed, and then use that database. +2. Use the database in ``/usr/share/zoneinfo``, if it exists. + 3. Use the Python-provided database in ``Lib/tzdata``. If no database is found an ``UnknownTimeZoneError`` or subclass thereof will @@ -206,7 +206,7 @@ The ``is_dst`` parameter can be ``False`` (default), ``True``, or ``None``. ``False`` will specify that the given datetime should be interpreted as not happening during daylight savings time, i.e. that the time specified is after -the change from DST. +the change from DST. This is default to preserve existing behavior. ``True`` will specify that the given datetime should be interpreted as happening during daylight savings time, i.e. that the time specified is before the change @@ -224,7 +224,7 @@ New exceptions This exception is a subclass of KeyError and raised when giving a time zone specification that can't be found:: - >>> datetime.Timezone('Europe/New_York') + >>> datetime.zoneinfo('Europe/New_York') Traceback (most recent call last): ... UnknownTimeZoneError: There is no time zone called 'Europe/New_York' @@ -250,8 +250,8 @@ New exceptions * ``NonExistentTimeError`` - This exception is raised when giving a datetime specification that is ambiguous - while setting ``is_dst`` to None:: + This exception is raised when giving a datetime specification for a time that due to + daylight saving does not exist, while setting ``is_dst`` to None:: >>> datetime(2012, 3, 25, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'), is_dst=None) >>> @@ -266,13 +266,9 @@ New collections * ``all_timezones`` is the exhaustive list of the time zone names that can be used, listed alphabethically. -* ``all_timezones_set`` is a set of the time zones in ``all_timezones``. - * ``common_timezones`` is a list of useful, current time zones, listed alphabethically. -* ``common_timezones_set`` is a set of the time zones in ``common_timezones``. - The ``tzdata-update``-package -----------------------------