hdx-python-database 1.3.7__py3-none-any.whl → 1.3.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hdx/database/_version.py CHANGED
@@ -1,21 +1,24 @@
1
- # file generated by setuptools-scm
1
+ # file generated by vcs-versioning
2
2
  # don't change, don't track in version control
3
+ from __future__ import annotations
3
4
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
-
6
- TYPE_CHECKING = False
7
- if TYPE_CHECKING:
8
- from typing import Tuple
9
- from typing import Union
10
-
11
- VERSION_TUPLE = Tuple[Union[int, str], ...]
12
- else:
13
- VERSION_TUPLE = object
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
14
13
 
15
14
  version: str
16
15
  __version__: str
17
- __version_tuple__: VERSION_TUPLE
18
- version_tuple: VERSION_TUPLE
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '1.3.9'
22
+ __version_tuple__ = version_tuple = (1, 3, 9)
19
23
 
20
- __version__ = version = '1.3.7'
21
- __version_tuple__ = version_tuple = (1, 3, 7)
24
+ __commit_id__ = commit_id = None
hdx/database/database.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Database utilities"""
2
2
 
3
3
  import logging
4
- from typing import Any, Dict, List, Optional, Tuple, Type, Union
4
+ from typing import Any
5
5
 
6
6
  from sqlalchemy import Engine, TableClause, create_engine, insert
7
7
  from sqlalchemy.exc import SQLAlchemyError
@@ -64,7 +64,7 @@ class Database:
64
64
  table_base (Optional[Type[DeclarativeBase]]): Override table base. Defaults to None.
65
65
  reflect (bool): Whether to reflect existing tables. Defaults to False.
66
66
  **kwargs: See below
67
- pg_restore_file (str): Restore database from pg_restore file
67
+ pg_restore_file (Path | str): Restore database from pg_restore file
68
68
  recreate_schema (bool): Whether to recreate schema
69
69
  schema_name (str): Database schema name. Defaults to "public".
70
70
  prepare_fn (Callable[[], None]]): Function to call before Base.metadata.create_all.
@@ -79,17 +79,17 @@ class Database:
79
79
 
80
80
  def __init__(
81
81
  self,
82
- engine: Optional[Engine] = None,
83
- db_uri: Optional[str] = None,
84
- database: Optional[str] = None,
85
- host: Optional[str] = None,
86
- port: Union[int, str, None] = None,
87
- username: Optional[str] = None,
88
- password: Optional[str] = None,
82
+ engine: Engine | None = None,
83
+ db_uri: str | None = None,
84
+ database: str | None = None,
85
+ host: str | None = None,
86
+ port: int | str | None = None,
87
+ username: str | None = None,
88
+ password: str | None = None,
89
89
  dialect: str = "postgresql",
90
- driver: Optional[str] = None,
90
+ driver: str | None = None,
91
91
  db_has_tz: bool = False,
92
- table_base: Optional[Type[DeclarativeBase]] = None,
92
+ table_base: type[DeclarativeBase] | None = None,
93
93
  reflect: bool = False,
94
94
  **kwargs: Any,
95
95
  ) -> None:
@@ -230,8 +230,8 @@ class Database:
230
230
 
231
231
  def batch_populate(
232
232
  self,
233
- rows: List[Dict],
234
- dbtable: Type[DeclarativeBase],
233
+ rows: list[dict],
234
+ dbtable: type[DeclarativeBase],
235
235
  batch_size: int = 1000,
236
236
  ) -> None:
237
237
  """Batch populate database table.
@@ -244,21 +244,19 @@ class Database:
244
244
  Returns:
245
245
  Tuple[Session, Any]: (SQLAlchemy session, base)
246
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)
247
+
248
+ for i in range(0, len(rows), batch_size):
249
+ batch = rows[i : i + batch_size]
250
+ self._session.execute(insert(dbtable), batch)
253
251
  self._session.commit()
254
252
 
255
253
  @staticmethod
256
254
  def create_session(
257
- engine: Optional[Engine] = None,
258
- db_uri: Optional[str] = None,
259
- table_base: Type[DeclarativeBase] = NoTZBase,
255
+ engine: Engine | None = None,
256
+ db_uri: str | None = None,
257
+ table_base: type[DeclarativeBase] = NoTZBase,
260
258
  reflect: bool = False,
261
- ) -> Tuple[Session, Any]:
259
+ ) -> tuple[Session, Any]:
262
260
  """Creates SQLAlchemy session given SQLAlchemy engine or database uri
263
261
  (one of which must be supplied). Tables must inherit from Base in
264
262
  hdx.utilities.database unless base is defined. If reflect is True,
@@ -334,7 +332,7 @@ class Database:
334
332
  return False
335
333
 
336
334
  @staticmethod
337
- def prepare_view(view_params: Dict) -> TableClause:
335
+ def prepare_view(view_params: dict) -> TableClause:
338
336
  """Prepare SQLAlchemy view from dictionary with keys: name, metadata and
339
337
  selectable. Must be run before Base.metadata.create_all.
340
338
 
@@ -347,7 +345,7 @@ class Database:
347
345
  return view(**view_params)
348
346
 
349
347
  @classmethod
350
- def prepare_views(cls, view_params_list: List[Dict]) -> List[TableClause]:
348
+ def prepare_views(cls, view_params_list: list[dict]) -> list[TableClause]:
351
349
  """Prepare SQLAlchemy views from a list of dictionaries with keys: name,
352
350
  metadata and selectable. Must be run before Base.metadata.create_all.
353
351
 
hdx/database/dburi.py CHANGED
@@ -1,13 +1,13 @@
1
1
  """Connection URI utilities"""
2
2
 
3
- from typing import Any, Dict, Optional, Union
3
+ from typing import Any
4
4
  from urllib.parse import urlsplit
5
5
 
6
6
 
7
7
  def get_params_from_connection_uri(
8
8
  db_uri: str,
9
9
  include_driver: bool = True,
10
- ) -> Dict[str, Any]:
10
+ ) -> dict[str, Any]:
11
11
  """Gets PostgreSQL database connection parameters from connection URI
12
12
 
13
13
  Args:
@@ -38,13 +38,13 @@ def get_params_from_connection_uri(
38
38
 
39
39
 
40
40
  def get_connection_uri(
41
- database: Optional[str] = None,
42
- host: Optional[str] = None,
43
- port: Union[int, str, None] = None,
44
- username: Optional[str] = None,
45
- password: Optional[str] = None,
41
+ database: str | None = None,
42
+ host: str | None = None,
43
+ port: int | str | None = None,
44
+ username: str | None = None,
45
+ password: str | None = None,
46
46
  dialect: str = "postgresql",
47
- driver: Optional[str] = None,
47
+ driver: str | None = None,
48
48
  include_driver: bool = True,
49
49
  ) -> str:
50
50
  """Gets connection uri from database connection parameters
@@ -1,7 +1,6 @@
1
1
  """Utilities for database datetime columns without timezone"""
2
2
 
3
3
  from datetime import datetime, timezone
4
- from typing import Optional
5
4
 
6
5
  from sqlalchemy import DateTime, TypeDecorator
7
6
  from sqlalchemy.orm import DeclarativeBase, declared_attr
@@ -16,7 +15,7 @@ class ConversionNoTZ(TypeDecorator):
16
15
  impl = DateTime
17
16
  cache_ok = True
18
17
 
19
- def process_bind_param(self, value: Optional[datetime], _):
18
+ def process_bind_param(self, value: datetime | None, _):
20
19
  if value is None:
21
20
  return value
22
21
  if value.tzinfo:
@@ -4,6 +4,7 @@ import logging
4
4
  import subprocess
5
5
  import time
6
6
  from os import environ
7
+ from pathlib import Path
7
8
 
8
9
  from .dburi import get_params_from_connection_uri, remove_driver_from_uri
9
10
 
@@ -47,19 +48,20 @@ def wait_for_postgresql(db_uri: str) -> None:
47
48
  time.sleep(1)
48
49
 
49
50
 
50
- def restore_from_pgfile(db_uri: str, pg_restore_file: str) -> str:
51
+ def restore_from_pgfile(db_uri: str, pg_restore_file: Path | str) -> str:
51
52
  """Restore database from a pg_restore file created by pg_backup using the
52
53
  pg_restore command.
53
54
 
54
55
  Args:
55
56
  db_uri (str): Connection URI
56
- pg_restore_file (str): Path to the pg_restore database file
57
+ pg_restore_file (Path | str): Path to the pg_restore database file
57
58
 
58
59
  Returns:
59
60
  str: Output from the pg_restore command
60
61
  """
62
+ pg_restore_file = Path(pg_restore_file)
61
63
  db_params = get_params_from_connection_uri(db_uri)
62
- if pg_restore_file[-3:] == ".xz":
64
+ if pg_restore_file.suffix == ".xz":
63
65
  decompress = subprocess.Popen(
64
66
  ("unxz", "-c", "-d", pg_restore_file), stdout=subprocess.PIPE
65
67
  ).stdout
@@ -81,7 +83,7 @@ def restore_from_pgfile(db_uri: str, pg_restore_file: str) -> str:
81
83
  subprocess_params.append(f"{value}")
82
84
 
83
85
  if not decompress:
84
- subprocess_params.append(pg_restore_file)
86
+ subprocess_params.append(str(pg_restore_file))
85
87
  env = environ.copy()
86
88
  password = db_params.get("password")
87
89
  if password:
hdx/database/views.py CHANGED
@@ -24,15 +24,12 @@ class DropView(DDLElement):
24
24
 
25
25
  @compiler.compiles(CreateView)
26
26
  def _create_view(element, compiler, **kw):
27
- return "CREATE VIEW %s AS %s" % (
28
- element.name,
29
- compiler.sql_compiler.process(element.selectable, literal_binds=True),
30
- )
27
+ return f"CREATE VIEW {element.name} AS {compiler.sql_compiler.process(element.selectable, literal_binds=True)}"
31
28
 
32
29
 
33
30
  @compiler.compiles(DropView)
34
31
  def _drop_view(element, compiler, **kw):
35
- return "DROP VIEW %s" % (element.name)
32
+ return f"DROP VIEW {element.name}"
36
33
 
37
34
 
38
35
  def view_exists(ddl, target, connection, **kw):
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hdx-python-database
3
- Version: 1.3.7
3
+ Version: 1.3.9
4
4
  Summary: HDX Python database utilities
5
5
  Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-database
6
- Author-email: Michael Rans <rans@email.com>
6
+ Author-email: Michael Rans <rans@un.org>
7
7
  License: MIT
8
8
  License-File: LICENSE
9
9
  Keywords: HDX,database,postgresql
@@ -16,29 +16,15 @@ Classifier: Operating System :: Microsoft :: Windows
16
16
  Classifier: Operating System :: POSIX :: Linux
17
17
  Classifier: Operating System :: Unix
18
18
  Classifier: Programming Language :: Python
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3 :: Only
21
- Classifier: Programming Language :: Python :: 3.8
22
- Classifier: Programming Language :: Python :: 3.9
23
- Classifier: Programming Language :: Python :: 3.10
24
- Classifier: Programming Language :: Python :: 3.11
25
- Classifier: Programming Language :: Python :: 3.12
26
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
20
  Requires-Python: >=3.10
28
21
  Requires-Dist: sqlalchemy>=2
29
- Provides-Extra: dev
30
- Requires-Dist: pre-commit; extra == 'dev'
31
22
  Provides-Extra: docs
32
23
  Requires-Dist: mkapi; extra == 'docs'
33
24
  Provides-Extra: postgresql
34
25
  Requires-Dist: psycopg[binary]; extra == 'postgresql'
35
26
  Provides-Extra: sshtunnel
36
27
  Requires-Dist: sshtunnel; extra == 'sshtunnel'
37
- Provides-Extra: test
38
- Requires-Dist: psycopg[binary]; extra == 'test'
39
- Requires-Dist: pytest; extra == 'test'
40
- Requires-Dist: pytest-cov; extra == 'test'
41
- Requires-Dist: sshtunnel; extra == 'test'
42
28
  Description-Content-Type: text/markdown
43
29
 
44
30
  [![Build Status](https://github.com/OCHA-DAP/hdx-python-database/actions/workflows/run-python-tests.yaml/badge.svg)](https://github.com/OCHA-DAP/hdx-python-database/actions/workflows/run-python-tests.yaml)
@@ -53,3 +39,78 @@ For more information, please read the [documentation](https://hdx-python-databas
53
39
 
54
40
  This library is part of the [Humanitarian Data Exchange](https://data.humdata.org/) (HDX) project. If you have
55
41
  humanitarian related data, please upload your datasets to HDX.
42
+
43
+ # Development
44
+
45
+ ## Environment
46
+
47
+ Development is currently done using Python 3.13. The environment can be created with:
48
+
49
+ ```shell
50
+ uv sync
51
+ ```
52
+
53
+ This creates a .venv folder with the versions specified in the project's uv.lock file.
54
+
55
+ ### Pre-commit
56
+
57
+ pre-commit will be installed when syncing uv. It is run every time you make a git
58
+ commit if you call it like this:
59
+
60
+ ```shell
61
+ pre-commit install
62
+ ```
63
+
64
+ With pre-commit, all code is formatted according to
65
+ [ruff](https://docs.astral.sh/ruff/) guidelines.
66
+
67
+ To check if your changes pass pre-commit without committing, run:
68
+
69
+ ```shell
70
+ pre-commit run --all-files
71
+ ```
72
+
73
+ ## Packages
74
+
75
+ [uv](https://github.com/astral-sh/uv) is used for package management. If
76
+ you've introduced a new package to the source code (i.e. anywhere in `src/`),
77
+ please add it to the `project.dependencies` section of `pyproject.toml` with
78
+ any known version constraints.
79
+
80
+ To add packages required only for testing, add them to the
81
+ `[dependency-groups]`.
82
+
83
+ Any changes to the dependencies will be automatically reflected in
84
+ `uv.lock` with `pre-commit`, but you can re-generate the files without committing by
85
+ executing:
86
+
87
+ ```shell
88
+ uv lock --upgrade
89
+ ```
90
+
91
+ ## Project
92
+
93
+ [uv](https://github.com/astral-sh/uv) is used for project management. The project can be
94
+ built using:
95
+
96
+ ```shell
97
+ uv build
98
+ ```
99
+
100
+ Linting and syntax checking can be run with:
101
+
102
+ ```shell
103
+ uv run ruff check
104
+ ```
105
+
106
+ To run the tests and view coverage, execute:
107
+
108
+ ```shell
109
+ uv run pytest
110
+ ```
111
+
112
+ ## Documentation
113
+
114
+ The documentation, including API documentation, is generated using ReadtheDocs and
115
+ MkDocs with Material. As you change the source code, remember to update the
116
+ documentation at `documentation/index.md`.
@@ -0,0 +1,13 @@
1
+ hdx/database/__init__.py,sha256=sG2OYV5LHskgiDkB4IeVeQyPHL22Ta1kuxf-xN92-5E,155
2
+ hdx/database/_version.py,sha256=g62BHujLgGdP6cB1oucUZ89PYnKUKXkd5IR17viSOVM,520
3
+ hdx/database/database.py,sha256=ZjI8roQM0x56RlywG5xLIVZ4pVqVqiREilbTfzYxwNU,12856
4
+ hdx/database/dburi.py,sha256=Kkg9eyS0Dia63vTTWPu4K1nqhn9igpZYMw-66wPn2ZU,2934
5
+ hdx/database/no_timezone.py,sha256=WuiSijzzUox6mpvPMveklA2oqKQcaudr2zz-U78Lq6A,1099
6
+ hdx/database/postgresql.py,sha256=sBvuBQNoT_iJvy3W2lFupDKbx-g25UhlRYv2LlQmpVs,3013
7
+ hdx/database/utils.py,sha256=nzChgDj2_Mq8GS6xWaNmqOgpAiwK9tGYV_skKbErEVA,401
8
+ hdx/database/views.py,sha256=zkRTsD1cE_afJaxdYd72EoUv3qdnqBL-ekYPkv-DeD4,1603
9
+ hdx/database/with_timezone.py,sha256=GUUylmTwQHp22yedmCVKpVJzvjWgdS9lg9KeqciNJkY,235
10
+ hdx_python_database-1.3.9.dist-info/METADATA,sha256=YIP17SHZ_JMjbUlKBYmKmN0LAUI1nPEYgMmmI2XNH0g,3920
11
+ hdx_python_database-1.3.9.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
12
+ hdx_python_database-1.3.9.dist-info/licenses/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
13
+ hdx_python_database-1.3.9.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.29.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,13 +0,0 @@
1
- hdx/database/__init__.py,sha256=sG2OYV5LHskgiDkB4IeVeQyPHL22Ta1kuxf-xN92-5E,155
2
- hdx/database/_version.py,sha256=P4BCutErILqbg7G9_GBs9LhAib9fH-uALXBnLt2OtK8,511
3
- hdx/database/database.py,sha256=1Xn-UYZ_OZquAtNnrimdR0CIgbtx-hQZD0NSAYHitHY,13055
4
- hdx/database/dburi.py,sha256=rw8RuLpU85vxYl5-Zk1SdZRAz-tqre_ot5aEnkjhxAQ,2977
5
- hdx/database/no_timezone.py,sha256=Lw087G3qOf8H70o8Hq_VvOMZ3ANei-lIA_sUlpFU_Uo,1130
6
- hdx/database/postgresql.py,sha256=5xmGFbzjTPTr9clQw4rOD1ZQEzYuY25Ho2hhz-WdCC8,2923
7
- hdx/database/utils.py,sha256=nzChgDj2_Mq8GS6xWaNmqOgpAiwK9tGYV_skKbErEVA,401
8
- hdx/database/views.py,sha256=U4BN9tbjlr93qKkeNbZNo_PCIwGsng09mQ2xFqh5CH0,1636
9
- hdx/database/with_timezone.py,sha256=GUUylmTwQHp22yedmCVKpVJzvjWgdS9lg9KeqciNJkY,235
10
- hdx_python_database-1.3.7.dist-info/METADATA,sha256=Q9bf8Jl8u0cEVVqTM-Pv7KschLbWaUPpINPBVeWHA1Y,2841
11
- hdx_python_database-1.3.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
- hdx_python_database-1.3.7.dist-info/licenses/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
13
- hdx_python_database-1.3.7.dist-info/RECORD,,