prism-lidarcloud 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: prism-lidarcloud
3
+ Version: 1.0.0
4
+ Summary: Official Python client + CLI for the PRISM LiDAR Cloud REST API (LiDAR → survey-grade DEM/DSM/CHM).
5
+ Author: PRISM LiDAR Cloud
6
+ License: MIT
7
+ Project-URL: Homepage, https://lidarcloud.app
8
+ Project-URL: Documentation, https://app.lidarcloud.app/docs/api
9
+ Keywords: lidar,dem,dsm,chm,point-cloud,gis,remote-sensing,geospatial
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Scientific/Engineering :: GIS
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # prism-lidarcloud
17
+
18
+ Official Python client + CLI for the [PRISM LiDAR Cloud](https://lidarcloud.app) REST API —
19
+ turn raw airborne/UAV LiDAR (`.las`/`.laz`) into a survey-grade deliverable set (bare-earth DEM,
20
+ DSM, CHM, classified point cloud, per-cell uncertainty, accuracy report, CAD bundle) with one call.
21
+
22
+ Zero dependencies (Python standard library only).
23
+
24
+ ## Install
25
+
26
+ > **PyPI publish pending.** `pip install prism-lidarcloud` is *coming to PyPI* but is not
27
+ > live yet. Until then, install the wheel we serve from the app (works for everyone — zero
28
+ > dependencies, pure standard library):
29
+
30
+ ```bash
31
+ # served wheel (recommended — no account/repo access needed)
32
+ pip install https://app.lidarcloud.app/downloads/prism_lidarcloud-1.0.0-py3-none-any.whl
33
+ ```
34
+
35
+ Have repo access? You can also install straight from GitHub (no clone needed — the package
36
+ lives in a subdirectory):
37
+
38
+ ```bash
39
+ pip install "git+https://github.com/ebennb/PRISM_cloud.git#subdirectory=clients/python"
40
+ ```
41
+
42
+ Already have the repo checked out? Install the local package directory instead:
43
+
44
+ ```bash
45
+ pip install ./clients/python
46
+ ```
47
+
48
+ Either way you get the `prism` CLI on your `PATH` and the `prism_lidarcloud` Python package.
49
+ (Once published, the install will simply be `pip install prism-lidarcloud`.)
50
+
51
+ ## Get an API key
52
+
53
+ Sign in at <https://app.lidarcloud.app>, click your email → **API access** → **Create API key**.
54
+ The key (`prism_live_…`) is shown once — copy it. Keep it secret; it carries your account's quota
55
+ and billing.
56
+
57
+ ```bash
58
+ export PRISM_API_KEY=prism_live_xxxxxxxxxxxx
59
+ ```
60
+
61
+ ## CLI
62
+
63
+ ```bash
64
+ # one shot: upload, wait, download the product zip
65
+ prism run scan.las --align 3dep --out products.zip
66
+
67
+ # same, with a real .las path (Windows)
68
+ prism run "Z:\DOKI_github\PRISM_cloud\Sites\Blues_Creek_Subsets\Blues_Creek_Subset_Small\LAS_20260514-191148_LAS_RGB_p051526_v2_alignedSubSmall.las" --align 3dep --out blues_creek_products.zip
69
+
70
+ # step by step
71
+ prism submit scan.las --align 3dep # prints {job_id, status_url, ...}
72
+ prism status <job_id>
73
+ prism download <job_id> -o products.zip
74
+ prism jobs # list your jobs
75
+ ```
76
+
77
+ Common flags: `--align none|3dep|upload|existing`, `--reference other.las` (paired change
78
+ detection), `--no-change`, `--no-classify`, `--no-report`, `--no-cad`, `--dem-res 25cm`,
79
+ `--vdatum navd88`.
80
+
81
+ ## Python
82
+
83
+ ```python
84
+ from prism_lidarcloud import Client
85
+
86
+ c = Client() # reads PRISM_API_KEY
87
+ out = c.run("scan.las", out="products.zip", align="3dep", change=True)
88
+ print("saved", out)
89
+
90
+ # or control each step
91
+ job = c.submit("scan.las", align="3dep")
92
+ final = c.wait(job["job_id"], on_progress=lambda d: print(d["status"], d["pct"]))
93
+ c.download(job["job_id"], "products.zip")
94
+ ```
95
+
96
+ ## What you get back
97
+
98
+ A `.zip` containing the bare-earth **DEM**, **DSM**, **CHM**, **DEM uncertainty** rasters
99
+ (GeoTIFF), the classified point cloud, the AOI boundary, and — unless disabled — the **accuracy
100
+ report** (Word) and **CAD bundle** (DXF + LandXML). Paired/3DEP runs add alignment + change-detection
101
+ products.
102
+
103
+ ## Notes
104
+
105
+ - Jobs run on ephemeral cloud workers; `wait()` polls until `done`/`error`.
106
+ - API jobs consume the same account quota as the web app and appear in your usage console tagged
107
+ **API** (vs **web**).
108
+ - Full reference: <https://app.lidarcloud.app/docs/api>
@@ -0,0 +1,93 @@
1
+ # prism-lidarcloud
2
+
3
+ Official Python client + CLI for the [PRISM LiDAR Cloud](https://lidarcloud.app) REST API —
4
+ turn raw airborne/UAV LiDAR (`.las`/`.laz`) into a survey-grade deliverable set (bare-earth DEM,
5
+ DSM, CHM, classified point cloud, per-cell uncertainty, accuracy report, CAD bundle) with one call.
6
+
7
+ Zero dependencies (Python standard library only).
8
+
9
+ ## Install
10
+
11
+ > **PyPI publish pending.** `pip install prism-lidarcloud` is *coming to PyPI* but is not
12
+ > live yet. Until then, install the wheel we serve from the app (works for everyone — zero
13
+ > dependencies, pure standard library):
14
+
15
+ ```bash
16
+ # served wheel (recommended — no account/repo access needed)
17
+ pip install https://app.lidarcloud.app/downloads/prism_lidarcloud-1.0.0-py3-none-any.whl
18
+ ```
19
+
20
+ Have repo access? You can also install straight from GitHub (no clone needed — the package
21
+ lives in a subdirectory):
22
+
23
+ ```bash
24
+ pip install "git+https://github.com/ebennb/PRISM_cloud.git#subdirectory=clients/python"
25
+ ```
26
+
27
+ Already have the repo checked out? Install the local package directory instead:
28
+
29
+ ```bash
30
+ pip install ./clients/python
31
+ ```
32
+
33
+ Either way you get the `prism` CLI on your `PATH` and the `prism_lidarcloud` Python package.
34
+ (Once published, the install will simply be `pip install prism-lidarcloud`.)
35
+
36
+ ## Get an API key
37
+
38
+ Sign in at <https://app.lidarcloud.app>, click your email → **API access** → **Create API key**.
39
+ The key (`prism_live_…`) is shown once — copy it. Keep it secret; it carries your account's quota
40
+ and billing.
41
+
42
+ ```bash
43
+ export PRISM_API_KEY=prism_live_xxxxxxxxxxxx
44
+ ```
45
+
46
+ ## CLI
47
+
48
+ ```bash
49
+ # one shot: upload, wait, download the product zip
50
+ prism run scan.las --align 3dep --out products.zip
51
+
52
+ # same, with a real .las path (Windows)
53
+ prism run "Z:\DOKI_github\PRISM_cloud\Sites\Blues_Creek_Subsets\Blues_Creek_Subset_Small\LAS_20260514-191148_LAS_RGB_p051526_v2_alignedSubSmall.las" --align 3dep --out blues_creek_products.zip
54
+
55
+ # step by step
56
+ prism submit scan.las --align 3dep # prints {job_id, status_url, ...}
57
+ prism status <job_id>
58
+ prism download <job_id> -o products.zip
59
+ prism jobs # list your jobs
60
+ ```
61
+
62
+ Common flags: `--align none|3dep|upload|existing`, `--reference other.las` (paired change
63
+ detection), `--no-change`, `--no-classify`, `--no-report`, `--no-cad`, `--dem-res 25cm`,
64
+ `--vdatum navd88`.
65
+
66
+ ## Python
67
+
68
+ ```python
69
+ from prism_lidarcloud import Client
70
+
71
+ c = Client() # reads PRISM_API_KEY
72
+ out = c.run("scan.las", out="products.zip", align="3dep", change=True)
73
+ print("saved", out)
74
+
75
+ # or control each step
76
+ job = c.submit("scan.las", align="3dep")
77
+ final = c.wait(job["job_id"], on_progress=lambda d: print(d["status"], d["pct"]))
78
+ c.download(job["job_id"], "products.zip")
79
+ ```
80
+
81
+ ## What you get back
82
+
83
+ A `.zip` containing the bare-earth **DEM**, **DSM**, **CHM**, **DEM uncertainty** rasters
84
+ (GeoTIFF), the classified point cloud, the AOI boundary, and — unless disabled — the **accuracy
85
+ report** (Word) and **CAD bundle** (DXF + LandXML). Paired/3DEP runs add alignment + change-detection
86
+ products.
87
+
88
+ ## Notes
89
+
90
+ - Jobs run on ephemeral cloud workers; `wait()` polls until `done`/`error`.
91
+ - API jobs consume the same account quota as the web app and appear in your usage console tagged
92
+ **API** (vs **web**).
93
+ - Full reference: <https://app.lidarcloud.app/docs/api>
@@ -0,0 +1,155 @@
1
+ """prism-lidarcloud — official Python client for the PRISM LiDAR Cloud REST API.
2
+
3
+ Zero dependencies (Python standard library only). Get an API key from your account at
4
+ https://app.lidarcloud.app/account → "API access" → Create API key.
5
+
6
+ from prism_lidarcloud import Client
7
+ c = Client(api_key="prism_live_...") # or set PRISM_API_KEY
8
+ out = c.run("scan.las", out="products.zip", align="3dep", wait=True)
9
+ print("saved", out)
10
+
11
+ Or step by step:
12
+
13
+ job = c.submit("scan.las", align="3dep", change=True)
14
+ c.wait(job["job_id"])
15
+ c.download(job["job_id"], "products.zip")
16
+ """
17
+ import io, json, mimetypes, os, time, uuid
18
+ import urllib.request, urllib.error
19
+
20
+ __version__ = "1.0.0"
21
+ DEFAULT_BASE_URL = os.environ.get("PRISM_BASE_URL", "https://app.lidarcloud.app")
22
+
23
+
24
+ class PrismError(RuntimeError):
25
+ """An API error. `.status` is the HTTP code; `.detail` the server message."""
26
+ def __init__(self, message, status=None, detail=None):
27
+ super().__init__(message)
28
+ self.status = status
29
+ self.detail = detail
30
+
31
+
32
+ def _multipart(fields, files):
33
+ """Encode a multipart/form-data body. fields: {name: str}. files: {name: (filename, bytes)}.
34
+ Returns (content_type, body_bytes)."""
35
+ boundary = "----prism" + uuid.uuid4().hex
36
+ out = io.BytesIO()
37
+ def w(s): out.write(s.encode() if isinstance(s, str) else s)
38
+ for name, val in (fields or {}).items():
39
+ w(f"--{boundary}\r\n")
40
+ w(f'Content-Disposition: form-data; name="{name}"\r\n\r\n')
41
+ w(f"{val}\r\n")
42
+ for name, (fn, data) in (files or {}).items():
43
+ ctype = mimetypes.guess_type(fn)[0] or "application/octet-stream"
44
+ w(f"--{boundary}\r\n")
45
+ w(f'Content-Disposition: form-data; name="{name}"; filename="{fn}"\r\n')
46
+ w(f"Content-Type: {ctype}\r\n\r\n")
47
+ w(data); w("\r\n")
48
+ w(f"--{boundary}--\r\n")
49
+ return f"multipart/form-data; boundary={boundary}", out.getvalue()
50
+
51
+
52
+ class Client:
53
+ """A PRISM LiDAR Cloud API client.
54
+
55
+ api_key : your prism_live_... key (or set the PRISM_API_KEY env var).
56
+ base_url : the API host (defaults to https://app.lidarcloud.app).
57
+ timeout : per-request socket timeout in seconds (uploads use upload_timeout).
58
+ """
59
+ def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, timeout=120, upload_timeout=1800):
60
+ self.api_key = api_key or os.environ.get("PRISM_API_KEY")
61
+ if not self.api_key:
62
+ raise PrismError("No API key — pass api_key= or set PRISM_API_KEY.")
63
+ self.base_url = base_url.rstrip("/")
64
+ self.timeout = timeout
65
+ self.upload_timeout = upload_timeout
66
+
67
+ # ── low-level request ──
68
+ def _req(self, method, path, *, body=None, ctype=None, timeout=None, raw=False):
69
+ url = self.base_url + path
70
+ headers = {"Authorization": f"Bearer {self.api_key}", "Accept": "application/json"}
71
+ if ctype:
72
+ headers["Content-Type"] = ctype
73
+ req = urllib.request.Request(url, data=body, method=method, headers=headers)
74
+ try:
75
+ resp = urllib.request.urlopen(req, timeout=timeout or self.timeout)
76
+ except urllib.error.HTTPError as e:
77
+ detail = None
78
+ try:
79
+ detail = json.loads(e.read().decode()).get("detail") or json.loads(e.read().decode()).get("message")
80
+ except Exception:
81
+ pass
82
+ raise PrismError(f"{method} {path} failed: HTTP {e.code}{(' — ' + detail) if detail else ''}",
83
+ status=e.code, detail=detail) from None
84
+ except urllib.error.URLError as e:
85
+ raise PrismError(f"{method} {path} failed: {e.reason}") from None
86
+ if raw:
87
+ return resp
88
+ return json.loads(resp.read().decode())
89
+
90
+ # ── high-level operations ──
91
+ def submit(self, path, *, align="3dep", change=True, classify=True, dem_res="auto",
92
+ vdatum="navd88", report=True, cad=True, reference=None, notify=False):
93
+ """Submit a point cloud (.las/.laz) for processing. Returns {job_id, status, status_url,
94
+ download_url, ...}. `reference` (optional path) enables paired change detection."""
95
+ with open(path, "rb") as f:
96
+ data = f.read()
97
+ files = {"file": (os.path.basename(path), data)}
98
+ if reference:
99
+ with open(reference, "rb") as f:
100
+ files["reference"] = (os.path.basename(reference), f.read())
101
+ align = "upload"
102
+ fields = {"align": align, "change": "1" if change else "0",
103
+ "classify": "1" if classify else "0", "dem_res": dem_res, "vdatum": vdatum,
104
+ "report": "1" if report else "0", "cad": "1" if cad else "0",
105
+ "notify": "1" if notify else "0"}
106
+ ctype, b = _multipart(fields, files)
107
+ return self._req("POST", "/api/v1/jobs", body=b, ctype=ctype, timeout=self.upload_timeout)
108
+
109
+ def status(self, job_id):
110
+ """Poll one job. Returns {status: queued|running|done|error, pct, stage, ...}."""
111
+ return self._req("GET", f"/api/v1/jobs/{job_id}")
112
+
113
+ def jobs(self):
114
+ """List your account's jobs visible to the server. Returns {jobs:[...], count}."""
115
+ return self._req("GET", "/api/v1/jobs")
116
+
117
+ def wait(self, job_id, poll=5, timeout=14400, on_progress=None):
118
+ """Block until the job is done or errors. Returns the final status dict. Raises PrismError
119
+ on a failed job or timeout. `on_progress(status_dict)` is called on each poll if given."""
120
+ t0 = time.time()
121
+ while True:
122
+ d = self.status(job_id)
123
+ if on_progress:
124
+ on_progress(d)
125
+ st = d.get("status")
126
+ if st == "done":
127
+ return d
128
+ if st == "error":
129
+ raise PrismError(f"job {job_id} failed: {d.get('error') or 'unknown error'}", detail=d.get("error"))
130
+ if time.time() - t0 > timeout:
131
+ raise PrismError(f"timed out waiting for job {job_id} after {timeout}s")
132
+ time.sleep(poll)
133
+
134
+ def download(self, job_id, out, *, clouds=True):
135
+ """Stream the finished product zip to `out` (a path). Returns the path."""
136
+ resp = self._req("GET", f"/api/v1/jobs/{job_id}/download?clouds={1 if clouds else 0}",
137
+ timeout=self.upload_timeout, raw=True)
138
+ with open(out, "wb") as f:
139
+ while True:
140
+ chunk = resp.read(1 << 20)
141
+ if not chunk:
142
+ break
143
+ f.write(chunk)
144
+ return out
145
+
146
+ def run(self, path, *, out=None, wait=True, poll=5, on_progress=None, **submit_kwargs):
147
+ """One call: submit -> (optionally) wait -> download. Returns the output path if downloaded,
148
+ else the submit response dict."""
149
+ job = self.submit(path, **submit_kwargs)
150
+ jid = job["job_id"]
151
+ if not wait:
152
+ return job
153
+ self.wait(jid, poll=poll, on_progress=on_progress)
154
+ out = out or (os.path.splitext(os.path.basename(path))[0] + "_products.zip")
155
+ return self.download(jid, out, clouds=submit_kwargs.get("clouds", True))
@@ -0,0 +1,87 @@
1
+ """prism — command-line interface for PRISM LiDAR Cloud.
2
+
3
+ prism run scan.las --align 3dep --wait -o products.zip
4
+ prism submit scan.las --align 3dep
5
+ prism status <job_id>
6
+ prism download <job_id> -o products.zip
7
+ prism jobs
8
+
9
+ Auth: --token prism_live_... or set PRISM_API_KEY. Host override: --base-url / PRISM_BASE_URL.
10
+ """
11
+ import argparse, json, sys
12
+ from . import Client, PrismError, __version__, DEFAULT_BASE_URL
13
+
14
+
15
+ def _client(args):
16
+ return Client(api_key=args.token, base_url=args.base_url)
17
+
18
+
19
+ def _progress(d):
20
+ sys.stderr.write(f"\r {d.get('status','?'):9} {d.get('pct',0):5.1f}% {d.get('stage','')[:48]:48}")
21
+ sys.stderr.flush()
22
+
23
+
24
+ def main(argv=None):
25
+ p = argparse.ArgumentParser(prog="prism", description="PRISM LiDAR Cloud CLI")
26
+ p.add_argument("--version", action="version", version=f"prism-lidarcloud {__version__}")
27
+ p.add_argument("--token", help="API key (or set PRISM_API_KEY)")
28
+ p.add_argument("--base-url", default=DEFAULT_BASE_URL, help="API host")
29
+ sub = p.add_subparsers(dest="cmd", required=True)
30
+
31
+ def add_opts(sp):
32
+ sp.add_argument("--align", default="3dep", choices=["none", "3dep", "upload", "existing"],
33
+ help="co-registration reference (default 3dep)")
34
+ sp.add_argument("--reference", help="reference .las/.laz for paired change detection")
35
+ sp.add_argument("--no-change", action="store_true", help="disable change detection")
36
+ sp.add_argument("--no-classify", action="store_true", help="disable semantic classification")
37
+ sp.add_argument("--no-report", action="store_true", help="omit the accuracy report")
38
+ sp.add_argument("--no-cad", action="store_true", help="omit the CAD bundle")
39
+ sp.add_argument("--dem-res", default="auto", help="DEM resolution (auto|25cm|50cm|100cm)")
40
+ sp.add_argument("--vdatum", default="navd88", help="navd88 (default, rigorous GEOID18) | ellipsoidal")
41
+
42
+ def opts(args):
43
+ return dict(align=args.align, reference=args.reference, change=not args.no_change,
44
+ classify=not args.no_classify, report=not args.no_report, cad=not args.no_cad,
45
+ dem_res=args.dem_res, vdatum=args.vdatum)
46
+
47
+ sp = sub.add_parser("run", help="submit, wait, and download in one step")
48
+ sp.add_argument("file"); add_opts(sp)
49
+ sp.add_argument("-o", "--out", help="output zip path")
50
+ sp.add_argument("--no-wait", action="store_true", help="just submit; don't wait/download")
51
+ sp.add_argument("--poll", type=int, default=5, help="poll interval seconds")
52
+
53
+ sp = sub.add_parser("submit", help="submit a job and print its id")
54
+ sp.add_argument("file"); add_opts(sp)
55
+
56
+ sp = sub.add_parser("status", help="print a job's status"); sp.add_argument("job_id")
57
+ sp = sub.add_parser("download", help="download a finished job's product zip")
58
+ sp.add_argument("job_id"); sp.add_argument("-o", "--out", required=True)
59
+ sub.add_parser("jobs", help="list your jobs")
60
+
61
+ args = p.parse_args(argv)
62
+ try:
63
+ c = _client(args)
64
+ if args.cmd == "run":
65
+ if args.no_wait:
66
+ print(json.dumps(c.submit(args.file, **opts(args)), indent=2)); return 0
67
+ out = c.run(args.file, out=args.out, wait=True, poll=args.poll,
68
+ on_progress=_progress, **opts(args))
69
+ sys.stderr.write("\n")
70
+ print(out); return 0
71
+ if args.cmd == "submit":
72
+ print(json.dumps(c.submit(args.file, **opts(args)), indent=2)); return 0
73
+ if args.cmd == "status":
74
+ print(json.dumps(c.status(args.job_id), indent=2)); return 0
75
+ if args.cmd == "download":
76
+ print(c.download(args.job_id, args.out)); return 0
77
+ if args.cmd == "jobs":
78
+ print(json.dumps(c.jobs(), indent=2)); return 0
79
+ except PrismError as e:
80
+ sys.stderr.write(f"error: {e}\n"); return 1
81
+ except KeyboardInterrupt:
82
+ sys.stderr.write("\naborted\n"); return 130
83
+ return 0
84
+
85
+
86
+ if __name__ == "__main__":
87
+ sys.exit(main())
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: prism-lidarcloud
3
+ Version: 1.0.0
4
+ Summary: Official Python client + CLI for the PRISM LiDAR Cloud REST API (LiDAR → survey-grade DEM/DSM/CHM).
5
+ Author: PRISM LiDAR Cloud
6
+ License: MIT
7
+ Project-URL: Homepage, https://lidarcloud.app
8
+ Project-URL: Documentation, https://app.lidarcloud.app/docs/api
9
+ Keywords: lidar,dem,dsm,chm,point-cloud,gis,remote-sensing,geospatial
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Scientific/Engineering :: GIS
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # prism-lidarcloud
17
+
18
+ Official Python client + CLI for the [PRISM LiDAR Cloud](https://lidarcloud.app) REST API —
19
+ turn raw airborne/UAV LiDAR (`.las`/`.laz`) into a survey-grade deliverable set (bare-earth DEM,
20
+ DSM, CHM, classified point cloud, per-cell uncertainty, accuracy report, CAD bundle) with one call.
21
+
22
+ Zero dependencies (Python standard library only).
23
+
24
+ ## Install
25
+
26
+ > **PyPI publish pending.** `pip install prism-lidarcloud` is *coming to PyPI* but is not
27
+ > live yet. Until then, install the wheel we serve from the app (works for everyone — zero
28
+ > dependencies, pure standard library):
29
+
30
+ ```bash
31
+ # served wheel (recommended — no account/repo access needed)
32
+ pip install https://app.lidarcloud.app/downloads/prism_lidarcloud-1.0.0-py3-none-any.whl
33
+ ```
34
+
35
+ Have repo access? You can also install straight from GitHub (no clone needed — the package
36
+ lives in a subdirectory):
37
+
38
+ ```bash
39
+ pip install "git+https://github.com/ebennb/PRISM_cloud.git#subdirectory=clients/python"
40
+ ```
41
+
42
+ Already have the repo checked out? Install the local package directory instead:
43
+
44
+ ```bash
45
+ pip install ./clients/python
46
+ ```
47
+
48
+ Either way you get the `prism` CLI on your `PATH` and the `prism_lidarcloud` Python package.
49
+ (Once published, the install will simply be `pip install prism-lidarcloud`.)
50
+
51
+ ## Get an API key
52
+
53
+ Sign in at <https://app.lidarcloud.app>, click your email → **API access** → **Create API key**.
54
+ The key (`prism_live_…`) is shown once — copy it. Keep it secret; it carries your account's quota
55
+ and billing.
56
+
57
+ ```bash
58
+ export PRISM_API_KEY=prism_live_xxxxxxxxxxxx
59
+ ```
60
+
61
+ ## CLI
62
+
63
+ ```bash
64
+ # one shot: upload, wait, download the product zip
65
+ prism run scan.las --align 3dep --out products.zip
66
+
67
+ # same, with a real .las path (Windows)
68
+ prism run "Z:\DOKI_github\PRISM_cloud\Sites\Blues_Creek_Subsets\Blues_Creek_Subset_Small\LAS_20260514-191148_LAS_RGB_p051526_v2_alignedSubSmall.las" --align 3dep --out blues_creek_products.zip
69
+
70
+ # step by step
71
+ prism submit scan.las --align 3dep # prints {job_id, status_url, ...}
72
+ prism status <job_id>
73
+ prism download <job_id> -o products.zip
74
+ prism jobs # list your jobs
75
+ ```
76
+
77
+ Common flags: `--align none|3dep|upload|existing`, `--reference other.las` (paired change
78
+ detection), `--no-change`, `--no-classify`, `--no-report`, `--no-cad`, `--dem-res 25cm`,
79
+ `--vdatum navd88`.
80
+
81
+ ## Python
82
+
83
+ ```python
84
+ from prism_lidarcloud import Client
85
+
86
+ c = Client() # reads PRISM_API_KEY
87
+ out = c.run("scan.las", out="products.zip", align="3dep", change=True)
88
+ print("saved", out)
89
+
90
+ # or control each step
91
+ job = c.submit("scan.las", align="3dep")
92
+ final = c.wait(job["job_id"], on_progress=lambda d: print(d["status"], d["pct"]))
93
+ c.download(job["job_id"], "products.zip")
94
+ ```
95
+
96
+ ## What you get back
97
+
98
+ A `.zip` containing the bare-earth **DEM**, **DSM**, **CHM**, **DEM uncertainty** rasters
99
+ (GeoTIFF), the classified point cloud, the AOI boundary, and — unless disabled — the **accuracy
100
+ report** (Word) and **CAD bundle** (DXF + LandXML). Paired/3DEP runs add alignment + change-detection
101
+ products.
102
+
103
+ ## Notes
104
+
105
+ - Jobs run on ephemeral cloud workers; `wait()` polls until `done`/`error`.
106
+ - API jobs consume the same account quota as the web app and appear in your usage console tagged
107
+ **API** (vs **web**).
108
+ - Full reference: <https://app.lidarcloud.app/docs/api>
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ prism_lidarcloud/__init__.py
4
+ prism_lidarcloud/cli.py
5
+ prism_lidarcloud.egg-info/PKG-INFO
6
+ prism_lidarcloud.egg-info/SOURCES.txt
7
+ prism_lidarcloud.egg-info/dependency_links.txt
8
+ prism_lidarcloud.egg-info/entry_points.txt
9
+ prism_lidarcloud.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ prism = prism_lidarcloud.cli:main
@@ -0,0 +1 @@
1
+ prism_lidarcloud
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "prism-lidarcloud"
7
+ version = "1.0.0"
8
+ description = "Official Python client + CLI for the PRISM LiDAR Cloud REST API (LiDAR → survey-grade DEM/DSM/CHM)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "PRISM LiDAR Cloud" }]
13
+ keywords = ["lidar", "dem", "dsm", "chm", "point-cloud", "gis", "remote-sensing", "geospatial"]
14
+ dependencies = [] # standard library only
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Topic :: Scientific/Engineering :: GIS",
19
+ ]
20
+
21
+ [project.urls]
22
+ Homepage = "https://lidarcloud.app"
23
+ Documentation = "https://app.lidarcloud.app/docs/api"
24
+
25
+ [project.scripts]
26
+ prism = "prism_lidarcloud.cli:main"
27
+
28
+ [tool.setuptools]
29
+ packages = ["prism_lidarcloud"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+