Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): fix Plan.invalidated_at datetime not being timezone aware #2823

Merged
merged 3 commits into from Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions renku/command/schema/plan.py
Expand Up @@ -17,6 +17,8 @@
# limitations under the License.
"""Represent run templates."""

from datetime import timezone

import marshmallow

from renku.command.schema.calamus import JsonLDSchema, Nested, fields, prov, renku, schema
Expand Down Expand Up @@ -49,3 +51,14 @@ class Meta:
outputs = Nested(renku.hasOutputs, CommandOutputSchema, many=True, missing=None)
parameters = Nested(renku.hasArguments, CommandParameterSchema, many=True, missing=None)
success_codes = fields.List(renku.successCodes, fields.Integer(), missing=[0])

@marshmallow.pre_dump
def _pre_dump(self, in_data, **kwargs):
"""Fix data on dumping."""
if in_data.invalidated_at is not None and in_data.invalidated_at.tzinfo is None:
# NOTE: There was a bug that caused invalidated_at to be set without timezone (as UTC time)
# so we patch in the timezone here
in_data.unfreeze()
in_data.invalidated_at = in_data.invalidated_at.replace(microsecond=0).astimezone(timezone.utc)
in_data.freeze()
return in_data
3 changes: 1 addition & 2 deletions renku/command/workflow.py
Expand Up @@ -21,7 +21,6 @@
import itertools
import re
from collections import defaultdict
from datetime import datetime
from functools import reduce
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
Expand Down Expand Up @@ -133,7 +132,7 @@ def _remove_workflow(name: str, force: bool, plan_gateway: IPlanGateway):

plan = plan or workflows[name]
plan.unfreeze()
plan.invalidated_at = datetime.utcnow()
plan.invalidated_at = local_now()
plan.freeze()


Expand Down
27 changes: 18 additions & 9 deletions renku/data/shacl_shape.json
Expand Up @@ -102,7 +102,8 @@
"@id": "xsd:string"
},
"minCount": 1,
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
Expand Down Expand Up @@ -385,7 +386,8 @@
"datatype": {
"@id": "xsd:string"
},
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
Expand All @@ -396,15 +398,17 @@
"maxCount": 1,
"sh:moreThanOrEquals": {
"@id": "schema:dateCreated"
}
},
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
"path": "schema:datePublished",
"datatype": {
"@id": "xsd:string"
},
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
Expand Down Expand Up @@ -724,7 +728,8 @@
"@id": "xsd:string"
},
"minCount": 1,
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
Expand All @@ -735,7 +740,8 @@
"maxCount": 1,
"sh:moreThanOrEquals": {
"@id": "schema:dateCreated"
}
},
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"path": "prov:entity",
Expand Down Expand Up @@ -1044,7 +1050,8 @@
"@id": "xsd:string"
},
"minCount": 1,
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
},
{
"nodeKind": "sh:Literal",
Expand All @@ -1055,7 +1062,8 @@
"maxCount": 1,
"sh:moreThanOrEquals": {
"@id": "schema:dateCreated"
}
},
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
}
]
},
Expand Down Expand Up @@ -1455,7 +1463,8 @@
"datatype": {
"@id": "xsd:string"
},
"maxCount": 1
"maxCount": 1,
"sh:pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}:\\d{2}"
}
]
},
Expand Down
14 changes: 14 additions & 0 deletions tests/core/commands/test_workflow.py
Expand Up @@ -19,13 +19,16 @@


from contextlib import nullcontext
from datetime import datetime

import pytest

from renku.command.schema.plan import PlanSchema
from renku.core import errors
from renku.core.workflow.concrete_execution_graph import ExecutionGraph
from renku.core.workflow.value_resolution import CompositePlanValueResolver
from renku.domain_model.workflow.composite_plan import CompositePlan
from renku.domain_model.workflow.plan import Plan


def _get_nested_actual_values(run):
Expand Down Expand Up @@ -501,3 +504,14 @@ def test_composite_plan_auto_links(composite_plan, mappings, defaults, links, ra
with maybe_raises:
for virtual_link in graph.virtual_links:
grouped.add_link(virtual_link[0], [virtual_link[1]])


def test_plan_invalidated_at_datetime_export():
"""The invalidated_at has a timezone on export."""
plan = Plan(id=Plan.generate_id(), name="p1", command="/bin/sh")
plan.invalidated_at = datetime.utcnow()

dumped = PlanSchema().dump(plan)

date = datetime.fromisoformat(dumped["http://www.w3.org/ns/prov#invalidatedAtTime"])
assert date.tzinfo is not None