Modify

Ticket #14 (closed defect: fixed)

Opened 8 years ago

Last modified 8 years ago

Inf and NaN handling needs re-vamp

Reported by: Scott David Daniels <Scott.Daniels@…> Owned by: xi
Priority: normal Component: pyyaml
Severity: normal Keywords:
Cc:

Description (last modified by xi) (diff)

Trying to import YAML fails in Python 2.5. Even simple patches fail, because the root cause is that NaNs and INFs cannot be marshalled/unmarshalled. Marshalling is used to save and restore compiled python modules, so a tested module can work initially, but later fail to load (when not from source).

When handling INFs and NaNs, you need to be careful. 1e300000 is not a safe way to represent infinity, and fails to pickle/unpickle safely from manifest constants. Different C runtimes represent the text for INFs and NaNs differently. Since Python 2.5 folds constants, a simple expression won't solve the problem.

The following changes should allow yaml to work on python 2.5a2 on Win2000 (and I think for 64-bit machines as well):

=============== constructor.py: ===============

*** 231,239 ****
          else:
              return sign*int(value)

-     inf_value = 1e300000
-     nan_value = inf_value/inf_value
-
      def construct_yaml_float(self, node):
          value = str(self.construct_scalar(node))
          value = value.replace('_', '')
--- 231,236 ----
***************
***************
*** 242,251 ****
              sign = -1
          if value[0] in '+-':
              value = value[1:]
!         if value.lower() == '.inf':
!             return sign*self.inf_value
!         elif value.lower() == '.nan':
!             return self.nan_value
          elif ':' in value:
              digits = [float(part) for part in value.split(':')]
              digits.reverse()
--- 239,253 ----
              sign = -1
          if value[0] in '+-':
              value = value[1:]
!         if value.lower() in ('.inf', '.nan'):
!             big = 1e300
!             bigger = big * big
!             while bigger > big and bigger == bigger:
!                 big = bigger
!                 bigger = big * big
!             if value.lower() == '.nan':
!                 return bigger / bigger
!             return sign * bigger
          elif ':' in value:
              digits = [float(part) for part in value.split(':')]
              digits.reverse()

=============== representer.py: ===============

*** 192,200 ****
      def represent_long(self, data):
          return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))

!     repr_pos_inf = repr(1e300000)
!     repr_neg_inf = repr(-1e300000)
!     repr_nan = repr(1e300000/1e300000)

      def represent_float(self, data):
          repr_data = repr(data)
--- 192,206 ----
      def represent_long(self, data):
          return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))

!     big = 1e300
!     bigger = big * big
!     while bigger > big and bigger == bigger:
!         big = bigger
!         bigger = big * big
!     repr_pos_inf = repr(bigger)
!     repr_neg_inf = repr(-bigger)
!     repr_nan = repr(bigger / bigger)
!     del big, bigger

      def represent_float(self, data):
          repr_data = repr(data)

Attachments

Change History

comment:1 Changed 8 years ago by xi

  • Status changed from new to closed
  • Resolution set to fixed
  • Description modified (diff)

Strange, it works for me under Python 2.5a2 on Linux and marshal dumps and loads inf/nan values correctly. Probably it's a win32 issue.

Anyway I've applied a modified version of your patch ([168]). I assume it fixes the problem, so I'm closing the ticket. Could you check in on your PC and reopen it if it still fails?

Thanks for the patch.

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
The resolution will be deleted. Next status will be 'reopened'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.