mirror of https://github.com/python/cpython
#1330538: Improve comparison of xmlrpclib.DateTime and datetime instances.
Remove automatic handling of datetime.date and datetime.time. This breaks backward compatibility, but python-dev discussion was strongly against this automatic conversion; see the bug for a link.
This commit is contained in:
parent
8328bbc57d
commit
085f75a851
|
@ -34,10 +34,7 @@ between conformable Python objects and XML on the wire.
|
|||
all clients and servers; see http://ontosys.com/xml-rpc/extensions.php for a
|
||||
description. The *use_datetime* flag can be used to cause date/time values to
|
||||
be presented as :class:`datetime.datetime` objects; this is false by default.
|
||||
:class:`datetime.datetime`, :class:`datetime.date` and :class:`datetime.time`
|
||||
objects may be passed to calls. :class:`datetime.date` objects are converted
|
||||
with a time of "00:00:00". :class:`datetime.time` objects are converted using
|
||||
today's date.
|
||||
:class:`datetime.datetime` objects may be passed to calls.
|
||||
|
||||
Both the HTTP and HTTPS transports support the URL syntax extension for HTTP
|
||||
Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass``
|
||||
|
@ -81,9 +78,7 @@ between conformable Python objects and XML on the wire.
|
|||
+---------------------------------+---------------------------------------------+
|
||||
| :const:`dates` | in seconds since the epoch (pass in an |
|
||||
| | instance of the :class:`DateTime` class) or |
|
||||
| | a :class:`datetime.datetime`, |
|
||||
| | :class:`datetime.date` or |
|
||||
| | :class:`datetime.time` instance |
|
||||
| | a :class:`datetime.datetime` instance. |
|
||||
+---------------------------------+---------------------------------------------+
|
||||
| :const:`binary data` | pass in an instance of the :class:`Binary` |
|
||||
| | wrapper class |
|
||||
|
@ -221,10 +216,10 @@ The client code for the preceding server::
|
|||
DateTime Objects
|
||||
----------------
|
||||
|
||||
This class may be initialized with seconds since the epoch, a time tuple, an ISO
|
||||
8601 time/date string, or a :class:`datetime.datetime`, :class:`datetime.date`
|
||||
or :class:`datetime.time` instance. It has the following methods, supported
|
||||
mainly for internal use by the marshalling/unmarshalling code:
|
||||
This class may be initialized with seconds since the epoch, a time
|
||||
tuple, an ISO 8601 time/date string, or a :class:`datetime.datetime`
|
||||
instance. It has the following methods, supported mainly for internal
|
||||
use by the marshalling/unmarshalling code:
|
||||
|
||||
|
||||
.. method:: DateTime.decode(string)
|
||||
|
@ -507,10 +502,7 @@ Convenience Functions
|
|||
``None`` if no method name is present in the packet. If the XML-RPC packet
|
||||
represents a fault condition, this function will raise a :exc:`Fault` exception.
|
||||
The *use_datetime* flag can be used to cause date/time values to be presented as
|
||||
:class:`datetime.datetime` objects; this is false by default. Note that even if
|
||||
you call an XML-RPC method with :class:`datetime.date` or :class:`datetime.time`
|
||||
objects, they are converted to :class:`DateTime` objects internally, so only
|
||||
:class:`datetime.datetime` objects will be returned.
|
||||
:class:`datetime.datetime` objects; this is false by default.
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
The *use_datetime* flag was added.
|
||||
|
|
|
@ -1511,6 +1511,15 @@ code:
|
|||
|
||||
.. Issue 1706815
|
||||
|
||||
* The :mod:`xmlrpclib` module no longer automatically converts
|
||||
:class:`datetime.date` and :class:`datetime.time` to the
|
||||
:class:`xmlrpclib.DateTime` type; the conversion semantics were
|
||||
not necessarily correct for all applications. Code using
|
||||
:mod:`xmlrpclib` should convert :class:`date` and :class:`time`
|
||||
instances.
|
||||
|
||||
.. Issue 1330538
|
||||
|
||||
.. ======================================================================
|
||||
|
||||
|
||||
|
|
|
@ -33,10 +33,6 @@ alist = [{'astring': 'foo@bar.baz.spam',
|
|||
(2005, 02, 10, 11, 41, 23, 0, 1, -1)),
|
||||
'datetime3': xmlrpclib.DateTime(
|
||||
datetime.datetime(2005, 02, 10, 11, 41, 23)),
|
||||
'datetime4': xmlrpclib.DateTime(
|
||||
datetime.date(2005, 02, 10)),
|
||||
'datetime5': xmlrpclib.DateTime(
|
||||
datetime.time(11, 41, 23)),
|
||||
}]
|
||||
|
||||
class XMLRPCTestCase(unittest.TestCase):
|
||||
|
@ -59,34 +55,14 @@ class XMLRPCTestCase(unittest.TestCase):
|
|||
(newdt,), m = xmlrpclib.loads(s, use_datetime=0)
|
||||
self.assertEquals(newdt, xmlrpclib.DateTime('20050210T11:41:23'))
|
||||
|
||||
def test_dump_bare_date(self):
|
||||
# This checks that an unwrapped datetime.date object can be handled
|
||||
# by the marshalling code. This can't be done via test_dump_load()
|
||||
# since the unmarshaller produces a datetime object
|
||||
d = datetime.datetime(2005, 02, 10, 11, 41, 23).date()
|
||||
s = xmlrpclib.dumps((d,))
|
||||
(newd,), m = xmlrpclib.loads(s, use_datetime=1)
|
||||
self.assertEquals(newd.date(), d)
|
||||
self.assertEquals(newd.time(), datetime.time(0, 0, 0))
|
||||
self.assertEquals(m, None)
|
||||
|
||||
(newdt,), m = xmlrpclib.loads(s, use_datetime=0)
|
||||
self.assertEquals(newdt, xmlrpclib.DateTime('20050210T00:00:00'))
|
||||
|
||||
def test_dump_bare_time(self):
|
||||
# This checks that an unwrapped datetime.time object can be handled
|
||||
# by the marshalling code. This can't be done via test_dump_load()
|
||||
# since the unmarshaller produces a datetime object
|
||||
t = datetime.datetime(2005, 02, 10, 11, 41, 23).time()
|
||||
s = xmlrpclib.dumps((t,))
|
||||
(newt,), m = xmlrpclib.loads(s, use_datetime=1)
|
||||
today = datetime.datetime.now().date().strftime("%Y%m%d")
|
||||
self.assertEquals(newt.time(), t)
|
||||
self.assertEquals(newt.date(), datetime.datetime.now().date())
|
||||
self.assertEquals(m, None)
|
||||
|
||||
(newdt,), m = xmlrpclib.loads(s, use_datetime=0)
|
||||
self.assertEquals(newdt, xmlrpclib.DateTime('%sT11:41:23'%today))
|
||||
def test_cmp_datetime_DateTime(self):
|
||||
now = datetime.datetime.now()
|
||||
dt = xmlrpclib.DateTime(now.timetuple())
|
||||
self.assert_(dt == now)
|
||||
self.assert_(now == dt)
|
||||
then = now + datetime.timedelta(seconds=4)
|
||||
self.assert_(then >= dt)
|
||||
self.assert_(dt < then)
|
||||
|
||||
def test_bug_1164912 (self):
|
||||
d = xmlrpclib.DateTime()
|
||||
|
@ -242,21 +218,6 @@ class DateTimeTestCase(unittest.TestCase):
|
|||
t = xmlrpclib.DateTime(d)
|
||||
self.assertEqual(str(t), '20070102T03:04:05')
|
||||
|
||||
def test_datetime_date(self):
|
||||
d = datetime.date(2007,9,8)
|
||||
t = xmlrpclib.DateTime(d)
|
||||
self.assertEqual(str(t), '20070908T00:00:00')
|
||||
|
||||
def test_datetime_time(self):
|
||||
d = datetime.time(13,17,19)
|
||||
# allow for date rollover by checking today's or tomorrow's dates
|
||||
dd1 = datetime.datetime.now().date()
|
||||
dd2 = dd1 + datetime.timedelta(days=1)
|
||||
vals = (dd1.strftime('%Y%m%dT13:17:19'),
|
||||
dd2.strftime('%Y%m%dT13:17:19'))
|
||||
t = xmlrpclib.DateTime(d)
|
||||
self.assertEqual(str(t) in vals, True)
|
||||
|
||||
def test_repr(self):
|
||||
d = datetime.datetime(2007,1,2,3,4,5)
|
||||
t = xmlrpclib.DateTime(d)
|
||||
|
|
|
@ -357,13 +357,6 @@ class DateTime:
|
|||
if datetime and isinstance(value, datetime.datetime):
|
||||
self.value = value.strftime("%Y%m%dT%H:%M:%S")
|
||||
return
|
||||
if datetime and isinstance(value, datetime.date):
|
||||
self.value = value.strftime("%Y%m%dT%H:%M:%S")
|
||||
return
|
||||
if datetime and isinstance(value, datetime.time):
|
||||
today = datetime.datetime.now().strftime("%Y%m%d")
|
||||
self.value = value.strftime(today+"T%H:%M:%S")
|
||||
return
|
||||
if not isinstance(value, (TupleType, time.struct_time)):
|
||||
if value == 0:
|
||||
value = time.time()
|
||||
|
@ -371,10 +364,57 @@ class DateTime:
|
|||
value = time.strftime("%Y%m%dT%H:%M:%S", value)
|
||||
self.value = value
|
||||
|
||||
def __cmp__(self, other):
|
||||
def make_comparable(self, other):
|
||||
if isinstance(other, DateTime):
|
||||
other = other.value
|
||||
return cmp(self.value, other)
|
||||
s = self.value
|
||||
o = other.value
|
||||
elif datetime and isinstance(other, datetime.datetime):
|
||||
s = self.value
|
||||
o = other.strftime("%Y%m%dT%H:%M:%S")
|
||||
elif isinstance(other, (str, unicode)):
|
||||
s = self.value
|
||||
o = other
|
||||
elif hasattr(other, "timetuple"):
|
||||
s = self.timetuple()
|
||||
o = other.timetuple()
|
||||
else:
|
||||
otype = (hasattr(other, "__class__")
|
||||
and other.__class__.__name__
|
||||
or type(other))
|
||||
raise TypeError("Can't compare %s and %s" %
|
||||
(self.__class__.__name__, otype))
|
||||
return s, o
|
||||
|
||||
def __lt__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s < o
|
||||
|
||||
def __le__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s <= o
|
||||
|
||||
def __gt__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s > o
|
||||
|
||||
def __ge__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s >= o
|
||||
|
||||
def __eq__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s == o
|
||||
|
||||
def __ne__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return s != o
|
||||
|
||||
def timetuple(self):
|
||||
return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
|
||||
|
||||
def __cmp__(self, other):
|
||||
s, o = self.make_comparable(other)
|
||||
return cmp(s, o)
|
||||
|
||||
##
|
||||
# Get date/time value.
|
||||
|
@ -736,19 +776,6 @@ class Marshaller:
|
|||
write("</dateTime.iso8601></value>\n")
|
||||
dispatch[datetime.datetime] = dump_datetime
|
||||
|
||||
def dump_date(self, value, write):
|
||||
write("<value><dateTime.iso8601>")
|
||||
write(value.strftime("%Y%m%dT00:00:00"))
|
||||
write("</dateTime.iso8601></value>\n")
|
||||
dispatch[datetime.date] = dump_date
|
||||
|
||||
def dump_time(self, value, write):
|
||||
write("<value><dateTime.iso8601>")
|
||||
write(datetime.datetime.now().date().strftime("%Y%m%dT"))
|
||||
write(value.strftime("%H:%M:%S"))
|
||||
write("</dateTime.iso8601></value>\n")
|
||||
dispatch[datetime.time] = dump_time
|
||||
|
||||
def dump_instance(self, value, write):
|
||||
# check for special wrappers
|
||||
if value.__class__ in WRAPPERS:
|
||||
|
|
Loading…
Reference in New Issue