Source code for pylablib.core.utils.funcargparse

"""
Contains routines for checking arguments passed into a function for better flexibility. 
"""

from .py3 import textstring

import numpy as np


_default_parameter_error_message="unrecognized value of a parameter '{1}': '{0}'"
[docs] def parameter_value_error(par_val, par_name, message=None, error_type=None): """ Raise parameter value error (:exc:`ValueError` by default). """ error_type=error_type or ValueError message=message or _default_parameter_error_message raise error_type(message.format(par_val,par_name))
_default_parameter_range_error_message=_default_parameter_error_message+"; acceptable values are {2}"
[docs] def parameter_range_error(par_val, par_name, par_set=None, message=None, error_type=None): """ Raise parameter range error (:exc:`ValueError` by default). """ if par_set is None: parameter_value_error(par_val,par_name,message,error_type) error_type=error_type or ValueError message=message or _default_parameter_range_error_message raise error_type(message.format(par_val,par_name,list(par_set)))
[docs] def check_parameter_range(par_val, par_name, par_set, message=None, error_type=None): """ Raise error if `par_val` is not in in the `par_set` (`par_name` is used in the error message). """ if not (par_val in par_set): parameter_range_error(par_val,par_name,par_set,message,error_type)
_default_parameter_disagreeing_message="assigned value {1} doesn't agree with the current values {0}"
[docs] def getdefault(value, default_value, unassigned_value=None, conflict_action="ignore", message=None, error_type=None): """ Analog of ``dict``'s ``getdefault``. If `value` is `unassigned_value`, return `default_value` instead. If ``conflict_action=='error'`` and ``value!=default_value``, raise value error using `message` and `error_type`. """ if unassigned_value is None: unassigned=value is None else: unassigned=(value==unassigned_value) if unassigned: return default_value elif value!=default_value: check_parameter_range(conflict_action,"conflict_action",{"ignore","error"}) if conflict_action=="error": error_type=error_type or ValueError message=message or _default_parameter_disagreeing_message raise error_type(message.format(value,default_value)) return value
[docs] def is_sequence(value, sequence_type="builtin;nostring"): """ Check if `value` is a sequence. `sequence_type` is semicolon separated list of possible sequence types: - ``'builtin'`` - ``list``, ``tuple`` or ``str`` - ``'nostring'`` - ``str`` is not allows - ``'array'`` - ``list``, ``tuple`` or ``numpy.ndarray`` - ``'indexable'`` - anything which can be indexed - ``'haslength'`` - anything with length property """ try: iter(value) # iter is supported by any object having __getitem__ or __iter__ except TypeError: return False sequence_types=sequence_type.split(";") for st in sequence_types: if st=="builtin": if not (isinstance(value,list) or isinstance(value,tuple) or isinstance(value,textstring)): return False elif st=="nostring": if isinstance(value,textstring): return False elif st=="array": if not (isinstance(value,list) or isinstance(value,tuple) or isinstance(value,np.ndarray)): return False elif st=="indexable": try: value[0] except (IndexError,ValueError,KeyError): pass except TypeError: return False elif st=="haslength": try: len(value) except TypeError: return False else: check_parameter_range(st,"sequence_type",{"builtin","indexable","nostring","haslength","array"}) return True
[docs] def make_sequence(element, length=1, sequence_type="list"): """ Turn element into a sequence of `sequence_type` (``'list'`` or ``'tuple'``) repeated `length` times. """ check_parameter_range(sequence_type,"sequence_type",{"list","tuple"}) if sequence_type=="list": return [element]*length elif sequence_type=="tuple": return (element,)*length
_default_length_disagreeing_message="length of a parameter {0} doesn't agree with the expected length {1}"
[docs] def as_sequence(value, multiply_length=1, allowed_type="builtin;nostring", wrapping_type="list", length_conflict_action="ignore", message=None, error_type=None): """ Ensure that `value` is a sequence. If `value` is not a sequence of `allowed_type` (as checked by :func:`is_sequence`), turn it into a sequence specified by `wrapping_type` and `multiply_length`. If value is a sequence and ``length_conflict_action=='error'``, raise error with `error_type` and `error_message` if the length doesn't match `multiply_length`. Otherwise, return value unchanged. """ if is_sequence(value,sequence_type=allowed_type): if len(value)!=multiply_length: check_parameter_range(length_conflict_action,"length_conflict_action",{"ignore","error"}) if length_conflict_action=="error": error_type=error_type or ValueError message=message or _default_length_disagreeing_message raise error_type(message.format(value,multiply_length)) return value else: return make_sequence(value,length=multiply_length,sequence_type=wrapping_type)