hdx-python-database 1.2.1__py2.py3-none-any.whl → 1.2.2__py2.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/__init__.py +25 -14
- hdx/database/_version.py +2 -2
- hdx/database/no_timezone.py +40 -0
- hdx/database/postgresql.py +1 -1
- {hdx_python_database-1.2.1.dist-info → hdx_python_database-1.2.2.dist-info}/METADATA +1 -1
- hdx_python_database-1.2.2.dist-info/RECORD +11 -0
- hdx_python_database-1.2.1.dist-info/RECORD +0 -10
- {hdx_python_database-1.2.1.dist-info → hdx_python_database-1.2.2.dist-info}/LICENSE +0 -0
- {hdx_python_database-1.2.1.dist-info → hdx_python_database-1.2.2.dist-info}/WHEEL +0 -0
- {hdx_python_database-1.2.1.dist-info → hdx_python_database-1.2.2.dist-info}/top_level.txt +0 -0
- {hdx_python_database-1.2.1.dist-info → hdx_python_database-1.2.2.dist-info}/zip-safe +0 -0
hdx/database/__init__.py
CHANGED
|
@@ -3,30 +3,32 @@ from .dburi import get_connection_uri
|
|
|
3
3
|
|
|
4
4
|
"""Database utilities"""
|
|
5
5
|
import logging
|
|
6
|
-
from typing import Any, Optional, Union
|
|
6
|
+
from typing import Any, Optional, Type, Union
|
|
7
7
|
|
|
8
8
|
from sqlalchemy import create_engine
|
|
9
|
-
from sqlalchemy.ext.declarative import
|
|
10
|
-
from sqlalchemy.orm import Session, sessionmaker
|
|
9
|
+
from sqlalchemy.ext.declarative import declared_attr
|
|
10
|
+
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
|
|
11
11
|
from sqlalchemy.pool import NullPool
|
|
12
12
|
from sshtunnel import SSHTunnelForwarder
|
|
13
13
|
|
|
14
|
-
from
|
|
14
|
+
from .no_timezone import Base as NoTZBase
|
|
15
|
+
from .postgresql import wait_for_postgresql
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
class
|
|
20
|
+
class Base(DeclarativeBase):
|
|
20
21
|
@declared_attr.directive
|
|
21
22
|
def __tablename__(cls):
|
|
22
23
|
return f"{cls.__name__.lower()}s"
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
Base = declarative_base(cls=HDXBase)
|
|
26
|
-
|
|
27
|
-
|
|
28
26
|
class Database:
|
|
29
|
-
"""Database helper class to handle ssh tunnels, waiting for PostgreSQL to
|
|
27
|
+
"""Database helper class to handle ssh tunnels, waiting for PostgreSQL to
|
|
28
|
+
be up etc. Can be used in a with statement returning a Session object.
|
|
29
|
+
db_has_tz which defaults to False indicates whether database datetime
|
|
30
|
+
columns have timezones. If not, conversion occurs between Python datetimes
|
|
31
|
+
with timezones to timezoneless database columns.
|
|
30
32
|
|
|
31
33
|
Args:
|
|
32
34
|
database (Optional[str]): Database name
|
|
@@ -36,6 +38,7 @@ class Database:
|
|
|
36
38
|
password (Optional[str]): Password to log into database
|
|
37
39
|
dialect (str): Database dialect. Defaults to "postgresql".
|
|
38
40
|
driver (Optional[str]): Database driver. Defaults to None (psycopg if postgresql or None)
|
|
41
|
+
db_has_tz (bool): True if db datetime columns have timezone. Defaults to False.
|
|
39
42
|
**kwargs: See below
|
|
40
43
|
ssh_host (str): SSH host (the server to connect to)
|
|
41
44
|
ssh_port (int): SSH port. Defaults to 22.
|
|
@@ -55,6 +58,7 @@ class Database:
|
|
|
55
58
|
password: Optional[str] = None,
|
|
56
59
|
dialect: str = "postgresql",
|
|
57
60
|
driver: Optional[str] = None,
|
|
61
|
+
db_has_tz: bool = False,
|
|
58
62
|
**kwargs: Any,
|
|
59
63
|
) -> None:
|
|
60
64
|
if port is not None:
|
|
@@ -89,7 +93,11 @@ class Database:
|
|
|
89
93
|
)
|
|
90
94
|
if dialect == "postgresql":
|
|
91
95
|
wait_for_postgresql(db_uri)
|
|
92
|
-
|
|
96
|
+
if db_has_tz:
|
|
97
|
+
table_base = Base
|
|
98
|
+
else:
|
|
99
|
+
table_base = NoTZBase
|
|
100
|
+
self.session = self.get_session(db_uri, table_base=table_base)
|
|
93
101
|
|
|
94
102
|
def __enter__(self) -> Session:
|
|
95
103
|
return self.session
|
|
@@ -100,17 +108,20 @@ class Database:
|
|
|
100
108
|
self.server.stop()
|
|
101
109
|
|
|
102
110
|
@staticmethod
|
|
103
|
-
def get_session(
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
def get_session(
|
|
112
|
+
db_uri: str, table_base: Type[DeclarativeBase] = NoTZBase
|
|
113
|
+
) -> Session:
|
|
114
|
+
"""Gets SQLAlchemy session given url. Tables must inherit from Base in
|
|
115
|
+
hdx.utilities.database unless base is defined.
|
|
106
116
|
|
|
107
117
|
Args:
|
|
108
118
|
db_uri (str): Connection URI
|
|
119
|
+
table_base (Type[DeclarativeBase]): Base database table class. Defaults to NoTZBase.
|
|
109
120
|
|
|
110
121
|
Returns:
|
|
111
122
|
sqlalchemy.orm.Session: SQLAlchemy session
|
|
112
123
|
"""
|
|
113
124
|
engine = create_engine(db_uri, poolclass=NullPool, echo=False)
|
|
114
125
|
Session = sessionmaker(bind=engine)
|
|
115
|
-
|
|
126
|
+
table_base.metadata.create_all(engine)
|
|
116
127
|
return Session()
|
hdx/database/_version.py
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Utilities for database datetime columns without timezone"""
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import DateTime, TypeDecorator
|
|
6
|
+
from sqlalchemy.orm import DeclarativeBase, declared_attr
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConversionNoTZ(TypeDecorator):
|
|
10
|
+
"""Convert from/to datetime with timezone from database columns that don't
|
|
11
|
+
use timezone"""
|
|
12
|
+
|
|
13
|
+
impl = DateTime
|
|
14
|
+
cache_ok = True
|
|
15
|
+
|
|
16
|
+
def process_bind_param(self, value: Optional[datetime], _):
|
|
17
|
+
if value is None:
|
|
18
|
+
return value
|
|
19
|
+
if value.tzinfo:
|
|
20
|
+
value = value.astimezone(timezone.utc)
|
|
21
|
+
|
|
22
|
+
return value.replace(tzinfo=None)
|
|
23
|
+
|
|
24
|
+
def process_result_value(self, value, _):
|
|
25
|
+
if value is None:
|
|
26
|
+
return value
|
|
27
|
+
if value.tzinfo is None:
|
|
28
|
+
return value.replace(tzinfo=timezone.utc)
|
|
29
|
+
|
|
30
|
+
return value.astimezone(timezone.utc)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Base(DeclarativeBase):
|
|
34
|
+
type_annotation_map = {
|
|
35
|
+
datetime: ConversionNoTZ,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@declared_attr.directive
|
|
39
|
+
def __tablename__(cls):
|
|
40
|
+
return f"{cls.__name__.lower()}s"
|
hdx/database/postgresql.py
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
hdx/database/__init__.py,sha256=HPKyvzWk-Gqd63sE3kcoyEO9n5h_9l3IeuzhzFnMWfQ,4458
|
|
2
|
+
hdx/database/_version.py,sha256=O2qpyKb1ilx0S5H2I5jnx1k8SSt3R0rHyv19gH5I8Ws,160
|
|
3
|
+
hdx/database/dburi.py,sha256=hNksrjaCC7AtD_M5ef0DCjkS0rJCofQqdXVD2BHBIGc,2938
|
|
4
|
+
hdx/database/no_timezone.py,sha256=7Gnidmu317AWAWx4aPY4oIWBio9dqqSsiUTndEi5hMY,1082
|
|
5
|
+
hdx/database/postgresql.py,sha256=9VlcdHhBURZPDaazj1kEq8gA4hUFJY-5hIN9uzibOlM,969
|
|
6
|
+
hdx_python_database-1.2.2.dist-info/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
|
|
7
|
+
hdx_python_database-1.2.2.dist-info/METADATA,sha256=ykW44dWeZ6DVkzUerqYbitQNoJE5WiBOkhBZXo3Rtzg,2464
|
|
8
|
+
hdx_python_database-1.2.2.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
|
9
|
+
hdx_python_database-1.2.2.dist-info/top_level.txt,sha256=cfo3TyDjnu-B1jb_itPPFQCH00c5VT5GuZ30eNrGmlI,4
|
|
10
|
+
hdx_python_database-1.2.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
11
|
+
hdx_python_database-1.2.2.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
hdx/database/__init__.py,sha256=OcQxMp3lTyDyw_nwI_du5rz_MfJNizVe7mY815ZI-24,3753
|
|
2
|
-
hdx/database/_version.py,sha256=osFGs6qmlEth0Xu2MHIHoChfXcj8NUW4hLWDEu-1_K4,160
|
|
3
|
-
hdx/database/dburi.py,sha256=hNksrjaCC7AtD_M5ef0DCjkS0rJCofQqdXVD2BHBIGc,2938
|
|
4
|
-
hdx/database/postgresql.py,sha256=mV31vmWCa8Dnqz_82zVkB8x021_HBNbz1rkFzFoKQh0,981
|
|
5
|
-
hdx_python_database-1.2.1.dist-info/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
|
|
6
|
-
hdx_python_database-1.2.1.dist-info/METADATA,sha256=oRowXwXZgOMa5MDNdFtqRVUoQ_1Ob-tQBuH_tWJ7w3E,2464
|
|
7
|
-
hdx_python_database-1.2.1.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
|
8
|
-
hdx_python_database-1.2.1.dist-info/top_level.txt,sha256=cfo3TyDjnu-B1jb_itPPFQCH00c5VT5GuZ30eNrGmlI,4
|
|
9
|
-
hdx_python_database-1.2.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
10
|
-
hdx_python_database-1.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|