def test_istext(): assert validate.is_text('test') is True assert validate.is_text('123') is True assert validate.is_text('') is True assert validate.is_text('', False) is False assert validate.is_text(None) is False assert validate.is_text(True) is False assert validate.is_text(' ') is True assert validate.is_text(' ', False) is True assert validate.is_text(1) is False
def unquote(text: str) -> str: """ Strips trailing quotes from a text string and returns it. :param text: The string to strip. """ _vld.pass_if(_vld.is_text(text), TypeError, "'text' attribute must be a string (got {!r})".format(text)) return text.strip('\'"`')
def capitalize(text: str) -> str: """ Function that works similar to the built-in string method :func:`str.capitalize`, except that it only makes the first character uppercase, and leaves the other characters unchanged. :param text: The string to capitalize. """ _vld.pass_if(_vld.is_text(text), TypeError, "'text' attribute must be a string (got {!r})".format(text)) if len(text) < 2: return text.upper() return f'{text[0].upper()}{text[1:]}'
def __init__(self, path, base=None): _vld.pass_if(_vld.is_text(path, False), TypeError, "Attribute 'path' should be a non-empty string") self._path = _os.path.normpath(path) if base: _vld.raise_if( _os.path.isabs(self._path), ValueError, f'{self.__class__.__name__} expects a relative path when root has been set' ) self._path = get_abs(self._path, base) self._head, self._tail = _os.path.split(self._path) self._end, self._ext = _os.path.splitext(self._tail)
def get_alphachars(text: str) -> str: """ Returns all alphabetic characters [a-zA-Z] in string *text* in a new (concatenated) string. Example: >>> get_alphachars('Test123') 'Test' :param text: The string to search. """ _vld.pass_if(_vld.is_text(text), TypeError, "'text' attribute must be a string (got {!r})".format(text)) return _const.CHAR_EMPTY.join(s for s in text if s.isalpha())
def walk(node, level): if (((levels is not None) and (level > levels)) or _vld.is_text(node) or ((base_type is not None) and isinstance(node, base_type))): yield node return try: tree = iter(node) except TypeError: yield node return else: for child in tree: for v in walk(child, level + 1): yield v
def _parse(self, plan, user_prefix): """ Parses the plan, sets the plan parameters and validates them. """ _vld.pass_if(_vld.is_text(plan, False), ValueError, "'plan' argument must be a string") parts = plan.upper().split(self.__PLAN_SEP) self._gpn = _tu.get_alphachars(parts[-1]) self._num = _tu.get_digits(parts[-1]) _vld.pass_if(self._gpn, ValueError, "'plan' argument must start with one or more characters (e.g. 'PW')") _vld.pass_if(self._num, ValueError, "'plan' argument must contain a number") if int(self._num) >= 1000: self._pfx = user_prefix + self.__PLAN_SEP
def get_digits(text: str) -> str: """ Returns all numeric characters (digits) in string *text* in a new (concatenated) **string**. Example: >>> get_digits('Test123') '123' >>> int(get_digits('The answer is 42')) 42 :param text: The string to search. """ _vld.pass_if(_vld.is_text(text), TypeError, "'text' attribute must be a string (got {!r})".format(text)) return _const.CHAR_EMPTY.join(s for s in text if s.isdigit())
def __init__(self, where_field, operator=None, *values): self._locked = False self._fields = {} self._parts = [] if _vld.is_text(where_field, False) and operator: self._fields.setdefault(where_field.lower(), [0]) self._parts.append(where_field) self._add_expression(operator, *values) elif isinstance(where_field, self.__class__): # When `where_field` is another Where instance, simply wrap its contents in parentheses self._update_fieldmap(where_field._fields, 1) self._parts = ['('] + where_field._parts + [')'] elif where_field is not None: raise InitError( '{0} expects a field name and an operator, or another {0} instance' .format(Where.__name__))
def _check_types(*args): """ Checks that all query values have compatible data types. Applies to IN and BETWEEN operators. """ # Check that none of the arguments are of type 'object' (this breaks the type check) _vld.raise_if( any(v.__class__ is object for v in args), ValueError, 'Values of type object are not allowed in IN and BETWEEN queries') # Get the first value and get its type sample_val = args[0] sample_type = type(sample_val) # Allow for some flexibility concerning numbers and strings if _vld.is_number(sample_val, True): # For now, we will allow a mixture of floats and integers (and bools) in the list of values sample_type = int, float, bool elif _vld.is_text(sample_val): # Allow str and unicode (basestring type sometimes fails with isinstance) sample_type = str, unicode return all(isinstance(v, sample_type) for v in args)
def format_plural(word, number, plural_suffix='s'): """ Function that prefixes `word` with `number` and appends `plural_suffix` to it if `number` <> 1. Note that this only works for words with simple conjugation (where the base word and suffix do not change). E.g. words like 'sheep' or 'life' will be falsely pluralized ('sheeps' and 'lifes' respectively). Examples: >>> format_plural('{} error', 42) '42 errors' >>> format_plural('{} bus', 99, 'es') '99 buses' >>> format_plural('{} goal', 1) '1 goal' >>> format_plural('{} regret', 0) '0 regrets' :param word: The word that should be pluralized if `number` <> 1. :param number: The numeric value for which `word` will be prefixed and pluralized. :param plural_suffix: If `word` is a constant and the `plural_suffix` for it cannot be 's', set your own. :type word: str, unicode :type number: int, float :type plural_suffix: str, unicode :rtype: str, unicode """ # Argument validation _vld.pass_if(_vld.is_number(number), TypeError, "'number' attribute must be numeric") _vld.pass_if(_vld.is_text(word, False), TypeError, "'word' attribute must be a non-empty string") _vld.pass_if(word[-1].isalpha(), ValueError, "'word' must end with an alphabetic character") if number == 1: plural_suffix = EMPTY_STR return type(word)(EMPTY_STR).join( (str(number), SPACE, word, plural_suffix))
def _format_value(value): """ Private method to format *value* for use in an SQL expression based on its type. This basically means that all non-numeric values will be quoted. If value is a :class:`gpf.common.guids.Guid` string, the result will be wrapped in curly braces and quoted. :param value: Any value. Single quotes in strings will be escaped automatically. :return: A formatted string. :rtype: str, unicode """ if _vld.is_number(value, True): # Note: a `bool` is of instance `int` but calling format() on it will return a string (True or False) # To prevent this from happening, we'll use the `real` numeric value instead (on int, float and bool) return format(value.real) elif _vld.is_text(value): try: return repr(str(_guids.Guid(value))) except (_guids.Guid.MissingGuidError, _guids.Guid.BadGuidError): return _tu.to_repr(value) raise TypeError( 'All values in an SQL expression must be of type str, bool, int or float' )
def _fix_values(self, *values, **kwargs): """ Private method to validate *values* for use in an SQL expression. All values, regardless if they are iterables themselves, will be flattened (up to 1 level). If the values do not have comparable types (i.e. all numeric, all strings), a ``TypeError`` will be raised. :param values: An iterable (of iterables) with values to use for the SQL expression. :keyword check_only: When False (default=True), values will be sorted and duplicates will be removed. Furthermore, the returned values will be formatted for the SQL expression. When True, the values will only be flattened and checked for comparable types. :return: A generator of checked (and formatted) values. """ _vld.pass_if( values, OperatorError, 'Specified {} operator requires at least one value'.format( Where.__name__)) values = [v for v in _iter.collapse(values, levels=1)] unique_values = frozenset(values) first_val = _iter.first(unique_values) if _vld.is_number(first_val, True): # For now, allow a mixture of floats and integers (and bools) in the list of values # TODO: When input field is an arcpy.Field instance, filter by field.type first_type = (int, float, bool) elif _vld.is_text(first_val): first_type = (str, unicode) else: first_type = type(first_val) _vld.raise_if( any(not isinstance(v, first_type) for v in unique_values), TypeError, 'All {} values must have the same data type'.format( Where.__name__)) check_only = kwargs.get(_CHECK_ARG, False) return (v if check_only else self._format_value(v) for v in (values if check_only else sorted(unique_values)))
def _format_value(self, value): """ Private method to format *value* for use in an SQL expression based on its type. This basically means that all non-numeric values (strings) will be quoted. If value is a :class:`gpf.common.guids.Guid` instance, the result will be wrapped in curly braces and quoted. :param value: Any value. Single quotes in strings will be escaped automatically. :return: A formatted string. :rtype: unicode """ if _vld.is_number(value, True): # Note: a `bool` is of instance `int` but calling format() on it will return a string (True or False). # To prevent this from happening, we'll use the `real` numeric part instead (on int, float and bool). return _tu.to_unicode(value.real, self._enc) if isinstance(value, _guids.Guid): # Parse Guid instances as strings value = str(value) if _vld.is_text(value): return _tu.to_unicode(_tu.to_repr(value, self._enc), self._enc) raise ValueError( 'All values in an SQL expression must be text strings or numeric values' )
def func_wrapper(self, *args): args = (x.upper() if _vld.is_text(x) else x for x in args) return func[-1](self, *args)