Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ansys/rep/client/common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .base_resource import Object
from .base_schema import BaseSchema, ObjectSchema
from .restricted_value import RestrictedValue
26 changes: 26 additions & 0 deletions ansys/rep/client/common/restricted_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from marshmallow import fields
from marshmallow.exceptions import ValidationError


class RestrictedValue(fields.Field):
restricted_fields = [
fields.Int(strict=True),
fields.Bool(truthy=[True], falsy=[False]),
fields.Str(),
fields.Float(allow_nan=False),
]

def __init__(self):
super().__init__(allow_none=True)

def _deserialize(self, value, attr, obj, **kwargs):
for field in self.restricted_fields:
try:
return field._deserialize(value, attr, obj, **kwargs)
except:
pass

self.raise_validation_error()

def raise_validation_error():
raise ValidationError("Value must be of type float, integer, boolean, or string")
2 changes: 1 addition & 1 deletion ansys/rep/client/jms/resource/evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Evaluator(Object):
Which strategy to use for selecting projects to work on.
project_list : list
List of projects on which this evaluator should be working.
configuration : dict, optional
configuration : object, optional
Details of the evaluator configuration, including hardware info and available applications.
configuration_updates : EvaluatorConfigurationUpdate, optional
Changes to the evaluator configurations.
Expand Down
4 changes: 2 additions & 2 deletions ansys/rep/client/jms/resource/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ class Job(Object):
ID of the linked job definition, see :class:`JobDefinition`.
priority : int, optional
Priority with which jobs are evaluated. The default is 0, which is the highest priority. Assigning a higher value to a design point makes it a lower priority.
values : dict, optional
values : dict[str, any], optional
Dictionary with (name,value) pairs for all parameters defined in the linked job definition.
fitness : float, optional
Fitness value computed.
fitness_term_values : dict, optional
fitness_term_values : dict[str, float], optional
Dictionary with (name,value) pairs for all fitness terms computed.
note : str, optional
Optional note for this job.
Expand Down
6 changes: 3 additions & 3 deletions ansys/rep/client/jms/resource/task_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ResourceRequirements(Object):
cpu_core_usage : float, optional
disk_space : int, optional
distributed : bool, optional
custom : dict, optional
custom : dict[str, int | float | str | bool], optional

"""

Expand Down Expand Up @@ -154,9 +154,9 @@ class TaskDefinition(Object):
Script to execute (command or execution script is required).
execution_level : int
Define execution level for this task.
execution_context : dict, optional
execution_context : dict[str, int | float | str | bool], optional
Additional arguments to pass to the executing command
environment : dict, optional
environment : dict[str, str], optional
Environment variables to set for the executed process
max_execution_time : float, optional
Maximum time in seconds for executing the task.
Expand Down
6 changes: 3 additions & 3 deletions ansys/rep/client/jms/resource/task_definition_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class TemplateResourceRequirements(Object):
cpu_core_usage : TemplateProperty, optional
disk_space : TemplateProperty, optional
distributed : TemplateProperty, optional
custom : dict, optional
custom : dict[str, TemplateProperty], optional

"""

Expand Down Expand Up @@ -186,9 +186,9 @@ class TaskDefinitionTemplate(Object):
A list of required software.
resource_requirements : TemplateResourceRequirements, optional
Includes hardware requirements such as number of cores, memory and disk space.
execution_context : dict, optional
execution_context : dict[str, TemplateProperty], optional
Additional arguments to pass to the executing command.
environment : dict, optional
environment : dict[str, TemplateProperty], optional
Environment variables to set for the executed process.
execution_command : str, optional
Command to execute (command or execution script is required).
Expand Down
28 changes: 26 additions & 2 deletions ansys/rep/client/jms/schema/evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
# Author(s): F.Negri
# ----------------------------------------------------------

import marshmallow
from marshmallow import fields
from marshmallow.validate import OneOf

from ansys.rep.client.common import ObjectSchema
from ansys.rep.client.common import ObjectSchema, RestrictedValue

project_assignment_modes = ["disabled", "all_active", "project_list"]

Expand All @@ -31,6 +32,28 @@ class Meta:
custom_resource_properties = fields.Dict(allow_none=True)


class EvaluatorRegistrationConfigurationContextSchema(marshmallow.Schema):
class Meta:
unknown = marshmallow.INCLUDE

custom = fields.Dict(allow_none=True, keys=fields.Str(), values=RestrictedValue())


class EvaluatorRegistrationConfigurationResourcesSchema(marshmallow.Schema):
class Meta:
unknown = marshmallow.INCLUDE

custom = fields.Dict(allow_none=True, keys=fields.Str(), values=RestrictedValue())


class EvaluatorRegistrationConfigurationSchema(marshmallow.Schema):
class Meta:
unknown = marshmallow.INCLUDE

context = fields.Nested(EvaluatorRegistrationConfigurationContextSchema, allow_none=True)
resources = fields.Nested(EvaluatorRegistrationConfigurationResourcesSchema, allow_none=True)


class EvaluatorSchema(ObjectSchema):
class Meta:
ordered = True
Expand Down Expand Up @@ -92,7 +115,8 @@ class Meta:
fields.String,
metadata={"description": "List of projects on which this evaluator should be working."},
)
configuration = fields.Dict(
configuration = fields.Nested(
EvaluatorRegistrationConfigurationSchema,
allow_none=True,
metadata={
"description": "Details of the evaluator configuration, "
Expand Down
14 changes: 10 additions & 4 deletions ansys/rep/client/jms/schema/task_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from marshmallow import fields

from ansys.rep.client.common import BaseSchema, ObjectSchema
from ansys.rep.client.common import BaseSchema, ObjectSchema, RestrictedValue

from .object_reference import IdReference, IdReferenceList

Expand All @@ -31,7 +31,7 @@ class Meta(BaseSchema.Meta):
disk_space = fields.Int(allow_none=True)
distributed = fields.Bool(allow_none=True)

custom = fields.Dict(allow_none=True)
custom = fields.Dict(allow_none=True, keys=fields.Str(), values=RestrictedValue())


class SuccessCriteriaSchema(BaseSchema):
Expand Down Expand Up @@ -98,10 +98,16 @@ class Meta(ObjectSchema.Meta):

execution_level = fields.Int(description="Define execution level for this task.")
execution_context = fields.Dict(
allow_none=True, description="Additional arguments to pass to the executing command"
allow_none=True,
description="Additional arguments to pass to the executing command",
keys=fields.Str(),
values=RestrictedValue(),
)
environment = fields.Dict(
allow_none=True, description="Environment variables to set for the executed process"
allow_none=True,
description="Environment variables to set for the executed process",
keys=fields.Str(),
values=fields.Str(),
)
max_execution_time = fields.Float(
allow_none=True, description="Maximum time in seconds for executing the task."
Expand Down
88 changes: 59 additions & 29 deletions generate_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import marshmallow

from ansys.rep.client.common.restricted_value import RestrictedValue
from ansys.rep.client.jms.schema.object_reference import IdReference, IdReferenceList

# we define here which resources to auto-generate
Expand Down Expand Up @@ -287,47 +288,76 @@
marshmallow.fields.Nested: "object",
IdReferenceList: "list[str]",
IdReference: "str",
RestrictedValue: "int | float | str | bool",
}


def extract_field_info(name: str, field_object: marshmallow.fields, resources):

field = name
v = field_object

# Ensure that we use the attribute name if defined
if getattr(v, "attribute", None) is not None:
field = v.attribute

# build attribute doc
field_doc = f"{field}"

field_type = _extract_field_type(v, resources)
if field_type:
field_doc += f" : {field_type}"
if v.allow_none:
field_doc += ", optional"
field_doc += "\n"
elif v.allow_none:
field_doc += " : any, optional\n"
desc = v.metadata.get("description", None)
if desc:
field_doc += f" {desc}\n"

return field, field_doc


def _extract_field_type(v, resources) -> str:

if v.__class__ == marshmallow.fields.Constant:
field_type = type(v.constant).__name__
elif v.__class__ == marshmallow.fields.Nested:
field_type_schema = v.nested.__name__
field_type = next(
(r["class"] for r in resources if r["schema"] == field_type_schema),
"object",
)
else:
field_type = FIELD_MAPPING.get(v.__class__, None)
if field_type:
if v.__class__ == marshmallow.fields.Dict:
if v.key_field:
key_field_type = _extract_field_type(v.key_field, resources)
if v.value_field:
value_field_type = _extract_field_type(v.value_field, resources)
else:
value_field_type = "any"
field_type += f"[{key_field_type}, {value_field_type}]"
if hasattr(v, "many") and v.many == True:
field_type = f"list[{field_type}]"

return field_type


def declared_fields(schema, resources):
"""
Helper function to retrieve the fields that will be defined as class members for an object
"""
fields = []
fields_doc = []
for k, v in schema._declared_fields.items():
field = k
# Ensure that we use the attribute name if defined
if getattr(v, "attribute", None) is not None:
field = v.attribute
fields.append(field)

# build attribute doc
field_doc = f"{field}"
if v.__class__ == marshmallow.fields.Constant:
field_type = type(v.constant).__name__
elif v.__class__ == marshmallow.fields.Nested:
field_type_schema = v.nested.__name__
field_type = next(
(r["class"] for r in resources if r["schema"] == field_type_schema),
"object",
)
else:
field_type = FIELD_MAPPING.get(v.__class__, None)
if field_type:
if hasattr(v, "many") and v.many == True:
field_type = f"list[{field_type}]"
field_doc += f" : {field_type}"
if v.allow_none:
field_doc += ", optional"
field_doc += "\n"
elif v.allow_none:
field_doc += " : any, optional\n"
desc = v.metadata.get("description", None)
if desc:
field_doc += f" {desc}\n"
field, field_doc = extract_field_info(k, v, resources)
fields.append(field)
fields_doc.append(field_doc)

return fields, fields_doc


Expand Down
Loading