Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a good pattern to raise exceptions in a python decorator?

Context: I have Flask routes defined for different API endpoints and each endpoint calls a controller class with certain parameters (uid, project_id, etc.).

@app.route('/sample/route', methods=['POST'])
@require_json_payload
@require_fields({
    'pid',
    'params'
})
def route_handler(arg1, arg2):
    #input filtering
    ...

    try:
        proj_cntr.sample_method(
            pid         = pid,
            ...         = ...
        )
    except ProjCntrException:
        #handle error

    #response generation
    ...

The controller (proj_cntr) is responsible for determining, say, if the given PID is valid, wether the given user is allowed to perform the action, and other business logic validation.

I noticed that I am c/pasting a lot of code like this in different controllers:

if not project_object:
    sys_logger.info('...')
    raise ProjCntrException('PID %d does not exist' % pid)

Putting these checks (validations) in decorators seems like the best thing to do. But I am not sure which error handling pattern is best practice should the validation not pass.

1) Should I create specific custom exceptions (InvalidProjException, PermissionsException, etc.) for each decorator to raise?

Concerns: The catch block of the caller method will look bloated. Also, is it good to make the assumption that the caller knows what exceptions the decorators of the callee raise?

2) The decorator passes an extra error argument to the method and the method decides what exception to raise. This way the caller method is aware what exception type to expect and handle.

Concerns: Approach seems a little over-engineered and messy.

Sorry for the verbose question. Any thoughts/ideas are greatly appreciated.

like image 824
Albert E Avatar asked Jan 28 '15 19:01

Albert E


1 Answers

I ended up using decorators and throwing specific exceptions within them. For example:

The @validate_pid decorator raises InvalidPidException() which are caught in the except block of any consumer that calls the decorated method.

Advantages so far:

  • Controllers are much cleaner and there is a lot less code replication.
  • Fairly versatile solution, as I use these "business logic validation" decorators all over my code.

Disadvantages so far:

  • The decorator relies on certain keyname parameters to be passed when the decorated method is called, but some of these parameters are not used within the method itself. This can lead to some odd "dangling" parameters in the method signature.
  • I have some minor performance concerns. For example: the project validation decorator initializes a session and loads an object (Project) only to be loaded again in the decorated method itself. Just seems a little janky.
like image 105
Albert E Avatar answered Sep 28 '22 09:09

Albert E