diff --git a/features/index.html b/features/index.html index 3347412..e9bfd4e 100644 --- a/features/index.html +++ b/features/index.html @@ -353,6 +353,13 @@ handle_exc_class + + +
  • + + ignore_exc_class + +
  • @@ -607,6 +614,13 @@ handle_exc_class +
  • + +
  • + + ignore_exc_class + +
  • @@ -907,7 +921,7 @@

    exc_builder

    Functions the same as require_condition.

    handle_exc_class

    This option describes the type of exception that will be handled by this context -manager. Any instance of the option's exception (or any of it's derived exception +manager. Any instance of the option's exception (or any of its derived exception classes) will be caught. This is very useful if you only want to handle a certain category of exceptions and let the others rise up un-altered:

    with handle_errors("Something went wrong", handle_exc_class=MyProjectError):
    @@ -918,6 +932,15 @@ 

    handle_exc_class

    handle_exc_class option will not be handled at all. It is worth noting that the do_except task will not be executed if another exception type occurs. However, the do_else and do_finally tasks will be executed normally.

    +

    ignore_exc_class

    +

    This option describes a type of exception that should not be handled by this +context manager. Any instance of the option's exception (or any of its derived +exception classes) will be raised immediately by handle_errors and will be not +be handled or processed.

    +

    This is useful if you want a specific variant of your handle_exc_class to not +be handled by handle_errors. For example, if you want to use +handle_exc_class=Exception but you do not want handle_errors to handle +RuntimeError, then, you would set ignore_exc_class=RuntimeError.

    do_except

    Often, it is useful to do some particular things when an exception is caught. Most frequently this includes logging the exception. The do_except optional argument diff --git a/reference/index.html b/reference/index.html index fc46324..cf5c9f4 100644 --- a/reference/index.html +++ b/reference/index.html @@ -1033,6 +1033,9 @@

    raise_kwargs: Mapping[str, Any] | None = None, handle_exc_class: type[Exception] | Tuple[type[Exception], ...] = Exception, + ignore_exc_class: type[Exception] + | Tuple[type[Exception], ...] + | None = None, do_finally: Callable[[], None] = noop, do_except: Callable[[DoExceptParams], None] = noop, do_else: Callable[[], None] = noop, @@ -1139,6 +1142,25 @@

    Exception + + ignore_exc_class + + type[Exception] | Tuple[type[Exception], ...] | None + + +
    +

    Defines an exception or set of exception types that should not be handled at all. + Any matching exception types will be immediately re-raised. They will not be handled by + the handle_errors context manager at all. This is useful if you want a specific variant of + your handle_exc_class to not be handled by handle_errors. For example, if you want to use + handle_exc_class=Exception but you do not want handle_errors to handle RuntimeError. + Then, you would set ignore_exc_class=RuntimeError.

    +
    + + + None + + do_finally diff --git a/search/search_index.json b/search/search_index.json index f66e3b6..8eebff1 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"

    That's not flying, it's falling with style

    Take Exceptions to infinity...and beyond with py-buzz!

    "},{"location":"#overview","title":"Overview","text":"

    Have you ever found yourself writing the same code over and over to provide error handling in your python projects? I certainly did. In fact, I found that I often needed to re-implement the same patterns in almost every project. These patterns included:

    • checking conditions and raising errors on failure
    • checking that values are defined and raising errors if they are not
    • catching exceptions and wrapping them in clearer exception types with better error messages
    • checking many conditions and reporting which ones failed

    This led me to create an exception toolkit called py-buzz that provides powerful helper tools for each of the cases listed above. The py-buzz package intends to make your error handling easy, expressive, and robust.

    Because py-buzz requires only Python itself, it's a very light-weight package that you can use in any project with very little overhead.

    py-buzz provides functionality or two different main use-cases. Either use-case allows you to focus on clear and concise error handling in your project without a lot of repetitive code:

    "},{"location":"#helper-functions","title":"Helper Functions","text":"

    This set of functions can be used with any exception types. So, if you already have a set of custom exceptions or simply wish to use existing exceptions, you can import the py-buzz functions like require_condition, handle_errors, enforce_defined, and use them in your code immediately.

    "},{"location":"#buzz-base-class","title":"Buzz base class","text":"

    This class is meant to be used as a base class for custom exceptions that you can use in your project. Buzz includes all of the helper functions as class methods that will use your custom exception type.

    "},{"location":"#quickstart","title":"Quickstart","text":""},{"location":"#requirements","title":"Requirements","text":"
    • Python 3.8 or greater
    "},{"location":"#installation","title":"Installation","text":"

    This will install the latest release of py-buzz from pypi via pip:

    pip install py-buzz\n
    "},{"location":"#usage","title":"Usage","text":"

    Just import!

    from buzz import require_condition\n\nrequire_condition(check_something(), \"The check failed!\")\n

    For more examples of usage, see the Features page.

    "},{"location":"features/","title":"Features","text":""},{"location":"features/#main-features","title":"Main Features","text":"

    There are a few main features of py-buzz that are noteworthy:

    "},{"location":"features/#raise-exception-on-condition-failure","title":"Raise exception on condition failure","text":"

    The py-buzz package provides a function that checks a condition and raises an exception if it fails. This is nice, because you often find your self writing a lot of if <whatever>: raise Exception(<message>) throughout your code base. It's just a little easier with py-buzz:

    # Vanilla python\nif not some_condition():\n    raise Exception(\"some_condition failed\")\n\n# With py-buzz\nrequire_condition(some_condition(), \"some_condition failed\")\n

    This is mostly just a bit of syntactic sugar, but it can make your code a bit more palatable. This is especially true in functions that need to check a lot of conditions before prior to executing their core logic.

    You may also specify the exception type that should be raised by passing it to the raise_exc_class parameter:

    require_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n)\n

    In this case, a MyProjectError would be raised if the condition fails.

    There are a few special keyword argument parameters for the require_condition() function:

    "},{"location":"features/#raise_exc_class","title":"raise_exc_class","text":"

    This just specifies the type of exception to raise if the condition fails. It defaults to Exception.

    "},{"location":"features/#raise_args","title":"raise_args","text":"

    With this parameter, you can specify any positional arguments that should be passed to the raised exception after the message. Here is an example:

    class MyProjectError(Exception):\n    def __init__(self, message, init_arg1, init_arg2):\n        self.init_arg1 = init_arg1\n        self.init_arg2 = init_arg2\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n    raise_args=[\"foo\", \"bar\"],\n)\n

    If the condition fails, require_condition will rais a MyProjectError initialized with positional args init_arg1 == \"foo\" and init_arg2 == \"bar\".

    "},{"location":"features/#raise_kwargs","title":"raise_kwargs","text":"

    Like the raise_args parameter, this one passes along a dictionary of keyword arguments to the newly raised exception:

    class MyProjectError(Exception):\n    def __init__(self, message, init_kwarg1=None, init_kwarg2=None):\n        self.init_kwarg1 = init_kwarg1\n        self.init_kwarg2 = init_kwarg2\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n    raise_kwargs=dict(\"foo\", \"bar\"),\n)\n

    If the condition fails, require_condition will rais a MyProjectError initialized with keyword arguments init_kwarg1 == \"foo\" and init_kwarg2 == \"bar\".

    "},{"location":"features/#exc_builder","title":"exc_builder","text":"

    If the exception to be raised with the raise_exc_class option is a non-standard exception type that does not take a string message as its first argument, you will need to use an alternative exception builder that knows how to map the exception parts to the correct place.

    For example, FastAPI's HTTPException takes a status_code as its first positional argument and expects that any message details are passed as a keyword argument named details.

    In this case, you need to define a builder function to construct the exception and pass it to the exc_builder option:

    class WeirdArgsError(Exception):\n    def __init__(self, weird_arg, detail=\"\"):\n        self.weird_arg = weird_arg\n        self.detail = detail\n\ndef weird_builder(exc_class, message, *args, **kwargs):\n    return exc_class(*args, detail=message, **kwargs)\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=WeirdArgsError,\n    raise_kwargs=dict(\"foo\", \"bar\"),\n    exc_builder=weird_builder,\n)\n
    "},{"location":"features/#raise-exception-if-value-is-not-defined","title":"Raise exception if value is not defined","text":"

    The py-buzz package provides a function that checks a value and raises an exception if it is not defined. This is especially useful for both checking if a variable passed to a function is defined and also to satisfy static type checkers when you want to call a method on the object.

        # Vanilla python\n    def vanilla(val: Optional[str]):\n        if val is None:\n            raise Exception(\"Received an undefined value!\")\n        return val.upper()\n\n    # With py-buzz\n    def buzzy(val: Optional[str]):\n        val = enforce_defined(val)\n        return val.upper()\n

    This is also mostly just syntactic sugar, but it save you a few lines of code and is still very expressive. It might also be useful if you need to supply some more context in your error:

    def neopolitan(val: Optional[str]):\n    val = enforce_defined(\n        val,\n        \"Received an undefined value!\"\n        raise_exc_class=MyProjectError,\n        raise_args=[\"foo\", \"bar\"],\n        raise_kwargs=dict(baz=\"QUX\"),\n    )\n    return val\n

    In this case, a MyProjectError with be raised with positional arguments of \"foo\" and \"bar\" and a keyword argument of baz=\"QUX\" if the value passed in is not defined.

    By default, enforce_defined() raises an exception with a basic message saying that the value was not defined. However, you may pass in a custom message with the message keyword argument. Like require_condition(), the enforce_defined() function also accepts the raise_exc_class, raise_args, raise_kwargs, and exc_builder keyword arguments.

    "},{"location":"features/#exception-handling-context-manager","title":"Exception handling context manager","text":"

    The py-buzz package also provides a context manager that catches any exceptions that might be raised while executing a bit of code. The caught exceptions are re-packaged and raised as another exception type. The message attahed to the new expression captures the initial exception's message:

    # Vanilla python\ntry:\n    this_could_fail()\n    this_could_also_fail()\n    this_will_definitely_fail()\nexcept Exception as err:\n    raise RuntimeError(f\"Something didn't work -- Error: {err}\")\n\n# With py-buzz\nwith handle_errors(\"Something didn't work\", raise_exc_class=RuntimeError):\n    this_could_fail()\n    this_could_also_fail()\n    this_will_definitely_fail()\n

    This actually can save a bit of code and makes things a bit cleaner. It is also a implements pattern that tends to get repeated over and over again. If you need to do very complicated things while handling an exception, you should use a standard try- catch block. However, there are some extra bells and whistles on handle_errors that can be used by passing additional keyword arguments to the function.

    "},{"location":"features/#raise_exc_class_1","title":"raise_exc_class","text":"

    This parameter is the same as for require_condition(). However, if you pass None it will not raise a new exception. Instead, handle_errors will process the do_except, do_else, and do_finally methods and then continue. This effectively absorbs any exceptions that occur in the context. However the context is immediately exited after the first raised exception.

    "},{"location":"features/#raise_args_1","title":"raise_args","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_kwargs_1","title":"raise_kwargs","text":"

    Functions the same as require_condition.

    "},{"location":"features/#exc_builder_1","title":"exc_builder","text":"

    Functions the same as require_condition.

    "},{"location":"features/#handle_exc_class","title":"handle_exc_class","text":"

    This option describes the type of exception that will be handled by this context manager. Any instance of the option's exception (or any of it's derived exception classes) will be caught. This is very useful if you only want to handle a certain category of exceptions and let the others rise up un-altered:

    with handle_errors(\"Something went wrong\", handle_exc_class=MyProjectError):\n   some_function_that_could_raise_mine_or_other_errors()\n

    Exception instances that do not fall within the inheritance tree of the handle_exc_class option will not be handled at all. It is worth noting that the do_except task will not be executed if another exception type occurs. However, the do_else and do_finally tasks will be executed normally.

    "},{"location":"features/#do_except","title":"do_except","text":"

    Often, it is useful to do some particular things when an exception is caught. Most frequently this includes logging the exception. The do_except optional argument provides the ability to do this. The do_except option should be a callable function that accepts a paramter of type DoExceptParams that can be imported from buzz. This dataclass has three attributes:

    • err: The caught exception itself
    • final_message: A message describing the error (This will be the formatted error message)
    • trace: A stack trace

    This option might be invoked something like this:

    def log_error(dep: DoExceptParams):\n    logger.error(dep.final_message)\n    logger.error('\\n'.join(dep.trace))\n\nwith handle_errors(\"Something went wrong\", do_except=log_error):\n    some_dangerous_function()\n
    "},{"location":"features/#do_else","title":"do_else","text":"

    This option describes some action that should happen if no exceptions are encountered. This option is less useful than do_except but it may useful in some circumstances. This option should be a callable that takes no arguments:

        def log_yay():\n        logger.info(\"we did it!\")\n\n    with handle_errors(\"Something went wrong\", do_else=log_yay):\n        some_not_dangerous_function()\n
    "},{"location":"features/#do_finally","title":"do_finally","text":"

    This option describes some action that should happen at the end of the context regardless to whether an exception occurred or not. This is a useful feature if you need to do some cleanup in either case. It should take a callable that receives no arguments:

    def close_resource():\n    resource.close()\n\nwith handle_errors(\"Something went wrong\", do_finally=close_resource):\n    some_dangerous_function_that_uses_resource(resource)\n
    "},{"location":"features/#additional-features","title":"Additional Features","text":""},{"location":"features/#check_expressions","title":"check_expressions","text":"

    The check_expressions context manager is used to check multiple expressions inside of a context manager. Each expression is checked and each failing expression is reported at the end in a raised exception. If no expressions fail in the block, no exception is raised.

    with check_expressions(main_message='there will be errors') as check:\n    check(True)\n    check(False)\n    check(1 == 2, \"one is not two\")\n    check('cooooooool', 'not a problem')\n    check(0, \"zero is still zero\")\n

    If the above code was executed, an exception would be raised that looks like this:

    Exception: Checked expressions failed: there will be errors\n2: 2nd expression failed\n3: one is not two\n5: zero is still zero\n

    The check_expressions() also accepts some keyword arguments:

    "},{"location":"features/#raise_exc_class_2","title":"raise_exc_class","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_args_2","title":"raise_args","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_kwargs_2","title":"raise_kwargs","text":"

    Functions the same as require_condition.

    "},{"location":"features/#exc_builder_2","title":"exc_builder","text":"

    Functions the same as require_condition.

    "},{"location":"features/#reformat_exception","title":"reformat_exception","text":"

    This method is used internally by the handle_errors context manager. However, it is sometimes useful in other circumstances. It simply allows you to wrap an exception message in a more informative block of text:

    try:\n    raise ValueError(\"I didn't like that\")\nexcept Exception as err:\n    print(reformat_exception(\"welp...that didn't work\", err))\n

    The above block would result in output like:

    > welp...that didn't work -- ValueError: I didn't like that\n
    "},{"location":"features/#get_traceback","title":"get_traceback","text":"

    This function is just a tool to fetch the traceback for the current function. It does this by fetching it out of sys.exc_info. It is used internally with Buzz but could be useful in other contexts.

    "},{"location":"features/#the-buzz-base-class","title":"The Buzz base class","text":"

    All of the methods described above are attached to the special exception class, Buzz. You could, for example, use this as the base exception type for your project and then access all the functions of py-buzz from that exception type:

    from buzz import Buzz\n\nclass MyProjectError(Buzz):\n    pass\n\nMyProjectError.require_condition(check_vals(), \"Value check failed!\")\n

    The code above would raise a MyProjectError with the supplied message if the condition expression was falsey.

    The Buzz base class provides the same sort of access for handle_errors, enforce_defined, and check_expressions.

    Check out the examples for more.

    "},{"location":"reference/","title":"Reference","text":""},{"location":"reference/#buzz.tools","title":"buzz.tools","text":"

    This module supplies the core functions of the py-buzz package.

    "},{"location":"reference/#buzz.tools.DoExceptParams","title":"DoExceptParams dataclass","text":"

    Dataclass for the do_except user supplied handling method.

    Attributes:

    Name Type Description err Exception

    The exception instance itself.

    final_message str

    The final, combined message

    trace types.TracebackType | None

    A traceback of the exception

    "},{"location":"reference/#buzz.tools.check_expressions","title":"check_expressions","text":"
    check_expressions(\n    main_message: str,\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n)\n

    Check a series of expressions inside of a context manager. If any fail an exception is raised that contains a main message and a description of each failing expression.

    Parameters:

    Name Type Description Default main message

    The main failure message to include in the constructed message that is passed to the raised Exception

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey.

               Defaults to Exception.\n\n           May not be None.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None Example

    The following is an example usage::

    with check_expressions(\"Something wasn't right\") as check:\n    check(a is not None)\n    check(a > b, \"a must be greater than b\")\n    check(a != 1, \"a must not equal 1\")\n    check(b >= 0, \"b must not be negative\")\n

    This would render output like::

    Checked expressions failed: Something wasn't right:\n  1: first expressoin failed\n  3: a must not equal 1\n
    "},{"location":"reference/#buzz.tools.default_exc_builder","title":"default_exc_builder","text":"
    default_exc_builder(\n    exc: type[TExc], message: str, *args: str, **kwargs: str\n) -> TExc\n

    Build an exception instance using default behavior where message is passed as first positional argument.

    Some exception types such as FastAPI's HTTPException do not take a message as the first positional argument, so they will need a different exception builder.

    "},{"location":"reference/#buzz.tools.enforce_defined","title":"enforce_defined","text":"
    enforce_defined(\n    value: TNonNull | None,\n    message: str = \"Value was not defined (None)\",\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n) -> TNonNull\n

    Assert that a value is not None. If the assertion fails, raise an exception with the supplied message.

    Parameters:

    Name Type Description Default value TNonNull | None

    The value that is checked to be non-null

    required message str

    The failure message to attach to the raised Exception

    'Value was not defined (None)' expr

    The value that is checked for truthiness (usually an evaluated expression)

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey.

              Defaults to Exception.\n          May not be None.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None"},{"location":"reference/#buzz.tools.get_traceback","title":"get_traceback","text":"
    get_traceback() -> types.TracebackType | None\n

    Retrieves the traceback after an exception has been raised.

    "},{"location":"reference/#buzz.tools.handle_errors","title":"handle_errors","text":"
    handle_errors(\n    message: str,\n    raise_exc_class: type[Exception] | None = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    handle_exc_class: type[Exception]\n    | Tuple[type[Exception], ...] = Exception,\n    do_finally: Callable[[], None] = noop,\n    do_except: Callable[[DoExceptParams], None] = noop,\n    do_else: Callable[[], None] = noop,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n) -> Iterator[None]\n

    Provide a context manager that will intercept exceptions and repackage them with a message attached:

    Parameters:

    Name Type Description Default message str

    The message to attach to the raised exception.

    required raise_exc_class type[Exception] | None

    The exception type to raise with the constructed message if an exception is caught in the managed context.

               Defaults to Exception.\n\nIf ``None`` is passed, no new exception will be raised and only the ``do_except``,\n``do_else``, and ``do_finally`` functions will be called.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None handle_exc_class type[Exception] | Tuple[type[Exception], ...]

    Limits the class of exceptions that will be intercepted Any other exception types will not be caught and re-packaged. Defaults to Exception (will handle all exceptions). May also be provided as a tuple of multiple exception types to handle.

    Exception do_finally Callable[[], None]

    A function that should always be called at the end of the block. Should take no parameters.

    noop do_except Callable[[DoExceptParams], None]

    A function that should be called only if there was an exception. Must accept one parameter that is an instance of the DoExceptParams dataclass. Note that the do_except method is passed the original exception.

    noop do_else Callable[[], None]

    A function that should be called only if there were no exceptions encountered.

    noop Example

    The following is an example usage::

    with handle_errors(\"It didn't work\"):\n    some_code_that_might_raise_an_exception()\n
    "},{"location":"reference/#buzz.tools.reformat_exception","title":"reformat_exception","text":"
    reformat_exception(message: str, err: Exception) -> str\n

    Reformat an exception by adding a message to it and reporting the original exception name and message.

    "},{"location":"reference/#buzz.tools.require_condition","title":"require_condition","text":"
    require_condition(\n    expr: Any,\n    message: str,\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n)\n

    Assert that an expression is truthy. If the assertion fails, raise an exception with the supplied message.

    Parameters:

    Name Type Description Default message str

    The failure message to attach to the raised Exception

    required expr Any

    The value that is checked for truthiness (usually an evaluated expression)

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey. Defaults to Exception. May not be None.

    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None"},{"location":"reference/#buzz.base","title":"buzz.base","text":"

    This module defines the Buzz base class.

    "},{"location":"reference/#buzz.base.Buzz","title":"Buzz","text":"

    Bases: Exception

    This provides a specialized exception class that wraps up all the buzz utility functions.

    "},{"location":"reference/#buzz.base.Buzz.__init__","title":"__init__","text":"
    __init__(message)\n

    Initialize the exception with a message. Dedent the supplied message.

    "},{"location":"reference/#buzz.base.Buzz.check_expressions","title":"check_expressions classmethod","text":"
    check_expressions(*args, **kwargs)\n

    Call the check_expressions() context manager with this class as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.enforce_defined","title":"enforce_defined classmethod","text":"
    enforce_defined(\n    value: TNonNull | None,\n    *args: TNonNull | None,\n    **kwargs: TNonNull | None\n) -> TNonNull\n

    Call the enforce_defined() function with this class as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.get_traceback","title":"get_traceback classmethod","text":"
    get_traceback(*args, **kwargs)\n

    Call the get_traceback() function.

    "},{"location":"reference/#buzz.base.Buzz.handle_errors","title":"handle_errors classmethod","text":"
    handle_errors(*args, re_raise = True, **kwargs)\n

    Call the handle_errors() context manager with this class as the raise_exc_class kwarg.

    Note

    If re_raise is not True, None will be passed as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.require_condition","title":"require_condition classmethod","text":"
    require_condition(*args, **kwargs)\n

    Call the require_condition() function with this class as the raise_exc_class kwarg.

    "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"

    That's not flying, it's falling with style

    Take Exceptions to infinity...and beyond with py-buzz!

    "},{"location":"#overview","title":"Overview","text":"

    Have you ever found yourself writing the same code over and over to provide error handling in your python projects? I certainly did. In fact, I found that I often needed to re-implement the same patterns in almost every project. These patterns included:

    • checking conditions and raising errors on failure
    • checking that values are defined and raising errors if they are not
    • catching exceptions and wrapping them in clearer exception types with better error messages
    • checking many conditions and reporting which ones failed

    This led me to create an exception toolkit called py-buzz that provides powerful helper tools for each of the cases listed above. The py-buzz package intends to make your error handling easy, expressive, and robust.

    Because py-buzz requires only Python itself, it's a very light-weight package that you can use in any project with very little overhead.

    py-buzz provides functionality or two different main use-cases. Either use-case allows you to focus on clear and concise error handling in your project without a lot of repetitive code:

    "},{"location":"#helper-functions","title":"Helper Functions","text":"

    This set of functions can be used with any exception types. So, if you already have a set of custom exceptions or simply wish to use existing exceptions, you can import the py-buzz functions like require_condition, handle_errors, enforce_defined, and use them in your code immediately.

    "},{"location":"#buzz-base-class","title":"Buzz base class","text":"

    This class is meant to be used as a base class for custom exceptions that you can use in your project. Buzz includes all of the helper functions as class methods that will use your custom exception type.

    "},{"location":"#quickstart","title":"Quickstart","text":""},{"location":"#requirements","title":"Requirements","text":"
    • Python 3.8 or greater
    "},{"location":"#installation","title":"Installation","text":"

    This will install the latest release of py-buzz from pypi via pip:

    pip install py-buzz\n
    "},{"location":"#usage","title":"Usage","text":"

    Just import!

    from buzz import require_condition\n\nrequire_condition(check_something(), \"The check failed!\")\n

    For more examples of usage, see the Features page.

    "},{"location":"features/","title":"Features","text":""},{"location":"features/#main-features","title":"Main Features","text":"

    There are a few main features of py-buzz that are noteworthy:

    "},{"location":"features/#raise-exception-on-condition-failure","title":"Raise exception on condition failure","text":"

    The py-buzz package provides a function that checks a condition and raises an exception if it fails. This is nice, because you often find your self writing a lot of if <whatever>: raise Exception(<message>) throughout your code base. It's just a little easier with py-buzz:

    # Vanilla python\nif not some_condition():\n    raise Exception(\"some_condition failed\")\n\n# With py-buzz\nrequire_condition(some_condition(), \"some_condition failed\")\n

    This is mostly just a bit of syntactic sugar, but it can make your code a bit more palatable. This is especially true in functions that need to check a lot of conditions before prior to executing their core logic.

    You may also specify the exception type that should be raised by passing it to the raise_exc_class parameter:

    require_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n)\n

    In this case, a MyProjectError would be raised if the condition fails.

    There are a few special keyword argument parameters for the require_condition() function:

    "},{"location":"features/#raise_exc_class","title":"raise_exc_class","text":"

    This just specifies the type of exception to raise if the condition fails. It defaults to Exception.

    "},{"location":"features/#raise_args","title":"raise_args","text":"

    With this parameter, you can specify any positional arguments that should be passed to the raised exception after the message. Here is an example:

    class MyProjectError(Exception):\n    def __init__(self, message, init_arg1, init_arg2):\n        self.init_arg1 = init_arg1\n        self.init_arg2 = init_arg2\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n    raise_args=[\"foo\", \"bar\"],\n)\n

    If the condition fails, require_condition will rais a MyProjectError initialized with positional args init_arg1 == \"foo\" and init_arg2 == \"bar\".

    "},{"location":"features/#raise_kwargs","title":"raise_kwargs","text":"

    Like the raise_args parameter, this one passes along a dictionary of keyword arguments to the newly raised exception:

    class MyProjectError(Exception):\n    def __init__(self, message, init_kwarg1=None, init_kwarg2=None):\n        self.init_kwarg1 = init_kwarg1\n        self.init_kwarg2 = init_kwarg2\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=MyProjectError,\n    raise_kwargs=dict(\"foo\", \"bar\"),\n)\n

    If the condition fails, require_condition will rais a MyProjectError initialized with keyword arguments init_kwarg1 == \"foo\" and init_kwarg2 == \"bar\".

    "},{"location":"features/#exc_builder","title":"exc_builder","text":"

    If the exception to be raised with the raise_exc_class option is a non-standard exception type that does not take a string message as its first argument, you will need to use an alternative exception builder that knows how to map the exception parts to the correct place.

    For example, FastAPI's HTTPException takes a status_code as its first positional argument and expects that any message details are passed as a keyword argument named details.

    In this case, you need to define a builder function to construct the exception and pass it to the exc_builder option:

    class WeirdArgsError(Exception):\n    def __init__(self, weird_arg, detail=\"\"):\n        self.weird_arg = weird_arg\n        self.detail = detail\n\ndef weird_builder(exc_class, message, *args, **kwargs):\n    return exc_class(*args, detail=message, **kwargs)\n\nrequire_condition(\n    some_condition(),\n    \"some_condition failed\",\n    raise_exc_class=WeirdArgsError,\n    raise_kwargs=dict(\"foo\", \"bar\"),\n    exc_builder=weird_builder,\n)\n
    "},{"location":"features/#raise-exception-if-value-is-not-defined","title":"Raise exception if value is not defined","text":"

    The py-buzz package provides a function that checks a value and raises an exception if it is not defined. This is especially useful for both checking if a variable passed to a function is defined and also to satisfy static type checkers when you want to call a method on the object.

        # Vanilla python\n    def vanilla(val: Optional[str]):\n        if val is None:\n            raise Exception(\"Received an undefined value!\")\n        return val.upper()\n\n    # With py-buzz\n    def buzzy(val: Optional[str]):\n        val = enforce_defined(val)\n        return val.upper()\n

    This is also mostly just syntactic sugar, but it save you a few lines of code and is still very expressive. It might also be useful if you need to supply some more context in your error:

    def neopolitan(val: Optional[str]):\n    val = enforce_defined(\n        val,\n        \"Received an undefined value!\"\n        raise_exc_class=MyProjectError,\n        raise_args=[\"foo\", \"bar\"],\n        raise_kwargs=dict(baz=\"QUX\"),\n    )\n    return val\n

    In this case, a MyProjectError with be raised with positional arguments of \"foo\" and \"bar\" and a keyword argument of baz=\"QUX\" if the value passed in is not defined.

    By default, enforce_defined() raises an exception with a basic message saying that the value was not defined. However, you may pass in a custom message with the message keyword argument. Like require_condition(), the enforce_defined() function also accepts the raise_exc_class, raise_args, raise_kwargs, and exc_builder keyword arguments.

    "},{"location":"features/#exception-handling-context-manager","title":"Exception handling context manager","text":"

    The py-buzz package also provides a context manager that catches any exceptions that might be raised while executing a bit of code. The caught exceptions are re-packaged and raised as another exception type. The message attahed to the new expression captures the initial exception's message:

    # Vanilla python\ntry:\n    this_could_fail()\n    this_could_also_fail()\n    this_will_definitely_fail()\nexcept Exception as err:\n    raise RuntimeError(f\"Something didn't work -- Error: {err}\")\n\n# With py-buzz\nwith handle_errors(\"Something didn't work\", raise_exc_class=RuntimeError):\n    this_could_fail()\n    this_could_also_fail()\n    this_will_definitely_fail()\n

    This actually can save a bit of code and makes things a bit cleaner. It is also a implements pattern that tends to get repeated over and over again. If you need to do very complicated things while handling an exception, you should use a standard try- catch block. However, there are some extra bells and whistles on handle_errors that can be used by passing additional keyword arguments to the function.

    "},{"location":"features/#raise_exc_class_1","title":"raise_exc_class","text":"

    This parameter is the same as for require_condition(). However, if you pass None it will not raise a new exception. Instead, handle_errors will process the do_except, do_else, and do_finally methods and then continue. This effectively absorbs any exceptions that occur in the context. However the context is immediately exited after the first raised exception.

    "},{"location":"features/#raise_args_1","title":"raise_args","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_kwargs_1","title":"raise_kwargs","text":"

    Functions the same as require_condition.

    "},{"location":"features/#exc_builder_1","title":"exc_builder","text":"

    Functions the same as require_condition.

    "},{"location":"features/#handle_exc_class","title":"handle_exc_class","text":"

    This option describes the type of exception that will be handled by this context manager. Any instance of the option's exception (or any of its derived exception classes) will be caught. This is very useful if you only want to handle a certain category of exceptions and let the others rise up un-altered:

    with handle_errors(\"Something went wrong\", handle_exc_class=MyProjectError):\n   some_function_that_could_raise_mine_or_other_errors()\n

    Exception instances that do not fall within the inheritance tree of the handle_exc_class option will not be handled at all. It is worth noting that the do_except task will not be executed if another exception type occurs. However, the do_else and do_finally tasks will be executed normally.

    "},{"location":"features/#ignore_exc_class","title":"ignore_exc_class","text":"

    This option describes a type of exception that should not be handled by this context manager. Any instance of the option's exception (or any of its derived exception classes) will be raised immediately by handle_errors and will be not be handled or processed.

    This is useful if you want a specific variant of your handle_exc_class to not be handled by handle_errors. For example, if you want to use handle_exc_class=Exception but you do not want handle_errors to handle RuntimeError, then, you would set ignore_exc_class=RuntimeError.

    "},{"location":"features/#do_except","title":"do_except","text":"

    Often, it is useful to do some particular things when an exception is caught. Most frequently this includes logging the exception. The do_except optional argument provides the ability to do this. The do_except option should be a callable function that accepts a paramter of type DoExceptParams that can be imported from buzz. This dataclass has three attributes:

    • err: The caught exception itself
    • final_message: A message describing the error (This will be the formatted error message)
    • trace: A stack trace

    This option might be invoked something like this:

    def log_error(dep: DoExceptParams):\n    logger.error(dep.final_message)\n    logger.error('\\n'.join(dep.trace))\n\nwith handle_errors(\"Something went wrong\", do_except=log_error):\n    some_dangerous_function()\n
    "},{"location":"features/#do_else","title":"do_else","text":"

    This option describes some action that should happen if no exceptions are encountered. This option is less useful than do_except but it may useful in some circumstances. This option should be a callable that takes no arguments:

        def log_yay():\n        logger.info(\"we did it!\")\n\n    with handle_errors(\"Something went wrong\", do_else=log_yay):\n        some_not_dangerous_function()\n
    "},{"location":"features/#do_finally","title":"do_finally","text":"

    This option describes some action that should happen at the end of the context regardless to whether an exception occurred or not. This is a useful feature if you need to do some cleanup in either case. It should take a callable that receives no arguments:

    def close_resource():\n    resource.close()\n\nwith handle_errors(\"Something went wrong\", do_finally=close_resource):\n    some_dangerous_function_that_uses_resource(resource)\n
    "},{"location":"features/#additional-features","title":"Additional Features","text":""},{"location":"features/#check_expressions","title":"check_expressions","text":"

    The check_expressions context manager is used to check multiple expressions inside of a context manager. Each expression is checked and each failing expression is reported at the end in a raised exception. If no expressions fail in the block, no exception is raised.

    with check_expressions(main_message='there will be errors') as check:\n    check(True)\n    check(False)\n    check(1 == 2, \"one is not two\")\n    check('cooooooool', 'not a problem')\n    check(0, \"zero is still zero\")\n

    If the above code was executed, an exception would be raised that looks like this:

    Exception: Checked expressions failed: there will be errors\n2: 2nd expression failed\n3: one is not two\n5: zero is still zero\n

    The check_expressions() also accepts some keyword arguments:

    "},{"location":"features/#raise_exc_class_2","title":"raise_exc_class","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_args_2","title":"raise_args","text":"

    Functions the same as require_condition.

    "},{"location":"features/#raise_kwargs_2","title":"raise_kwargs","text":"

    Functions the same as require_condition.

    "},{"location":"features/#exc_builder_2","title":"exc_builder","text":"

    Functions the same as require_condition.

    "},{"location":"features/#reformat_exception","title":"reformat_exception","text":"

    This method is used internally by the handle_errors context manager. However, it is sometimes useful in other circumstances. It simply allows you to wrap an exception message in a more informative block of text:

    try:\n    raise ValueError(\"I didn't like that\")\nexcept Exception as err:\n    print(reformat_exception(\"welp...that didn't work\", err))\n

    The above block would result in output like:

    > welp...that didn't work -- ValueError: I didn't like that\n
    "},{"location":"features/#get_traceback","title":"get_traceback","text":"

    This function is just a tool to fetch the traceback for the current function. It does this by fetching it out of sys.exc_info. It is used internally with Buzz but could be useful in other contexts.

    "},{"location":"features/#the-buzz-base-class","title":"The Buzz base class","text":"

    All of the methods described above are attached to the special exception class, Buzz. You could, for example, use this as the base exception type for your project and then access all the functions of py-buzz from that exception type:

    from buzz import Buzz\n\nclass MyProjectError(Buzz):\n    pass\n\nMyProjectError.require_condition(check_vals(), \"Value check failed!\")\n

    The code above would raise a MyProjectError with the supplied message if the condition expression was falsey.

    The Buzz base class provides the same sort of access for handle_errors, enforce_defined, and check_expressions.

    Check out the examples for more.

    "},{"location":"reference/","title":"Reference","text":""},{"location":"reference/#buzz.tools","title":"buzz.tools","text":"

    This module supplies the core functions of the py-buzz package.

    "},{"location":"reference/#buzz.tools.DoExceptParams","title":"DoExceptParams dataclass","text":"

    Dataclass for the do_except user supplied handling method.

    Attributes:

    Name Type Description err Exception

    The exception instance itself.

    final_message str

    The final, combined message

    trace types.TracebackType | None

    A traceback of the exception

    "},{"location":"reference/#buzz.tools.check_expressions","title":"check_expressions","text":"
    check_expressions(\n    main_message: str,\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n)\n

    Check a series of expressions inside of a context manager. If any fail an exception is raised that contains a main message and a description of each failing expression.

    Parameters:

    Name Type Description Default main message

    The main failure message to include in the constructed message that is passed to the raised Exception

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey.

               Defaults to Exception.\n\n           May not be None.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None Example

    The following is an example usage::

    with check_expressions(\"Something wasn't right\") as check:\n    check(a is not None)\n    check(a > b, \"a must be greater than b\")\n    check(a != 1, \"a must not equal 1\")\n    check(b >= 0, \"b must not be negative\")\n

    This would render output like::

    Checked expressions failed: Something wasn't right:\n  1: first expressoin failed\n  3: a must not equal 1\n
    "},{"location":"reference/#buzz.tools.default_exc_builder","title":"default_exc_builder","text":"
    default_exc_builder(\n    exc: type[TExc], message: str, *args: str, **kwargs: str\n) -> TExc\n

    Build an exception instance using default behavior where message is passed as first positional argument.

    Some exception types such as FastAPI's HTTPException do not take a message as the first positional argument, so they will need a different exception builder.

    "},{"location":"reference/#buzz.tools.enforce_defined","title":"enforce_defined","text":"
    enforce_defined(\n    value: TNonNull | None,\n    message: str = \"Value was not defined (None)\",\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n) -> TNonNull\n

    Assert that a value is not None. If the assertion fails, raise an exception with the supplied message.

    Parameters:

    Name Type Description Default value TNonNull | None

    The value that is checked to be non-null

    required message str

    The failure message to attach to the raised Exception

    'Value was not defined (None)' expr

    The value that is checked for truthiness (usually an evaluated expression)

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey.

              Defaults to Exception.\n          May not be None.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None"},{"location":"reference/#buzz.tools.get_traceback","title":"get_traceback","text":"
    get_traceback() -> types.TracebackType | None\n

    Retrieves the traceback after an exception has been raised.

    "},{"location":"reference/#buzz.tools.handle_errors","title":"handle_errors","text":"
    handle_errors(\n    message: str,\n    raise_exc_class: type[Exception] | None = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    handle_exc_class: type[Exception]\n    | Tuple[type[Exception], ...] = Exception,\n    ignore_exc_class: type[Exception]\n    | Tuple[type[Exception], ...]\n    | None = None,\n    do_finally: Callable[[], None] = noop,\n    do_except: Callable[[DoExceptParams], None] = noop,\n    do_else: Callable[[], None] = noop,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n) -> Iterator[None]\n

    Provide a context manager that will intercept exceptions and repackage them with a message attached:

    Parameters:

    Name Type Description Default message str

    The message to attach to the raised exception.

    required raise_exc_class type[Exception] | None

    The exception type to raise with the constructed message if an exception is caught in the managed context.

               Defaults to Exception.\n\nIf ``None`` is passed, no new exception will be raised and only the ``do_except``,\n``do_else``, and ``do_finally`` functions will be called.\n
    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None handle_exc_class type[Exception] | Tuple[type[Exception], ...]

    Limits the class of exceptions that will be intercepted Any other exception types will not be caught and re-packaged. Defaults to Exception (will handle all exceptions). May also be provided as a tuple of multiple exception types to handle.

    Exception ignore_exc_class type[Exception] | Tuple[type[Exception], ...] | None

    Defines an exception or set of exception types that should not be handled at all. Any matching exception types will be immediately re-raised. They will not be handled by the handle_errors context manager at all. This is useful if you want a specific variant of your handle_exc_class to not be handled by handle_errors. For example, if you want to use handle_exc_class=Exception but you do not want handle_errors to handle RuntimeError. Then, you would set ignore_exc_class=RuntimeError.

    None do_finally Callable[[], None]

    A function that should always be called at the end of the block. Should take no parameters.

    noop do_except Callable[[DoExceptParams], None]

    A function that should be called only if there was an exception. Must accept one parameter that is an instance of the DoExceptParams dataclass. Note that the do_except method is passed the original exception.

    noop do_else Callable[[], None]

    A function that should be called only if there were no exceptions encountered.

    noop Example

    The following is an example usage::

    with handle_errors(\"It didn't work\"):\n    some_code_that_might_raise_an_exception()\n
    "},{"location":"reference/#buzz.tools.reformat_exception","title":"reformat_exception","text":"
    reformat_exception(message: str, err: Exception) -> str\n

    Reformat an exception by adding a message to it and reporting the original exception name and message.

    "},{"location":"reference/#buzz.tools.require_condition","title":"require_condition","text":"
    require_condition(\n    expr: Any,\n    message: str,\n    raise_exc_class: type[Exception] = Exception,\n    raise_args: Iterable[Any] | None = None,\n    raise_kwargs: Mapping[str, Any] | None = None,\n    exc_builder: Callable[\n        ..., Exception\n    ] = default_exc_builder,\n)\n

    Assert that an expression is truthy. If the assertion fails, raise an exception with the supplied message.

    Parameters:

    Name Type Description Default message str

    The failure message to attach to the raised Exception

    required expr Any

    The value that is checked for truthiness (usually an evaluated expression)

    required raise_exc_class type[Exception]

    The exception type to raise with the constructed message if the expression is falsey. Defaults to Exception. May not be None.

    Exception raise_args Iterable[Any] | None

    Additional positional args (after the constructed message) that will passed when raising an instance of the raise_exc_class.

    None raise_kwargs Mapping[str, Any] | None

    Keyword args that will be passed when raising an instance of the raise_exc_class.

    None"},{"location":"reference/#buzz.base","title":"buzz.base","text":"

    This module defines the Buzz base class.

    "},{"location":"reference/#buzz.base.Buzz","title":"Buzz","text":"

    Bases: Exception

    This provides a specialized exception class that wraps up all the buzz utility functions.

    "},{"location":"reference/#buzz.base.Buzz.__init__","title":"__init__","text":"
    __init__(message)\n

    Initialize the exception with a message. Dedent the supplied message.

    "},{"location":"reference/#buzz.base.Buzz.check_expressions","title":"check_expressions classmethod","text":"
    check_expressions(*args, **kwargs)\n

    Call the check_expressions() context manager with this class as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.enforce_defined","title":"enforce_defined classmethod","text":"
    enforce_defined(\n    value: TNonNull | None,\n    *args: TNonNull | None,\n    **kwargs: TNonNull | None\n) -> TNonNull\n

    Call the enforce_defined() function with this class as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.get_traceback","title":"get_traceback classmethod","text":"
    get_traceback(*args, **kwargs)\n

    Call the get_traceback() function.

    "},{"location":"reference/#buzz.base.Buzz.handle_errors","title":"handle_errors classmethod","text":"
    handle_errors(*args, re_raise = True, **kwargs)\n

    Call the handle_errors() context manager with this class as the raise_exc_class kwarg.

    Note

    If re_raise is not True, None will be passed as the raise_exc_class kwarg.

    "},{"location":"reference/#buzz.base.Buzz.require_condition","title":"require_condition classmethod","text":"
    require_condition(*args, **kwargs)\n

    Call the require_condition() function with this class as the raise_exc_class kwarg.

    "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index a7058e1..41794d1 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,17 +2,17 @@ http://py-buzz.readthedocs.io/en/latest/ - 2023-08-29 + 2023-09-01 daily http://py-buzz.readthedocs.io/en/latest/features/ - 2023-08-29 + 2023-09-01 daily http://py-buzz.readthedocs.io/en/latest/reference/ - 2023-08-29 + 2023-09-01 daily \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 2a04a1d..05f1cd9 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ