def _validate_and_split_len(self, key): """Validate all key lengths greater than one, N. Valid input is an arbitrarily deep series of iterables that culminate in N length tuples, this includes an iterable depth of zero. The N length tuples can contain for each member either a type string or an iterable of type strings. """ if isinstance(key, tuple) and len(key) == self._len_keys: fst, snd = key if any([ not is_good_iterable(v) and not isinstance(v, str) for v in key ]): raise KeyError("The key {} is not valid.".format(key)) key = list(key) for ind in range(len(key)): if isinstance(key[ind], str): key[ind] = [key[ind]] return list(product(*key)) elif _is_iterable(key): keys = [] for k in key: keys.extend(self._validate_and_split_len(k)) return keys else: raise KeyError("The key {} is not valid.".format(key))
def __init__(self, sequence, default): if _is_iterable(default): dft_iter = cycle(default) else: dft_iter = repeat(default) self.default = tuple( [_to_default(item, dft) for item, dft in zip(sequence, dft_iter)])
def validate_and_split_len(self, key): """Validate all key lengths greater than one, N. Valid input is an arbitrarily deep series of iterables that culminate in N length tuples, this includes an iterable depth of zero. The N length tuples can contain for each member either a type string or an iterable of type strings. """ if isinstance(key, tuple) and len(key) == self.len_key: if any([ not _is_good_iterable(v) and not isinstance(v, str) for v in key ]): raise KeyError("The key {} is not valid.".format(key)) # convert str to single item list for proper enumeration using # product key_types_list = [[v] if isinstance(v, str) else v for v in key] return list(product(*key_types_list)) elif _is_iterable(key): keys = [] for k in key: keys.extend(self.validate_and_split_len(k)) return keys else: raise KeyError("The key {} is not valid.".format(key))
def _to_default(value, defaults=_NoDefault): if isinstance(value, tuple): if defaults is _NoDefault or _is_iterable(defaults): return _SmartDefaultFixedLengthSequence(value, defaults) else: return defaults if _is_iterable(value): if defaults is _NoDefault or _is_iterable(defaults): return _SmartDefaultSequence(value, defaults) else: return defaults elif isinstance(value, Mapping): if defaults is _NoDefault or isinstance(defaults, Mapping): return _SmartDefaultMapping(value, defaults) else: return defaults elif isclass(value) or callable(value): return RequiredArg if defaults is _NoDefault else defaults else: return value if defaults is _NoDefault else defaults
def __call__(self, sequence): """Called when the value is set.""" if not _is_iterable(sequence): raise TypeConversionError( "Expected a sequence like instance. Received {} of type {}." "".format(sequence, type(sequence))) else: new_sequence = [] try: for i, (v, c) in enumerate(zip(sequence, self)): new_sequence.append(c(v)) except (TypeConversionError) as err: raise TypeConversionError("In list item number {}: {}" "".format(i, str(err))) return new_sequence
def _validate_and_split_len_one(self, key): """Validate single type keys. Accepted input is a type string, and arbitrarily nested interators that culminate in str types. """ if isinstance(key, str): return [key] elif _is_iterable(key): keys = [] for k in key: keys.extend(self._validate_and_split_len_one(k)) return keys else: raise KeyError("The key {} is not valid.".format(key))
def _validate(self, sequence): """Called when the value is set.""" if not _is_iterable(sequence): raise TypeConversionError( f"Expected a sequence like instance. Received {sequence} of " f"type {type(sequence)}.") else: new_sequence = [] try: for i, v in enumerate(sequence): new_sequence.append(self.converter(v)) except (ValueError, TypeError) as err: raise TypeConversionError( f"In list item number {i}: {str(err)}") from err return new_sequence
def __call__(self, sequence): """Called when the value is set.""" if not _is_iterable(sequence): raise TypeConversionError( "Expected a tuple like object. Received {} of type {}." "".format(sequence, type(sequence))) elif len(sequence) != len(self.converter): raise TypeConversionError( "Expected exactly {} items. Received {}.".format( len(self.converter), len(sequence))) else: new_sequence = [] try: for i, (v, c) in enumerate(zip(sequence, self)): new_sequence.append(c(v)) except (TypeConversionError) as err: raise TypeConversionError("In tuple item number {}: {}" "".format(i, str(err))) return tuple(new_sequence)
def _validate(self, sequence): """Called when the value is set.""" if not _is_iterable(sequence): raise TypeConversionError( f"Expected a tuple like object. Received {sequence} of type " f"{type(sequence)}.") elif len(sequence) != len(self.converter): raise TypeConversionError( f"Expected exactly {len(self.converter)} items. Received " f"{len(sequence)}.") else: new_sequence = [] try: for i, (v, c) in enumerate(zip(sequence, self)): new_sequence.append(c(v)) except (ValueError, TypeError) as err: raise TypeConversionError( f"In tuple item number {i}: {str(err)}") from err return tuple(new_sequence)
def to_type_converter(value): """The function to use for creating a structure of `TypeConverter` objects. This is the function to use when defining validation not any of the `TypeConverter` subclasses. .. code-block:: python # list take a list of tuples of 3 floats each validation = to_type_converter( {'str': str, 'list': [(float, float, float)]}) """ if isinstance(value, tuple): return TypeConverterFixedLengthSequence(value) if _is_iterable(value): return TypeConverterSequence(value) elif isinstance(value, Mapping): return TypeConverterMapping(value) else: return TypeConverterValue(value)
def is_good_iterable(obj): """Returns True if object is iterable with respect to types.""" return _is_iterable(obj) and has_str_elems(obj)