diracx-db 0.0.1a39__py3-none-any.whl → 0.0.1a41__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.
@@ -1,28 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
- import time
4
- from datetime import timezone
5
- from typing import TYPE_CHECKING
3
+ from collections import defaultdict
4
+ from datetime import datetime, timezone
5
+ from typing import Iterable
6
6
 
7
7
  from sqlalchemy import delete, func, select
8
8
 
9
- if TYPE_CHECKING:
10
- pass
11
-
12
- from collections import defaultdict
13
-
14
- from diracx.core.models import (
15
- JobLoggingRecord,
16
- JobStatusReturn,
17
- )
9
+ from diracx.core.models import JobLoggingRecord, JobStatusReturn
18
10
 
19
11
  from ..utils import BaseSQLDB
20
- from .schema import (
21
- JobLoggingDBBase,
22
- LoggingInfo,
23
- )
24
-
25
- MAGIC_EPOC_NUMBER = 1270000000
12
+ from .schema import JobLoggingDBBase, LoggingInfo
26
13
 
27
14
 
28
15
  class JobLoggingDB(BaseSQLDB):
@@ -35,14 +22,6 @@ class JobLoggingDB(BaseSQLDB):
35
22
  records: list[JobLoggingRecord],
36
23
  ):
37
24
  """Bulk insert entries to the JobLoggingDB table."""
38
-
39
- def get_epoc(date):
40
- return (
41
- time.mktime(date.timetuple())
42
- + date.microsecond / 1000000.0
43
- - MAGIC_EPOC_NUMBER
44
- )
45
-
46
25
  # First, fetch the maximum SeqNums for the given job_ids
47
26
  seqnum_stmt = (
48
27
  select(
@@ -70,7 +49,7 @@ class JobLoggingDB(BaseSQLDB):
70
49
  "MinorStatus": record.minor_status,
71
50
  "ApplicationStatus": record.application_status[:255],
72
51
  "StatusTime": record.date,
73
- "StatusTimeOrder": get_epoc(record.date),
52
+ "StatusTimeOrder": record.date,
74
53
  "StatusSource": record.source[:32],
75
54
  }
76
55
  )
@@ -159,21 +138,16 @@ class JobLoggingDB(BaseSQLDB):
159
138
  stmt = delete(LoggingInfo).where(LoggingInfo.job_id.in_(job_ids))
160
139
  await self.conn.execute(stmt)
161
140
 
162
- async def get_wms_time_stamps(self, job_ids):
141
+ async def get_wms_time_stamps(
142
+ self, job_ids: Iterable[int]
143
+ ) -> dict[int, dict[str, datetime]]:
163
144
  """Get TimeStamps for job MajorState transitions for multiple jobs at once
164
145
  return a {JobID: {State:timestamp}} dictionary.
165
146
  """
166
- result = defaultdict(dict)
147
+ result: defaultdict[int, dict[str, datetime]] = defaultdict(dict)
167
148
  stmt = select(
168
- LoggingInfo.job_id,
169
- LoggingInfo.status,
170
- LoggingInfo.status_time_order,
149
+ LoggingInfo.job_id, LoggingInfo.status, LoggingInfo.status_time_order
171
150
  ).where(LoggingInfo.job_id.in_(job_ids))
172
- rows = await self.conn.execute(stmt)
173
- if not rows.rowcount:
174
- return {}
175
-
176
- for job_id, event, etime in rows:
177
- result[job_id][event] = str(etime + MAGIC_EPOC_NUMBER)
178
-
179
- return result
151
+ for job_id, event, etime in await self.conn.execute(stmt):
152
+ result[job_id][event] = etime
153
+ return dict(result)
@@ -1,11 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- from sqlalchemy import (
4
- Integer,
5
- Numeric,
6
- PrimaryKeyConstraint,
7
- String,
8
- )
3
+ from datetime import UTC, datetime
4
+
5
+ from sqlalchemy import Integer, Numeric, PrimaryKeyConstraint, String, TypeDecorator
9
6
  from sqlalchemy.orm import declarative_base
10
7
 
11
8
  from ..utils import Column, DateNowColumn
@@ -13,6 +10,47 @@ from ..utils import Column, DateNowColumn
13
10
  JobLoggingDBBase = declarative_base()
14
11
 
15
12
 
13
+ class MagicEpochDateTime(TypeDecorator):
14
+ """A SQLAlchemy type that stores a datetime as a numeric value representing the
15
+ seconds elapsed since MAGIC_EPOC_NUMBER. The underlying column is defined as
16
+ Numeric(12,3) which provides a fixed-precision representation.
17
+ """
18
+
19
+ impl = Numeric(12, 3)
20
+ cache_ok = True
21
+
22
+ MAGIC_EPOC_NUMBER = 1270000000
23
+
24
+ def process_bind_param(self, value, dialect):
25
+ """Convert a Python datetime to a numeric value: (timestamp - MAGIC_EPOC_NUMBER).
26
+ The result is rounded to three decimal places.
27
+ """
28
+ if value is None:
29
+ return None
30
+ if isinstance(value, datetime):
31
+ # Convert datetime to seconds since the Unix epoch, subtract our magic epoch,
32
+ # and round to three decimal places.
33
+ epoch_seconds = (
34
+ value.replace(tzinfo=UTC).timestamp() - self.MAGIC_EPOC_NUMBER
35
+ )
36
+ return round(epoch_seconds, 3)
37
+ raise ValueError(
38
+ "Expected a datetime object for MagicEpochDateTime bind parameter."
39
+ )
40
+
41
+ def process_result_value(self, value, dialect):
42
+ """Convert the numeric database value back into a Python datetime by reversing the
43
+ stored difference (adding MAGIC_EPOC_NUMBER).
44
+ """
45
+ if value is None:
46
+ return None
47
+ # Carefully convert from Decimal to datetime to avoid loosing precision
48
+ value += self.MAGIC_EPOC_NUMBER
49
+ value_int = int(value)
50
+ result = datetime.fromtimestamp(value_int, tz=UTC)
51
+ return result.replace(microsecond=int((value - value_int) * 1_000_000))
52
+
53
+
16
54
  class LoggingInfo(JobLoggingDBBase):
17
55
  __tablename__ = "LoggingInfo"
18
56
  job_id = Column("JobID", Integer)
@@ -21,9 +59,6 @@ class LoggingInfo(JobLoggingDBBase):
21
59
  minor_status = Column("MinorStatus", String(128), default="")
22
60
  application_status = Column("ApplicationStatus", String(255), default="")
23
61
  status_time = DateNowColumn("StatusTime")
24
- # TODO: Check that this corresponds to the DOUBLE(12,3) type in MySQL
25
- status_time_order = Column(
26
- "StatusTimeOrder", Numeric(precision=12, scale=3), default=0
27
- )
62
+ status_time_order = Column("StatusTimeOrder", MagicEpochDateTime, default=0)
28
63
  source = Column("StatusSource", String(32), default="Unknown")
29
64
  __table_args__ = (PrimaryKeyConstraint("JobID", "SeqNum"),)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diracx-db
3
- Version: 0.0.1a39
3
+ Version: 0.0.1a41
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -16,8 +16,8 @@ diracx/db/sql/job/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
16
16
  diracx/db/sql/job/db.py,sha256=PTivVrSl4hrOTgy77WECunPJUJiYzGhSlqO0wYwEuE8,11909
17
17
  diracx/db/sql/job/schema.py,sha256=eFgZshe6NEzOM2qI0HI9Y3abrqDMoQIwa9L0vZugHcU,5431
18
18
  diracx/db/sql/job_logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- diracx/db/sql/job_logging/db.py,sha256=0WuRn3pKEeuV9IZ_3VDhlvqI9eM1W4C0dZwIVZKW9N8,5811
20
- diracx/db/sql/job_logging/schema.py,sha256=DyFr_4goxfC453xPJX4OkxTGHtlP_5q8PXpr8bhNQS0,960
19
+ diracx/db/sql/job_logging/db.py,sha256=BYzlPuvdvHR7wdzQEVWMH_V5kL0bLBZtQkcugnSGbjs,5497
20
+ diracx/db/sql/job_logging/schema.py,sha256=W2VeE7czBXF6uP2hmjBDur90S4BlidzFXX2V_WZkfzU,2525
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
@@ -31,8 +31,8 @@ diracx/db/sql/utils/__init__.py,sha256=QkvpqBuIAgkAOywAssYzdxSzUQVZlSUumK7mPxotX
31
31
  diracx/db/sql/utils/base.py,sha256=7UxHBNLOSjdrIdslMKW4C_c5H9-6Y1BEimxscri2poE,12367
32
32
  diracx/db/sql/utils/functions.py,sha256=iLqlUIQ6SrDUtDEnZ5szaFbdcINJW15KNbCdGXss6kc,3055
33
33
  diracx/db/sql/utils/types.py,sha256=yU-tXsu6hFGPsr9ba1n3ZjGPnHQI_06lbpkTeDCWJtg,1287
34
- diracx_db-0.0.1a39.dist-info/METADATA,sha256=DwYPjyX2hAHKaG9WpL1Ej4TjLbEQ5CSHR2WS7FtyWU8,644
35
- diracx_db-0.0.1a39.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
36
- diracx_db-0.0.1a39.dist-info/entry_points.txt,sha256=UPqhLvb9gui0kOyWeI_edtefcrHToZmQt1p76vIwujo,317
37
- diracx_db-0.0.1a39.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
38
- diracx_db-0.0.1a39.dist-info/RECORD,,
34
+ diracx_db-0.0.1a41.dist-info/METADATA,sha256=pxDO9aAH41RLsym_fs8ySzjZlXjY53GGQwb0MvnE-Lk,644
35
+ diracx_db-0.0.1a41.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
36
+ diracx_db-0.0.1a41.dist-info/entry_points.txt,sha256=UPqhLvb9gui0kOyWeI_edtefcrHToZmQt1p76vIwujo,317
37
+ diracx_db-0.0.1a41.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
38
+ diracx_db-0.0.1a41.dist-info/RECORD,,