diracx-db 0.0.1a26__py3-none-any.whl → 0.0.1a28__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.
@@ -5,9 +5,14 @@ from typing import Any
5
5
  from sqlalchemy import Executable, delete, insert, literal, select, update
6
6
  from sqlalchemy.exc import IntegrityError, NoResultFound
7
7
 
8
- from diracx.core.exceptions import SandboxNotFoundError
8
+ from diracx.core.exceptions import (
9
+ SandboxAlreadyAssignedError,
10
+ SandboxAlreadyInsertedError,
11
+ SandboxNotFoundError,
12
+ )
9
13
  from diracx.core.models import SandboxInfo, SandboxType, UserInfo
10
- from diracx.db.sql.utils import BaseSQLDB, utcnow
14
+ from diracx.db.sql.utils.base import BaseSQLDB
15
+ from diracx.db.sql.utils.functions import utcnow
11
16
 
12
17
  from .schema import Base as SandboxMetadataDBBase
13
18
  from .schema import SandBoxes, SBEntityMapping, SBOwners
@@ -16,18 +21,16 @@ from .schema import SandBoxes, SBEntityMapping, SBOwners
16
21
  class SandboxMetadataDB(BaseSQLDB):
17
22
  metadata = SandboxMetadataDBBase.metadata
18
23
 
19
- async def upsert_owner(self, user: UserInfo) -> int:
24
+ async def get_owner_id(self, user: UserInfo) -> int | None:
20
25
  """Get the id of the owner from the database."""
21
- # TODO: Follow https://github.com/DIRACGrid/diracx/issues/49
22
26
  stmt = select(SBOwners.OwnerID).where(
23
27
  SBOwners.Owner == user.preferred_username,
24
28
  SBOwners.OwnerGroup == user.dirac_group,
25
29
  SBOwners.VO == user.vo,
26
30
  )
27
- result = await self.conn.execute(stmt)
28
- if owner_id := result.scalar_one_or_none():
29
- return owner_id
31
+ return (await self.conn.execute(stmt)).scalar_one_or_none()
30
32
 
33
+ async def insert_owner(self, user: UserInfo) -> int:
31
34
  stmt = insert(SBOwners).values(
32
35
  Owner=user.preferred_username,
33
36
  OwnerGroup=user.dirac_group,
@@ -50,11 +53,9 @@ class SandboxMetadataDB(BaseSQLDB):
50
53
  return "/" + "/".join(parts)
51
54
 
52
55
  async def insert_sandbox(
53
- self, se_name: str, user: UserInfo, pfn: str, size: int
56
+ self, owner_id: int, se_name: str, pfn: str, size: int
54
57
  ) -> None:
55
58
  """Add a new sandbox in SandboxMetadataDB."""
56
- # TODO: Follow https://github.com/DIRACGrid/diracx/issues/49
57
- owner_id = await self.upsert_owner(user)
58
59
  stmt = insert(SandBoxes).values(
59
60
  OwnerId=owner_id,
60
61
  SEName=se_name,
@@ -64,11 +65,9 @@ class SandboxMetadataDB(BaseSQLDB):
64
65
  LastAccessTime=utcnow(),
65
66
  )
66
67
  try:
67
- result = await self.conn.execute(stmt)
68
- except IntegrityError:
69
- await self.update_sandbox_last_access_time(se_name, pfn)
70
- else:
71
- assert result.rowcount == 1
68
+ await self.conn.execute(stmt)
69
+ except IntegrityError as e:
70
+ raise SandboxAlreadyInsertedError(pfn, se_name) from e
72
71
 
73
72
  async def update_sandbox_last_access_time(self, se_name: str, pfn: str) -> None:
74
73
  stmt = (
@@ -135,10 +134,18 @@ class SandboxMetadataDB(BaseSQLDB):
135
134
  stmt = insert(SBEntityMapping).from_select(
136
135
  ["SBId", "EntityId", "Type"], select_sb_id
137
136
  )
138
- await self.conn.execute(stmt)
137
+ try:
138
+ await self.conn.execute(stmt)
139
+ except IntegrityError as e:
140
+ raise SandboxAlreadyAssignedError(pfn, se_name) from e
139
141
 
140
142
  stmt = update(SandBoxes).where(SandBoxes.SEPFN == pfn).values(Assigned=True)
141
143
  result = await self.conn.execute(stmt)
144
+ if result.rowcount == 0:
145
+ # If the update didn't affect any row, the sandbox doesn't exist
146
+ # It means the previous insert didn't have any effect
147
+ raise SandboxNotFoundError(pfn, se_name)
148
+
142
149
  assert result.rowcount == 1
143
150
 
144
151
  async def unassign_sandboxes_to_jobs(self, jobs_ids: list[int]) -> None:
@@ -7,8 +7,6 @@ from sqlalchemy import delete, func, select, update
7
7
  if TYPE_CHECKING:
8
8
  pass
9
9
 
10
- from diracx.core.properties import JOB_SHARING, SecurityProperty
11
-
12
10
  from ..utils import BaseSQLDB
13
11
  from .schema import (
14
12
  BannedSitesQueue,
@@ -49,126 +47,23 @@ class TaskQueueDB(BaseSQLDB):
49
47
  )
50
48
  return dict((await self.conn.execute(stmt)).one()._mapping)
51
49
 
52
- async def remove_job(self, job_id: int):
53
- """Remove a job from the task queues."""
54
- stmt = delete(JobsQueue).where(JobsQueue.JobId == job_id)
55
- await self.conn.execute(stmt)
56
-
57
- async def remove_jobs(self, job_ids: list[int]):
58
- """Remove jobs from the task queues."""
59
- stmt = delete(JobsQueue).where(JobsQueue.JobId.in_(job_ids))
60
- await self.conn.execute(stmt)
61
-
62
- async def delete_task_queue_if_empty(
63
- self,
64
- tq_id: int,
65
- tq_owner: str,
66
- tq_group: str,
67
- job_share: int,
68
- group_properties: set[SecurityProperty],
69
- enable_shares_correction: bool,
70
- allow_background_tqs: bool,
71
- ):
72
- """Try to delete a task queue if it's empty."""
73
- # Check if the task queue is empty
74
- stmt = (
75
- select(TaskQueues.TQId)
76
- .where(TaskQueues.Enabled >= 1)
77
- .where(TaskQueues.TQId == tq_id)
78
- .where(~TaskQueues.TQId.in_(select(JobsQueue.TQId)))
79
- )
80
- rows = await self.conn.execute(stmt)
81
- if not rows.rowcount:
82
- return
83
-
84
- # Deleting the task queue (the other tables will be deleted in cascade)
85
- stmt = delete(TaskQueues).where(TaskQueues.TQId == tq_id)
86
- await self.conn.execute(stmt)
87
-
88
- await self.recalculate_tq_shares_for_entity(
89
- tq_owner,
90
- tq_group,
91
- job_share,
92
- group_properties,
93
- enable_shares_correction,
94
- allow_background_tqs,
95
- )
96
-
97
- async def recalculate_tq_shares_for_entity(
98
- self,
99
- owner: str,
100
- group: str,
101
- job_share: int,
102
- group_properties: set[SecurityProperty],
103
- enable_shares_correction: bool,
104
- allow_background_tqs: bool,
105
- ):
106
- """Recalculate the shares for a user/userGroup combo."""
107
- if JOB_SHARING in group_properties:
108
- # If group has JobSharing just set prio for that entry, user is irrelevant
109
- return await self.__set_priorities_for_entity(
110
- owner, group, job_share, group_properties, allow_background_tqs
111
- )
112
-
50
+ async def get_task_queue_owners_by_group(self, group: str) -> dict[str, int]:
51
+ """Get the owners for a task queue and group."""
113
52
  stmt = (
114
53
  select(TaskQueues.Owner, func.count(TaskQueues.Owner))
115
54
  .where(TaskQueues.OwnerGroup == group)
116
55
  .group_by(TaskQueues.Owner)
117
56
  )
118
57
  rows = await self.conn.execute(stmt)
119
- # make the rows a list of tuples
120
58
  # Get owners in this group and the amount of times they appear
121
59
  # TODO: I guess the rows are already a list of tupes
122
60
  # maybe refactor
123
- data = [(r[0], r[1]) for r in rows if r]
124
- num_owners = len(data)
125
- # If there are no owners do now
126
- if num_owners == 0:
127
- return
128
- # Split the share amongst the number of owners
129
- entities_shares = {row[0]: job_share / num_owners for row in data}
130
-
131
- # TODO: implement the following
132
- # If corrector is enabled let it work it's magic
133
- # if enable_shares_correction:
134
- # entities_shares = await self.__shares_corrector.correct_shares(
135
- # entitiesShares, group=group
136
- # )
137
-
138
- # Keep updating
139
- owners = dict(data)
140
- # IF the user is already known and has more than 1 tq, the rest of the users don't need to be modified
141
- # (The number of owners didn't change)
142
- if owner in owners and owners[owner] > 1:
143
- await self.__set_priorities_for_entity(
144
- owner,
145
- group,
146
- entities_shares[owner],
147
- group_properties,
148
- allow_background_tqs,
149
- )
150
- return
151
- # Oops the number of owners may have changed so we recalculate the prio for all owners in the group
152
- for owner in owners:
153
- await self.__set_priorities_for_entity(
154
- owner,
155
- group,
156
- entities_shares[owner],
157
- group_properties,
158
- allow_background_tqs,
159
- )
160
-
161
- async def __set_priorities_for_entity(
162
- self,
163
- owner: str,
164
- group: str,
165
- share,
166
- properties: set[SecurityProperty],
167
- allow_background_tqs: bool,
168
- ):
169
- """Set the priority for a user/userGroup combo given a splitted share."""
170
- from DIRAC.WorkloadManagementSystem.DB.TaskQueueDB import calculate_priority
61
+ return {r[0]: r[1] for r in rows if r}
171
62
 
63
+ async def get_task_queue_priorities(
64
+ self, group: str, owner: str | None = None
65
+ ) -> dict[int, float]:
66
+ """Get the priorities for a list of task queues."""
172
67
  stmt = (
173
68
  select(
174
69
  TaskQueues.TQId,
@@ -178,24 +73,48 @@ class TaskQueueDB(BaseSQLDB):
178
73
  .where(TaskQueues.OwnerGroup == group)
179
74
  .group_by(TaskQueues.TQId)
180
75
  )
181
- if JOB_SHARING not in properties:
76
+ if owner:
182
77
  stmt = stmt.where(TaskQueues.Owner == owner)
183
78
  rows = await self.conn.execute(stmt)
184
- tq_dict: dict[int, float] = {tq_id: priority for tq_id, priority in rows}
79
+ return {tq_id: priority for tq_id, priority in rows}
185
80
 
186
- if not tq_dict:
187
- return
81
+ async def remove_jobs(self, job_ids: list[int]):
82
+ """Remove jobs from the task queues."""
83
+ stmt = delete(JobsQueue).where(JobsQueue.JobId.in_(job_ids))
84
+ await self.conn.execute(stmt)
188
85
 
189
- rows = await self.retrieve_task_queues(list(tq_dict))
86
+ async def is_task_queue_empty(self, tq_id: int) -> bool:
87
+ """Check if a task queue is empty."""
88
+ stmt = (
89
+ select(TaskQueues.TQId)
90
+ .where(TaskQueues.Enabled >= 1)
91
+ .where(TaskQueues.TQId == tq_id)
92
+ .where(~TaskQueues.TQId.in_(select(JobsQueue.TQId)))
93
+ )
94
+ rows = await self.conn.execute(stmt)
95
+ return not rows.rowcount
190
96
 
191
- prio_dict = calculate_priority(tq_dict, rows, share, allow_background_tqs)
97
+ async def delete_task_queue(
98
+ self,
99
+ tq_id: int,
100
+ ):
101
+ """Delete a task queue."""
102
+ # Deleting the task queue (the other tables will be deleted in cascade)
103
+ stmt = delete(TaskQueues).where(TaskQueues.TQId == tq_id)
104
+ await self.conn.execute(stmt)
192
105
 
193
- # Execute updates
194
- for prio, tqs in prio_dict.items():
195
- update_stmt = (
196
- update(TaskQueues).where(TaskQueues.TQId.in_(tqs)).values(Priority=prio)
197
- )
198
- await self.conn.execute(update_stmt)
106
+ async def set_priorities_for_entity(
107
+ self,
108
+ tq_ids: list[int],
109
+ priority: float,
110
+ ):
111
+ """Set the priority for a user/userGroup combo given a splitted share."""
112
+ update_stmt = (
113
+ update(TaskQueues)
114
+ .where(TaskQueues.TQId.in_(tq_ids))
115
+ .values(Priority=priority)
116
+ )
117
+ await self.conn.execute(update_stmt)
199
118
 
200
119
  async def retrieve_task_queues(self, tq_id_list=None):
201
120
  """Get all the task queues."""
@@ -6,7 +6,7 @@ from .base import (
6
6
  apply_search_filters,
7
7
  apply_sort_constraints,
8
8
  )
9
- from .functions import substract_date, utcnow
9
+ from .functions import hash, substract_date, utcnow
10
10
  from .types import Column, DateNowColumn, EnumBackedBool, EnumColumn, NullColumn
11
11
 
12
12
  __all__ = (
@@ -20,5 +20,6 @@ __all__ = (
20
20
  "apply_search_filters",
21
21
  "apply_sort_constraints",
22
22
  "substract_date",
23
+ "hash",
23
24
  "SQLDBUnavailableError",
24
25
  )
@@ -104,7 +104,7 @@ class BaseSQLDB(metaclass=ABCMeta):
104
104
  db_classes: list[type[BaseSQLDB]] = [
105
105
  entry_point.load()
106
106
  for entry_point in select_from_extension(
107
- group="diracx.db.sql", name=db_name
107
+ group="diracx.dbs.sql", name=db_name
108
108
  )
109
109
  ]
110
110
  if not db_classes:
@@ -119,7 +119,7 @@ class BaseSQLDB(metaclass=ABCMeta):
119
119
  prefixed with ``DIRACX_DB_URL_{DB_NAME}``.
120
120
  """
121
121
  db_urls: dict[str, str] = {}
122
- for entry_point in select_from_extension(group="diracx.db.sql"):
122
+ for entry_point in select_from_extension(group="diracx.dbs.sql"):
123
123
  db_name = entry_point.name
124
124
  var_name = f"DIRACX_DB_URL_{entry_point.name.upper()}"
125
125
  if var_name in os.environ:
@@ -232,7 +232,7 @@ def find_time_resolution(value):
232
232
  if isinstance(value, datetime):
233
233
  return None, value
234
234
  if match := re.fullmatch(
235
- r"\d{4}(-\d{2}(-\d{2}(([ T])\d{2}(:\d{2}(:\d{2}(\.\d{6}Z?)?)?)?)?)?)?", value
235
+ r"\d{4}(-\d{2}(-\d{2}(([ T])\d{2}(:\d{2}(:\d{2}(\.\d{1,6}Z?)?)?)?)?)?)?", value
236
236
  ):
237
237
  if match.group(6):
238
238
  precision, pattern = "SECOND", r"\1-\2-\3 \4:\5:\6"
@@ -249,7 +249,7 @@ def find_time_resolution(value):
249
249
  return (
250
250
  precision,
251
251
  re.sub(
252
- r"^(\d{4})-?(\d{2})?-?(\d{2})?[ T]?(\d{2})?:?(\d{2})?:?(\d{2})?\.?(\d{6})?Z?$",
252
+ r"^(\d{4})-?(\d{2})?-?(\d{2})?[ T]?(\d{2})?:?(\d{2})?:?(\d{2})?\.?(\d{1,6})?Z?$",
253
253
  pattern,
254
254
  value,
255
255
  ),
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import hashlib
3
4
  from datetime import datetime, timedelta, timezone
4
5
  from typing import TYPE_CHECKING
5
6
 
@@ -47,7 +48,8 @@ class date_trunc(expression.FunctionElement): # noqa: N801
47
48
  """
48
49
 
49
50
  type = DateTime()
50
- inherit_cache = True
51
+ # Cache does not work as intended with time resolution values, so we disable it
52
+ inherit_cache = False
51
53
 
52
54
  def __init__(self, *args, time_resolution, **kwargs) -> None:
53
55
  super().__init__(*args, **kwargs)
@@ -103,3 +105,7 @@ def sqlite_date_trunc(element, compiler, **kw):
103
105
 
104
106
  def substract_date(**kwargs: float) -> datetime:
105
107
  return datetime.now(tz=timezone.utc) - timedelta(**kwargs)
108
+
109
+
110
+ def hash(code: str):
111
+ return hashlib.sha256(code.encode()).hexdigest()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: diracx-db
3
- Version: 0.0.1a26
3
+ Version: 0.0.1a28
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -10,9 +10,7 @@ Classifier: Topic :: Scientific/Engineering
10
10
  Classifier: Topic :: System :: Distributed Computing
11
11
  Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
- Requires-Dist: dirac
14
13
  Requires-Dist: diracx-core
15
- Requires-Dist: fastapi
16
14
  Requires-Dist: opensearch-py[async]
17
15
  Requires-Dist: pydantic>=2.10
18
16
  Requires-Dist: sqlalchemy[aiomysql,aiosqlite]>=2
@@ -4,36 +4,35 @@ diracx/db/exceptions.py,sha256=1nn-SZLG-nQwkxbvHjZqXhE5ouzWj1f3qhSda2B4ZEg,83
4
4
  diracx/db/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  diracx/db/os/__init__.py,sha256=IZr6z6SefrRvuC8sTC4RmB3_wwOyEt1GzpDuwSMH8O4,112
6
6
  diracx/db/os/job_parameters.py,sha256=Knca19uT2G-5FI7MOFlaOAXeHn4ecPVLIH30TiwhaTw,858
7
- diracx/db/os/utils.py,sha256=k4EBCDLzx_P35aTOoFFrYjO7bnyIF_-PRZGlpMk3IAI,11366
7
+ diracx/db/os/utils.py,sha256=xQLhOgC9YidfeEIbmdigXg3_YZLKHwMcZzhHf4mRwyQ,11399
8
8
  diracx/db/sql/__init__.py,sha256=JYu0b0IVhoXy3lX2m2r2dmAjsRS7IbECBUMEDvX0Te4,391
9
9
  diracx/db/sql/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- diracx/db/sql/auth/db.py,sha256=Ma3P6m49wUNM9wcQZWoQu1CsyJF8vvGeirBFuQUaAIY,10202
10
+ diracx/db/sql/auth/db.py,sha256=O9sp-AKobQ4X4IF2WaJKig-8LU8Ra9Syn5jW8JNLRU4,9030
11
11
  diracx/db/sql/auth/schema.py,sha256=-yXVfNz45W3VvvrNf-ZrSzIgb9qMaI9x1fWDshSkpPU,3141
12
12
  diracx/db/sql/dummy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  diracx/db/sql/dummy/db.py,sha256=whcF02IjFQTwe1l4iTHtCkg2XukEaLHpLeHYNGMuGGw,1645
14
14
  diracx/db/sql/dummy/schema.py,sha256=9zI53pKlzc6qBezsyjkatOQrNZdGCjwgjQ8Iz_pyAXs,789
15
15
  diracx/db/sql/job/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- diracx/db/sql/job/db.py,sha256=21J5vvIT6z_kdVxmoQjiZ61pjCvAXJ5tKN25eJyNR6Q,11712
16
+ diracx/db/sql/job/db.py,sha256=qoK1toWekRP1BO5XbT9CaRuGKR9_oixMVfRZ9myZsjg,8644
17
17
  diracx/db/sql/job/schema.py,sha256=Rmt5ldVN6Pf4MJHMhiT_Zn-k9LVPBTVivmGlyPKFRZE,4647
18
18
  diracx/db/sql/job_logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- diracx/db/sql/job_logging/db.py,sha256=-i_azE67MI95LnXER31USCKioq0l4Q3VJb1oQPdy2Ds,7827
19
+ diracx/db/sql/job_logging/db.py,sha256=0WuRn3pKEeuV9IZ_3VDhlvqI9eM1W4C0dZwIVZKW9N8,5811
20
20
  diracx/db/sql/job_logging/schema.py,sha256=DyFr_4goxfC453xPJX4OkxTGHtlP_5q8PXpr8bhNQS0,960
21
21
  diracx/db/sql/pilot_agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  diracx/db/sql/pilot_agents/db.py,sha256=7-cuCbh_KhM0jlybsHMWV-W66bHsPHIVBpbuqwjncj0,1232
23
23
  diracx/db/sql/pilot_agents/schema.py,sha256=KeWnFSpYOTrT3-_rOCFjbjNnPNXKnUZiJVsu4vv5U2U,2149
24
24
  diracx/db/sql/sandbox_metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- diracx/db/sql/sandbox_metadata/db.py,sha256=wpGPUA1KLrt9B9qJaQGZExnyeREp44jdbW3XkRX_kP0,6410
25
+ diracx/db/sql/sandbox_metadata/db.py,sha256=IyQtTIxRzRv0cdhR3Of1uVzliggePY67bz_9HeKIOjE,6666
26
26
  diracx/db/sql/sandbox_metadata/schema.py,sha256=mI-YpH6NneOQ6QiqwIwyJ4afwfoamybSlQpvaISFfPY,1431
27
27
  diracx/db/sql/task_queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- diracx/db/sql/task_queue/db.py,sha256=xY8yPpCIwTC5epcyFGxAP8K9sOVybYsgoH2_QH3NHb8,9105
28
+ diracx/db/sql/task_queue/db.py,sha256=Ymd9cBasiSAPmgu5846B8KmguRiJ_GoJhuOev9YwW2o,6248
29
29
  diracx/db/sql/task_queue/schema.py,sha256=5efAgvNYRkLlaJ2NzRInRfmVa3tyIzQu2l0oRPy4Kzw,3258
30
- diracx/db/sql/utils/__init__.py,sha256=b4lLIYRFVX8PW15ekklzs5OeulA6lNEOfBOJqgIOtYY,529
31
- diracx/db/sql/utils/base.py,sha256=hAFeUKWQIOJq9w_WholaLDdDxBd-E8UVLKq99uX7aYw,12361
32
- diracx/db/sql/utils/functions.py,sha256=PFA570qkCZQdABxsz2_LBEfYUv8dln3suNHx17PHGS0,2879
33
- diracx/db/sql/utils/job.py,sha256=U_y8DZdMGU5NbQF3udA4Yg43HaKhF8YhYa-PhzYmIyI,19592
30
+ diracx/db/sql/utils/__init__.py,sha256=QkvpqBuIAgkAOywAssYzdxSzUQVZlSUumK7mPxotXfM,547
31
+ diracx/db/sql/utils/base.py,sha256=7UxHBNLOSjdrIdslMKW4C_c5H9-6Y1BEimxscri2poE,12367
32
+ diracx/db/sql/utils/functions.py,sha256=iLqlUIQ6SrDUtDEnZ5szaFbdcINJW15KNbCdGXss6kc,3055
34
33
  diracx/db/sql/utils/types.py,sha256=yU-tXsu6hFGPsr9ba1n3ZjGPnHQI_06lbpkTeDCWJtg,1287
35
- diracx_db-0.0.1a26.dist-info/METADATA,sha256=2s_xYS6cfK8T9C4lhl9ad7mK8_tWRzXUV4oXOviqOcA,688
36
- diracx_db-0.0.1a26.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
- diracx_db-0.0.1a26.dist-info/entry_points.txt,sha256=YLI4f6640bri8Ud6Jt9WNq79pSTVQAkfUasb9f75fR8,315
38
- diracx_db-0.0.1a26.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
39
- diracx_db-0.0.1a26.dist-info/RECORD,,
34
+ diracx_db-0.0.1a28.dist-info/METADATA,sha256=7tBHb4St4d0QeFQEBqfMYGTxhXaIOP2K2evK0GvJHCo,644
35
+ diracx_db-0.0.1a28.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
36
+ diracx_db-0.0.1a28.dist-info/entry_points.txt,sha256=UPqhLvb9gui0kOyWeI_edtefcrHToZmQt1p76vIwujo,317
37
+ diracx_db-0.0.1a28.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
38
+ diracx_db-0.0.1a28.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,7 +1,7 @@
1
- [diracx.db.os]
1
+ [diracx.dbs.os]
2
2
  JobParametersDB = diracx.db.os:JobParametersDB
3
3
 
4
- [diracx.db.sql]
4
+ [diracx.dbs.sql]
5
5
  AuthDB = diracx.db.sql:AuthDB
6
6
  JobDB = diracx.db.sql:JobDB
7
7
  JobLoggingDB = diracx.db.sql:JobLoggingDB