More puzzling behavior while subclassing datetime

Discussion in 'Python' started by insyte@gmail.com, Nov 16, 2006.

  1. Guest

    With assistance from Gabriel and Frederik (and a few old threads in
    c.l.p.) I've been making headway on my specialized datetime class. Now
    I'm puzzled by behavior I didn't expect while attempting to use some of
    the alternate datetime constructors. Specifically, it appears if I
    call GeneralizedTime.now() it calls the __new__ method of my class but
    treats keyword arguments as if they were positional.

    My class:

    class GeneralizedTime(datetime):
    def __new__(cls, time=None, *args, **kwargs):
    print time, args, kwargs
    if isinstance(time, str):
    timeValues, tzOffset = cls.stringToTimeTuple(time)
    return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    **timeValues)
    elif isinstance(time, datetime):
    timeValues = time.timetuple()[:6]
    tzOffset = time.utcoffset()
    return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    *timeValues)
    elif time is None:
    print "Still gotta figure out now to do this one..."
    else:
    raise Invalidtime(time)
    @staticmethod
    def stringToTimeTuple(timeString):
    ... regex that parses timeString ...

    >>> GeneralizedTime.today()

    2006 (11, 16, 0, 35, 18, 747275, None) {}
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "gentime.py", line 106, in __new__
    raise InvalidTime(time)
    gentime.InvalidTime: 2006

    So it appears the time tuple is being passed to
    GeneralizedTime.__new__, but the first value is being assigned to the
    "time" argument.

    Is this a side effect of how datetime is implemented? Or am I doing
    something screwy?

    Thanks!

    -Ben
    , Nov 16, 2006
    #1
    1. Advertising

  2. Guest

    wrote:
    > With assistance from Gabriel and Frederik (and a few old threads in
    > c.l.p.) I've been making headway on my specialized datetime class. Now
    > I'm puzzled by behavior I didn't expect while attempting to use some of
    > the alternate datetime constructors. Specifically, it appears if I
    > call GeneralizedTime.now() it calls the __new__ method of my class but
    > treats keyword arguments as if they were positional.
    >
    > My class:
    >
    > class GeneralizedTime(datetime):
    > def __new__(cls, time=None, *args, **kwargs):

    datetime.datetime() takes these arguments: year, month, day[, hour[,
    minute[, second[, microsecond[, tzinfo]]]]]), see
    http://docs.python.org/lib/datetime-datetime.html
    > print time, args, kwargs
    > if isinstance(time, str):
    > timeValues, tzOffset = cls.stringToTimeTuple(time)
    > return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    > **timeValues)
    > elif isinstance(time, datetime):
    > timeValues = time.timetuple()[:6]

    time.timetuple() does not exist, see
    http://docs.python.org/lib/module-time.html, time is represented as a
    tuple. checkout time.mktime() on how to convert to a tuple to a time
    > tzOffset = time.utcoffset()
    > return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    > *timeValues)
    > elif time is None:
    > print "Still gotta figure out now to do this one..."
    > else:
    > raise Invalidtime(time)
    > @staticmethod
    > def stringToTimeTuple(timeString):
    > ... regex that parses timeString ...
    >
    > >>> GeneralizedTime.today()

    > 2006 (11, 16, 0, 35, 18, 747275, None) {}
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > File "gentime.py", line 106, in __new__
    > raise InvalidTime(time)
    > gentime.InvalidTime: 2006
    >
    > So it appears the time tuple is being passed to
    > GeneralizedTime.__new__, but the first value is being assigned to the
    > "time" argument.
    >
    > Is this a side effect of how datetime is implemented? Or am I doing
    > something screwy?
    >
    > Thanks!
    >
    > -Ben


    A very cutback part of your code gets the basics working:
    from datetime import datetime
    class Invalidtime(Exception):
    pass

    class GeneralizedTime(datetime):
    def __new__(cls, *args, **kwargs):
    if isinstance(args, tuple):
    return datetime.__new__(cls, *args)
    else:
    raise Invalidtime(args)

    t = GeneralizedTime.today()
    print t.year
    print t.month
    print t.day
    print t.hour
    print t.minute
    print t.second
    print t.microsecond
    print t.tzinfo
    , Nov 16, 2006
    #2
    1. Advertising

  3. Peter Otten Guest

    wrote:

    > With assistance from Gabriel and Frederik (and a few old threads in
    > c.l.p.) I've been making headway on my specialized datetime class. Now
    > I'm puzzled by behavior I didn't expect while attempting to use some of
    > the alternate datetime constructors. Specifically, it appears if I
    > call GeneralizedTime.now() it calls the __new__ method of my class but
    > treats keyword arguments as if they were positional.
    >
    > My class:
    >
    > class GeneralizedTime(datetime):
    > def __new__(cls, time=None, *args, **kwargs):
    > print time, args, kwargs
    > if isinstance(time, str):
    > timeValues, tzOffset = cls.stringToTimeTuple(time)
    > return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    > **timeValues)
    > elif isinstance(time, datetime):
    > timeValues = time.timetuple()[:6]
    > tzOffset = time.utcoffset()
    > return datetime.__new__(cls, tzinfo=GenericTZ(tzOffset),
    > *timeValues)
    > elif time is None:
    > print "Still gotta figure out now to do this one..."
    > else:
    > raise Invalidtime(time)
    > @staticmethod
    > def stringToTimeTuple(timeString):
    > ... regex that parses timeString ...
    >
    >>>> GeneralizedTime.today()

    > 2006 (11, 16, 0, 35, 18, 747275, None) {}
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > File "gentime.py", line 106, in __new__
    > raise InvalidTime(time)
    > gentime.InvalidTime: 2006
    >
    > So it appears the time tuple is being passed to
    > GeneralizedTime.__new__, but the first value is being assigned to the
    > "time" argument.
    >
    > Is this a side effect of how datetime is implemented?


    Yes. Consider:

    >>> def today(time=None, *args):

    .... print "time = ", time, "args = ", args
    ....
    >>> today(2006, 11, 16)

    time = 2006 args = (11, 16)

    To fix the issue you'll probably have to remove the time=None parameter from
    GeneralizedTime.__new__() and instead extract it from args or kwargs.

    Peter
    Peter Otten, Nov 16, 2006
    #3
  4. Guest

    > Yes. Consider:
    >
    > >>> def today(time=None, *args):

    > ... print "time = ", time, "args = ", args
    > ...
    > >>> today(2006, 11, 16)

    > time = 2006 args = (11, 16)
    >
    > To fix the issue you'll probably have to remove the time=None parameter from
    > GeneralizedTime.__new__() and instead extract it from args or kwargs.


    D'oh. That *should* have been obvious.

    I am now no longer allowed to program after midnight.

    Thanks!

    -Ben
    , Nov 16, 2006
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Christos TZOTZIOY Georgiou
    Replies:
    3
    Views:
    691
    Christos TZOTZIOY Georgiou
    Sep 13, 2003
  2. Tim Peters
    Replies:
    0
    Views:
    524
    Tim Peters
    Sep 9, 2003
  3. mp
    Replies:
    1
    Views:
    377
    John Machin
    Jul 28, 2006
  4. Martin
    Replies:
    0
    Views:
    329
    Martin
    Dec 27, 2008
  5. Replies:
    2
    Views:
    744
    M.-A. Lemburg
    Jan 6, 2009
Loading...

Share This Page