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

1"""Serializers for the machine app.""" 

2 

3from django.utils.translation import gettext_lazy as _ 

4 

5from rest_framework import serializers 

6 

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 

12 

13 

14class MachinePropertySerializer(serializers.Serializer): 

15 """Machine Properties are set by the driver/machine to represent specific state.""" 

16 

17 class Meta: 

18 """Meta for serializer.""" 

19 

20 fields = ['key', 'value', 'group', 'type', 'max_progress'] 

21 read_only_fields = fields 

22 

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 ) 

45 

46 

47class MachineConfigSerializer(serializers.ModelSerializer): 

48 """Serializer for a MachineConfig.""" 

49 

50 class Meta: 

51 """Meta for serializer.""" 

52 

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 ] 

69 

70 read_only_fields = ['machine_type', 'driver', 'properties'] 

71 

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 ) 

85 

86 def get_initialized(self, obj: MachineConfig) -> bool: 

87 """Indicator if machine is initialized.""" 

88 return getattr(obj.machine, 'initialized', False) 

89 

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 

96 

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__ 

101 

102 def get_status_text(self, obj: MachineConfig) -> str: 

103 """Current status text for machine.""" 

104 return getattr(obj.machine, 'status_text', '') 

105 

106 def get_errors(self, obj: MachineConfig) -> list[str]: 

107 """List of machine errors.""" 

108 return [str(err) for err in obj.errors] 

109 

110 def get_is_driver_available(self, obj: MachineConfig) -> bool: 

111 """Indicator if driver for machine is available.""" 

112 return obj.is_driver_available() 

113 

114 def get_restart_required(self, obj: MachineConfig) -> bool: 

115 """Indicator if machine restart is required.""" 

116 return getattr(obj.machine, 'restart_required', False) 

117 

118 

119class MachineConfigCreateSerializer(MachineConfigSerializer): 

120 """Serializer for creating a MachineConfig.""" 

121 

122 class Meta(MachineConfigSerializer.Meta): 

123 """Meta for serializer.""" 

124 

125 read_only_fields = list( 

126 set(MachineConfigSerializer.Meta.read_only_fields) 

127 - {'machine_type', 'driver'} 

128 ) 

129 

130 

131class MachineSettingSerializer(GenericReferencedSettingSerializer): 

132 """Serializer for the MachineSetting model.""" 

133 

134 MODEL = MachineSetting 

135 EXTRA_FIELDS = ['config_type'] 

136 

137 def __init__(self, *args, **kwargs): 

138 """Custom init method to make the config_type field read only.""" 

139 super().__init__(*args, **kwargs) 

140 

141 self.Meta.read_only_fields = ['config_type'] 

142 

143 

144class BaseMachineClassSerializer(serializers.Serializer): 

145 """Serializer for a BaseClass.""" 

146 

147 class Meta: 

148 """Meta for a serializer.""" 

149 

150 fields = [ 

151 'slug', 

152 'name', 

153 'description', 

154 'provider_file', 

155 'provider_plugin', 

156 'is_builtin', 

157 ] 

158 

159 read_only_fields = fields 

160 

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') 

167 

168 def get_provider_file(self, obj: ClassProviderMixin) -> str: 

169 """File that contains the class definition.""" 

170 return obj.get_provider_file() 

171 

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 

182 

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() 

186 

187 

188class MachineTypeSerializer(BaseMachineClassSerializer): 

189 """Available machine types.""" 

190 

191 class Meta(BaseMachineClassSerializer.Meta): 

192 """Meta for a serializer.""" 

193 

194 fields = [*BaseMachineClassSerializer.Meta.fields] 

195 

196 

197class MachineDriverSerializer(BaseMachineClassSerializer): 

198 """Machine drivers.""" 

199 

200 class Meta(BaseMachineClassSerializer.Meta): 

201 """Meta for a serializer.""" 

202 

203 fields = [*BaseMachineClassSerializer.Meta.fields, 'machine_type', 'errors'] 

204 

205 machine_type = serializers.SlugField(read_only=True) 

206 

207 driver_errors = serializers.SerializerMethodField('get_errors') 

208 

209 def get_errors(self, obj) -> list[str]: 

210 """Errors registered against driver.""" 

211 driver_instance = registry.get_driver_instance(obj.SLUG) 

212 

213 if driver_instance is None: 

214 return [] 

215 return [str(err) for err in driver_instance.errors] 

216 

217 

218class MachineRegistryErrorSerializer(serializers.Serializer): 

219 """Machine registry error.""" 

220 

221 class Meta: 

222 """Meta for a serializer.""" 

223 

224 fields = ['message'] 

225 

226 message = serializers.CharField() 

227 

228 

229class MachineRegistryStatusSerializer(serializers.Serializer): 

230 """Machine registry status, showing all errors that were registered.""" 

231 

232 class Meta: 

233 """Meta for a serializer.""" 

234 

235 fields = ['registry_errors'] 

236 

237 registry_errors = serializers.ListField(child=MachineRegistryErrorSerializer()) 

238 

239 

240class MachineRestartSerializer(serializers.Serializer): 

241 """Serializer for the machine restart response.""" 

242 

243 class Meta: 

244 """Meta for a serializer.""" 

245 

246 fields = ['ok'] 

247 

248 ok = serializers.BooleanField()