1class Material:
2 def __init__(self, mass):
3 self.mass = mass
4 self._is_used = False
5
6 @property
7 def volume(self):
8 return self.mass / self.density
9
10 def mark_as_used(self):
11 self._is_used = True
12
13 def check_is_used(self):
14 if self._is_used:
15 raise AssertionError("This material is already used")
16
17 def get_is_used(self):
18 return self._is_used
19
20class Concrete(Material):
21 density = 2500
22
23class Brick(Material):
24 density = 2000
25
26class Stone(Material):
27 density = 1600
28
29class Wood(Material):
30 density = 600
31
32class Steel(Material):
33 density = 7700
34
35class Factory:
36 _dynamic_classes = {}
37 _factories = []
38 def __init__(self):
39 self.materials = []
40 Factory._factories.append(self)
41
42 def __call__(self, *args, **kwargs):
43 if args and kwargs:
44 raise ValueError("Cannot mix positional and keyword arguments")
45 if not args and not kwargs:
46 raise ValueError("There must be at least one argument")
47 if args:
48 types_of_given_materials = []
49 for material in args:
50 material.check_is_used()
51 material.mark_as_used()
52 material_type = type(material)
53 if material_type in Factory._dynamic_classes.values():
54 composite_elements = material_type.__name__.split("_")
55 types_of_given_materials.extend([globals()[comp] for comp in composite_elements])
56 else:
57 types_of_given_materials.append(material_type)
58 sorted_types_of_materials = sorted(set(types_of_given_materials), key=lambda cls: cls.__name__)
59 name_of_the_composition = "_".join(cls.__name__ for cls in sorted_types_of_materials)
60 if name_of_the_composition not in Factory._dynamic_classes:
61 composition_density = sum(cls.density for cls in sorted_types_of_materials) / len(sorted_types_of_materials)
62 class CreateMaterial(Material):
63 density = composition_density
64 CreateMaterial.__name__ = name_of_the_composition
65 Factory._dynamic_classes[name_of_the_composition] = CreateMaterial
66 current_material_class = Factory._dynamic_classes[name_of_the_composition]
67 mass_of_current_material = sum(material.mass for material in args)
68 current_material = current_material_class(mass_of_current_material)
69 self.materials.append(current_material)
70 return current_material
71 if kwargs:
72 list_of_materials = []
73 for material_name, mass in kwargs.items():
74 material = self._get_class_by_name(material_name)
75 if not material:
76 raise ValueError("Invalid input")
77 list_of_materials.append(material(mass))
78 self.materials.extend(list_of_materials)
79 return tuple(list_of_materials)
80
81 @staticmethod
82 def _get_class_by_name(name):
83 return globals().get(name) or Factory._dynamic_classes.get(name)
84
85 def can_build(self, volume):
86 full_volume = sum(material.volume for material in self.materials if not material.get_is_used())
87 return full_volume >= volume
88
89 @classmethod
90 def can_build_together(cls, volume):
91 all_materials = []
92 for factory in cls._factories:
93 all_materials.extend(factory.materials)
94
95 full_volume = sum(material.volume for material in all_materials if not material.get_is_used())
96 return full_volume >= volume
.....F.F..
======================================================================
FAIL: test_positional_arguments_multiple_argument_from_initial_set (test.TestFactory.test_positional_arguments_multiple_argument_from_initial_set)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 116, in test_positional_arguments_multiple_argument_from_initial_set
concrete_wood = self.factory1(concrete, wood)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 50, in __call__
material.check_is_used()
File "/tmp/solution.py", line 15, in check_is_used
raise AssertionError("This material is already used")
AssertionError: This material is already used
======================================================================
FAIL: test_positional_arguments_single_argument (test.TestFactory.test_positional_arguments_single_argument)
Test calling a factory using a sigle positional argument.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_positional_arguments_single_argument
self.assertIs(type(concrete2), solution.Concrete)
AssertionError: <class 'solution.Factory.__call__.<locals>.CreateMaterial'> is not <class 'solution.Concrete'>
----------------------------------------------------------------------
Ran 10 tests in 0.010s
FAILED (failures=2)
25.11.2024 11:15
25.11.2024 11:23
25.11.2024 11:25
25.11.2024 11:30
25.11.2024 11:17