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
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)
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())
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)
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))
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 _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