This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Deprecate use of more than 3 positional arguments in timedelta constructor
Type: enhancement Stage: test needed
Components: Versions: Python 3.2
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: belopolsky Nosy List: belopolsky, mark.dickinson, pitrou, tim.peters
Priority: low Keywords:

Created on 2010-07-05 17:07 by belopolsky, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (6)
msg109339 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-07-05 17:07
Prior to r82454, python implementation of timedelta had the following comment:

class timedelta:
     def __new__(cls, days=0, seconds=0, microseconds=0,
                 # XXX The following should only be used as keyword args:	 
                 milliseconds=0, minutes=0, hours=0, weeks=0):


This suggests that these arguments were intended to be keyword only, but at the time there was no language support for that.

In 3.x, the above can be rewritten as

class timedelta:
     def __new__(cls, days=0, seconds=0, microseconds=0, *,
                 milliseconds=0, minutes=0, hours=0, weeks=0):

to require that milliseconds, minutes, etc, be used only positionally.

This would be a backward incompatible change, so it would need to go through a deprecation process, but I think someone writing

HOUR = timedelta(0, 0, 0, 0, 0, 1)

or

WEEK = timedelta(0, 0, 0, 0, 0, 0, 1)

deserves a deprecation warning.
msg109341 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-07-05 17:39
> This would be a backward incompatible change, so it would need to go
> through a deprecation process, but I think someone writing
> 
> HOUR = timedelta(0, 0, 0, 0, 0, 1)
> 
> or
> 
> WEEK = timedelta(0, 0, 0, 0, 0, 0, 1)
> 
> deserves a deprecation warning.

-1 from me. Deprecating correct code should be done for serious reasons,
not aesthetical (i.e. gratuitous) ones.
msg109345 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-07-05 18:16
On Mon, Jul 5, 2010 at 1:39 PM, Antoine Pitrou <report@bugs.python.org> wrote:
..
> -1 from me. Deprecating correct code should be done for serious
> reasons, not aesthetical (i.e. gratuitous) ones.

I would think that deprecating error-prone constructs is well within normal library evolution.  For example, several interfaces that accepted floats by truncating them to ints were deprecated in the past.

PS: "aesthetical" != "gratuitous"

Someone using more than 3 positional arguments to timedelta most likely  expects

timedelta(days, hours, minutes, seconds, microseconds)

rather than

timedelta(days, seconds, microseconds, milliseconds, minutes, ...)

Has anyone seen (non-buggy) code in the wild that used > 3 positional arguments to timedelta?  (Mark just asked me not to use 2!)
msg109362 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-07-05 23:38
> I would think that deprecating error-prone constructs is well within
> normal library evolution.  For example, several interfaces that
> accepted floats by truncating them to ints were deprecated in the
> past.

That's because silent truncation to int will lead to possible loss of
precision, or (worse) to poorly defined behaviour.
For example, if you call file.read(3.5), should it try to read 3 bytes
or 4 bytes? Deprecating such use is perfectly reasonable, because it
disambiguizes the API and avoids the use of a wrong type.

On the other hand, using positional arguments presents none of these
problems. There is no reason to deprecate it except your own aesthetical
preferences. Therefore I'm still -1.

> Has anyone seen (non-buggy) code in the wild that used > 3 positional
> arguments to timedelta?

Why do you think such code doesn't exist? It's not like timedelta() is
an extremely difficult API to use, even without keyword arguments.
Using Google Code Search, you will find snippets such as:

FIVE_MINUTES =  datetime.timedelta(0, 0, 0, 0, 5)
msg109391 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-07-06 14:03
I supported this idea when Alexander brought it up in IRC.  On reflection, I think Antoine is right, though:  deprecations aren't something to be done lightly.

As a matter of good style, though, I'd still like to see all uses of timedelta in the standard library and documentation use the keywords explicitly: "timedelta(minutes=10)" is instantly understandable, while "timedelta(0, 0, 0, 0, 10)" requires some effort to understand (well, on my part, anyway).
msg109393 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-07-06 14:28
> As a matter of good style, though, I'd still like to see all uses of
> timedelta in the standard library and documentation use the keywords
> explicitly ...

It is a bit of a shame, but there are exactly 3 places using timedelta in stdlib:

Lib/_strptime.py:492:        tzdelta = datetime_timedelta(seconds=gmtoff)
Lib/calendar.py:160:        date -= datetime.timedelta(days=days)
Lib/calendar.py:161:        oneday = datetime.timedelta(days=1)


The later two uses of keywords I don't necessarily approve, particularly timedelta(days=days).  I find timedelta(n) meaning n days fairly easy to remember.  Two arguments, timedelta(days, secs) is borderline.  I would approve it if the meaning is clear from context as in

MINUTE = timedelta(0, 60)

or from the the argument name as in timedelta(0, seconds).

I would certainly reject the abominations like

FIVE_MINUTES =  datetime.timedelta(0, 0, 0, 0, 5)

in any code review.

I checked datetime.rst and it looks like it only uses positional arguments for timedelta(0), which is pretty uncontroversial and in output displays.
History
Date User Action Args
2022-04-11 14:57:03adminsetgithub: 53415
2010-07-13 22:35:53belopolskysetstatus: open -> closed
2010-07-06 14:28:58belopolskysetstatus: pending -> open

messages: + msg109393
2010-07-06 14:03:45mark.dickinsonsetstatus: open -> pending
2010-07-06 14:03:21mark.dickinsonsetstatus: pending -> open

messages: + msg109391
2010-07-06 13:35:41belopolskysetstatus: open -> pending
priority: normal -> low
resolution: rejected
2010-07-05 23:38:56pitrousetmessages: + msg109362
2010-07-05 18:16:31belopolskysetmessages: + msg109345
2010-07-05 17:39:21pitrousetmessages: + msg109341
2010-07-05 17:07:28belopolskycreate