GeoAlchemy2 0.14.7__tar.gz → 0.15.1__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.1}/.github/workflows/test_and_publish.yml +8 -2
  2. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.pre-commit-config.yaml +3 -3
  3. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/CHANGES.txt +12 -0
  4. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1/GeoAlchemy2.egg-info}/PKG-INFO +1 -1
  5. {GeoAlchemy2-0.14.7/GeoAlchemy2.egg-info → geoalchemy2-0.15.1}/PKG-INFO +1 -1
  6. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/conf.py +3 -0
  7. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/spatialite_tutorial.rst +1 -1
  8. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/__init__.py +1 -0
  9. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/_functions_helpers.py +2 -2
  10. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/__init__.py +1 -0
  11. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/__init__.py +1 -0
  12. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/common.py +1 -0
  13. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/geopackage.py +1 -0
  14. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/mysql.py +1 -0
  15. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/postgresql.py +1 -0
  16. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/admin/dialects/sqlite.py +1 -0
  17. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/alembic_helpers.py +1 -0
  18. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/comparator.py +1 -0
  19. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/elements.py +1 -0
  20. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/functions.py +1 -0
  21. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/functions.pyi +2 -2
  22. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/shape.py +1 -0
  23. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/__init__.py +1 -0
  24. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/dialects/__init__.py +1 -0
  25. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/dialects/geopackage.py +1 -0
  26. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/dialects/mysql.py +1 -0
  27. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/dialects/postgresql.py +1 -0
  28. geoalchemy2-0.15.1/geoalchemy2/types/dialects/sqlite.py +50 -0
  29. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/Dockerfile +1 -1
  30. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/helpers/install_requirements.sh +6 -4
  31. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/conftest.py +13 -8
  32. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_decipher_raster.py +1 -0
  33. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_disable_wrapping.py +1 -0
  34. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_insert_raster.py +1 -0
  35. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_length_at_insert.py +1 -0
  36. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_orm_mapped_v2.py +1 -0
  37. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_raster_transform.py +1 -0
  38. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_specific_compilation.py +1 -0
  39. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_summarystatsagg.py +1 -0
  40. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/test_type_decorator.py +1 -0
  41. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/schema_fixtures.py +2 -1
  42. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_alembic_migrations.py +1 -0
  43. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functional.py +147 -1
  44. GeoAlchemy2-0.14.7/geoalchemy2/types/dialects/sqlite.py +0 -21
  45. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.codespellrc +0 -0
  46. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.coveragerc +0 -0
  47. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.flake8 +0 -0
  48. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  49. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  50. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  51. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
  52. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/dependabot.yml +0 -0
  53. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.github/pull_request_template.md +0 -0
  54. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.gitignore +0 -0
  55. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/.readthedocs.yaml +0 -0
  56. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/COPYING.rst +0 -0
  57. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2.egg-info/SOURCES.txt +0 -0
  58. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2.egg-info/dependency_links.txt +0 -0
  59. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2.egg-info/not-zip-safe +0 -0
  60. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2.egg-info/requires.txt +0 -0
  61. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2.egg-info/top_level.txt +0 -0
  62. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/GeoAlchemy2_dev.yml +0 -0
  63. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/MANIFEST.in +0 -0
  64. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/README.rst +0 -0
  65. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/RELEASE.rst +0 -0
  66. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/TEST.rst +0 -0
  67. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/Makefile +0 -0
  68. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_static/geoalchemy.png +0 -0
  69. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_static/geoalchemy.svg +0 -0
  70. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_static/geoalchemy_small.png +0 -0
  71. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_static/geoalchemy_small.svg +0 -0
  72. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_templates/sidebar-about.html +0 -0
  73. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_templates/sidebar-links.html +0 -0
  74. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_templates/sidebar-logo.html +0 -0
  75. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/LICENSE +0 -0
  76. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/README +0 -0
  77. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/flask/layout.html +0 -0
  78. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/flask/relations.html +0 -0
  79. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/flask/static/flasky.css_t +0 -0
  80. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/flask/static/small_flask.css +0 -0
  81. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/_themes/flask/theme.conf +0 -0
  82. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/admin.rst +0 -0
  83. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/alembic.rst +0 -0
  84. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/alembic_helpers.rst +0 -0
  85. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/changelog.rst +0 -0
  86. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/core_tutorial.rst +0 -0
  87. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/elements.rst +0 -0
  88. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/index.rst +0 -0
  89. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/make.bat +0 -0
  90. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/migrate.rst +0 -0
  91. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/orm_tutorial.rst +0 -0
  92. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/shape.rst +0 -0
  93. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/spatial_functions.rst +0 -0
  94. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/spatial_operators.rst +0 -0
  95. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/doc/types.rst +0 -0
  96. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/generate_type_stubs.py +0 -0
  97. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/_functions.py +0 -0
  98. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/exc.py +0 -0
  99. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/py.typed +0 -0
  100. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/types/dialects/common.py +0 -0
  101. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/geoalchemy2/utils.py +0 -0
  102. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/pyproject.toml +0 -0
  103. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/requirements-doc.txt +0 -0
  104. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/requirements-mypy.txt +0 -0
  105. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/requirements-rtd.txt +0 -0
  106. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/requirements.txt +0 -0
  107. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/setup.cfg +0 -0
  108. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/setup.py +0 -0
  109. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/.dockerignore +0 -0
  110. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/.gitignore +0 -0
  111. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/build.sh +0 -0
  112. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/helpers/entrypoint.sh +0 -0
  113. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/helpers/init_mysql.sh +0 -0
  114. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/helpers/init_postgres.sh +0 -0
  115. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/test_container/run.sh +0 -0
  116. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/__init__.py +0 -0
  117. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/alembic_config/alembic.ini +0 -0
  118. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/data/spatialite_ge_4.sqlite +0 -0
  119. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/data/spatialite_geopackage.gpkg +0 -0
  120. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/data/spatialite_lt_4.sqlite +0 -0
  121. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/README.rst +0 -0
  122. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/gallery/__init__.py +0 -0
  123. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_comparator.py +0 -0
  124. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_elements.py +0 -0
  125. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functional_geopackage.py +0 -0
  126. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functional_mysql.py +0 -0
  127. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functional_postgresql.py +0 -0
  128. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functional_sqlite.py +0 -0
  129. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_functions.py +0 -0
  130. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_pickle.py +0 -0
  131. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_shape.py +0 -0
  132. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/tests/test_types.py +0 -0
  133. {GeoAlchemy2-0.14.7 → geoalchemy2-0.15.1}/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,18 @@
1
1
  GeoAlchemy 2 Changelog
2
2
  ======================
3
3
 
4
+ 0.15.1
5
+ ------
6
+
7
+ * Fix: Default SRID is bypassed when using floating point coordinates @aballet (#509)
8
+ * Test: Dispose of the connection pools of the test engines @adrien-berchet (#511)
9
+
10
+ 0.15.0
11
+ ------
12
+
13
+ * Specific process for geometries with Z or M coordinate with SpatiaLite dialect @spd5 (#506)
14
+ * Chore: Fix type hints on stubs @adrien-berchet (#504)
15
+
4
16
  0.14.7
5
17
  ------
6
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: GeoAlchemy2
3
- Version: 0.14.7
3
+ Version: 0.15.1
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.1
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[@]}"
@@ -161,18 +161,23 @@ def engine(tmpdir, db_url, _engine_echo):
161
161
  # Copy the input SQLite DB to a temporary file and return an engine to it
162
162
  input_url = str(db_url)[10:]
163
163
  output_file = "test_spatial_db.sqlite"
164
- return copy_and_connect_sqlite_db(input_url, tmpdir / output_file, _engine_echo, "sqlite")
165
-
166
- if db_url.startswith("gpkg:///"):
164
+ current_engine = copy_and_connect_sqlite_db(
165
+ input_url, tmpdir / output_file, _engine_echo, "sqlite"
166
+ )
167
+ elif db_url.startswith("gpkg:///"):
167
168
  # Copy the input SQLite DB to a temporary file and return an engine to it
168
169
  input_url = str(db_url)[8:]
169
170
  output_file = "test_spatial_db.gpkg"
170
- return copy_and_connect_sqlite_db(input_url, tmpdir / output_file, _engine_echo, "gpkg")
171
+ current_engine = copy_and_connect_sqlite_db(
172
+ input_url, tmpdir / output_file, _engine_echo, "gpkg"
173
+ )
174
+ else:
175
+ # For other dialects the engine is directly returned
176
+ current_engine = create_engine(db_url, echo=_engine_echo)
177
+ current_engine.update_execution_options(search_path=["gis", "public"])
171
178
 
172
- # For other dialects the engine is directly returned
173
- engine = create_engine(db_url, echo=_engine_echo)
174
- engine.update_execution_options(search_path=["gis", "public"])
175
- return engine
179
+ yield current_engine
180
+ current_engine.dispose()
176
181
 
177
182
 
178
183
  @pytest.fixture
@@ -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,152 @@ 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
+ @pytest.mark.parametrize(
339
+ "use_floating_point",
340
+ [
341
+ pytest.param(True, id="Use floating point"),
342
+ pytest.param(False, id="Do not use floating point"),
343
+ ],
344
+ )
345
+ def test_insert_all_geom_types(
346
+ self, dialect_name, base, conn, metadata, geom_type, wkt, use_floating_point
347
+ ):
348
+ """Test insertion and selection of all geometry types."""
349
+ ndims = 2
350
+ if "Z" in geom_type[-2:]:
351
+ ndims += 1
352
+ if geom_type.endswith("M"):
353
+ ndims += 1
354
+ has_m = True
355
+ else:
356
+ has_m = False
357
+
358
+ if ndims > 2 and dialect_name == "mysql":
359
+ # Explicitly skip MySQL dialect to show that it can only work with 2D geometries
360
+ pytest.xfail(reason="MySQL only supports 2D geometry types")
361
+
362
+ class GeomTypeTable(base):
363
+ __tablename__ = "test_geom_types"
364
+ id = Column(Integer, primary_key=True)
365
+ geom = Column(Geometry(srid=4326, geometry_type=geom_type, dimension=ndims))
366
+
367
+ metadata.drop_all(bind=conn, checkfirst=True)
368
+ metadata.create_all(bind=conn)
369
+
370
+ if use_floating_point:
371
+ wkt = wkt.replace("1 2", "1.5 2.5")
372
+
373
+ inserted_wkt = f"{geom_type}{wkt}"
374
+
375
+ # Use the DB to generate the corresponding raw WKB
376
+ raw_wkb = conn.execute(
377
+ text("SELECT ST_AsBinary(ST_GeomFromText('{}', 4326))".format(inserted_wkt))
378
+ ).scalar()
379
+
380
+ wkb_elem = WKBElement(raw_wkb, srid=4326)
381
+ inserted_elements = [
382
+ {"geom": inserted_wkt},
383
+ {"geom": f"SRID=4326;{inserted_wkt}"},
384
+ {"geom": WKTElement(inserted_wkt, srid=4326)},
385
+ {"geom": WKTElement(f"SRID=4326;{inserted_wkt}")},
386
+ ]
387
+ if dialect_name not in ["postgresql", "sqlite"] or not has_m:
388
+ # Currently Shapely does not support geometry types with M dimension
389
+ inserted_elements.append({"geom": wkb_elem})
390
+ inserted_elements.append({"geom": wkb_elem.as_ewkb()})
391
+
392
+ # Insert the elements
393
+ conn.execute(
394
+ GeomTypeTable.__table__.insert(),
395
+ inserted_elements,
396
+ )
397
+
398
+ # Select the elements
399
+ query = select(
400
+ [
401
+ GeomTypeTable.__table__.c.id,
402
+ GeomTypeTable.__table__.c.geom.ST_AsText(),
403
+ GeomTypeTable.__table__.c.geom.ST_SRID(),
404
+ ],
405
+ )
406
+ results = conn.execute(query)
407
+ rows = results.all()
408
+
409
+ # Check that the selected elements are the same as the inputs
410
+ for row_id, row, srid in rows:
411
+ checked_wkt = row.upper().replace(" ", "")
412
+ expected_wkt = inserted_wkt.upper().replace(" ", "")
413
+ if "MULTIPOINT" in geom_type:
414
+ # Some dialects return MULTIPOINT geometries with nested parenthesis and others
415
+ # do not so we remove them before checking the results
416
+ checked_wkt = re.sub(r"\(([0-9\.]+)\)", "\\1", checked_wkt)
417
+ if row_id >= 5 and dialect_name in ["geopackage"] and has_m:
418
+ # Currently Shapely does not support geometry types with M dimension
419
+ assert checked_wkt != expected_wkt
420
+ else:
421
+ assert checked_wkt == expected_wkt
422
+ assert srid == 4326
423
+
278
424
  @test_only_with_dialects("postgresql", "sqlite")
279
425
  def test_insert_geom_poi(self, conn, Poi, setup_tables):
280
426
  conn.execute(
@@ -380,7 +526,7 @@ class TestInsertionORM:
380
526
  lake = Lake("LINESTRING(0 0,1 1)")
381
527
  session.add(lake)
382
528
 
383
- if (dialect_name == "postgresql" and postgis_version < 3) or dialect_name == "sqlite":
529
+ if dialect_name == "postgresql" and postgis_version < 3:
384
530
  with pytest.raises((DataError, IntegrityError)):
385
531
  session.flush()
386
532
  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