GeoAlchemy2 0.17.1__py3-none-any.whl → 0.18.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.
@@ -5,14 +5,14 @@ The :class:`geoalchemy2.types.Geometry`, :class:`geoalchemy2.types.Geography`, a
5
5
  columns/properties in models.
6
6
  """
7
7
 
8
+ import re
8
9
  import warnings
9
10
  from typing import Any
10
11
  from typing import Dict
11
12
  from typing import Optional
12
13
 
14
+ from sqlalchemy import Computed
13
15
  from sqlalchemy.dialects import postgresql
14
- from sqlalchemy.dialects.postgresql.base import ischema_names as _postgresql_ischema_names
15
- from sqlalchemy.dialects.sqlite.base import ischema_names as _sqlite_ischema_names
16
16
  from sqlalchemy.ext.compiler import compiles
17
17
  from sqlalchemy.sql import func
18
18
  from sqlalchemy.types import Float
@@ -116,17 +116,17 @@ class _GISType(UserDefinedType):
116
116
  def __init__(
117
117
  self,
118
118
  geometry_type: Optional[str] = "GEOMETRY",
119
- srid=-1,
120
- dimension=2,
121
- spatial_index=True,
122
- use_N_D_index=False,
119
+ srid: int = -1,
120
+ dimension: Optional[int] = None,
121
+ spatial_index: bool = True,
122
+ use_N_D_index: bool = False,
123
123
  use_typmod: Optional[bool] = None,
124
124
  from_text: Optional[str] = None,
125
125
  name: Optional[str] = None,
126
- nullable=True,
126
+ nullable: bool = True,
127
127
  _spatial_index_reflected=None,
128
128
  ) -> None:
129
- geometry_type, srid = self.check_ctor_args(
129
+ geometry_type, srid, dimension = self.check_ctor_args(
130
130
  geometry_type, srid, dimension, use_typmod, nullable
131
131
  )
132
132
  self.geometry_type = geometry_type
@@ -195,7 +195,21 @@ class _GISType(UserDefinedType):
195
195
  'The "nullable" and "use_typmod" arguments can not be used together'
196
196
  )
197
197
 
198
- return geometry_type, srid
198
+ if dimension not in [None, 2, 3, 4]:
199
+ raise ValueError("dimension must be one of [None, 2, 3, 4] " "but got %s" % dimension)
200
+ if geometry_type is not None:
201
+ if geometry_type.endswith("ZM"):
202
+ if dimension not in [None, 4]:
203
+ raise ValueError("dimension must be 4 when geometry_type ends with 'ZM'")
204
+ dimension = 4
205
+ elif geometry_type[-1] in ["Z", "M"]:
206
+ if dimension not in [None, 3]:
207
+ raise ValueError("dimension must be 3 when geometry_type ends with 'Z' or 'M'")
208
+ dimension = 3
209
+ else:
210
+ dimension = 2
211
+
212
+ return geometry_type, srid, dimension
199
213
 
200
214
 
201
215
  @compiles(_GISType, "mysql")
@@ -206,10 +220,23 @@ def get_col_spec_mysql(self, compiler, *args, **kwargs):
206
220
  else:
207
221
  spec = "GEOMETRY"
208
222
 
209
- if not self.nullable or self.spatial_index:
210
- spec += " NOT NULL"
211
- if self.srid > 0 and compiler.dialect.name != "mariadb":
212
- spec += " SRID %d" % self.srid
223
+ type_expression = kwargs.get("type_expression", None)
224
+ if type_expression is None or type_expression.computed is None:
225
+ if not self.nullable or self.spatial_index:
226
+ spec += " NOT NULL"
227
+ if self.srid > 0 and compiler.dialect.name != "mariadb":
228
+ spec += " SRID %d" % self.srid
229
+ return spec
230
+
231
+
232
+ @compiles(Computed, "mysql")
233
+ @compiles(Computed, "mariadb")
234
+ def get_col_spec_computed_mysql(self, compiler, *args, **kwargs):
235
+ # MySQL uses a different syntax for computed columns
236
+ # than PostgreSQL, so we need to handle it here.
237
+ spec = self.sqltext.compile(compiler, **kwargs).string
238
+ pattern = re.compile("st_", re.IGNORECASE)
239
+ spec = "AS (%s)" % re.sub(pattern, "", spec)
213
240
  return spec
214
241
 
215
242
 
@@ -246,7 +273,7 @@ class Geometry(_GISType):
246
273
  ``result_processor`` method. """
247
274
 
248
275
  cache_ok = True
249
- """ Disable cache for this type. """
276
+ """ Enable cache for this type. """
250
277
 
251
278
 
252
279
  class Geography(_GISType):
@@ -276,7 +303,7 @@ class Geography(_GISType):
276
303
  ``result_processor`` method. """
277
304
 
278
305
  cache_ok = True
279
- """ Disable cache for this type. """
306
+ """ Enable cache for this type. """
280
307
 
281
308
 
282
309
  class Raster(_GISType):
@@ -316,26 +343,34 @@ class Raster(_GISType):
316
343
  ``result_processor`` method. """
317
344
 
318
345
  cache_ok = True
319
- """ Disable cache for this type. """
346
+ """ Enable cache for this type. """
320
347
 
321
- def __init__(self, spatial_index=True, from_text=None, name=None, nullable=True) -> None:
348
+ def __init__(
349
+ self,
350
+ spatial_index=True,
351
+ from_text=None,
352
+ name=None,
353
+ nullable=True,
354
+ _spatial_index_reflected=None,
355
+ ) -> None:
322
356
  # Enforce default values
323
357
  super(Raster, self).__init__(
324
358
  geometry_type=None,
325
359
  srid=-1,
326
- dimension=2,
360
+ dimension=None,
327
361
  spatial_index=spatial_index,
328
362
  use_N_D_index=False,
329
363
  use_typmod=False,
330
364
  from_text=from_text,
331
365
  name=name,
332
366
  nullable=nullable,
367
+ _spatial_index_reflected=_spatial_index_reflected,
333
368
  )
334
369
  self.extended = None
335
370
 
336
371
  @staticmethod
337
372
  def check_ctor_args(*args, **kwargs):
338
- return None, -1
373
+ return None, -1, None
339
374
 
340
375
 
341
376
  class _DummyGeometry(Geometry):
@@ -383,23 +418,6 @@ class GeometryDump(CompositeType):
383
418
  """ Enable cache for this type. """
384
419
 
385
420
 
386
- # Register Geometry, Geography and Raster to SQLAlchemy's reflection subsystems.
387
- _postgresql_ischema_names["geometry"] = Geometry
388
- _postgresql_ischema_names["geography"] = Geography
389
- _postgresql_ischema_names["raster"] = Raster
390
-
391
- _sqlite_ischema_names["GEOMETRY"] = Geometry
392
- _sqlite_ischema_names["POINT"] = Geometry
393
- _sqlite_ischema_names["LINESTRING"] = Geometry
394
- _sqlite_ischema_names["POLYGON"] = Geometry
395
- _sqlite_ischema_names["MULTIPOINT"] = Geometry
396
- _sqlite_ischema_names["MULTILINESTRING"] = Geometry
397
- _sqlite_ischema_names["MULTIPOLYGON"] = Geometry
398
- _sqlite_ischema_names["CURVE"] = Geometry
399
- _sqlite_ischema_names["GEOMETRYCOLLECTION"] = Geometry
400
- _sqlite_ischema_names["RASTER"] = Raster
401
-
402
-
403
421
  class SummaryStats(CompositeType):
404
422
  """Define the composite type returned by the function ST_SummaryStatsAgg."""
405
423
 
@@ -42,6 +42,21 @@ def bind_processor_process(spatial_type, bindvalue):
42
42
  bindvalue.srid = spatial_type.srid
43
43
  return bindvalue
44
44
  elif isinstance(bindvalue, WKBElement):
45
- # With MariaDB we use Shapely to convert the WKBElement to an EWKT string
46
- return to_shape(bindvalue).wkt
45
+ if "wkb" not in spatial_type.from_text.lower():
46
+ # With MariaDB we use Shapely to convert the WKBElement to an EWKT string
47
+ wkt = to_shape(bindvalue).wkt
48
+ if "multipoint" in wkt[:20].lower():
49
+ # Shapely>=2.1 adds parentheses around each sub-point which is not supported
50
+ first_idx = wkt.find("(")
51
+ last_idx = wkt.rfind(")")
52
+ wkt = (
53
+ wkt[: first_idx + 1]
54
+ + wkt[first_idx:last_idx].replace("(", "").replace(")", "")
55
+ + wkt[last_idx:]
56
+ )
57
+ return wkt
58
+ # MariaDB does not support raw binary data so we use the hex representation
59
+ return bindvalue.desc
60
+ elif isinstance(bindvalue, memoryview):
61
+ return bindvalue.tobytes().hex()
47
62
  return bindvalue
@@ -38,11 +38,11 @@ def bind_processor_process(spatial_type, bindvalue):
38
38
 
39
39
  if isinstance(bindvalue, WKTElement):
40
40
  bindvalue = bindvalue.as_wkt()
41
- if bindvalue.srid == -1:
41
+ if bindvalue.srid <= 0:
42
42
  bindvalue.srid = spatial_type.srid
43
43
  return bindvalue
44
44
  elif isinstance(bindvalue, WKBElement):
45
45
  if "wkb" not in spatial_type.from_text.lower():
46
46
  # With MySQL we use Shapely to convert the WKBElement to an EWKT string
47
47
  return to_shape(bindvalue).wkt
48
- return bindvalue
48
+ return bindvalue
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: GeoAlchemy2
3
- Version: 0.17.1
3
+ Version: 0.18.0
4
4
  Summary: Using SQLAlchemy with Spatial Databases
5
5
  Home-page: https://geoalchemy-2.readthedocs.io/en/stable/
6
6
  Author: Eric Lemoine
@@ -13,16 +13,14 @@ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Environment :: Plugins
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
- Classifier: Programming Language :: Python :: 3.7
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
19
16
  Classifier: Programming Language :: Python :: 3.10
20
17
  Classifier: Programming Language :: Python :: 3.11
21
18
  Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
22
20
  Classifier: Intended Audience :: Information Technology
23
21
  Classifier: License :: OSI Approved :: MIT License
24
22
  Classifier: Topic :: Scientific/Engineering :: GIS
25
- Requires-Python: >=3.7
23
+ Requires-Python: >=3.10
26
24
  License-File: COPYING.rst
27
25
  Requires-Dist: SQLAlchemy>=1.4
28
26
  Requires-Dist: packaging
@@ -35,6 +33,7 @@ Dynamic: description
35
33
  Dynamic: home-page
36
34
  Dynamic: keywords
37
35
  Dynamic: license
36
+ Dynamic: license-file
38
37
  Dynamic: project-url
39
38
  Dynamic: provides-extra
40
39
  Dynamic: requires-dist
@@ -0,0 +1,35 @@
1
+ geoalchemy2/__init__.py,sha256=YCZ2cWjNdpRLtIuGPi6Q4GX7l-4DV8YQ-D7QVYboSPk,1389
2
+ geoalchemy2/_functions.py,sha256=WuCmli7S6NzFnMyCX4KU2etLxU6AQ9XHLx32WXlQy8s,63872
3
+ geoalchemy2/_functions_helpers.py,sha256=5UEF72WdOif9ljtuDHSgSMrxjYZB5-aQDnJ1mAtxET0,2698
4
+ geoalchemy2/alembic_helpers.py,sha256=3U0Co-VdkkZ44MaRDG-ukN93dRk6qWDz2BOgcEOpTl4,27906
5
+ geoalchemy2/comparator.py,sha256=k-MdwOK4IThJi0_d_yiyRIRmfC54nbS5tR2SN5_ZEv0,8136
6
+ geoalchemy2/elements.py,sha256=ynXBSH2QeAdClfaPLSGOVuK4atQqzshXujALhsQpFuc,15312
7
+ geoalchemy2/exc.py,sha256=Nn9bRKB_35skWDMkEf4_Y2GL6gvguPVycPZcbOfa69g,226
8
+ geoalchemy2/functions.py,sha256=_s1j-PEu-KrtT_l_dOy5CpH9WP_ybNxZCLGpvD8QZ2I,10381
9
+ geoalchemy2/functions.pyi,sha256=K9OH6yiJO6YqcMA-ddjOYA4xXMxypjESn3TOV0_lmys,126010
10
+ geoalchemy2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ geoalchemy2/shape.py,sha256=TLeWa6NwXZqBxh3Zj-l96wBB5kPviEhnZ44kyr8v678,2735
12
+ geoalchemy2/utils.py,sha256=OYWYnT64tjp4DWhPdq3KIxHbVti932xPMtGGxajtu-I,488
13
+ geoalchemy2/admin/__init__.py,sha256=O5kr1ETm3lTpEELm16Oxq6344KztOZmUaapf0ZIP6b8,4016
14
+ geoalchemy2/admin/plugin.py,sha256=2U5p4_JdZM7b2MOXXBfP8KhtXlLHu-ASjxTq4mF-thg,4332
15
+ geoalchemy2/admin/dialects/__init__.py,sha256=z4gBrdglClnmp9VdDW0WwEAGNoemMUSvMCeFFvuQcgs,422
16
+ geoalchemy2/admin/dialects/common.py,sha256=er5twNOw_31xG5DpY9Gg-Ipyi0nt34R_gPdfy851JlU,3750
17
+ geoalchemy2/admin/dialects/geopackage.py,sha256=0KK61SRh6g6KDa5_0GjODhnSWBag7XHHfUuEXAmzTkQ,14788
18
+ geoalchemy2/admin/dialects/mariadb.py,sha256=pv1InVcLHmMuBLS8yo4SUnZpzm_V0rd8AU78rvmvAy0,4176
19
+ geoalchemy2/admin/dialects/mysql.py,sha256=0pIdR3_TiEGbwC61CakjMlKIMpaY1Hk_O0lVJRx2Z-g,8163
20
+ geoalchemy2/admin/dialects/postgresql.py,sha256=Ax8zhHl1K1D4ERH933PPVcwVKmj7s-3zF_aOU51jDV8,8900
21
+ geoalchemy2/admin/dialects/sqlite.py,sha256=YbGQhV0XFjNkoZ1yh4Y-lScY-e4X54AwLKm68s4ieQA,16289
22
+ geoalchemy2/types/__init__.py,sha256=KyZL-w7-re1cvJDJcqlwvBjFqGRpQ0y0M6M9UvduuF4,14868
23
+ geoalchemy2/types/dialects/__init__.py,sha256=GYqO6nDtzElvsV22VN1SSUet2elaZG4ZuRrM-asbstM,414
24
+ geoalchemy2/types/dialects/common.py,sha256=eiIKe-sFAdzgvQ7YT0cV29tYAPrs55GXKJi3p1UvjPQ,158
25
+ geoalchemy2/types/dialects/geopackage.py,sha256=nRmN_PnF-CWMEHkWhKVdsybnw3SvXZIBXAHIHXJLTqw,147
26
+ geoalchemy2/types/dialects/mariadb.py,sha256=9MXIe9jFB5HUu1B2JyO8FdgU97Mg0F8prXLBddBX4qw,2434
27
+ geoalchemy2/types/dialects/mysql.py,sha256=J689ycYgy1n5nBnrBZfuLBSyfdLZkfNHNG3PWcttx6I,1785
28
+ geoalchemy2/types/dialects/postgresql.py,sha256=7NBKEbDJXMwX8Sgs6o_N2bAUHgjUcjbrdmYOA7sDiRw,1117
29
+ geoalchemy2/types/dialects/sqlite.py,sha256=B-yLzaQcqL_4dXoOPX9D9IXw2ZQlq-Tibv_kqUIBeb4,2104
30
+ geoalchemy2-0.18.0.dist-info/licenses/COPYING.rst,sha256=-bQKftq9uMOROzF7oN65kYBBIJKxTmBuDoftp27IC3I,1056
31
+ geoalchemy2-0.18.0.dist-info/METADATA,sha256=H_xDsK9r7TTAVSsEvuwLiX7jo7-fOXU05YVQxyxXXvo,2251
32
+ geoalchemy2-0.18.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ geoalchemy2-0.18.0.dist-info/entry_points.txt,sha256=izFHecGE8cNV6IjoLkc0uEmKH13rYbbvozc4fEwRl6Y,70
34
+ geoalchemy2-0.18.0.dist-info/top_level.txt,sha256=3kGUTcfBeXd61zFpof6-qiuw1peNF_HuZabgHQgrdis,12
35
+ geoalchemy2-0.18.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,35 +0,0 @@
1
- geoalchemy2/__init__.py,sha256=aGo3WcjOBcqrvqYXBuzCff1d_WiFUFObgtcyR11gg6M,2043
2
- geoalchemy2/_functions.py,sha256=e8v584Fx_fmh8XnJvkuYEXrcyPDiWV95Mu2yw6L-LHY,62863
3
- geoalchemy2/_functions_helpers.py,sha256=V_e58pX6aalDD3HeECZbUen__2vHhEhMZty2qIZSBGA,2680
4
- geoalchemy2/alembic_helpers.py,sha256=3U0Co-VdkkZ44MaRDG-ukN93dRk6qWDz2BOgcEOpTl4,27906
5
- geoalchemy2/comparator.py,sha256=WUDXn10doDlJVnYiWbVIAhhBu7N5AO9BI8sNf2mhpA4,8100
6
- geoalchemy2/elements.py,sha256=5yd_7dUQGbrLvgYvo6A2YYAFwTvP4_BskIdBCB0DrlM,13002
7
- geoalchemy2/exc.py,sha256=Nn9bRKB_35skWDMkEf4_Y2GL6gvguPVycPZcbOfa69g,226
8
- geoalchemy2/functions.py,sha256=8VzEoE1jANlOmWM4Y6i8eGPwYSwRMLZLulqpyyCgkMs,10375
9
- geoalchemy2/functions.pyi,sha256=bQUzlBCuJXGiDVPHKwGCO5tDYH5KRYxgnERGn37BVn8,108665
10
- geoalchemy2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- geoalchemy2/shape.py,sha256=TLeWa6NwXZqBxh3Zj-l96wBB5kPviEhnZ44kyr8v678,2735
12
- geoalchemy2/utils.py,sha256=OYWYnT64tjp4DWhPdq3KIxHbVti932xPMtGGxajtu-I,488
13
- geoalchemy2/admin/__init__.py,sha256=O5kr1ETm3lTpEELm16Oxq6344KztOZmUaapf0ZIP6b8,4016
14
- geoalchemy2/admin/plugin.py,sha256=2U5p4_JdZM7b2MOXXBfP8KhtXlLHu-ASjxTq4mF-thg,4332
15
- geoalchemy2/admin/dialects/__init__.py,sha256=z4gBrdglClnmp9VdDW0WwEAGNoemMUSvMCeFFvuQcgs,422
16
- geoalchemy2/admin/dialects/common.py,sha256=p-CGtcooIESy-BiwZ8bmmdAORjuJtTK-sq_X0jnjHB0,3036
17
- geoalchemy2/admin/dialects/geopackage.py,sha256=PgOhRftDN4I_OIqqOfop7jgmospReCq6qJi6BGW-Gts,13596
18
- geoalchemy2/admin/dialects/mariadb.py,sha256=4PtkC1Gv4jcAl_grO5lJwxPsIChi4_8g36soZXnMM3w,4267
19
- geoalchemy2/admin/dialects/mysql.py,sha256=NP0qXGsvssHZKegP8m8-4Vqbx8CosNHTsq6qfSD2MHs,7181
20
- geoalchemy2/admin/dialects/postgresql.py,sha256=VwB_h3TC8M5aQ6aKE3UYgxHfbEKav3eIHJeLx534Zzg,6191
21
- geoalchemy2/admin/dialects/sqlite.py,sha256=iW5MBhbxVKGMVghN5Do0iF-_9Pbtrv65NTXmW9mOyZA,13802
22
- geoalchemy2/types/__init__.py,sha256=Ud1_6gukAs3gSzN3BThZnC-p0naHnTcNEjlyD5Ahm-M,14240
23
- geoalchemy2/types/dialects/__init__.py,sha256=GYqO6nDtzElvsV22VN1SSUet2elaZG4ZuRrM-asbstM,414
24
- geoalchemy2/types/dialects/common.py,sha256=eiIKe-sFAdzgvQ7YT0cV29tYAPrs55GXKJi3p1UvjPQ,158
25
- geoalchemy2/types/dialects/geopackage.py,sha256=nRmN_PnF-CWMEHkWhKVdsybnw3SvXZIBXAHIHXJLTqw,147
26
- geoalchemy2/types/dialects/mariadb.py,sha256=tPZpfj95XlVSOm8zC52iFbqVrIOdj-EDH5KVJP1Gd9c,1723
27
- geoalchemy2/types/dialects/mysql.py,sha256=zMNi1920v0XlVaCJWSwtq0b0P5YQRn8y3X_rBxC5KEw,1790
28
- geoalchemy2/types/dialects/postgresql.py,sha256=7NBKEbDJXMwX8Sgs6o_N2bAUHgjUcjbrdmYOA7sDiRw,1117
29
- geoalchemy2/types/dialects/sqlite.py,sha256=B-yLzaQcqL_4dXoOPX9D9IXw2ZQlq-Tibv_kqUIBeb4,2104
30
- GeoAlchemy2-0.17.1.dist-info/COPYING.rst,sha256=-bQKftq9uMOROzF7oN65kYBBIJKxTmBuDoftp27IC3I,1056
31
- GeoAlchemy2-0.17.1.dist-info/METADATA,sha256=MWAit1vb7ST4fMZOE0nkxAXMDMGyfAsLFZNLumLynGo,2327
32
- GeoAlchemy2-0.17.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
33
- GeoAlchemy2-0.17.1.dist-info/entry_points.txt,sha256=izFHecGE8cNV6IjoLkc0uEmKH13rYbbvozc4fEwRl6Y,70
34
- GeoAlchemy2-0.17.1.dist-info/top_level.txt,sha256=3kGUTcfBeXd61zFpof6-qiuw1peNF_HuZabgHQgrdis,12
35
- GeoAlchemy2-0.17.1.dist-info/RECORD,,