Skip to content

Commit

Permalink
feat!: redefine model versioning enums (#44)
Browse files Browse the repository at this point in the history
Problem:
 The existing `SchemaVersion` enum has become ambiguous. It means both
the Open Job Description revision (e.g. "v2023_09") and the template
specification versions (e.g. "jobtemplate-2023-09"). Originally, the job
template version and the spec revision were synonmous so a single enum
made sense. However, we now have multiple template kinds in a revision
('jobtemplate-2023-09' and 'environment-2023-09'), so things like the
special 'version' field of a model class are now ambiguous.

Solution:
 Split `SchemaVersion` in to two separate enums:
TemplateSpecificationVersion, and RevisionVersion. The former is for the
'specificationVersion' fields of templates, and the later is for the
specific revision of the specification. I've also changed the 'version'
field to 'revision' in all model classes.

**BREAKING CHANGE** - The SchemaVersion enum has been removed. Please
use TemplateSpecificationVersion or SpecificationRevision in its place.

Signed-off-by: Daniel Neilson <53624638+ddneilson@users.noreply.github.com>
  • Loading branch information
ddneilson authored Jan 24, 2024
1 parent c891ee1 commit c90352f
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 108 deletions.
6 changes: 4 additions & 2 deletions src/openjd/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@
OpenJDModel,
ParameterValue,
ParameterValueType,
SchemaVersion,
SpecificationRevision,
Step,
StepParameterSpace,
TaskParameterSet,
TemplateSpecificationVersion,
)
from ._version import version

Expand Down Expand Up @@ -72,7 +73,7 @@
"OpenJDModel",
"ParameterValue",
"ParameterValueType",
"SchemaVersion",
"SpecificationRevision",
"Step",
"StepDependencyGraph",
"StepDependencyGraphNode",
Expand All @@ -81,6 +82,7 @@
"StepParameterSpaceIterator",
"SymbolTable",
"TaskParameterSet",
"TemplateSpecificationVersion",
"TokenError",
"UnsupportedSchema",
"version",
Expand Down
19 changes: 11 additions & 8 deletions src/openjd/model/_create_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
JobTemplate,
ParameterValue,
ParameterValueType,
SchemaVersion,
SpecificationRevision,
TemplateSpecificationVersion,
)
from ._convert_pydantic_error import pydantic_validationerrors_to_str, ErrorDict

Expand Down Expand Up @@ -193,13 +194,15 @@ def preprocess_job_parameters(
Raises:
ValueError - If any errors are detected with the given job parameter values.
"""
if job_template.version not in (SchemaVersion.v2023_09,):
raise NotImplementedError(f"Not implemented for schema version {job_template.version}")
if job_template.revision not in (SpecificationRevision.v2023_09,):
raise NotImplementedError(
f"Not implemented for Open Job Description Job Templates from revision {str(job_template.revision.value)}"
)
if environment_templates and any(
env.version not in (SchemaVersion.v2023_09,) for env in environment_templates
env.revision not in (SpecificationRevision.v2023_09,) for env in environment_templates
):
raise NotImplementedError(
f"Not implemented for Environment Template schema versions other than {str(SchemaVersion.ENVIRONMENT_v2023_09)}"
f"Not implemented for Open Job Description Environment Templates from revisions other than {str(SpecificationRevision.v2023_09.value)}"
)

return_value: JobParameterValues = dict[str, ParameterValue]()
Expand All @@ -225,7 +228,7 @@ def preprocess_job_parameters(
if parameterDefinitions:
# Set of all required, but undefined, job parameter values
try:
if job_template.version == SchemaVersion.v2023_09:
if job_template.revision == SpecificationRevision.v2023_09:
return_value = _collect_defaults_2023_09(
parameterDefinitions,
job_parameter_values,
Expand All @@ -236,7 +239,7 @@ def preprocess_job_parameters(
_check_2023_09(parameterDefinitions, return_value)
else:
raise NotImplementedError(
f"Not implemented for schema version {job_template.version}"
f"Not implemented for schema version {str(job_template.revision.value)}"
)
except ValueError as err:
errors.append(str(err))
Expand Down Expand Up @@ -306,7 +309,7 @@ def create_job(
# Build out the symbol table for instantiating the Job.
# We just prefix all job parameter names with the appropriate prefix.
symtab = SymbolTable()
if job_template.specificationVersion == SchemaVersion.v2023_09:
if job_template.specificationVersion == TemplateSpecificationVersion.JOBTEMPLATE_v2023_09:
from .v2023_09 import ValueReferenceConstants as ValueReferenceConstants_2023_09

for name, param in all_job_parameter_values.items():
Expand Down
25 changes: 16 additions & 9 deletions src/openjd/model/_merge_job_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

from ._errors import CompatibilityError
from ._parse import parse_model
from ._types import JobParameterDefinition, JobTemplate, EnvironmentTemplate, SchemaVersion
from ._types import (
JobParameterDefinition,
JobTemplate,
EnvironmentTemplate,
TemplateSpecificationVersion,
)
from .v2023_09 import (
JobParameterType,
JobPathParameterDefinition,
Expand Down Expand Up @@ -66,14 +71,16 @@ def merge_job_parameter_definitions(
list[JobParameterDefinition]: The result of merging the Job Parameter Definitions from all of the given
templates.
"""
if job_template and job_template.specificationVersion not in (SchemaVersion.v2023_09,):
raise NotImplementedError(f"Not implemented for schema version {job_template.version}")
if job_template and job_template.specificationVersion not in (
TemplateSpecificationVersion.JOBTEMPLATE_v2023_09,
):
raise NotImplementedError(f"Not implemented for schema: {str(job_template.revision.value)}")
if environment_templates and any(
env.specificationVersion not in (SchemaVersion.ENVIRONMENT_v2023_09,)
env.specificationVersion not in (TemplateSpecificationVersion.ENVIRONMENT_v2023_09,)
for env in environment_templates
):
raise NotImplementedError(
f"Not implemented for Environment Template schema versions other than {str(SchemaVersion.ENVIRONMENT_v2023_09)}"
f"Not implemented for Environment Template schemas other than: {str(TemplateSpecificationVersion.ENVIRONMENT_v2023_09.value)}"
)

# param name -> list[SourcedParamDefinition]
Expand Down Expand Up @@ -136,11 +143,11 @@ def merge_job_parameter_definitions_for_one(
raise CompatibilityError("Parameter names differ. Please report this as a bug.")
merged_properties["name"] = name

# The two parameters must be from compatible SchemaVersions
# The two parameters must be from compatible revision versions.
# This is the same schema version right now, but may be relaxed as new versions are added.
schema_version = params[-1].definition.version
if any(param.definition.version != schema_version for param in params):
raise CompatibilityError("Parameter model versions differ.")
schema_revision = params[-1].definition.revision
if any(param.definition.revision != schema_revision for param in params):
raise CompatibilityError("Parameter models are from different specification revisions.")

# All parameters must be the same parameter type.
param_type = params[-1].definition.type
Expand Down
26 changes: 15 additions & 11 deletions src/openjd/model/_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pydantic import ValidationError as PydanticValidationError

from ._errors import DecodeValidationError
from ._types import EnvironmentTemplate, JobTemplate, OpenJDModel, SchemaVersion
from ._types import EnvironmentTemplate, JobTemplate, OpenJDModel, TemplateSpecificationVersion
from ._convert_pydantic_error import pydantic_validationerrors_to_str, ErrorDict
from .v2023_09 import JobTemplate as JobTemplate_2023_09
from .v2023_09 import EnvironmentTemplate as EnvironmentTemplate_2023_09
Expand Down Expand Up @@ -136,32 +136,36 @@ def decode_job_template(*, template: dict[str, Any]) -> JobTemplate:
# Raises: KeyError
document_version = template["specificationVersion"]
# Raises: ValueError
schema_version = SchemaVersion(document_version)
schema_version = TemplateSpecificationVersion(document_version)
except KeyError:
# Unable to get 'specificationVersion' key from the document
raise DecodeValidationError(
"Template is missing Open Job Description schema version key: specificationVersion"
)
except ValueError:
# Value of the schema version is not one we know.
values_allowed = ", ".join(str(s.value) for s in SchemaVersion.job_template_versions())
values_allowed = ", ".join(
str(s.value) for s in TemplateSpecificationVersion.job_template_versions()
)
raise DecodeValidationError(
(
f"Unknown template version: {document_version}. "
f"Values allowed for 'specificationVersion' in Job Templates are: {values_allowed}"
)
)

if not SchemaVersion.is_job_template(schema_version):
values_allowed = ", ".join(str(s.value) for s in SchemaVersion.job_template_versions())
if not TemplateSpecificationVersion.is_job_template(schema_version):
values_allowed = ", ".join(
str(s.value) for s in TemplateSpecificationVersion.job_template_versions()
)
raise DecodeValidationError(
(
f"Specification version '{document_version}' is not a Job Template version. "
f"Values allowed for 'specificationVersion' in Job Templates are: {values_allowed}"
)
)

if schema_version == SchemaVersion.v2023_09:
if schema_version == TemplateSpecificationVersion.JOBTEMPLATE_v2023_09:
return parse_model(model=JobTemplate_2023_09, obj=template)
else:
raise NotImplementedError(
Expand Down Expand Up @@ -194,7 +198,7 @@ def decode_environment_template(*, template: dict[str, Any]) -> EnvironmentTempl
# Raises: KeyError
document_version = template["specificationVersion"]
# Raises: ValueError
schema_version = SchemaVersion(document_version)
schema_version = TemplateSpecificationVersion(document_version)
except KeyError:
# Unable to get 'specificationVersion' key from the document
raise DecodeValidationError(
Expand All @@ -203,22 +207,22 @@ def decode_environment_template(*, template: dict[str, Any]) -> EnvironmentTempl
except ValueError:
# Value of the schema version is not one we know.
values_allowed = ", ".join(
str(s.value) for s in SchemaVersion.environment_template_versions()
str(s.value) for s in TemplateSpecificationVersion.environment_template_versions()
)
raise DecodeValidationError(
f"Unknown template version: {document_version}. Allowed values are: {values_allowed}"
)

if not SchemaVersion.is_environment_template(schema_version):
if not TemplateSpecificationVersion.is_environment_template(schema_version):
values_allowed = ", ".join(
str(s.value) for s in SchemaVersion.environment_template_versions()
str(s.value) for s in TemplateSpecificationVersion.environment_template_versions()
)
raise DecodeValidationError(
f"Specification version '{document_version}' is not an Environment Template version. "
f"Allowed values for 'specificationVersion' are: {values_allowed}"
)

if schema_version == SchemaVersion.ENVIRONMENT_v2023_09:
if schema_version == TemplateSpecificationVersion.ENVIRONMENT_v2023_09:
return parse_model(model=EnvironmentTemplate_2023_09, obj=template)
else:
raise NotImplementedError(
Expand Down
4 changes: 2 additions & 2 deletions src/openjd/model/_step_dependency_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from dataclasses import dataclass

from ._types import Job, SchemaVersion, Step, dataclass_kwargs
from ._types import Job, SpecificationRevision, Step, dataclass_kwargs


@dataclass(frozen=True, **dataclass_kwargs)
Expand Down Expand Up @@ -67,7 +67,7 @@ class StepDependencyGraph:
def __init__(self, *, job: Job) -> None:
# The only version supported at the moment.
# Assert's here as a signal to change this class when we add a new spec rev.
assert job.version == SchemaVersion.v2023_09
assert job.revision == SpecificationRevision.v2023_09

# Step 1 - create all of the graph nodes (one per step)
self._nodes = dict()
Expand Down
49 changes: 34 additions & 15 deletions src/openjd/model/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@
"OpenJDModel",
"ParameterValue",
"ParameterValueType",
"SchemaVersion",
"SpecificationRevision",
"Step",
"StepParameterSpace",
"TaskParameterSet",
"TemplateSpecificationVersion",
)


Expand Down Expand Up @@ -90,8 +91,10 @@ class ParameterValue:
JobParameterValues = dict[str, ParameterValue]


class SchemaVersion(str, Enum):
"""Enumerant of all Open Job Description specification versions supported by this library.
class TemplateSpecificationVersion(str, Enum):
"""Enumerant of all Open Job Description Specification version strings for
templates. This is generally the value of a template's 'specificationVersion'
field.
Special values:
UNDEFINED -- Purely for internal testing.
Expand All @@ -102,24 +105,41 @@ class SchemaVersion(str, Enum):
"""

UNDEFINED = "UNDEFINED"
v2023_09 = "jobtemplate-2023-09"
JOBTEMPLATE_v2023_09 = "jobtemplate-2023-09"
ENVIRONMENT_v2023_09 = "environment-2023-09"
# Future:
# JOBTEMPLATE_EXPERIMENTAL = "jobtemplate-experimental"
# ENVIRONMENT_EXPERIMENTAL = "environment-experimental"

@staticmethod
def job_template_versions() -> tuple[SchemaVersion, ...]:
return (SchemaVersion.v2023_09,)
def job_template_versions() -> tuple[TemplateSpecificationVersion, ...]:
return (TemplateSpecificationVersion.JOBTEMPLATE_v2023_09,)

@staticmethod
def is_job_template(version: SchemaVersion) -> bool:
return version in SchemaVersion.job_template_versions()
def is_job_template(version: TemplateSpecificationVersion) -> bool:
return version in TemplateSpecificationVersion.job_template_versions()

@staticmethod
def environment_template_versions() -> tuple[SchemaVersion, ...]:
return (SchemaVersion.ENVIRONMENT_v2023_09,)
def environment_template_versions() -> tuple[TemplateSpecificationVersion, ...]:
return (TemplateSpecificationVersion.ENVIRONMENT_v2023_09,)

@staticmethod
def is_environment_template(version: SchemaVersion) -> bool:
return version in SchemaVersion.environment_template_versions()
def is_environment_template(version: TemplateSpecificationVersion) -> bool:
return version in TemplateSpecificationVersion.environment_template_versions()


class SpecificationRevision(str, Enum):
"""Enumerant of all published Open Job Description revisions. This appears as the value
of the 'revision' property in all model instances.
Special values:
UNDEFINED -- Purely for internal testing.
"""

UNDEFINED = "UNDEFINED"
v2023_09 = "2023-09"
# Future:
# EXPERIMENTAL = "experimental"


class ResolutionScope(str, Enum):
Expand Down Expand Up @@ -257,9 +277,8 @@ class Config:
# Make the model instances immutable
frozen = True

# The specific schema version that the model implements.
_version: ClassVar[SchemaVersion] # deprecated
version: ClassVar[SchemaVersion]
# The specific schema revision that the model implements.
revision: ClassVar[SpecificationRevision]

# ----
# Metadata used for defining template variables for use in FormatStrings
Expand Down
13 changes: 7 additions & 6 deletions src/openjd/model/v2023_09/_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@
JobParameterInterface,
OpenJDModel,
ResolutionScope,
SchemaVersion,
SpecificationRevision,
TemplateSpecificationVersion,
TemplateVariableDef,
)


class OpenJDModel_v2023_09(OpenJDModel): # noqa: N801
version = SchemaVersion.v2023_09
revision = SpecificationRevision.v2023_09


class ValueReferenceConstants(Enum):
Expand Down Expand Up @@ -2158,7 +2159,7 @@ class JobTemplate(OpenJDModel_v2023_09):
"""Definition of an Open Job Description Job Template.
Attributes:
specificationVersion (SchemaVersion.v2023_09): The OpenJD schema version
specificationVersion (TemplateSpecificationVersion.v2023_09): The OpenJD schema version
whose data model this follows.
name (JobTemplateName): The name of Jobs constructed by this template.
steps (StepTemplateList): The Step Templates that comprise the Job Template.
Expand All @@ -2171,7 +2172,7 @@ class JobTemplate(OpenJDModel_v2023_09):
schemaStr (Optional[str]): Ignored. Allowed for compatibility with json editing IDEs.
"""

specificationVersion: Literal[SchemaVersion.v2023_09] # noqa: N815
specificationVersion: Literal[TemplateSpecificationVersion.JOBTEMPLATE_v2023_09] # noqa: N815
name: JobTemplateName
steps: StepTemplateList
description: Optional[Description] = None
Expand Down Expand Up @@ -2310,15 +2311,15 @@ class EnvironmentTemplate(OpenJDModel_v2023_09):
"""Definition of an Open Job Description Environment Template.
Attributes:
specificationVersion (SchemaVersion.ENVIRONMENT_v2023_09): The OpenJD schema version
specificationVersion (TemplateSpecificationVersion.ENVIRONMENT_v2023_09): The OpenJD schema version
whose data model this follows.
parameterDefinitions (Optional[JobParameterDefinitionList]): The job parameters that are available for use
within this template, and that must have values defined for them when creating jobs while this
environment template is included.
environment (Environment): The definition of the Environment that is applied.
"""

specificationVersion: Literal[SchemaVersion.ENVIRONMENT_v2023_09]
specificationVersion: Literal[TemplateSpecificationVersion.ENVIRONMENT_v2023_09]
parameterDefinitions: Optional[JobParameterDefinitionList] = None
environment: Environment

Expand Down
Loading

0 comments on commit c90352f

Please sign in to comment.