Skip to content

Commit

Permalink
refactor VODatetime to UTCTimestamp from VOResource
Browse files Browse the repository at this point in the history
  • Loading branch information
jwfraustro committed Dec 7, 2023
1 parent 63bf93c commit 26e12ad
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 45 deletions.
32 changes: 16 additions & 16 deletions tests/uws/models_test.py → tests/uws/uws_models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from lxml import etree

from vo_models.xml.generics import VODateTime
from vo_models.xml.voresource.types import UTCTimestamp
from vo_models.xml.uws import (
ErrorSummary,
Jobs,
Expand Down Expand Up @@ -213,7 +213,7 @@ def test_read_from_xml(self):
self.assertEqual(short_job_description.phase, "PENDING")
self.assertEqual(short_job_description.run_id, "runId1")
self.assertEqual(short_job_description.owner_id, None)
self.assertEqual(short_job_description.creation_time, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(short_job_description.creation_time, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))

def test_write_to_xml(self):
"""Test writing to XML"""
Expand All @@ -224,7 +224,7 @@ def test_write_to_xml(self):
href="http://uri1",
phase="PENDING",
run_id="runId1",
creation_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
creation_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
)
short_job_description_xml = short_job_description.to_xml(encoding=str)

Expand Down Expand Up @@ -323,11 +323,11 @@ def test_read_from_xml(self):
self.assertEqual(job_summary.owner_id, "ownerId1")
self.assertEqual(job_summary.phase, ExecutionPhase.PENDING.value)
self.assertEqual(job_summary.quote, None)
self.assertEqual(job_summary.creation_time, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.start_time, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.end_time, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.creation_time, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.start_time, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.end_time, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.execution_duration, 0)
self.assertEqual(job_summary.destruction, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(job_summary.destruction, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(len(job_summary.parameters.parameter), 2)
self.assertEqual(job_summary.parameters.parameter[0].id, "param1")
self.assertEqual(job_summary.parameters.parameter[1].id, "param2")
Expand All @@ -346,11 +346,11 @@ def test_write_to_xml(self):
owner_id="ownerId1",
phase=ExecutionPhase.PENDING,
quote=None,
creation_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
start_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
end_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
creation_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
start_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
end_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
execution_duration=0,
destruction=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
destruction=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
parameters=Parameters(
parameter=[
Parameter(id="param1", value="value1"),
Expand All @@ -376,11 +376,11 @@ def test_validate(self):
owner_id="ownerId1",
phase=ExecutionPhase.PENDING,
quote=None,
creation_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
creation_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
start_time=None,
end_time=None,
execution_duration=0,
destruction=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
destruction=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
parameters=Parameters(
parameter=[
Parameter(id="param1", value="value1"),
Expand Down Expand Up @@ -416,7 +416,7 @@ def test_read_from_xml(self):
self.assertEqual(jobs_element.jobref[0].job_id, "id1")
self.assertEqual(jobs_element.jobref[0].owner_id, None)
self.assertEqual(jobs_element.jobref[0].phase, ExecutionPhase.PENDING)
self.assertEqual(jobs_element.jobref[0].creation_time, VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))
self.assertEqual(jobs_element.jobref[0].creation_time, UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc))

def test_write_to_xml(self):
"""Test writing to XML"""
Expand All @@ -428,7 +428,7 @@ def test_write_to_xml(self):
owner_id=None,
href="http://uri1",
phase=ExecutionPhase.PENDING,
creation_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
creation_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
)
]
)
Expand All @@ -447,7 +447,7 @@ def test_validate(self):
ShortJobDescription(
job_id="id1",
phase=ExecutionPhase.PENDING,
creation_time=VODateTime(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
creation_time=UTCTimestamp(1900, 1, 1, 1, 1, 1, tzinfo=tz.utc),
)
]
)
Expand Down
Empty file added tests/voresource/__init__.py
Empty file.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for generic VO xml models"""
"""Tests for VOResource simple types"""
from unittest import TestCase

from vo_models.xml.generics import VODateTime
from vo_models.xml.voresource.types import UTCTimestamp


class TestVODatetimeModel(TestCase):
Expand All @@ -14,31 +14,31 @@ def test_vodatetime_parse(self):
good_vo_dt = "2023-03-15T18:27:18.758Z"

# 2023-03-15T18:27:18.758 (No timezone - Z UTC assumed)
vo_dt = VODateTime.fromisoformat("2023-03-15T18:27:18.758")
self.assertIsInstance(vo_dt, VODateTime)
vo_dt = UTCTimestamp.fromisoformat("2023-03-15T18:27:18.758")
self.assertIsInstance(vo_dt, UTCTimestamp)
self.assertEqual(vo_dt.isoformat(), good_vo_dt)

# 2023-03-15T18:27:18.758Z (Zulu UTC - T separator)
vo_dt = VODateTime.fromisoformat("2023-03-15T18:27:18.758Z")
self.assertIsInstance(vo_dt, VODateTime)
vo_dt = UTCTimestamp.fromisoformat("2023-03-15T18:27:18.758Z")
self.assertIsInstance(vo_dt, UTCTimestamp)
self.assertEqual(vo_dt.isoformat(), good_vo_dt)

# 2023-03-15 18:27:18.758Z (Zulu UTC - space separator)
vo_dt = VODateTime.fromisoformat("2023-03-15 18:27:18.758Z")
self.assertIsInstance(vo_dt, VODateTime)
vo_dt = UTCTimestamp.fromisoformat("2023-03-15 18:27:18.758Z")
self.assertIsInstance(vo_dt, UTCTimestamp)
self.assertEqual(vo_dt.isoformat(), good_vo_dt)

# 2023-03-15T18:27:18.758+00:00 (UTC w/ offset - T separator)
vo_dt = VODateTime.fromisoformat("2023-03-15T18:27:18.758+00:00")
self.assertIsInstance(vo_dt, VODateTime)
vo_dt = UTCTimestamp.fromisoformat("2023-03-15T18:27:18.758+00:00")
self.assertIsInstance(vo_dt, UTCTimestamp)
self.assertEqual(vo_dt.isoformat(), good_vo_dt)

# 2023-03-15 18:27:18.758+00:00 (UTC w/ offset - space separator)
vo_dt = VODateTime.fromisoformat("2023-03-15 18:27:18.758+00:00")
self.assertIsInstance(vo_dt, VODateTime)
vo_dt = UTCTimestamp.fromisoformat("2023-03-15 18:27:18.758+00:00")
self.assertIsInstance(vo_dt, UTCTimestamp)
self.assertEqual(vo_dt.isoformat(), good_vo_dt)

# Test that we reject non-UTC datetimes
with self.assertRaises(ValueError):
# pylint: disable=protected-access
VODateTime._validate("20230315T18:27:18.758")
UTCTimestamp._validate("20230315T18:27:18.758")
15 changes: 8 additions & 7 deletions vo_models/xml/uws/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pydantic import field_validator
from pydantic_xml import BaseXmlModel, attr, element

from vo_models.xml.generics import VODateTime
from vo_models.xml.voresource.types import UTCTimestamp
from vo_models.xml.uws.types import ErrorType, ExecutionPhase, UWSVersion
from vo_models.xml.xlink import XlinkType

Expand Down Expand Up @@ -122,7 +122,7 @@ class ShortJobDescription(BaseXmlModel, tag="jobref", ns="uws", nsmap=NSMAP):
phase: ExecutionPhase = element()
run_id: Optional[str] = element(tag="runId", default=None)
owner_id: Optional[str] = element(tag="ownerId", default=None, nillable=True)
creation_time: Optional[VODateTime] = element(tag="creationTime", default=None)
creation_time: Optional[UTCTimestamp] = element(tag="creationTime", default=None)

job_id: str = attr(name="id")
type: Optional[XlinkType] = attr(ns="xlink", default=XlinkType.SIMPLE)
Expand Down Expand Up @@ -192,17 +192,18 @@ class JobSummary(BaseXmlModel, Generic[ParametersType], tag="job", ns="uws", nsm
"""

# pylint: disable = no-self-argument
# pylint: disable = too-few-public-methods

job_id: str = element(tag="jobId")
run_id: Optional[str] = element(tag="runId", default=None)
owner_id: Optional[str] = element(tag="ownerId", default=None, nillable=True)
phase: ExecutionPhase = element(tag="phase")
quote: Optional[VODateTime] = element(tag="quote", default=None, nillable=True)
creation_time: Optional[VODateTime] = element(tag="creationTime", default=None)
start_time: Optional[VODateTime] = element(tag="startTime", default=None, nillable=True)
end_time: Optional[VODateTime] = element(tag="endTime", default=None, nillable=True)
quote: Optional[UTCTimestamp] = element(tag="quote", default=None, nillable=True)
creation_time: Optional[UTCTimestamp] = element(tag="creationTime", default=None)
start_time: Optional[UTCTimestamp] = element(tag="startTime", default=None, nillable=True)
end_time: Optional[UTCTimestamp] = element(tag="endTime", default=None, nillable=True)
execution_duration: Optional[int] = element(tag="executionDuration", default=0)
destruction: Optional[VODateTime] = element(tag="destruction", default=None, nillable=True)
destruction: Optional[UTCTimestamp] = element(tag="destruction", default=None, nillable=True)
parameters: Optional[ParametersType] = element(tag="parameters", default=None)
results: Optional[Results] = element(tag="results", default=None)
error_summary: Optional[ErrorSummary] = element(tag="errorSummary", default=None)
Expand Down
2 changes: 0 additions & 2 deletions vo_models/xml/uws/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from enum import Enum

from pydantic_xml import RootXmlModel


class ErrorType(str, Enum):
"""Enum for error types."""
Expand Down
3 changes: 3 additions & 0 deletions vo_models/xml/voresource/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Module containing VOResource classes.
"""
11 changes: 4 additions & 7 deletions vo_models/xml/generics.py → vo_models/xml/voresource/types.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
"""Definitions for useful VO objects"""
"""VOResource Simple Types"""

import re
from datetime import datetime
from typing import Optional

from pydantic import GetCoreSchemaHandler
from pydantic_core import CoreSchema, core_schema
from pydantic_xml import BaseXmlModel, RootXmlModel, computed_attr


class VODateTime(datetime):
class UTCTimestamp(datetime):
"""A subclass of datetime to allow expanded handling of ISO formatted datetimes, and enforce
the use of a Z identifier for UTC timezone in outputs
Expand Down Expand Up @@ -52,7 +50,6 @@ def __get_pydantic_core_schema__(cls, source_type, handler: GetCoreSchemaHandler
),
)


@classmethod
def _validate(cls, value: str):
"""Validator that expands the pydantic datetime model to include Z UTC identifiers
Expand All @@ -64,7 +61,7 @@ def _validate(cls, value: str):
VODateTime: VO-compliant datetime subclass
"""

if isinstance(value, VODateTime):
if isinstance(value, UTCTimestamp):
return value

if isinstance(value, datetime):
Expand Down Expand Up @@ -96,4 +93,4 @@ def isoformat(self, sep: str = "T", timespec: str = "milliseconds") -> str:
str: VO-compliant ISO-8601 datetime string
"""
iso_dt = super().isoformat(sep=sep, timespec=timespec)
return iso_dt.replace("+00:00", "Z")
return iso_dt.replace("+00:00", "Z")

0 comments on commit 26e12ad

Please sign in to comment.