Source: https://gometry.monicz.dev/api/toplevel/io-interop/

# I/O & interop

Parse external representations, export coordinates, and build GeoJSON feature records.

**Related:** [Text & binary formats](https://gometry.monicz.dev/ecosystem/text-formats/)

## from\_arrow

```python
from_arrow(data: SupportsArrowArray | SupportsArrowStream | PyArrowArray | PyArrowChunkedArray | PyArrowTable | PyArrowRecordBatch | PyArrowRecordBatchReader, *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

Build geometries from an Arrow array, table, record batch, reader, or
Arrow-C provider. Protocol callbacks and PyArrow object inspection remain
attached; selected buffers are owned before the decoder is detached.
Arrow null slots become missing rows; typed empty geometries remain typed
empty values. Empty arrays and streams return an empty array while retaining
compatible CRS and epoch metadata when the input provides it.

Geographic literal edges are subdivided as needed for the periodic native
chart, with rounded new coordinates and affine wire Z/M interpolation.
Longitude aliases may be canonicalized. Original ordinate occurrences are
retained; exact external point incidence is not a round-trip guarantee.
Raw WKT/WKB readers retain literal coordinates without this adaptation.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `data` | `object` | A foreign PyArrow `Array`, `ChunkedArray`, `Table`, `RecordBatch`, or `RecordBatchReader`, or an object implementing `__arrow_c_array__` or `__arrow_c_stream__`. The input must use a supported GeoArrow encoding, including GeoArrow WKB. Pass the provider object itself; the capsule tuple returned by manually calling `__arrow_c_array__` is not a supported input. | *required* |
| `crs` | `str, int, or CRS-like object` | CRS to attach when the input has no embedded CRS. If embedded metadata is present, it must be operationally compatible with this value and the explicit value is retained as the result's CRS. Passing `None` does not strip compatible embedded metadata. | `None` |
| `epoch` | `numeric scalar or 0-D numeric array` | Coordinate epoch (decimal year) to attach as frame metadata. A supplied epoch must be finite and have a compatible embedded or explicit CRS; an embedded epoch is preserved when this argument is omitted. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `GeometryArray[Geometry \| None]` | Decoded geometry rows. Arrow null slots become missing `None` rows; typed empty geometries remain typed empty values. Empty input produces an empty array, retaining compatible CRS and epoch metadata when available. |

Raises:

| Type | Description |
| --- | --- |
| `CRSError` | If `crs` or an embedded EWKB SRID cannot be resolved, or `epoch` is supplied without a CRS or with a static CRS. |
| `CRSMismatchError` | If explicit CRS or epoch metadata conflicts with embedded metadata, or EWKB row SRIDs disagree. |
| `GeometryError` | If `epoch` is not finite or admitted geometry data violates a geometry invariant. |
| `ParseError` | If GeoArrow metadata, offsets, validity buffers, coordinate buffers, or WKB data are malformed, or a selected table geometry child is absent or out of range. |
| `TypeError` | If `data` is not a supported Arrow object or provider, its schema or encoding cannot be classified, it has no geometry column, a C array length or offset is negative, its `null_count` is below -1 (`-1` means unknown) or a known count exceeds the logical length, or its format-specific buffer/child layout conflicts with the schema. |
| `OSError` | If an Arrow C stream schema or batch callback returns a nonzero status other than `ENOMEM`; the callback status is exposed as `errno`. |
| `MemoryError` | If an Arrow C stream callback returns `ENOMEM`. Native Rust allocator exhaustion is process-fatal and is not translated into a Python error. |
| `OverflowError` | If a nonnegative Arrow buffer byte span cannot fit `usize` or the maximum size of a Rust slice, or accumulated row counts overflow `usize`. |

See Also

[GeometryArray.to\_arrow](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray.to_arrow "to_arrow") : Export an array as a GeoArrow array.

Examples:

```pycon
>>> import gometry as gm
>>> source = gm.points([1.0], [2.0])
>>> restored = gm.from_arrow(source.to_arrow())
>>> restored.to_wkt()
['POINT (1 2)']
```

## from\_geojson

Accepted call forms

```python
from_geojson(data: GeoJsonFeatureCollection, *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_geojson(data: GeoJsonGeometry | GeoJsonFeatureNonNull, *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_geojson(data: SupportsGeoInterface[GeoJsonGeometry], *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_geojson(data: SupportsGeoInterface[GeoJsonFeatureNonNull], *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_geojson(data: SupportsGeoInterface[GeoJsonFeatureCollection], *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_geojson(data: str | bytes | bytearray | memoryview | Mapping[str, Any] | SupportsGeoInterface, *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry | GeometryArray[Geometry | None]
```

```python
from_geojson(data: PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray | Iterable[str | bytes | bytearray | memoryview | Mapping[str, Any] | SupportsGeoInterface | None], *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_geojson(data: str | bytes | bytearray | memoryview | Mapping[str, Any] | SupportsGeoInterface | PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray | Iterable[str | bytes | bytearray | memoryview | Mapping[str, Any] | SupportsGeoInterface | None], *, features: Literal[False] = False, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry | GeometryArray[Geometry | None]
```

```python
from_geojson(data: str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | GeoJsonFeatureCollection | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | SupportsGeoInterface[GeoJsonFeatureCollection] | (Sequence[str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | Iterator[str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | Iterable[GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | ndarray[Any, dtype[Any]]) | PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray, *, features: Literal[True], crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Features
```

```python
from_geojson(data: str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | GeoJsonFeatureCollection | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | SupportsGeoInterface[GeoJsonFeatureCollection] | (Sequence[str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | Iterator[str | Buffer | GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | Iterable[GeoJsonFeature | GeoJsonFeatureNonNull | SupportsGeoInterface[GeoJsonFeature] | SupportsGeoInterface[GeoJsonFeatureNonNull] | None] | ndarray[Any, dtype[Any]]) | PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray, *, features: bool, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry | GeometryArray[Geometry | None] | Features
```

Parse GeoJSON geometry, rows, or feature metadata.

A geometry or `Feature` decodes to a `Geometry` by default; a
`FeatureCollection` decodes to a `GeometryArray` with one geometry per
feature. Set `features=True` to retain feature properties and IDs in a
`Features` result.

Coordinate sequences are **axis-uniform**: every position in one sequence
(LineString, MultiPoint member list, ring, …) must share the same axes
(all XY or all XYZ). RFC 7946 makes the third ordinate optional per
position, but gometry's coordinate model requires finite values on every
active ordinate and rejects non-finite coordinates, so mixed XY/XYZ within
one sequence is a `ParseError` rather than a silent 0-elevation fill.
Distinct members of a `GeometryCollection` may still differ in axes.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `data` | `str, mapping, row iterable, or dataframe/Arrow column` | A GeoJSON string, mapping, row iterable, or pandas/Polars Series or PyArrow Array/ChunkedArray. Feature and FeatureCollection inputs are accepted. Missing column values become missing rows. | *required* |
| `features` | `bool` | Preserve Feature properties and IDs in a `Features` result. Geometry- only inputs are not valid when this is `True`. Feature row iterables accept Feature mappings or serialized Feature text/bytes; `None` rows retain alignment with a missing geometry, missing properties, and no ID. | `varies by call form` |
| `crs` | `CRS - like` | CRS to attach. `geojson` coordinates are WGS84 by specification, so the default declares OGC:CRS84 (lon/lat, matching GeoParquet); pass `None` for a CRS-free geometry or `crs=4326` for EPSG:4326. Only the WGS84 family (`EPSG:4326`, `EPSG:4979`, `OGC:CRS84`, `OGC:CRS84h`) is accepted — reproject first for other CRS. A legacy top-level `crs` member (pre-RFC 7946) is ignored when it agrees with `crs=` and raises on conflict or unsupported declarations. | `'OGC:CRS84'` |
| `epoch` | `numeric scalar or 0-D numeric array` | Coordinate epoch (decimal year) to attach as frame metadata. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `Geometry or GeometryArray` | The decoded geometry, or one geometry per feature for a `FeatureCollection`. |
| `Features` | When `features=True`, one geometry and its aligned properties and ID per input feature. |

Raises:

| Type | Description |
| --- | --- |
| `ParseError` | If the `geojson` is malformed or an unsupported type, a coordinate sequence mixes axes (XY with XYZ), a coordinate integer is not exactly representable as binary64, a `bbox`, Feature `properties` or `id` is malformed, a Python mapping contains non-JSON data, or a legacy `crs` member is unsupported or conflicts with `crs`, a position is outside the WGS84 domain, or a ring fails structural admission (`format` is `"geojson"`). |
| `CRSError` | If `crs` is not a recognized CRS or is outside the WGS84 family, or `epoch` is set with `crs=None`. |
| `GeometryError` | If `epoch` is not a finite decimal year. |

Notes

Finite decimals parse as correctly-rounded binary64 (bit-exact round-trip
with `to_geojson`). Integer tokens and Python `int` values are admitted
only when exactly representable as `float`; non-exact integers raise
rather than silently rounding. Text and mapping inputs share this rule.
Dataframe and Arrow columns are converted to their native Python row values
before the same decoder runs.


See Also

[Geometry.to\_geojson](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.to_geojson "to_geojson") : Serialize a geometry to GeoJSON.
[Features](https://gometry.monicz.dev/api/results/#gometry.Features "Features") : The aligned feature properties and IDs returned by
`features=True`.

Examples:

```pycon
>>> import gometry as gm
>>> gm.from_geojson('{"type": "Point", "coordinates": [1, 2]}').to_wkt()
'POINT (1 2)'
```

## from\_polyline

Accepted call forms

```python
from_polyline(data: str, *, precision: int = 5, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Point | LineString
```

```python
from_polyline(data: PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray, *, precision: int = 5, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Point | LineString | None]
```

```python
from_polyline(data: Iterable[str], *, precision: int = 5, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Point | LineString]
```

```python
from_polyline(data: Iterable[str | None], *, precision: int = 5, crs: CrsInput | None = 'OGC:CRS84', epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Point | LineString | None]
```

Decode polyline text into `LineString`/`Point` geometries.

The Google Encoded Polyline Algorithm Format — the compact lat/lon
route encoding used by Google Maps, OSRM, and Valhalla. Accepts one
string (returns a `Point` for one coordinate, otherwise a `LineString`)
or an iterable/dataframe/Arrow column of strings/`None` rows (returns a
`GeometryArray` with missing rows). Polylines are WGS84 by definition, so results carry OGC:CRS84
unless `crs=None` explicitly requests a CRS-free result;
`epoch` restores coordinate-epoch metadata on round-trip.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `data` | `str, iterable of str, or dataframe/Arrow column` | Encoded polyline text or a pandas/Polars Series or PyArrow Array/ChunkedArray. Missing column values become missing rows. | *required* |
| `precision` | `int` | Decimal digits encoded per ordinate (`0` to `11`); 5 is the classic default, 6 the high-resolution variant. | `5` |
| `crs` | `CRS - like or None` | Frame for the decoded longitude/latitude coordinates. Only WGS84 longitude/latitude CRS are valid; pass `None` for CRS-free output. | `'OGC:CRS84'` |
| `epoch` | `numeric scalar or 0-D numeric array` | Coordinate epoch (decimal year) to attach as frame metadata. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `Point, LineString, or GeometryArray` | A `Point` when the encoding has one coordinate, a `LineString` for two or more, or a `GeometryArray` for iterable input. |

Raises:

| Type | Description |
| --- | --- |
| `ParseError` | If the text is not valid polyline data. |
| `GeometryError` | If `precision` is out of range. |
| `CRSError` | If `epoch` is set without `crs`, or `crs` is not recognized. |

See Also

[Geometry.to\_polyline](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.to_polyline "to_polyline") : Encode a LineString or Point as a polyline.

Examples:

```pycon
>>> import gometry as gm
>>> gm.from_polyline('_p~iF~ps|U_ulLnnqC_mqNvxq`@').to_wkt()
'LINESTRING (-120.2 38.5, -120.95 40.7, -126.453 43.252)'
```

## from\_wkb

Accepted call forms

```python
from_wkb(data: PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray, *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_wkb(data: NDArray[uint8] | NDArray[int8], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_wkb(data: NDArray[object_], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_wkb(data: NDArray[bytes_], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry]
```

```python
from_wkb(data: Buffer, *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_wkb(data: Iterable[Buffer], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry]
```

```python
from_wkb(data: Iterable[Buffer | None], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_wkb(data: Buffer | Iterable[Buffer | None], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry | GeometryArray[Geometry | None]
```

Parse a geometry (or array) from Well-Known Binary.

Also accepts EWKB; an embedded SRID becomes the geometry's CRS.
`SRID=0` / EWKB SRID 0 is PostGIS unknown → CRS-free; nonzero codes
resolve through the canonical PROJ CRS parser (invalid codes raise).

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `data` | `bytes, byte buffer, iterable of buffers, or dataframe/Arrow column` | A WKB/EWKB byte buffer, an iterable of byte buffers, or a pandas/Polars Series or PyArrow Array/ChunkedArray of WKB values. A one-byte integer ndarray is one scalar byte buffer; other ndarrays are row columns. Missing column values become missing rows. | *required* |
| `crs` | `CRS - like` | CRS for SRID-less input. An embedded SRID that *contradicts* an explicit `crs` raises rather than silently winning. | `None` |
| `epoch` | `numeric scalar or 0-D numeric array` | Coordinate epoch (decimal year) to attach as frame metadata. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `Geometry or GeometryArray` | A `GeometryArray` when `data` is an iterable, else a `Geometry`. |

Raises:

| Type | Description |
| --- | --- |
| `ParseError` | If the WKB is malformed. |
| `CRSMismatchError` | If an embedded SRID conflicts with `crs`. |
| `CRSError` | If `crs` or an embedded nonzero SRID is not recognized, or `epoch` is set without `crs`. |
| `GeometryError` | If `epoch` is not a finite decimal year. |

Notes

The (E)WKB format does not carry a coordinate epoch and one does not
survive a WKB round-trip; `epoch=` attaches it as frame metadata (as
with `GeometryArray`), and Arrow interchange preserves it on export.


See Also

[Geometry.to\_wkb](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.to_wkb "to_wkb") : Serialize a geometry to WKB.

Examples:

```pycon
>>> import gometry as gm
>>> hex = '0101000000000000000000f03f0000000000000040'
>>> gm.from_wkb(bytes.fromhex(hex)).to_wkt()
'POINT (1 2)'
```

## from\_wkt

Accepted call forms

```python
from_wkt(data: str, *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> Geometry
```

```python
from_wkt(data: PandasSeries | PolarsSeries | PyArrowArray | PyArrowChunkedArray, *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

```python
from_wkt(data: Iterable[str], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry]
```

```python
from_wkt(data: Iterable[str | None], *, crs: CrsInput | None = None, epoch: SupportsFloat | SupportsIndex | FloatScalar | ScalarFloatArray | None = None) -> GeometryArray[Geometry | None]
```

Parse a geometry (or array) from Well-Known Text.

Also accepts EWKT; an embedded `SRID=...;` prefix becomes the
geometry's CRS. `SRID=0` is PostGIS unknown/unspecified and yields a
CRS-free geometry; nonzero codes resolve through the canonical PROJ CRS
parser (invalid codes raise `CRSError`).

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `data` | `str, iterable of str, or dataframe/Arrow column` | A single WKT/EWKT string, an iterable of rows, or a pandas/Polars Series or PyArrow Array/ChunkedArray. Missing column values become missing rows. | *required* |
| `crs` | `CRS - like` | CRS for SRID-less input. An embedded SRID that *contradicts* an explicit `crs` raises rather than silently winning. | `None` |
| `epoch` | `numeric scalar or 0-D numeric array` | Coordinate epoch (decimal year) to attach as frame metadata. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `Geometry or GeometryArray` | A `GeometryArray` when `data` is an iterable, else a `Geometry`. |

Raises:

| Type | Description |
| --- | --- |
| `ParseError` | If the WKT is malformed. |
| `CRSMismatchError` | If an embedded SRID conflicts with `crs`. |
| `CRSError` | If `crs` or an embedded nonzero SRID is not recognized, or `epoch` is set without `crs`. |
| `GeometryError` | If `epoch` is not a finite decimal year. |

See Also

[Geometry.to\_wkt](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.to_wkt "to_wkt") : Serialize a geometry to WKT.

Examples:

```pycon
>>> import gometry as gm
>>> gm.from_wkt('POINT (1 2)').geometry_type
'Point'
>>> gm.from_wkt('SRID=4326;POINT (1 2)').crs
CRS("EPSG:4326")
```

## to\_feature

```python
to_feature(geom: Geometry | None, *, properties: Mapping[str, Any] | None = None, id: FeatureId = None, drop_epoch: bool = False) -> GeoJsonFeature
```

Build a GeoJSON Feature mapping from a geometry and side data.
Unsupported Z/M axes raise an error rather than being silently discarded. Remove them explicitly with `force_2d()`, `with_coordinates(z=None)`, or `with_coordinates(m=None)`.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `geom` | `Geometry` | Geometry to encode. `None` emits a null GeoJSON geometry. A geometry with a CRS must use WGS84 longitude/latitude coordinates. A CRS-free geometry is explicitly assumed to already use those coordinates too. | *required* |
| `properties` | `Mapping[str, Any]` | Feature properties. The mapping is copied and all keys must be strings. | `None` |
| `id` | `str or finite number` | Feature identifier. | `None` |
| `drop_epoch` | `bool` | GeoJSON Feature mappings cannot encode coordinate epoch metadata. If `False`, an epoch-bearing geometry raises `GeometryError`; pass `True` to acknowledge and explicitly lose the epoch metadata. | `False` |

Returns:

| Type | Description |
| --- | --- |
| `GeoJsonFeature` | A new `{"type": "Feature", ...}` mapping. |

Raises:

| Type | Description |
| --- | --- |
| `TypeError` | If `geom` is not a Geometry or `None`. |
| `GeometryError` | If properties are not a string-keyed mapping, the id is invalid, or coordinate epoch metadata is present without `drop_epoch=True`. |
| `InvalidGeometryError` | If the geometry has an M ordinate or coordinates outside the WGS84 longitude/latitude domain. GeoJSON Feature mappings have no representation for M; drop it with `with_coordinates(m=None)` (or `force_2d()`). |
| `CRSError` | If a CRS-tagged geometry is not in the WGS84 lon/lat family. |

Notes

Coordinate epoch metadata is not representable in GeoJSON Feature mappings.
It is rejected unless `drop_epoch=True`; that option explicitly
acknowledges and loses the epoch metadata.

Examples:

```pycon
>>> import gometry as gm
>>> feature = gm.to_feature(gm.Point(1, 2), properties={"name": "A"})
>>> feature.get("properties")
{'name': 'A'}
```

## to\_feature\_collection

Accepted call forms

```python
to_feature_collection(values: Features, *, properties: None = None, ids: None = None, drop_epoch: bool = False) -> GeoJsonFeatureCollection
```

```python
to_feature_collection(values: Geometry | GeometryArray[Geometry | None] | Iterable[Geometry | None] | None, *, properties: Mapping[str, Any] | Iterable[Mapping[str, Any] | None] | None = None, ids: Iterable[FeatureId] | None = None, drop_epoch: bool = False) -> GeoJsonFeatureCollection
```

Build a GeoJSON FeatureCollection from geometries and aligned side data.
Unsupported Z/M axes raise an error rather than being silently discarded. Remove them explicitly with `force_2d()`, `with_coordinates(z=None)`, or `with_coordinates(m=None)`.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `values` | `Features, Geometry, None, GeometryArray, or iterable of Geometry or None` | A `Features` record reuses its aligned geometries, properties, and ids. Features already owns aligned properties and ids, so properties and ids must be omitted; supplying them raises `TypeError`. Otherwise, one geometry or geometry rows to encode. CRS-tagged rows must use WGS84 longitude/latitude coordinates; CRS-free rows are explicitly assumed to already use those coordinates. | *required* |
| `properties` | `Mapping or iterable of Mapping or None` | One mapping broadcasts to every geometry. An iterable supplies one mapping or explicit `None` per row. Omit for independent empty mappings. | `None` |
| `ids` | `iterable of str, finite number, or None` | One optional feature identifier per geometry. | `None` |
| `drop_epoch` | `bool` | GeoJSON Feature mappings cannot encode coordinate epoch metadata. If `False`, an epoch-bearing geometry raises `GeometryError`; pass `True` to acknowledge and explicitly lose the epoch metadata. | `False` |

Returns:

| Type | Description |
| --- | --- |
| `GeoJsonFeatureCollection` | A new `{"type": "FeatureCollection", "features": [...]}` mapping. |

Raises:

| Type | Description |
| --- | --- |
| `TypeError` | If a geometry row is not a Geometry or `None`, or if properties or ids are supplied when values is a Features record. |
| `GeometryError` | If properties or ids are invalid or are not aligned with geometries, or coordinate epoch metadata is present without `drop_epoch=True`. |
| `InvalidGeometryError` | If a geometry has an M ordinate or coordinates outside the WGS84 longitude/latitude domain. GeoJSON Feature mappings cannot represent M; drop it with `with_coordinates(m=None)` (or `force_2d()`). |
| `CRSError` | If a CRS-tagged geometry is not EPSG:4326 longitude/latitude. |

Examples:

```pycon
>>> import gometry as gm
>>> fc = gm.to_feature_collection(gm.GeometryArray([gm.Point(1, 2)]))
>>> fc["type"], len(fc["features"])
('FeatureCollection', 1)
```
