Skip to content

Commit

Permalink
Use expected XSD spellings for xsi:double infinity and NaN (GH-338)
Browse files Browse the repository at this point in the history
W3C specification for xsd:double says
> The special values positive and negative infinity and
> not-a-number have lexical representations INF, -INF and NaN,
> respectively.

Thus case matters. The previously used float.__repr__ would generate
"inf", "-inf", "nan". Now we prepend special handling to get
"INF", "-INF", "NaN" instead (which is still pytype compatible).

Includes minor non-functional alignments of related bool to text code,
and tests to assert its XML schema conformance as well.
  • Loading branch information
haxtibal committed Feb 13, 2022
1 parent 1e36660 commit f7bb07b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
20 changes: 16 additions & 4 deletions src/lxml/objectify.pyx
Expand Up @@ -38,6 +38,9 @@ import_lxml__etree()

__version__ = etree.__version__

cdef object _float_is_inf, _float_is_nan
from math import isinf as _float_is_inf, isnan as _float_is_nan

cdef object re
import re

Expand Down Expand Up @@ -1205,8 +1208,17 @@ cdef dict _PYTYPE_DICT = {}
cdef dict _SCHEMA_TYPE_DICT = {}
cdef list _TYPE_CHECKS = []

cdef unicode _lower_bool(b):
return u"true" if b else u"false"
cdef unicode _xml_bool(value):
return u"true" if value else u"false"

cdef unicode _xml_float(value):
if _float_is_inf(value):
if value > 0:
return u"INF"
return u"-INF"
if _float_is_nan(value):
return u"NaN"
return unicode(repr(value))

cdef _pytypename(obj):
return u"str" if python._isString(obj) else _typename(obj)
Expand All @@ -1230,11 +1242,11 @@ cdef _registerPyTypes():
pytype = PyType(u'long', None, IntElement)
pytype.register()

pytype = PyType(u'float', _checkFloat, FloatElement, repr) # wraps _parseFloat for Python
pytype = PyType(u'float', _checkFloat, FloatElement, _xml_float) # wraps functions for Python
pytype.xmlSchemaTypes = (u"double", u"float")
pytype.register()

pytype = PyType(u'bool', _checkBool, BoolElement, _lower_bool) # wraps functions for Python
pytype = PyType(u'bool', _checkBool, BoolElement, _xml_bool) # wraps functions for Python
pytype.xmlSchemaTypes = (u"boolean",)
pytype.register()

Expand Down
9 changes: 9 additions & 0 deletions src/lxml/tests/test_objectify.py
Expand Up @@ -873,6 +873,10 @@ def test_data_element_bool(self):
self.assertTrue(isinstance(value, objectify.BoolElement))
self.assertEqual(value, False)

def test_data_element_bool_text(self):
self.assertEqual(objectify.DataElement(False).text, "false")
self.assertEqual(objectify.DataElement(True).text, "true")

def test_type_str(self):
Element = self.Element
SubElement = self.etree.SubElement
Expand Down Expand Up @@ -1115,6 +1119,11 @@ def test_data_element_float_hash_repr(self):
value = objectify.DataElement(f)
self.assertEqual(hash(value), hash(f))

def test_data_element_float_special_value_text(self):
self.assertEqual(objectify.DataElement(float("inf")).text, "INF")
self.assertEqual(objectify.DataElement(float("-inf")).text, "-INF")
self.assertEqual(objectify.DataElement(float("nan")).text, "NaN")

def test_data_element_xsitypes(self):
for xsi, objclass in xsitype2objclass.items():
# 1 is a valid value for all ObjectifiedDataElement classes
Expand Down

0 comments on commit f7bb07b

Please sign in to comment.