Package: macaroni
Py-MacaroniThis is a library to help you avoidSpaghetti Code. It helps you
express your application logic in a testable way. The whole idea for this lib
was based on some concepts from functional programming and rust, mainly the
"unwrap" concept from rust.WhyWhen creating bussiness logic for your application, sometimes it gets hard to
structure complex logic in a easy to understand way. To help with that, this
library was created. The main objective is to help you structure your
application in a clean and readable way, enabling future maintenance of the
code.For example, if you have a CRUD application, some logic will be shared between
the Create and Update functions, the lib, in this case, can help by chaining
functions required to implement the main bussiness rule, and makes it easier to
reuse functions when required.importmacaroniasmciclassBussinessLogic(mci.Macaroni):defvalidate_request(self,data):# ...defcheck_user_permissions(self,data):# ...deflog_operation(self,data):# ...defcreate_item(self,data):# ...defupdate_item(self,data):# ...@mci.errordefhandle_error(self,data,error):# ...@mci.exception(DuplicateKey)defhandle_duplicate_item(self,data,exception):# ...defcreate_item(data):bl=BussinessLogic(data)result=(bl.validate_request().check_user_permissions().create_item().log_operation().handle_error().handle_duplicate_item().unwrap())returnresultdefupdate_item(data):bl=BussinessLogic(data)result=(bl.validate_request().check_user_permissions().update_item().log_operation().handle_error().unwrap())returnresultIt also helps you avoid dealing with error and exception handling on each part
of your application logic, letting you handle then only at the end of the
application execution, automatically skipping steps in your application logic
when an error or exception happens.Installationpip install macaroniUsageMore examples can be found in the./examplesdirectory.importmacaroniasmciclassCalculator(mci.Macaroni):defincrement(self,value,increment=None):ifincrementisNone:increment=1returnvalue+incrementdefdivide(self,value,denominator):ifdenominator==0:returnmci.Error('invalid denominator{0}'.format(denominator))returnvalue/denominatordefinvalid(self,value):raiseValueError('invalid data')base_val=10calc=Calcultator(base_val)result=calc\.increment(2)\.divide(2)\.unwrap()# this returns the final resultassertresult==6Error handling:calc=Calculator(10)result=calc\.increment(2)# this is executed \.divide(-3)# this causes an error \.increment()# this is not executed \.unwrap()# returns the errorassertbool(calc.error)==Trueassertresult=='invalid denominator 0'Exception handling:calc=Calculator(10)try:calc\.increment(2)# this is executed \.invalid()# this causes an exception \.increment()# this is not executed \.unwrap()# the exception ValueError is raised on unwrapexceptValueError:passassertbool(calc.exception)==TrueWhen testing, you can use the parametermagic=Falseto disable the automatic value passing, chaining and error/exception handling:deftest_increment():calc=Calculator(magic=False)result=calc.increment(10,2)assertresult==12deftest_error():calc=Calculator(magic=False)result=calc.divide(10,0)assertcalc.errorisnotNoneassertresult='invalid denominator 0'deftest_exception()calc=Calculator(magic=False)raised_error=Falsetry:calc.invalid(10)exceptValueError:raised_error=Trueassertraised_error