cdse-client 0.3.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.
Files changed (34) hide show
  1. cdse_client-0.3.0/LICENSE +21 -0
  2. cdse_client-0.3.0/PKG-INFO +321 -0
  3. cdse_client-0.3.0/README.md +231 -0
  4. cdse_client-0.3.0/pyproject.toml +168 -0
  5. cdse_client-0.3.0/setup.cfg +4 -0
  6. cdse_client-0.3.0/src/cdse/__init__.py +101 -0
  7. cdse_client-0.3.0/src/cdse/async_client.py +335 -0
  8. cdse_client-0.3.0/src/cdse/auth.py +145 -0
  9. cdse_client-0.3.0/src/cdse/catalog.py +455 -0
  10. cdse_client-0.3.0/src/cdse/cli.py +356 -0
  11. cdse_client-0.3.0/src/cdse/client.py +504 -0
  12. cdse_client-0.3.0/src/cdse/converters.py +232 -0
  13. cdse_client-0.3.0/src/cdse/downloader.py +676 -0
  14. cdse_client-0.3.0/src/cdse/exceptions.py +43 -0
  15. cdse_client-0.3.0/src/cdse/geocoding.py +246 -0
  16. cdse_client-0.3.0/src/cdse/geometry.py +496 -0
  17. cdse_client-0.3.0/src/cdse/product.py +153 -0
  18. cdse_client-0.3.0/src/cdse/py.typed +0 -0
  19. cdse_client-0.3.0/src/cdse_client.egg-info/PKG-INFO +321 -0
  20. cdse_client-0.3.0/src/cdse_client.egg-info/SOURCES.txt +32 -0
  21. cdse_client-0.3.0/src/cdse_client.egg-info/dependency_links.txt +1 -0
  22. cdse_client-0.3.0/src/cdse_client.egg-info/entry_points.txt +2 -0
  23. cdse_client-0.3.0/src/cdse_client.egg-info/requires.txt +67 -0
  24. cdse_client-0.3.0/src/cdse_client.egg-info/top_level.txt +1 -0
  25. cdse_client-0.3.0/tests/test_async_client.py +27 -0
  26. cdse_client-0.3.0/tests/test_auth.py +125 -0
  27. cdse_client-0.3.0/tests/test_catalog.py +205 -0
  28. cdse_client-0.3.0/tests/test_cli.py +328 -0
  29. cdse_client-0.3.0/tests/test_client.py +149 -0
  30. cdse_client-0.3.0/tests/test_converters.py +279 -0
  31. cdse_client-0.3.0/tests/test_downloader.py +180 -0
  32. cdse_client-0.3.0/tests/test_geocoding.py +213 -0
  33. cdse_client-0.3.0/tests/test_geometry.py +188 -0
  34. cdse_client-0.3.0/tests/test_product.py +128 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Vito D'Elia
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,321 @@
1
+ Metadata-Version: 2.4
2
+ Name: cdse-client
3
+ Version: 0.3.0
4
+ Summary: Python client for Copernicus Data Space Ecosystem (CDSE) - Drop-in replacement for sentinelsat
5
+ Author-email: Vito D'Elia <75219756+VTvito@users.noreply.github.com>
6
+ Maintainer-email: Vito D'Elia <75219756+VTvito@users.noreply.github.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/VTvito/cdse-client
9
+ Project-URL: Documentation, https://github.com/VTvito/cdse-client#readme
10
+ Project-URL: Repository, https://github.com/VTvito/cdse-client.git
11
+ Project-URL: Issues, https://github.com/VTvito/cdse-client/issues
12
+ Project-URL: Changelog, https://github.com/VTvito/cdse-client/blob/main/CHANGELOG.md
13
+ Keywords: copernicus,sentinel,satellite,remote-sensing,earth-observation,CDSE,STAC,sentinelsat
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: GIS
25
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: requests>=2.28.0
30
+ Requires-Dist: requests-oauthlib>=1.3.0
31
+ Requires-Dist: oauthlib>=3.2.0
32
+ Requires-Dist: tqdm>=4.64.0
33
+ Requires-Dist: python-dateutil>=2.8.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
36
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
37
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
38
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
39
+ Requires-Dist: responses>=0.22.0; extra == "dev"
40
+ Requires-Dist: black>=23.0.0; extra == "dev"
41
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
42
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
43
+ Requires-Dist: build>=1.0.0; extra == "dev"
44
+ Requires-Dist: twine>=4.0.0; extra == "dev"
45
+ Requires-Dist: bandit>=1.7.0; extra == "dev"
46
+ Requires-Dist: types-requests>=2.28.0; extra == "dev"
47
+ Requires-Dist: types-tqdm>=4.64.0; extra == "dev"
48
+ Provides-Extra: docs
49
+ Requires-Dist: mkdocs>=1.5.0; extra == "docs"
50
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
51
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
52
+ Requires-Dist: mkdocs-gen-files>=0.5.0; extra == "docs"
53
+ Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == "docs"
54
+ Requires-Dist: mkdocs-section-index>=0.3.0; extra == "docs"
55
+ Provides-Extra: geo
56
+ Requires-Dist: shapely>=2.0.0; extra == "geo"
57
+ Requires-Dist: geojson>=3.0.0; extra == "geo"
58
+ Requires-Dist: geopy>=2.4.0; extra == "geo"
59
+ Requires-Dist: geopandas>=0.14.0; extra == "geo"
60
+ Provides-Extra: dataframe
61
+ Requires-Dist: pandas>=2.0.0; extra == "dataframe"
62
+ Provides-Extra: async
63
+ Requires-Dist: aiohttp>=3.9.0; extra == "async"
64
+ Requires-Dist: aiofiles>=23.0.0; extra == "async"
65
+ Provides-Extra: processing
66
+ Requires-Dist: rasterio>=1.3.0; extra == "processing"
67
+ Requires-Dist: shapely>=2.0.0; extra == "processing"
68
+ Requires-Dist: numpy>=1.24.0; extra == "processing"
69
+ Requires-Dist: Pillow>=10.0.0; extra == "processing"
70
+ Requires-Dist: matplotlib>=3.7.0; extra == "processing"
71
+ Provides-Extra: all
72
+ Requires-Dist: shapely>=2.0.0; extra == "all"
73
+ Requires-Dist: geojson>=3.0.0; extra == "all"
74
+ Requires-Dist: geopy>=2.4.0; extra == "all"
75
+ Requires-Dist: geopandas>=0.14.0; extra == "all"
76
+ Requires-Dist: pandas>=2.0.0; extra == "all"
77
+ Requires-Dist: aiohttp>=3.9.0; extra == "all"
78
+ Requires-Dist: aiofiles>=23.0.0; extra == "all"
79
+ Requires-Dist: rasterio>=1.3.0; extra == "all"
80
+ Requires-Dist: numpy>=1.24.0; extra == "all"
81
+ Requires-Dist: Pillow>=10.0.0; extra == "all"
82
+ Requires-Dist: matplotlib>=3.7.0; extra == "all"
83
+ Requires-Dist: mkdocs>=1.5.0; extra == "all"
84
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "all"
85
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "all"
86
+ Requires-Dist: mkdocs-gen-files>=0.5.0; extra == "all"
87
+ Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == "all"
88
+ Requires-Dist: mkdocs-section-index>=0.3.0; extra == "all"
89
+ Dynamic: license-file
90
+
91
+ # cdse-client
92
+
93
+ [![PyPI version](https://badge.fury.io/py/cdse-client.svg)](https://badge.fury.io/py/cdse-client)
94
+ [![Python](https://img.shields.io/pypi/pyversions/cdse-client.svg)](https://pypi.org/project/cdse-client/)
95
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
96
+
97
+ **Python client for Copernicus Data Space Ecosystem (CDSE)** — a modern replacement for `sentinelsat`.
98
+
99
+ Requires Python >= 3.9.
100
+
101
+ ## Installation
102
+
103
+ ```bash
104
+ pip install cdse-client # Core
105
+ pip install cdse-client[geo] # + shapely, geopandas, geopy
106
+ pip install cdse-client[dataframe] # + pandas
107
+ pip install cdse-client[processing] # + rasterio, numpy, pillow, matplotlib, shapely
108
+ pip install cdse-client[async] # + aiohttp, aiofiles
109
+ pip install cdse-client[all] # Everything
110
+ ```
111
+
112
+ ## Setup
113
+
114
+ 1. Register at [Copernicus Data Space](https://dataspace.copernicus.eu/)
115
+ 2. Create OAuth2 credentials in [Account Settings](https://dataspace.copernicus.eu/profile)
116
+
117
+ Environment variables:
118
+
119
+ - macOS/Linux (bash/zsh)
120
+ ```bash
121
+ export CDSE_CLIENT_ID="your-client-id"
122
+ export CDSE_CLIENT_SECRET="your-client-secret"
123
+ ```
124
+ - Windows (PowerShell)
125
+ ```powershell
126
+ $env:CDSE_CLIENT_ID = "your-client-id"
127
+ $env:CDSE_CLIENT_SECRET = "your-client-secret"
128
+ ```
129
+
130
+ ## Quick start
131
+
132
+ ```python
133
+ from cdse import CDSEClient
134
+
135
+ client = CDSEClient() # Uses environment variables
136
+
137
+ # Search Sentinel-2 products
138
+ products = client.search(
139
+ bbox=[9.0, 45.0, 9.5, 45.5], # Milan area
140
+ start_date="2024-01-01",
141
+ end_date="2024-01-31",
142
+ collection="sentinel-2-l2a",
143
+ cloud_cover_max=20,
144
+ limit=5
145
+ )
146
+
147
+ # Download
148
+ for product in products:
149
+ client.download(product)
150
+ ```
151
+
152
+ ## Search methods
153
+
154
+ ```python
155
+ # By bounding box
156
+ products = client.search(bbox=[lon_min, lat_min, lon_max, lat_max], ...)
157
+
158
+ # By geographic point
159
+ products = client.search_by_point(lon=9.19, lat=45.46, buffer_km=10, ...)
160
+
161
+ # By city name (requires [geo])
162
+ products = client.search_by_city(city_name="Milano, Italia", ...)
163
+
164
+ # By product name (OData catalogue)
165
+ products = client.search_by_name("S2A_MSIL2A_20240115T102351...", exact=True)
166
+
167
+ # By UUID (OData catalogue)
168
+ product = client.search_by_id("a1b2c3d4-e5f6...")
169
+ ```
170
+
171
+ Note: `search()` returns STAC results; product identifiers there are not guaranteed to be OData UUIDs. If you need a UUID, use `search_by_name(..., exact=True)`.
172
+
173
+ **Collections**: `sentinel-1-grd`, `sentinel-2-l1c`, `sentinel-2-l2a`, `sentinel-3-olci`, `sentinel-3-slstr`, `sentinel-5p-l2`
174
+
175
+ ## Download methods
176
+
177
+ ```python
178
+ # Single product
179
+ client.download(product, output_dir="./downloads")
180
+
181
+ # Multiple products (parallel)
182
+ client.download_all(products, parallel=True, max_workers=4)
183
+
184
+ # With checksum verification
185
+ client.download_with_checksum(product)
186
+
187
+ # Quicklook preview only
188
+ client.download_quicklook(product)
189
+ client.download_all_quicklooks(products)
190
+ ```
191
+
192
+ ## Data export (sentinelsat compatible)
193
+
194
+ ```python
195
+ # DataFrame for sorting/filtering
196
+ df = client.to_dataframe(products)
197
+ df.sort_values('cloud_cover').to_csv("products.csv")
198
+
199
+ # GeoJSON footprints
200
+ geojson = client.to_geojson(products)
201
+
202
+ # GeoDataFrame for spatial analysis (requires [geo])
203
+ gdf = client.to_geodataframe(products)
204
+ gdf.plot()
205
+
206
+ # Total size
207
+ size_gb = client.get_products_size(products)
208
+ ```
209
+
210
+ ## Geometry utilities
211
+
212
+ ```python
213
+ from cdse import read_geojson, geojson_to_wkt, bbox_to_geojson
214
+
215
+ geojson = read_geojson("area.geojson")
216
+ wkt = geojson_to_wkt(geojson)
217
+ geojson = bbox_to_geojson([9.0, 45.0, 9.5, 45.5])
218
+ ```
219
+
220
+ ## Processing
221
+
222
+ ```bash
223
+ pip install cdse-client[processing]
224
+ ```
225
+
226
+ ```python
227
+ from cdse.processing import calculate_ndvi, crop_and_stack, preview_product
228
+
229
+ # Extract bands, crop to AOI, stack into GeoTIFF
230
+ result = crop_and_stack(
231
+ safe_path="S2A_MSIL2A_20240115.zip",
232
+ bbox=[9.15, 45.45, 9.25, 45.55],
233
+ bands=["B04", "B03", "B02", "B08"],
234
+ resolution=10
235
+ )
236
+
237
+ # Calculate NDVI
238
+ ndvi = calculate_ndvi(nir_path="B08.tif", red_path="B04.tif")
239
+
240
+ # Preview in Jupyter
241
+ preview_product(safe_path="...", bbox=[...], display=True)
242
+ ```
243
+
244
+ ## Async support
245
+
246
+ ```bash
247
+ pip install cdse-client[async]
248
+ ```
249
+
250
+ ```python
251
+ import asyncio
252
+ from cdse import CDSEClientAsync
253
+
254
+ async def main():
255
+ async with CDSEClientAsync(client_id, client_secret) as client:
256
+ products = await client.search(...)
257
+ paths = await client.download_all(products)
258
+
259
+ asyncio.run(main())
260
+ ```
261
+
262
+ ## CLI
263
+
264
+ ```bash
265
+ # Search
266
+ cdse search --bbox 9.0,45.0,9.5,45.5 -s 2024-01-01 -e 2024-01-31 -c 20 -l 5
267
+
268
+ # Download by name/UUID
269
+ cdse download --name S2A_MSIL2A_20240115T102351...
270
+ cdse download --uuid a1b2c3d4-... [--quicklook] [--checksum]
271
+
272
+ # List collections
273
+ cdse collections
274
+
275
+ # Help
276
+ cdse --help
277
+ ```
278
+
279
+ ## Migration from sentinelsat
280
+
281
+ | sentinelsat | cdse-client |
282
+ |-------------|-------------|
283
+ | `SentinelAPI(user, password)` | `CDSEClient(client_id, client_secret)` |
284
+ | `api.query(area, date, ...)` | `client.search(bbox, start_date, ...)` |
285
+ | `api.download(uuid)` | `client.download(product)` |
286
+ | `api.download_all(products)` | `client.download_all(products)` |
287
+ | `api.download_quicklook(uuid)` | `client.download_quicklook(product)` |
288
+ | `api.to_dataframe(products)` | `client.to_dataframe(products)` |
289
+ | `api.to_geojson(products)` | `client.to_geojson(products)` |
290
+ | `read_geojson(path)` | `read_geojson(path)` |
291
+ | `geojson_to_wkt(geojson)` | `geojson_to_wkt(geojson)` |
292
+
293
+ ## Resources
294
+
295
+ - [Copernicus Data Space](https://dataspace.copernicus.eu/)
296
+ - [CDSE API Documentation](https://documentation.dataspace.copernicus.eu/)
297
+
298
+ ## Documentation (MkDocs)
299
+
300
+ Build and preview locally:
301
+
302
+ ```bash
303
+ pip install -e ".[docs]"
304
+ mkdocs serve
305
+ ```
306
+
307
+ ## Disclaimer
308
+
309
+ This is an **unofficial** client library and is not affiliated with, endorsed by, or connected to ESA, the European Commission, or the Copernicus Programme.
310
+
311
+ Copernicus Data Space Ecosystem and Sentinel data are provided by ESA and the European Commission. Users must:
312
+
313
+ 1. Register at [dataspace.copernicus.eu](https://dataspace.copernicus.eu/)
314
+ 2. Comply with the [Terms and Conditions](https://dataspace.copernicus.eu/terms-and-conditions)
315
+ 3. Respect [API quotas and fair usage policies](https://documentation.dataspace.copernicus.eu/Quotas.html)
316
+
317
+ Sentinel data is available under a **free, full, and open** data policy for any use, including commercial. See the [Sentinel Data Legal Notice](https://sentinels.copernicus.eu/documents/247904/690755/Sentinel_Data_Legal_Notice).
318
+
319
+ ## License
320
+
321
+ MIT License - see [LICENSE](LICENSE)
@@ -0,0 +1,231 @@
1
+ # cdse-client
2
+
3
+ [![PyPI version](https://badge.fury.io/py/cdse-client.svg)](https://badge.fury.io/py/cdse-client)
4
+ [![Python](https://img.shields.io/pypi/pyversions/cdse-client.svg)](https://pypi.org/project/cdse-client/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ **Python client for Copernicus Data Space Ecosystem (CDSE)** — a modern replacement for `sentinelsat`.
8
+
9
+ Requires Python >= 3.9.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install cdse-client # Core
15
+ pip install cdse-client[geo] # + shapely, geopandas, geopy
16
+ pip install cdse-client[dataframe] # + pandas
17
+ pip install cdse-client[processing] # + rasterio, numpy, pillow, matplotlib, shapely
18
+ pip install cdse-client[async] # + aiohttp, aiofiles
19
+ pip install cdse-client[all] # Everything
20
+ ```
21
+
22
+ ## Setup
23
+
24
+ 1. Register at [Copernicus Data Space](https://dataspace.copernicus.eu/)
25
+ 2. Create OAuth2 credentials in [Account Settings](https://dataspace.copernicus.eu/profile)
26
+
27
+ Environment variables:
28
+
29
+ - macOS/Linux (bash/zsh)
30
+ ```bash
31
+ export CDSE_CLIENT_ID="your-client-id"
32
+ export CDSE_CLIENT_SECRET="your-client-secret"
33
+ ```
34
+ - Windows (PowerShell)
35
+ ```powershell
36
+ $env:CDSE_CLIENT_ID = "your-client-id"
37
+ $env:CDSE_CLIENT_SECRET = "your-client-secret"
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ ```python
43
+ from cdse import CDSEClient
44
+
45
+ client = CDSEClient() # Uses environment variables
46
+
47
+ # Search Sentinel-2 products
48
+ products = client.search(
49
+ bbox=[9.0, 45.0, 9.5, 45.5], # Milan area
50
+ start_date="2024-01-01",
51
+ end_date="2024-01-31",
52
+ collection="sentinel-2-l2a",
53
+ cloud_cover_max=20,
54
+ limit=5
55
+ )
56
+
57
+ # Download
58
+ for product in products:
59
+ client.download(product)
60
+ ```
61
+
62
+ ## Search methods
63
+
64
+ ```python
65
+ # By bounding box
66
+ products = client.search(bbox=[lon_min, lat_min, lon_max, lat_max], ...)
67
+
68
+ # By geographic point
69
+ products = client.search_by_point(lon=9.19, lat=45.46, buffer_km=10, ...)
70
+
71
+ # By city name (requires [geo])
72
+ products = client.search_by_city(city_name="Milano, Italia", ...)
73
+
74
+ # By product name (OData catalogue)
75
+ products = client.search_by_name("S2A_MSIL2A_20240115T102351...", exact=True)
76
+
77
+ # By UUID (OData catalogue)
78
+ product = client.search_by_id("a1b2c3d4-e5f6...")
79
+ ```
80
+
81
+ Note: `search()` returns STAC results; product identifiers there are not guaranteed to be OData UUIDs. If you need a UUID, use `search_by_name(..., exact=True)`.
82
+
83
+ **Collections**: `sentinel-1-grd`, `sentinel-2-l1c`, `sentinel-2-l2a`, `sentinel-3-olci`, `sentinel-3-slstr`, `sentinel-5p-l2`
84
+
85
+ ## Download methods
86
+
87
+ ```python
88
+ # Single product
89
+ client.download(product, output_dir="./downloads")
90
+
91
+ # Multiple products (parallel)
92
+ client.download_all(products, parallel=True, max_workers=4)
93
+
94
+ # With checksum verification
95
+ client.download_with_checksum(product)
96
+
97
+ # Quicklook preview only
98
+ client.download_quicklook(product)
99
+ client.download_all_quicklooks(products)
100
+ ```
101
+
102
+ ## Data export (sentinelsat compatible)
103
+
104
+ ```python
105
+ # DataFrame for sorting/filtering
106
+ df = client.to_dataframe(products)
107
+ df.sort_values('cloud_cover').to_csv("products.csv")
108
+
109
+ # GeoJSON footprints
110
+ geojson = client.to_geojson(products)
111
+
112
+ # GeoDataFrame for spatial analysis (requires [geo])
113
+ gdf = client.to_geodataframe(products)
114
+ gdf.plot()
115
+
116
+ # Total size
117
+ size_gb = client.get_products_size(products)
118
+ ```
119
+
120
+ ## Geometry utilities
121
+
122
+ ```python
123
+ from cdse import read_geojson, geojson_to_wkt, bbox_to_geojson
124
+
125
+ geojson = read_geojson("area.geojson")
126
+ wkt = geojson_to_wkt(geojson)
127
+ geojson = bbox_to_geojson([9.0, 45.0, 9.5, 45.5])
128
+ ```
129
+
130
+ ## Processing
131
+
132
+ ```bash
133
+ pip install cdse-client[processing]
134
+ ```
135
+
136
+ ```python
137
+ from cdse.processing import calculate_ndvi, crop_and_stack, preview_product
138
+
139
+ # Extract bands, crop to AOI, stack into GeoTIFF
140
+ result = crop_and_stack(
141
+ safe_path="S2A_MSIL2A_20240115.zip",
142
+ bbox=[9.15, 45.45, 9.25, 45.55],
143
+ bands=["B04", "B03", "B02", "B08"],
144
+ resolution=10
145
+ )
146
+
147
+ # Calculate NDVI
148
+ ndvi = calculate_ndvi(nir_path="B08.tif", red_path="B04.tif")
149
+
150
+ # Preview in Jupyter
151
+ preview_product(safe_path="...", bbox=[...], display=True)
152
+ ```
153
+
154
+ ## Async support
155
+
156
+ ```bash
157
+ pip install cdse-client[async]
158
+ ```
159
+
160
+ ```python
161
+ import asyncio
162
+ from cdse import CDSEClientAsync
163
+
164
+ async def main():
165
+ async with CDSEClientAsync(client_id, client_secret) as client:
166
+ products = await client.search(...)
167
+ paths = await client.download_all(products)
168
+
169
+ asyncio.run(main())
170
+ ```
171
+
172
+ ## CLI
173
+
174
+ ```bash
175
+ # Search
176
+ cdse search --bbox 9.0,45.0,9.5,45.5 -s 2024-01-01 -e 2024-01-31 -c 20 -l 5
177
+
178
+ # Download by name/UUID
179
+ cdse download --name S2A_MSIL2A_20240115T102351...
180
+ cdse download --uuid a1b2c3d4-... [--quicklook] [--checksum]
181
+
182
+ # List collections
183
+ cdse collections
184
+
185
+ # Help
186
+ cdse --help
187
+ ```
188
+
189
+ ## Migration from sentinelsat
190
+
191
+ | sentinelsat | cdse-client |
192
+ |-------------|-------------|
193
+ | `SentinelAPI(user, password)` | `CDSEClient(client_id, client_secret)` |
194
+ | `api.query(area, date, ...)` | `client.search(bbox, start_date, ...)` |
195
+ | `api.download(uuid)` | `client.download(product)` |
196
+ | `api.download_all(products)` | `client.download_all(products)` |
197
+ | `api.download_quicklook(uuid)` | `client.download_quicklook(product)` |
198
+ | `api.to_dataframe(products)` | `client.to_dataframe(products)` |
199
+ | `api.to_geojson(products)` | `client.to_geojson(products)` |
200
+ | `read_geojson(path)` | `read_geojson(path)` |
201
+ | `geojson_to_wkt(geojson)` | `geojson_to_wkt(geojson)` |
202
+
203
+ ## Resources
204
+
205
+ - [Copernicus Data Space](https://dataspace.copernicus.eu/)
206
+ - [CDSE API Documentation](https://documentation.dataspace.copernicus.eu/)
207
+
208
+ ## Documentation (MkDocs)
209
+
210
+ Build and preview locally:
211
+
212
+ ```bash
213
+ pip install -e ".[docs]"
214
+ mkdocs serve
215
+ ```
216
+
217
+ ## Disclaimer
218
+
219
+ This is an **unofficial** client library and is not affiliated with, endorsed by, or connected to ESA, the European Commission, or the Copernicus Programme.
220
+
221
+ Copernicus Data Space Ecosystem and Sentinel data are provided by ESA and the European Commission. Users must:
222
+
223
+ 1. Register at [dataspace.copernicus.eu](https://dataspace.copernicus.eu/)
224
+ 2. Comply with the [Terms and Conditions](https://dataspace.copernicus.eu/terms-and-conditions)
225
+ 3. Respect [API quotas and fair usage policies](https://documentation.dataspace.copernicus.eu/Quotas.html)
226
+
227
+ Sentinel data is available under a **free, full, and open** data policy for any use, including commercial. See the [Sentinel Data Legal Notice](https://sentinels.copernicus.eu/documents/247904/690755/Sentinel_Data_Legal_Notice).
228
+
229
+ ## License
230
+
231
+ MIT License - see [LICENSE](LICENSE)