summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolger Joukl <holger.joukl@gmx.de>2016-04-08 09:11:18 +0200
committerHolger Joukl <holger.joukl@gmx.de>2016-04-08 09:11:18 +0200
commite70558389119316f9733711a515d247fc8aa0347 (patch)
treed820c30edecad53f8a069cad4e7f8a5ba8600089
parentaedf10b01d281ae79f06c4931778d2f47824f379 (diff)
downloadpython-lxml-e70558389119316f9733711a515d247fc8aa0347.tar.gz
Fix losing float precision for lxml.objectify FloatElement.
Use repr() instead of str()/unicode() as 'stringification' function in the FloatElement type registration.
-rw-r--r--src/lxml/lxml.objectify.pyx15
-rw-r--r--src/lxml/tests/test_objectify.py44
2 files changed, 53 insertions, 6 deletions
diff --git a/src/lxml/lxml.objectify.pyx b/src/lxml/lxml.objectify.pyx
index 371eb2c5..d79fcd82 100644
--- a/src/lxml/lxml.objectify.pyx
+++ b/src/lxml/lxml.objectify.pyx
@@ -896,11 +896,14 @@ cdef class PyType:
u"""PyType(self, name, type_check, type_class, stringify=None)
User defined type.
- Named type that contains a type check function and a type class that
- inherits from ObjectifiedDataElement. The type check must take a string
- as argument and raise ValueError or TypeError if it cannot handle the
- string value. It may be None in which case it is not considered for type
- guessing.
+ Named type that contains a type check function, a type class that
+ inherits from ObjectifiedDataElement and an optional "stringification"
+ function. The type check must take a string as argument and raise
+ ValueError or TypeError if it cannot handle the string value. It may be
+ None in which case it is not considered for type guessing. For registered
+ named types, the 'stringify' function (or unicode() if None) is used to
+ convert a Python object with type name 'name' to the string representation
+ stored in the XML tree.
Example::
@@ -1031,7 +1034,7 @@ cdef _registerPyTypes():
pytype = PyType(u'long', None, IntElement)
pytype.register()
- pytype = PyType(u'float', float, FloatElement)
+ pytype = PyType(u'float', float, FloatElement, repr)
pytype.xmlSchemaTypes = (u"double", u"float")
pytype.register()
diff --git a/src/lxml/tests/test_objectify.py b/src/lxml/tests/test_objectify.py
index b17e38c2..68b9d7a8 100644
--- a/src/lxml/tests/test_objectify.py
+++ b/src/lxml/tests/test_objectify.py
@@ -1016,6 +1016,50 @@ class ObjectifyTestCase(HelperTestCase):
value = objectify.DataElement(5.5)
self.assertEqual(hash(value), hash(5.5))
+ def test_type_float_precision(self):
+ # test not losing precision by shortened float str() value
+ # repr(2.305064300557): '2.305064300557'
+ # str(2.305064300557): '2.30506430056'
+ # "%57.54f" % 2.305064300557:
+ # ' 2.305064300556999956626214043353684246540069580078125000'
+ Element = self.Element
+ root = Element("{objectified}root")
+ s = "2.305064300557"
+ root.f = float(s)
+ self.assertTrue(isinstance(root.f, objectify.FloatElement))
+ self.assertEqual(root.f.text, s)
+ self.assertEqual(root.f.pyval, float(s))
+
+ def test_type_float_instantiation_precision(self):
+ # test precision preservation for FloatElement instantiation
+ s = "2.305064300557"
+ self.assertEqual(objectify.FloatElement(s), float(s))
+
+ def test_type_float_precision_consistency(self):
+ # test consistent FloatElement values for the different instantiation
+ # possibilities
+ Element = self.Element
+ root = Element("{objectified}root")
+ s = "2.305064300557"
+ f = float(s)
+ float_elem = objectify.FloatElement(s)
+ float_data_elem = objectify.DataElement(f)
+ root.float_child = float(f)
+ self.assertTrue(f == float_elem == float_data_elem == root.float_child)
+
+ def test_data_element_float_precision(self):
+ # test not losing precision by shortened float str() value
+ f = 2305064300557.0
+ value = objectify.DataElement(f)
+ self.assertTrue(isinstance(value, objectify.FloatElement))
+ self.assertEqual(value, f)
+
+ def test_data_element_float_hash_repr(self):
+ # test not losing precision by shortened float str() value
+ f = 2305064300557.0
+ value = objectify.DataElement(f)
+ self.assertEqual(hash(value), hash(f))
+
def test_data_element_xsitypes(self):
for xsi, objclass in xsitype2objclass.items():
# 1 is a valid value for all ObjectifiedDataElement classes