Skip to content

Commit df82f9f

Browse files
authored
fix(core): fix Plan.invalidated_at datetime not being timezone aware (#2823)
1 parent c61384b commit df82f9f

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

renku/command/schema/plan.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
# limitations under the License.
1818
"""Represent run templates."""
1919

20+
from datetime import timezone
21+
2022
import marshmallow
2123

2224
from renku.command.schema.calamus import JsonLDSchema, Nested, fields, prov, renku, schema
@@ -49,3 +51,14 @@ class Meta:
4951
outputs = Nested(renku.hasOutputs, CommandOutputSchema, many=True, missing=None)
5052
parameters = Nested(renku.hasArguments, CommandParameterSchema, many=True, missing=None)
5153
success_codes = fields.List(renku.successCodes, fields.Integer(), missing=[0])
54+
55+
@marshmallow.pre_dump
56+
def _pre_dump(self, in_data, **kwargs):
57+
"""Fix data on dumping."""
58+
if in_data.invalidated_at is not None and in_data.invalidated_at.tzinfo is None:
59+
# NOTE: There was a bug that caused invalidated_at to be set without timezone (as UTC time)
60+
# so we patch in the timezone here
61+
in_data.unfreeze()
62+
in_data.invalidated_at = in_data.invalidated_at.replace(microsecond=0).astimezone(timezone.utc)
63+
in_data.freeze()
64+
return in_data

renku/command/workflow.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import itertools
2222
import re
2323
from collections import defaultdict
24-
from datetime import datetime
2524
from functools import reduce
2625
from pathlib import Path
2726
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
@@ -133,7 +132,7 @@ def _remove_workflow(name: str, force: bool, plan_gateway: IPlanGateway):
133132

134133
plan = plan or workflows[name]
135134
plan.unfreeze()
136-
plan.invalidated_at = datetime.utcnow()
135+
plan.invalidated_at = local_now()
137136
plan.freeze()
138137

139138

renku/data/shacl_shape.json

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
"@id": "xsd:string"
103103
},
104104
"minCount": 1,
105-
"maxCount": 1
105+
"maxCount": 1,
106+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
106107
},
107108
{
108109
"nodeKind": "sh:Literal",
@@ -385,7 +386,8 @@
385386
"datatype": {
386387
"@id": "xsd:string"
387388
},
388-
"maxCount": 1
389+
"maxCount": 1,
390+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
389391
},
390392
{
391393
"nodeKind": "sh:Literal",
@@ -396,15 +398,17 @@
396398
"maxCount": 1,
397399
"sh:moreThanOrEquals": {
398400
"@id": "schema:dateCreated"
399-
}
401+
},
402+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
400403
},
401404
{
402405
"nodeKind": "sh:Literal",
403406
"path": "schema:datePublished",
404407
"datatype": {
405408
"@id": "xsd:string"
406409
},
407-
"maxCount": 1
410+
"maxCount": 1,
411+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
408412
},
409413
{
410414
"nodeKind": "sh:Literal",
@@ -724,7 +728,8 @@
724728
"@id": "xsd:string"
725729
},
726730
"minCount": 1,
727-
"maxCount": 1
731+
"maxCount": 1,
732+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
728733
},
729734
{
730735
"nodeKind": "sh:Literal",
@@ -735,7 +740,8 @@
735740
"maxCount": 1,
736741
"sh:moreThanOrEquals": {
737742
"@id": "schema:dateCreated"
738-
}
743+
},
744+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
739745
},
740746
{
741747
"path": "prov:entity",
@@ -1044,7 +1050,8 @@
10441050
"@id": "xsd:string"
10451051
},
10461052
"minCount": 1,
1047-
"maxCount": 1
1053+
"maxCount": 1,
1054+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
10481055
},
10491056
{
10501057
"nodeKind": "sh:Literal",
@@ -1055,7 +1062,8 @@
10551062
"maxCount": 1,
10561063
"sh:moreThanOrEquals": {
10571064
"@id": "schema:dateCreated"
1058-
}
1065+
},
1066+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
10591067
}
10601068
]
10611069
},
@@ -1455,7 +1463,8 @@
14551463
"datatype": {
14561464
"@id": "xsd:string"
14571465
},
1458-
"maxCount": 1
1466+
"maxCount": 1,
1467+
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
14591468
}
14601469
]
14611470
},

tests/core/commands/test_workflow.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919

2020

2121
from contextlib import nullcontext
22+
from datetime import datetime
2223

2324
import pytest
2425

26+
from renku.command.schema.plan import PlanSchema
2527
from renku.core import errors
2628
from renku.core.workflow.concrete_execution_graph import ExecutionGraph
2729
from renku.core.workflow.value_resolution import CompositePlanValueResolver
2830
from renku.domain_model.workflow.composite_plan import CompositePlan
31+
from renku.domain_model.workflow.plan import Plan
2932

3033

3134
def _get_nested_actual_values(run):
@@ -501,3 +504,14 @@ def test_composite_plan_auto_links(composite_plan, mappings, defaults, links, ra
501504
with maybe_raises:
502505
for virtual_link in graph.virtual_links:
503506
grouped.add_link(virtual_link[0], [virtual_link[1]])
507+
508+
509+
def test_plan_invalidated_at_datetime_export():
510+
"""The invalidated_at has a timezone on export."""
511+
plan = Plan(id=Plan.generate_id(), name="p1", command="/bin/sh")
512+
plan.invalidated_at = datetime.utcnow()
513+
514+
dumped = PlanSchema().dump(plan)
515+
516+
date = datetime.fromisoformat(dumped["http://www.w3.org/ns/prov#invalidatedAtTime"])
517+
assert date.tzinfo is not None

0 commit comments

Comments
 (0)