Beispiel #1
0
    def _add_expression(self, operator, *values):
        """
        Private method to properly complete an SQL expression for the initial field.
        The current internal SQL expression will be permanently changed.
        Explicit consecutive calls to this function will raise an ``OverflowError``.

        :param operator:    The operator to use (=, <>, IN etc.).
        :param values:      The value(s) following the operator.
        """
        _vld.raise_if(self._locked, OverflowError,
                      'Cannot add more than one expression to a field')

        operator = self._fix_operator(operator)
        is_between = operator.endswith(self.__SQL_BETWEEN)
        self._parts.append(operator.upper())

        if operator not in (self.__SQL_NULL, self.__SQL_NOT_NULL):
            values = self._fix_values(*values, check_only=is_between)
            if operator.endswith(self.__SQL_IN):
                self._parts.append('({})'.format(', '.join(values)))
            elif is_between:
                self._between(operator, *values)
            else:
                self._parts.append(_iter.first(values))

        self._locked = True
Beispiel #2
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)
Beispiel #3
0
def _read_curve(curve_object):
    """
    Extracts a tuple of (curve type, curve properties) from the single `curve_object` key-value pair.

    :param curve_object:    The curve object dictionary (key-value pair).
    :rtype:                 tuple
    """
    return _iter.first(curve_object.iteritems())
Beispiel #4
0
 def __init__(self, *args):
     # Because Array is an ArcObject, we cannot inherit from it the way we'd like to (raises RuntimeError).
     # We'll instantiate a new Array and store it in its own variable instead...
     self._arr = _arcpy.Array()
     self._num_coords = 0
     if args:
         try:
             self.extend(_iter.first(args))
         except ValueError:
             self.append(*args)
Beispiel #5
0
def get_xyz(*args):
    """
    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.
    :rtype:         tuple

    .. 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))
Beispiel #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)))
Beispiel #7
0
 def _get_handler(self, match_func):
     """ Returns the first handler where ``match_func(handler) is True``. """
     return _iter.first((h for h in self._log.handlers
                         if match_func(h)), None) if self._log else None