示例#1
0
def test_isnumber():
    assert validate.is_number(3.14) is True
    assert validate.is_number(0) is True
    assert validate.is_number(False) is False
    assert validate.is_number(True) is False
    assert validate.is_number(False, True) is True
    assert validate.is_number(True, True) is True
    assert validate.is_number('test') is False
    assert validate.is_number(None) is False
    assert validate.is_number(Decimal('0.123456789')) is True
示例#2
0
def get_xyz(*args) -> _tp.Tuple[float]:
    """
    Returns a floating point coordinate XYZ tuple for a given coordinate.
    Valid input includes EsriJSON, ArcPy Point or PointGeometry instances or a minimum of 2 floating point values.
    If the geometry is not Z aware, the Z value in the output tuple will be set to ``None``.

    :param args:    A tuple of floating point values, an EsriJSON dictionary, an ArcPy Point or PointGeometry instance.

    .. note::       For Point geometries, M and ID values are ignored.
    """
    p_args = args

    if len(args) == 1:
        a = _iter.first(args)

        # Unfortunately, we can't really rely on isinstance() to check if it's a PointGeometry or Point.
        # However, if it's a PointGeometry, it must have a pointCount attribute with a value of 1.
        if getattr(a, 'pointCount', 0) == 1:
            # Get first Point from PointGeometry...
            a = a.firstPoint

        if hasattr(a, 'X') and hasattr(a, 'Y'):
            # Get X, Y and Z properties from Point
            p_args = a.X, a.Y, a.Z
        elif isinstance(a, dict):
            # Assume argument is JSON(-like) input: read x, y and z keys
            p_args = tuple(v for k, v in sorted(a.items()) if k.lower() in ('x', 'y', 'z'))
            # Validate values
            for a in p_args:
                _vld.pass_if(_vld.is_number(a), ValueError, 'Failed to parse coordinate from JSON'.format(args))
        else:
            raise ValueError('Input is not a Point, PointGeometry, JSON dictionary or iterable of float')

    return tuple(_fix_coord(*p_args, dim=3))
示例#3
0
    def _check_types(*args) -> bool:
        """ 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,
            f'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
        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)

        return all(isinstance(v, sample_type) for v in args)
示例#4
0
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))
示例#5
0
    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'
        )
示例#6
0
    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)))
示例#7
0
文件: queries.py 项目: geocom-gis/gpf
    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'
        )