A lib to help you avoid spaghetti code
Project description
Py-Macaroni
This is a library to help you avoid Spaghetti 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.
Why
When 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.
import macaroni as mci class BussinessLogic(mci.Macaroni): def validate_request(self, data): # ... def check_user_permissions(self, data): # ... def log_operation(self, data): # ... def create_item(self, data): # ... def update_item(self, data): # ... @mci.error def handle_error(self, data, error): # ... @mci.exception(DuplicateKey) def handle_duplicate_item(self, data, exception): # ... def create_item(data): bl = BussinessLogic(data) result = ( bl.validate_request() .check_user_permissions() .create_item() .log_operation() .handle_error() .handle_duplicate_item() .unwrap() ) return result def update_item(data): bl = BussinessLogic(data) result = ( bl.validate_request() .check_user_permissions() .update_item() .log_operation() .handle_error() .unwrap() ) return result
It 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.
Installation
pip install macaroni
Usage
More examples can be found in the ./examples directory.
import macaroni as mci class Calculator(mci.Macaroni): def increment(self, value, increment=None): if increment is None: increment = 1 return value + increment def divide(self, value, denominator): if denominator == 0: return mci.Error('invalid denominator {0}'.format(denominator)) return value / denominator def invalid(self, value): raise ValueError('invalid data') base_val = 10 calc = Calcultator(base_val) result = calc \ .increment(2) \ .divide(2) \ .unwrap() # this returns the final result assert result == 6
Error 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 error assert bool(calc.error) == True assert result == '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 unwrap except ValueError: pass assert bool(calc.exception) == True
When testing, you can use the parameter magic=False
to disable the automatic value passing, chaining and error/exception handling:
def test_increment(): calc = Calculator(magic=False) result = calc.increment(10, 2) assert result == 12 def test_error(): calc = Calculator(magic=False) result = calc.divide(10, 0) assert calc.error is not None assert result = 'invalid denominator 0' def test_exception() calc = Calculator(magic=False) raised_error = False try: calc.invalid(10) except ValueError: raised_error = True assert raised_error
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Filename, size | File type | Python version | Upload date | Hashes |
---|---|---|---|---|
Filename, size macaroni-0.0.3-py3-none-any.whl (5.5 kB) | File type Wheel | Python version py3 | Upload date | Hashes View |
Filename, size macaroni-0.0.3.tar.gz (4.2 kB) | File type Source | Python version None | Upload date | Hashes View |