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

Accept settings JSON on analysis or model creation #1067

Merged
merged 9 commits into from
Jun 27, 2024
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
52 changes: 50 additions & 2 deletions src/server/oasisapi/analyses/v2_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,25 @@
TaskErrorSerializer,
)

from ...schemas.serializers import AnalysisSettingsSerializer
from django.core.files import File
from tempfile import TemporaryFile
from ...files.models import RelatedFile


def create_settings_file(data, user):
json_serializer = AnalysisSettingsSerializer()
with TemporaryFile() as tmp_file:
tmp_file.write(data.encode('utf-8'))
tmp_file.seek(0)

return RelatedFile.objects.create(
file=File(tmp_file, name=json_serializer.filename),
filename=json_serializer.filename,
content_type='application/json',
creator=user,
)


class AnalysisTaskStatusSerializer(serializers.ModelSerializer):
output_log = serializers.SerializerMethodField()
Expand Down Expand Up @@ -65,6 +84,7 @@ class AnalysisListSerializer(serializers.Serializer):
task_started = serializers.DateTimeField(read_only=True)
task_finished = serializers.DateTimeField(read_only=True)
complex_model_data_files = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
priority = serializers.IntegerField(read_only=True)

# Groups - inherited from portfolio
groups = serializers.SerializerMethodField(read_only=True)
Expand Down Expand Up @@ -266,7 +286,7 @@ def get_settings_file(self, instance):
request = self.context.get('request')
return instance.get_absolute_settings_file_url(request=request, namespace=self.ns) if instance.settings_file_id else None

@swagger_serializer_method(serializer_or_field=serializers.URLField)
@swagger_serializer_method(serializer_or_field=AnalysisSettingsSerializer)
def get_settings(self, instance):
request = self.context.get('request')
return instance.get_absolute_settings_url(request=request, namespace=self.ns) if instance.settings_file_id else None
Expand Down Expand Up @@ -378,7 +398,6 @@ def validate(self, attrs):

# Check that portfolio has a location file and user is allowed to use the portfolio
if attrs.get('portfolio'):

try:
verify_and_get_groups(user, attrs['portfolio'].groups.all())
except ValidationError:
Expand All @@ -398,8 +417,37 @@ def validate(self, attrs):
'model': ["Model pk \"{}\" - 'run_mode' must not be null".format(attrs['model'].id)]
})

# Validate analyses settings if given at create/update
if attrs.get('settings'):
attrs['settings'] = AnalysisSettingsSerializer().validate(attrs.get('settings'))
return attrs

def to_internal_value(self, data):
settings = data.get('settings', {})
data = super(AnalysisSerializer, self).to_internal_value(data)
data['settings'] = AnalysisSettingsSerializer().to_internal_value(settings)
return data

def update(self, instance, validated_data):
data = validated_data.copy()
settings = data.pop('settings', {})
if settings:
instance.settings_file = create_settings_file(settings, instance.creator)
return super(AnalysisSerializer, self).update(instance, validated_data)

def create(self, validated_data):
data = validated_data.copy()
settings = data.pop('settings', {})
if 'request' in self.context:
data['creator'] = self.context.get('request').user

instance = super(AnalysisSerializer, self).create(data)
if settings:
instance.settings_file = create_settings_file(settings, data['creator'])

instance.save()
return instance


class AnalysisSerializerWebSocket(serializers.Serializer):
""" Minimal Analysis Infomation needed to send via WebSocket
Expand Down
4 changes: 2 additions & 2 deletions src/server/oasisapi/analyses/v2_api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ def get_queryset(self):
return super().get_queryset().select_related(*self.file_action_types).prefetch_related('complex_model_data_files')

def get_serializer_class(self):
if self.action in ['create', 'options', 'update', 'partial_update', 'retrieve']:
if self.action in ['create', 'options', 'update', 'partial_update']:
return super().get_serializer_class()
elif self.action in ['list']:
elif self.action in ['list', 'retrieve']:
return AnalysisListSerializer
elif self.action == 'copy':
return AnalysisCopySerializer
Expand Down
88 changes: 86 additions & 2 deletions src/server/oasisapi/analysis_models/v2_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,73 @@
from ..models import AnalysisModel, ModelScalingOptions, ModelChunkingOptions
from ...permissions.group_auth import validate_and_update_groups, validate_data_files

from ...schemas.serializers import ModelParametersSerializer
from django.core.files import File
from tempfile import TemporaryFile
from ...files.models import RelatedFile


def create_settings_file(data, user):
json_serializer = ModelParametersSerializer()
with TemporaryFile() as tmp_file:
tmp_file.write(data.encode('utf-8'))
tmp_file.seek(0)

return RelatedFile.objects.create(
file=File(tmp_file, name=json_serializer.filename),
filename=json_serializer.filename,
content_type='application/json',
creator=user,
)


class AnalysisModelListSerializer(serializers.Serializer):
""" Read Only Model Deserializer for efficiently returning a list of all
entries in DB
"""
id = serializers.IntegerField(read_only=True)
supplier_id = serializers.CharField(read_only=True)
model_id = serializers.CharField(read_only=True)
version_id = serializers.CharField(read_only=True)
created = serializers.DateTimeField(read_only=True)
modified = serializers.DateTimeField(read_only=True)
settings = serializers.SerializerMethodField()
versions = serializers.SerializerMethodField()
scaling_configuration = serializers.SerializerMethodField()
chunking_configuration = serializers.SerializerMethodField()
groups = serializers.SlugRelatedField(many=True, read_only=False, slug_field='name', required=False, queryset=Group.objects.all())
settings = serializers.SerializerMethodField()
run_mode = serializers.CharField(read_only=True)
namespace = 'v2-models'

@swagger_serializer_method(serializer_or_field=serializers.URLField)
def get_settings(self, instance):
request = self.context.get('request')
return instance.get_absolute_settings_url(request=request, namespace=self.namespace)

@swagger_serializer_method(serializer_or_field=serializers.URLField)
def get_versions(self, instance):
request = self.context.get('request')
return instance.get_absolute_versions_url(request=request, namespace=self.namespace)

@swagger_serializer_method(serializer_or_field=serializers.URLField)
def get_scaling_configuration(self, instance):
request = self.context.get('request')
return instance.get_absolute_scaling_configuration_url(request=request, namespace=self.namespace)

@swagger_serializer_method(serializer_or_field=serializers.URLField)
def get_chunking_configuration(self, instance):
request = self.context.get('request')
return instance.get_absolute_chunking_configuration_url(request=request, namespace=self.namespace)


class AnalysisModelSerializer(serializers.ModelSerializer):
settings = serializers.SerializerMethodField()
versions = serializers.SerializerMethodField()
scaling_configuration = serializers.SerializerMethodField()
chunking_configuration = serializers.SerializerMethodField()
groups = serializers.SlugRelatedField(many=True, read_only=False, slug_field='name', required=False, queryset=Group.objects.all())
settings = serializers.SerializerMethodField()
namespace = 'v2-models'

class Meta:
Expand Down Expand Up @@ -45,15 +105,39 @@ def validate(self, attrs):
validate_and_update_groups(self.partial, user, attrs)
validate_data_files(user, attrs.get('data_files'))

if attrs.get('settings'):
attrs['settings'] = ModelParametersSerializer().validate(attrs.get('settings'))

return attrs

def to_internal_value(self, data):
settings = data.get('settings', {})
data = super(AnalysisModelSerializer, self).to_internal_value(data)
data['settings'] = ModelParametersSerializer().to_internal_value(settings)
return data

def update(self, instance, validated_data):
data = validated_data.copy()
settings = data.pop('settings', {})
if settings:
instance.resource_file = create_settings_file(settings, instance.creator)

return super(AnalysisModelSerializer, self).update(instance, validated_data)

def create(self, validated_data):
data = validated_data.copy()
settings = data.pop('settings', {})
if 'request' in self.context:
data['creator'] = self.context.get('request').user
return super(AnalysisModelSerializer, self).create(data)

@swagger_serializer_method(serializer_or_field=serializers.URLField)
instance = super(AnalysisModelSerializer, self).create(data)
if settings:
instance.resource_file = create_settings_file(settings, data['creator'])

instance.save()
return instance

@swagger_serializer_method(serializer_or_field=ModelParametersSerializer)
def get_settings(self, instance):
request = self.context.get('request')
return instance.get_absolute_settings_url(request=request, namespace=self.namespace)
Expand Down
3 changes: 3 additions & 0 deletions src/server/oasisapi/analysis_models/v2_api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from ..models import AnalysisModel, SettingsTemplate
from .serializers import (
AnalysisModelSerializer,
AnalysisModelListSerializer,
ModelVersionsSerializer,
CreateTemplateSerializer,
TemplateSerializer,
Expand Down Expand Up @@ -194,6 +195,8 @@ class AnalysisModelViewSet(VerifyGroupAccessModelViewSet):
def get_serializer_class(self):
if self.action in ['resource_file', 'set_resource_file']:
return RelatedFileSerializer
elif self.action in ['list', 'retrieve']:
return AnalysisModelListSerializer
elif self.action in ['data_files']:
return DataFileSerializer
elif self.action in ['versions']:
Expand Down
Loading