Package: factory-manager
Factory managerfactory-manageris a python package to create objects with their dependencies
from descriptions in the form of a dictionary.Example usageGiven the following hierarchy of Vehicles with and without a motor:>>>importabc>>>>>>classVehicle(metaclass=abc.ABCMeta):...def__init__(self):...pass...@abc.abstractmethod...defgetVehicleType(self):...pass...>>>classBicycle(Vehicle):...name='bicycle'...defgetVehicleType(self):...return'Bicycle'...>>>classEngine(metaclass=abc.ABCMeta):...def__init__(self):...self.engine_type=self.name...defgetEngineType(self):...returnself.engine_type...>>>classGasolineEngine(Engine):...name='gasoline'...>>>classElectroEngine(Engine):...name='electro'...>>>classDieselEngine(Engine):...name='diesel'...>>>classMotorizedVehicle(Vehicle):...def__init__(self,engine:Engine,registered_drivers:set=None):...self.engine=engine...ifregistered_driversisNone:...self.registered_drivers=set()...else:...self.registered_drivers=registered_drivers...>>>classCar(MotorizedVehicle):...name='car'...defgetVehicleType(self):...return'Car'+' with '+self.engine.getEngineType()+' engine'...>>>classMotorbike(MotorizedVehicle):...name='motorbike'...defgetVehicleType(self):...return'Motorbike'+' with '+self.engine.getEngineType()+' engine'We can now use aFactoryManagerto create a factory for vehicles:>>>fromfactory_managerimportFactoryManager>>>my_factories=FactoryManager()>>>my_factories.add_object_hierarchy("vehicle",Vehicle)TheFactoryManagersearches for subclasses of the given class (Vehicle) and
uses the existence of the class attributenameas an indicator that the subclass should be a type of a vehicle that the factory provides.
In the given examplemy_factoriescan be used to create bicycles, cars and motorbikes.A bicycle can be instantiated as follows (either by using the bass class or the name given toadd_object_hierarchyto select the factory):>>>my_factories.create_from_cls(Vehicle,{'type':'bicycle'}).getVehicleType()'Bicycle'>>>my_factories.create_from_name('vehicle',{'type':'bicycle'}).getVehicleType()'Bicycle'When creating a car, an engine has to be provided:>>>my_factories.create_from_name('vehicle',{'type':'car'}).getVehicleType()Traceback<...>ValueError:Missingoptions[engine]forvehicleoftypecar>>>my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':ElectroEngine()}}).getVehicleType()'Car with electro engine'Now we can also registerEnginewith theFactoryManager:>>>my_factories.add_object_hierarchy("engine",Engine)This allows us to create an engine similar to vehicle:>>>my_factories.create_from_name('engine',{'type':'electro'}).getEngineType()'electro'But it also allows us to create a vehicle and an engine in one step asmy_factoriesknows from the type hint that a motorized vehicle needs an engine:>>>my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':{'type':'electro'}}}).getVehicleType()'Car with electro engine'registered_driversdoes not need to be provided as it has a default value.
But it can be provided:>>>my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':{'type':'electro'}}}).registered_driversset()>>>sorted(...my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':{'type':'electro'},...'registered_drivers':set(['driver1','driver2'])...}}).registered_drivers)['driver1','driver2']There is no type checking, so the value forregistered_driversdoes not have to be aset:>>>my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':{'type':'electro'},...'registered_drivers':['driver1','driver2','driver1']...}}).registered_drivers['driver1','driver2','driver1']However, we can register a factory method for the typeset.
Now, the factory forVehiclewill call this factory for the provided
attribute if it is not already aset:>>>my_factories.add_factory_method(set,lambdas:set(s))>>>sorted(...my_factories.create_from_name('vehicle',{'type':'car','options':{...'engine':{'type':'electro'},...'registered_drivers':['driver1','driver2','driver1']...}}).registered_drivers)['driver1','driver2']This is useful if the dictionary used to instantiate the object comes
from json data.