hdx-python-database 1.3.4__tar.gz → 1.3.6__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.
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.config/pre-commit-config.yaml +3 -3
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.github/workflows/publish.yaml +9 -6
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.github/workflows/run-python-tests.yaml +4 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/PKG-INFO +4 -2
- hdx_python_database-1.3.6/documentation/.readthedocs.yaml +14 -0
- hdx_python_database-1.3.4/documentation/main.md → hdx_python_database-1.3.6/documentation/index.md +11 -0
- hdx_python_database-1.3.6/documentation/mkdocs.yaml +16 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/pyproject.toml +4 -0
- hdx_python_database-1.3.6/requirements.txt +148 -0
- hdx_python_database-1.3.6/src/hdx/database/__init__.py +3 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/_version.py +9 -4
- hdx_python_database-1.3.4/src/hdx/database/__init__.py → hdx_python_database-1.3.6/src/hdx/database/database.py +44 -21
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/views.py +8 -17
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_database.py +11 -3
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_reflect.py +1 -1
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_ssh.py +4 -4
- hdx_python_database-1.3.4/documentation/.readthedocs.yaml +0 -16
- hdx_python_database-1.3.4/documentation/pydoc-markdown.yaml +0 -29
- hdx_python_database-1.3.4/requirements.txt +0 -62
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.config/coveragerc +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.config/pytest.ini +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.config/ruff.toml +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/.gitignore +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/CONTRIBUTING.md +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/LICENSE +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/README.md +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/dburi.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/no_timezone.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/postgresql.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/utils.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/src/hdx/database/with_timezone.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/fixtures/test.db +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/__init__.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/conftest.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/dbtestdate.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_dburi.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_postgresql.py +0 -0
- {hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_recreate.py +0 -0
|
@@ -2,13 +2,13 @@ default_language_version:
|
|
|
2
2
|
python: python3.12
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
-
rev:
|
|
5
|
+
rev: v5.0.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: trailing-whitespace
|
|
8
8
|
- id: end-of-file-fixer
|
|
9
9
|
- id: check-ast
|
|
10
10
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
11
|
-
rev: v0.
|
|
11
|
+
rev: v0.9.10
|
|
12
12
|
hooks:
|
|
13
13
|
# Run the linter.
|
|
14
14
|
- id: ruff
|
|
@@ -17,7 +17,7 @@ repos:
|
|
|
17
17
|
- id: ruff-format
|
|
18
18
|
args: [--config, .config/ruff.toml]
|
|
19
19
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
20
|
-
rev: 0.
|
|
20
|
+
rev: 0.6.5
|
|
21
21
|
hooks:
|
|
22
22
|
# Run the pip compile
|
|
23
23
|
- id: pip-compile
|
|
@@ -8,6 +8,13 @@ jobs:
|
|
|
8
8
|
publish:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
|
|
11
|
+
environment:
|
|
12
|
+
name: pypi
|
|
13
|
+
url: https://pypi.org/p/hdx-python-database
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write # IMPORTANT: mandatory for trusted publishing
|
|
17
|
+
|
|
11
18
|
steps:
|
|
12
19
|
- uses: actions/checkout@v4
|
|
13
20
|
- name: Get history and tags for versioning to work
|
|
@@ -26,9 +33,5 @@ jobs:
|
|
|
26
33
|
- name: Build with hatch
|
|
27
34
|
run: |
|
|
28
35
|
hatch build
|
|
29
|
-
- name: Publish
|
|
30
|
-
|
|
31
|
-
HATCH_INDEX_USER: ${{secrets.HATCH_INDEX_USER}}
|
|
32
|
-
HATCH_INDEX_AUTH: ${{secrets.HATCH_INDEX_AUTH}}
|
|
33
|
-
run: |
|
|
34
|
-
hatch publish
|
|
36
|
+
- name: Publish distribution 📦 to PyPI
|
|
37
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: hdx-python-database
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: HDX Python database utilities
|
|
5
5
|
Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-database
|
|
6
6
|
Author-email: Michael Rans <rans@email.com>
|
|
@@ -28,6 +28,8 @@ Requires-Python: >=3.8
|
|
|
28
28
|
Requires-Dist: sqlalchemy>=2
|
|
29
29
|
Provides-Extra: dev
|
|
30
30
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: mkapi; extra == 'docs'
|
|
31
33
|
Provides-Extra: postgresql
|
|
32
34
|
Requires-Dist: psycopg[binary]; extra == 'postgresql'
|
|
33
35
|
Provides-Extra: sshtunnel
|
hdx_python_database-1.3.4/documentation/main.md → hdx_python_database-1.3.6/documentation/index.md
RENAMED
|
@@ -61,6 +61,7 @@ Versions from 1.0.6 no longer support Python 2.7.
|
|
|
61
61
|
A fresh schema can be created using the function `recreate_schema`. Any
|
|
62
62
|
existing schema with that name will be dropped eg.
|
|
63
63
|
|
|
64
|
+
from hdx.database import Database
|
|
64
65
|
Database.recreate_schema(engine, db_uri)
|
|
65
66
|
|
|
66
67
|
Your SQLAlchemy database tables must inherit from `Base` in
|
|
@@ -117,6 +118,16 @@ If a prepare function is supplied in prepare_fn, it will be executed before
|
|
|
117
118
|
Base.metadata.create_all and the results of it returned in instance variable
|
|
118
119
|
prepare_results.
|
|
119
120
|
|
|
121
|
+
Batch population of rows (list of dictionaries) can be achieved with the
|
|
122
|
+
batch_populate method of Database, for example:
|
|
123
|
+
|
|
124
|
+
now = datetime(2023, 10, 20, 22, 35, 55, tzinfo=timezone.utc)
|
|
125
|
+
rows = [{"test_date": now}]
|
|
126
|
+
dbdatabase.batch_populate(rows, DBTestDate)
|
|
127
|
+
dbtestdate = (
|
|
128
|
+
dbsession.execute(select(DBTestDate)).all()[1][0].test_date
|
|
129
|
+
)
|
|
130
|
+
|
|
120
131
|
|
|
121
132
|
## Connection URI
|
|
122
133
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
site_name: HDX Python Database
|
|
2
|
+
repo_url: https://github.com/OCHA-DAP/hdx-python-database/
|
|
3
|
+
repo_name: OCHA-DAP/hdx-python-database
|
|
4
|
+
docs_dir: .
|
|
5
|
+
site_dir: ../site
|
|
6
|
+
theme:
|
|
7
|
+
name: material
|
|
8
|
+
highlightjs: true
|
|
9
|
+
plugins:
|
|
10
|
+
- search
|
|
11
|
+
- mkapi
|
|
12
|
+
nav:
|
|
13
|
+
- Home: index.md
|
|
14
|
+
- API Documentation:
|
|
15
|
+
- Database: $src/hdx.database.*
|
|
16
|
+
- PostgreSQL specific: $src/hdx.database.postgresql.*
|
|
@@ -50,6 +50,7 @@ sshtunnel = ["sshtunnel"]
|
|
|
50
50
|
postgresql = ["psycopg[binary]"]
|
|
51
51
|
test = ["pytest", "pytest-cov"]
|
|
52
52
|
dev = ["pre-commit"]
|
|
53
|
+
docs = ["mkapi"]
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
#########
|
|
@@ -88,6 +89,9 @@ run = """
|
|
|
88
89
|
--cov-report=lcov --cov-report=term-missing
|
|
89
90
|
"""
|
|
90
91
|
|
|
92
|
+
[tool.hatch.envs.hatch-static-analysis]
|
|
93
|
+
dependencies = ["ruff==0.9.10"]
|
|
94
|
+
|
|
91
95
|
[tool.hatch.envs.hatch-static-analysis.scripts]
|
|
92
96
|
format-check = ["ruff format --config .config/ruff.toml --check --diff {args:.}",]
|
|
93
97
|
format-fix = ["ruff format --config .config/ruff.toml {args:.}",]
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# This file was autogenerated by uv via the following command:
|
|
2
|
+
# uv pip compile pyproject.toml --resolver=backtracking --all-extras -o requirements.txt
|
|
3
|
+
astdoc==1.1.5
|
|
4
|
+
# via mkapi
|
|
5
|
+
babel==2.17.0
|
|
6
|
+
# via mkdocs-material
|
|
7
|
+
backrefs==5.8
|
|
8
|
+
# via mkdocs-material
|
|
9
|
+
bcrypt==4.3.0
|
|
10
|
+
# via paramiko
|
|
11
|
+
certifi==2025.1.31
|
|
12
|
+
# via requests
|
|
13
|
+
cffi==1.17.1
|
|
14
|
+
# via
|
|
15
|
+
# cryptography
|
|
16
|
+
# pynacl
|
|
17
|
+
cfgv==3.4.0
|
|
18
|
+
# via pre-commit
|
|
19
|
+
charset-normalizer==3.4.1
|
|
20
|
+
# via requests
|
|
21
|
+
click==8.1.8
|
|
22
|
+
# via mkdocs
|
|
23
|
+
colorama==0.4.6
|
|
24
|
+
# via mkdocs-material
|
|
25
|
+
coverage==7.7.0
|
|
26
|
+
# via pytest-cov
|
|
27
|
+
cryptography==44.0.2
|
|
28
|
+
# via paramiko
|
|
29
|
+
distlib==0.3.9
|
|
30
|
+
# via virtualenv
|
|
31
|
+
filelock==3.18.0
|
|
32
|
+
# via virtualenv
|
|
33
|
+
ghp-import==2.1.0
|
|
34
|
+
# via mkdocs
|
|
35
|
+
greenlet==3.1.1
|
|
36
|
+
# via sqlalchemy
|
|
37
|
+
identify==2.6.9
|
|
38
|
+
# via pre-commit
|
|
39
|
+
idna==3.10
|
|
40
|
+
# via requests
|
|
41
|
+
iniconfig==2.0.0
|
|
42
|
+
# via pytest
|
|
43
|
+
jinja2==3.1.6
|
|
44
|
+
# via
|
|
45
|
+
# mkapi
|
|
46
|
+
# mkdocs
|
|
47
|
+
# mkdocs-material
|
|
48
|
+
markdown==3.7
|
|
49
|
+
# via
|
|
50
|
+
# astdoc
|
|
51
|
+
# mkdocs
|
|
52
|
+
# mkdocs-material
|
|
53
|
+
# pymdown-extensions
|
|
54
|
+
markdown-it-py==3.0.0
|
|
55
|
+
# via rich
|
|
56
|
+
markupsafe==3.0.2
|
|
57
|
+
# via
|
|
58
|
+
# jinja2
|
|
59
|
+
# mkdocs
|
|
60
|
+
mdurl==0.1.2
|
|
61
|
+
# via markdown-it-py
|
|
62
|
+
mergedeep==1.3.4
|
|
63
|
+
# via
|
|
64
|
+
# mkdocs
|
|
65
|
+
# mkdocs-get-deps
|
|
66
|
+
mkapi==4.1.3
|
|
67
|
+
# via hdx-python-database (pyproject.toml)
|
|
68
|
+
mkdocs==1.6.1
|
|
69
|
+
# via
|
|
70
|
+
# mkapi
|
|
71
|
+
# mkdocs-material
|
|
72
|
+
mkdocs-get-deps==0.2.0
|
|
73
|
+
# via mkdocs
|
|
74
|
+
mkdocs-material==9.6.8
|
|
75
|
+
# via mkapi
|
|
76
|
+
mkdocs-material-extensions==1.3.1
|
|
77
|
+
# via mkdocs-material
|
|
78
|
+
nodeenv==1.9.1
|
|
79
|
+
# via pre-commit
|
|
80
|
+
packaging==24.2
|
|
81
|
+
# via
|
|
82
|
+
# mkdocs
|
|
83
|
+
# pytest
|
|
84
|
+
paginate==0.5.7
|
|
85
|
+
# via mkdocs-material
|
|
86
|
+
paramiko==3.5.1
|
|
87
|
+
# via sshtunnel
|
|
88
|
+
pathspec==0.12.1
|
|
89
|
+
# via mkdocs
|
|
90
|
+
platformdirs==4.3.6
|
|
91
|
+
# via
|
|
92
|
+
# mkdocs-get-deps
|
|
93
|
+
# virtualenv
|
|
94
|
+
pluggy==1.5.0
|
|
95
|
+
# via pytest
|
|
96
|
+
pre-commit==4.1.0
|
|
97
|
+
# via hdx-python-database (pyproject.toml)
|
|
98
|
+
psycopg==3.2.6
|
|
99
|
+
# via hdx-python-database (pyproject.toml)
|
|
100
|
+
psycopg-binary==3.2.6
|
|
101
|
+
# via psycopg
|
|
102
|
+
pycparser==2.22
|
|
103
|
+
# via cffi
|
|
104
|
+
pygments==2.19.1
|
|
105
|
+
# via
|
|
106
|
+
# mkdocs-material
|
|
107
|
+
# rich
|
|
108
|
+
pymdown-extensions==10.14.3
|
|
109
|
+
# via mkdocs-material
|
|
110
|
+
pynacl==1.5.0
|
|
111
|
+
# via paramiko
|
|
112
|
+
pytest==8.3.5
|
|
113
|
+
# via
|
|
114
|
+
# hdx-python-database (pyproject.toml)
|
|
115
|
+
# pytest-cov
|
|
116
|
+
pytest-cov==6.0.0
|
|
117
|
+
# via hdx-python-database (pyproject.toml)
|
|
118
|
+
python-dateutil==2.9.0.post0
|
|
119
|
+
# via ghp-import
|
|
120
|
+
pyyaml==6.0.2
|
|
121
|
+
# via
|
|
122
|
+
# mkdocs
|
|
123
|
+
# mkdocs-get-deps
|
|
124
|
+
# pre-commit
|
|
125
|
+
# pymdown-extensions
|
|
126
|
+
# pyyaml-env-tag
|
|
127
|
+
pyyaml-env-tag==0.1
|
|
128
|
+
# via mkdocs
|
|
129
|
+
requests==2.32.3
|
|
130
|
+
# via mkdocs-material
|
|
131
|
+
rich==13.9.4
|
|
132
|
+
# via mkapi
|
|
133
|
+
six==1.17.0
|
|
134
|
+
# via python-dateutil
|
|
135
|
+
sqlalchemy==2.0.39
|
|
136
|
+
# via hdx-python-database (pyproject.toml)
|
|
137
|
+
sshtunnel==0.4.0
|
|
138
|
+
# via hdx-python-database (pyproject.toml)
|
|
139
|
+
typing-extensions==4.12.2
|
|
140
|
+
# via
|
|
141
|
+
# psycopg
|
|
142
|
+
# sqlalchemy
|
|
143
|
+
urllib3==2.3.0
|
|
144
|
+
# via requests
|
|
145
|
+
virtualenv==20.29.3
|
|
146
|
+
# via pre-commit
|
|
147
|
+
watchdog==6.0.0
|
|
148
|
+
# via mkdocs
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '1.3.
|
|
16
|
-
__version_tuple__ = version_tuple = (1, 3,
|
|
20
|
+
__version__ = version = '1.3.6'
|
|
21
|
+
__version_tuple__ = version_tuple = (1, 3, 6)
|
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
|
5
5
|
|
|
6
|
-
from sqlalchemy import Engine, TableClause, create_engine
|
|
6
|
+
from sqlalchemy import Engine, TableClause, create_engine, insert
|
|
7
7
|
from sqlalchemy.exc import SQLAlchemyError
|
|
8
8
|
from sqlalchemy.ext.automap import automap_base
|
|
9
9
|
from sqlalchemy.orm import DeclarativeBase, Session
|
|
10
10
|
from sqlalchemy.pool import NullPool
|
|
11
11
|
from sqlalchemy.sql.ddl import CreateSchema, DropSchema
|
|
12
12
|
|
|
13
|
-
from ._version import version as __version__ # noqa: F401
|
|
14
13
|
from .dburi import get_connection_uri
|
|
15
14
|
from .no_timezone import Base as NoTZBase
|
|
16
15
|
from .postgresql import restore_from_pgfile, wait_for_postgresql
|
|
@@ -123,16 +122,16 @@ class Database:
|
|
|
123
122
|
del kwargs["ssh_port"]
|
|
124
123
|
else:
|
|
125
124
|
ssh_port = 22
|
|
126
|
-
self.
|
|
125
|
+
self._server = sshtunnel.SSHTunnelForwarder(
|
|
127
126
|
(ssh_host, ssh_port),
|
|
128
127
|
remote_bind_address=(host, port),
|
|
129
128
|
**kwargs,
|
|
130
129
|
)
|
|
131
|
-
self.
|
|
132
|
-
host = self.
|
|
133
|
-
port = self.
|
|
130
|
+
self._server.start()
|
|
131
|
+
host = self._server.local_bind_host
|
|
132
|
+
port = self._server.local_bind_port
|
|
134
133
|
else:
|
|
135
|
-
self.
|
|
134
|
+
self._server = None
|
|
136
135
|
if not engine and not db_uri:
|
|
137
136
|
db_uri = get_connection_uri(
|
|
138
137
|
database,
|
|
@@ -158,19 +157,19 @@ class Database:
|
|
|
158
157
|
table_base = NoTZBase
|
|
159
158
|
if not engine:
|
|
160
159
|
engine = create_engine(db_uri, poolclass=NullPool, echo=False)
|
|
161
|
-
self.
|
|
160
|
+
self._engine: Engine = engine
|
|
162
161
|
if recreate_schema:
|
|
163
162
|
self.recreate_schema(engine, schema_name)
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
163
|
+
self._prepare_results = prepare_fn()
|
|
164
|
+
self._session, self._base = self.create_session(
|
|
166
165
|
engine,
|
|
167
166
|
table_base=table_base,
|
|
168
167
|
reflect=reflect,
|
|
169
168
|
)
|
|
170
169
|
if reflect:
|
|
171
|
-
self.
|
|
170
|
+
self._reflected_classes = self._base.classes
|
|
172
171
|
else:
|
|
173
|
-
self.
|
|
172
|
+
self._reflected_classes = None
|
|
174
173
|
|
|
175
174
|
def cleanup(self) -> None:
|
|
176
175
|
"""Cleanup SQLAlchemy.
|
|
@@ -178,10 +177,10 @@ class Database:
|
|
|
178
177
|
Returns:
|
|
179
178
|
sqlalchemy.Engine: SQLAlchemy engine
|
|
180
179
|
"""
|
|
181
|
-
self.
|
|
182
|
-
self.
|
|
183
|
-
if self.
|
|
184
|
-
self.
|
|
180
|
+
self._session.close()
|
|
181
|
+
self._engine.dispose()
|
|
182
|
+
if self._server is not None:
|
|
183
|
+
self._server.stop()
|
|
185
184
|
|
|
186
185
|
def __enter__(self) -> "Database":
|
|
187
186
|
return self
|
|
@@ -195,7 +194,7 @@ class Database:
|
|
|
195
194
|
Returns:
|
|
196
195
|
None
|
|
197
196
|
"""
|
|
198
|
-
self.
|
|
197
|
+
self._base.metadata.drop_all(self._engine)
|
|
199
198
|
|
|
200
199
|
def get_engine(self) -> Engine:
|
|
201
200
|
"""Returns SQLAlchemy engine.
|
|
@@ -203,7 +202,7 @@ class Database:
|
|
|
203
202
|
Returns:
|
|
204
203
|
sqlalchemy.Engine: SQLAlchemy engine
|
|
205
204
|
"""
|
|
206
|
-
return self.
|
|
205
|
+
return self._engine
|
|
207
206
|
|
|
208
207
|
def get_session(self) -> Session:
|
|
209
208
|
"""Returns SQLAlchemy session.
|
|
@@ -211,7 +210,7 @@ class Database:
|
|
|
211
210
|
Returns:
|
|
212
211
|
sqlalchemy.orm.Session: SQLAlchemy session
|
|
213
212
|
"""
|
|
214
|
-
return self.
|
|
213
|
+
return self._session
|
|
215
214
|
|
|
216
215
|
def get_reflected_classes(self) -> Any:
|
|
217
216
|
"""Gets reflected classes.
|
|
@@ -219,7 +218,7 @@ class Database:
|
|
|
219
218
|
Returns:
|
|
220
219
|
Any: Reflected classes
|
|
221
220
|
"""
|
|
222
|
-
return self.
|
|
221
|
+
return self._reflected_classes
|
|
223
222
|
|
|
224
223
|
def get_prepare_results(self) -> Any:
|
|
225
224
|
"""Returns results from prepare function.
|
|
@@ -227,7 +226,31 @@ class Database:
|
|
|
227
226
|
Returns:
|
|
228
227
|
Any: Results from prepare function
|
|
229
228
|
"""
|
|
230
|
-
return self.
|
|
229
|
+
return self._prepare_results
|
|
230
|
+
|
|
231
|
+
def batch_populate(
|
|
232
|
+
self,
|
|
233
|
+
rows: List[Dict],
|
|
234
|
+
dbtable: Type[DeclarativeBase],
|
|
235
|
+
batch_size: int = 1000,
|
|
236
|
+
) -> None:
|
|
237
|
+
"""Batch populate database table.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
rows (List[Dict]): List of rows
|
|
241
|
+
dbtable (Type[DeclarativeBase]): Database table
|
|
242
|
+
batch_size (int): Batch size. Defaults to 1000.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Tuple[Session, Any]: (SQLAlchemy session, base)
|
|
246
|
+
"""
|
|
247
|
+
batches = range(len(rows) // batch_size + 1)
|
|
248
|
+
for batch in batches:
|
|
249
|
+
start_row = batch * batch_size
|
|
250
|
+
end_row = start_row + batch_size
|
|
251
|
+
batch_rows = rows[start_row:end_row]
|
|
252
|
+
self._session.execute(insert(dbtable), batch_rows)
|
|
253
|
+
self._session.commit()
|
|
231
254
|
|
|
232
255
|
@staticmethod
|
|
233
256
|
def create_session(
|
|
@@ -7,10 +7,8 @@ https://github.com/sqlalchemy/sqlalchemy/wiki/Views#sqlalchemy-14-20-version
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import sqlalchemy as sa
|
|
10
|
-
from sqlalchemy import MetaData, Selectable, TableClause
|
|
11
10
|
from sqlalchemy.ext import compiler
|
|
12
11
|
from sqlalchemy.schema import DDLElement
|
|
13
|
-
from sqlalchemy.sql import table
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
class CreateView(DDLElement):
|
|
@@ -45,22 +43,15 @@ def view_doesnt_exist(ddl, target, connection, **kw):
|
|
|
45
43
|
return not view_exists(ddl, target, connection, **kw)
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
def view(name
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
TableClause: SQLAlchemy View
|
|
58
|
-
"""
|
|
59
|
-
t = table(name)
|
|
60
|
-
|
|
61
|
-
t._columns._populate_separate_keys(
|
|
62
|
-
col._make_proxy(t) for col in selectable.selected_columns
|
|
46
|
+
def view(name, metadata, selectable):
|
|
47
|
+
t = sa.table(
|
|
48
|
+
name,
|
|
49
|
+
*(
|
|
50
|
+
sa.Column(c.name, c.type, primary_key=c.primary_key)
|
|
51
|
+
for c in selectable.selected_columns
|
|
52
|
+
),
|
|
63
53
|
)
|
|
54
|
+
t.primary_key.update(c for c in t.c if c.primary_key)
|
|
64
55
|
|
|
65
56
|
sa.event.listen(
|
|
66
57
|
metadata,
|
|
@@ -31,10 +31,9 @@ class TestDatabase:
|
|
|
31
31
|
) as dbdatabase:
|
|
32
32
|
dbsession = dbdatabase.get_session()
|
|
33
33
|
assert str(dbsession.bind.engine.url) == f"sqlite:///{dbpath}"
|
|
34
|
-
assert dbdatabase.
|
|
34
|
+
assert dbdatabase._base == NoTZBase
|
|
35
35
|
now = datetime(2022, 10, 20, 22, 35, 55, tzinfo=timezone.utc)
|
|
36
|
-
input_dbtestdate = DBTestDate()
|
|
37
|
-
input_dbtestdate.test_date = now
|
|
36
|
+
input_dbtestdate = DBTestDate(test_date=now)
|
|
38
37
|
dbsession.add(input_dbtestdate)
|
|
39
38
|
dbsession.commit()
|
|
40
39
|
dbtestdate = dbsession.execute(select(DBTestDate)).scalar_one()
|
|
@@ -42,6 +41,15 @@ class TestDatabase:
|
|
|
42
41
|
date_view = dbdatabase.get_prepare_results()[0]
|
|
43
42
|
dbtestdate = dbsession.execute(select(date_view)).scalar_one()
|
|
44
43
|
assert dbtestdate == now
|
|
44
|
+
|
|
45
|
+
now = datetime(2023, 10, 20, 22, 35, 55, tzinfo=timezone.utc)
|
|
46
|
+
rows = [{"test_date": now}]
|
|
47
|
+
dbdatabase.batch_populate(rows, DBTestDate)
|
|
48
|
+
dbtestdate = (
|
|
49
|
+
dbsession.execute(select(DBTestDate)).all()[1][0].test_date
|
|
50
|
+
)
|
|
51
|
+
assert dbtestdate == now
|
|
52
|
+
|
|
45
53
|
remove(dbpath)
|
|
46
54
|
|
|
47
55
|
def test_errors(self):
|
|
@@ -27,7 +27,7 @@ class TestReflect:
|
|
|
27
27
|
dburi = f"sqlite:///{dbpath}"
|
|
28
28
|
assert str(dbengine.url) == dburi
|
|
29
29
|
dbsession = dbdatabase.get_session()
|
|
30
|
-
assert isinstance(dbdatabase.
|
|
30
|
+
assert isinstance(dbdatabase._base, DeclarativeAttributeIntercept)
|
|
31
31
|
assert str(dbsession.bind.engine.url) == dburi
|
|
32
32
|
Table1 = dbdatabase.get_reflected_classes().table1
|
|
33
33
|
row = dbsession.execute(select(Table1)).scalar_one()
|
|
@@ -33,7 +33,7 @@ class TestSSH:
|
|
|
33
33
|
str(dbsession.bind.engine.url)
|
|
34
34
|
== "postgresql+psycopg://myuser@0.0.0.0:12345/mydatabase"
|
|
35
35
|
)
|
|
36
|
-
assert dbdatabase.
|
|
36
|
+
assert dbdatabase._base == TZBase
|
|
37
37
|
|
|
38
38
|
with Database(
|
|
39
39
|
ssh_host="mysshhost", ssh_port=25, table_base=TZBase, **params
|
|
@@ -43,7 +43,7 @@ class TestSSH:
|
|
|
43
43
|
str(dbsession.bind.engine.url)
|
|
44
44
|
== "postgresql+psycopg://myuser@0.0.0.0:12345/mydatabase"
|
|
45
45
|
)
|
|
46
|
-
assert dbdatabase.
|
|
46
|
+
assert dbdatabase._base == TZBase
|
|
47
47
|
|
|
48
48
|
with Database(ssh_host="mysshhost", **self.params_pg) as dbdatabase:
|
|
49
49
|
dbsession = dbdatabase.get_session()
|
|
@@ -51,7 +51,7 @@ class TestSSH:
|
|
|
51
51
|
str(dbsession.bind.engine.url)
|
|
52
52
|
== "postgresql+psycopg://myuser:***@0.0.0.0:12345/mydatabase"
|
|
53
53
|
)
|
|
54
|
-
assert dbdatabase.
|
|
54
|
+
assert dbdatabase._base == NoTZBase
|
|
55
55
|
|
|
56
56
|
with Database(
|
|
57
57
|
ssh_host="mysshhost", ssh_port=25, **params
|
|
@@ -61,4 +61,4 @@ class TestSSH:
|
|
|
61
61
|
str(dbsession.bind.engine.url)
|
|
62
62
|
== "postgresql+psycopg://myuser@0.0.0.0:12345/mydatabase"
|
|
63
63
|
)
|
|
64
|
-
assert dbdatabase.
|
|
64
|
+
assert dbdatabase._base == NoTZBase
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
|
|
3
|
-
mkdocs:
|
|
4
|
-
configuration: docs/mkdocs.yml
|
|
5
|
-
fail_on_warning: false
|
|
6
|
-
|
|
7
|
-
build:
|
|
8
|
-
os: ubuntu-22.04
|
|
9
|
-
tools:
|
|
10
|
-
python: "3.11"
|
|
11
|
-
jobs:
|
|
12
|
-
pre_build:
|
|
13
|
-
- pip install --upgrade mkdocs
|
|
14
|
-
- pip install mkdocs-material
|
|
15
|
-
- pip install pydoc-markdown
|
|
16
|
-
- pydoc-markdown documentation/pydoc-markdown.yaml
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
loaders:
|
|
2
|
-
- type: python
|
|
3
|
-
search_path:
|
|
4
|
-
- ../src
|
|
5
|
-
packages:
|
|
6
|
-
- hdx.database
|
|
7
|
-
renderer:
|
|
8
|
-
type: mkdocs
|
|
9
|
-
output_directory: docs
|
|
10
|
-
mkdocs_config:
|
|
11
|
-
site_name: HDX Python Database
|
|
12
|
-
theme: material
|
|
13
|
-
repo_url: "https://github.com/OCHA-DAP/hdx-python-database"
|
|
14
|
-
markdown:
|
|
15
|
-
source_linker:
|
|
16
|
-
type: github
|
|
17
|
-
repo: OCHA-DAP/hdx-python-database
|
|
18
|
-
pages:
|
|
19
|
-
- title: Home
|
|
20
|
-
name: index
|
|
21
|
-
source: main.md
|
|
22
|
-
- title: API Documentation
|
|
23
|
-
children:
|
|
24
|
-
- title: Database
|
|
25
|
-
contents:
|
|
26
|
-
- hdx.database.Database.*
|
|
27
|
-
- title: PostgreSQL specific
|
|
28
|
-
contents:
|
|
29
|
-
- hdx.database.postgresql.*
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# This file was autogenerated by uv via the following command:
|
|
2
|
-
# uv pip compile pyproject.toml --resolver=backtracking --all-extras -o requirements.txt
|
|
3
|
-
bcrypt==4.2.0
|
|
4
|
-
# via paramiko
|
|
5
|
-
cffi==1.17.1
|
|
6
|
-
# via
|
|
7
|
-
# cryptography
|
|
8
|
-
# pynacl
|
|
9
|
-
cfgv==3.4.0
|
|
10
|
-
# via pre-commit
|
|
11
|
-
coverage==7.6.3
|
|
12
|
-
# via pytest-cov
|
|
13
|
-
cryptography==43.0.1
|
|
14
|
-
# via paramiko
|
|
15
|
-
distlib==0.3.9
|
|
16
|
-
# via virtualenv
|
|
17
|
-
filelock==3.16.1
|
|
18
|
-
# via virtualenv
|
|
19
|
-
greenlet==3.1.1
|
|
20
|
-
# via sqlalchemy
|
|
21
|
-
identify==2.6.1
|
|
22
|
-
# via pre-commit
|
|
23
|
-
iniconfig==2.0.0
|
|
24
|
-
# via pytest
|
|
25
|
-
nodeenv==1.9.1
|
|
26
|
-
# via pre-commit
|
|
27
|
-
packaging==24.1
|
|
28
|
-
# via pytest
|
|
29
|
-
paramiko==3.5.0
|
|
30
|
-
# via sshtunnel
|
|
31
|
-
platformdirs==4.3.6
|
|
32
|
-
# via virtualenv
|
|
33
|
-
pluggy==1.5.0
|
|
34
|
-
# via pytest
|
|
35
|
-
pre-commit==4.0.1
|
|
36
|
-
# via hdx-python-database (pyproject.toml)
|
|
37
|
-
psycopg==3.2.3
|
|
38
|
-
# via hdx-python-database (pyproject.toml)
|
|
39
|
-
psycopg-binary==3.2.3
|
|
40
|
-
# via psycopg
|
|
41
|
-
pycparser==2.22
|
|
42
|
-
# via cffi
|
|
43
|
-
pynacl==1.5.0
|
|
44
|
-
# via paramiko
|
|
45
|
-
pytest==8.3.3
|
|
46
|
-
# via
|
|
47
|
-
# hdx-python-database (pyproject.toml)
|
|
48
|
-
# pytest-cov
|
|
49
|
-
pytest-cov==5.0.0
|
|
50
|
-
# via hdx-python-database (pyproject.toml)
|
|
51
|
-
pyyaml==6.0.2
|
|
52
|
-
# via pre-commit
|
|
53
|
-
sqlalchemy==2.0.35
|
|
54
|
-
# via hdx-python-database (pyproject.toml)
|
|
55
|
-
sshtunnel==0.4.0
|
|
56
|
-
# via hdx-python-database (pyproject.toml)
|
|
57
|
-
typing-extensions==4.12.2
|
|
58
|
-
# via
|
|
59
|
-
# psycopg
|
|
60
|
-
# sqlalchemy
|
|
61
|
-
virtualenv==20.26.6
|
|
62
|
-
# via pre-commit
|
|
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
|
{hdx_python_database-1.3.4 → hdx_python_database-1.3.6}/tests/hdx/database/test_postgresql.py
RENAMED
|
File without changes
|
|
File without changes
|