Skip to main content

a module for easy error-handling without exceptions

Project description

retval

A MIT-licensed Python module for better function return values without exceptions.

Description

This module provides RetVal, a class which powers up how you handle errors and return values. With RetVal you can:

  • Use more specific error codes
  • Pull from a small library of common errors
  • Provide context information with errors
  • Create your own errors quickly -- no more writing custom Exception classes
  • Return a variable number of data values from functions

Status

The module is production stable and in active use.

Usage

Most usage of RetVal revolves around using the constructor to quickly package error information.

import json
from retval import RetVal, ErrBadType, ErrEmptyData, ErrExists

# Creating new error constants is super simple
ErrDecryptionFailure = 'decryption failure'

def save(self, path: str) -> RetVal:
	'''Saves the key to a file'''

	if not path:
		# The second argument, which may be omitted, is for context information for the developer.
		# It is not intended to be user-facing.
		return RetVal(ErrEmptyData, 'path may not be empty')
	
	if os.path.exists(path):
		return RetVal(ErrExists, f"{path} exists")

	try:
		fhandle = open(path, 'w')
		json.dump({ 'SecretKey' : self.get_key() }, fhandle, ensure_ascii=False, indent=1)
		fhandle.close()
	
	except Exception as e:
		# This little gem allows you to elegantly handle any exception the same way as any other
		# error
		return RetVal().wrap_exception(e)

	return RetVal()


def decrypt(self, encrypted_data: str) -> RetVal:
	'''Decrypts Base85-encoded encrypted data and returns it as bytes in the 'data' field.'''
	# It is highly recommended to mention returned fields in the docstring.

	if not encrypted_data:
		return RetVal(ErrEmptyData)
	
	if not isinstance(encdata, str):
		return RetVal(ErrBadType)

	secretbox = nacl.secret.SecretBox(self.key.raw_data())
	try:
		decrypted_data = secretbox.decrypt(encrypted_data, encoder=Base85Encoder)
	except:
		return RetVal(ErrDecryptionFailure)
	
	return RetVal().set_value('data', decrypted_data)

Unless your code uses a lot of different error messages, for maximum code clarity it is recommended to import the RetVal class and any error codes used directly into your code as demonstrated above. An empty constructor indicates success. Call-chaining is the most efficient way to return a single value using RetVal, as demonstrated in decrypt(), and multiple values can be call-chained using set_values().

Because RetVal is intended to be treated as a dictionary with some extra features, using a RetVal returned from a function is very simple.

pubkey = PublicKey(organization_key)
status = pubkey.encrypt(tagstr.encode())
if status.error():
	return status

return status['data']

The encrypt() function called in the above example is similar to decrypt(), taking bytes and returning a RetVal containing the encrypted data in the data field. Most of the time, dealing with a function which returns a RetVal is just a matter of checking for an error state and returning the entire RetVal object if there is one and accessing the data in the object if there isn't.

History

This module exists because I was inspired to think about Python error-handling and return values after spending more than a little time learning Go. Go errors are little more than strings, which isn't great, but they are often paired with other return values. If no error is returned, then the other return value is safe to consider as valid. Go also doesn't have very many built-in error codes and are not very well documented. RetVal takes from the good and builds upon it. It integrates pretty easily into existing code and the extra contextual information makes debugging significantly easier. Is it Pythonic? Most likely not. I don't care... it's made error-handling easier for me and I'm sure it will for you, too.

Building

This is a very simple but useful module. Most people will just want to install it from pip. Running python setup.py install should be the thing needed if you want to install from the tarball.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

retval-1.0.2.tar.gz (5.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

retval-1.0.2-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

Details for the file retval-1.0.2.tar.gz.

File metadata

  • Download URL: retval-1.0.2.tar.gz
  • Upload date:
  • Size: 5.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.3.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.0 CPython/3.9.5

File hashes

Hashes for retval-1.0.2.tar.gz
Algorithm Hash digest
SHA256 bcf56a1d18798ec9adbc11c98efe4aa93cbdf181b74eef58dc18a473630ab03b
MD5 5af07776c86957df4e9abf539ca4e106
BLAKE2b-256 c3cd21420b2fb40827a916f801eec52add54a049f6bf218a1c1d1aeb29e6af04

See more details on using hashes here.

File details

Details for the file retval-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: retval-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 5.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.3.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.0 CPython/3.9.5

File hashes

Hashes for retval-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6d34effe7112b972729e7ce1da59247660ceaa050e4f9666a901bd78d5dacd6f
MD5 615d801ff7a3d4be62cfdc93b358e2e7
BLAKE2b-256 70ada1154d7ee369ee1bbba564c51f6d50e913c669bcdef48b8100d0dbc5928e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page