1class Materials:
2 """Base class for all materials."""
3 def __init__(self, weight):
4 self.weight = weight
5 self.used_before = False
6
7 @property
8 def volume(self):
9 return self.weight / self.density
10
11 def mark_used_before(self):
12 self.used_before = True
13
14 def is_used_before(self):
15 return self.used_before
16
17
18class Concrete(Materials):
19 density = 2500
20
21
22class Brick(Materials):
23 density = 2000
24
25
26class Stone(Materials):
27 density = 1600
28
29
30class Wood(Materials):
31 density = 600
32
33
34class Steel(Materials):
35 density = 7700
36
37
38MATERIALS_TYPES = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone,
39 "Wood": Wood, "Steel": Steel}
40
41ALLOY_CLASSES = {}
42ALL_MATERIALS = []
43
44
45class Factory:
46 """Class that simulat a factory for creat materials and alloys from them."""
47 def __init__(self):
48 self.all_materials_for_instance = []
49
50 def _sort_material_names(self, materials_name):
51 """Sort the names of the materials alphabetically."""
52 all_parts = []
53 for name in materials_name:
54 parts = name.split("_")
55 all_parts.extend(parts)
56
57 all_parts.sort()
58 return "_".join(all_parts)
59
60 def __call__(self, *args, **kwargs):
61 """Creat new materials or alloys and add them to the factory's materials list."""
62 if not args and not kwargs:
63 raise ValueError("Cannot call this function without arguments.")
64
65 if args and kwargs:
66 raise ValueError(
67 "Cannot call this function with mix positional and keyword arguments.")
68
69 if kwargs:
70 instances = []
71 for key, weight in kwargs.items():
72 if key in MATERIALS_TYPES:
73 materials = MATERIALS_TYPES[key](weight)
74 instances.append(materials)
75 self.all_materials_for_instance.append(materials)
76 ALL_MATERIALS.append(materials)
77 elif key in ALLOY_CLASSES:
78 materials = ALLOY_CLASSES[key](weight)
79 instances.append(materials)
80 self.all_materials_for_instance.append(materials)
81 ALL_MATERIALS.append(materials)
82 else:
83 raise ValueError(f"This type - {key} - not found.")
84 return tuple(instances)
85
86 if args:
87 for material in args:
88 if not isinstance(material, Materials):
89 raise ValueError("Arguments must be instances of materials.")
90
91 if material.is_used_before():
92 raise AssertionError("This material has already been used.")
93 material.mark_used_before()
94 self.all_materials_for_instance.append(material)
95 ALL_MATERIALS.append(material)
96
97 materials_name = sorted(type(material).__name__ for material in args)
98 alloy_name = self._sort_material_names(materials_name)
99
100 if alloy_name in ALLOY_CLASSES:
101 alloy_class = ALLOY_CLASSES[alloy_name]
102 else:
103 alloy_density = sum(type(material).density for material in args) / len(args)
104 alloy_class = type(alloy_name, (Materials,), {"density": alloy_density})
105 ALLOY_CLASSES[alloy_name] = alloy_class
106
107 alloy_weight = sum(material.weight for material in args)
108 self.all_materials_for_instance.append(alloy_class(alloy_weight))
109 ALL_MATERIALS.append(alloy_class(alloy_weight))
110 return alloy_class(alloy_weight)
111
112 def can_build(self, current_volume):
113 """Check all materials created by the current instance."""
114 return sum(material.volume for material in self.all_materials_for_instance
115 if not material.is_used_before()) >= current_volume
116
117 @classmethod
118 def can_build_together(cls, current_volume):
119 """Check all materials created by all instances"""
120 return sum(material.volume for material in ALL_MATERIALS
121 if not material.is_used_before()) >= current_volume
.....FFF..
======================================================================
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 92, in __call__
raise AssertionError("This material has already been used.")
AssertionError: This material has already been used.
======================================================================
FAIL: test_positional_arguments_multiple_argument_with_dynamics (test.TestFactory.test_positional_arguments_multiple_argument_with_dynamics)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 130, in test_positional_arguments_multiple_argument_with_dynamics
self.assertAlmostEqual(mega_material.volume, 6.77, places=2) # mass=19500, density=2880
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 5.661290322580645 != 6.77 within 2 places (1.1087096774193546 difference)
======================================================================
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.Concrete'> is not <class 'solution.Concrete'>
----------------------------------------------------------------------
Ran 10 tests in 0.010s
FAILED (failures=3)
26.11.2024 17:30
26.11.2024 17:30