GeoAlchemy2 0.16.0__tar.gz → 0.17.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 (144) hide show
  1. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/workflows/test_and_publish.yml +7 -3
  2. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.pre-commit-config.yaml +3 -3
  3. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/CHANGES.txt +7 -0
  4. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0/GeoAlchemy2.egg-info}/PKG-INFO +14 -2
  5. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2.egg-info/SOURCES.txt +8 -1
  6. geoalchemy2-0.17.0/GeoAlchemy2.egg-info/entry_points.txt +2 -0
  7. {geoalchemy2-0.16.0/GeoAlchemy2.egg-info → geoalchemy2-0.17.0}/PKG-INFO +14 -2
  8. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/admin.rst +6 -1
  9. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/core_tutorial.rst +14 -2
  10. geoalchemy2-0.17.0/doc/dialect_specific_features.rst +13 -0
  11. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/index.rst +7 -2
  12. geoalchemy2-0.17.0/doc/mysql_mariadb_dialect.rst +43 -0
  13. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/orm_tutorial.rst +15 -1
  14. geoalchemy2-0.17.0/doc/plugin.rst +9 -0
  15. geoalchemy2-0.16.0/doc/spatialite_tutorial.rst → geoalchemy2-0.17.0/doc/spatialite_dialect.rst +14 -106
  16. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/__init__.py +2 -0
  17. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/__init__.py +4 -4
  18. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/__init__.py +1 -0
  19. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/common.py +5 -5
  20. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/geopackage.py +7 -3
  21. geoalchemy2-0.17.0/geoalchemy2/admin/dialects/mariadb.py +134 -0
  22. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/mysql.py +20 -72
  23. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/sqlite.py +10 -5
  24. geoalchemy2-0.17.0/geoalchemy2/admin/plugin.py +98 -0
  25. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/shape.py +0 -1
  26. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/__init__.py +3 -3
  27. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/common.py +1 -1
  28. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/setup.py +5 -0
  29. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/__init__.py +4 -1
  30. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/conftest.py +3 -3
  31. geoalchemy2-0.17.0/tests/test_plugin.py +90 -0
  32. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_shape.py +21 -0
  33. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tox.ini +6 -6
  34. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.codespellrc +0 -0
  35. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.coveragerc +0 -0
  36. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.flake8 +0 -0
  37. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  38. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  39. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  40. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
  41. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/dependabot.yml +0 -0
  42. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.github/pull_request_template.md +0 -0
  43. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.gitignore +0 -0
  44. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/.readthedocs.yaml +0 -0
  45. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/COPYING.rst +0 -0
  46. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2.egg-info/dependency_links.txt +0 -0
  47. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2.egg-info/not-zip-safe +0 -0
  48. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2.egg-info/requires.txt +0 -0
  49. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2.egg-info/top_level.txt +0 -0
  50. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/GeoAlchemy2_dev.yml +0 -0
  51. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/MANIFEST.in +0 -0
  52. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/README.rst +0 -0
  53. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/RELEASE.rst +0 -0
  54. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/TEST.rst +0 -0
  55. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/Makefile +0 -0
  56. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_static/geoalchemy.png +0 -0
  57. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_static/geoalchemy.svg +0 -0
  58. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_static/geoalchemy_small.png +0 -0
  59. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_static/geoalchemy_small.svg +0 -0
  60. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_templates/sidebar-about.html +0 -0
  61. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_templates/sidebar-links.html +0 -0
  62. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_templates/sidebar-logo.html +0 -0
  63. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/LICENSE +0 -0
  64. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/README +0 -0
  65. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/flask/layout.html +0 -0
  66. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/flask/relations.html +0 -0
  67. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/flask/static/flasky.css_t +0 -0
  68. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/flask/static/small_flask.css +0 -0
  69. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/_themes/flask/theme.conf +0 -0
  70. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/alembic.rst +0 -0
  71. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/alembic_helpers.rst +0 -0
  72. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/changelog.rst +0 -0
  73. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/conf.py +0 -0
  74. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/elements.rst +0 -0
  75. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/make.bat +0 -0
  76. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/migrate.rst +0 -0
  77. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/shape.rst +0 -0
  78. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/spatial_functions.rst +0 -0
  79. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/spatial_operators.rst +0 -0
  80. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/doc/types.rst +0 -0
  81. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/generate_type_stubs.py +0 -0
  82. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/_functions.py +0 -0
  83. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/_functions_helpers.py +0 -0
  84. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/admin/dialects/postgresql.py +0 -0
  85. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/alembic_helpers.py +0 -0
  86. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/comparator.py +0 -0
  87. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/elements.py +0 -0
  88. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/exc.py +0 -0
  89. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/functions.py +0 -0
  90. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/functions.pyi +0 -0
  91. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/py.typed +0 -0
  92. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/__init__.py +0 -0
  93. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/geopackage.py +0 -0
  94. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/mariadb.py +0 -0
  95. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/mysql.py +0 -0
  96. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/postgresql.py +0 -0
  97. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/types/dialects/sqlite.py +0 -0
  98. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/geoalchemy2/utils.py +0 -0
  99. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/pyproject.toml +0 -0
  100. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/requirements-doc.txt +0 -0
  101. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/requirements-mypy.txt +0 -0
  102. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/requirements-rtd.txt +0 -0
  103. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/requirements.txt +0 -0
  104. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/setup.cfg +0 -0
  105. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/.dockerignore +0 -0
  106. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/.gitignore +0 -0
  107. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/Dockerfile +0 -0
  108. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/Dockerfile_mariadb +0 -0
  109. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/build.sh +0 -0
  110. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/build_mariadb.sh +0 -0
  111. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/helpers/entrypoint.sh +0 -0
  112. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/helpers/init_mariadb.sh +0 -0
  113. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/helpers/init_mysql.sh +0 -0
  114. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/helpers/init_postgres.sh +0 -0
  115. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/helpers/install_requirements.sh +0 -0
  116. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/run.sh +0 -0
  117. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/test_container/run_mariadb.sh +0 -0
  118. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/alembic_config/alembic.ini +0 -0
  119. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/data/spatialite_ge_4.sqlite +0 -0
  120. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/data/spatialite_geopackage.gpkg +0 -0
  121. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/data/spatialite_lt_4.sqlite +0 -0
  122. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/README.rst +0 -0
  123. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/__init__.py +0 -0
  124. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_decipher_raster.py +0 -0
  125. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_disable_wrapping.py +0 -0
  126. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_insert_raster.py +0 -0
  127. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_length_at_insert.py +0 -0
  128. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_orm_mapped_v2.py +0 -0
  129. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_raster_transform.py +0 -0
  130. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_specific_compilation.py +0 -0
  131. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_summarystatsagg.py +0 -0
  132. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/gallery/test_type_decorator.py +0 -0
  133. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/schema_fixtures.py +0 -0
  134. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_alembic_migrations.py +0 -0
  135. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_comparator.py +0 -0
  136. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_elements.py +0 -0
  137. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functional.py +0 -0
  138. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functional_geopackage.py +0 -0
  139. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functional_mysql.py +0 -0
  140. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functional_postgresql.py +0 -0
  141. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functional_sqlite.py +0 -0
  142. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_functions.py +0 -0
  143. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_pickle.py +0 -0
  144. {geoalchemy2-0.16.0 → geoalchemy2-0.17.0}/tests/test_types.py +0 -0
@@ -33,7 +33,7 @@ jobs:
33
33
  {"pkg_name": "python==3.10.*", "flag": "3.10"},
34
34
  {"pkg_name": "python==3.11.*", "flag": "3.11"},
35
35
  {"pkg_name": "python==3.12.*", "flag": "3.12"},
36
- {"pkg_name": "pypy3.8", "flag": "pypy3.8"},
36
+ {"pkg_name": "pypy3.10", "flag": "pypy3.10"},
37
37
  ]
38
38
 
39
39
  # The type of runner that the job will run on
@@ -100,6 +100,7 @@ jobs:
100
100
  # Install MariaDB
101
101
  - name: Install MariaDB and SpatiaLite
102
102
  run: |
103
+ sudo apt-get update
103
104
  sudo apt-get install -y mariadb-server mariadb-client libsqlite3-mod-spatialite libgdal-dev gdal-bin rasterio
104
105
 
105
106
  # Config PostgreSQL
@@ -153,9 +154,12 @@ jobs:
153
154
  PYTEST_MYSQL_DB_URL: mysql://gis:gis@127.0.0.1:3307/gis
154
155
  PYTEST_MARIADB_DB_URL: mariadb://gis:gis@127.0.0.1:3308/gis
155
156
  run: |
156
- export PYTEST_ADDOPTS='--require-all-dialects'
157
- if [[ ${{ matrix.python-version.flag }} == 'pypy3.8' ]]; then
157
+ if [[ ${{ matrix.python-version.flag }} == 'pypy3.10' ]]; then
158
158
  export PYTEST_ADDOPTS=${PYTEST_ADDOPTS}' --ignore=tests/gallery/test_insert_raster.py'
159
+ export PYTEST_SPATIALITE3_DB_URL="FAILING URL"
160
+ export PYTEST_SPATIALITE4_DB_URL="FAILING URL"
161
+ else
162
+ export PYTEST_ADDOPTS='--require-all-dialects'
159
163
  fi;
160
164
  # Run the unit test suite with SQLAlchemy=1.4.* and then with the latest version of SQLAlchemy
161
165
  tox -vv
@@ -1,6 +1,6 @@
1
1
  repos:
2
2
  - repo: https://github.com/pre-commit/pre-commit-hooks
3
- rev: v4.6.0
3
+ rev: v5.0.0
4
4
  hooks:
5
5
  - id: check-added-large-files
6
6
  - id: check-case-conflict
@@ -15,7 +15,7 @@ repos:
15
15
  hooks:
16
16
  - id: isort
17
17
  - repo: https://github.com/psf/black
18
- rev: 24.4.2
18
+ rev: 24.10.0
19
19
  hooks:
20
20
  - id: black
21
21
  - repo: https://github.com/codespell-project/codespell
@@ -29,7 +29,7 @@ repos:
29
29
  additional_dependencies: ["tomli"]
30
30
  exclude: "tests"
31
31
  - repo: https://github.com/PyCQA/flake8
32
- rev: 7.1.0
32
+ rev: 7.1.1
33
33
  hooks:
34
34
  - id: flake8
35
35
  ci:
@@ -1,6 +1,13 @@
1
1
  GeoAlchemy 2 Changelog
2
2
  ======================
3
3
 
4
+ 0.17.0
5
+ ------
6
+
7
+ * Perf: Enable cache for all types of GeoAlchemy2 @adrien-berchet (#525)
8
+ * Feat: Add new plugin to automatically attach events based on the engine dialect @adrien-berchet (#525)
9
+ * CI: Disable SQLite for Pypy job @adrien-berchet (#528)
10
+
4
11
  0.16.0
5
12
  ------
6
13
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: GeoAlchemy2
3
- Version: 0.16.0
3
+ Version: 0.17.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
@@ -28,6 +28,18 @@ Requires-Dist: SQLAlchemy>=1.4
28
28
  Requires-Dist: packaging
29
29
  Provides-Extra: shapely
30
30
  Requires-Dist: Shapely>=1.7; extra == "shapely"
31
+ Dynamic: author
32
+ Dynamic: author-email
33
+ Dynamic: classifier
34
+ Dynamic: description
35
+ Dynamic: home-page
36
+ Dynamic: keywords
37
+ Dynamic: license
38
+ Dynamic: project-url
39
+ Dynamic: provides-extra
40
+ Dynamic: requires-dist
41
+ Dynamic: requires-python
42
+ Dynamic: summary
31
43
 
32
44
  ============
33
45
  GeoAlchemy 2
@@ -29,6 +29,7 @@ tox.ini
29
29
  GeoAlchemy2.egg-info/PKG-INFO
30
30
  GeoAlchemy2.egg-info/SOURCES.txt
31
31
  GeoAlchemy2.egg-info/dependency_links.txt
32
+ GeoAlchemy2.egg-info/entry_points.txt
32
33
  GeoAlchemy2.egg-info/not-zip-safe
33
34
  GeoAlchemy2.egg-info/requires.txt
34
35
  GeoAlchemy2.egg-info/top_level.txt
@@ -39,15 +40,18 @@ doc/alembic_helpers.rst
39
40
  doc/changelog.rst
40
41
  doc/conf.py
41
42
  doc/core_tutorial.rst
43
+ doc/dialect_specific_features.rst
42
44
  doc/elements.rst
43
45
  doc/index.rst
44
46
  doc/make.bat
45
47
  doc/migrate.rst
48
+ doc/mysql_mariadb_dialect.rst
46
49
  doc/orm_tutorial.rst
50
+ doc/plugin.rst
47
51
  doc/shape.rst
48
52
  doc/spatial_functions.rst
49
53
  doc/spatial_operators.rst
50
- doc/spatialite_tutorial.rst
54
+ doc/spatialite_dialect.rst
51
55
  doc/types.rst
52
56
  doc/_static/geoalchemy.png
53
57
  doc/_static/geoalchemy.svg
@@ -76,9 +80,11 @@ geoalchemy2/py.typed
76
80
  geoalchemy2/shape.py
77
81
  geoalchemy2/utils.py
78
82
  geoalchemy2/admin/__init__.py
83
+ geoalchemy2/admin/plugin.py
79
84
  geoalchemy2/admin/dialects/__init__.py
80
85
  geoalchemy2/admin/dialects/common.py
81
86
  geoalchemy2/admin/dialects/geopackage.py
87
+ geoalchemy2/admin/dialects/mariadb.py
82
88
  geoalchemy2/admin/dialects/mysql.py
83
89
  geoalchemy2/admin/dialects/postgresql.py
84
90
  geoalchemy2/admin/dialects/sqlite.py
@@ -116,6 +122,7 @@ tests/test_functional_postgresql.py
116
122
  tests/test_functional_sqlite.py
117
123
  tests/test_functions.py
118
124
  tests/test_pickle.py
125
+ tests/test_plugin.py
119
126
  tests/test_shape.py
120
127
  tests/test_types.py
121
128
  tests/alembic_config/alembic.ini
@@ -0,0 +1,2 @@
1
+ [sqlalchemy.plugins]
2
+ geoalchemy2 = geoalchemy2.admin.plugin:GeoEngine
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: GeoAlchemy2
3
- Version: 0.16.0
3
+ Version: 0.17.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
@@ -28,6 +28,18 @@ Requires-Dist: SQLAlchemy>=1.4
28
28
  Requires-Dist: packaging
29
29
  Provides-Extra: shapely
30
30
  Requires-Dist: Shapely>=1.7; extra == "shapely"
31
+ Dynamic: author
32
+ Dynamic: author-email
33
+ Dynamic: classifier
34
+ Dynamic: description
35
+ Dynamic: home-page
36
+ Dynamic: keywords
37
+ Dynamic: license
38
+ Dynamic: project-url
39
+ Dynamic: provides-extra
40
+ Dynamic: requires-dist
41
+ Dynamic: requires-python
42
+ Dynamic: summary
31
43
 
32
44
  ============
33
45
  GeoAlchemy 2
@@ -33,8 +33,13 @@ MySQL/MariadDB-specific objects
33
33
  :private-members:
34
34
  :show-inheritance:
35
35
 
36
+ .. automodule:: geoalchemy2.admin.dialects.mariadb
37
+ :members:
38
+ :private-members:
39
+ :show-inheritance:
40
+
36
41
  SQLite-specific objects
37
- ---------------------------
42
+ -----------------------
38
43
 
39
44
  .. automodule:: geoalchemy2.admin.dialects.sqlite
40
45
  :members:
@@ -21,7 +21,11 @@ For this tutorial we will use a PostGIS 2 database. To connect we use
21
21
  SQLAlchemy's ``create_engine()`` function::
22
22
 
23
23
  >>> from sqlalchemy import create_engine
24
- >>> engine = create_engine('postgresql://gis:gis@localhost/gis', echo=True)
24
+ >>> engine = create_engine(
25
+ ... 'postgresql://gis:gis@localhost/gis',
26
+ ... echo=True,
27
+ ... plugins=["geoalchemy2"],
28
+ ... )
25
29
 
26
30
  In this example the name of the database, the database user, and the database
27
31
  password, is ``gis``.
@@ -30,6 +34,11 @@ The ``echo`` flag is a shortcut to setting up SQLAlchemy logging, which is
30
34
  accomplished via Python's standard logging module. With it is enabled, we'll
31
35
  see all the generated SQL produced.
32
36
 
37
+ The ``plugins`` argument adds some event listeners to adapt the behavior of
38
+ ``GeoAlchemy2`` to the dialect. This is not mandatory but if the plugin is not
39
+ loaded, then the listeners will have to be added to the engine manually (see an
40
+ example in :ref:`spatialite_dialect`).
41
+
33
42
  The return value of ``create_engine`` is an ``Engine`` object, which
34
43
  represents the core interface to the database.
35
44
 
@@ -84,7 +93,10 @@ be registered into SQLAlchemy, even if it is not used explicitly.
84
93
 
85
94
  >>> from geoalchemy2 import Geometry # <= not used but must be imported
86
95
  >>> from sqlalchemy import create_engine, MetaData
87
- >>> engine = create_engine("postgresql://myuser:mypass@mydb.host.tld/mydbname")
96
+ >>> engine = create_engine(
97
+ ... "postgresql://myuser:mypass@mydb.host.tld/mydbname",
98
+ ... plugins=["geoalchemy2"]
99
+ ... )
88
100
  >>> meta = MetaData()
89
101
  >>> meta.reflect(bind=engine)
90
102
 
@@ -0,0 +1,13 @@
1
+ .. _dialect_specific_features:
2
+
3
+ Dialect specific features
4
+ =========================
5
+
6
+ Several dialects handle spatial data in different ways. ``GeoAlchemy2`` tries to hide these
7
+ differences but sometimes manual tweaks are needed.
8
+
9
+ .. toctree::
10
+ :maxdepth: 1
11
+
12
+ mysql_mariadb_dialect
13
+ spatialite_dialect
@@ -87,7 +87,7 @@ system. If you're new to GeoAlchemy 2 start with this.
87
87
 
88
88
  orm_tutorial
89
89
  core_tutorial
90
- spatialite_tutorial
90
+ dialect_specific_features
91
91
 
92
92
 
93
93
  Gallery
@@ -121,6 +121,7 @@ Reference Documentation
121
121
  :maxdepth: 1
122
122
 
123
123
  admin
124
+ plugin
124
125
  types
125
126
  elements
126
127
  spatial_functions
@@ -133,10 +134,14 @@ Development
133
134
 
134
135
  The code is available on GitHub: https://github.com/geoalchemy/geoalchemy2.
135
136
 
136
- Contributors:
137
+ Main authors:
137
138
 
138
139
  * Adrien Berchet (https://github.com/adrien-berchet)
139
140
  * Éric Lemoine (https://github.com/elemoine)
141
+
142
+ Other contributors:
143
+
144
+ * Caleb Johnson (https://github.com/calebj)
140
145
  * Dolf Andringa (https://github.com/dolfandringa)
141
146
  * Frédéric Junod, Camptocamp SA (https://github.com/fredj)
142
147
  * ijl (https://github.com/ijl)
@@ -0,0 +1,43 @@
1
+ .. _mysql_mariadb_dialect:
2
+
3
+ MySQL / MariaDB Tutorial
4
+ ========================
5
+
6
+ GeoAlchemy 2's main target is PostGIS. But GeoAlchemy 2 also supports MySQL and MariaDB.
7
+ This tutorial describes how to use GeoAlchemy 2 with these dialects.
8
+
9
+ .. _mysql_mariadb_connect:
10
+
11
+ Connect to the DB
12
+ -----------------
13
+
14
+ Just like when using PostGIS connecting to a MySQL or MariaDB database requires an ``Engine``.
15
+ An engine for these dialects can be created in two ways. Using the plugin provided by
16
+ ``GeoAlchemy2`` (see :ref:`plugin` for more details)::
17
+
18
+ >>> from sqlalchemy import create_engine
19
+ >>> engine = create_engine(
20
+ ... "mysql://user:password@host:port/dbname",
21
+ ... echo=True,
22
+ ... plugins=["geoalchemy2"]
23
+ ... )
24
+
25
+ The call to ``create_engine`` creates an engine bound to the database given in the URL. After that
26
+ a ``before_cursor_execute`` listener is registered on the engine (see
27
+ :func:`geoalchemy2.admin.dialects.mysql.before_cursor_execute` and
28
+ :func:`geoalchemy2.admin.dialects.mariadb.before_cursor_execute`). The listener is responsible for
29
+ converting the parameters passed to query in the proper format, which is often a necessary operation
30
+ for using these dialects, though it depends on the driver used. If the driver does not require such
31
+ conversion, it is possible to disable this feature with the URL parameter
32
+ ``geoalchemy2_before_cursor_execute_mysql_convert`` or
33
+ ``geoalchemy2_before_cursor_execute_mariadb_convert``, depending on the dialect used.
34
+
35
+
36
+ It is also possible to create a raw engine and attach the listener manually::
37
+
38
+ >>> from geoalchemy2.admin.dialects.mysql import before_cursor_execute
39
+ >>> from sqlalchemy import create_engine
40
+ >>> from sqlalchemy.event import listen
41
+ >>>
42
+ >>> engine = create_engine("mysql://user:password@host:port/dbname", echo=True)
43
+ >>> listen(engine, "before_cursor_execute", before_cursor_execute)
@@ -20,7 +20,11 @@ For this tutorial we will use a PostGIS 2 database. To connect we use
20
20
  SQLAlchemy's ``create_engine()`` function::
21
21
 
22
22
  >>> from sqlalchemy import create_engine
23
- >>> engine = create_engine('postgresql://gis:gis@localhost/gis', echo=True)
23
+ >>> engine = create_engine(
24
+ ... 'postgresql://gis:gis@localhost/gis',
25
+ ... echo=True,
26
+ ... plugins=["geoalchemy2"]
27
+ ... )
24
28
 
25
29
  In this example the name of the database, the database user, and the database
26
30
  password, is ``gis``.
@@ -29,6 +33,11 @@ The ``echo`` flag is a shortcut to setting up SQLAlchemy logging, which is
29
33
  accomplished via Python's standard logging module. With it is enabled, we'll
30
34
  see all the generated SQL produced.
31
35
 
36
+ The ``plugins`` argument adds some event listeners to adapt the behavior of
37
+ ``GeoAlchemy2`` to the dialect. This is not mandatory but if the plugin is not
38
+ loaded, then the listeners will have to be added to the engine manually (see an
39
+ example in :ref:`spatialite_dialect`).
40
+
32
41
  The return value of ``create_engine`` is an ``Engine`` object, which
33
42
  represents the core interface to the database.
34
43
 
@@ -128,7 +137,9 @@ Add New Objects
128
137
 
129
138
  To persist our ``Lake`` object, we ``add()`` it to the ``Session``::
130
139
 
140
+ >>> lake = Lake(name="Majeur", geom="POLYGON((0 0,1 0,1 1,0 1,0 0))")
131
141
  >>> session.add(lake)
142
+ >>> session.commit()
132
143
 
133
144
  At this point the ``lake`` object has been added to the ``Session``, but no SQL
134
145
  has been issued to the database. The object is in a *pending* state. To persist
@@ -237,6 +248,9 @@ We can also apply relationship functions to
237
248
  ``session.scalar`` allows executing a clause and returning a scalar
238
249
  value (a boolean value in this case).
239
250
 
251
+ The value ``True`` indicates that the lake "Garde" does intersects the ``LINESTRING(2 1,4 1)``
252
+ geometry. See the SpatiaLite SQL functions reference list for more information.
253
+
240
254
  The GeoAlchemy functions all start with ``ST_``. Operators are also called as
241
255
  functions, but the function names don't include the ``ST_`` prefix. As an
242
256
  example let's use PostGIS' ``&&`` operator, which allows testing
@@ -0,0 +1,9 @@
1
+ .. _plugin:
2
+
3
+ Plugin
4
+ ======
5
+
6
+ .. automodule:: geoalchemy2.admin.plugin
7
+ :members:
8
+ :private-members:
9
+ :show-inheritance:
@@ -1,4 +1,4 @@
1
- .. _spatialite_tutorial:
1
+ .. _spatialite_dialect:
2
2
 
3
3
  SpatiaLite Tutorial
4
4
  ===================
@@ -12,8 +12,18 @@ the :ref:`orm_tutorial`, which you may want to read first.
12
12
  Connect to the DB
13
13
  -----------------
14
14
 
15
- Just like when using PostGIS connecting to a SpatiaLite database requires an ``Engine``. This is how
16
- you create one for SpatiaLite::
15
+ Just like when using PostGIS connecting to a SpatiaLite database requires an ``Engine``. An engine
16
+ for the SpatiaLite dialect can be created in two ways. Using the plugin provided by
17
+ ``GeoAlchemy2`` (see :ref:`plugin` for more details)::
18
+
19
+ >>> from sqlalchemy import create_engine
20
+ >>> engine = create_engine(
21
+ ... "sqlite:///gis.db",
22
+ ... echo=True,
23
+ ... plugins=["geoalchemy2"]
24
+ ... )
25
+
26
+ Or by attaching the listeners manually::
17
27
 
18
28
  >>> from geoalchemy2 import load_spatialite
19
29
  >>> from sqlalchemy import create_engine
@@ -70,108 +80,6 @@ From the user point of view this works in the same way as with PostGIS. The diff
70
80
  internally the ``RecoverGeometryColumn`` and ``DiscardGeometryColumn`` management functions will be
71
81
  used for the creation and removal of the geometry column.
72
82
 
73
- Create the Table in the Database
74
- --------------------------------
75
-
76
- We can now create the ``lake`` table in the ``gis.db`` database::
77
-
78
- >>> Lake.__table__.create(engine)
79
-
80
- If we wanted to drop the table we'd use::
81
-
82
- >>> Lake.__table__.drop(engine)
83
-
84
- There's nothing specific to SpatiaLite here.
85
-
86
- Create a Session
87
- ----------------
88
-
89
- When using the SQLAlchemy ORM the ORM interacts with the database through a ``Session``.
90
-
91
- >>> from sqlalchemy.orm import sessionmaker
92
- >>> Session = sessionmaker(bind=engine)
93
- >>> session = Session()
94
-
95
- The session is associated with our SpatiaLite ``Engine``. Again, there's nothing
96
- specific to SpatiaLite here.
97
-
98
- Add New Objects
99
- ---------------
100
-
101
- We can now create and insert new ``Lake`` objects into the database, the same way we'd
102
- do it using GeoAlchemy 2 with PostGIS.
103
-
104
- ::
105
-
106
- >>> lake = Lake(name="Majeur", geom="POLYGON((0 0,1 0,1 1,0 1,0 0))")
107
- >>> session.add(lake)
108
- >>> session.commit()
109
-
110
- We can now query the database for ``Majeur``::
111
-
112
- >>> our_lake = session.query(Lake).filter_by(name="Majeur").first()
113
- >>> our_lake.name
114
- u"Majeur"
115
- >>> our_lake.geom
116
- <WKBElement at 0x9af594c; "0103000000010000000500000000000000000000000000000000000000000000000000f03f0000000000000000000000000000f03f000000000000f03f0000000000000000000000000000f03f00000000000000000000000000000000">
117
- >>> our_lake.id
118
- 1
119
-
120
- Let's add more lakes::
121
-
122
- >>> session.add_all([
123
- ... Lake(name="Garde", geom="POLYGON((1 0,3 0,3 2,1 2,1 0))"),
124
- ... Lake(name="Orta", geom="POLYGON((3 0,6 0,6 3,3 3,3 0))")
125
- ... ])
126
- >>> session.commit()
127
-
128
- Query
129
- -----
130
-
131
- Let's make a simple, non-spatial, query::
132
-
133
- >>> query = session.query(Lake).order_by(Lake.name)
134
- >>> for lake in query:
135
- ... print(lake.name)
136
- ...
137
- Garde
138
- Majeur
139
- Orta
140
-
141
- Now a spatial query::
142
-
143
- >>> from geolachemy2 import WKTElement
144
- >>> query = session.query(Lake).filter(
145
- ... func.ST_Contains(Lake.geom, WKTElement("POINT(4 1)")))
146
- ...
147
- >>> for lake in query:
148
- ... print(lake.name)
149
- ...
150
- Orta
151
-
152
- Here's another spatial query, using ``ST_Intersects`` this time::
153
-
154
- >>> query = session.query(Lake).filter(
155
- ... Lake.geom.ST_Intersects(WKTElement("LINESTRING(2 1,4 1)")))
156
- ...
157
- >>> for lake in query:
158
- ... print(lake.name)
159
- ...
160
- Garde
161
- Orta
162
-
163
- We can also apply relationship functions to :class:`geoalchemy2.elements.WKBElement`. For example::
164
-
165
- >>> lake = session.query(Lake).filter_by(name="Garde").one()
166
- >>> print(session.scalar(lake.geom.ST_Intersects(WKTElement("LINESTRING(2 1,4 1)"))))
167
- 1
168
-
169
- ``session.scalar`` allows executing a clause and returning a scalar value (an integer value in this
170
- case).
171
-
172
- The value ``1`` indicates that the lake "Garde" does intersects the ``LINESTRING(2 1,4 1)``
173
- geometry. See the SpatiaLite SQL functions reference list for more information.
174
-
175
83
  Function mapping
176
84
  ----------------
177
85
 
@@ -201,7 +109,7 @@ GeoPackage format
201
109
  Starting from the version ``4.2`` of Spatialite, it is possible to use GeoPackage files as DB
202
110
  containers. GeoAlchemy 2 is able to handle most of the GeoPackage features automatically if the
203
111
  GeoPackage dialect is used (i.e. the DB URL starts with ``gpkg:///``) and the SpatiaLite extension
204
- is loaded. Usually, this extension should be loaded using the ``load_spatialite_gpkg`` listener::
112
+ is loaded. Usually, this extension should be loaded using the the ``GeoAlchemy2`` plugin (see :ref:`connect <spatialite_connect>` section) or by attaching the ``load_spatialite_gpkg`` listener to the engine::
205
113
 
206
114
  >>> from geoalchemy2 import load_spatialite_gpkg
207
115
  >>> from sqlalchemy import create_engine
@@ -8,6 +8,7 @@ from geoalchemy2 import shape # noqa
8
8
  from geoalchemy2 import types # noqa
9
9
  from geoalchemy2.admin.dialects.geopackage import load_spatialite_gpkg # noqa
10
10
  from geoalchemy2.admin.dialects.sqlite import load_spatialite # noqa
11
+ from geoalchemy2.admin.plugin import GeoEngine # noqa
11
12
  from geoalchemy2.elements import CompositeElement # noqa
12
13
  from geoalchemy2.elements import RasterElement # noqa
13
14
  from geoalchemy2.elements import WKBElement # noqa
@@ -50,6 +51,7 @@ __all__ = [
50
51
  "__version__",
51
52
  "ArgumentError",
52
53
  "CompositeElement",
54
+ "GeoEngine",
53
55
  "Geography",
54
56
  "Geometry",
55
57
  "Raster",
@@ -20,7 +20,7 @@ def select_dialect(dialect_name):
20
20
  known_dialects = {
21
21
  "geopackage": dialects.geopackage,
22
22
  "mysql": dialects.mysql,
23
- "mariadb": dialects.mysql,
23
+ "mariadb": dialects.mariadb,
24
24
  "postgresql": dialects.postgresql,
25
25
  "sqlite": dialects.sqlite,
26
26
  }
@@ -53,7 +53,7 @@ def setup_ddl_event_listeners():
53
53
  @event.listens_for(Column, "after_parent_attach")
54
54
  def after_parent_attach(column, table):
55
55
  """Automatically add spatial indexes."""
56
- if not isinstance(table, Table):
56
+ if not isinstance(table, Table): # pragma: no cover
57
57
  # For old versions of SQLAlchemy, subqueries might trigger the after_parent_attach event
58
58
  # with a selectable as table, so we want to skip this case.
59
59
  return
@@ -75,7 +75,7 @@ def setup_ddl_event_listeners():
75
75
  try:
76
76
  if column.type._spatial_index_reflected:
77
77
  return
78
- except AttributeError:
78
+ except AttributeError: # pragma: no cover
79
79
  pass
80
80
 
81
81
  kwargs = {
@@ -98,7 +98,7 @@ def setup_ddl_event_listeners():
98
98
  )
99
99
 
100
100
  @event.listens_for(Table, "column_reflect")
101
- def _reflect_geometry_column(inspector, table, column_info):
101
+ def column_reflect(inspector, table, column_info):
102
102
  select_dialect(inspector.bind.dialect.name).reflect_geometry_column(
103
103
  inspector, table, column_info
104
104
  )
@@ -2,6 +2,7 @@
2
2
 
3
3
  from geoalchemy2.admin.dialects import common # noqa
4
4
  from geoalchemy2.admin.dialects import geopackage # noqa
5
+ from geoalchemy2.admin.dialects import mariadb # noqa
5
6
  from geoalchemy2.admin.dialects import mysql # noqa
6
7
  from geoalchemy2.admin.dialects import postgresql # noqa
7
8
  from geoalchemy2.admin.dialects import sqlite # noqa
@@ -85,20 +85,20 @@ def setup_create_drop(table, bind, check_col_management=None):
85
85
 
86
86
 
87
87
  def reflect_geometry_column(inspector, table, column_info):
88
- return
88
+ return # pragma: no cover
89
89
 
90
90
 
91
91
  def before_create(table, bind, **kw):
92
- return
92
+ return # pragma: no cover
93
93
 
94
94
 
95
95
  def after_create(table, bind, **kw):
96
- return
96
+ return # pragma: no cover
97
97
 
98
98
 
99
99
  def before_drop(table, bind, **kw):
100
- return
100
+ return # pragma: no cover
101
101
 
102
102
 
103
103
  def after_drop(table, bind, **kw):
104
- return
104
+ return # pragma: no cover
@@ -71,15 +71,15 @@ def init_geopackage(dbapi_conn, *args):
71
71
  dbapi_conn.execute("SELECT gpkgCreateBaseTables();")
72
72
 
73
73
 
74
- def load_spatialite_gpkg(*args, **kwargs):
74
+ def load_spatialite_gpkg(dbapi_conn, *args, **kwargs):
75
75
  """Load SpatiaLite extension in GeoPackage and initialize internal tables.
76
76
 
77
77
  See :func:`geoalchemy2.admin.dialects.geopackage.load_geopackage_driver` and
78
78
  :func:`geoalchemy2.admin.dialects.geopackage.init_geopackage` functions for details about
79
79
  arguments.
80
80
  """
81
- load_geopackage_driver(*args)
82
- init_geopackage(*args, **kwargs)
81
+ load_geopackage_driver(dbapi_conn)
82
+ init_geopackage(dbapi_conn, **kwargs)
83
83
 
84
84
 
85
85
  def _get_spatialite_attrs(bind, table_name, col_name):
@@ -188,6 +188,10 @@ def reflect_geometry_column(inspector, table, column_info):
188
188
  column_info["type"]._spatial_index_reflected = False
189
189
 
190
190
 
191
+ def connect(dbapi_conn, *args, **kwargs):
192
+ return load_spatialite_gpkg(dbapi_conn, *args, **kwargs)
193
+
194
+
191
195
  def before_create(table, bind, **kw):
192
196
  """Handle spatial indexes during the before_create event."""
193
197
  dialect, gis_cols, regular_cols = setup_create_drop(table, bind)