def FloatCompare(a, b): a = float(a or 0) b = float(b or 0) # NaN seems to always equal everything else, so we'll do it ourselves # the IEEE definition of NaN makes it the largest possible number if number.isnan(a): if number.isnan(b): return 0 else: return -1 elif number.isnan(b): return 1 return cmp(a, b)
def f(a, b): if number.isnan(b): return b elif a > b: return a else: return b
def Substring(context, st, start, length=None): """Function: <string> substring(<string>, <number>, <number>?)""" if not isinstance(st, XPathStringType): st = Conversions.StringValue(st) if not isinstance(start, NumberType): start = Conversions.NumberValue(start) # start == NaN: spec doesn't say; assume no substring to return # start == +Inf or -Inf: no substring to return if number.isnan(start) or number.isinf(start): return u'' # start is finite, safe for int() and round(). start = int(round(start)) # convert to 0-based index for python string slice if start < 1: startidx = 0 else: startidx = start - 1 # length undefined: return chars startidx to end if length is None: return st[startidx:] elif not isinstance(length, NumberType): length = Conversions.NumberValue(length) # length == NaN: spec doesn't say; assume no substring to return if number.isnan(length): return u'' # length == +Inf: return chars startidx to end # length == -Inf: no substring to return elif number.isinf(length): if length > 0: return st[startidx:] else: return u'' # length is finite, safe for int() and round(). length = int(round(length)) # return value must end before position (start+length) # which is (start+length-1) in 0-based index endidx = start + length - 1 if endidx > startidx: return st[startidx:endidx] else: return u''
def Round(context, object_): """Function: <number> round(<number>)""" num = Conversions.NumberValue(object_) if number.isnan(num) or number.isinf(num): return num elif num < 0 and num % 1.0 == 0.5: return round(num, 0) + 1 else: return round(num, 0)
def __repr__(self): if number.isnan(self._literal): return 'NaN' elif number.isinf(self._literal): if self._literal < 0: return '-Infinity' else: return 'Infinity' else: return str(self._nliteral)
def Floor(context, object_): """Function: <number> floor(<number>)""" num = Conversions.NumberValue(object_) if number.isnan(num) or number.isinf(num): return num elif int(num) == num: return num elif num < 0: return float(int(num) - 1) else: return float(int(num))
def Ceiling(context, object_): """Function: <number> ceiling(<number>)""" num = Conversions.NumberValue(object_) if number.isnan(num) or number.isinf(num): return num elif int(num) == num: return num elif num > 0: return float(int(num) + 1) else: return float(int(num))
def _strFloat(float): if number.finite(float): if float == round(float): return unicode(str(long(float))) else: # 12 digits is how many Python uses for str() return u'%0.12g' % float elif number.isnan(float): return u'NaN' elif float < 0: return u'-Infinity' else: return u'Infinity'
def Sqrt(context, num): """ The math:sqrt function returns the square root of a number. """ # The platform C library determines what math.sqrt() returns. # On some platforms, especially prior to Python 2.4, # nan may be returned for a negative or nan argument. # On other platforms, and especially since Python 2.4, # a ValueError is raised. # # EXSLT requires that we return zero for negative arg. # The result for a nan arg is undefined, but we'll return nan. n = Conversions.NumberValue(num) if number.isnan(n): return number.nan if n < 0.0: return 0.0 try: return math.sqrt(Conversions.NumberValue(num)) except ValueError: return 0.0
def Lowest(context, nodeset): """ The math:lowest function returns the nodes in the node set whose value is the minimum value for the node set. The minimum value for the node set is the same as the value as calculated by math:min. A node has this minimum value if the result of converting its string value to a number as if by the number function is equal to the minimum value, where the equality comparison is defined as a numerical comparison using the = operator. """ if type(nodeset) != type([]): raise XsltRuntimeException(Error.WRONG_ARGUMENT_TYPE, context.currentInstruction) numbers = map(Conversions.NumberValue, nodeset) min = _min(numbers[:]) if number.isnan(min): return [] result = [] for i in xrange(len(nodeset)): if numbers[i] == min: result.append(nodeset[i]) return result
def Range(context, lo, hi): """ Returns a node-set consisting of text nodes encapsulating integers in the numeric range bounded by the given low and high values. """ # contributed by Lars Marius Garshol; # originally using namespace URI 'http://garshol.priv.no/symbolic/' doc = context.node.rootNode # sanity check for n in (lo, hi): if number.isinf(n) or number.isnan(n): raise ValueError("Arguments to ft:range must be neither infinite nor NaN.") #xrange wants int, not float lo = int(round(Conversions.NumberValue(lo))) hi = int(round(Conversions.NumberValue(hi))) nodeset = [] for num in xrange(lo, hi): nodeset.append(doc.createTextNode(str(num))) return nodeset
def filter(self, nodeList, context, reverse): if self._length: state = context.copy() for pred in self._predicates: size = len(nodeList) ctr = 0 current = nodeList nodeList = [] for node in current: position = (reverse and size - ctr) or (ctr + 1) context.node, context.position, context.size = \ node, position, size res = pred.evaluate(context) if type(res) in NumberTypes: # This must be separate to prevent falling into # the boolean check. if not number.isnan(res) and res == position: nodeList.append(node) elif Conversions.BooleanValue(res): nodeList.append(node) ctr += 1 context.set(state) return nodeList
def compare(self, expected, actual, msg=None, func=cmp, diff=0, stackLevel=1, funcArgs={}): """ Uses func to compare the expected result with actual result of a regression test. diff is ignored. msg is an optional custom message to print if the comparison tests positive (i.e. the results differ). func is the comparison function to use, and must be a function that returns the same as the built-in cmp(). stackLevel affects exception reporting. funcArgs is an optional dictionary of keyword arguments that will be passed to the comparison function, if the dictionary is not empty. """ self.totalComparisons += 1 # Normalize float values if type(expected) == type(actual) == float: if number.finite(expected): expected = float(str(expected)) elif number.isnan(expected): expected = 'NaN' elif number.isinf(expected) > 0: expected = 'Inf' else: expected = '-Inf' if number.finite(actual): actual = float(str(actual)) elif number.isnan(actual): actual = 'NaN' elif number.isinf(actual) > 0: actual = 'Inf' else: actual = '-Inf' # Make sure there was a message for this comparison if not msg: if self.test: self.test.comparisons += 1 msg = 'Test %d' % (self.test.comparisons) else: msg = 'Test %d of all tests' % self.totalComparisons start = time.time() try: if funcArgs: res = func(expected, actual, **funcArgs) else: res = func(expected, actual) if res: # failure self.message(msg) if diff and self.verbose >= VERBOSE_DEBUG: self._diff(expected, actual) error = '%sExpected:%s %s\n' % (self.GREEN, self.NORMAL, repr(expected)) error += '%sCompared:%s %s' % (self.RED, self.NORMAL, repr(actual)) self.error(error, stackLevel=(stackLevel+1)) return 0 finally: end = time.time() if self.test: self.test.compareTime += (end - start) # success return 1
def compare(self, expected, actual, msg=None, func=cmp, diff=0, stackLevel=1, funcArgs={}): """ Uses func to compare the expected result with actual result of a regression test. diff is ignored. msg is an optional custom message to print if the comparison tests positive (i.e. the results differ). func is the comparison function to use, and must be a function that returns the same as the built-in cmp(). stackLevel affects exception reporting. funcArgs is an optional dictionary of keyword arguments that will be passed to the comparison function, if the dictionary is not empty. """ self.totalComparisons += 1 # Normalize float values if type(expected) == type(actual) == float: if number.finite(expected): expected = float(str(expected)) elif number.isnan(expected): expected = 'NaN' elif number.isinf(expected) > 0: expected = 'Inf' else: expected = '-Inf' if number.finite(actual): actual = float(str(actual)) elif number.isnan(actual): actual = 'NaN' elif number.isinf(actual) > 0: actual = 'Inf' else: actual = '-Inf' # Make sure there was a message for this comparison if not msg: if self.test: self.test.comparisons += 1 msg = 'Test %d' % (self.test.comparisons) else: msg = 'Test %d of all tests' % self.totalComparisons start = time.time() try: if funcArgs: res = func(expected, actual, **funcArgs) else: res = func(expected, actual) if res: # failure self.message(msg) if diff and self.verbose >= VERBOSE_DEBUG: self._diff(expected, actual) error = '%sExpected:%s %s\n' % (self.GREEN, self.NORMAL, repr(expected)) error += '%sCompared:%s %s' % (self.RED, self.NORMAL, repr(actual)) self.error(error, stackLevel=(stackLevel + 1)) return 0 finally: end = time.time() if self.test: self.test.compareTime += (end - start) # success return 1