Skip to content

Commit

Permalink
wip-imps
Browse files Browse the repository at this point in the history
  • Loading branch information
aaxelb committed Feb 22, 2024
1 parent 46ce540 commit 4f59f0a
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 67 deletions.
2 changes: 1 addition & 1 deletion addon_service/authorized_storage_account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def authorized_operations(self) -> list[StorageOperationModel]:
return [
StorageOperationModel(_imp)
for _imp in get_operation_implementations(
self.external_storage_service.storage_implementation_cls,
self.external_storage_service.storage_imp.imp_cls,
capabilities=self.authorized_capabilities_enum,
)
]
6 changes: 4 additions & 2 deletions addon_service/authorized_storage_account/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from rest_framework_json_api.utils import get_resource_type_from_model

from addon_service.capability.serializers import IntStorageCapabilityMultipleChoiceField
from addon_service.common.serializer_fields import DataclassRelatedField
from addon_service.models import (
AuthorizedStorageAccount,
ConfiguredStorageAddon,
Expand All @@ -14,7 +15,7 @@
ExternalStorageService,
UserReference,
)
from addon_service.storage_operation.serializers import StorageOperationRelationField
from addon_service.storage_operation.models import StorageOperationModel


RESOURCE_TYPE = get_resource_type_from_model(AuthorizedStorageAccount)
Expand Down Expand Up @@ -64,7 +65,8 @@ def __init__(self, *args, **kwargs):
related_link_view_name=RELATED_LINK_VIEW_NAME,
required=False,
)
authorized_operations = StorageOperationRelationField(
authorized_operations = DataclassRelatedField(
dataclass_model=StorageOperationModel,
related_link_view_name=RELATED_LINK_VIEW_NAME,
)
username = serializers.CharField(
Expand Down
16 changes: 16 additions & 0 deletions addon_service/common/serializer_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import dataclasses

from rest_framework_json_api.relations import (
ResourceRelatedField,
SkipDataMixin,
)


class DataclassRelatedField(SkipDataMixin, ResourceRelatedField):
def __init__(self, /, dataclass_model, **kwargs):
assert dataclasses.is_dataclass(dataclass_model)
return super().__init__(
read_only=True,
model=dataclass_model,
**kwargs,
)
6 changes: 4 additions & 2 deletions addon_service/configured_storage_addon/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
from rest_framework_json_api.utils import get_resource_type_from_model

from addon_service.capability.serializers import IntStorageCapabilityMultipleChoiceField
from addon_service.common.serializer_fields import DataclassRelatedField
from addon_service.models import (
AuthorizedStorageAccount,
ConfiguredStorageAddon,
ResourceReference,
)
from addon_service.storage_operation.serializers import StorageOperationRelationField
from addon_service.storage_operation.models import StorageOperationModel


RESOURCE_TYPE = get_resource_type_from_model(ConfiguredStorageAddon)
Expand All @@ -28,7 +29,8 @@ class ConfiguredStorageAddonSerializer(serializers.HyperlinkedModelSerializer):
root_folder = serializers.CharField(required=False)
url = serializers.HyperlinkedIdentityField(view_name=SELF_LINK_VIEW_NAME)
connected_capabilities = IntStorageCapabilityMultipleChoiceField()
connected_operations = StorageOperationRelationField(
connected_operations = DataclassRelatedField(
dataclass_model=StorageOperationModel,
related_link_view_name=RELATED_LINK_VIEW_NAME,
)
base_account = ResourceRelatedField(
Expand Down
12 changes: 2 additions & 10 deletions addon_service/external_storage_service/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
from addon_service.common.base_model import AddonsServiceBaseModel
from addon_service.storage_imp.known import IntStorageImp
from addon_service.storage_imp.models import StorageImpModel
from addon_service.storage_operation.models import StorageOperationModel
from addon_toolkit import get_operation_implementations


class ExternalStorageService(AddonsServiceBaseModel):
Expand Down Expand Up @@ -32,11 +30,5 @@ class JSONAPIMeta:

@property
def storage_imp(self) -> StorageImpModel:
return StorageImpModel(IntStorageImp(self.int_storage_imp).to_original_enum())

@property
def supported_operations(self) -> list[StorageOperationModel]:
return [
StorageOperationModel(_imp)
for _imp in get_operation_implementations(self.storage_implementation_cls)
]
_imp_cls = IntStorageImp(self.int_storage_imp).to_original_enum().value
return StorageImpModel(_imp_cls)
14 changes: 5 additions & 9 deletions addon_service/external_storage_service/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from rest_framework_json_api import serializers
from rest_framework_json_api.utils import get_resource_type_from_model

from addon_service.common.serializer_fields import DataclassRelatedField
from addon_service.models import ExternalStorageService
from addon_service.storage_imp.serializers import StorageImpRelationField
from addon_service.storage_operation.serializers import StorageOperationRelationField
from addon_service.storage_imp.models import StorageImpModel


RESOURCE_TYPE = get_resource_type_from_model(ExternalStorageService)
Expand All @@ -13,15 +13,12 @@

class ExternalStorageServiceSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name=SELF_LINK_VIEW_NAME)
storage_imp = StorageImpRelationField(
storage_imp = DataclassRelatedField(
dataclass_model=StorageImpModel,
related_link_view_name=RELATED_LINK_VIEW_NAME,
)
supported_operations = StorageOperationRelationField(
related_link_view_name=RELATED_LINK_VIEW_NAME,
)

included_serializers = {
"supported_operations": "addon_service.serializers.StorageOperationSerializer",
"storage_imp": "addon_service.serializers.StorageImpSerializer",
}

class Meta:
Expand All @@ -31,6 +28,5 @@ class Meta:
"max_concurrent_downloads",
"max_upload_mb",
"auth_uri",
"supported_operations",
"storage_imp",
]
2 changes: 2 additions & 0 deletions addon_service/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ExternalStorageServiceSerializer,
)
from addon_service.resource_reference.serializers import ResourceReferenceSerializer
from addon_service.storage_imp.serializers import StorageImpSerializer
from addon_service.storage_operation.serializers import StorageOperationSerializer
from addon_service.storage_operation_invocation.serializers import (
StorageOperationInvocationSerializer,
Expand All @@ -22,6 +23,7 @@
"ConfiguredStorageAddonSerializer",
"ExternalStorageServiceSerializer",
"ResourceReferenceSerializer",
"StorageImpSerializer",
"StorageOperationInvocationSerializer",
"StorageOperationSerializer",
"UserReferenceSerializer",
Expand Down
22 changes: 18 additions & 4 deletions addon_service/storage_imp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,42 @@
ApiStorageImp,
StorageImp,
)
from addon_toolkit import get_operation_implementations


# not a database model; represents an implementation
# of StorageInterface in a form easy to give the serializer
@dataclasses.dataclass
class StorageImpModel:
storage_imp: StorageImp
imp_cls: type

@classmethod
def get_by_pk(cls, pk: str) -> "StorageImpModel":
_imp_name = unmake_opaque(pk)
_imp: StorageImp = ApiStorageImp[_imp_name].to_original_enum()
return cls(_imp)
return cls(_imp.value)

@property
def pk(self) -> str:
return make_opaque(self.name)

@property
def name(self) -> str:
return ApiStorageImp.from_original_enum_value(self.storage_imp).value
return ApiStorageImp.from_original_enum_value(self.imp_cls).value

@property
def docstring(self) -> str:
return self.storage_imp.__doc__ or ""
return self.imp_cls.__doc__ or ""

@property
def implemented_operations(self) -> list:
# TODO: reorganize to avoid this inline import
from addon_service.storage_operation.models import StorageOperationModel

return [
StorageOperationModel(_imp_op)
for _imp_op in get_operation_implementations(self.imp_cls)
]

class JSONAPIMeta:
resource_name = "storage-imps"
40 changes: 19 additions & 21 deletions addon_service/storage_imp/serializers.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
from rest_framework_json_api import serializers
from rest_framework_json_api.relations import (
ResourceRelatedField,
SkipDataMixin,
)
from rest_framework_json_api.utils import get_resource_type_from_model

from addon_service.common.serializer_fields import DataclassRelatedField
from addon_service.storage_operation.models import StorageOperationModel

from .models import StorageImpModel


# note: most other serializers get resource_type from the db model
# (for rest_framework_json_api to behave correctly) but operations
# are declared as dataclasses, not stored in a database
RESOURCE_TYPE = "storage-imps"
RESOURCE_TYPE = get_resource_type_from_model(StorageImpModel)
SELF_LINK_VIEW_NAME = f"{RESOURCE_TYPE}-detail"
RELATED_LINK_VIEW_NAME = f"{RESOURCE_TYPE}-related"


class StorageImpSerializer(serializers.Serializer):
url = serializers.HyperlinkedIdentityField(view_name=SELF_LINK_VIEW_NAME)
name = serializers.CharField(read_only=True)
docstring = serializers.CharField(read_only=True)
# TODO operation_parameters = ListField(

class JSONAPIMeta:
resource_name = RESOURCE_TYPE


class StorageImpRelationField(SkipDataMixin, ResourceRelatedField):
def __init__(self, **kwargs):
return super().__init__(
many=True,
read_only=True,
model=StorageImpModel,
**kwargs,
)
implemented_operations = DataclassRelatedField(
dataclass_model=StorageOperationModel,
related_link_view_name=RELATED_LINK_VIEW_NAME,
)

class Meta:
model = StorageImpModel
fields = [
"url",
"name",
"docstring",
"implemented_operations",
]
5 changes: 4 additions & 1 deletion addon_service/storage_operation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,7 @@ def capability(self):

@property
def implemented_by(self) -> StorageImpModel:
return StorageImpModel(StorageImp(self.imp.implementation_cls))
return StorageImpModel(self.imp.implementation_cls)

class JSONAPIMeta:
resource_name = "storage-operations"
26 changes: 9 additions & 17 deletions addon_service/storage_operation/serializers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
from rest_framework_json_api import serializers
from rest_framework_json_api.relations import (
ResourceRelatedField,
SkipDataMixin,
)

from addon_service.capability.serializers import StorageCapabilityChoiceField
from addon_service.storage_imp.serializers import StorageImpRelationField
from addon_service.common.serializer_fields import DataclassRelatedField
from addon_service.storage_imp.models import StorageImpModel

from .models import StorageOperationModel

Expand All @@ -24,20 +21,15 @@ class StorageOperationSerializer(serializers.Serializer):
docstring = serializers.CharField(read_only=True)
implementation_docstring = serializers.CharField(read_only=True)
capability = StorageCapabilityChoiceField(read_only=True)
implemented_by = StorageImpRelationField(
implemented_by = DataclassRelatedField(
dataclass_model=StorageImpModel,
related_link_view_name=RELATED_LINK_VIEW_NAME,
)
# TODO operation_parameters = ListField(

class JSONAPIMeta:
resource_name = RESOURCE_TYPE
included_serializers = {
"implemented_by": "addon_service.serializers.StorageImpSerializer",
}


class StorageOperationRelationField(SkipDataMixin, ResourceRelatedField):
def __init__(self, **kwargs):
return super().__init__(
many=True,
read_only=True,
model=StorageOperationModel,
**kwargs,
)
class Meta:
model = StorageOperationModel

0 comments on commit 4f59f0a

Please sign in to comment.