Metadata-Version: 2.4
Name: env-able
Version: 0.5.0
Summary: AI-ready GIS toolkit for energy and subsurface workflows.
License: MIT
License-File: LICENSE
Requires-Python: >=3.8
Requires-Dist: geopandas
Requires-Dist: openpyxl
Requires-Dist: pyogrio
Requires-Dist: xlrd
Provides-Extra: atlas
Requires-Dist: fastapi; extra == 'atlas'
Requires-Dist: uvicorn; extra == 'atlas'
Provides-Extra: databricks
Requires-Dist: databricks-sql-connector; extra == 'databricks'
Provides-Extra: fast
Requires-Dist: duckdb; extra == 'fast'
Requires-Dist: requests; extra == 'fast'
Provides-Extra: fiona
Requires-Dist: fiona; extra == 'fiona'
Description-Content-Type: text/markdown

# env-able

An open source spatial analysis library built for AI-driven GIS workflows. Designed to give AI systems like Claude reliable, hallucination-free tools for spatial operations in energy and subsurface contexts.

## Install

```bash
pip install env-able

# with Databricks support
pip install env-able[databricks]
```

## Usage

```python
import env_able as env
```

---

## Functions

### `env.pull(table, output=None, wkt_col=None, chunk_size=None, crs="EPSG:4326")`

Pull a Databricks table or query to a local file, chunking around the row/byte limit automatically.

Databricks caps result sets (~4 096 rows for narrow tables, fewer when WKT columns are present). `pull()` paginates with `LIMIT`/`OFFSET`, assembles the complete dataset in memory, and writes it to disk in the requested format.

**Parameters**
- `table` — fully-qualified table name (`catalog.schema.table`) or a complete `SELECT` query
- `output` — destination file path; format inferred from extension (`.gpkg`, `.geojson`, `.shp`, `.parquet`, `.csv`, `.xlsx`). Omit to return a GeoDataFrame or DataFrame.
- `wkt_col` — column containing WKT geometry strings. Auto-detected if omitted.
- `chunk_size` — rows per Databricks query. Defaults to 512 (WKT) or 4 096 (tabular). Reduce if you hit payload errors on wide tables.
- `crs` — CRS to assign geometry. Default `EPSG:4326`.

**Environment variables required**
```
DATABRICKS_HOST       # https://adb-<workspace-id>.azuredatabricks.net
DATABRICKS_TOKEN      # personal access token
DATABRICKS_HTTP_PATH  # /sql/1.0/warehouses/<warehouse-id>
```

```python
import env_able as env

# pull a full table to GeoPackage
env.pull("catalog.schema.wells", "wells.gpkg")

# pull with a filter query
env.pull("SELECT * FROM catalog.schema.wells WHERE state = 'TX'", "wells_tx.gpkg")

# pull tabular (no geometry)
env.pull("catalog.schema.formations", "formations.csv")

# return in-memory without writing
gdf = env.pull("catalog.schema.leases", wkt_col="geom_wkt", crs="EPSG:4269")
```

---

### `env.Intersect(input_layer, intersect_layer, output=None)`
Computes geometric intersection of input features against a polygon boundary.
- `input_layer` — point, line, or polygon (file path or GeoDataFrame)
- `intersect_layer` — polygon layer defining the intersection boundary
- `output` — file path to save result (`.gpkg`, `.shp`, etc.) — omit to return a GeoDataFrame

```python
import env_able as env
env.Intersect("wells.shp", "boundary.shp", "result.gpkg")
```

---

### `env.Buffer(input_layer, distance, unit="meters", output=None)`
Buffers input features by a given distance and unit.
- `input_layer` — point, line, or polygon (file path or GeoDataFrame)
- `distance` — numeric buffer distance
- `unit` — `meters`, `km`, `miles`, `feet`, `usfeet`, `nautical miles`
- `output` — file path to save result — omit to return a GeoDataFrame

```python
env.Buffer("wells.shp", 1, "miles", "wells_buffer.gpkg")
```

---

### `env.Clip(input_layer, clip_layer, output=None)`
Clips input features to the extent of a polygon clip boundary.
- `input_layer` — point, line, or polygon (file path or GeoDataFrame)
- `clip_layer` — polygon layer defining the clip boundary
- `output` — file path to save result — omit to return a GeoDataFrame

```python
env.Clip("roads.shp", "county.shp", "roads_clipped.gpkg")
```

---

### `env.morph(input_path, output_path, **kwargs)`
Universal format translation. Converts between shp, gpkg, gdb, csv, xlsx, xls, dbf, geojson, json with automatic CRS handling, field name fixes, and multi-layer support.

- `input_path` — source file or geodatabase
- `output_path` — destination file. Extension sets the format. Use trailing `/` for directory output (one file per layer). Use dot notation for named layers: `roads.parcels.gpkg`
- `x_col`, `y_col` — column names for X/Y coordinates (auto-detected if not provided)
- `wkt_col` — column containing WKT geometry (auto-detected if not provided)
- `crs` — coordinate reference system e.g. `EPSG:4326` (required for tabular → spatial)

```python
env.morph("roads.shp", "roads.gpkg")
env.morph("county.gdb", "county.gpkg")
env.morph("county.gdb", "output_folder/")
env.morph("owners.csv", "owners.geojson", crs="EPSG:4269")
env.morph("owners.csv", "owners.shp", x_col="LONGITUDE", y_col="LATITUDE", crs="EPSG:4269")
env.morph("roads.gpkg", "roads.parcels.gpkg")
env.morph("data.json", "data.gpkg")
```

**Smart behavior:**
- GDB / GPKG with multiple layers → detects all layers automatically
- CRS mismatch → auto-reprojects
- Shapefile field name limit (10 chars) → auto-truncates with warnings
- Invalid output path → plain English error
- Empty layers → skipped with a warning, not a crash

---

## Changelog

### v0.3.0 — 2026-07-14
- `pull()` — paginated Databricks table fetch with WKT auto-detection and chunked assembly

### v0.2.0 — 2026-07-14
- Renamed import alias convention from `e` to `env`

### v0.1.0 — 2026-07-14
- Initial release of env-able
- `Intersect()`, `Buffer()`, `Clip()` with full guardrails
- `morph()` — universal format translation
- Smart geometry detection for WKT and lat/lon columns
- GeoJSON, JSON support with auto WGS84 reprojection
- Multi-layer GDB/GPKG support
