Skip to content

Commit 9518110

Browse files
committed
docs: Update readme info on creating model objects
Some of the sample code in the README.md no longer worked after the change for RFC 0002. https://github.com/OpenJobDescription/openjd-specifications/blob/mainline/rfcs/0002-model-extensions.md updated OpenJD to make the fields and validation of template components depend on an 'extensions' property at the top level of the template. Implementing this in the model library involved adding a model parsing context that objects look at during construction and validation. This change adds a docstring for the parse_model function and updates the broken examples to explain how the extensions fit in and how to create model objects. Signed-off-by: Mark <[email protected]>
1 parent 907b262 commit 9518110

File tree

2 files changed

+113
-60
lines changed

2 files changed

+113
-60
lines changed

README.md

Lines changed: 101 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -40,85 +40,126 @@ Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines.
4040

4141
## Example Usage
4242

43-
### Reading and Validating a Template File
43+
### Reading and Validating a Job Template
44+
45+
To validate a job template, you can read the JSON or YAML input
46+
into Python data structures and then pass the result to `decode_job_template`.
47+
By default, this will accept templates of any supported version number with
48+
no extensions enabled. Use `decode_environment_template` for environment templates.
49+
50+
To accept extensions in templates, provide the list of the names you support. See the
51+
[Open Job Description 2023-09 specification](https://github.com/OpenJobDescription/openjd-specifications/wiki/2023-09-Template-Schemas#1-root-elements)
52+
for the list of extensions available.
4453

4554
```python
46-
from openjd.model import (
47-
DecodeValidationError,
48-
DocumentType,
49-
JobTemplate,
50-
document_string_to_object,
51-
decode_job_template
52-
)
55+
from openjd.model import DocumentType, decode_job_template, document_string_to_object
5356

5457
# String containing the json of the job template
55-
template_string = "..."
56-
try:
57-
template_object = document_string_to_object(
58-
document=template_string,
59-
document_type=DocumentType.JSON
60-
)
61-
# Use 'decode_environment_template()' instead if decoding an
62-
# Environment Template
63-
job_template = decode_job_template(template=template_object)
64-
except DecodeValidationError as e:
65-
print(str(e))
58+
template_string = """specificationVersion: jobtemplate-2023-09
59+
name: DemoJob
60+
steps:
61+
- name: DemoStep
62+
script:
63+
actions:
64+
onRun:
65+
command: python
66+
args: ["-c", "print('Hello')"]
67+
"""
68+
69+
# You can use 'json.loads' or 'yaml.safe_load' directly as well
70+
template_object = document_string_to_object(
71+
document=template_string,
72+
document_type=DocumentType.YAML
73+
)
74+
75+
# Raises a DecodeValidationError if it fails.
76+
job_template = decode_job_template(template=template_object, supported_extensions=["TASK_CHUNKING"])
6677
```
6778

68-
### Creating a Template Model
79+
Once you have the Open Job Description model object, you can use the `model_to_object` function
80+
to convert it into an object suitable for converting to JSON or YAML.
6981

7082
```python
71-
from openjd.model.v2023_09 import *
72-
73-
job_template = JobTemplate(
74-
specificationVersion="jobtemplate-2023-09",
75-
name="DemoJob",
76-
steps=[
77-
StepTemplate(
78-
name="DemoStep",
79-
script=StepScript(
80-
actions=StepActions(
81-
onRun=Action(
82-
command="python",
83-
args=["-c", "print('Hello world!')"]
84-
)
85-
)
86-
)
87-
)
88-
]
83+
import json
84+
from openjd.model import model_to_object
85+
86+
obj = model_to_object(model=job_template)
87+
print(json.dumps(obj, indent=2))
88+
```
89+
90+
### Creating Template Model Objects
91+
92+
As an alternative to assembling full job templates as raw data following the specification data model,
93+
you can use the library to construct model objects of components, such as for StepTemplates,
94+
and then assemble the result into a job template. The `parse_model` function provides a way to
95+
do this.
96+
97+
To call `parse_model`, you will need to provide the list of extensions you want to enable as the
98+
`supported_extensions` argument. Individual model objects can accept inputs differently depending on
99+
what extensions are requested in the job template, and the model parsing context holds that list.
100+
The functions `decode_job_template` and `decode_environment_template` create this
101+
context from top-level template fields, but when using `parse_model` to process interior model types
102+
you must provide it explicitly.
103+
104+
```python
105+
import json
106+
from openjd.model import parse_model, model_to_object
107+
from openjd.model.v2023_09 import StepTemplate
108+
109+
extensions_list = ["TASK_CHUNKING"]
110+
111+
step_template = parse_model(
112+
model=StepTemplate,
113+
obj={
114+
"name": "DemoStep",
115+
"script": {
116+
"actions": {"onRun": {"command": "python", "args": ["-c", "print('Hello world!')"]}}
117+
},
118+
},
119+
supported_extensions=extensions_list,
89120
)
121+
122+
obj = model_to_object(model=step_template)
123+
print(json.dumps(obj, indent=2))
90124
```
91125

92-
### Converting a Template Model to a Dictionary
126+
You can also construct the individual elements of the template from the model object types.
127+
This can be more effort than using `parse_model` depending on how the enabled extensions
128+
affect processing. You will need to create a ModelParsingContext object to hold
129+
the extensions list, and pass it to any model object constructors that need it.
93130

94131
```python
95132
import json
96-
from openjd.model import (
97-
decode_job_template,
98-
model_to_object,
133+
from openjd.model import model_to_object
134+
from openjd.model.v2023_09 import (
135+
StepTemplate,
136+
StepScript,
137+
StepActions,
138+
Action,
139+
ArgString,
140+
CommandString,
141+
ModelParsingContext,
99142
)
100-
from openjd.model.v2023_09 import *
101-
102-
job_template = JobTemplate(
103-
specificationVersion="jobtemplate-2023-09",
104-
name="DemoJob",
105-
steps=[
106-
StepTemplate(
107-
name="DemoStep",
108-
script=StepScript(
109-
actions=StepActions(
110-
onRun=Action(
111-
command="echo",
112-
args=["Hello world"]
113-
)
114-
)
143+
144+
context = ModelParsingContext(supported_extensions=["TASK_CHUNKING"])
145+
146+
step_template = StepTemplate(
147+
name="DemoStep",
148+
script=StepScript(
149+
actions=StepActions(
150+
onRun=Action(
151+
command=CommandString("python", context=context),
152+
args=[
153+
ArgString("-c", context=context),
154+
ArgString("print('Hello world!')", context=context),
155+
],
115156
)
116157
)
117-
]
158+
),
118159
)
119160

120-
obj = model_to_object(model=job_template)
121-
print(json.dumps(obj))
161+
obj = model_to_object(model=step_template)
162+
print(json.dumps(obj, indent=2))
122163
```
123164

124165
### Creating a Job from a Job Template

src/openjd/model/_parse.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ def _parse_model(*, model: Type[T], obj: Any, context: Any = None) -> T:
9696
def parse_model(
9797
*, model: Type[T], obj: Any, supported_extensions: Optional[Iterable[str]] = None
9898
) -> T:
99+
"""
100+
Parses an Open Job Description model object from an object following the Open Job Description
101+
specification.
102+
103+
Arguments:
104+
model: The Open Job Description model type, e.g. JobTemplate or JobParameterDefinition.
105+
obj: The object to parse, e.g. {"specificationVersion": "2023-09", ...}
106+
supported_extensions (optional): If the model type is a base template like JobTemplate or EnvironmentTemplate,
107+
this is the list of extensions to allow in parsing the object. Otherwise, it is
108+
the list of extensions that are accepted for parsing as if they were listed in the
109+
base template's extensions field.
110+
"""
99111
try:
100112
return _parse_model(
101113
model=model,

0 commit comments

Comments
 (0)