Пример #1
0
def crop(d: Mapping, prefix: str, trim: bool = True) -> dict:
    """Crop mapping to keys, that start with an initial string.

    Args:
        d: Mapping that encodes sections by the prefix of string keys
        prefix: Key prefix as string
        trim: Determines if the section prefix is removed from the keys of the
            returned mapping. Default: True

    Returns:
        Subset of the original mapping, which only contains keys that start
        with the given section. Thereby the new keys are trimmed
        from the initial section string.

    Examples:
        >>> crop({'a1': 1, 'a2': 2, 'b1': 3}, 'a')
        {'1': 1, '2': 2}

    """
    # Check types
    check.has_type('d', d, Mapping)
    check.has_type('prefix', prefix, str)

    # Create new dictionary with section
    i = len(prefix)
    if trim:
        section = {k[i:]: v for k, v in d.items() \
            if isinstance(k, str) and k[:i] == prefix}
    else:
        section = {k: v for k, v in d.items() \
            if isinstance(k, str) and k[:i] == prefix}

    return section
Пример #2
0
def distance(x: NpArrayLike,
             y: NpArrayLike,
             name: str = 'euclid',
             axes: NpAxes = 0,
             **kwds: Any) -> NpArray:
    """Calculate distance of two arrays along given axes.

    A vector distance function, also known as metric, is a function d(x, y),
    which quantifies the proximity of vectors in a vector space as non-negative
    real numbers. If the distance is zero, then the vectors are equivalent with
    respect to the distance function. Distance functions are often used as
    error, loss or risk functions, to evaluate statistical estimations.

    Args:
        x: Any sequence that can be interpreted as a numpy ndarray of arbitrary
            dimension. This includes nested lists, tuples, scalars and existing
            arrays.
        y: Any sequence that can be interpreted as a numpy ndarray with the same
            dimension, shape and datatypes as 'x'.
        name: Name of distance. Accepted values are:
            'minkowski': :term:`Minkowski distance`
                Remark: requires additional parameter 'p'
            'manhattan': :term:`Manhattan distance`
            'euclid': :term:`Euclidean distance` (default)
            'chebyshev': :term:`Chebyshev distance`
            'pmean': :term:`Power mean difference`
                Remark: requires additional parameter 'p'
            'amean': :term:`Mean absolute difference`
            'qmean': :term:`Quadratic mean difference`
        axes: Integer or tuple of integers, that identify the array axes, along
            which the function is evaluated. In a one-dimensional array the
            single axis has ID 0. In a two-dimensional array the axis with ID 0
            is running across the rows and the axis with ID 1 is running across
            the columns. For the value None, the function is evaluated with
            respect to all axes of the array. The default value is 0, which
            is an evaluation with respect to the first axis in the array.
        **kwds: Parameters of the given distance or class of distances.
            The Parameters are documented within the respective 'dist'
            functions.

    Returns:
        :class:`numpy.ndarray` of dimension dim(*x*) - len(*axes*).

    """
    # Try to cast 'x' and 'y' as arrays
    x = array.cast(x)
    y = array.cast(y)

    # Check type of 'axes'
    check.has_type("'axes'", axes, (int, tuple))

    # Check dimensions of 'x' and 'y'
    if x.shape != y.shape:
        raise ValueError("arrays 'x' and 'y' can not be broadcasted together")

    # Get function from catalog
    f = catalog.pick(Distance, name=name)

    # Evaluate function
    return call.safe_call(f, x, y, axes=axes, **kwds)
Пример #3
0
def add_cols(
        base: NpRecArray, data: NpRecArray,
        cols: NpFields = None) -> NpRecArray:
    """Add columns from source table to target table.

    Wrapper function to numpy's `rec_append_fields`_.

    Args:
        base: Numpy record array with table like data
        data: Numpy record array storing the fields to add to the base.
        cols: String or sequence of strings corresponding to the names of the
            new columns. If cols is None, then all columns of the data table
            are appended. Default: None

    Returns:
        Numpy record array containing the base array, as well as the
        appended columns.

    """
    cols = cols or getattr(data, 'dtype').names
    check.has_type("'cols'", cols, (tuple, str))
    cols = list(cols) # make cols mutable

    # Append fields
    return nprec.rec_append_fields(base, cols, [data[c] for c in cols])
Пример #4
0
 def _get_bindict(self, obj: 'Group') -> dict:
     binddict = self.binddict
     if not binddict:
         return obj.__dict__
     check.has_attr(obj, binddict)
     check.has_type(binddict, getattr(obj, binddict), dict)
     return getattr(obj, binddict)
Пример #5
0
def from_dict(
        d: StrPairDict, labels: StrListPair, nan: Number = NaN) -> NpArray:
    """Convert dictionary to array.

    Args:
        d: Dictionary with keys (<*row*>, <*col*>), where the elemns <*row*> are
            row labels from the list <*rows*> and <*col*> column labels from the
            list *columns*.
        labels: Tuple of format (<*rows*>, <*columns*>), where <*rows*> is a
            list of row labels, e.g. ['row1', 'row2', ...] and <*columns*> a
            list of column labels, e.g. ['col1', 'col2', ...].
        nan: Value to mask Not Not a Number (NaN) entries. Missing entries in
            the dictionary are replenished by the NaN value in the array.
            Default: [IEEE754]_ floating point representation of NaN.

    Returns:
        :class:`numpy.ndarray` of shape (*n*, *m*), where *n* equals the number
        of <*rows*> and *m* the number of <*columns*>.

    """
    # Check type of 'd'
    check.has_type("'d'", d, dict)

    # Declare and initialize return value
    x: NpArray = np.empty(shape=(len(labels[0]), len(labels[1])))

    # Get numpy ndarray
    setit = getattr(x, 'itemset')
    for i, row in enumerate(labels[0]):
        for j, col in enumerate(labels[1]):
            setit((i, j), d.get((row, col), nan))

    return x
Пример #6
0
def get_caller_module_name(frame: int = 0) -> str:
    """Get name of module, which calls this function.

    Args:
        frame: Frame index relative to the current frame in the callstack,
            which is identified with 0. Negative values consecutively identify
            previous modules within the callstack. Default: 0

    Returns:
        String with name of module.

    """
    # Check types
    check.has_type("'frame'", frame, int)

    # Check values
    if frame > 0:
        raise ValueError("'frame' is required to be a negative number or zero")

    # Traceback frames using inspect
    mname: str = ''
    cframe = inspect.currentframe()
    for _ in range(abs(frame) + 1):
        if cframe is None:
            break
        cframe = cframe.f_back
    if cframe is not None:
        mname = cframe.f_globals['__name__']

    return mname
Пример #7
0
def create_field(field: FieldLike) -> Field:
    """Create a Field object.

    Args:
        field: :term:`Field definition`

    Return:
        Instance of class :class:`Field`

    """
    # Get Field Arguments
    if isinstance(field, Field):
        args = (field.id, field.type)
    elif isinstance(field, tuple):
        if len(field) == 1:
            args = (field[0], NoneType)
        elif len(field) == 2:
            args = (field[0], field[1])
    else:
        args = (field, NoneType)

    # Check Field Arguments
    check.has_type('field identifier', args[0], Hashable)
    check.has_type('field type', args[1], type)

    # Create and return Field
    return Field(*args)
Пример #8
0
 def __post_init__(self) -> None:
     check.has_type('type', self.type, int)
     check.has_type('key', self.key, str)
     if not self.type in [CONSTANT, VARIABLE]:
         check.is_callable('value', self.value)
     check.has_type('priority', self.priority, int)
     check.has_type('builtin', self.builtin, bool)
     check.has_type('factory', self.factory, bool)
Пример #9
0
def distance(x: NpArrayLike,
             y: NpArrayLike,
             name: str = 'frobenius',
             axes: IntPair = (0, 1),
             **kwds: Any) -> NpArray:
    """Calculate matrix distances of two arrays along given axes.

    A matrix distance function, is a function d(x, y), which quantifies the
    proximity of matrices in a vector space as non-negative
    real numbers. If the distance is zero, then the matrices are equivalent with
    respect to the distance function. Distance functions are often used as
    error, loss or risk functions, to evaluate statistical estimations.

    Args:
        x: Any sequence that can be interpreted as a numpy ndarray of two or
            more dimensions. This includes nested lists, tuples, scalars and
            existing arrays.
        y: Any sequence that can be interpreted as a numpy ndarray with the same
            dimension, shape and datatypes as 'x'.
        name: Name of used matrix distance. Accepted values are:
            'frobenius': :term:`Frobenius distance` (default)
        axes: Pair (2-tuple) of integers, that identify the array axes, along
            which the function is evaluated. In a two-dimensional array the axis
            with ID 0 is running across the rows and the axis with ID 1 is
            running across the columns. The default value is (0, 1), which is an
            evaluation with respect to the first two axis in the array.
        **kwds: Parameters of the given distance or class of distances.
            The Parameters are documented within the respective 'dist'
            functions.

    Returns:
        :class:`numpy.ndarray` of dimension dim(*x*) - 2.

    """
    # Try to cast 'x' and 'y' as arrays
    x = array.cast(x)
    y = array.cast(y)

    # Check type of 'axes'
    check.has_type("'axes'", axes, tuple)

    # Check dimensions of 'x' and 'y'
    if x.shape != y.shape:
        raise ValueError("arrays 'x' and 'y' can not be broadcasted together")

    # Check value of 'axes'
    check.has_size("argument 'axes'", axes, size=2)
    if axes[0] == axes[1]:
        raise np.AxisError("first and second axis have to be different")

    # Get function from catalog
    f = catalog.pick(Distance, name=name)

    # Evaluate function
    return call.safe_call(f, x=x, y=y, axes=axes, **kwds)
Пример #10
0
def merge(*args: Mapping, mode: int = 1) -> Mapping:
    """Recursively right merge mappings.

    Args:
        *args: Mappings with arbitrary structure
        mode: Creation mode for merged mapping:
            0: change rightmost dictionary
            1: create new dictionary by deepcopy
            2: create new dictionary by chain mapping

    Returns:
        Dictionary containing right merge of dictionaries.

    Examples:
        >>> merge({'a': 1}, {'a': 2, 'b': 2}, {'c': 3})
        {'a': 1, 'b': 2, 'c': 3}

    """
    # Check for trivial cases
    if not args:
        return {}
    if len(args) == 1:
        return args[0]

    # Check for chain mapping creation mode
    if mode == 2:
        import collections
        return dict(collections.ChainMap(*args))

    # Recursively right merge
    if len(args) == 2:
        d1, d2 = args[0], args[1]
    else:
        d1, d2 = args[0], merge(*args[1:], mode=mode)
        mode = 0

    # Check Type of first and second argument
    check.has_type("first argument", d1, dict)
    check.has_type("second argument", d2, dict)

    # Create new dictionary
    if mode == 1:
        d2 = copy.deepcopy(d2)

    # Right merge couple of dictionaries
    for k1, v1 in d1.items():
        if k1 not in d2:
            d2[k1] = v1  # type: ignore
        elif isinstance(v1, dict):
            merge(v1, d2[k1], mode=0)
        else:
            d2[k1] = v1  # type: ignore

    return d2
Пример #11
0
def get_dir(dirname: str,
            *args: Any,
            pkgname: OptStr = None,
            **kwds: Any) -> pathlib.Path:
    """Get application specific environmental directory by name.

    This function returns application specific system directories by platform
    independent names to allow platform independent storage for caching,
    logging, configuration and permanent data storage.

    Args:
        dirname: Environmental directory name. Allowed values are:

            :user_cache_dir: Cache directory of user
            :user_config_dir: Configuration directory of user
            :user_data_dir: Data directory of user
            :user_log_dir: Logging directory of user
            :site_config_dir: Site global configuration directory
            :site_data_dir: Site global data directory
            :site_package_dir: Site global package directory
            :site_temp_dir: Site global directory for temporary files
            :package_dir: Current package directory
            :package_data_dir: Current package data directory
        *args: Optional arguments that specify the application, as required by
            the function '.env.update_dirs'.
        **kwds: Optional keyword arguments that specify the application, as
            required by the function '.env.update_dirs'.

    Returns:
        String containing path of environmental directory or None if the
        pathname is not supported.

    """
    # Get package name from callers top level module
    pkgname = pkgname or pkg.get_root_name(stack.get_caller_module_name(-2))

    # Check type of 'dirname'
    check.has_type("'dirname'", dirname, str)

    # Update derectories if not present or if any optional arguments are given
    try:
        dirs = globals()['cache'][pkgname]['dirs']
    except KeyError:
        update_dirs(*args, pkgname=pkgname, **kwds)
    dirs = globals()['cache'][pkgname]['dirs']

    # Check value of 'dirname'
    if dirname not in dirs:
        raise ValueError(f"directory name '{dirname}' is not valid")

    return dirs[dirname]
Пример #12
0
def length(x: NpArrayLike,
           norm: str = 'euclid',
           axes: NpAxes = 0,
           **kwds: Any) -> NpArray:
    r"""Calculate the length of a vector with respect to a given norm.

    Args:
        x: Any sequence that can be interpreted as a numpy ndarray of arbitrary
            dimension. This includes nested lists, tuples, scalars and existing
            arrays.
        norm: String, which identifies the used vector norm:

            :p-norm: The :term:`p-norm` requires an additional parameter *p* and
                induces the :term:`Minkowski distance`.
            :1-norm: The :term:`1-norm` induces the :term:`Manhattan distance`.
            :euclid: The :term:`Euclidean norm` is the default norm and induces
                the :term:`Euclidean distance`.
            :max: The :term:`Maximum norm` induces the
                :term:`Chebyshev distance`.
            :pmean: The :term:`Hölder mean` requires an additional parameter
                *p* and induces the :term:`power mean difference`.
            :amean: The :term:`mean absolute` induces the
                :term:`mean absolute difference`
            :qmean: The :term:`quadratic mean` induces the
                :term:`quadratic mean difference`
        axes: Integer or tuple of integers, that identify the array axes, along
            which the function is evaluated. In a one-dimensional array the
            single axis has ID 0. In a two-dimensional array the axis with ID 0
            is running across the rows and the axis with ID 1 is running across
            the columns. For the value None, the function is evaluated with
            respect to all axes of the array. The default value is 0, which
            is an evaluation with respect to the first axis in the array.
        **kwds: Additional parameters of the given norm. These norm parameters
            are documented within the respective 'norm' functions.

    Returns:
        :class:`numpy.ndarray` of dimension dim(*x*) - len(*axes*).

    """
    # Try to cast 'x' as array
    x = array.cast(x)

    # Check type of 'axes'
    check.has_type("'axes'", axes, (int, tuple))

    # Get function from catalog
    f = catalog.pick(Norm, name=norm)

    # Evaluate function
    return call.safe_call(f, x, axes=axes, **kwds)
Пример #13
0
def norm(x: NpArrayLike,
         name: str = 'frobenius',
         axes: IntPair = (0, 1),
         **kwds: Any) -> NpArray:
    """Calculate magnitude of matrix with respect to given norm.

    Args:
        x: Any sequence that can be interpreted as a numpy ndarray of two or
            more dimensions. This includes nested lists, tuples, scalars and
            existing arrays.
        name: Name of matrix norm. Accepted values are:

            :pq: :term:`pq-Norm`. Remark: requires additional parameters *p* and
                *q*
            :frobenius: The default norm is the :term:`Frobenius Norm`

        axes: Pair (2-tuple) of integers, that identify the array axes, along
            which the function is evaluated. In a two-dimensional array the axis
            with ID 0 is running across the rows and the axis with ID 1 is
            running across the columns. The default value is (0, 1), which is an
            evaluation with respect to the first two axis in the array.
        **kwds: Parameters of the given norm / class of norms.
            The norm Parameters are documented within the respective 'norm'
            functions.

    Returns:
        :class:`numpy.ndarray` of dimension dim(*x*) - 2.

    """
    # Try to cast 'x' as array
    x = array.cast(x)

    # Check type of 'axes'
    check.has_type("'axes'", axes, tuple)

    # Check dimension of 'x'
    if x.ndim < 2:
        raise ValueError("'x' is required to have dimension > 1")

    # Check value of 'axes'
    check.has_size("argument 'axes'", axes, size=2)
    if axes[0] == axes[1]:
        raise np.AxisError("first and second axis have to be different")

    # Get function from catalog
    f = catalog.pick(Norm, name=name)

    # Evaluate function
    return call.safe_call(f, x=x, axes=axes, **kwds)
Пример #14
0
def as_tuples(x: NpArray) -> List[tuple]:
    """Convert two dimensional array list of tuples.

    Args:
        x: Numpy ndarray of shape (*n*, *m*), where *n* equals the number of
            <*rows*> and *m* the number of <*columns*>.

    Returns:
        List of tuples.

    """
    # Check type of 'x'
    check.has_type("'x'", x, np.ndarray)

    return x.tolist()
Пример #15
0
 def __set__(self, obj: 'Group', val: Any) -> None:
     # Bypass and type check setter requests
     if self._get_readonly(obj):
         raise errors.ReadOnlyAttrError(obj, self.name)
     if self._is_remote(obj):
         self._set_remote(obj, val)
         return
     dtype = self.dtype
     if dtype and not isinstance(val, type(self.default)):
         check.has_type(f"attribute '{self.name}'", val, dtype)
     if callable(self.fset):
         self.fset(obj, val)  # type: ignore
         return
     if isinstance(self.sset, str):
         getattr(obj, self.sset, void)(val)
         return
     binddict = self._get_bindict(obj)
     bindkey = self._get_bindkey(obj)
     binddict[bindkey] = val
Пример #16
0
def create_variable(var: VarLike, default: OptOp = None) -> Variable:
    """Create variable from variable definition.

    Args:
        var: Variable defintion
        default:

    Returns:

    """
    # Check Arguments
    check.has_type('var', var, (str, tuple))
    check.not_empty('var', var)

    # Get Defaults
    default = default or operator.Identity()

    # Get Variable Arguments
    args: VarLike
    if isinstance(var, str):
        if var.isidentifier():
            args = (var, default, (var, ))
        else:
            op = operator.Lambda(expression=var)
            args = (var, op, op.variables)
    elif len(var) == 1:
        args = (var[0], default, (var[0], ))
    elif len(var) == 2:
        if callable(var[1]):
            args = (var[0], var[1], (var[0], ))
        elif isinstance(var[1], tuple):
            args = (var[0], default, var[1])
        else:
            args = (var[0], default, (var[1], ))
    elif callable(var[1]):
        if isinstance(var[2], tuple):
            args = (var[0], var[1], var[2])
        else:
            args = (var[0], var[1], (var[2], ))
    elif isinstance(var[2], tuple):
        op = operator.Lambda(expression=var[1], domain=(None, var[2]))
        args = (var[0], op, var[2])
    else:
        op = operator.Lambda(expression=var[1], domain=(None, (var[2], )))
        args = (var[0], op, (var[2], ))

    # Check Variable Arguments
    check.has_type('variable name', args[0], str)
    check.has_type('variable operator', args[1], Callable)
    check.has_type('variable frame', args[2], tuple)

    # Create and return Variable
    return Variable(*args)
Пример #17
0
def as_path(text: str, expand: bool = True) -> pathlib.Path:
    """Convert text into list.

    Args:
        text: String representing a path.
        expand: Boolen value, whoch determines, if variables in environmental
            path variables are expanded.

    Returns:
        Value of the text as Path.

    """
    # Check types of Arguments
    check.has_type("first argument 'text'", text, str)
    check.has_type("'expand'", expand, bool)

    if expand:
        return env.expand(text)
    return pathlib.Path(text)
Пример #18
0
def decode(text: str,
           target: OptType = None,
           undef: OptStr = 'None',
           **kwds: Any) -> Any:
    """Decode text representation of object to object.

    Args:
        text: String representing the value of a given type in it's respective
            syntax format. The standard format corresponds to the standard
            Python representation if available. Some types also accept
            further formats, which may use additional keywords.
        target: Target type, in which the text is to be converted.
        undef: Optional string, which respresents an undefined value. If undef
            is a string, then the any text, the matches the string is decoded
            as None, independent from the given target type.
        **kwds: Supplementary parameters, that specify the encoding format of
            the target type.

    Returns:
        Value of the text in given target format or None.

    """
    # Check Arguments
    check.has_type("'text'", text, str)
    check.has_opt_type("'target'", target, type)

    # Check for undefined value
    if text == undef:
        return None

    # If no target type is given, estimate type
    target = target or estimate(text) or str

    # Elementary literals
    if target == str:
        return text.strip().replace('\n', '')
    if target == bool:
        return text.lower().strip() == 'true'
    if target in [int, float, complex]:
        return target(text, **kwds)

    fname = 'as_' + target.__name__.lower()
    return pkg.call_attr(fname, text, **kwds)
Пример #19
0
def as_datetime(text: str, fmt: OptStr = None) -> Date:
    """Convert text to datetime.

    Args:
        text: String representation of datetime
        fmt: Optional string parameter, that specifies the format, which is
            used to decode the text to datetime. The default format is the [ISO
            8601]_ format, given by the string `%Y-%m-%d %H:%M:%S.%f`.


    Returns:
        Value of the text as datetime.

    """
    # Check types of Arguments
    check.has_type("first argument 'text'", text, str)

    # Convert text to datetime
    fmt = fmt or '%Y-%m-%d %H:%M:%S.%f'
    return Date.strptime(text, fmt)
Пример #20
0
def has_attr(name: str, module: OptModule = None) -> bool:
    """Determine if a module has an attribute of given name.

    Args:
        name: Name of attribute
        module: Optional reference to module, which is used to search for the
            given attribute. By default the current callers module is used.

    Returns:
        Result of call.

    """
    # Set default values
    module = module or stack.get_caller_module()

    # Check Arguments
    check.has_type("'name'", name, str)
    check.has_type("'module'", module, Module)

    return hasattr(module, name)
Пример #21
0
def as_dict(
        x: NpArray, labels: StrListPair, nan: OptNumber = NaN) -> StrPairDict:
    """Convert two dimensional array to dictionary of pairs.

    Args:
        x: Numpy ndarray of shape (*n*, *m*), where *n* equals the number of
            <*rows*> and *m* the number of <*columns*>.
        labels: Tuple of format (<*rows*>, <*columns*>), where <*rows*> is a
            list of row labels, e.g. ['row1', 'row2', ...] and <*columns*> a
            list of column labels, e.g. ['col1', 'col2', ...].
        na: Optional value to mask Not a Number (NaN) entries. For cells in the
            array, which have this value, no entry in the returned dictionary
            is created. If nan is None, then for all numbers entries are
            created. Default: [IEEE754]_ floating point representation of NaN.

    Returns:
         Dictionary with keys (<*row*>, <*col*>), where the elemns <*row*> are
         row labels from the list <*rows*> and <*col*> column labels from the
         list *columns*.

    """
    # Check type of 'x'
    check.has_type("'x'", x, np.ndarray)

    # Check dimension of 'x'
    if x.ndim != 2:
        raise TypeError(
            "Numpy ndarray 'x' is required to have dimension 2"
            f", not '{x.ndim}'")

    # Get dictionary with pairs as keys
    d: StrPairDict = {}
    for i, row in enumerate(labels[0]):
        for j, col in enumerate(labels[1]):
            val = x.item(i, j)
            if nan is None or not np.isnan(val):
                d[(row, col)] = val

    return d
Пример #22
0
def select(d: Mapping, pattern: str) -> dict:
    """Filter mappings to keys, that match a given pattern.

    Args:
        d: Mapping, which keys aregiven by strings
        pattern: Wildcard pattern as described in the standard library module
            :mod:`fnmatch`.

    Returns:
        Subset of the original mapping, which only contains keys, that match
        the given pattern.

    Examples:
        >>> select({'a1': 1, 'a2': 2, 'b1': 3}, 'a*')
        {'a1': 1, 'a2': 2}

    """
    # Check types
    check.has_type('d', d, Mapping)
    check.has_type('pattern', pattern, str)

    valid = fnmatch.filter(d.keys(), pattern)
    return {k: d[k] for k in valid}
Пример #23
0
def as_set(text: str, delim: str = ',') -> set:
    """Convert text into set.

    Args:
        text: String representing a set. Valid representations are:
            Python format: Allows elements of arbitrary types:
                Example: "{'a', 'b', 3}"
            Delimiter separated values (DSV): Allows string elements:
                Example: "a, b, c"
        delim: A string, which is used as delimiter for the separatation of the
            text. This parameter is only used in the DSV format.

    Returns:
        Value of the text as set.

    """
    # Check types of Arguments
    check.has_type("first argument 'text'", text, str)
    check.has_type("'delim'", delim, str)

    # Return empty set if the string is blank
    if not text or not text.strip():
        return set()

    # Python standard format
    val = None
    if delim == ',':
        try:
            val = set(ast.literal_eval(text))
        except (SyntaxError, ValueError, Warning):
            pass
    if isinstance(val, set):
        return val

    # Delimited string format
    return {item.strip() for item in text.split(delim)}
Пример #24
0
def get_caller_name(frame: int = 0) -> str:
    """Get name of the callable, which calls this function.

    Args:
        frame: Frame index relative to the current frame in the callstack,
            which is identified with 0. Negative values consecutively identify
            previous modules within the callstack. Default: 0

    Returns:
        String with name of the caller.

    """
    # Check types
    check.has_type("'frame'", frame, int)

    # Check value of 'frame'
    if frame > 0:
        raise ValueError("'frame' is required to be a negative number or zero")

    # Get name of caller using inspect
    stack = inspect.stack()[abs(frame - 1)]
    mname = inspect.getmodule(stack[0]).__name__
    fbase = stack[3]
    return '.'.join([mname, fbase])
Пример #25
0
    def __init__(self,
                 fget: OptCallOrStr = None,
                 fset: OptCallOrStr = None,
                 fdel: OptCallOrStr = None,
                 doc: OptStr = None,
                 dtype: OptClassInfo = None,
                 readonly: bool = False,
                 default: Any = None,
                 factory: OptCallOrStr = None,
                 binddict: OptStr = None,
                 bindkey: OptStr = None,
                 remote: bool = False,
                 inherit: bool = False,
                 category: OptStr = None) -> None:

        # Initialize Property Class
        super().__init__(  # type: ignore
            fget=fget if callable(fget) else None,
            fset=fset if callable(fset) else None,
            fdel=fdel if callable(fdel) else None,
            doc=doc)

        # Check Types
        check.has_opt_type("'dtype'", dtype, TypeHint)
        check.has_type("'readonly'", readonly, bool)
        check.has_opt_type("'binddict'", binddict, str)
        check.has_opt_type("'bindkey'", bindkey, str)
        check.has_type("'remote'", inherit, bool)
        check.has_type("'inherit'", inherit, bool)
        check.has_opt_type("'category'", category, str)

        # Bind Instance Attributes to given Arguments
        self.sget = fget if isinstance(fget, str) else None
        self.sset = fset if isinstance(fset, str) else None
        self.sdel = fdel if isinstance(fdel, str) else None
        self.dtype = dtype
        self.default = default
        self.factory = factory
        self.readonly = readonly
        self.binddict = binddict
        self.bindkey = bindkey
        self.remote = remote
        self.inherit = inherit
        self.category = category
Пример #26
0
def create_domain(domain: DomLike = None, defaults: Keywords = None) -> Domain:
    """Create Domain object from domain definition.

    Args:
        domain: Optional :term:`domain like` parameter, that specifies the type
            and (if required) the frame of a domain.
        defaults: Optional :term:`mapping` which is used to complete the given
            domain definition. The key `'type'` specifies the default domain
            type and is required to be given as a :class:`type`. The key
            `'fields'` specifies a default ordered basis for the domain and is
            required to be given as a single or a tuple of :term:`field
            definitions<field definition>`.

    Returns:
        Instance of the class :class:`Domain`

    """
    # Check Arguments
    check.has_opt_type('domain', domain, (Hashable, Field, tuple))
    check.has_opt_type('defaults', defaults, Mapping)

    # Get Defaults
    defaults = defaults or {}
    dtype = defaults.get('type', NoneType)
    dfields = defaults.get('fields', tuple())

    # Get Domain Arguments
    if not domain:
        args = (dtype, *create_basis(dfields))
    elif isinstance(domain, Domain):
        args = (domain.type, domain.frame, domain.basis)
    elif isinstance(domain, tuple):
        args = (domain[0] or dtype, *create_basis(domain[1] or dfields))
    else:
        args = (domain, *create_basis(dfields))

    # Check Domain Arguments
    check.has_type('domain type', args[0], type)
    check.has_type('domain frame', args[1], tuple)
    check.no_dublicates('domain frame', args[1])
    check.has_type('domain basis', args[2], dict)

    # Create and return Domain
    return Domain(*args)
Пример #27
0
def decode(text: str,
           scheme: OptScheme = None,
           autocast: bool = False,
           flat: OptBool = None) -> Scheme:
    """Load configuration dictionary from INI-formated text.

    Args:
        text: Text, that describes a configuration in INI-format.
        scheme: Dictionary of dictionaries, which determines the structure of
            the configuration dictionary. If scheme is None, the INI-file
            is completely imported and all values are interpreted as strings. If
            the scheme is a dictionary of dictionaries, the keys of the outer
            dictionary describe valid section names by strings, that are
            interpreted as regular expressions. Therupon, the keys of the
            respective inner dictionaries describe valid parameter names as
            strings, that are also interpreted as regular expressions. Finally
            the values of the inner dictionaries define the type of the
            parameters by their own type, e.g. str, int, float etc. Accepted
            types can be found in the documentation of the function
            :func:`literal.decode <hup.base.literal.decode>`.
        autocast: If no scheme is given autocast determines, if the values are
            automatically converted to types, estimated by the function
            :func:`literal.estimate <hup.base.literal.estimate>`
        flat: Determines if the desired INI format structure contains sections
            or not. By default sections are used, if the first non blank, non
            comment line in the string identifies a section.

    Return:
        Structured configuration dictionary.

    """
    # Check arguments
    check.has_type("first argument", text, str)

    # If the usage of sections is not defined by the argument 'flat' their
    # existence is determined from the given file scheme. If the file
    # scheme also is not given, it is determined by the first not blank and
    # non comment line in the text. If this line does not start with the
    # character '[', then the file scheme is considered to be flat.
    if flat is None:
        if isinstance(scheme, dict):
            flat = not any(isinstance(val, dict) for val in scheme.values())
        else:
            flat = True
            with StringIO(text) as fh:
                line = ''
                for line in fh:
                    content = line.strip()
                    if content and not content.startswith('#'):
                        break
                flat = not line.lstrip().startswith('[')

    # For flat structured files a temporary [root] section is created and the
    # scheme dictionary is embedded within the 'root' key of a wrapping
    # dictionary.
    if flat:
        text = '\n'.join(['[root]', text])
        if isinstance(scheme, dict):
            scheme = cast(SecDict, {'root': scheme})

    # Parse ini without literal decoding
    parser = ConfigParser()
    setattr(parser, 'optionxform', lambda key: key)
    parser.read_string(text)

    # Decode literals by using the scheme dictionary
    config = parse(parser, scheme=cast(SecDict, scheme), autocast=autocast)

    # If scheme is flat collapse the 'root' key
    return config.get('root') or {} if flat else config
Пример #28
0
def search(module: OptModule = None,
           pattern: OptStr = None,
           classinfo: ClassInfo = Function,
           key: OptStr = None,
           val: OptStr = None,
           groupby: OptStr = None,
           recursive: bool = True,
           rules: OptDictOfKeyOps = None,
           errors: bool = False,
           **kwds: Any) -> dict:
    """Recursively search for objects within submodules.

    Args:
        module: Optional reference to module, which is used to search objects.
            By default the current callers module is used.
        pattern: Only objects which names satisfy the wildcard pattern given
            by 'pattern' are returned. The format of the wildcard pattern is
            described in the standard library module :py:mod:`fnmatch`. If
            pattern is None, then all objects are returned. Default: None
        classinfo: Classinfo given as a class, a type or a tuple containing
            classes, types or other tuples. Only members, which are ether an
            instance or a subclass of classinfo are returned. By default all
            types are allowed.
        key: Name of function attribute which is used as the key for the
            returned dictionary. If 'key' is None, then the fully qualified
            function names are used as keys. Default: None
        val: Name of function attribute which is used as the value for the
            returned dictionary. If 'val' is None, then all attributes of the
            respective objects are returned. Default: None
        groupby: Name of function attribute which is used to group the results.
            If 'groupby' is None, then the results are not grouped. Default:
            None
        recursive: Boolean value which determines if the search is performed
            recursively within all submodules. Default: True
        rules: Dictionary with individual filter rules, used by the attribute
            filter. The form is {<attribute>: <lambda>, ...}, where: <attribute>
            is a string with the attribute name and <lambda> is a boolean valued
            lambda function, which specifies the comparison of the attribute
            value against the argument value. Example: {'tags': lambda arg,
            attr: set(arg) <= set(attr)} By default any attribute, which is not
            in the filter rules is compared to the argument value by equality.
        errors: Boolean value which determines if an error is raised, if the
            module could not be found. By default errors are not raised.
        **kwds: Keyword arguments, that define the attribute filter for the
            returned dictionary. For example if the argument "tags = ['test']"
            is given, then only objects are returned, which have the attribute
            'tags' and the value of the attribute equals ['test']. If, however,
            the filter rule of the above example is given, then any function,
            with attribute 'tags' and a corresponding tag list, that comprises
            'test' is returned.

    Returns:
        Dictionary with function information as specified in the arguments
        'key' and 'val'.

    """
    # Set default values
    module = module or stack.get_caller_module()

    # Check argument types
    check.has_type("'module'", module, Module)
    check.has_opt_type("'pattern'", pattern, str)

    # Get list with module names, including the given and the submodules
    submodules = get_submodules(parent=module, recursive=recursive)
    mnames = [module.__name__] + submodules

    # Create dictionary with member attributes
    fd = {}
    rules = rules or {}
    for mname in mnames:
        minst = get_module(mname, errors=errors)
        if minst is None:
            continue
        d = otree.get_members_dict(minst,
                                   classinfo=classinfo,
                                   pattern=pattern,
                                   rules=rules,
                                   **kwds)

        # Ignore members if any required attribute is not available
        for name, attr in d.items():
            if key and not key in attr:
                continue
            if val and not val in attr:
                continue
            fd[name] = attr

    # Rename key for returned dictionary
    if key:
        d = {}
        for name, attr in fd.items():
            if key not in attr:
                continue
            kval = attr[key]
            if kval in d:
                continue
            d[kval] = attr
        fd = d

    # Group results
    if groupby:
        fd = mapping.groupby(fd, key=groupby)

    # Set value for returned dictionary
    if val:
        if groupby:
            for gn, group in fd.items():
                for name, attr in group.items():
                    fd[name] = attr[val]
        else:
            for name, attr in fd.items():
                fd[name] = attr[val]

    return fd
Пример #29
0
def get_var(varname: str,
            *args: Any,
            pkgname: OptStr = None,
            **kwds: Any) -> OptStr:
    """Get environment or application variable.

    Environment variables comprise static and runtime properties of the
    operating system like 'username' or 'hostname'. Application variables in
    turn, are intended to describe the application distribution by authorship
    information, bibliographic information, status, formal conditions and notes
    or warnings. For mor information see :PEP:`345`.

    Args:
        varname: Name of environment variable. Typical application variable
            names are:
            'name': The name of the distribution
            'version': A string containing the distribution's version number
            'status': Development status of the distributed application.
                Typical values are 'Prototype', 'Development', or 'Production'
            'description': A longer description of the distribution that can
                run to several paragraphs.
            'keywords': A list of additional keywords to be used to assist
                searching for the distribution in a larger catalog.
            'url': A string containing the URL for the distribution's
                homepage.
            'license': Text indicating the license covering the distribution
            'copyright': Notice of statutorily prescribed form that informs
                users of the distribution to published copyright ownership.
            'author': A string containing the author's name at a minimum;
                additional contact information may be provided.
            'email': A string containing the author's e-mail address. It can
                contain a name and e-mail address, as described in :rfc:`822`.
            'maintainer': A string containing the maintainer's name at a
                minimum; additional contact information may be provided.
            'company': The company, which created or maintains the distribution.
            'organization': The organization, twhich created or maintains the
                distribution.
            'credits': list with strings, acknowledging further contributors,
                Teams or supporting organizations.
        *args: Optional arguments that specify the application, as required by
            the function :func:`~hup.base.env.update_vars`.
        pkgname:
        **kwds: Optional keyword arguments that specify the application, as
            required by the function :func:`~hup.base.env.update_vars`.

    Returns:
        String representing the value of the application variable.

    """
    # Check type of 'varname'
    check.has_type("'varname'", varname, str)

    # Get package name from callers top level module
    pkgname = pkgname or pkg.get_root_name(stack.get_caller_module_name(-2))

    # Update variables if not present or if optional arguments are given
    try:
        appvars = globals()['cache'][pkgname]['vars']
    except KeyError:
        update_vars(*args, pkgname=pkgname, **kwds)
    appvars = globals()['cache'][pkgname]['vars']

    return appvars.get(varname, None)
Пример #30
0
def as_dict(text: str, delim: str = ',') -> dict:
    """Convert text into dictionary.

    Args:
        text: String representing a dictionary. Valid representations are:
            Python format: Allows keys and values of arbitrary types:
                Example: "{'a': 2, 1: True}"
            Delimiter separated expressions: Allow string keys and values:
                Example (Variant A): "<key> = <value><delim> ..."
                Example (Variant B): "'<key>': <value><delim> ..."
        delim: A string, which is used as delimiter for the separatation of the
            text. This parameter is only used in the DSV format.

    Returns:
        Value of the text as dictionary.

    """
    # Check types of Arguments
    check.has_type("first argument 'text'", text, str)
    check.has_type("argumnt 'delim'", delim, str)

    # Return empty dict if the string is blank
    if not text or not text.strip():
        return dict()

    Num = pp.Word(pp.nums + '.')
    Str = pp.quotedString
    Bool = pp.Or(pp.Word("True") | pp.Word("False"))
    Key = pp.Word(pp.alphas + "_", pp.alphanums + "_.")
    Val = pp.Or(Num | Str | Bool)

    # Try dictionary format "<key> = <value><delim> ..."
    Term = pp.Group(Key + '=' + Val)
    Terms = Term + pp.ZeroOrMore(delim + Term)
    try:
        l = Terms.parseString(text.strip('{}'))
    except pp.ParseException:
        l = None

    # Try dictionary format "'<key>': <value><delim> ..."
    if not l:
        Term = pp.Group(Str + ':' + Val)
        Terms = Term + pp.ZeroOrMore(delim + Term)
        try:
            l = Terms.parseString(text.strip('{}'))
        except pp.ParseException:
            return {}

    # Create dictionary from list
    d = {}
    for item in l:
        if len(item) == 1:
            if item[0] == ',':
                continue
            d[item] = True
            continue
        try:
            key, val = item[0].strip('\'\"'), ast.literal_eval(item[2])
        except (KeyError, NameError, TypeError, ValueError, SyntaxError,
                AttributeError):
            continue

        if isinstance(val, str):
            val = val.strip()
        d[key] = val

    return d