Skip to content

cursor

Cursor Helper module

Classes:

Name Description
Field

Field Representation

InsertOptions

Optional parameters for InsertCursors

SQLClause

Wrapper for Cursor sql_clause attribute,

SearchOptions

Optional parameters for SearchCursors

UpdateOptions

Optional parameters for UpdateCursors

WhereClause

Wraps a string clause to signal to FeatureClass/Table indexes that a Where Clause is being passed

Functions:

Name Description
convert_field

Convert an arcpy Field object to a Field argument dictionary

get_field_type

Convert a field type flag from a describe arcpy.Field to arguments for AddField

Attributes:

Name Type Description
EditToken
FeatureToken
FeatureTokens tuple[FeatureToken, ...]
FieldType
GeneralToken
GeometryType
ShapeToken
TableToken
TableTokens tuple[TableToken, ...]

EditToken = Literal['CREATED@', 'CREATOR@', 'EDITED@', 'EDITOR@'] module-attribute

FeatureToken = Literal[TableToken | ShapeToken] module-attribute

FeatureTokens = FeatureToken.__args__ module-attribute

FieldType = Literal['SHORT', 'LONG', 'BIGINTEGER', 'FLOAT', 'DOUBLE', 'TEXT', 'DATE', 'DATEHIGHPRECISION', 'DATEONLY', 'TIMEONLY', 'TIMESTAMPOFFSET', 'BLOB', 'GUID', 'RASTER'] module-attribute

GeneralToken = Literal['ANNO@', 'GLOBALID@', 'OID@', 'SUBTYPE@'] module-attribute

GeometryType = Geometry | Polygon | PointGeometry | Polyline | Multipoint | Multipatch module-attribute

ShapeToken = Literal['SHAPE@', 'SHAPE@XY', 'SHAPE@XYZ', 'SHAPE@TRUECENTROID', 'SHAPE@X', 'SHAPE@Y', 'SHAPE@Z', 'SHAPE@M', 'SHAPE@JSON', 'SHAPE@WKB', 'SHAPE@WKT', 'SHAPE@AREA', 'SHAPE@LENGTH'] module-attribute

TableToken = Literal[GeneralToken | EditToken] module-attribute

TableTokens = TableToken.__args__ module-attribute

Field

Bases: TypedDict

Field Representation

Attributes:

Name Type Description
field_type FieldType

The type of the field (required)

field_precision int

The precision (digits) of numeric fields (default: database determined)

field_scale int

The number of decimal places for floating point fields (default: database determined)

field_length int

The maximum character count for TEXT fields (default: 255)

field_alias str

Human readable alias for fields with confusing internal names (optional)

field_is_nullable bool

Allow null values (default: True)

field_is_required bool

Field requires a value to be set (default: False)

field_domain str

Existing Domain name to bind to field (optional)

Source code in src/arcpie/cursor.py
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
class Field(TypedDict, total=False):
    """Field Representation

    Attributes:
        field_type (FieldType): The type of the field (required)
        field_precision (int): The precision (digits) of numeric fields (default: database determined)
        field_scale (int): The number of decimal places for floating point fields (default: database determined)
        field_length (int): The maximum character count for `TEXT` fields (default: 255)
        field_alias (str): Human readable alias for fields with confusing internal names (optional)
        field_is_nullable (bool): Allow null values (default: `True`)
        field_is_required (bool): Field requires a value to be set (default: False)
        field_domain (str): Existing Domain name to bind to field (optional)
    """
    field_type: FieldType
    field_precision: int
    field_scale: int
    field_length: int
    field_alias: str
    field_is_nullable: Literal['NULLABLE', 'NON_NULLABLE']
    field_is_required: Literal['REQUIRED', 'NON_REQUIRED']
    field_domain: str

field_alias instance-attribute

field_domain instance-attribute

field_is_nullable instance-attribute

field_is_required instance-attribute

field_length instance-attribute

field_precision instance-attribute

field_scale instance-attribute

field_type instance-attribute

InsertOptions

Bases: TypedDict

Optional parameters for InsertCursors

Attributes:

Name Type Description
datum_transformation str | None
explicit bool
Source code in src/arcpie/cursor.py
191
192
193
194
class InsertOptions(TypedDict, total=False):
    """Optional parameters for InsertCursors"""
    datum_transformation: str | None
    explicit: bool

datum_transformation instance-attribute

explicit instance-attribute

SQLClause

Bases: NamedTuple

Wrapper for Cursor sql_clause attribute,

Attributes:

Name Type Description
prefix str

The SQL prefix to be prepended to the FROM part of the statment

postfix str

The SQL postfix that will be appended to the WHERE clause

Format
SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}
Usage
>>> five_longest = SQLClause(prefix='TOP 5', postfix='ORDER BY LENGTH DESC')
>>> fc_result = feature_class.get_tuples(('NAME', 'LENGTH'), sql_clause=five_longest))
>>> print(list(fc_result))
[('foo', 1001), ('bar', 999), ('baz', 567), ('buzz', 345), ('bang', 233)]
Source code in src/arcpie/cursor.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
class SQLClause(NamedTuple):
    """Wrapper for Cursor sql_clause attribute,

    Attributes:
        prefix (str): The SQL prefix to be prepended to the `FROM` part of the statment
        postfix (str): The SQL postfix that will be appended to the `WHERE` clause

    Format:
        ```sql
        SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}
        ```

    Usage:
        ```python
        >>> five_longest = SQLClause(prefix='TOP 5', postfix='ORDER BY LENGTH DESC')
        >>> fc_result = feature_class.get_tuples(('NAME', 'LENGTH'), sql_clause=five_longest))
        >>> print(list(fc_result))
        [('foo', 1001), ('bar', 999), ('baz', 567), ('buzz', 345), ('bang', 233)]
        ```
    """
    prefix: str|None
    postfix: str|None

postfix instance-attribute

prefix instance-attribute

SearchOptions

Bases: TypedDict

Optional parameters for SearchCursors

Attributes:

Name Type Description
where_clause str

A SQL query that is inserted after the SQL WHERE (SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}...)

spatial_reference str | int | SpatialReference

Perform an on the fly projection of the yielded geometry to this reference

explode_to_points bool

Return a row per vertex in each feature (e.g. [SHAPE, 'eric', 'idle'] -> [Point, 'eric', 'idle'], [Point, 'eric', 'idle'], ...)

sql_clause SQLClause

A tuple of SQL queries that is inserted after the SQL SELECT and WHERE clauses (SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}...)

datum_transformation str

The transformation to use during projection if there is a datum difference between the feature projection and the target SpatialReference (you can use arcpy.ListTransformations to find valid transformations)

spatial_filter Geometry

A shape that will be used to test each feature against using the specified spatial_relationship ('INTERSECTS') by default.

spatial_relationship SpatialRelationship

The type of relationship with the spatial_filter to test for in each row. Only rows with shapes that match this relationship will be yielded.

search_order SearchOrder

Run the where_clause {sql_clause} ('ATTRIBUTEFIRST' default) or spatial_filter ('SPATIALFIRST') first. This can be used to optimize a cursor. If you have a complex where_clause, consider switching to 'SPATIALFIRST' to cut down on the number of records that the where_clause runs for. These two operations are done as seperate SQL operations and JOINED in the result

Returns:

Type Description
dict

A dictionary with the populated keys

Usage
>>> options = SearchOptions(where_clause='OBJECTID > 10')
>>> not_first_ten = feature_class.get_tuples(['NAME', 'LENGTH'], **options)
>>> print(list(not_first_ten))
[('cleese', 777), ('idle', 222), ('gilliam', 111), ...]
Source code in src/arcpie/cursor.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
class SearchOptions(TypedDict, total=False):
    """Optional parameters for SearchCursors

    Attributes:
        where_clause (str): A SQL query that is inserted after the SQL `WHERE` (`SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}...`)
        spatial_reference (str | int | SpatialReference): Perform an on the fly projection of the yielded geometry to this reference
        explode_to_points (bool): Return a row per vertex in each feature (e.g. `[SHAPE, 'eric', 'idle'] -> [Point, 'eric', 'idle'], [Point, 'eric', 'idle'], ...`)
        sql_clause (SQLClause): A tuple of SQL queries that is inserted after the SQL 
            `SELECT` and `WHERE` clauses (`SELECT {prefix} {fields} FROM {table} WHERE {where_clause} {postfix}...`)
        datum_transformation (str): The transformation to use during projection if there is a datum difference between the feature projection and the 
            target SpatialReference (you can use `arcpy.ListTransformations` to find valid transformations)
        spatial_filter (Geometry): A shape that will be used to test each feature against using the specified `spatial_relationship` (`'INTERSECTS'`)
            by default.
        spatial_relationship (SpatialRelationship): The type of relationship with the `spatial_filter` to test for in each row. Only rows with shapes
            that match this relationship will be yielded.
        search_order (SearchOrder): Run the `where_clause {sql_clause}` (`'ATTRIBUTEFIRST'` default) or `spatial_filter` (`'SPATIALFIRST'`) first.
            This can be used to optimize a cursor. If you have a complex `where_clause`, consider switching to `'SPATIALFIRST'` to cut down on the number
            of records that the `where_clause` runs for. These two operations are done as seperate SQL operations and `JOINED` in the result

    Returns:
        ( dict ): A dictionary with the populated keys

    Usage:
        ```python
        >>> options = SearchOptions(where_clause='OBJECTID > 10')
        >>> not_first_ten = feature_class.get_tuples(['NAME', 'LENGTH'], **options)
        >>> print(list(not_first_ten))
        [('cleese', 777), ('idle', 222), ('gilliam', 111), ...]
        ```
    """
    where_clause: str
    spatial_reference: str | int | SpatialReference
    explode_to_points: bool
    sql_clause: SQLClause
    datum_transformation: str
    spatial_filter: GeometryType | Extent
    spatial_relationship: SpatialRelationship
    search_order: SearchOrder

datum_transformation instance-attribute

explode_to_points instance-attribute

search_order instance-attribute

spatial_filter instance-attribute

spatial_reference instance-attribute

spatial_relationship instance-attribute

sql_clause instance-attribute

where_clause instance-attribute

UpdateOptions

Bases: TypedDict

Optional parameters for UpdateCursors

Attributes:

Name Type Description
datum_transformation str | None
explicit bool
explode_to_points bool
search_order SearchOrder
spatial_filter GeometryType | Extent
spatial_reference str | int | SpatialReference
spatial_relationship SpatialRelationship
sql_clause SQLClause
where_clause str
Source code in src/arcpie/cursor.py
196
197
198
199
200
201
202
203
204
205
206
207
208
class UpdateOptions(TypedDict, total=False):
    """Optional parameters for UpdateCursors"""
    where_clause: str
    spatial_reference: str | int | SpatialReference
    explode_to_points: bool
    sql_clause: SQLClause
    #skip_nulls: bool
    #null_value: dict[str, Any]
    datum_transformation: str | None
    explicit: bool
    spatial_filter: GeometryType | Extent
    spatial_relationship: SpatialRelationship
    search_order: SearchOrder

datum_transformation instance-attribute

explicit instance-attribute

explode_to_points instance-attribute

search_order instance-attribute

spatial_filter instance-attribute

spatial_reference instance-attribute

spatial_relationship instance-attribute

sql_clause instance-attribute

where_clause instance-attribute

WhereClause

Wraps a string clause to signal to FeatureClass/Table indexes that a Where Clause is being passed

Methods:

Name Description
__init__

Object for storing and validating where clauses

__repr__
get_fields

Sanitize a where clause by removing whitespace

validate

Check to see if the clause fields are in the fields list

Attributes:

Name Type Description
fields
skip_validation
where_clause
Source code in src/arcpie/cursor.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
class WhereClause:
    """Wraps a string clause to signal to FeatureClass/Table indexes that a Where Clause is being passed"""

    def __init__(self, where_clause: str, skip_validation: bool=False) -> None:
        """Object for storing and validating where clauses

        Args:
            where_clause (str): The where clause that you want to pass to a FeatureClass
            skip_validation (bool): Skip the validation step (default: False)
        """
        if '@' in where_clause:
            raise AttributeError(
                '`@` Parameters/Tokens not supported in WhereClauses, Please use full fieldname'
            )
        self.where_clause = where_clause
        self.fields = self.get_fields(where_clause)
        self.skip_validation = skip_validation

    def __repr__(self) -> str:
        return self.where_clause

    def get_fields(self, clause: str) -> Sequence[str]:
        """Sanitize a where clause by removing whitespace"""

        #    -0-     1    2      3      -4-      5    6
        # '<FIELD> <OP> <VAL> <AND/OR> <FIELD> <OP> <VAL> ...'
        # A properly structured WhereClause should have a field
        # as every 4th token split on spaces

        # CAVEAT: Parens and whitespace
        # This comprehension drops individual parens, replaces ', ' with ','
        # and finds all field components

        # TODO: This needs thorough testing
        return [
            fld.strip().replace('(', '').replace(')', '')
            for fld in [
                tok for tok in
                clause.replace(', ', ',').split()
                if tok not in '()'
            ][::4]
        ]

    def validate(self, fields: Sequence[str]) -> bool:
        """Check to see if the clause fields are in the fields list

        Args:
            fields (Sequence[str]): The fields to check against
        """
        return self.skip_validation or set(self.fields) <= set(fields)

fields = self.get_fields(where_clause) instance-attribute

skip_validation = skip_validation instance-attribute

where_clause = where_clause instance-attribute

__init__(where_clause, skip_validation=False)

Object for storing and validating where clauses

Parameters:

Name Type Description Default
where_clause str

The where clause that you want to pass to a FeatureClass

required
skip_validation bool

Skip the validation step (default: False)

False
Source code in src/arcpie/cursor.py
80
81
82
83
84
85
86
87
88
89
90
91
92
93
def __init__(self, where_clause: str, skip_validation: bool=False) -> None:
    """Object for storing and validating where clauses

    Args:
        where_clause (str): The where clause that you want to pass to a FeatureClass
        skip_validation (bool): Skip the validation step (default: False)
    """
    if '@' in where_clause:
        raise AttributeError(
            '`@` Parameters/Tokens not supported in WhereClauses, Please use full fieldname'
        )
    self.where_clause = where_clause
    self.fields = self.get_fields(where_clause)
    self.skip_validation = skip_validation

__repr__()

Source code in src/arcpie/cursor.py
95
96
def __repr__(self) -> str:
    return self.where_clause

get_fields(clause)

Sanitize a where clause by removing whitespace

Source code in src/arcpie/cursor.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def get_fields(self, clause: str) -> Sequence[str]:
    """Sanitize a where clause by removing whitespace"""

    #    -0-     1    2      3      -4-      5    6
    # '<FIELD> <OP> <VAL> <AND/OR> <FIELD> <OP> <VAL> ...'
    # A properly structured WhereClause should have a field
    # as every 4th token split on spaces

    # CAVEAT: Parens and whitespace
    # This comprehension drops individual parens, replaces ', ' with ','
    # and finds all field components

    # TODO: This needs thorough testing
    return [
        fld.strip().replace('(', '').replace(')', '')
        for fld in [
            tok for tok in
            clause.replace(', ', ',').split()
            if tok not in '()'
        ][::4]
    ]

validate(fields)

Check to see if the clause fields are in the fields list

Parameters:

Name Type Description Default
fields Sequence[str]

The fields to check against

required
Source code in src/arcpie/cursor.py
120
121
122
123
124
125
126
def validate(self, fields: Sequence[str]) -> bool:
    """Check to see if the clause fields are in the fields list

    Args:
        fields (Sequence[str]): The fields to check against
    """
    return self.skip_validation or set(self.fields) <= set(fields)

convert_field(arc_field)

Convert an arcpy Field object to a Field argument dictionary

Parameters:

Name Type Description Default
arc_field Field

The Field object returned by Describe().fields

required

Returns:

Type Description
Field

A Field argument dictionary that can be used to construct a new field

Source code in src/arcpie/cursor.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
def convert_field(arc_field: ArcField) -> Field:
    """Convert an arcpy Field object to a Field argument dictionary

    Args:
        arc_field (arcpy.Field): The Field object returned by Describe().fields

    Returns:
        (Field): A Field argument dictionary that can be used to construct a new field
    """
    return Field(
        field_type=get_field_type(arc_field.type),
        field_precision=arc_field.precision,
        field_scale=arc_field.scale,
        field_length=arc_field.length,
        field_alias=arc_field.aliasName,
        field_is_nullable='NULLABLE' if arc_field.isNullable else 'NON_NULLABLE',
        field_is_required='REQUIRED' if arc_field.required else 'NON_REQUIRED',
        field_domain=arc_field.domain,
    )

get_field_type(arc_field_type, *, strict=False)

Convert a field type flag from a describe arcpy.Field to arguments for AddField

Parameters:

Name Type Description Default
arc_field_type FieldType

The field type as reported by arcpy.Describe(...).fields

required
strict bool

Raise a ValueError if this is set to True, otherwise assume TEXT

False

Returns:

Type Description
FieldType

(FieldType)

Raises:

Type Description
ValueError

If strict flag is set and the input type is unmapped

Source code in src/arcpie/cursor.py
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
def get_field_type(arc_field_type: ArcFieldType, *, strict: bool=False) -> FieldType:
    """Convert a field type flag from a describe arcpy.Field to arguments for AddField

    Args:
        arc_field_type (ArcFieldType): The field type as reported by arcpy.Describe(...).fields
        strict (bool): Raise a ValueError if this is set to True, otherwise assume `TEXT`

    Returns:
        (FieldType)

    Raises:
        (ValueError): If `strict` flag is set and the input type is unmapped
    """
    match arc_field_type:
        case 'BigInteger':
            return 'BIGINTEGER'
        case 'Blob':
            return 'BLOB'
        case 'Date':
            return 'DATE'
        case 'DateOnly':
            return 'DATEONLY'
        case 'Double':
            return 'DOUBLE'
        case 'Geometry': # No Passthrough
            return 'BLOB'
        case 'GlobalID': # No Passthrough
            return 'GUID'
        case 'GUID':
            return 'GUID'
        case 'Integer':
            return 'LONG'
        case 'OID':
            return 'BIGINTEGER'
        case 'Raster':
            return 'RASTER'
        case 'Single':
            return 'FLOAT'
        case 'SmallInteger':
            return 'SHORT'
        case 'String':
            return 'TEXT'
        case 'TimeOnly':
            return 'TIMEONLY'
        case 'TimestampOffset':
            return 'TIMESTAMPOFFSET'
        case _:
            if strict:
                raise ValueError()
            return 'TEXT'