Package: construction-requirements-integrator
Construction Requirements Integrator PackageUsing this module, we can inherit classes configuring after their requirements are met (instead of being launched immediately after creation). You can see an example of this application below.In this example, theExampleclass needs three arguments,x,y, andz, to be constructed. For example, it will calculate the volume of a cube in its constructor, so it needs all the arguments simultaneously. We want to initializexandyfor ourExampleinstance using instances ofXProviderandYProviderclasses.
The problem is that bothXProviderandYProvderneed their target object to provide their values. So we need to have an uncompleted instance ofExampletillXProviderandYProviderfinish their processes. Then the instance can complete its construction.Inherit your class that needs uncompleted construction from theCRIabstract class.Pass the construction required arguments to theCRI.__init__(in the__init__function of inherited class). We will call them "construction requirements." Don't forget to set the default value of the delayable construction requirements in the__init__function of the inherited class toNone. TheNonevalue is whatCRIknows as "NOT YET"!Override abstract__construct__function in the inherited class. Arguments are the same as construction requirements.Once you get an instance of your inherited class, you can pass to it each construction requirement value that you already know as initialization arguments. After that, you can assign values to construction requirements using theinstance.meet_requirementfunction.The instance starts to complete the construction, As soon as the class requirements are met.Useconstruction_requireddecorator to avoid running a function before completion of the construction. In the example below,get_construction_statuscan be called before completion of construction, butget_volumecan not.fromconstruction_requirements_integratorimportCRI,construction_requiredfromrandomimportrandomclassXProvider:def__init__(self):self.x=int((random()*10))defprovide_for(self,obj):obj.meet_requirement(x=self.x)classYProvider:def__init__(self):self.y=int((random()*5))defprovide_for(self,obj):obj.meet_requirement(y=self.y)classExample(CRI):def__init__(self,x=None,y=None,z=None):CRI.__init__(self,x=x,y=y,z=z)def__construct__(self,x,y,z):self.x=xself.y=yself.z=zself.volume=x*y*zdefget_construction_status(self):returnself.is_constructed@construction_requireddefget_volume(self):returnself.volumeexample1=Example(z=2)XProvider().provide_for(example1)YProvider().provide_for(example1)print(example1.get_construction_status())# >>> Trueprint(example1.x,example1.y,example1.z)# >>> 6 2 2print(example1.get_volume())# >>> 24example2=Example(z=2)print(example2.get_construction_status())# >>> Falseprint(example2.get_volume())# Exception: The object is not constructed yet!When calling the__init__function from theCRIclass, you can input settings:overwrite_requirement (default: False): If true, if one construction requirement meets multiple times, the previous values will be ignored and the new value replaced. Else, based on theignore_overwrite_errorsetting, the new value will be ignored or cause an exception.ignore_overwrite_error (default: False): Ifoverwrite_requirementbe not true and one construction requirement meets multiple times, the object raises an error. The class will not publish this error ifignore_overwrite_errorbe true.auto_construct (default: True): If true, the class starts to complete the construction, As soon as the class requirements are met. If false, You must call theintegrate_requirementsfunction to complete the construction. Useignore_requirements_meeting_errorargument ofintegrate_requirementsfunction to manage raising exception it.purge_after_construction (default: True): The class does not need the construction requirements after construction (unless it stores them again during the construction process). Therefore, after completing this process, it will delete them.print(example1.__dict__)# >>> {'_CRI__reconstruct': False, 'is_constructed': True, 'x': 6, 'y': 1, 'z': 2, 'volume': 12}print(example2.__dict__)# >>> {'_CRI__requirements': {'x': None, 'y': None, 'z': 2}, '_CRI__overwrite_requirement': False, '_CRI__ignore_overwrite_error': False, '_CRI__auto_construct': True, '_CRI__purge_after_construction': True, '_CRI__reconstruct': False, 'is_constructed': False}You can prevent this deletion by settingpurge_after_constructiontoFalse.reconstruct (default: False): If true, allows to reconstruct the instance with new values. You can not set bothpurge_after_constructionandreconstructtoTruebecause reconstruction needs construction requirements. Also, note that ifauto_constructis true, everymeet_requirementcall can reconstruct the object.ignore_constructed_error (default: False): Ifreconstructbe false, and one construction requirement meets when the object is constructed, it raises an error. It will not publish this error ifignore_constructed_errorbe true.construction_permission (default: True): While it is false, it will not be possible to construct the instance. If you want the object to auto construct, but you want to ensure it will not be constructed till some event, you can initialize this setting toFalseand, after the event, flip it toTrue. Change construction permission usingset_construction_permissionfunction.add_to_construction_requirements(self, **requirements):Use this function to add to construction requirements after initialization. Its very useful when you are using inheritance.requirement_value(self, requirement):Use this function to access to value setted to a requirement. Ifpurge_after_constructionisTrue, this function will not be available after construction completion.A technique:Ifauto_constructis true and all the requirements defined in the initialization are satisfied before callingadd_to_construction_requirements, the object will complete the construction and not catch new requirements. To prevent this state, you can setconstruction_permissiontoFalse. It will prevent the object from being auto constructed until you callinstance.set_construction_permission(True). Use this function after callingadd_to_construction_requirements.fromconstruction_requirements_integratorimportCRI,construction_requiredfromrandomimportrandomclassParent(CRI):def__init__(self,x=None,y=None,construction_permission=True):CRI.__init__(self,x=x,y=y,construction_permission=construction_permission)def__construct__(self,x,y):self.x=xself.y=yself.s=self.x*self.y@construction_requireddefget_s(self):returnself.sclassChild(Parent):def__init__(self,z=None,**kwargs):super().__init__(construction_permission=False,**kwargs)self.add_to_construction_requirements(z=z)self.set_construction_permission(True)def__construct__(self,z,**kwargs):super().__construct__(**kwargs)self.z=zself.v=self.x*self.y*self.z@construction_requireddefget_v(self):returnself.vp=Parent(x=2,y=3)print(p.get_s())# >>> 6c=Child(x=2,y=3)print(c.is_constructed)# >>> Falsec.meet_requirement(z=4)print(c.is_constructed)# >>> Trueprint(c.get_v())# >>> 24c2=Child(x=2,y=3,z=4)print(c2.get_v())# >>> 24Installationpip install construction-requirements-integrator