gispulse 1.2.0__py3-none-any.whl

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 (226) hide show
  1. capabilities/__init__.py +380 -0
  2. capabilities/base.py +106 -0
  3. capabilities/classification.py +1653 -0
  4. capabilities/clustering.py +307 -0
  5. capabilities/density.py +397 -0
  6. capabilities/network.py +974 -0
  7. capabilities/network_topology.py +493 -0
  8. capabilities/overlay.py +238 -0
  9. capabilities/palettes.py +370 -0
  10. capabilities/pointcloud.py +521 -0
  11. capabilities/polygon_topology.py +401 -0
  12. capabilities/postgis_sql.py +143 -0
  13. capabilities/raster.py +721 -0
  14. capabilities/registry.py +151 -0
  15. capabilities/relation_detector.py +355 -0
  16. capabilities/schema.py +985 -0
  17. capabilities/selection.py +313 -0
  18. capabilities/spatial_stats.py +471 -0
  19. capabilities/strategy.py +108 -0
  20. capabilities/temporal.py +268 -0
  21. capabilities/transforms.py +491 -0
  22. capabilities/validation.py +679 -0
  23. capabilities/vector/__init__.py +165 -0
  24. capabilities/vector/aggregate.py +187 -0
  25. capabilities/vector/assign_projection.py +62 -0
  26. capabilities/vector/boundary.py +51 -0
  27. capabilities/vector/buffer.py +350 -0
  28. capabilities/vector/calculate.py +204 -0
  29. capabilities/vector/centroid_area.py +107 -0
  30. capabilities/vector/chaikin.py +114 -0
  31. capabilities/vector/classify.py +224 -0
  32. capabilities/vector/clip.py +189 -0
  33. capabilities/vector/concave_hull.py +99 -0
  34. capabilities/vector/diff.py +225 -0
  35. capabilities/vector/dissolve.py +51 -0
  36. capabilities/vector/extract_holes.py +86 -0
  37. capabilities/vector/extract_ops.py +257 -0
  38. capabilities/vector/filter.py +389 -0
  39. capabilities/vector/force_geometry_type.py +220 -0
  40. capabilities/vector/intersects.py +188 -0
  41. capabilities/vector/line_merge.py +58 -0
  42. capabilities/vector/line_ops.py +193 -0
  43. capabilities/vector/merge.py +89 -0
  44. capabilities/vector/nearest.py +197 -0
  45. capabilities/vector/offset_curve.py +106 -0
  46. capabilities/vector/parts.py +202 -0
  47. capabilities/vector/polygonize.py +57 -0
  48. capabilities/vector/reproject.py +48 -0
  49. capabilities/vector/shape_ops_advanced.py +263 -0
  50. capabilities/vector/shape_ops_basic.py +207 -0
  51. capabilities/vector/simplify.py +131 -0
  52. capabilities/vector/snap_grid.py +73 -0
  53. capabilities/vector/spatial_join.py +109 -0
  54. capabilities/vector/union.py +36 -0
  55. capabilities/vector/voronoi.py +80 -0
  56. catalog/__init__.py +22 -0
  57. catalog/models.py +80 -0
  58. catalog/providers/__init__.py +1 -0
  59. catalog/providers/base.py +32 -0
  60. catalog/providers/basemaps.py +57 -0
  61. catalog/providers/flux_ign.py +152 -0
  62. catalog/providers/flux_osm.py +86 -0
  63. catalog/providers/opendata_datagouv.py +96 -0
  64. catalog/providers/opendata_hub.py +105 -0
  65. catalog/providers/opendata_ign.py +176 -0
  66. catalog/providers/projections.py +59 -0
  67. catalog/providers/stac_client.py +274 -0
  68. catalog/registry.py +85 -0
  69. core/__init__.py +1 -0
  70. core/cache.py +47 -0
  71. core/capability_params.py +247 -0
  72. core/conditions.py +120 -0
  73. core/config.py +696 -0
  74. core/crs.py +97 -0
  75. core/enums.py +139 -0
  76. core/filter/__init__.py +24 -0
  77. core/filter/cache.py +184 -0
  78. core/filter/chain.py +224 -0
  79. core/filter/expression.py +219 -0
  80. core/filter/expression_converter.py +292 -0
  81. core/filter/result.py +204 -0
  82. core/filter/service.py +230 -0
  83. core/filter/types.py +97 -0
  84. core/graph.py +118 -0
  85. core/io/__init__.py +5 -0
  86. core/io/geoparquet.py +233 -0
  87. core/logging.py +124 -0
  88. core/models.py +331 -0
  89. core/observability.py +184 -0
  90. core/pipeline.py +354 -0
  91. core/pipeline_schema.py +298 -0
  92. core/plugin_contracts.py +138 -0
  93. core/plugin_hub.py +244 -0
  94. core/predicates.py +67 -0
  95. core/registry.py +150 -0
  96. core/relations.py +72 -0
  97. core/session.py +35 -0
  98. core/sql_safety.py +104 -0
  99. gispulse/__init__.py +8 -0
  100. gispulse/adapters/__init__.py +12 -0
  101. gispulse/adapters/esb/__init__.py +25 -0
  102. gispulse/adapters/esb/action_dispatcher.py +325 -0
  103. gispulse/adapters/esb/bus_message.py +204 -0
  104. gispulse/adapters/esb/circuit_breaker.py +236 -0
  105. gispulse/adapters/esb/dlq.py +201 -0
  106. gispulse/adapters/esb/enums.py +90 -0
  107. gispulse/adapters/esb/event_router.py +300 -0
  108. gispulse/adapters/esb/pg_notify.py +225 -0
  109. gispulse/adapters/esb/pool.py +398 -0
  110. gispulse/adapters/esb/predicate_evaluator.py +14 -0
  111. gispulse/adapters/esb/state_store.py +243 -0
  112. gispulse/adapters/esb/trigger_manager.py +211 -0
  113. gispulse/adapters/esb/workers/__init__.py +7 -0
  114. gispulse/adapters/esb/workers/base_worker.py +261 -0
  115. gispulse/adapters/esb/workers/dispatch_worker.py +160 -0
  116. gispulse/adapters/esb/workers/identify_worker.py +134 -0
  117. gispulse/adapters/http/__init__.py +10 -0
  118. gispulse/adapters/http/app.py +712 -0
  119. gispulse/adapters/http/auth.py +227 -0
  120. gispulse/adapters/http/dependencies.py +168 -0
  121. gispulse/adapters/http/error_handlers.py +166 -0
  122. gispulse/adapters/http/event_hub.py +70 -0
  123. gispulse/adapters/http/layer_utils.py +132 -0
  124. gispulse/adapters/http/middleware/__init__.py +0 -0
  125. gispulse/adapters/http/middleware/audit_middleware.py +196 -0
  126. gispulse/adapters/http/middleware/metrics_middleware.py +68 -0
  127. gispulse/adapters/http/middleware/read_only.py +100 -0
  128. gispulse/adapters/http/portal_app.py +30 -0
  129. gispulse/adapters/http/rate_limit.py +61 -0
  130. gispulse/adapters/http/routers/__init__.py +1 -0
  131. gispulse/adapters/http/routers/_upload_utils.py +23 -0
  132. gispulse/adapters/http/routers/capabilities_router.py +161 -0
  133. gispulse/adapters/http/routers/catalog_router.py +428 -0
  134. gispulse/adapters/http/routers/datasets_router.py +266 -0
  135. gispulse/adapters/http/routers/esb_router.py +76 -0
  136. gispulse/adapters/http/routers/filter_router.py +409 -0
  137. gispulse/adapters/http/routers/jobs_router.py +399 -0
  138. gispulse/adapters/http/routers/marketplace_router.py +394 -0
  139. gispulse/adapters/http/routers/ogc_features_router.py +338 -0
  140. gispulse/adapters/http/routers/pipelines_router.py +632 -0
  141. gispulse/adapters/http/routers/portal_datasets_router.py +560 -0
  142. gispulse/adapters/http/routers/portal_features_router.py +206 -0
  143. gispulse/adapters/http/routers/portal_router.py +25 -0
  144. gispulse/adapters/http/routers/portal_sql_router.py +307 -0
  145. gispulse/adapters/http/routers/portal_upload_router.py +355 -0
  146. gispulse/adapters/http/routers/projects_router.py +591 -0
  147. gispulse/adapters/http/routers/relations_router.py +448 -0
  148. gispulse/adapters/http/routers/rules_router.py +261 -0
  149. gispulse/adapters/http/routers/scenarios_router.py +488 -0
  150. gispulse/adapters/http/routers/schedules_router.py +226 -0
  151. gispulse/adapters/http/routers/sessions_router.py +109 -0
  152. gispulse/adapters/http/routers/tiles_router.py +252 -0
  153. gispulse/adapters/http/routers/triggers_router.py +501 -0
  154. gispulse/adapters/http/routers/viewer_router.py +333 -0
  155. gispulse/adapters/http/routers/ws_router.py +85 -0
  156. gispulse/adapters/http/schemas.py +742 -0
  157. gispulse/adapters/http/serve_app.py +185 -0
  158. gispulse/adapters/mcp/__init__.py +11 -0
  159. gispulse/adapters/mcp/server.py +404 -0
  160. gispulse/adapters/metrics.py +10 -0
  161. gispulse/adapters/ogc/__init__.py +0 -0
  162. gispulse/adapters/ogc/auth.py +45 -0
  163. gispulse/adapters/ogc/loader.py +56 -0
  164. gispulse/adapters/ogc/wfs_client.py +254 -0
  165. gispulse/cli.py +1534 -0
  166. gispulse/config.py +51 -0
  167. gispulse/core/dispatcher.py +80 -0
  168. gispulse/telemetry.py +357 -0
  169. gispulse-1.2.0.dist-info/METADATA +624 -0
  170. gispulse-1.2.0.dist-info/RECORD +226 -0
  171. gispulse-1.2.0.dist-info/WHEEL +5 -0
  172. gispulse-1.2.0.dist-info/entry_points.txt +2 -0
  173. gispulse-1.2.0.dist-info/licenses/LICENSE +661 -0
  174. gispulse-1.2.0.dist-info/top_level.txt +8 -0
  175. orchestration/__init__.py +6 -0
  176. orchestration/capability_executor.py +87 -0
  177. orchestration/graph_executor.py +414 -0
  178. orchestration/job_queue.py +540 -0
  179. orchestration/job_queue_factory.py +35 -0
  180. orchestration/metering.py +143 -0
  181. orchestration/pipeline_executor.py +334 -0
  182. orchestration/runner.py +187 -0
  183. orchestration/scenario_runner.py +339 -0
  184. orchestration/scheduler.py +344 -0
  185. orchestration/session_manager.py +514 -0
  186. orchestration/trigger_bridge.py +161 -0
  187. orchestration/worker.py +290 -0
  188. persistence/__init__.py +165 -0
  189. persistence/audit.py +245 -0
  190. persistence/auth_models.py +83 -0
  191. persistence/auth_repository.py +319 -0
  192. persistence/bridge.py +312 -0
  193. persistence/duckdb_change_detector.py +286 -0
  194. persistence/duckdb_engine.py +286 -0
  195. persistence/engine.py +211 -0
  196. persistence/engine_factory.py +188 -0
  197. persistence/gpkg.py +400 -0
  198. persistence/gpkg_engine.py +512 -0
  199. persistence/gpkg_repository.py +179 -0
  200. persistence/gpkg_schema.py +308 -0
  201. persistence/gpkg_spatial.py +226 -0
  202. persistence/io.py +697 -0
  203. persistence/licence.py +223 -0
  204. persistence/postgis.py +289 -0
  205. persistence/project_io.py +266 -0
  206. persistence/raster_io.py +315 -0
  207. persistence/repository.py +114 -0
  208. persistence/schedule_repository.py +175 -0
  209. persistence/schema.py +260 -0
  210. persistence/session_provisioner.py +233 -0
  211. persistence/sld_converter.py +521 -0
  212. persistence/spatialite_session.py +369 -0
  213. persistence/sql_dialect.py +313 -0
  214. persistence/sqlite_repository.py +333 -0
  215. persistence/storage.py +386 -0
  216. persistence/style_converter.py +609 -0
  217. persistence/style_sidecar.py +107 -0
  218. persistence/tier.py +226 -0
  219. rules/__init__.py +6 -0
  220. rules/engine.py +163 -0
  221. rules/loader.py +95 -0
  222. rules/operation_executor.py +453 -0
  223. rules/predicates.py +532 -0
  224. rules/trigger_evaluator.py +503 -0
  225. rules/validation.py +406 -0
  226. viewer/__init__.py +0 -0
@@ -0,0 +1,380 @@
1
+ """GISPulse capabilities — spatial operations registry."""
2
+
3
+ # Auto-import capability modules so they register themselves.
4
+ # vector et postgis_sql n'ont aucune dépendance optionnelle.
5
+ import capabilities.vector # noqa: F401
6
+ import capabilities.postgis_sql # noqa: F401
7
+
8
+ # validation : dépend uniquement de geopandas/shapely (déjà obligatoires)
9
+ import capabilities.validation # noqa: F401
10
+
11
+ # Network & polygon topology repair — pure shapely, no optional deps.
12
+ import capabilities.network_topology # noqa: F401
13
+ import capabilities.polygon_topology # noqa: F401
14
+
15
+ # Spatial statistics + density — require numpy/scipy/sklearn (always installed).
16
+ import capabilities.spatial_stats # noqa: F401
17
+ import capabilities.density # noqa: F401
18
+
19
+ # Classification / choropleth — pure numpy core; mapclassify optional.
20
+ import capabilities.classification # noqa: F401
21
+
22
+ # Schema / attribute manipulation — pure pandas, no optional deps.
23
+ import capabilities.schema # noqa: F401
24
+
25
+ # Selection / row-level ops — pure pandas, no optional deps.
26
+ import capabilities.selection # noqa: F401
27
+
28
+ # Overlay (intersection / union / erase) — pure geopandas.
29
+ import capabilities.overlay # noqa: F401
30
+
31
+ # Geometry transforms — pure shapely.
32
+ import capabilities.transforms # noqa: F401
33
+
34
+ # Temporal — pure pandas.
35
+ import capabilities.temporal # noqa: F401
36
+
37
+ # Pointcloud — three pure-pandas capabilities + one optional laspy loader.
38
+ # The module imports laspy lazily inside execute(), so this top-level import is
39
+ # always safe; pointcloud_load_las raises RuntimeError if laspy is missing.
40
+ import capabilities.pointcloud # noqa: F401
41
+
42
+ from capabilities.base import Capability
43
+ from capabilities.registry import REGISTRY, get, list_all, register
44
+ from capabilities.postgis_sql import PostGISSQLCapability
45
+ from capabilities.classification import (
46
+ BivariateChoroplethCapability,
47
+ ChoroplethCapability,
48
+ ClassifyCapability,
49
+ ClassifyCategoricalCapability,
50
+ ContinuousRampCapability,
51
+ GraduatedSizeCapability,
52
+ HeadTailBreaksCapability,
53
+ NormalizeCapability,
54
+ build_graduated_style_def,
55
+ build_legend,
56
+ )
57
+ from capabilities.vector import (
58
+ AlphaShapeCapability,
59
+ AreaLengthCapability,
60
+ AssignProjectionCapability,
61
+ BoundaryCapability,
62
+ BufferCapability,
63
+ CalculateCapability,
64
+ CentroidCapability,
65
+ ChaikinSmoothCapability,
66
+ ClassifyByRingCapability,
67
+ ClipCapability,
68
+ ConcaveHullCapability,
69
+ ConvexHullCapability,
70
+ DelaunayTriangulationCapability,
71
+ DensifyVerticesCapability,
72
+ DissolveCapability,
73
+ EnvelopeCapability,
74
+ ExtractHolesCapability,
75
+ ExtractSegmentsCapability,
76
+ ExtractVerticesCapability,
77
+ FilterCapability,
78
+ ForceGeometryTypeCapability,
79
+ IntersectsCapability,
80
+ LineLocatePointCapability,
81
+ LineMergeCapability,
82
+ LineSubstringCapability,
83
+ MakeValidCapability,
84
+ MergeLayersCapability,
85
+ MinBoundingCircleCapability,
86
+ MultipartToSinglepartsCapability,
87
+ NearestNeighborCapability,
88
+ OffsetCurveCapability,
89
+ OrientedBBoxCapability,
90
+ PolygonizeCapability,
91
+ ReprojectCapability,
92
+ SimplifyCapability,
93
+ SinglepartsToMultipartCapability,
94
+ SnapToGridCapability,
95
+ SpatialAggregateCapability,
96
+ SpatialJoinCapability,
97
+ SymmetricDifferenceCapability,
98
+ UnionCapability,
99
+ VectorDiffCapability,
100
+ VoronoiPolygonsCapability,
101
+ )
102
+ from capabilities.schema import (
103
+ AddFieldCapability,
104
+ AttributeJoinCapability,
105
+ CaseWhenCapability,
106
+ CastFieldCapability,
107
+ CoalesceFieldsCapability,
108
+ DropFieldCapability,
109
+ LookupTableCapability,
110
+ PivotCapability,
111
+ RenameFieldCapability,
112
+ SelectColumnsCapability,
113
+ UnpivotCapability,
114
+ )
115
+ from capabilities.selection import (
116
+ DeduplicateCapability,
117
+ RandomSampleCapability,
118
+ SortCapability,
119
+ TopNCapability,
120
+ )
121
+ from capabilities.overlay import (
122
+ EraseCapability,
123
+ OverlayIntersectionCapability,
124
+ OverlayUnionCapability,
125
+ )
126
+ from capabilities.transforms import (
127
+ AddMCapability,
128
+ AddZCapability,
129
+ AffineTransformCapability,
130
+ DropMCapability,
131
+ DropZCapability,
132
+ ReverseLinesCapability,
133
+ SwapXYCapability,
134
+ )
135
+ from capabilities.temporal import (
136
+ TemporalFilterCapability,
137
+ TemporalJoinCapability,
138
+ )
139
+ from capabilities.pointcloud import (
140
+ PointcloudFilterClassificationCapability,
141
+ PointcloudGridSummaryCapability,
142
+ PointcloudLoadLasCapability,
143
+ PointcloudZonalHeightCapability,
144
+ )
145
+ from capabilities.spatial_stats import (
146
+ GetisOrdGStarCapability,
147
+ MoransICapability,
148
+ SpatialWeightsCapability,
149
+ )
150
+ from capabilities.density import (
151
+ GridCreateCapability,
152
+ HexGridCreateCapability,
153
+ KDEHeatmapCapability,
154
+ )
155
+ from capabilities.network_topology import (
156
+ ExtendDanglesCapability,
157
+ NodeLinesCapability,
158
+ RemoveDuplicateEdgesCapability,
159
+ RemovePseudoNodesCapability,
160
+ SnapEndpointsCapability,
161
+ )
162
+ from capabilities.polygon_topology import (
163
+ FixGapsCapability,
164
+ FixOverlapsCapability,
165
+ RemoveSliversCapability,
166
+ SnapBordersCapability,
167
+ )
168
+
169
+ # Clustering depends on scikit-learn (optional).
170
+ try:
171
+ import capabilities.clustering # noqa: F401
172
+ from capabilities.clustering import (
173
+ DBSCANClusterCapability,
174
+ HDBSCANClusterCapability,
175
+ KMeansClusterCapability,
176
+ )
177
+
178
+ _CLUSTERING_AVAILABLE = True
179
+ except ImportError:
180
+ _CLUSTERING_AVAILABLE = False
181
+ DBSCANClusterCapability = None # type: ignore[assignment, misc]
182
+ HDBSCANClusterCapability = None # type: ignore[assignment, misc]
183
+ KMeansClusterCapability = None # type: ignore[assignment, misc]
184
+ from capabilities.validation import (
185
+ AttributeValidationCapability,
186
+ CompletenessCheckCapability,
187
+ DuplicateGeometryCapability,
188
+ TopologyCheckCapability,
189
+ )
190
+
191
+ # raster : dépend de rasterio / rasterstats (optionnels)
192
+ try:
193
+ import capabilities.raster # noqa: F401
194
+ from capabilities.raster import (
195
+ ChangeDetectionCapability,
196
+ NdviCapability,
197
+ RasterClipCapability,
198
+ RasterMergeCapability,
199
+ RasterReprojectCapability,
200
+ ZonalStatsCapability,
201
+ )
202
+
203
+ _RASTER_AVAILABLE = True
204
+ except ImportError:
205
+ _RASTER_AVAILABLE = False
206
+ ChangeDetectionCapability = None # type: ignore[assignment, misc]
207
+ ZonalStatsCapability = None # type: ignore[assignment, misc]
208
+ RasterClipCapability = None # type: ignore[assignment, misc]
209
+ NdviCapability = None # type: ignore[assignment, misc]
210
+ RasterReprojectCapability = None # type: ignore[assignment, misc]
211
+ RasterMergeCapability = None # type: ignore[assignment, misc]
212
+
213
+ # network : dépend de networkx (optionnel)
214
+ try:
215
+ import capabilities.network # noqa: F401
216
+ from capabilities.network import (
217
+ ConnectivityCheckCapability,
218
+ IsochroneCapability,
219
+ MinimumSpanningTreeCapability,
220
+ NetworkAllocationCapability,
221
+ ODMatrixCapability,
222
+ ShortestPathCapability,
223
+ )
224
+
225
+ _NETWORK_AVAILABLE = True
226
+ except ImportError:
227
+ _NETWORK_AVAILABLE = False
228
+ IsochroneCapability = None # type: ignore[assignment, misc]
229
+ ShortestPathCapability = None # type: ignore[assignment, misc]
230
+ NetworkAllocationCapability = None # type: ignore[assignment, misc]
231
+ ConnectivityCheckCapability = None # type: ignore[assignment, misc]
232
+ ODMatrixCapability = None # type: ignore[assignment, misc]
233
+ MinimumSpanningTreeCapability = None # type: ignore[assignment, misc]
234
+
235
+ __all__ = [
236
+ "Capability",
237
+ "REGISTRY",
238
+ "get",
239
+ "list_all",
240
+ "register",
241
+ # classification / choropleth
242
+ "BivariateChoroplethCapability",
243
+ "ChoroplethCapability",
244
+ "ClassifyCapability",
245
+ "ClassifyCategoricalCapability",
246
+ "ContinuousRampCapability",
247
+ "GraduatedSizeCapability",
248
+ "HeadTailBreaksCapability",
249
+ "NormalizeCapability",
250
+ "build_graduated_style_def",
251
+ "build_legend",
252
+ # vector
253
+ "AlphaShapeCapability",
254
+ "AreaLengthCapability",
255
+ "AssignProjectionCapability",
256
+ "BoundaryCapability",
257
+ "BufferCapability",
258
+ "CalculateCapability",
259
+ "CentroidCapability",
260
+ "ChaikinSmoothCapability",
261
+ "ClassifyByRingCapability",
262
+ "ClipCapability",
263
+ "ConcaveHullCapability",
264
+ "ConvexHullCapability",
265
+ "DelaunayTriangulationCapability",
266
+ "DensifyVerticesCapability",
267
+ "DissolveCapability",
268
+ "EnvelopeCapability",
269
+ "ExtractHolesCapability",
270
+ "ExtractSegmentsCapability",
271
+ "ExtractVerticesCapability",
272
+ "FilterCapability",
273
+ "ForceGeometryTypeCapability",
274
+ "IntersectsCapability",
275
+ "LineLocatePointCapability",
276
+ "LineMergeCapability",
277
+ "LineSubstringCapability",
278
+ "MakeValidCapability",
279
+ "MergeLayersCapability",
280
+ "MinBoundingCircleCapability",
281
+ "MultipartToSinglepartsCapability",
282
+ "NearestNeighborCapability",
283
+ "OffsetCurveCapability",
284
+ "OrientedBBoxCapability",
285
+ "PolygonizeCapability",
286
+ "ReprojectCapability",
287
+ "SimplifyCapability",
288
+ "SinglepartsToMultipartCapability",
289
+ "SnapToGridCapability",
290
+ "SpatialAggregateCapability",
291
+ "SpatialJoinCapability",
292
+ "SymmetricDifferenceCapability",
293
+ "UnionCapability",
294
+ "VectorDiffCapability",
295
+ "VoronoiPolygonsCapability",
296
+ # schema / attribute manipulation
297
+ "AddFieldCapability",
298
+ "AttributeJoinCapability",
299
+ "CaseWhenCapability",
300
+ "CastFieldCapability",
301
+ "CoalesceFieldsCapability",
302
+ "DropFieldCapability",
303
+ "LookupTableCapability",
304
+ "PivotCapability",
305
+ "RenameFieldCapability",
306
+ "SelectColumnsCapability",
307
+ "UnpivotCapability",
308
+ # selection / row-level
309
+ "DeduplicateCapability",
310
+ "RandomSampleCapability",
311
+ "SortCapability",
312
+ "TopNCapability",
313
+ # overlay
314
+ "EraseCapability",
315
+ "OverlayIntersectionCapability",
316
+ "OverlayUnionCapability",
317
+ # geometry transforms
318
+ "AddMCapability",
319
+ "AddZCapability",
320
+ "AffineTransformCapability",
321
+ "DropMCapability",
322
+ "DropZCapability",
323
+ "ReverseLinesCapability",
324
+ "SwapXYCapability",
325
+ # temporal
326
+ "TemporalFilterCapability",
327
+ "TemporalJoinCapability",
328
+ # pointcloud (load_las requires laspy; others are pure pandas/shapely)
329
+ "PointcloudFilterClassificationCapability",
330
+ "PointcloudGridSummaryCapability",
331
+ "PointcloudLoadLasCapability",
332
+ "PointcloudZonalHeightCapability",
333
+ # spatial statistics
334
+ "GetisOrdGStarCapability",
335
+ "MoransICapability",
336
+ "SpatialWeightsCapability",
337
+ # density & tessellation
338
+ "GridCreateCapability",
339
+ "HexGridCreateCapability",
340
+ "KDEHeatmapCapability",
341
+ # network topology
342
+ "ExtendDanglesCapability",
343
+ "NodeLinesCapability",
344
+ "RemoveDuplicateEdgesCapability",
345
+ "RemovePseudoNodesCapability",
346
+ "SnapEndpointsCapability",
347
+ # polygon topology
348
+ "FixGapsCapability",
349
+ "FixOverlapsCapability",
350
+ "RemoveSliversCapability",
351
+ "SnapBordersCapability",
352
+ # clustering (None si non disponible)
353
+ "DBSCANClusterCapability",
354
+ "HDBSCANClusterCapability",
355
+ "KMeansClusterCapability",
356
+ "_CLUSTERING_AVAILABLE",
357
+ # validation (Community — toujours disponible)
358
+ "TopologyCheckCapability",
359
+ "DuplicateGeometryCapability",
360
+ "AttributeValidationCapability",
361
+ "CompletenessCheckCapability",
362
+ # raster (None si non disponible)
363
+ "ZonalStatsCapability",
364
+ "ChangeDetectionCapability",
365
+ "RasterClipCapability",
366
+ "NdviCapability",
367
+ "RasterReprojectCapability",
368
+ "RasterMergeCapability",
369
+ "_RASTER_AVAILABLE",
370
+ # network (None si non disponible)
371
+ "ShortestPathCapability",
372
+ "IsochroneCapability",
373
+ "NetworkAllocationCapability",
374
+ "ConnectivityCheckCapability",
375
+ "ODMatrixCapability",
376
+ "MinimumSpanningTreeCapability",
377
+ "_NETWORK_AVAILABLE",
378
+ # postgis
379
+ "PostGISSQLCapability",
380
+ ]
capabilities/base.py ADDED
@@ -0,0 +1,106 @@
1
+ """
2
+ Base class for all GISPulse capabilities.
3
+
4
+ Each capability encapsulates a single, reusable spatial operation.
5
+ Concrete implementations live in capabilities/vector.py (and future
6
+ capabilities/raster.py, capabilities/network.py, etc.).
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from abc import ABC, abstractmethod
12
+ from typing import TYPE_CHECKING
13
+
14
+ import geopandas as gpd
15
+
16
+ if TYPE_CHECKING:
17
+ from capabilities.strategy import ExecutionContext, ExecutionStrategy
18
+
19
+ from core.logging import get_logger
20
+
21
+ log = get_logger(__name__)
22
+
23
+
24
+ class Capability(ABC):
25
+ """Abstract base for all GISPulse spatial capabilities.
26
+
27
+ Subclasses must declare:
28
+ - ``name`` : unique snake_case identifier used in the registry.
29
+ - ``description`` : human-readable one-liner for Studio/API.
30
+
31
+ And implement:
32
+ - ``execute()`` : the spatial operation itself.
33
+ - ``get_schema()`` (optional): JSON Schema of accepted **params.
34
+
35
+ Optionally, subclasses can populate ``_strategies`` with
36
+ :class:`ExecutionStrategy` instances to enable backend-aware
37
+ dispatching via ``execute_with_context()``.
38
+ """
39
+
40
+ name: str
41
+ description: str
42
+ # Subclasses override with a list of strategies; empty tuple prevents
43
+ # accidental mutation of the shared class-level default.
44
+ _strategies: list[ExecutionStrategy] | tuple[()] = ()
45
+
46
+ @abstractmethod
47
+ def execute(self, gdf: gpd.GeoDataFrame, **params) -> gpd.GeoDataFrame:
48
+ """Run the capability on a GeoDataFrame.
49
+
50
+ Args:
51
+ gdf: Input GeoDataFrame (never mutated in-place).
52
+ **params: Capability-specific keyword arguments.
53
+
54
+ Returns:
55
+ New GeoDataFrame with the operation applied.
56
+ """
57
+ ...
58
+
59
+ def execute_with_context(
60
+ self, gdf: gpd.GeoDataFrame, ctx: ExecutionContext,
61
+ ) -> gpd.GeoDataFrame:
62
+ """Run the capability using the best available execution strategy.
63
+
64
+ Selects the highest-priority strategy that can execute in the
65
+ given context. Falls back to the plain ``execute()`` method
66
+ (Python/GeoPandas) if no strategy is eligible or none are declared.
67
+
68
+ Args:
69
+ gdf: Input GeoDataFrame (never mutated in-place).
70
+ ctx: Runtime execution context with engine info and params.
71
+
72
+ Returns:
73
+ New GeoDataFrame with the operation applied.
74
+ """
75
+ from capabilities.strategy import select_strategy
76
+
77
+ if self._strategies:
78
+ strategy = select_strategy(self._strategies, ctx)
79
+ if strategy is not None:
80
+ log.info(
81
+ "strategy_selected",
82
+ capability=self.name,
83
+ strategy=strategy.mode.value,
84
+ priority=strategy.priority,
85
+ )
86
+ return strategy.execute(gdf, ctx)
87
+ log.debug(
88
+ "no_eligible_strategy",
89
+ capability=self.name,
90
+ fallback="python",
91
+ )
92
+
93
+ # Fallback: plain execute() with params from context
94
+ return self.execute(gdf, **ctx.params)
95
+
96
+ def get_schema(self) -> dict:
97
+ """Return the JSON Schema for this capability's **params.
98
+
99
+ Used by GISPulse Studio to build dynamic forms.
100
+ Subclasses should override this to expose their parameters.
101
+
102
+ Returns:
103
+ JSON Schema dict (``{"type": "object", "properties": {...}}``)
104
+ or an empty dict when no parameters are needed.
105
+ """
106
+ return {}