<div dir="ltr">OK, I approved the PR. Can some other core dev ensure that it gets merged? No backports though!<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Feb 4, 2019 at 8:46 AM Paul Ganssle <<a href="mailto:paul@ganssle.io">paul@ganssle.io</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF">
    <p>There's already a PR, actually, #10902: <a class="gmail-m_3519432959184518876gmail-m_8165555785083225151moz-txt-link-freetext" href="https://github.com/python/cpython/pull/10902" target="_blank">https://github.com/python/cpython/pull/10902</a><br>
      <br>
      Victor reviewed and approved it, I think before I started this
      thread, so now it's just waiting on merge.<br>
    </p>
    <div class="gmail-m_3519432959184518876moz-cite-prefix">On 2/4/19 11:38 AM, Guido van Rossum
      wrote:<br>
    </div>
    <blockquote type="cite">
      <div dir="ltr">I recommend that you submit a PR so we can get it
        into 3.8 alpha 2.<br>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Feb 4, 2019 at 5:50 AM
          Paul Ganssle <<a href="mailto:paul@ganssle.io" target="_blank">paul@ganssle.io</a>> wrote:<br>
        </div>
        <blockquote class="gmail_quote">
          <div>
            <p>Hey all,</p>
            <p>This thread about the return type of datetime operations
              seems to have stopped without any explicit decision - I
              think I responded to everyone who had objections, but I
              think only Guido has given a +1 to whether or not we
              should go ahead.</p>
            <p>Have we got agreement to go ahead with this change? Are
              we still targeting Python 3.8 here?</p>
            <p>For those who don't want to dig through your old e-mails,
              here's the archive link for this thread: <a class="gmail-m_3519432959184518876gmail-m_8165555785083225151moz-txt-link-freetext" href="https://mail.python.org/pipermail/python-dev/2019-January/155984.html" target="_blank">https://mail.python.org/pipermail/python-dev/2019-January/155984.html</a><br>
              <br>
              If you want to start commenting on the actual
              implementation, it's available here (though it's pretty
              simple): <a class="gmail-m_3519432959184518876gmail-m_8165555785083225151moz-txt-link-freetext" href="https://github.com/python/cpython/pull/10902" target="_blank">https://github.com/python/cpython/pull/10902</a><br>
              <br>
              Best,</p>
            <p>Paul</p>
            <p><br>
            </p>
            <div class="gmail-m_3519432959184518876gmail-m_8165555785083225151moz-cite-prefix">On
              1/6/19 7:17 PM, Guido van Rossum wrote:<br>
            </div>
            <blockquote type="cite">
              <div dir="ltr">OK, I concede your point (and indeed I only
                tested this on 3.6). If we could break the backward
                compatibility for now() we presumably can break it for
                this purpose.<br>
              </div>
              <br>
              <div class="gmail_quote">
                <div dir="ltr">On Sun, Jan 6, 2019 at 11:02 AM Paul
                  Ganssle <<a href="mailto:paul@ganssle.io" target="_blank">paul@ganssle.io</a>>
                  wrote:<br>
                </div>
                <blockquote class="gmail_quote">
                  <div>
                    <p>I did address this in the original post - the
                      assumption that the subclass constructor will have
                      the same arguments as the base constructor is
                      baked into many alternate constructors of
                      datetime. I acknowledge that this is a breaking
                      change, but it is a small one - anyone creating
                      such a subclass that <i>cannot</i> handled the
                      class being created this way would be broken in
                      myriad ways.<br>
                      <br>
                      We have also in recent years changed several
                      alternate constructors (including `replace`) to
                      retain the original subclass, which by your same
                      standard would be a breaking change. I believe
                      there have been no complaints. In fact, between
                      Python 3.6 and 3.7, the very example you showed
                      broke:<br>
                      <br>
                      Python 3.6.6:<br>
                      <br>
                      >>> class D(datetime.datetime):<br>
                      ...     def __new__(cls):<br>
                      ...         return cls.now()<br>
                      ... <br>
                      >>> D()<br>
                      D(2019, 1, 6, 13, 49, 38, 842033)<br>
                      <br>
                      Python 3.7.2:<br>
                      <br>
                      >>> class D(datetime.datetime):<br>
                      ...     def __new__(cls):<br>
                      ...         return cls.now()<br>
                      ... <br>
                      >>> D()<br>
                      Traceback (most recent call last):<br>
                        File "<stdin>", line 1, in <module><br>
                        File "<stdin>", line 3, in __new__<br>
                      TypeError: __new__() takes 1 positional argument
                      but 9 were given</p>
                    <p><br>
                      We haven't seen any bug reports about this sort of
                      thing; what we <i>have</i> been getting is bug
                      reports that subclassing datetime doesn't retain
                      the subclass in various ways (because people <i>are</i>
                      using datetime subclasses). This is likely to
                      cause very little in the way of problems, but it
                      will improve convenience for people making
                      datetime subclasses and almost certainly
                      performance for people using them (e.g. pendulum
                      and arrow, which now need to take a slow pure
                      python route in many situations to work around
                      this problem).</p>
                    <p>If we're <i>really</i> concerned with this
                      backward compatibility breaking, we could do the
                      equivalent of:<br>
                      <tt><br>
                      </tt><tt>try:</tt><tt><br>
                      </tt><tt>    return new_behavior(...)</tt><tt><br>
                      </tt><tt>except TypeError:</tt><tt><br>
                      </tt><tt>    warnings.warn("The semantics of
                        timedelta addition have "</tt><tt><br>
                      </tt><tt>                  "changed in a way that
                        raises an error in "<br>
                                          "this subclass. Please
                        implement __add__ "<br>
                                          "if you need the old
                        behavior.", DeprecationWarning)<br>
                        <br>
                      </tt>Then after a suitable notice period drop the
                      warning and turn it to a hard error.<br>
                    </p>
                    <p>Best,</p>
                    <p>Paul<br>
                    </p>
                    <div class="gmail-m_3519432959184518876gmail-m_8165555785083225151gmail-m_-344422180359162179moz-cite-prefix">On
                      1/6/19 1:43 PM, Guido van Rossum wrote:<br>
                    </div>
                    <blockquote type="cite">
                      <div dir="ltr">
                        <div dir="ltr">
                          <div dir="ltr">
                            <div dir="ltr">
                              <div>I don't think datetime and builtins
                                like int necessarily need to be aligned.
                                But I do see a problem -- the __new__
                                and __init__ methods defined in the
                                subclass (if any) should allow for being
                                called with the same signature as the
                                base datetime class. Currently you can
                                have a subclass of datetime whose
                                __new__ has no arguments (or, more
                                realistically, interprets its arguments
                                differently). Instances of such a class
                                can still be added to a timedelta. The
                                proposal would cause this to break
                                (since such an addition has to create a
                                new instance, which calls __new__ and
                                __init__). Since this is a backwards
                                incompatibility, I don't see how it can
                                be done -- and I also don't see many use
                                cases, so I think it's not worth
                                pursuing further.<br>
                              </div>
                              <div><br>
                              </div>
                              <div>Note that the same problem already
                                happens with the .fromordinal() class
                                method, though it doesn't happen with
                                .fromdatetime() or .now():</div>
                              <div><br>
                              </div>
                              <div>>>> class
                                D(datetime.datetime):<br>
                                ...   def __new__(cls): return cls.now()<br>
                                ... <br>
                                >>> D()<br>
                                D(2019, 1, 6, 10, 33, 37, 161606)<br>
                                >>> D.fromordinal(100)<br>
                                Traceback (most recent call last):<br>
                                  File "<stdin>", line 1, in
                                <module><br>
                                TypeError: __new__() takes 1 positional
                                argument but 4 were given<br>
                                >>> D.fromtimestamp(123456789)<br>
                                D(1973, 11, 29, 13, 33, 9)<br>
                                >>> <br>
                              </div>
                            </div>
                          </div>
                        </div>
                      </div>
                      <br>
                      <div class="gmail_quote">
                        <div dir="ltr">On Sun, Jan 6, 2019 at 9:05 AM
                          Paul Ganssle <<a href="mailto:paul@ganssle.io" target="_blank">paul@ganssle.io</a>>
                          wrote:<br>
                        </div>
                        <blockquote class="gmail_quote">
                          <div>
                            <p>I can think of many reasons why datetime
                              is different from builtins, though to be
                              honest I'm not sure that consistency for
                              its own sake is really a strong argument
                              for keeping a counter-intuitive behavior -
                              and to be honest I'm open to the idea that
                              <i>all</i> arithmetic types <i>should</i>
                              have some form of this change.<br>
                            </p>
                            <p>That said, I would say that the biggest
                              difference between datetime and builtins
                              (other than the fact that datetime is <i>not</i>
                              a builtin, and as such doesn't necessarily
                              need to be categorized in this group), is
                              that unlike almost all other arithmetic
                              types, <i>datetime</i> has a special,
                              dedicated type for describing differences
                              in datetimes. Using your example of a
                              float subclass, consider that without the
                              behavior of "addition of floats returns
                              floats", it would be hard to predict what
                              would happen in this situation:<br>
                              <br>
                              >>> F(1.2) + 3.4<br>
                              <br>
                              Would that always return a float, even
                              though F(1.2) + F(3.4) returns an F? Would
                              that return an F because F is the
                              left-hand operand? Would it return a float
                              because float is the right-hand operand?
                              Would you walk the MROs and find the
                              lowest type in common between the operands
                              and return that? It's not entirely clear
                              which subtype predominates. With datetime,
                              you have:<br>
                              <br>
                              datetime - datetime -> timedelta<br>
                              datetime ± timedelta -> datetime<br>
                              timedelta ± timedelta -> timedelta<br>
                              <br>
                              There's no operation between two datetime
                              objects that would return a datetime
                              object, so it's always clear: operations
                              between datetime subclasses return
                              timedelta, operations between a datetime
                              object and a timedelta return the subclass
                              of the datetime that it was added to or
                              subtracted from.</p>
                            <p>Of course, the real way to resolve
                              whether datetime should be different from
                              int/float/string/etc is to look at why
                              this choice was actually made for those
                              types in the first place, and decide
                              whether datetime is like them <i>in this
                                respect</i>. The heterogeneous
                              operations problem may be a reasonable
                              justification for leaving the other
                              builtins alone but changing datetime, but
                              if someone knows of other fundamental
                              reasons why the decision to have
                              arithmetic operations always create the
                              base class was chosen, please let me know.<br>
                              <br>
                              Best,<br>
                              Paul<br>
                            </p>
                            <div class="gmail-m_3519432959184518876gmail-m_8165555785083225151gmail-m_-344422180359162179gmail-m_-6009346472102158879moz-cite-prefix">On
                              1/5/19 3:55 AM, Alexander Belopolsky
                              wrote:<br>
                            </div>
                            <blockquote type="cite">
                              <div dir="ltr">
                                <div dir="ltr">
                                  <div dir="ltr">
                                    <div dir="ltr"><br>
                                    </div>
                                    <br>
                                    <div class="gmail_quote">
                                      <div dir="ltr">On Wed, Jan 2, 2019
                                        at 10:18 PM Paul Ganssle <<a href="mailto:paul@ganssle.io" target="_blank">paul@ganssle.io</a>>
                                        wrote:<br>
                                      </div>
                                      <blockquote class="gmail_quote">
                                        <div>
                                          <p>.. the original objection
                                            was that this implementation
                                            assumes that the datetime
                                            subclass has a constructor
                                            with the same (or a
                                            sufficiently similar)
                                            signature as datetime.</p>
                                        </div>
                                      </blockquote>
                                      <div>While this was used as a
                                        possible rationale for the way
                                        standard types behave, the main
                                        objection to changing datetime
                                        classes is that it will make
                                        them behave differently from
                                        builtins.  For example:</div>
                                      <div>
                                        <div><br>
                                        </div>
                                        <div>>>> class
                                          F(float):</div>
                                        <div>...     pass</div>
                                        <div>...</div>
                                      </div>
                                      <div>
                                        <div>>>>
                                          type(F.fromhex('AA'))</div>
                                        <div><class '__main__.F'></div>
                                        <div>>>> type(F(1) +
                                          F(2))</div>
                                        <div><class 'float'></div>
                                      </div>
                                      <div><br>
                                      </div>
                                      <blockquote class="gmail_quote">
                                        <div>
                                          <p> This may be a legitimate
                                            gripe, but unfortunately
                                            that ship has sailed long
                                            ago. All of datetime's
                                            alternate constructors make
                                            this assumption. Any
                                            subclass that does not meet
                                            this requirement must have
                                            worked around it long ago
                                            (or they don't care about
                                            alternate constructors).</p>
                                        </div>
                                      </blockquote>
                                      <div><br>
                                      </div>
                                      <div>This is right, but the same
                                        argument is equally applicable
                                        to int, float, etc. subclasses. 
                                        If you want to limit your change
                                        to datetime types you should
                                        explain what makes these types
                                        special.  </div>
                                    </div>
                                  </div>
                                </div>
                              </div>
                            </blockquote>
                          </div>
_______________________________________________<br>
                          Python-Dev mailing list<br>
                          <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
                          <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
                          Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
                        </blockquote>
                      </div>
                      <br>
                      <br>
                      -- <br>
                      <div dir="ltr" class="gmail-m_3519432959184518876gmail-m_8165555785083225151gmail-m_-344422180359162179gmail_signature">--Guido
                        van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
                    </blockquote>
                  </div>
                  _______________________________________________<br>
                  Python-Dev mailing list<br>
                  <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
                  <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
                  Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
                </blockquote>
              </div>
              <br>
              <br>
              -- <br>
              <div dir="ltr" class="gmail-m_3519432959184518876gmail-m_8165555785083225151gmail_signature">--Guido
                van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
            </blockquote>
          </div>
          _______________________________________________<br>
          Python-Dev mailing list<br>
          <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
          <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
          Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
        </blockquote>
      </div>
      <br>
      <br>
      -- <br>
      <div dir="ltr" class="gmail-m_3519432959184518876gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
    </blockquote>
  </div>

_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote></div><br clear="all"><br>-- <br><div dir="ltr" class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>