dsw-database 4.13.0__py2.py3-none-any.whl → 4.15.0__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.
@@ -9,9 +9,9 @@ BuildInfo = namedtuple(
9
9
  )
10
10
 
11
11
  BUILD_INFO = BuildInfo(
12
- version='v4.13.0~c8e1cb3',
13
- built_at='2024-12-05 08:07:12Z',
14
- sha='c8e1cb3b7e0cc93bdf509eef715cd0a926d907c3',
12
+ version='v4.15.0~0624f1a',
13
+ built_at='2025-02-04 15:03:58Z',
14
+ sha='0624f1af3f4ccd0fa38ec76a640b17ef405ab153',
15
15
  branch='HEAD',
16
- tag='v4.13.0',
16
+ tag='v4.15.0',
17
17
  )
dsw/database/database.py CHANGED
@@ -1,13 +1,13 @@
1
1
  import datetime
2
2
  import logging
3
+ import typing
4
+
3
5
  import psycopg
4
6
  import psycopg.conninfo
5
7
  import psycopg.rows
6
8
  import psycopg.types.json
7
9
  import tenacity
8
10
 
9
- from typing import List, Iterable, Optional
10
-
11
11
  from dsw.config.model import DatabaseConfig
12
12
 
13
13
  from .model import DBDocumentTemplate, DBDocumentTemplateFile, \
@@ -28,44 +28,56 @@ def wrap_json_data(data: dict):
28
28
  return psycopg.types.json.Json(data)
29
29
 
30
30
 
31
+ # pylint: disable-next=too-many-public-methods
31
32
  class Database:
32
33
 
33
- # TODO: refactor queries and models
34
- SELECT_DOCUMENT = 'SELECT * FROM document WHERE uuid = %s AND tenant_uuid = %s LIMIT 1;'
35
- SELECT_QTN_DOCUMENTS = 'SELECT * FROM document WHERE questionnaire_uuid = %s AND tenant_uuid = %s;'
36
- SELECT_DOCUMENT_SUBMISSIONS = 'SELECT * FROM submission WHERE document_uuid = %s AND tenant_uuid = %s;'
37
- SELECT_QTN_SUBMISSIONS = 'SELECT s.* FROM document d JOIN submission s ON d.uuid = s.document_uuid ' \
38
- 'WHERE d.questionnaire_uuid = %s AND d.tenant_uuid = %s;'
39
- SELECT_QTN_SIMPLE = 'SELECT qtn.* FROM questionnaire qtn ' \
40
- 'WHERE qtn.uuid = %s AND qtn.tenant_uuid = %s;'
41
- SELECT_TENANT_CONFIG = 'SELECT * FROM tenant_config WHERE uuid = %(tenant_uuid)s LIMIT 1;'
42
- SELECT_TENANT_LIMIT = 'SELECT uuid, storage FROM tenant_limit_bundle WHERE uuid = %(tenant_uuid)s LIMIT 1;'
34
+ SELECT_DOCUMENT = ('SELECT * FROM document '
35
+ 'WHERE uuid = %s AND tenant_uuid = %s LIMIT 1;')
36
+ SELECT_QTN_DOCUMENTS = ('SELECT * FROM document '
37
+ 'WHERE questionnaire_uuid = %s AND tenant_uuid = %s;')
38
+ SELECT_DOCUMENT_SUBMISSIONS = ('SELECT * FROM submission '
39
+ 'WHERE document_uuid = %s AND tenant_uuid = %s;')
40
+ SELECT_QTN_SUBMISSIONS = ('SELECT s.* '
41
+ 'FROM document d JOIN submission s ON d.uuid = s.document_uuid '
42
+ 'WHERE d.questionnaire_uuid = %s AND d.tenant_uuid = %s;')
43
+ SELECT_QTN_SIMPLE = ('SELECT qtn.* FROM questionnaire qtn '
44
+ 'WHERE qtn.uuid = %s AND qtn.tenant_uuid = %s;')
45
+ SELECT_TENANT_CONFIG = ('SELECT * FROM tenant_config '
46
+ 'WHERE uuid = %(tenant_uuid)s LIMIT 1;')
47
+ SELECT_TENANT_LIMIT = ('SELECT uuid, storage FROM tenant_limit_bundle '
48
+ 'WHERE uuid = %(tenant_uuid)s LIMIT 1;')
43
49
  UPDATE_DOCUMENT_STATE = 'UPDATE document SET state = %s, worker_log = %s WHERE uuid = %s;'
44
50
  UPDATE_DOCUMENT_RETRIEVED = 'UPDATE document SET retrieved_at = %s, state = %s WHERE uuid = %s;'
45
- UPDATE_DOCUMENT_FINISHED = 'UPDATE document SET finished_at = %s, state = %s, ' \
46
- 'file_name = %s, content_type = %s, worker_log = %s, ' \
47
- 'file_size = %s WHERE uuid = %s;'
48
- SELECT_TEMPLATE = 'SELECT * FROM document_template WHERE id = %s AND tenant_uuid = %s LIMIT 1;'
49
- SELECT_TEMPLATE_FILES = 'SELECT * FROM document_template_file ' \
50
- 'WHERE document_template_id = %s AND tenant_uuid = %s;'
51
- SELECT_TEMPLATE_ASSETS = 'SELECT * FROM document_template_asset ' \
52
- 'WHERE document_template_id = %s AND tenant_uuid = %s;'
53
- CHECK_TABLE_EXISTS = 'SELECT EXISTS(SELECT * FROM information_schema.tables' \
54
- ' WHERE table_name = %(table_name)s)'
55
- SELECT_MAIL_CONFIG = 'SELECT icm.* ' \
56
- 'FROM tenant_config tc JOIN instance_config_mail icm ' \
57
- 'ON tc.mail_config_uuid = icm.uuid ' \
58
- 'WHERE tc.uuid = %(tenant_uuid)s;'
59
- UPDATE_COMPONENT_INFO = 'INSERT INTO component (name, version, built_at, created_at, updated_at) ' \
60
- 'VALUES (%(name)s, %(version)s, %(built_at)s, %(created_at)s, %(updated_at)s)' \
61
- 'ON CONFLICT (name) DO ' \
62
- 'UPDATE SET version = %(version)s, built_at = %(built_at)s, updated_at = %(updated_at)s;'
51
+ UPDATE_DOCUMENT_FINISHED = ('UPDATE document SET finished_at = %s, state = %s, '
52
+ 'file_name = %s, content_type = %s, worker_log = %s, '
53
+ 'file_size = %s WHERE uuid = %s;')
54
+ SELECT_TEMPLATE = ('SELECT * FROM document_template '
55
+ 'WHERE id = %s AND tenant_uuid = %s LIMIT 1;')
56
+ SELECT_TEMPLATE_FILES = ('SELECT * FROM document_template_file '
57
+ 'WHERE document_template_id = %s AND tenant_uuid = %s;')
58
+ SELECT_TEMPLATE_ASSETS = ('SELECT * FROM document_template_asset '
59
+ 'WHERE document_template_id = %s AND tenant_uuid = %s;')
60
+ CHECK_TABLE_EXISTS = ('SELECT EXISTS(SELECT * FROM information_schema.tables'
61
+ ' WHERE table_name = %(table_name)s)')
62
+ SELECT_MAIL_CONFIG = ('SELECT icm.* '
63
+ 'FROM tenant_config tc JOIN instance_config_mail icm '
64
+ 'ON tc.mail_config_uuid = icm.uuid '
65
+ 'WHERE tc.uuid = %(tenant_uuid)s;')
66
+ UPDATE_COMPONENT_INFO = ('INSERT INTO component '
67
+ '(name, version, built_at, created_at, updated_at) '
68
+ 'VALUES (%(name)s, %(version)s, %(built_at)s, '
69
+ '%(created_at)s, %(updated_at)s)'
70
+ 'ON CONFLICT (name) DO '
71
+ 'UPDATE SET version = %(version)s, built_at = %(built_at)s, '
72
+ 'updated_at = %(updated_at)s;')
63
73
  SELECT_COMPONENT_INFO = 'SELECT * FROM component WHERE name = %(name)s;'
64
- SUM_FILE_SIZES = 'SELECT (SELECT COALESCE(SUM(file_size)::bigint, 0) ' \
65
- 'FROM document WHERE tenant_uuid = %(tenant_uuid)s) ' \
66
- '+ (SELECT COALESCE(SUM(file_size)::bigint, 0) ' \
67
- 'FROM document_template_asset WHERE tenant_uuid = %(tenant_uuid)s) ' \
68
- 'as result;'
74
+ SUM_FILE_SIZES = ('SELECT (SELECT COALESCE(SUM(file_size)::bigint, 0) '
75
+ 'FROM document WHERE tenant_uuid = %(tenant_uuid)s) '
76
+ '+ (SELECT COALESCE(SUM(file_size)::bigint, 0) '
77
+ 'FROM document_template_asset WHERE tenant_uuid = %(tenant_uuid)s) '
78
+ '+ (SELECT COALESCE(SUM(file_size)::bigint, 0) '
79
+ 'FROM questionnaire_file WHERE tenant_uuid = %(tenant_uuid)s) '
80
+ 'AS result;')
69
81
 
70
82
  def __init__(self, cfg: DatabaseConfig, connect: bool = True,
71
83
  with_queue: bool = True):
@@ -121,7 +133,7 @@ class Database:
121
133
  before=tenacity.before_log(LOG, logging.DEBUG),
122
134
  after=tenacity.after_log(LOG, logging.DEBUG),
123
135
  )
124
- def fetch_document(self, document_uuid: str, tenant_uuid: str) -> Optional[DBDocument]:
136
+ def fetch_document(self, document_uuid: str, tenant_uuid: str) -> DBDocument | None:
125
137
  with self.conn_query.new_cursor(use_dict=True) as cursor:
126
138
  cursor.execute(
127
139
  query=self.SELECT_DOCUMENT,
@@ -139,7 +151,7 @@ class Database:
139
151
  before=tenacity.before_log(LOG, logging.DEBUG),
140
152
  after=tenacity.after_log(LOG, logging.DEBUG),
141
153
  )
142
- def fetch_tenant_config(self, tenant_uuid: str) -> Optional[DBTenantConfig]:
154
+ def fetch_tenant_config(self, tenant_uuid: str) -> DBTenantConfig | None:
143
155
  return self.get_tenant_config(tenant_uuid)
144
156
 
145
157
  @tenacity.retry(
@@ -149,7 +161,7 @@ class Database:
149
161
  before=tenacity.before_log(LOG, logging.DEBUG),
150
162
  after=tenacity.after_log(LOG, logging.DEBUG),
151
163
  )
152
- def fetch_tenant_limits(self, tenant_uuid: str) -> Optional[DBTenantLimits]:
164
+ def fetch_tenant_limits(self, tenant_uuid: str) -> DBTenantLimits | None:
153
165
  with self.conn_query.new_cursor(use_dict=True) as cursor:
154
166
  cursor.execute(
155
167
  query=self.SELECT_TENANT_LIMIT,
@@ -169,7 +181,7 @@ class Database:
169
181
  )
170
182
  def fetch_template(
171
183
  self, template_id: str, tenant_uuid: str
172
- ) -> Optional[DBDocumentTemplate]:
184
+ ) -> DBDocumentTemplate | None:
173
185
  with self.conn_query.new_cursor(use_dict=True) as cursor:
174
186
  cursor.execute(
175
187
  query=self.SELECT_TEMPLATE,
@@ -189,7 +201,7 @@ class Database:
189
201
  )
190
202
  def fetch_template_files(
191
203
  self, template_id: str, tenant_uuid: str
192
- ) -> List[DBDocumentTemplateFile]:
204
+ ) -> list[DBDocumentTemplateFile]:
193
205
  with self.conn_query.new_cursor(use_dict=True) as cursor:
194
206
  cursor.execute(
195
207
  query=self.SELECT_TEMPLATE_FILES,
@@ -206,7 +218,7 @@ class Database:
206
218
  )
207
219
  def fetch_template_assets(
208
220
  self, template_id: str, tenant_uuid: str
209
- ) -> List[DBDocumentTemplateAsset]:
221
+ ) -> list[DBDocumentTemplateAsset]:
210
222
  with self.conn_query.new_cursor(use_dict=True) as cursor:
211
223
  cursor.execute(
212
224
  query=self.SELECT_TEMPLATE_ASSETS,
@@ -221,7 +233,8 @@ class Database:
221
233
  before=tenacity.before_log(LOG, logging.DEBUG),
222
234
  after=tenacity.after_log(LOG, logging.DEBUG),
223
235
  )
224
- def fetch_qtn_documents(self, questionnaire_uuid: str, tenant_uuid: str) -> List[DBDocument]:
236
+ def fetch_qtn_documents(self, questionnaire_uuid: str,
237
+ tenant_uuid: str) -> list[DBDocument]:
225
238
  with self.conn_query.new_cursor(use_dict=True) as cursor:
226
239
  cursor.execute(
227
240
  query=self.SELECT_QTN_DOCUMENTS,
@@ -236,7 +249,8 @@ class Database:
236
249
  before=tenacity.before_log(LOG, logging.DEBUG),
237
250
  after=tenacity.after_log(LOG, logging.DEBUG),
238
251
  )
239
- def fetch_document_submissions(self, document_uuid: str, tenant_uuid: str) -> List[DBSubmission]:
252
+ def fetch_document_submissions(self, document_uuid: str,
253
+ tenant_uuid: str) -> list[DBSubmission]:
240
254
  with self.conn_query.new_cursor(use_dict=True) as cursor:
241
255
  cursor.execute(
242
256
  query=self.SELECT_DOCUMENT_SUBMISSIONS,
@@ -251,7 +265,8 @@ class Database:
251
265
  before=tenacity.before_log(LOG, logging.DEBUG),
252
266
  after=tenacity.after_log(LOG, logging.DEBUG),
253
267
  )
254
- def fetch_questionnaire_submissions(self, questionnaire_uuid: str, tenant_uuid: str) -> List[DBSubmission]:
268
+ def fetch_questionnaire_submissions(self, questionnaire_uuid: str,
269
+ tenant_uuid: str) -> list[DBSubmission]:
255
270
  with self.conn_query.new_cursor(use_dict=True) as cursor:
256
271
  cursor.execute(
257
272
  query=self.SELECT_QTN_SUBMISSIONS,
@@ -266,7 +281,8 @@ class Database:
266
281
  before=tenacity.before_log(LOG, logging.DEBUG),
267
282
  after=tenacity.after_log(LOG, logging.DEBUG),
268
283
  )
269
- def fetch_questionnaire_simple(self, questionnaire_uuid: str, tenant_uuid: str) -> DBQuestionnaireSimple:
284
+ def fetch_questionnaire_simple(self, questionnaire_uuid: str,
285
+ tenant_uuid: str) -> DBQuestionnaireSimple:
270
286
  with self.conn_query.new_cursor(use_dict=True) as cursor:
271
287
  cursor.execute(
272
288
  query=self.SELECT_QTN_SIMPLE,
@@ -303,7 +319,7 @@ class Database:
303
319
  query=self.UPDATE_DOCUMENT_RETRIEVED,
304
320
  params=(
305
321
  retrieved_at,
306
- DocumentState.PROCESSING,
322
+ DocumentState.PROCESSING.value,
307
323
  document_uuid,
308
324
  ),
309
325
  )
@@ -317,7 +333,7 @@ class Database:
317
333
  after=tenacity.after_log(LOG, logging.DEBUG),
318
334
  )
319
335
  def update_document_finished(
320
- self, finished_at: datetime.datetime, file_name: str, file_size: int,
336
+ self, *, finished_at: datetime.datetime, file_name: str, file_size: int,
321
337
  content_type: str, worker_log: str, document_uuid: str
322
338
  ) -> bool:
323
339
  with self.conn_query.new_cursor() as cursor:
@@ -325,7 +341,7 @@ class Database:
325
341
  query=self.UPDATE_DOCUMENT_FINISHED,
326
342
  params=(
327
343
  finished_at,
328
- DocumentState.FINISHED,
344
+ DocumentState.FINISHED.value,
329
345
  file_name,
330
346
  content_type,
331
347
  worker_log,
@@ -358,7 +374,7 @@ class Database:
358
374
  before=tenacity.before_log(LOG, logging.DEBUG),
359
375
  after=tenacity.after_log(LOG, logging.DEBUG),
360
376
  )
361
- def get_tenant_config(self, tenant_uuid: str) -> Optional[DBTenantConfig]:
377
+ def get_tenant_config(self, tenant_uuid: str) -> DBTenantConfig | None:
362
378
  if not self._check_table_exists(table_name='tenant_config'):
363
379
  return None
364
380
  with self.conn_query.new_cursor(use_dict=True) as cursor:
@@ -370,8 +386,8 @@ class Database:
370
386
  result = cursor.fetchone()
371
387
  return DBTenantConfig.from_dict_row(data=result)
372
388
  except Exception as e:
373
- LOG.warning(f'Could not retrieve tenant_config for tenant'
374
- f' "{tenant_uuid}": {str(e)}')
389
+ LOG.warning('Could not retrieve tenant_config for tenant "%s": %s',
390
+ tenant_uuid, str(e))
375
391
  return None
376
392
 
377
393
  @tenacity.retry(
@@ -381,7 +397,7 @@ class Database:
381
397
  before=tenacity.before_log(LOG, logging.DEBUG),
382
398
  after=tenacity.after_log(LOG, logging.DEBUG),
383
399
  )
384
- def get_mail_config(self, tenant_uuid: str) -> Optional[DBInstanceConfigMail]:
400
+ def get_mail_config(self, tenant_uuid: str) -> DBInstanceConfigMail | None:
385
401
  with self.conn_query.new_cursor(use_dict=True) as cursor:
386
402
  if not self._check_table_exists(table_name='instance_config_mail'):
387
403
  return None
@@ -395,8 +411,8 @@ class Database:
395
411
  return None
396
412
  return DBInstanceConfigMail.from_dict_row(data=result)
397
413
  except Exception as e:
398
- LOG.warning(f'Could not retrieve instance_config_mail for tenant'
399
- f' "{tenant_uuid}": {str(e)}')
414
+ LOG.warning('Could not retrieve instance_config_mail for tenant "%s": %s',
415
+ tenant_uuid, str(e))
400
416
  return None
401
417
 
402
418
  @tenacity.retry(
@@ -409,7 +425,7 @@ class Database:
409
425
  def update_component_info(self, name: str, version: str, built_at: datetime.datetime):
410
426
  with self.conn_query.new_cursor(use_dict=True) as cursor:
411
427
  if not self._check_table_exists(table_name='component'):
412
- return None
428
+ return
413
429
  ts_now = datetime.datetime.now(tz=datetime.UTC)
414
430
  try:
415
431
  cursor.execute(
@@ -424,7 +440,7 @@ class Database:
424
440
  )
425
441
  self.conn_query.connection.commit()
426
442
  except Exception as e:
427
- LOG.warning(f'Could not update component info: {str(e)}')
443
+ LOG.warning('Could not update component info: %s', str(e))
428
444
 
429
445
  @tenacity.retry(
430
446
  reraise=True,
@@ -433,7 +449,7 @@ class Database:
433
449
  before=tenacity.before_log(LOG, logging.DEBUG),
434
450
  after=tenacity.after_log(LOG, logging.DEBUG),
435
451
  )
436
- def get_component_info(self, name: str) -> Optional[DBComponent]:
452
+ def get_component_info(self, name: str) -> DBComponent | None:
437
453
  if not self._check_table_exists(table_name='component'):
438
454
  return None
439
455
  with self.conn_query.new_cursor(use_dict=True) as cursor:
@@ -447,7 +463,7 @@ class Database:
447
463
  return None
448
464
  return DBComponent.from_dict_row(data=result)
449
465
  except Exception as e:
450
- LOG.warning(f'Could not get component info: {str(e)}')
466
+ LOG.warning('Could not get component info: %s', str(e))
451
467
  return None
452
468
 
453
469
  @tenacity.retry(
@@ -457,7 +473,7 @@ class Database:
457
473
  before=tenacity.before_log(LOG, logging.DEBUG),
458
474
  after=tenacity.after_log(LOG, logging.DEBUG),
459
475
  )
460
- def execute_queries(self, queries: Iterable[str]):
476
+ def execute_queries(self, queries: typing.Iterable[str]):
461
477
  with self.conn_query.new_cursor(use_dict=True) as cursor:
462
478
  for query in queries:
463
479
  cursor.execute(query=query)
@@ -484,7 +500,7 @@ class PostgresConnection:
484
500
  connect_timeout=timeout,
485
501
  )
486
502
  self.autocommit = autocommit
487
- self._connection = None # type: Optional[psycopg.Connection]
503
+ self._connection: psycopg.Connection | None = None
488
504
 
489
505
  @tenacity.retry(
490
506
  reraise=True,
@@ -494,11 +510,15 @@ class PostgresConnection:
494
510
  after=tenacity.after_log(LOG, logging.DEBUG),
495
511
  )
496
512
  def _connect_db(self):
497
- LOG.info(f'Creating connection to PostgreSQL database "{self.name}"')
513
+ LOG.info('Creating connection to PostgreSQL database "%s"', self.name)
498
514
  try:
499
- connection = psycopg.connect(conninfo=self.dsn, autocommit=self.autocommit) # type: psycopg.Connection
515
+ connection: psycopg.Connection = psycopg.connect(
516
+ conninfo=self.dsn,
517
+ autocommit=self.autocommit,
518
+ )
500
519
  except Exception as e:
501
- LOG.error(f'Failed to connect to PostgreSQL database "{self.name}": {str(e)}')
520
+ LOG.error('Failed to connect to PostgreSQL database "%s": %s',
521
+ self.name, str(e))
502
522
  raise e
503
523
  # test connection
504
524
  cursor = connection.cursor()
@@ -506,7 +526,7 @@ class PostgresConnection:
506
526
  result = cursor.fetchone()
507
527
  if result is None:
508
528
  raise RuntimeError('Failed to verify DB connection')
509
- LOG.debug(f'DB connection verified (result={result[0]})')
529
+ LOG.debug('DB connection verified (result=%s)', result[0])
510
530
  cursor.close()
511
531
  connection.commit()
512
532
  self._connection = connection
@@ -532,6 +552,6 @@ class PostgresConnection:
532
552
 
533
553
  def close(self):
534
554
  if self._connection:
535
- LOG.info(f'Closing connection to PostgreSQL database "{self.name}"')
555
+ LOG.info('Closing connection to PostgreSQL database "%s"', self.name)
536
556
  self._connection.close()
537
557
  self._connection = None
dsw/database/model.py CHANGED
@@ -1,21 +1,20 @@
1
1
  import dataclasses
2
2
  import datetime
3
+ import enum
3
4
  import json
4
5
 
5
- from typing import Optional
6
-
7
6
 
8
7
  NULL_UUID = '00000000-0000-0000-0000-000000000000'
9
8
 
10
9
 
11
- class DocumentState:
10
+ class DocumentState(enum.Enum):
12
11
  QUEUED = 'QueuedDocumentState'
13
12
  PROCESSING = 'InProgressDocumentState'
14
13
  FAILED = 'ErrorDocumentState'
15
14
  FINISHED = 'DoneDocumentState'
16
15
 
17
16
 
18
- class DocumentTemplatePhase:
17
+ class DocumentTemplatePhase(enum.Enum):
19
18
  RELEASED = 'ReleasedTemplatePhase'
20
19
  DEPRECATED = 'DeprecatedTemplatePhase'
21
20
  DRAFT = 'DraftTemplatePhase'
@@ -55,8 +54,8 @@ class DBDocument:
55
54
  content_type: str
56
55
  worker_log: str
57
56
  created_by: str
58
- retrieved_at: Optional[datetime.datetime]
59
- finished_at: Optional[datetime.datetime]
57
+ retrieved_at: datetime.datetime | None
58
+ finished_at: datetime.datetime | None
60
59
  created_at: datetime.datetime
61
60
  tenant_uuid: str
62
61
  file_size: int
@@ -191,11 +190,11 @@ class PersistentCommand:
191
190
  component: str
192
191
  function: str
193
192
  body: dict
194
- last_error_message: Optional[str]
193
+ last_error_message: str | None
195
194
  attempts: int
196
195
  max_attempts: int
197
196
  tenant_uuid: str
198
- created_by: Optional[str]
197
+ created_by: str | None
199
198
  created_at: datetime.datetime
200
199
  updated_at: datetime.datetime
201
200
 
@@ -220,28 +219,28 @@ class PersistentCommand:
220
219
  @dataclasses.dataclass
221
220
  class DBTenantConfig:
222
221
  uuid: str
223
- organization: Optional[dict]
224
- authentication: Optional[dict]
225
- privacy_and_support: Optional[dict]
226
- dashboard: Optional[dict]
227
- look_and_feel: Optional[dict]
228
- registry: Optional[dict]
229
- knowledge_model: Optional[dict]
230
- questionnaire: Optional[dict]
231
- submission: Optional[dict]
232
- owl: Optional[dict]
233
- mail_config_uuid: Optional[str]
222
+ organization: dict | None
223
+ authentication: dict | None
224
+ privacy_and_support: dict | None
225
+ dashboard: dict | None
226
+ look_and_feel: dict | None
227
+ registry: dict | None
228
+ knowledge_model: dict | None
229
+ questionnaire: dict | None
230
+ submission: dict | None
231
+ owl: dict | None
232
+ mail_config_uuid: str | None
234
233
  created_at: datetime.datetime
235
234
  updated_at: datetime.datetime
236
235
 
237
236
  @property
238
- def app_title(self) -> Optional[str]:
237
+ def app_title(self) -> str | None:
239
238
  if self.look_and_feel is None:
240
239
  return None
241
240
  return self.look_and_feel.get('appTitle', None)
242
241
 
243
242
  @property
244
- def support_email(self) -> Optional[str]:
243
+ def support_email(self) -> str | None:
245
244
  if self.privacy_and_support is None:
246
245
  return None
247
246
  return self.privacy_and_support.get('supportEmail', None)
@@ -269,7 +268,7 @@ class DBTenantConfig:
269
268
  @dataclasses.dataclass
270
269
  class DBTenantLimits:
271
270
  tenant_uuid: str
272
- storage: Optional[int]
271
+ storage: int | None
273
272
 
274
273
  @staticmethod
275
274
  def from_dict_row(data: dict):
@@ -390,19 +389,19 @@ class DBInstanceConfigMail:
390
389
  uuid: str
391
390
  enabled: bool
392
391
  provider: str
393
- sender_name: Optional[str]
394
- sender_email: Optional[str]
395
- smtp_host: Optional[str]
396
- smtp_port: Optional[int]
397
- smtp_security: Optional[str]
398
- smtp_username: Optional[str]
399
- smtp_password: Optional[str]
400
- aws_access_key_id: Optional[str]
401
- aws_secret_access_key: Optional[str]
402
- aws_region: Optional[str]
403
- rate_limit_window: Optional[int]
404
- rate_limit_count: Optional[int]
405
- timeout: Optional[int]
392
+ sender_name: str | None
393
+ sender_email: str | None
394
+ smtp_host: str | None
395
+ smtp_port: int | None
396
+ smtp_security: str | None
397
+ smtp_username: str | None
398
+ smtp_password: str | None
399
+ aws_access_key_id: str | None
400
+ aws_secret_access_key: str | None
401
+ aws_region: str | None
402
+ rate_limit_window: int | None
403
+ rate_limit_count: int | None
404
+ timeout: int | None
406
405
 
407
406
  @staticmethod
408
407
  def from_dict_row(data: dict):
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dsw-database
3
- Version: 4.13.0
3
+ Version: 4.15.0
4
4
  Summary: Library for managing DSW database
5
5
  Author-email: Marek Suchánek <marek.suchanek@ds-wizard.org>
6
6
  License: Apache License 2.0
@@ -11,16 +11,16 @@ Keywords: dsw,database
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Topic :: Database
17
17
  Classifier: Topic :: Utilities
18
- Requires-Python: <4,>=3.10
18
+ Requires-Python: <4,>=3.11
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
21
  Requires-Dist: psycopg[binary]
22
22
  Requires-Dist: tenacity
23
- Requires-Dist: dsw-config==4.13.0
23
+ Requires-Dist: dsw-config==4.15.0
24
24
 
25
25
  # Data Stewardship Wizard: Database
26
26
 
@@ -0,0 +1,9 @@
1
+ dsw/database/__init__.py,sha256=58ZXZ8i4xzAvvjUdqt8lvdv28hD0yzY_xxI6n9deynw,55
2
+ dsw/database/build_info.py,sha256=Wt6gGkDZpCXZSJs_iWM7KmZoGYYCJ0wLqTtV7A7NHxQ,381
3
+ dsw/database/database.py,sha256=L0xa8DTjTvSClD6BYyYJBkSUcxaiSB2HzWAnBEwHwiY,23292
4
+ dsw/database/model.py,sha256=jGJ6trFuAuM7I7Pzi-eIPlJIo28TYMYpP2yOOTZjfRM,12957
5
+ dsw_database-4.15.0.dist-info/LICENSE,sha256=rDtJ4LdsXvf_euOpGD0Q86P78K4JyM5m4yfYz9wZ750,11346
6
+ dsw_database-4.15.0.dist-info/METADATA,sha256=HKUzU4OKb4Jq1mJCefLXC9F_sHudUc9SHgWyV1719XY,1821
7
+ dsw_database-4.15.0.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
8
+ dsw_database-4.15.0.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
9
+ dsw_database-4.15.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
@@ -1,9 +0,0 @@
1
- dsw/database/__init__.py,sha256=58ZXZ8i4xzAvvjUdqt8lvdv28hD0yzY_xxI6n9deynw,55
2
- dsw/database/build_info.py,sha256=IXb1iF0-459NFMJpr13fDd9hNxQyLzLQe93S21s8tk8,381
3
- dsw/database/database.py,sha256=vITvv5-Z--x7MvLgGK62NLYCDVeoU9jioOva_akB39E,22644
4
- dsw/database/model.py,sha256=u79ebW7jk3h7k4IKTtJVQ44vhgOKer7p_m4Povc27k0,13045
5
- dsw_database-4.13.0.dist-info/LICENSE,sha256=rDtJ4LdsXvf_euOpGD0Q86P78K4JyM5m4yfYz9wZ750,11346
6
- dsw_database-4.13.0.dist-info/METADATA,sha256=A40boSCnu4pqM2p3sCcMZMIeJSx2yS_V1J7CqgS5mUM,1821
7
- dsw_database-4.13.0.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
8
- dsw_database-4.13.0.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
9
- dsw_database-4.13.0.dist-info/RECORD,,