Source code for formulas.functions.eng

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright 2016-2023 European Commission (JRC);
# Licensed under the EUPL (the 'Licence');
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl

"""
Python equivalents of engineering Excel functions.
"""
import itertools
import functools
import schedula as sh
from . import wrap_func, flatten, Error, XlError

FUNCTIONS = {}


def _parseX(x):
    x = list(flatten(x, None))
    if len(x) == 1 and not isinstance(x[0], bool):
        x = x[0]
        if isinstance(x, XlError):
            return x
        x = sh.EMPTY is not x and x or '0'
        if isinstance(x, int) or (isinstance(x, float) and x.is_integer()):
            x = x >= 0 and str(int(x)) or x
        if not (not isinstance(x, str) or len(x) > 10):
            return x
        return Error.errors['#NUM!']
    return Error.errors['#VALUE!']


def _parseDEC(x):
    x = list(flatten(x, None))
    if len(x) == 1 and not isinstance(x[0], bool):
        x = x[0]
        if isinstance(x, XlError):
            return x
        try:
            return int(sh.EMPTY is not x and x or 0)
        except ValueError:
            pass
    return Error.errors['#VALUE!']


_xmask = {2: 1 << 9, 8: 1 << 29, 16: 1 << 39}


def _x2dec(x, base=16):
    if isinstance(x, XlError):
        return x
    try:
        x, y = int(x, base), _xmask[base]
        return (x & ~y) - (y & x)
    except ValueError:
        return Error.errors['#NUM!']


_xfunc = {2: bin, 8: oct, 16: hex}


def _dec2x(x, places=None, base=16):
    x = _parseDEC(x)
    if isinstance(x, XlError):
        return x
    y = _xmask[base]
    if -y <= x < y:
        if x < 0:
            x += y << 1
        x = _xfunc[base](int(x))[2:].upper()
        if places is not None:
            places = int(places)
            if places >= len(x):
                return x.zfill(int(places))
        else:
            return x
    return Error.errors['#NUM!']


[docs] def hex2dec2bin2oct(function_id, memo): dsp = sh.BlueDispatcher(raises=True) for k in ('HEX', 'OCT', 'BIN'): dsp.add_data(k, filters=[_parseX]) dsp.add_function( function_id='HEX2DEC', function=_x2dec, inputs=['HEX'], outputs=['DEC'] ) dsp.add_function( function_id='OCT2DEC', function=functools.partial(_x2dec, base=8), inputs=['OCT'], outputs=['DEC'] ) dsp.add_function( function_id='BIN2DEC', function=functools.partial(_x2dec, base=2), inputs=['BIN'], outputs=['DEC'] ) dsp.add_function( function_id='DEC2HEX', function=_dec2x, inputs=['DEC', 'places'], outputs=['HEX'] ) dsp.add_function( function_id='DEC2OCT', function=functools.partial(_dec2x, base=8), inputs=['DEC', 'places'], outputs=['OCT'] ) dsp.add_function( function_id='DEC2BIN', function=functools.partial(_dec2x, base=2), inputs=['DEC', 'places'], outputs=['BIN'] ) i, o = function_id.split('2') _func = sh.DispatchPipe(dsp, function_id, [i, 'places'], [o]) def func(x, places=None): return _func.register(memo=memo)(x, places) return func
_memo = {} for k in map('2'.join, itertools.permutations(['HEX', 'OCT', 'BIN', 'DEC'], 2)): FUNCTIONS[k] = wrap_func(hex2dec2bin2oct(k, _memo))