geopera-cli 0.1.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,59 @@
1
+ name: Publish CLI (geopera-cli)
2
+
3
+ # Publishes geopera-cli to PyPI on a tag like `v0.1.0`.
4
+ # Uses PyPI Trusted Publishing (OIDC) — no stored token.
5
+ #
6
+ # One-time PyPI setup: pypi.org -> the geopera-cli project -> Publishing -> add a GitHub
7
+ # Actions publisher (repo geo-pera/geopera-cli, workflow publish.yml, environment "pypi").
8
+ # First publish may use PyPI's "pending publisher" flow.
9
+ #
10
+ # NOTE: geopera-cli depends on the `geopera` SDK, so publish `geopera` to PyPI first —
11
+ # otherwise `pip install geopera-cli` can't resolve its dependency for end users.
12
+ #
13
+ # Release: bump `version` in pyproject.toml, then:
14
+ # git tag vX.Y.Z && git push origin vX.Y.Z
15
+
16
+ on:
17
+ push:
18
+ tags:
19
+ - "v*"
20
+ workflow_dispatch: {}
21
+
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ build-and-publish:
27
+ runs-on: ubuntu-latest
28
+ environment: pypi
29
+ permissions:
30
+ id-token: write # OIDC token for PyPI Trusted Publishing
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: "3.11"
37
+
38
+ - name: Build sdist + wheel
39
+ run: |
40
+ python -m pip install --upgrade build twine
41
+ python -m build
42
+ twine check dist/*
43
+
44
+ - name: Sanity-check the package metadata + entry point
45
+ # Doesn't install runtime deps (the `geopera` SDK may not be on PyPI yet) — just
46
+ # confirms the wheel declares the `geopera` console script.
47
+ run: |
48
+ python - <<'PY'
49
+ import zipfile, glob, sys
50
+ whl = glob.glob("dist/*.whl")[0]
51
+ names = zipfile.ZipFile(whl).namelist()
52
+ entry = [n for n in names if n.endswith("entry_points.txt")]
53
+ txt = zipfile.ZipFile(whl).read(entry[0]).decode() if entry else ""
54
+ assert "geopera" in txt and "geopera_cli" in txt, f"missing console_scripts entry: {txt!r}"
55
+ print("ok: wheel declares the `geopera` console script")
56
+ PY
57
+
58
+ - name: Publish to PyPI (Trusted Publishing)
59
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ *.egg
6
+ .eggs/
7
+ build/
8
+ dist/
9
+ .ruff_cache/
10
+ .pytest_cache/
11
+ .coverage
12
+ htmlcov/
13
+
14
+ # Virtualenvs
15
+ .venv/
16
+ venv/
17
+ env/
18
+
19
+ # Local credentials must NEVER be committed (they live in ~/.config/geopera).
20
+ credentials.json
21
+
22
+ # OS / editor
23
+ .DS_Store
24
+ .idea/
25
+ .vscode/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Geopera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.4
2
+ Name: geopera-cli
3
+ Version: 0.1.0
4
+ Summary: Command-line interface for the Geopera geospatial data platform
5
+ Project-URL: Homepage, https://docs.geopera.com
6
+ Project-URL: Documentation, https://docs.geopera.com/cli
7
+ Project-URL: Source, https://github.com/geo-pera/geopera-cli
8
+ Author-email: Geopera <support@geopera.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: cli,earth-observation,geopera,geospatial,satellite,stac
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: GIS
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: geopera>=2.0.0
27
+ Requires-Dist: httpx<0.29.0,>=0.23.1
28
+ Requires-Dist: typer[all]>=0.12.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.5.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # geopera-cli
35
+
36
+ Command-line interface for the [Geopera](https://docs.geopera.com) geospatial
37
+ data platform.
38
+
39
+ `geopera-cli` is a **thin auth + dispatch shell** over the published
40
+ [`geopera` Python SDK](https://github.com/geo-pera/geopera-python). The only
41
+ logic that lives in the CLI is authentication — the OAuth device flow, token
42
+ refresh, and the choice between a `Bearer` token and an `X-API-Key` header.
43
+ Every actual capability is reached through the generic API endpoint
44
+ `POST /v1/op/{operation_id}`, so any of the ~227 operations is callable with no
45
+ per-command code, and a new backend operation is instantly usable as
46
+ `geopera op <new.op>` with zero CLI changes.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install geopera-cli
52
+ ```
53
+
54
+ This pulls in the `geopera` SDK, `typer`, and `httpx`.
55
+
56
+ ## Quick start
57
+
58
+ ```bash
59
+ # Sign in (opens your browser; RFC 8628 device flow)
60
+ geopera login
61
+
62
+ # Who am I?
63
+ geopera whoami
64
+
65
+ # Price-preview an order (generic op dispatch)
66
+ geopera op orders.estimate '{"aoi": {...}, "product": "..."}'
67
+
68
+ # Search across every registered public data source
69
+ geopera op catalog.federated_search '{"bbox": [...], "datetime": "..."}'
70
+
71
+ # List every available operation id
72
+ geopera op --list
73
+
74
+ # Curated alias with table output
75
+ geopera orders list
76
+ ```
77
+
78
+ ## Commands
79
+
80
+ | Command | Description |
81
+ | --- | --- |
82
+ | `geopera login` | Device-flow login (default). `--api-key KEY` stores a key instead (`-` reads from stdin). `--api-url URL`, `--no-browser`, `--scope`. |
83
+ | `geopera logout` | Clear the active profile's stored credentials (best-effort OAuth logout). |
84
+ | `geopera whoami` | Show principal / org / scope (validates the session). `--json` for raw output. |
85
+ | `geopera op OPERATION_ID [JSON]` | Generic operation dispatch. Body from positional arg, `--file`, or `-` (stdin). `--list` enumerates operations. |
86
+ | `geopera orders list` | Curated alias over `op orders.list` with table formatting. |
87
+
88
+ Global flags `--profile NAME` (env `GEOPERA_PROFILE`) and `--api-url URL`
89
+ (env `GEOPERA_API_URL`) are accepted on every command.
90
+
91
+ ## Authentication
92
+
93
+ ### Device flow (default)
94
+
95
+ `geopera login` performs the OAuth 2.0 Device Authorization Grant
96
+ ([RFC 8628](https://www.rfc-editor.org/rfc/rfc8628)) with PKCE:
97
+
98
+ 1. Requests a device + user code from
99
+ `{api_url}/realms/public/protocol/openid-connect/auth/device`.
100
+ 2. Prints the user code and opens the verification URL in your browser
101
+ (skip with `--no-browser`).
102
+ 3. Polls the token endpoint until you approve, then stores the access and
103
+ refresh tokens.
104
+
105
+ Access tokens are refreshed automatically — proactively when within 30s of
106
+ expiry, and reactively on any `401` — using the stored refresh token. The
107
+ backend rotates the refresh token, so both tokens are rewritten on each
108
+ refresh.
109
+
110
+ ### API key (headless)
111
+
112
+ ```bash
113
+ geopera login --api-key gpra_xxxxxxxx
114
+ # or, keeping the key out of shell history:
115
+ printf '%s' "$GEOPERA_KEY" | geopera login --api-key -
116
+ ```
117
+
118
+ API keys are sent as `X-API-Key`, which the Geopera API accepts on every
119
+ authenticated endpoint.
120
+
121
+ ### Profiles
122
+
123
+ Multiple identities are namespaced by profile:
124
+
125
+ ```bash
126
+ geopera login --profile staging --api-url https://staging.api.geopera.com
127
+ geopera --help # default profile
128
+ GEOPERA_PROFILE=staging geopera whoami
129
+ geopera whoami --profile staging
130
+ ```
131
+
132
+ ## Credential store
133
+
134
+ Credentials live in `~/.config/geopera/credentials.json` (directory `0700`,
135
+ file `0600`). Each top-level key is a profile:
136
+
137
+ ```json
138
+ {
139
+ "default": {
140
+ "api_url": "https://api.geopera.com",
141
+ "auth": {
142
+ "type": "oauth",
143
+ "access_token": "...",
144
+ "refresh_token": "...",
145
+ "expires_at": 1750000000,
146
+ "scope": "openid profile",
147
+ "issuer": "https://api.geopera.com"
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ For an API key profile the `auth` block is
154
+ `{"type": "api_key", "api_key": "gpra_..."}`.
155
+
156
+ ### Environment overrides
157
+
158
+ - `GEOPERA_API_URL` — base URL override (below `--api-url`, above the stored value).
159
+ - `GEOPERA_PROFILE` — active profile name.
160
+ - `GEOPERA_API_TOKEN` — opaque bearer/API-key for ephemeral (e.g. CI) use,
161
+ bypassing the store. A value starting with `gpra_` is treated as an API key.
162
+
163
+ ## Configuration precedence
164
+
165
+ API base URL: `--api-url` flag → `GEOPERA_API_URL` → stored `api_url` →
166
+ `https://api.geopera.com`.
167
+
168
+ ## License
169
+
170
+ [MIT](./LICENSE)
@@ -0,0 +1,137 @@
1
+ # geopera-cli
2
+
3
+ Command-line interface for the [Geopera](https://docs.geopera.com) geospatial
4
+ data platform.
5
+
6
+ `geopera-cli` is a **thin auth + dispatch shell** over the published
7
+ [`geopera` Python SDK](https://github.com/geo-pera/geopera-python). The only
8
+ logic that lives in the CLI is authentication — the OAuth device flow, token
9
+ refresh, and the choice between a `Bearer` token and an `X-API-Key` header.
10
+ Every actual capability is reached through the generic API endpoint
11
+ `POST /v1/op/{operation_id}`, so any of the ~227 operations is callable with no
12
+ per-command code, and a new backend operation is instantly usable as
13
+ `geopera op <new.op>` with zero CLI changes.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install geopera-cli
19
+ ```
20
+
21
+ This pulls in the `geopera` SDK, `typer`, and `httpx`.
22
+
23
+ ## Quick start
24
+
25
+ ```bash
26
+ # Sign in (opens your browser; RFC 8628 device flow)
27
+ geopera login
28
+
29
+ # Who am I?
30
+ geopera whoami
31
+
32
+ # Price-preview an order (generic op dispatch)
33
+ geopera op orders.estimate '{"aoi": {...}, "product": "..."}'
34
+
35
+ # Search across every registered public data source
36
+ geopera op catalog.federated_search '{"bbox": [...], "datetime": "..."}'
37
+
38
+ # List every available operation id
39
+ geopera op --list
40
+
41
+ # Curated alias with table output
42
+ geopera orders list
43
+ ```
44
+
45
+ ## Commands
46
+
47
+ | Command | Description |
48
+ | --- | --- |
49
+ | `geopera login` | Device-flow login (default). `--api-key KEY` stores a key instead (`-` reads from stdin). `--api-url URL`, `--no-browser`, `--scope`. |
50
+ | `geopera logout` | Clear the active profile's stored credentials (best-effort OAuth logout). |
51
+ | `geopera whoami` | Show principal / org / scope (validates the session). `--json` for raw output. |
52
+ | `geopera op OPERATION_ID [JSON]` | Generic operation dispatch. Body from positional arg, `--file`, or `-` (stdin). `--list` enumerates operations. |
53
+ | `geopera orders list` | Curated alias over `op orders.list` with table formatting. |
54
+
55
+ Global flags `--profile NAME` (env `GEOPERA_PROFILE`) and `--api-url URL`
56
+ (env `GEOPERA_API_URL`) are accepted on every command.
57
+
58
+ ## Authentication
59
+
60
+ ### Device flow (default)
61
+
62
+ `geopera login` performs the OAuth 2.0 Device Authorization Grant
63
+ ([RFC 8628](https://www.rfc-editor.org/rfc/rfc8628)) with PKCE:
64
+
65
+ 1. Requests a device + user code from
66
+ `{api_url}/realms/public/protocol/openid-connect/auth/device`.
67
+ 2. Prints the user code and opens the verification URL in your browser
68
+ (skip with `--no-browser`).
69
+ 3. Polls the token endpoint until you approve, then stores the access and
70
+ refresh tokens.
71
+
72
+ Access tokens are refreshed automatically — proactively when within 30s of
73
+ expiry, and reactively on any `401` — using the stored refresh token. The
74
+ backend rotates the refresh token, so both tokens are rewritten on each
75
+ refresh.
76
+
77
+ ### API key (headless)
78
+
79
+ ```bash
80
+ geopera login --api-key gpra_xxxxxxxx
81
+ # or, keeping the key out of shell history:
82
+ printf '%s' "$GEOPERA_KEY" | geopera login --api-key -
83
+ ```
84
+
85
+ API keys are sent as `X-API-Key`, which the Geopera API accepts on every
86
+ authenticated endpoint.
87
+
88
+ ### Profiles
89
+
90
+ Multiple identities are namespaced by profile:
91
+
92
+ ```bash
93
+ geopera login --profile staging --api-url https://staging.api.geopera.com
94
+ geopera --help # default profile
95
+ GEOPERA_PROFILE=staging geopera whoami
96
+ geopera whoami --profile staging
97
+ ```
98
+
99
+ ## Credential store
100
+
101
+ Credentials live in `~/.config/geopera/credentials.json` (directory `0700`,
102
+ file `0600`). Each top-level key is a profile:
103
+
104
+ ```json
105
+ {
106
+ "default": {
107
+ "api_url": "https://api.geopera.com",
108
+ "auth": {
109
+ "type": "oauth",
110
+ "access_token": "...",
111
+ "refresh_token": "...",
112
+ "expires_at": 1750000000,
113
+ "scope": "openid profile",
114
+ "issuer": "https://api.geopera.com"
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ For an API key profile the `auth` block is
121
+ `{"type": "api_key", "api_key": "gpra_..."}`.
122
+
123
+ ### Environment overrides
124
+
125
+ - `GEOPERA_API_URL` — base URL override (below `--api-url`, above the stored value).
126
+ - `GEOPERA_PROFILE` — active profile name.
127
+ - `GEOPERA_API_TOKEN` — opaque bearer/API-key for ephemeral (e.g. CI) use,
128
+ bypassing the store. A value starting with `gpra_` is treated as an API key.
129
+
130
+ ## Configuration precedence
131
+
132
+ API base URL: `--api-url` flag → `GEOPERA_API_URL` → stored `api_url` →
133
+ `https://api.geopera.com`.
134
+
135
+ ## License
136
+
137
+ [MIT](./LICENSE)
@@ -0,0 +1,8 @@
1
+ """geopera-cli — command-line interface for the Geopera platform.
2
+
3
+ A thin auth + dispatch shell over the published `geopera` SDK. Every capability
4
+ is reached through /v1/op/{operation_id}; the only CLI-resident logic is auth
5
+ (device flow, token refresh, and the Bearer / X-API-Key choice).
6
+ """
7
+
8
+ __version__ = "0.1.0"