Example #1
0
    def append(self, *args):
        """
        Adds a coordinate or coordinate array to the geometry.
        Valid objects are another ``ShapeBuilder`` instance, an ArcPy ``Point`` or ``Array`` instance,
        or numeric X, Y, (Z, M, ID) values.

        :param args:        A valid coordinate object.
        :type args:         float, int, arcpy.Point, arcpy.Array, ShapeBuilder
        :raises ValueError: If the coordinate object is invalid and cannot be added.

        .. seealso::    https://desktop.arcgis.com/en/arcmap/latest/analyze/arcpy-classes/point.htm
        """
        value = tuple(_iter.collapse(args, levels=1))
        try:
            if len(value) == 1:
                # User can add Point, Array or ShapeBuilder objects
                coord = _iter.first(value)
                if isinstance(coord, (ShapeBuilder, _arcpy.Array)):
                    self._arr.append(coord)
                    self._num_coords += coord.num_coords if hasattr(
                        coord, 'num_coords') else len(coord)
                    return
            elif 2 <= len(value) <= 5:
                # User can add up to 5 values (X, Y, Z, M, ID)
                coord = _arcpy.Point(*value)
            else:
                raise ValueError('Cannot add coordinate object {}'.format(
                    _tu.to_repr(value)))
            self._arr.append(coord)
            self._num_coords += 1
        except (RuntimeError, ValueError) as e:
            # User tried to add something invalid
            raise ValueError(e)
Example #2
0
 def _set_attrs(self, attributes):
     """ Checks and fixes all attribute names. """
     out_attrs = []
     for attr_name in _iter.collapse(attributes):
         attr_name = self._fix_attr(attr_name).lower()
         _vld.raise_if(attr_name in self._blacklist, ValueError,
                       'Field name {!r} shadows built-in name'.format(attr_name))
         _vld.raise_if(attr_name in out_attrs, ValueError, 'Field names must be unique')
         out_attrs.append(attr_name)
     return tuple(out_attrs)
Example #3
0
 def _check_values(self, values, min_required, operator):
     """ Flattens the IN/BETWEEN query values, performs several checks, and returns the list if ok. """
     output = [v for v in _iter.collapse(values, levels=1)]
     _vld.pass_if(
         len(output) >= min_required, ValueError,
         '{} query requires at least {} value'.format(
             operator, min_required))
     _vld.pass_if(
         self._check_types(*output), ValueError,
         '{} query values must have similar data types'.format(operator))
     return output
Example #4
0
def get_bucket_class(field_names, writable=True):
    """
    Factory function to obtain a :class:`FrozenBucket` or a :class:`Bucket` container class.

    The function instantiates a :class:`BucketFactory` and calls its `get_bucket_class` method.

    :param field_names: An iterable of field names for which to create a bucket class.
    :param writable:    If ``False`` (default = ``True``), a :class:`FrozenBucket` type will be returned.
                        By default, a :class:`Bucket` type will be returned.
    :type field_names:  iterable
    :type writable:     bool
    :rtype:             type

    In theory, you could immediately instantiate the returned bucket class.
    This is okay for a single bucket, but considered bad practice if you do this consecutively (e.g. in a loop).
    For example, it's fine if you do this once:

        >>> my_bucket = get_bucket_class(['field1', 'field2'])(1, 2)
        >>> print(my_bucket)
        Bucket(field1=1, field2=2)

    However, if you need to reuse the bucket class to instantiate multiple buckets, this is better:

        >>> fields = ('Field-With-Dash', 'UPPERCASE_FIELD')
        >>> bucket_cls = get_bucket_class(fields, writable=False)
        >>> for i in range(3):
        >>>     print(bucket_cls(i, i+1))
        FrozenBucket(field_with_dash=0, uppercase_field=1)
        FrozenBucket(field_with_dash=1, uppercase_field=2)
        FrozenBucket(field_with_dash=2, uppercase_field=3)

    .. seealso::    :class:`BucketFactory`, :class:`Bucket`, :class:`FrozenBucket`
    """
    # Input validation
    _vld.raise_if(field_names == _tu.ASTERISK, NotImplementedError,
                  "{} does not support {!r} as 'field_names' attribute".format(get_bucket_class.__name__, _tu.ASTERISK))
    _vld.pass_if(_vld.is_iterable(field_names), TypeError, "'field_names' attribute must be an iterable")

    rec_fields = _iter.collapse(field_names, levels=1)
    return BucketFactory(rec_fields).get_bucket_class(writable)
Example #5
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)))