def load_function(excel_formula, name_space): """exec the code into our address space""" # the compiled expressions can call these functions if # referencing other cells or a range of cells name_space['_C_'] = evaluate name_space['_R_'] = evaluate_range name_space['_REF_'] = AddressRange.create name_space['pi'] = math.pi for name in ('int', 'abs', 'round'): name_space[name] = math_wrap(globals()['__builtins__'][name]) # function to fixup the operands name_space['excel_operator_operand_fixup'] = \ build_operator_operand_fixup(capture_error_state) # hook for the execed code to save the resulting lambda name_space['lambdas'] = lambdas = [] # get the compiled code and needed names compiled, names = excel_formula.compiled_python # load the needed names not_found = set() for name in names: if name not in name_space: funcs = ((getattr(module, name, None), module) for module in modules) func, module = next((f for f in funcs if f[0] is not None), (None, None)) if func is None: not_found.add(name) else: if module.__name__ == 'math': name_space[name] = math_wrap(func) else: name_space[name] = func # exec the code to define the lambda exec(compiled, name_space, name_space) excel_formula.compiled_lambda = lambdas[0] del name_space['lambdas'] return not_found
def xatan2(value1, value2): # Excel reference: https://support.office.com/en-us/article/ # ATAN2-function-C04592AB-B9E3-4908-B428-C96B3A565033 if value1 in ERROR_CODES: return value1 if value2 in ERROR_CODES: return value2 # swap arguments return math_wrap(atan2)(value2, value1)
def test_math_wrap_domain_error(): assert math_wrap(math.log)(-1) == NUM_ERROR
def test_math_wrap(value, result): assert math_wrap(lambda x: x)(value) == result
def xlog(value): if list_like(value): return [math_wrap(log)(x) for x in flatten(value)] else: return math_wrap(log)(value)
# Excel reference: https://support.office.com/en-us/article/ # ROUNDUP-function-F8BC9B23-E795-47DB-8703-DB171D0C42A7 number, num_digits = coerce_to_number(number), coerce_to_number(num_digits) if not is_number(number) or not is_number(num_digits): return VALUE_ERROR if isinstance(number, bool): number = int(number) quant = Decimal('1E{}{}'.format('+-'[num_digits >= 0], abs(num_digits))) return float(Decimal(repr(number)).quantize(quant, rounding=ROUND_UP)) roundup = math_wrap(roundup_unwrapped) def row(ref): if ref in ERROR_CODES: return ref if ref.is_range: ref = ref.start return max(ref.row, 1) def sumif(rng, criteria, sum_range=None): # Excel reference: https://support.office.com/en-us/article/ # SUMIF-function-169b8c99-c05c-4483-a712-1697a653039b if sum_range is None: