Coverage for src/backend/InvenTree/machine/serializers.py: 89%
100 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""Serializers for the machine app."""
3from django.utils.translation import gettext_lazy as _
5from rest_framework import serializers
7from common.serializers import GenericReferencedSettingSerializer
8from InvenTree.helpers_mixin import ClassProviderMixin
9from machine import registry
10from machine.machine_type import MachinePropertyType
11from machine.models import MachineConfig, MachineSetting
14class MachinePropertySerializer(serializers.Serializer):
15 """Machine Properties are set by the driver/machine to represent specific state."""
17 class Meta:
18 """Meta for serializer."""
20 fields = ['key', 'value', 'group', 'type', 'max_progress']
21 read_only_fields = fields
23 key = serializers.CharField(
24 label=_('Key'), help_text=_('Key of the property'), required=True
25 )
26 value = serializers.CharField(
27 label=_('Value'), help_text=_('Value of the property'), required=True
28 )
29 group = serializers.CharField(
30 label=_('Group'), help_text=_('Grouping of the property'), required=False
31 )
32 type = serializers.ChoiceField(
33 label=_('Type'),
34 choices=MachinePropertyType.__args__,
35 help_text=_('Type of the property'),
36 default='str',
37 required=False,
38 )
39 max_progress = serializers.IntegerField(
40 label=_('Max Progress'),
41 help_text=_('Maximum value for progress type, required if type=progress'),
42 required=False,
43 allow_null=True,
44 )
47class MachineConfigSerializer(serializers.ModelSerializer):
48 """Serializer for a MachineConfig."""
50 class Meta:
51 """Meta for serializer."""
53 model = MachineConfig
54 fields = [
55 'pk',
56 'name',
57 'machine_type',
58 'driver',
59 'initialized',
60 'active',
61 'status',
62 'status_model',
63 'status_text',
64 'machine_errors',
65 'is_driver_available',
66 'restart_required',
67 'properties',
68 ]
70 read_only_fields = ['machine_type', 'driver', 'properties']
72 initialized = serializers.SerializerMethodField('get_initialized')
73 status = serializers.SerializerMethodField('get_status')
74 status_model = serializers.SerializerMethodField('get_status_model')
75 status_text = serializers.SerializerMethodField('get_status_text')
76 machine_errors = serializers.SerializerMethodField('get_errors')
77 is_driver_available = serializers.SerializerMethodField('get_is_driver_available')
78 restart_required = serializers.SerializerMethodField('get_restart_required')
79 properties = serializers.ListField(
80 child=MachinePropertySerializer(),
81 source='machine.properties',
82 read_only=True,
83 default=[],
84 )
86 def get_initialized(self, obj: MachineConfig) -> bool:
87 """Indicator if machine is initialized."""
88 return getattr(obj.machine, 'initialized', False)
90 def get_status(self, obj: MachineConfig) -> int:
91 """Numerical machine status if available, else -1."""
92 status = getattr(obj.machine, 'status', None)
93 if status is not None: 93 ↛ 94line 93 didn't jump to line 94 because the condition on line 93 was never true
94 return status.value
95 return -1
97 def get_status_model(self, obj: MachineConfig) -> str | None:
98 """Textual machine status name if available, else None."""
99 if obj.machine and obj.machine.MACHINE_STATUS: 99 ↛ 100line 99 didn't jump to line 100 because the condition on line 99 was never true
100 return obj.machine.MACHINE_STATUS.__name__
102 def get_status_text(self, obj: MachineConfig) -> str:
103 """Current status text for machine."""
104 return getattr(obj.machine, 'status_text', '')
106 def get_errors(self, obj: MachineConfig) -> list[str]:
107 """List of machine errors."""
108 return [str(err) for err in obj.errors]
110 def get_is_driver_available(self, obj: MachineConfig) -> bool:
111 """Indicator if driver for machine is available."""
112 return obj.is_driver_available()
114 def get_restart_required(self, obj: MachineConfig) -> bool:
115 """Indicator if machine restart is required."""
116 return getattr(obj.machine, 'restart_required', False)
119class MachineConfigCreateSerializer(MachineConfigSerializer):
120 """Serializer for creating a MachineConfig."""
122 class Meta(MachineConfigSerializer.Meta):
123 """Meta for serializer."""
125 read_only_fields = list(
126 set(MachineConfigSerializer.Meta.read_only_fields)
127 - {'machine_type', 'driver'}
128 )
131class MachineSettingSerializer(GenericReferencedSettingSerializer):
132 """Serializer for the MachineSetting model."""
134 MODEL = MachineSetting
135 EXTRA_FIELDS = ['config_type']
137 def __init__(self, *args, **kwargs):
138 """Custom init method to make the config_type field read only."""
139 super().__init__(*args, **kwargs)
141 self.Meta.read_only_fields = ['config_type']
144class BaseMachineClassSerializer(serializers.Serializer):
145 """Serializer for a BaseClass."""
147 class Meta:
148 """Meta for a serializer."""
150 fields = [
151 'slug',
152 'name',
153 'description',
154 'provider_file',
155 'provider_plugin',
156 'is_builtin',
157 ]
159 read_only_fields = fields
161 slug = serializers.SlugField(source='SLUG')
162 name = serializers.CharField(source='NAME')
163 description = serializers.CharField(source='DESCRIPTION')
164 provider_file = serializers.SerializerMethodField('get_provider_file')
165 provider_plugin = serializers.SerializerMethodField('get_provider_plugin')
166 is_builtin = serializers.SerializerMethodField('get_is_builtin')
168 def get_provider_file(self, obj: ClassProviderMixin) -> str:
169 """File that contains the class definition."""
170 return obj.get_provider_file()
172 def get_provider_plugin(self, obj: ClassProviderMixin) -> dict | None:
173 """Plugin(s) that contain(s) the class definition."""
174 plugin = obj.get_provider_plugin()
175 if plugin: 175 ↛ 176line 175 didn't jump to line 176 because the condition on line 175 was never true
176 return {
177 'slug': plugin.slug,
178 'name': plugin.human_name,
179 'pk': getattr(plugin.plugin_config(), 'pk', None),
180 }
181 return None
183 def get_is_builtin(self, obj: ClassProviderMixin) -> bool:
184 """Indicates if the machine type is build into the InvenTree source code."""
185 return obj.get_is_builtin()
188class MachineTypeSerializer(BaseMachineClassSerializer):
189 """Available machine types."""
191 class Meta(BaseMachineClassSerializer.Meta):
192 """Meta for a serializer."""
194 fields = [*BaseMachineClassSerializer.Meta.fields]
197class MachineDriverSerializer(BaseMachineClassSerializer):
198 """Machine drivers."""
200 class Meta(BaseMachineClassSerializer.Meta):
201 """Meta for a serializer."""
203 fields = [*BaseMachineClassSerializer.Meta.fields, 'machine_type', 'errors']
205 machine_type = serializers.SlugField(read_only=True)
207 driver_errors = serializers.SerializerMethodField('get_errors')
209 def get_errors(self, obj) -> list[str]:
210 """Errors registered against driver."""
211 driver_instance = registry.get_driver_instance(obj.SLUG)
213 if driver_instance is None:
214 return []
215 return [str(err) for err in driver_instance.errors]
218class MachineRegistryErrorSerializer(serializers.Serializer):
219 """Machine registry error."""
221 class Meta:
222 """Meta for a serializer."""
224 fields = ['message']
226 message = serializers.CharField()
229class MachineRegistryStatusSerializer(serializers.Serializer):
230 """Machine registry status, showing all errors that were registered."""
232 class Meta:
233 """Meta for a serializer."""
235 fields = ['registry_errors']
237 registry_errors = serializers.ListField(child=MachineRegistryErrorSerializer())
240class MachineRestartSerializer(serializers.Serializer):
241 """Serializer for the machine restart response."""
243 class Meta:
244 """Meta for a serializer."""
246 fields = ['ok']
248 ok = serializers.BooleanField()