Source code for pcapkit.utilities.exceptions

# -*- coding: utf-8 -*-
"""user defined exceptions

:mod:`pcapkit.exceptions` refined built-in exceptions.
Make it possible to show only user error stack infomation [*]_,
when exception raised on user's operation.

.. [*] See |tbtrim|_ project for Pythonic implementation.
.. |tbtrim| replace:: ``tbtrim``
.. _tbtrim: https://github.com/gousaiyang/tbtrim

"""
import os
import struct
import sys
import traceback

from pcapkit.utilities.compat import ModuleNotFoundError  # pylint: disable=redefined-builtin

__all__ = [
    'BaseError',                                                    # Exception
    'DigitError', 'IntError', 'RealError', 'ComplexError',          # TypeError
    'BoolError', 'BytesError', 'StringError', 'BytearrayError',     # TypeError
    'DictError', 'ListError', 'TupleError', 'IterableError',        # TypeError
    'IOObjError', 'ProtocolUnbound', 'CallableError',               # TypeError
    'InfoError', 'IPError', 'EnumError', 'ComparisonError',         # TypeError
    'FormatError', 'UnsupportedCall',                               # AttributeError
    'FileError',                                                    # IOError
    'FileExists',                                                   # FileExistsError
    'FileNotFound',                                                 # FileNotFoundError
    'ProtocolNotFound',                                             # IndexError
    'VersionError', 'IndexNotFound', 'ProtocolError',               # ValueError
    'EndianError',                                                  # ValueError
    'ProtocolNotImplemented', 'VendorNotImplemented',               # NotImplementedError
    'StructError',                                                  # struct.error
    'FragmentError', 'PacketError',                                 # KeyError
    'ModuleNotFound',                                               # ModuleNotFoundError
]

# boolean mappings
BOOLEAN_STATES = {'1': True, '0': False,
                  'yes': True, 'no': False,
                  'true': True, 'false': False,
                  'on': True, 'off': False}

#: Development mode (``DEVMODE``) flag.
DEVMODE = BOOLEAN_STATES.get(os.environ.get('PCAPKIT_DEVMODE', 'false').casefold(), False)


[docs]def stacklevel(): """Fetch current stack level. The function will walk through the straceback stack (:func:`traceback.extract_stack`), and fetch the stack level where the path contains ``/pcapkit/``. So that it won't display any disturbing internal traceback information when raising errors. Returns: int: Stack level until internal stacks, i.e. contains ``/pcapkit/``. """ pcapkit = f'{os.path.sep}pcapkit{os.path.sep}' tb = traceback.extract_stack() for index, tbitem in enumerate(tb): if pcapkit in tbitem[0]: break else: index = len(tb) return index-1
############################################################################## # BaseError (abc of exceptions) session. ##############################################################################
[docs]class BaseError(Exception): """Base error class of all kinds. Important: * Turn off system-default traceback function by set :data:`sys.tracebacklimit` to ``0``. * But bugs appear in Python 3.6, so we have to set :data:`sys.tracebacklimit` to ``None``. .. note:: This note is deprecated since Python fixed the problem above. * In Python 2.7, :func:`trace.print_stack(limit)` dose not support negative limit. See Also: :func:`pcapkit.utilities.exceptions.stacklevel` """
[docs] def __init__(self, *args, quiet=False, **kwargs): if DEVMODE: index = stacklevel() if not quiet and index: fmt_exc = traceback.format_exc(limit=-index) if len(fmt_exc.splitlines(True)) > 1: print(fmt_exc, file=sys.stderr) else: sys.tracebacklimit = 0 super().__init__(*args, **kwargs)
############################################################################## # TypeError session. ##############################################################################
[docs]class DigitError(BaseError, TypeError): """The argument(s) must be (a) number(s)."""
[docs]class IntError(BaseError, TypeError): """The argument(s) must be integral."""
[docs]class RealError(BaseError, TypeError): """The function is not defined for real number."""
[docs]class ComplexError(BaseError, TypeError): """The function is not defined for complex instance."""
[docs]class BytesError(BaseError, TypeError): """The argument(s) must be :obj:`bytes` type."""
[docs]class BytearrayError(BaseError, TypeError): """The argument(s) must be :obj:`bytearray` type."""
[docs]class BoolError(BaseError, TypeError): """The argument(s) must be :obj:`bool` type."""
[docs]class StringError(BaseError, TypeError): """The argument(s) must be :obj:`str` type."""
[docs]class DictError(BaseError, TypeError): """The argument(s) must be :obj:`dict` type."""
[docs]class ListError(BaseError, TypeError): """The argument(s) must be :obj:`list` type."""
[docs]class TupleError(BaseError, TypeError): """The argument(s) must be :obj:`tuple` type."""
[docs]class IterableError(BaseError, TypeError): """The argument(s) must be *iterable*."""
[docs]class CallableError(BaseError, TypeError): """The argument(s) must be *callable*."""
[docs]class ProtocolUnbound(BaseError, TypeError): """Protocol slice unbound."""
[docs]class IOObjError(BaseError, TypeError): """The argument(s) must be *file-like object*."""
[docs]class InfoError(BaseError, TypeError): """The argument(s) must be :class:`~pcapkit.corekit.infoclass.Info` instance."""
[docs]class IPError(BaseError, TypeError): """The argument(s) must be *IP address*."""
[docs]class EnumError(BaseError, TypeError): """The argument(s) must be *enumeration protocol* type."""
[docs]class ComparisonError(BaseError, TypeError): """Rich comparison not supported between instances."""
############################################################################## # AttributeError session. ##############################################################################
[docs]class FormatError(BaseError, AttributeError): """Unknown format(s)."""
[docs]class UnsupportedCall(BaseError, AttributeError): """Unsupported function or property call."""
############################################################################## # IOError session. ##############################################################################
[docs]class FileError(BaseError, IOError): """[Errno 5] Wrong file format."""
# args: errno, strerror, filename, winerror, filename2 ############################################################################## # FileExistsError session. ##############################################################################
[docs]class FileExists(BaseError, FileExistsError): """[Errno 17] File already exists."""
# args: errno, strerror, filename, winerror, filename2 ############################################################################## # FileNotFoundError session. ##############################################################################
[docs]class FileNotFound(BaseError, FileNotFoundError): """[Errno 2] File not found."""
# args: errno, strerror, filename, winerror, filename2 ############################################################################## # IndexError session. ##############################################################################
[docs]class ProtocolNotFound(BaseError, IndexError): """Protocol not found in ProtoChain."""
############################################################################## # ValueError session. ##############################################################################
[docs]class VersionError(BaseError, ValueError): """Unknown IP version."""
[docs]class IndexNotFound(BaseError, ValueError): """Protocol not in ProtoChain."""
[docs]class ProtocolError(BaseError, ValueError): """Invalid protocol format."""
[docs]class EndianError(BaseError, ValueError): """Invalid endian (byte order)."""
############################################################################## # NotImplementedError session. ##############################################################################
[docs]class ProtocolNotImplemented(BaseError, NotImplementedError): """Protocol not implemented."""
[docs]class VendorNotImplemented(BaseError, NotImplementedError): """Vendor not implemented."""
############################################################################## # struct.error session. ##############################################################################
[docs]class StructError(BaseError, struct.error): """Unpack failed."""
############################################################################## # KeyError session. ##############################################################################
[docs]class FragmentError(BaseError, KeyError): """Invalid fragment dict."""
[docs]class PacketError(BaseError, KeyError): """Invalid packet dict."""
############################################################################## # ModuleNotFoundError session. ##############################################################################
[docs]class ModuleNotFound(BaseError, ModuleNotFoundError): """Module not found."""
# kwargs: name, path