GeoAlchemy2 0.14.7__tar.gz → 0.15.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 (133) hide show
  1. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/workflows/test_and_publish.yml +8 -2
  2. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.pre-commit-config.yaml +3 -3
  3. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/CHANGES.txt +6 -0
  4. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0/GeoAlchemy2.egg-info}/PKG-INFO +1 -1
  5. {GeoAlchemy2-0.14.7/GeoAlchemy2.egg-info → geoalchemy2-0.15.0}/PKG-INFO +1 -1
  6. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/conf.py +3 -0
  7. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/spatialite_tutorial.rst +1 -1
  8. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/__init__.py +1 -0
  9. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/_functions_helpers.py +2 -2
  10. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/__init__.py +1 -0
  11. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/__init__.py +1 -0
  12. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/common.py +1 -0
  13. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/geopackage.py +1 -0
  14. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/mysql.py +1 -0
  15. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/postgresql.py +1 -0
  16. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/admin/dialects/sqlite.py +1 -0
  17. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/alembic_helpers.py +1 -0
  18. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/comparator.py +1 -0
  19. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/elements.py +1 -0
  20. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/functions.py +1 -0
  21. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/functions.pyi +2 -2
  22. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/shape.py +1 -0
  23. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/__init__.py +1 -0
  24. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/dialects/__init__.py +1 -0
  25. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/dialects/geopackage.py +1 -0
  26. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/dialects/mysql.py +1 -0
  27. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/dialects/postgresql.py +1 -0
  28. geoalchemy2-0.15.0/geoalchemy2/types/dialects/sqlite.py +50 -0
  29. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/Dockerfile +1 -1
  30. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/helpers/install_requirements.sh +6 -4
  31. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_decipher_raster.py +1 -0
  32. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_disable_wrapping.py +1 -0
  33. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_insert_raster.py +1 -0
  34. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_length_at_insert.py +1 -0
  35. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_orm_mapped_v2.py +1 -0
  36. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_raster_transform.py +1 -0
  37. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_specific_compilation.py +1 -0
  38. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_summarystatsagg.py +1 -0
  39. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/test_type_decorator.py +1 -0
  40. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/schema_fixtures.py +2 -1
  41. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_alembic_migrations.py +1 -0
  42. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functional.py +135 -1
  43. GeoAlchemy2-0.14.7/geoalchemy2/types/dialects/sqlite.py +0 -21
  44. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.codespellrc +0 -0
  45. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.coveragerc +0 -0
  46. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.flake8 +0 -0
  47. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  48. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  49. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  50. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
  51. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/dependabot.yml +0 -0
  52. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.github/pull_request_template.md +0 -0
  53. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.gitignore +0 -0
  54. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/.readthedocs.yaml +0 -0
  55. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/COPYING.rst +0 -0
  56. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2.egg-info/SOURCES.txt +0 -0
  57. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2.egg-info/dependency_links.txt +0 -0
  58. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2.egg-info/not-zip-safe +0 -0
  59. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2.egg-info/requires.txt +0 -0
  60. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2.egg-info/top_level.txt +0 -0
  61. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/GeoAlchemy2_dev.yml +0 -0
  62. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/MANIFEST.in +0 -0
  63. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/README.rst +0 -0
  64. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/RELEASE.rst +0 -0
  65. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/TEST.rst +0 -0
  66. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/Makefile +0 -0
  67. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_static/geoalchemy.png +0 -0
  68. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_static/geoalchemy.svg +0 -0
  69. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_static/geoalchemy_small.png +0 -0
  70. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_static/geoalchemy_small.svg +0 -0
  71. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_templates/sidebar-about.html +0 -0
  72. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_templates/sidebar-links.html +0 -0
  73. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_templates/sidebar-logo.html +0 -0
  74. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/LICENSE +0 -0
  75. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/README +0 -0
  76. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/flask/layout.html +0 -0
  77. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/flask/relations.html +0 -0
  78. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/flask/static/flasky.css_t +0 -0
  79. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/flask/static/small_flask.css +0 -0
  80. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/_themes/flask/theme.conf +0 -0
  81. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/admin.rst +0 -0
  82. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/alembic.rst +0 -0
  83. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/alembic_helpers.rst +0 -0
  84. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/changelog.rst +0 -0
  85. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/core_tutorial.rst +0 -0
  86. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/elements.rst +0 -0
  87. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/index.rst +0 -0
  88. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/make.bat +0 -0
  89. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/migrate.rst +0 -0
  90. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/orm_tutorial.rst +0 -0
  91. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/shape.rst +0 -0
  92. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/spatial_functions.rst +0 -0
  93. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/spatial_operators.rst +0 -0
  94. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/doc/types.rst +0 -0
  95. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/generate_type_stubs.py +0 -0
  96. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/_functions.py +0 -0
  97. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/exc.py +0 -0
  98. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/py.typed +0 -0
  99. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/types/dialects/common.py +0 -0
  100. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/geoalchemy2/utils.py +0 -0
  101. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/pyproject.toml +0 -0
  102. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/requirements-doc.txt +0 -0
  103. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/requirements-mypy.txt +0 -0
  104. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/requirements-rtd.txt +0 -0
  105. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/requirements.txt +0 -0
  106. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/setup.cfg +0 -0
  107. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/setup.py +0 -0
  108. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/.dockerignore +0 -0
  109. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/.gitignore +0 -0
  110. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/build.sh +0 -0
  111. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/helpers/entrypoint.sh +0 -0
  112. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/helpers/init_mysql.sh +0 -0
  113. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/helpers/init_postgres.sh +0 -0
  114. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/test_container/run.sh +0 -0
  115. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/__init__.py +0 -0
  116. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/alembic_config/alembic.ini +0 -0
  117. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/conftest.py +0 -0
  118. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/data/spatialite_ge_4.sqlite +0 -0
  119. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/data/spatialite_geopackage.gpkg +0 -0
  120. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/data/spatialite_lt_4.sqlite +0 -0
  121. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/README.rst +0 -0
  122. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/gallery/__init__.py +0 -0
  123. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_comparator.py +0 -0
  124. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_elements.py +0 -0
  125. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functional_geopackage.py +0 -0
  126. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functional_mysql.py +0 -0
  127. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functional_postgresql.py +0 -0
  128. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functional_sqlite.py +0 -0
  129. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_functions.py +0 -0
  130. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_pickle.py +0 -0
  131. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_shape.py +0 -0
  132. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tests/test_types.py +0 -0
  133. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.0}/tox.ini +0 -0
@@ -41,7 +41,7 @@ jobs:
41
41
 
42
42
  services:
43
43
  postgres:
44
- image: mdillon/postgis:11
44
+ image: postgis/postgis:16-3.4
45
45
  env:
46
46
  POSTGRES_DB: gis
47
47
  POSTGRES_PASSWORD: gis
@@ -84,11 +84,17 @@ jobs:
84
84
  psql -h localhost -p 5432 -U gis -d gis -c 'CREATE SCHEMA gis;'
85
85
 
86
86
  # Add PostGIS extension to "gis" database
87
- psql -h localhost -p 5432 -U gis -d gis -c 'CREATE EXTENSION IF NOT EXISTS postgis;'
87
+ psql -h localhost -p 5432 -U gis -d gis -c 'CREATE EXTENSION IF NOT EXISTS postgis SCHEMA public;'
88
88
 
89
89
  # Drop PostGIS Tiger Geocoder extension to "gis" database
90
90
  psql -h localhost -p 5432 -U gis -d gis -c 'DROP EXTENSION IF EXISTS postgis_tiger_geocoder CASCADE;'
91
91
 
92
+ # Add PostGISRaster extension to "gis" database
93
+ psql -h localhost -p 5432 -U gis -d gis -c 'CREATE EXTENSION IF NOT EXISTS postgis_raster SCHEMA public;'
94
+
95
+ # Drop PostGIS Topology extension to "gis" database
96
+ psql -h localhost -p 5432 -U gis -d gis -c 'DROP EXTENSION IF EXISTS postgis_topology;'
97
+
92
98
  # Setup MySQL
93
99
  - name: Set up MySQL
94
100
  run: |
@@ -13,11 +13,11 @@ repos:
13
13
  - id: end-of-file-fixer
14
14
  - id: trailing-whitespace
15
15
  - repo: https://github.com/pycqa/isort
16
- rev: 5.12.0
16
+ rev: 5.13.2
17
17
  hooks:
18
18
  - id: isort
19
19
  - repo: https://github.com/psf/black
20
- rev: 23.10.0
20
+ rev: 24.3.0
21
21
  hooks:
22
22
  - id: black
23
23
  - repo: https://github.com/codespell-project/codespell
@@ -31,7 +31,7 @@ repos:
31
31
  additional_dependencies: ["tomli"]
32
32
  exclude: "tests"
33
33
  - repo: https://github.com/PyCQA/flake8
34
- rev: 6.1.0
34
+ rev: 7.0.0
35
35
  hooks:
36
36
  - id: flake8
37
37
  ci:
@@ -1,6 +1,12 @@
1
1
  GeoAlchemy 2 Changelog
2
2
  ======================
3
3
 
4
+ 0.15.0
5
+ ------
6
+
7
+ * Specific process for geometries with Z or M coordinate with SpatiaLite dialect @spd5 (#506)
8
+ * Chore: Fix type hints on stubs @adrien-berchet (#504)
9
+
4
10
  0.14.7
5
11
  ------
6
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: GeoAlchemy2
3
- Version: 0.14.7
3
+ Version: 0.15.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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: GeoAlchemy2
3
- Version: 0.14.7
3
+ Version: 0.15.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
@@ -60,6 +60,9 @@ copyright = "2012, Eric Lemoine"
60
60
  #
61
61
  version = release = geoalchemy2.__version__
62
62
 
63
+ # Remove some Sphinx warnings
64
+ suppress_warnings = ["config.cache"]
65
+
63
66
  # The language for content autogenerated by Sphinx. Refer to documentation
64
67
  # for a list of supported languages.
65
68
  # language = None
@@ -54,7 +54,7 @@ Declare a Mapping
54
54
  Now that we have a working connection we can go ahead and create a mapping between
55
55
  a Python class and a database table::
56
56
 
57
- >>> from sqlalchemy.ext.declarative import declarative_base
57
+ >>> from sqlalchemy.orm import declarative_base
58
58
  >>> from sqlalchemy import Column, Integer, String
59
59
  >>> from geoalchemy2 import Geometry
60
60
  >>>
@@ -1,4 +1,5 @@
1
1
  """GeoAlchemy2 package."""
2
+
2
3
  from geoalchemy2 import admin
3
4
  from geoalchemy2 import elements # noqa
4
5
  from geoalchemy2 import exc # noqa
@@ -60,8 +60,8 @@ class TableRowElement(ColumnElement):
60
60
  """The cache is disabled for this class."""
61
61
 
62
62
  def __init__(self, selectable: bool) -> None: ...
63
- @property
64
- def _from_objects(self) -> List[bool]: ... # type: ignore[override]
63
+ @property # type: ignore[override]
64
+ def _from_objects(self) -> List[bool]: ...
65
65
  '''
66
66
  stub_file_parts = [header]
67
67
 
@@ -1,4 +1,5 @@
1
1
  """This module defines the functions used for administration tasks."""
2
+
2
3
  from sqlalchemy import Column
3
4
  from sqlalchemy import Index
4
5
  from sqlalchemy import Table
@@ -1,4 +1,5 @@
1
1
  """This module defines some dialect-specific functions used for administration tasks."""
2
+
2
3
  from geoalchemy2.admin.dialects import common # noqa
3
4
  from geoalchemy2.admin.dialects import geopackage # noqa
4
5
  from geoalchemy2.admin.dialects import mysql # noqa
@@ -1,4 +1,5 @@
1
1
  """This module defines functions used by several dialects."""
2
+
2
3
  import sqlalchemy
3
4
  from packaging import version
4
5
  from sqlalchemy import Column
@@ -2,6 +2,7 @@
2
2
 
3
3
  See GeoPackage specifications here: http://www.geopackage.org/spec/
4
4
  """
5
+
5
6
  import re
6
7
 
7
8
  from sqlalchemy import text
@@ -1,4 +1,5 @@
1
1
  """This module defines specific functions for MySQL dialect."""
2
+
2
3
  from sqlalchemy import text
3
4
  from sqlalchemy.ext.compiler import compiles
4
5
  from sqlalchemy.sql.sqltypes import NullType
@@ -1,4 +1,5 @@
1
1
  """This module defines specific functions for Postgresql dialect."""
2
+
2
3
  from sqlalchemy import Index
3
4
  from sqlalchemy import text
4
5
  from sqlalchemy.sql import func
@@ -1,4 +1,5 @@
1
1
  """This module defines specific functions for SQLite dialect."""
2
+
2
3
  import os
3
4
  from typing import Optional
4
5
 
@@ -1,4 +1,5 @@
1
1
  """Some helpers to use with Alembic migration tool."""
2
+
2
3
  from alembic.autogenerate import renderers
3
4
  from alembic.autogenerate import rewriter
4
5
  from alembic.autogenerate.render import _add_column
@@ -36,6 +36,7 @@ Using the ORM::
36
36
 
37
37
  Session.query(Cls).order_by(Cls.geom.distance_box('POINT(0 0)')).limit(10)
38
38
  """
39
+
39
40
  from typing import Union
40
41
 
41
42
  from sqlalchemy import types as sqltypes
@@ -117,6 +117,7 @@ class WKTElement(_SpatialElement):
117
117
  """
118
118
 
119
119
  _REMOVE_SRID = re.compile("(SRID=([0-9]+); ?)?(.*)")
120
+ SPLIT_WKT_PATTERN = re.compile(r"((SRID=\d+) *; *)?([\w ]+) *(\([\d ,\(\)]+\))")
120
121
 
121
122
  geom_from: str = "ST_GeomFromText"
122
123
  geom_from_extended_version: str = "ST_GeomFromEWKT"
@@ -66,6 +66,7 @@ Reference
66
66
  ---------
67
67
 
68
68
  """
69
+
69
70
  import re
70
71
  from typing import List
71
72
  from typing import Type
@@ -13,8 +13,8 @@ class TableRowElement(ColumnElement):
13
13
  """The cache is disabled for this class."""
14
14
 
15
15
  def __init__(self, selectable: bool) -> None: ...
16
- @property
17
- def _from_objects(self) -> List[bool]: ... # type: ignore[override]
16
+ @property # type: ignore[override]
17
+ def _from_objects(self) -> List[bool]: ...
18
18
 
19
19
  class ST_AsGeoJSON(GenericFunction):
20
20
  """
@@ -5,6 +5,7 @@
5
5
  As GeoAlchemy 2 itself has no dependency on `Shapely`, applications using
6
6
  functions of this module have to ensure that `Shapely` is available.
7
7
  """
8
+
8
9
  from contextlib import contextmanager
9
10
  from typing import List
10
11
  from typing import Optional
@@ -4,6 +4,7 @@ The :class:`geoalchemy2.types.Geometry`, :class:`geoalchemy2.types.Geography`, a
4
4
  :class:`geoalchemy2.types.Raster` classes are used when defining geometry, geography and raster
5
5
  columns/properties in models.
6
6
  """
7
+
7
8
  import warnings
8
9
  from typing import Any
9
10
  from typing import Dict
@@ -1,4 +1,5 @@
1
1
  """This module defines some dialect-specific functions used for Column types."""
2
+
2
3
  from geoalchemy2.types.dialects import common # noqa
3
4
  from geoalchemy2.types.dialects import geopackage # noqa
4
5
  from geoalchemy2.types.dialects import mysql # noqa
@@ -1,2 +1,3 @@
1
1
  """This module defines specific functions for GeoPackage dialect."""
2
+
2
3
  from geoalchemy2.types.dialects.sqlite import bind_processor_process # noqa
@@ -1,4 +1,5 @@
1
1
  """This module defines specific functions for MySQL dialect."""
2
+
2
3
  from geoalchemy2.elements import WKBElement
3
4
  from geoalchemy2.elements import WKTElement
4
5
  from geoalchemy2.elements import _SpatialElement
@@ -1,4 +1,5 @@
1
1
  """This module defines specific functions for Postgresql dialect."""
2
+
2
3
  from geoalchemy2.elements import RasterElement
3
4
  from geoalchemy2.elements import WKBElement
4
5
  from geoalchemy2.elements import WKTElement
@@ -0,0 +1,50 @@
1
+ """This module defines specific functions for SQLite dialect."""
2
+
3
+ import re
4
+
5
+ from geoalchemy2.elements import RasterElement
6
+ from geoalchemy2.elements import WKBElement
7
+ from geoalchemy2.elements import WKTElement
8
+ from geoalchemy2.shape import to_shape
9
+
10
+
11
+ def format_geom_type(wkt, default_srid=None):
12
+ """Format the Geometry type for SQLite."""
13
+ match = re.match(WKTElement.SPLIT_WKT_PATTERN, wkt)
14
+ if match is None:
15
+ return wkt
16
+ _, srid, geom_type, coords = match.groups()
17
+ geom_type = geom_type.replace(" ", "")
18
+ if geom_type.endswith("ZM"):
19
+ geom_type = geom_type[:-2]
20
+ elif geom_type.endswith("Z"):
21
+ geom_type = geom_type[:-1]
22
+ if srid is None and default_srid is not None:
23
+ srid = f"SRID={default_srid}"
24
+ if srid is not None:
25
+ return "%s;%s%s" % (srid, geom_type, coords)
26
+ else:
27
+ return "%s%s" % (geom_type, coords)
28
+
29
+
30
+ def bind_processor_process(spatial_type, bindvalue):
31
+ if isinstance(bindvalue, WKTElement):
32
+ return format_geom_type(
33
+ bindvalue.data,
34
+ default_srid=bindvalue.srid if bindvalue.srid >= 0 else spatial_type.srid,
35
+ )
36
+ elif isinstance(bindvalue, WKBElement):
37
+ # With SpatiaLite we use Shapely to convert the WKBElement to an EWKT string
38
+ shape = to_shape(bindvalue)
39
+ # shapely.wkb.loads returns geom_type with a 'Z', for example, 'LINESTRING Z'
40
+ # which is a limitation with SpatiaLite. Hence, a temporary fix.
41
+ res = format_geom_type(
42
+ shape.wkt, default_srid=bindvalue.srid if bindvalue.srid >= 0 else spatial_type.srid
43
+ )
44
+ return res
45
+ elif isinstance(bindvalue, RasterElement):
46
+ return "%s" % (bindvalue.data)
47
+ elif isinstance(bindvalue, str):
48
+ return format_geom_type(bindvalue, default_srid=spatial_type.srid)
49
+ else:
50
+ return bindvalue
@@ -5,7 +5,7 @@ RUN /install_requirements.sh
5
5
 
6
6
  COPY ./helpers/init_postgres.sh /
7
7
  env PGDATA="/var/lib/postgresql/data"
8
- env POSTGRES_PATH="/usr/lib/postgresql/14"
8
+ env POSTGRES_PATH="/usr/lib/postgresql/16"
9
9
  RUN su postgres -c /init_postgres.sh
10
10
 
11
11
  ENV SPATIALITE_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu/mod_spatialite.so"
@@ -29,9 +29,9 @@ packages=(
29
29
  python3.12-venv
30
30
 
31
31
  # PostgreSQL and PostGIS
32
- postgresql
33
- postgresql-14-postgis-3
34
- postgresql-14-postgis-3-scripts
32
+ postgresql-16
33
+ postgresql-16-postgis-3
34
+ postgresql-16-postgis-3-scripts
35
35
  libpq-dev
36
36
  libgeos-dev
37
37
 
@@ -56,8 +56,10 @@ packages=(
56
56
  export DEBIAN_FRONTEND=noninteractive
57
57
 
58
58
  apt-get update -y
59
- apt-get install --no-install-recommends -y software-properties-common gnupg2
59
+ apt-get install --no-install-recommends -y software-properties-common gnupg2 wget
60
60
  add-apt-repository ppa:deadsnakes/ppa
61
+ sh -c 'echo "deb https://apt.PostgreSQL.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
62
+ wget --quiet -O - https://www.PostgreSQL.org/media/keys/ACCC4CF8.asc | apt-key add -
61
63
  apt-get update -y
62
64
 
63
65
  apt-get install --no-install-recommends -y "${packages[@]}"
@@ -7,6 +7,7 @@ usually better to convert them into TIFF, PNG, JPEG or whatever. Nevertheless, i
7
7
  possible to decipher the WKB to get a 2D list of values.
8
8
  This example uses SQLAlchemy ORM queries.
9
9
  """
10
+
10
11
  import binascii
11
12
  import struct
12
13
 
@@ -7,6 +7,7 @@ the wrapping of geometry columns with a `ST_AsEWKB()` function might be annoying
7
7
  this case it is possible to disable this wrapping.
8
8
  This example uses SQLAlchemy ORM queries.
9
9
  """
10
+
10
11
  from sqlalchemy import Column
11
12
  from sqlalchemy import Integer
12
13
  from sqlalchemy import func
@@ -13,6 +13,7 @@ This example uses SQLAlchemy ORM queries.
13
13
  raster and re-importing it using this method will properly import the values but might not
14
14
  keep the same internal types.
15
15
  """
16
+
16
17
  import struct
17
18
  from sys import byteorder
18
19
 
@@ -6,6 +6,7 @@ It is possible to insert a geometry and ask PostgreSQL to compute its length at
6
6
  time.
7
7
  This example uses SQLAlchemy core queries.
8
8
  """
9
+
9
10
  from sqlalchemy import Column
10
11
  from sqlalchemy import Float
11
12
  from sqlalchemy import Integer
@@ -6,6 +6,7 @@ New ORM Declarative Mapping Style
6
6
  ``sqlalchemy.orm.DeclarativeBase`` base class.
7
7
  This example shows how to use GeoAlchemy2 types in this context.
8
8
  """
9
+
9
10
  import pytest
10
11
  from pkg_resources import parse_version
11
12
  from sqlalchemy import __version__ as SA_VERSION
@@ -9,6 +9,7 @@ function on `Raster` requires minor tweaking.
9
9
 
10
10
  This example uses both SQLAlchemy core and ORM queries.
11
11
  """
12
+
12
13
  from sqlalchemy import Column
13
14
  from sqlalchemy import Integer
14
15
  from sqlalchemy import MetaData
@@ -28,6 +28,7 @@ with it.
28
28
 
29
29
  This example uses SQLAlchemy core queries.
30
30
  """
31
+
31
32
  from sqlalchemy import MetaData
32
33
  from sqlalchemy import func
33
34
  from sqlalchemy.ext.compiler import compiles
@@ -5,6 +5,7 @@ Use CompositeType
5
5
  Some functions return composite types. This example shows how to deal with this
6
6
  kind of functions.
7
7
  """
8
+
8
9
  import pytest
9
10
  from pkg_resources import parse_version
10
11
  from sqlalchemy import Column
@@ -8,6 +8,7 @@ are projected in the DB. To avoid having to always tweak the query with a
8
8
  ``ST_Transform()``, it is possible to define a `TypeDecorator
9
9
  <https://docs.sqlalchemy.org/en/13/core/custom_types.html#sqlalchemy.types.TypeDecorator>`_
10
10
  """
11
+
11
12
  import re
12
13
  from typing import Any
13
14
 
@@ -1,4 +1,5 @@
1
1
  """Declare tables used in tests."""
2
+
2
3
  import pytest
3
4
  from sqlalchemy import Column
4
5
  from sqlalchemy import Integer
@@ -119,7 +120,7 @@ class TransformedGeometry(TypeDecorator):
119
120
  SRID of the resulting WKBElement is correct"""
120
121
  return getattr(func, self.impl.as_binary)(
121
122
  func.ST_Transform(col, self.app_srid),
122
- type_=self.__class__.impl(srid=self.app_srid)
123
+ type_=self.__class__.impl(srid=self.app_srid),
123
124
  # srid could also be -1 so that the SRID is deduced from the
124
125
  # WKB data
125
126
  )
@@ -1,4 +1,5 @@
1
1
  """Test alembic migrations of spatial columns."""
2
+
2
3
  import pytest
3
4
  import sqlalchemy as sa # noqa (This import is only used in the migration scripts)
4
5
  from alembic import command
@@ -275,6 +275,140 @@ class TestInsertionCore:
275
275
  srid = conn.execute(row[1].ST_SRID()).scalar()
276
276
  assert srid == 4326
277
277
 
278
+ @pytest.mark.parametrize(
279
+ "geom_type,wkt",
280
+ [
281
+ pytest.param("POINT", "(1 2)", id="Point"),
282
+ pytest.param("POINTZ", "(1 2 3)", id="Point Z"),
283
+ pytest.param("POINTM", "(1 2 3)", id="Point M"),
284
+ pytest.param("POINTZM", "(1 2 3 4)", id="Point ZM"),
285
+ pytest.param("LINESTRING", "(1 2, 3 4)", id="LineString"),
286
+ pytest.param("LINESTRINGZ", "(1 2 3, 4 5 6)", id="LineString Z"),
287
+ pytest.param("LINESTRINGM", "(1 2 3, 4 5 6)", id="LineString M"),
288
+ pytest.param("LINESTRINGZM", "(1 2 3 4, 5 6 7 8)", id="LineString ZM"),
289
+ pytest.param("POLYGON", "((1 2, 3 4, 5 6, 1 2))", id="Polygon"),
290
+ pytest.param("POLYGONZ", "((1 2 3, 4 5 6, 7 8 9, 1 2 3))", id="Polygon Z"),
291
+ pytest.param("POLYGONM", "((1 2 3, 4 5 6, 7 8 9, 1 2 3))", id="Polygon M"),
292
+ pytest.param(
293
+ "POLYGONZM", "((1 2 3 4, 5 6 7 8, 9 10 11 12, 1 2 3 4))", id="Polygon ZM"
294
+ ),
295
+ pytest.param("MULTIPOINT", "(1 2, 3 4)", id="Multi Point"),
296
+ pytest.param("MULTIPOINTZ", "(1 2 3, 4 5 6)", id="Multi Point Z"),
297
+ pytest.param("MULTIPOINTM", "(1 2 3, 4 5 6)", id="Multi Point M"),
298
+ pytest.param("MULTIPOINTZM", "(1 2 3 4, 5 6 7 8)", id="Multi Point ZM"),
299
+ pytest.param("MULTILINESTRING", "((1 2, 3 4), (10 20, 30 40))", id="Multi LineString"),
300
+ pytest.param(
301
+ "MULTILINESTRINGZ",
302
+ "((1 2 3, 4 5 6), (10 20 30, 40 50 60))",
303
+ id="Multi LineString Z",
304
+ ),
305
+ pytest.param(
306
+ "MULTILINESTRINGM",
307
+ "((1 2 3, 4 5 6), (10 20 30, 40 50 60))",
308
+ id="Multi LineString M",
309
+ ),
310
+ pytest.param(
311
+ "MULTILINESTRINGZM",
312
+ "((1 2 3 4, 5 6 7 8), (10 20 30 40, 50 60 70 80))",
313
+ id="Multi LineString ZM",
314
+ ),
315
+ pytest.param(
316
+ "MULTIPOLYGON",
317
+ "(((1 2, 3 4, 5 6, 1 2)), ((10 20, 30 40, 50 60, 10 20)))",
318
+ id="Multi Polygon",
319
+ ),
320
+ pytest.param(
321
+ "MULTIPOLYGONZ",
322
+ "(((1 2 3, 4 5 6, 7 8 9, 1 2 3)), ((10 20 30, 40 50 60, 70 80 90, 10 20 30)))",
323
+ id="Multi Polygon Z",
324
+ ),
325
+ pytest.param(
326
+ "MULTIPOLYGONM",
327
+ "(((1 2 3, 4 5 6, 7 8 9, 1 2 3)), ((10 20 30, 40 50 60, 70 80 90, 10 20 30)))",
328
+ id="Multi Polygon M",
329
+ ),
330
+ pytest.param(
331
+ "MULTIPOLYGONZM",
332
+ "(((1 2 3 4, 5 6 7 8, 9 10 11 12, 1 2 3 4)),"
333
+ " ((10 20 30 40, 50 60 70 80, 90 100 100 120, 10 20 30 40)))",
334
+ id="Multi Polygon ZM",
335
+ ),
336
+ ],
337
+ )
338
+ def test_insert_all_geom_types(self, dialect_name, base, conn, metadata, geom_type, wkt):
339
+ """Test insertion and selection of all geometry types."""
340
+ ndims = 2
341
+ if "Z" in geom_type[-2:]:
342
+ ndims += 1
343
+ if geom_type.endswith("M"):
344
+ ndims += 1
345
+ has_m = True
346
+ else:
347
+ has_m = False
348
+
349
+ if ndims > 2 and dialect_name == "mysql":
350
+ # Explicitly skip MySQL dialect to show that it can only work with 2D geometries
351
+ pytest.xfail(reason="MySQL only supports 2D geometry types")
352
+
353
+ class GeomTypeTable(base):
354
+ __tablename__ = "test_geom_types"
355
+ id = Column(Integer, primary_key=True)
356
+ geom = Column(Geometry(srid=4326, geometry_type=geom_type, dimension=ndims))
357
+
358
+ metadata.drop_all(bind=conn, checkfirst=True)
359
+ metadata.create_all(bind=conn)
360
+
361
+ inserted_wkt = f"{geom_type}{wkt}"
362
+
363
+ # Use the DB to generate the corresponding raw WKB
364
+ raw_wkb = conn.execute(
365
+ text("SELECT ST_AsBinary(ST_GeomFromText('{}', 4326))".format(inserted_wkt))
366
+ ).scalar()
367
+
368
+ wkb_elem = WKBElement(raw_wkb, srid=4326)
369
+ inserted_elements = [
370
+ {"geom": inserted_wkt},
371
+ {"geom": f"SRID=4326;{inserted_wkt}"},
372
+ {"geom": WKTElement(inserted_wkt, srid=4326)},
373
+ {"geom": WKTElement(f"SRID=4326;{inserted_wkt}")},
374
+ ]
375
+ if dialect_name not in ["postgresql", "sqlite"] or not has_m:
376
+ # Currently Shapely does not support geometry types with M dimension
377
+ inserted_elements.append({"geom": wkb_elem})
378
+ inserted_elements.append({"geom": wkb_elem.as_ewkb()})
379
+
380
+ # Insert the elements
381
+ conn.execute(
382
+ GeomTypeTable.__table__.insert(),
383
+ inserted_elements,
384
+ )
385
+
386
+ # Select the elements
387
+ query = select(
388
+ [
389
+ GeomTypeTable.__table__.c.id,
390
+ GeomTypeTable.__table__.c.geom.ST_AsText(),
391
+ GeomTypeTable.__table__.c.geom.ST_SRID(),
392
+ ],
393
+ )
394
+ results = conn.execute(query)
395
+ rows = results.all()
396
+
397
+ # Check that the selected elements are the same as the inputs
398
+ for row_id, row, srid in rows:
399
+ checked_wkt = row.upper().replace(" ", "")
400
+ expected_wkt = inserted_wkt.upper().replace(" ", "")
401
+ if "MULTIPOINT" in geom_type:
402
+ # Some dialects return MULTIPOINT geometries with nested parenthesis and others
403
+ # do not so we remove them before checking the results
404
+ checked_wkt = re.sub(r"\(([0-9]+)\)", "\\1", checked_wkt)
405
+ if row_id >= 5 and dialect_name in ["geopackage"] and has_m:
406
+ # Currently Shapely does not support geometry types with M dimension
407
+ assert checked_wkt != expected_wkt
408
+ else:
409
+ assert checked_wkt == expected_wkt
410
+ assert srid == 4326
411
+
278
412
  @test_only_with_dialects("postgresql", "sqlite")
279
413
  def test_insert_geom_poi(self, conn, Poi, setup_tables):
280
414
  conn.execute(
@@ -380,7 +514,7 @@ class TestInsertionORM:
380
514
  lake = Lake("LINESTRING(0 0,1 1)")
381
515
  session.add(lake)
382
516
 
383
- if (dialect_name == "postgresql" and postgis_version < 3) or dialect_name == "sqlite":
517
+ if dialect_name == "postgresql" and postgis_version < 3:
384
518
  with pytest.raises((DataError, IntegrityError)):
385
519
  session.flush()
386
520
  else:
@@ -1,21 +0,0 @@
1
- """This module defines specific functions for SQLite dialect."""
2
- from geoalchemy2.elements import RasterElement
3
- from geoalchemy2.elements import WKBElement
4
- from geoalchemy2.elements import WKTElement
5
- from geoalchemy2.shape import to_shape
6
-
7
-
8
- def bind_processor_process(spatial_type, bindvalue):
9
- if isinstance(bindvalue, WKTElement):
10
- if bindvalue.extended:
11
- return "%s" % (bindvalue.data)
12
- else:
13
- return "SRID=%d;%s" % (bindvalue.srid, bindvalue.data)
14
- elif isinstance(bindvalue, WKBElement):
15
- # With SpatiaLite we use Shapely to convert the WKBElement to an EWKT string
16
- shape = to_shape(bindvalue)
17
- return "SRID=%d;%s" % (bindvalue.srid, shape.wkt)
18
- elif isinstance(bindvalue, RasterElement):
19
- return "%s" % (bindvalue.data)
20
- else:
21
- return bindvalue
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes