Repository: deepdoctection/deepdoctection (language: python)

Issue:
 File downloaded from deepdoctection/d2_casc_rcnn_X_32xd4_50_FPN_GN_2FC_publaynet_inference_only does not match the expected size!
**Bug** 💥
I try to use deepdoctection, but while executing my script, I get the following errors:

ERR  File downloaded from deepdoctection/d2_casc_rcnn_X_32xd4_50_FPN_GN_2FC_publaynet_inference_only does not match the expected size! You may have downloaded a broken file, or the upstream may have modified the file.
ERR  File downloaded from deepdoctection/d2_casc_rcnn_X_32xd4_50_FPN_GN_2FC_pubtabnet_rc_inference_only does not match the expected size! You may have downloaded a broken file, or the upstream may have modified the file.
ERR  File downloaded from deepdoctection/d2_casc_rcnn_X_32xd4_50_FPN_GN_2FC_pubtabnet_c_inference_only does not match the expected size! You may have downloaded a broken file, or the upstream may have modified the file.

**Desktop (please complete the following information, if any other than the one in the install requirements):**
 - devcontainer on Ubuntu 22.04 LTS
 - deepdoctection version 0.30



Discussion / hints:
This error log occurs if the download file does not have the expected size provided by the `ModelCatalog`. It should rather be a warning and on some machines I have spotted that the Python`s file size estimation does not always give you the same value.

Ignoring this log, may I ask if the code you are running terminates with an exception?  
@JaMe76 I see, no the code does not terminate with an exception.
Thanks for the reply. 

I will change this error log and turn it into a warning to reduce confusion.

Fix patch:
diff --git a/deepdoctection/analyzer/dd.py b/deepdoctection/analyzer/dd.py
index 3e571921..49187df3 100644
--- a/deepdoctection/analyzer/dd.py
+++ b/deepdoctection/analyzer/dd.py
@@ -113,11 +113,12 @@ def config_sanity_checks(cfg: AttrDict) -> None:
     """Some config sanity checks"""
     if cfg.USE_PDF_MINER and cfg.USE_OCR and cfg.OCR.USE_DOCTR:
         raise ValueError("Configuration USE_PDF_MINER= True and USE_OCR=True and USE_DOCTR=True is not allowed")
-    if cfg.OCR.USE_TESSERACT + cfg.OCR.USE_DOCTR + cfg.OCR.USE_TEXTRACT != 1:
-        raise ValueError(
-            "Choose either OCR.USE_TESSERACT=True or OCR.USE_DOCTR=True or OCR.USE_TEXTRACT=True and set the other two "
-            "to False. Only one OCR system can be activated."
-        )
+    if cfg.USE_OCR:
+        if cfg.OCR.USE_TESSERACT + cfg.OCR.USE_DOCTR + cfg.OCR.USE_TEXTRACT != 1:
+            raise ValueError(
+                "Choose either OCR.USE_TESSERACT=True or OCR.USE_DOCTR=True or OCR.USE_TEXTRACT=True "
+                "and set the other two to False. Only one OCR system can be activated."
+            )
 
 
 def build_detector(
diff --git a/deepdoctection/dataflow/base.py b/deepdoctection/dataflow/base.py
index 2931e749..bcf45f84 100644
--- a/deepdoctection/dataflow/base.py
+++ b/deepdoctection/dataflow/base.py
@@ -17,25 +17,6 @@
 from ..utils.utils import get_rng
 
 
-class DataFlowTerminated(BaseException):
-    """
-    An exception indicating that the DataFlow is unable to produce any more
-    data, i.e. something wrong happened so that calling `__iter__`
-    cannot give a valid iterator anymore.
-    In most DataFlow this will never be raised.
-    """
-
-
-class DataFlowResetStateNotCalled(BaseException):
-    """
-    An exception indicating that `reset_state()` has not been called before starting
-    iteration.
-    """
-
-    def __init__(self) -> None:
-        super().__init__("Iterating a dataflow requires .reset_state() to be called first")
-
-
 class DataFlowReentrantGuard:
     """
     A tool to enforce non-reentrancy.
diff --git a/deepdoctection/dataflow/custom.py b/deepdoctection/dataflow/custom.py
index dc4e54ab..8b78a342 100644
--- a/deepdoctection/dataflow/custom.py
+++ b/deepdoctection/dataflow/custom.py
@@ -25,10 +25,11 @@
 
 import numpy as np
 
+from ..utils.error import DataFlowResetStateNotCalledError
 from ..utils.logger import LoggingRecord, logger
 from ..utils.tqdm import get_tqdm
 from ..utils.utils import get_rng
-from .base import DataFlow, DataFlowReentrantGuard, DataFlowResetStateNotCalled, ProxyDataFlow
+from .base import DataFlow, DataFlowReentrantGuard, ProxyDataFlow
 from .serialize import DataFromIterable, DataFromList
 
 __all__ = ["CacheData", "CustomDataFromList", "CustomDataFromIterable"]
@@ -65,7 +66,7 @@ def reset_state(self) -> None:
 
     def __iter__(self) -> Iterator[Any]:
         if self._guard is None:
-            raise DataFlowResetStateNotCalled()
+            raise DataFlowResetStateNotCalledError()
 
         with self._guard:
             if self.buffer:
@@ -139,7 +140,7 @@ def __len__(self) -> int:
 
     def __iter__(self) -> Iterator[Any]:
         if self.rng is None:
-            raise DataFlowResetStateNotCalled()
+            raise DataFlowResetStateNotCalledError()
         if self.rebalance_func is not None:
             lst_tmp = self.rebalance_func(self.lst)
             logger.info(LoggingRecord(f"CustomDataFromList: subset size after re-balancing: {len(lst_tmp)}"))
diff --git a/deepdoctection/dataflow/custom_serialize.py b/deepdoctection/dataflow/custom_serialize.py
index 5d668008..b625298f 100644
--- a/deepdoctection/dataflow/custom_serialize.py
+++ b/deepdoctection/dataflow/custom_serialize.py
@@ -27,13 +27,16 @@
 from typing import DefaultDict, Dict, List, Optional, Sequence, Union
 
 from jsonlines import Reader, Writer
+from tabulate import tabulate
+from termcolor import colored
 
 from ..utils.context import timed_operation
 from ..utils.detection_types import JsonDict, Pathlike
+from ..utils.error import FileExtensionError
 from ..utils.identifier import get_uuid_from_str
 from ..utils.pdf_utils import PDFStreamer
 from ..utils.tqdm import get_tqdm
-from ..utils.utils import FileExtensionError, is_file_extension
+from ..utils.utils import is_file_extension
 from .base import DataFlow
 from .common import FlattenData, JoinData, MapData
 from .custom import CacheData, CustomDataFromIterable, CustomDataFromList
@@ -223,7 +226,7 @@ def save() -> None:
         """
         Not implemented
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class CocoParser:
@@ -283,8 +286,14 @@ def info(self) -> None:
         """
         Print information about the annotation file.
         """
+        rows = []
         for key, value in self.dataset["info"].items():
-            print(f"{key}: {value}")
+            row = [key, value]
+            rows.append(row)
+
+        header = ["key", "value"]
+        table = tabulate(rows, headers=header, tablefmt="fancy_grid", stralign="left", numalign="left")
+        print(colored(table, "cyan"))
 
     def get_ann_ids(
         self,
@@ -499,7 +508,7 @@ def save() -> None:
         """
         Not implemented
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class SerializerPdfDoc:
@@ -547,7 +556,7 @@ def save(path: Pathlike) -> None:
         """
         Not implemented
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @staticmethod
     def split(path: Pathlike, path_target: Optional[Pathlike] = None, max_datapoint: Optional[int] = None) -> None:
diff --git a/deepdoctection/dataflow/parallel_map.py b/deepdoctection/dataflow/parallel_map.py
index 1bf80ef9..d2b0cc8b 100644
--- a/deepdoctection/dataflow/parallel_map.py
+++ b/deepdoctection/dataflow/parallel_map.py
@@ -28,8 +28,9 @@
 import zmq
 
 from ..utils.concurrency import StoppableThread, enable_death_signal, start_proc_mask_signal
+from ..utils.error import DataFlowTerminatedError
 from ..utils.logger import LoggingRecord, logger
-from .base import DataFlow, DataFlowReentrantGuard, DataFlowTerminated, ProxyDataFlow
+from .base import DataFlow, DataFlowReentrantGuard, ProxyDataFlow
 from .common import RepeatedData
 from .serialize import PickleSerializer
 
@@ -49,14 +50,14 @@ def _zmq_catch_error(name):
         yield
     except zmq.ContextTerminated as exc:
         logger.info(LoggingRecord(f"_zmq_catch_error: [{name}] Context terminated."))
-        raise DataFlowTerminated() from exc
+        raise DataFlowTerminatedError() from exc
     except zmq.ZMQError as exc:
         if exc.errno == errno.ENOTSOCK:  # socket closed
             logger.info(LoggingRecord(f"_zmq_catch_error: [{name}]  Socket closed."))
-            raise DataFlowTerminated() from exc
-        raise ValueError from exc
+            raise DataFlowTerminatedError() from exc
+        raise ValueError() from exc
     except Exception as exc:
-        raise ValueError from exc
+        raise ValueError() from exc
 
 
 @no_type_check
@@ -78,8 +79,8 @@ def _get_pipe_name(name):
 class _ParallelMapData(ProxyDataFlow, ABC):
     def __init__(self, df: DataFlow, buffer_size: int, strict: bool = False) -> None:
         super().__init__(df)
-        if not buffer_size:
-            raise ValueError("buffer_size must be a positive number")
+        if buffer_size <= 0:
+            raise ValueError(f"buffer_size must be a positive number, got {buffer_size}")
         self._buffer_size = buffer_size
         self._buffer_occupancy = 0  # actual #elements in buffer, only useful in strict mode
         self._strict = strict
@@ -95,12 +96,12 @@ def reset_state(self) -> None:
     @no_type_check
     @abstractmethod
     def _recv(self):
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @no_type_check
     @abstractmethod
     def _send(self, dp: Any):
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @no_type_check
     def _recv_filter_none(self):
@@ -398,8 +399,8 @@ def __init__(
 
         _ParallelMapData.__init__(self, df, buffer_size, strict)
         _MultiProcessZMQDataFlow.__init__(self)
-        if not num_proc:
-            raise ValueError("num_proc must be a positive number")
+        if num_proc <= 0:
+            raise ValueError(f"num_proc must be a positive number, got {num_proc}")
         self.num_proc = num_proc
         self.map_func = map_func
         self._strict = strict
diff --git a/deepdoctection/dataflow/serialize.py b/deepdoctection/dataflow/serialize.py
index 18ce17bc..723f4c72 100644
--- a/deepdoctection/dataflow/serialize.py
+++ b/deepdoctection/dataflow/serialize.py
@@ -16,7 +16,8 @@
 
 import numpy as np
 
-from .base import DataFlow, DataFlowResetStateNotCalled, RNGDataFlow
+from ..utils.error import DataFlowResetStateNotCalledError
+from .base import DataFlow, RNGDataFlow
 
 
 class DataFromList(RNGDataFlow):
@@ -44,7 +45,7 @@ def __iter__(self) -> Iterator[Any]:
                 for k in idxs:
                     yield self.lst[k]
             else:
-                raise DataFlowResetStateNotCalled()
+                raise DataFlowResetStateNotCalledError()
 
 
 class DataFromIterable(DataFlow):
@@ -63,7 +64,7 @@ def __init__(self, iterable: Iterable[Any]) -> None:
 
     def __len__(self) -> int:
         if self._len is None:
-            raise NotImplementedError
+            raise NotImplementedError()
         return self._len
 
     def __iter__(self) -> Iterator[Any]:
@@ -107,7 +108,7 @@ def __len__(self) -> int:
 
     def __iter__(self) -> Iterator[Any]:
         if self.rng is None:
-            raise DataFlowResetStateNotCalled()
+            raise DataFlowResetStateNotCalledError()
         if self.random:
             for _ in range(self._size):
                 val = []
diff --git a/deepdoctection/datapoint/annotation.py b/deepdoctection/datapoint/annotation.py
index 2158819b..6be1735d 100644
--- a/deepdoctection/datapoint/annotation.py
+++ b/deepdoctection/datapoint/annotation.py
@@ -24,6 +24,7 @@
 from typing import Any, Dict, List, Optional, Union, no_type_check
 
 from ..utils.detection_types import JsonDict
+from ..utils.error import AnnotationError, UUIDError
 from ..utils.identifier import get_uuid, is_uuid_like
 from ..utils.logger import LoggingRecord, logger
 from ..utils.settings import DefaultType, ObjectTypes, SummaryType, TypeOrStr, get_type
@@ -101,7 +102,7 @@ def annotation_id(self) -> str:
         """
         if self._annotation_id:
             return self._annotation_id
-        raise ValueError("Dump annotation first or pass external_id to create an annotation id")
+        raise AnnotationError("Dump annotation first or pass external_id to create an annotation id")
 
     @annotation_id.setter
     def annotation_id(self, input_id: str) -> None:
@@ -109,13 +110,13 @@ def annotation_id(self, input_id: str) -> None:
         annotation_id setter
         """
         if self._annotation_id is not None:
-            raise AssertionError("Annotation_id already defined and cannot be reset")
+            raise AnnotationError("Annotation_id already defined and cannot be reset")
         if is_uuid_like(input_id):
             self._annotation_id = input_id
         elif isinstance(input_id, property):
             pass
         else:
-            raise ValueError("Annotation_id must be uuid3 string")
+            raise AnnotationError("Annotation_id must be uuid3 string")
 
     @abstractmethod
     def get_defining_attributes(self) -> List[str]:
@@ -132,7 +133,7 @@ def _assert_attributes_have_str(self, state_id: bool = False) -> None:
         defining_attributes = self.get_state_attributes() if state_id else self.get_defining_attributes()
         for attr in defining_attributes:
             if not hasattr(eval("self." + attr), "__str__"):  # pylint: disable=W0123
-                raise AttributeError(f"Attribute {attr} must have __str__ method")
+                raise AnnotationError(f"Attribute {attr} must have __str__ method")
 
     @staticmethod
     def set_annotation_id(annotation: "CategoryAnnotation", *container_id_context: Optional[str]) -> str:
@@ -179,7 +180,7 @@ def from_dict(cls, **kwargs: JsonDict) -> "Annotation":
 
         :return: Annotation instance
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @staticmethod
     @abstractmethod
@@ -189,7 +190,7 @@ def get_state_attributes() -> List[str]:
 
         :return: A list of attributes.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @property
     def state_id(self) -> str:
@@ -290,7 +291,12 @@ def dump_sub_category(
         """
 
         if sub_category_name in self.sub_categories:
-            raise KeyError(f"{sub_category_name} as sub category already defined for " f"{self.annotation_id}")
+            raise AnnotationError(
+                f"sub category {sub_category_name} already defined: "
+                f"annotation_id: {self.annotation_id}, "
+                f"category_name: {self.category_name}, "
+                f"category_id: {self.category_id}"
+            )
 
         if self._annotation_id is not None:
             if annotation._annotation_id is None:  # pylint: disable=W0212
@@ -333,7 +339,7 @@ def dump_relationship(self, key: TypeOrStr, annotation_id: str) -> None:
         :param annotation_id: An annotation id
         """
         if not is_uuid_like(annotation_id):
-            raise ValueError("Annotation_id must be uuid")
+            raise UUIDError("Annotation_id must be uuid")
 
         key_type = get_type(key)
         if key not in self.relationships:
@@ -436,14 +442,14 @@ def get_bounding_box(self, image_id: Optional[str] = None) -> BoundingBox:
             box = self.bounding_box
         if box:
             return box
-        raise ValueError(f"bounding_box has not been initialized for {self.annotation_id}")
+        raise AnnotationError(f"bounding_box has not been initialized for {self.annotation_id}")
 
     def get_summary(self, key: ObjectTypes) -> CategoryAnnotation:
         """Get summary sub categories from `image`. Raises `ValueError` if `key` is not available"""
         if self.image:
             if self.image.summary:
                 return self.image.summary.get_sub_category(key)
-        raise ValueError(f"Summary does not exist for {self.annotation_id} and key: {key}")
+        raise AnnotationError(f"Summary does not exist for {self.annotation_id} and key: {key}")
 
 
 @dataclass
diff --git a/deepdoctection/datapoint/box.py b/deepdoctection/datapoint/box.py
index cc3378a7..97fedcaf 100644
--- a/deepdoctection/datapoint/box.py
+++ b/deepdoctection/datapoint/box.py
@@ -28,6 +28,7 @@
 from numpy import float32
 
 from ..utils.detection_types import ImageType
+from ..utils.error import BoundingBoxError
 from ..utils.file_utils import cocotools_available
 from ..utils.logger import LoggingRecord, logger
 
@@ -140,10 +141,6 @@ def iou(boxes1: npt.NDArray[float32], boxes2: npt.NDArray[float32]) -> npt.NDArr
     return np_iou(boxes1, boxes2)
 
 
-class BoundingBoxError(BaseException):
-    """Special exception only for `BoundingBox`"""
-
-
 @dataclass
 class BoundingBox:
     """
diff --git a/deepdoctection/datapoint/convert.py b/deepdoctection/datapoint/convert.py
index 029d54f6..b197e1b2 100644
--- a/deepdoctection/datapoint/convert.py
+++ b/deepdoctection/datapoint/convert.py
@@ -32,6 +32,7 @@
 
 from ..utils.detection_types import ImageType
 from ..utils.develop import deprecated
+from ..utils.error import DependencyError
 from ..utils.pdf_utils import pdf_to_np_array
 from ..utils.viz import viz_handler
 
@@ -121,7 +122,8 @@ def convert_pdf_bytes_to_np_array(pdf_bytes: bytes, dpi: Optional[int] = None) -
     """
     from pdf2image import convert_from_bytes  # type: ignore # pylint: disable=C0415, E0401
 
-    assert which("pdftoppm") is not None, "convert_pdf_bytes_to_np_array requires poppler to be installed"
+    if which("pdftoppm") is None:
+        raise DependencyError("convert_pdf_bytes_to_np_array requires poppler to be installed")
 
     with BytesIO(pdf_bytes) as pdf_file:
         pdf = PdfReader(pdf_file).pages[0]
diff --git a/deepdoctection/datapoint/image.py b/deepdoctection/datapoint/image.py
index 10721ddb..33fd0130 100644
--- a/deepdoctection/datapoint/image.py
+++ b/deepdoctection/datapoint/image.py
@@ -28,6 +28,7 @@
 from numpy import uint8
 
 from ..utils.detection_types import ImageType, JsonDict, Pathlike
+from ..utils.error import AnnotationError, BoundingBoxError, ImageError, UUIDError
 from ..utils.identifier import get_uuid, is_uuid_like
 from ..utils.settings import ObjectTypes, get_type
 from .annotation import Annotation, BoundingBox, ImageAnnotation, SummaryAnnotation
@@ -108,7 +109,7 @@ def image_id(self) -> str:
         """
         if self._image_id is not None:
             return self._image_id
-        raise ValueError("image_id not set")
+        raise ImageError("image_id not set")
 
     @image_id.setter
     def image_id(self, input_id: str) -> None:
@@ -116,13 +117,13 @@ def image_id(self, input_id: str) -> None:
         image_id setter
         """
         if self._image_id is not None:
-            raise ValueError("image_id already defined and cannot be reset")
+            raise ImageError("image_id already defined and cannot be reset")
         if is_uuid_like(input_id):
             self._image_id = input_id
         elif isinstance(input_id, property):
             pass
         else:
-            raise ValueError("image_id must be uuid3 string")
+            raise UUIDError("image_id must be uuid3 string")
 
     @property
     def image(self) -> Optional[ImageType]:
@@ -153,7 +154,7 @@ def image(self, image: Optional[Union[str, ImageType, bytes]]) -> None:
             self._self_embedding()
         else:
             if not isinstance(image, np.ndarray):
-                raise TypeError(f"Cannot load image is of type: {type(image)}")
+                raise ImageError(f"Cannot load image is of type: {type(image)}")
             self._image = image.astype(uint8)
             self.set_width_height(self._image.shape[1], self._image.shape[0])
             self._self_embedding()
@@ -248,7 +249,7 @@ def width(self) -> float:
         width
         """
         if self._bbox is None:
-            raise ValueError("Width not available. Call set_width_height first")
+            raise ImageError("Width not available. Call set_width_height first")
         return self._bbox.width
 
     @property
@@ -257,7 +258,7 @@ def height(self) -> float:
         height
         """
         if self._bbox is None:
-            raise ValueError("Height not available. Call set_width_height first")
+            raise ImageError("Height not available. Call set_width_height first")
         return self._bbox.height
 
     def set_width_height(self, width: float, height: float) -> None:
@@ -281,7 +282,7 @@ def set_embedding(self, image_id: str, bounding_box: BoundingBox) -> None:
         :param bounding_box: bounding box of this image in terms of the embedding image.
         """
         if not isinstance(bounding_box, BoundingBox):
-            raise TypeError(f"Bounding box must be of type BoundingBox, is of type {type(bounding_box)}")
+            raise BoundingBoxError(f"Bounding box must be of type BoundingBox, is of type {type(bounding_box)}")
         self.embeddings[image_id] = bounding_box
 
     def get_embedding(self, image_id: str) -> BoundingBox:
@@ -307,14 +308,14 @@ def dump(self, annotation: ImageAnnotation) -> None:
         :param annotation: image annotation to store
         """
         if not isinstance(annotation, ImageAnnotation):
-            raise TypeError(
+            raise AnnotationError(
                 f"Annotation must be of type ImageAnnotation: "
                 f"{annotation.annotation_id} but is of type {str(type(annotation))}"
             )
         if annotation._annotation_id is None:  # pylint: disable=W0212
             annotation.annotation_id = self.define_annotation_id(annotation)
         if annotation.annotation_id in self._annotation_ids:
-            raise ValueError(f"Cannot dump annotation with already taken " f"id {annotation.annotation_id}")
+            raise ImageError(f"Cannot dump annotation with already taken " f"id {annotation.annotation_id}")
         self._annotation_ids.append(annotation.annotation_id)
         self.annotations.append(annotation)
 
@@ -439,7 +440,7 @@ def image_ann_to_image(self, annotation_id: str, crop_image: bool = False) -> No
         new_image = Image(file_name=self.file_name, location=self.location, external_id=annotation_id)
 
         if self._bbox is None or ann.bounding_box is None:
-            raise ValueError(f"Bounding box for image and ImageAnnotation ({annotation_id}) must be set")
+            raise ImageError(f"Bounding box for image and ImageAnnotation ({annotation_id}) must be set")
 
         new_bounding_box = intersection_box(self._bbox, ann.bounding_box, self.width, self.height)
         if new_bounding_box.absolute_coords:
@@ -454,7 +455,7 @@ def image_ann_to_image(self, annotation_id: str, crop_image: bool = False) -> No
         if crop_image and self.image is not None:
             new_image.image = crop_box_from_image(self.image, ann.bounding_box, self.width, self.height)
         elif crop_image and self.image is None:
-            raise ValueError("crop_image = True requires self.image to be not None")
+            raise ImageError("crop_image = True requires self.image to be not None")
 
         ann.image = new_image
 
@@ -472,7 +473,7 @@ def maybe_ann_to_sub_image(self, annotation_id: str, category_names: Union[str,
 
         ann = self.get_annotation(annotation_ids=annotation_id)[0]
         if ann.image is None:
-            raise ValueError("When adding sub images to ImageAnnotation then ImageAnnotation.image must not be None")
+            raise ImageError("When adding sub images to ImageAnnotation then ImageAnnotation.image must not be None")
         assert ann.bounding_box is not None
         box = ann.bounding_box.to_list("xyxy")
         proposals = self.get_annotation(category_names)
@@ -485,7 +486,7 @@ def maybe_ann_to_sub_image(self, annotation_id: str, category_names: Union[str,
         sub_images = self.get_annotation(annotation_ids=selected_ids.tolist())
         for sub_image in sub_images:
             if sub_image.image is None:
-                raise ValueError(
+                raise ImageError(
                     "When setting an embedding to ImageAnnotation then ImageAnnotation.image must not be None"
                 )
             sub_image.image.set_embedding(
diff --git a/deepdoctection/datapoint/view.py b/deepdoctection/datapoint/view.py
index 6db3ebb4..c0f7bde2 100644
--- a/deepdoctection/datapoint/view.py
+++ b/deepdoctection/datapoint/view.py
@@ -26,6 +26,7 @@
 import numpy as np
 
 from ..utils.detection_types import ImageType, JsonDict, Pathlike
+from ..utils.error import AnnotationError, ImageError
 from ..utils.logger import LoggingRecord, logger
 from ..utils.settings import (
     CellType,
@@ -96,7 +97,7 @@ def viz(self, interactive: bool = False) -> Optional[ImageType]:
                 interactive_imshow(np_image)
                 return None
             return np_image
-        raise ValueError(f"base_page.image is None for {self.annotation_id}")
+        raise AnnotationError(f"base_page.image is None for {self.annotation_id}")
 
     def __getattr__(self, item: str) -> Optional[Union[str, int, List[str]]]:
         """
@@ -115,7 +116,7 @@ def __getattr__(self, item: str) -> Optional[Union[str, int, List[str]]]:
         :return: value according to the logic described above
         """
         if item not in self.get_attribute_names():
-            raise AttributeError(f"Attribute {item} is not supported for {type(self)}")
+            raise AnnotationError(f"Attribute {item} is not supported for {type(self)}")
         if item in self.sub_categories:
             sub_cat = self.get_sub_category(get_type(item))
             if item != sub_cat.category_name:
@@ -326,7 +327,7 @@ def __str__(self) -> str:
     def text(self) -> str:
         try:
             return str(self)
-        except TypeError:
+        except (TypeError, AnnotationError):
             return super().text
 
     @property
@@ -368,7 +369,7 @@ def get_ordered_words(self) -> List[ImageAnnotationBaseView]:
             for cell in cells:
                 all_words.extend(cell.get_ordered_words())  # type: ignore
             return all_words
-        except TypeError:
+        except (TypeError, AnnotationError):
             return super().get_ordered_words()
 
 
@@ -485,7 +486,7 @@ def get_annotation(
 
     def __getattr__(self, item: str) -> Any:
         if item not in self.get_attribute_names():
-            raise AttributeError(f"Attribute {item} is not supported for {type(self)}")
+            raise ImageError(f"Attribute {item} is not supported for {type(self)}")
         if self.summary is not None:
             if item in self.summary.sub_categories:
                 sub_cat = self.summary.get_sub_category(get_type(item))
@@ -629,10 +630,10 @@ def get_layout_context(self, annotation_id: str, context_size: int = 3) -> List[
         """
         ann = self.get_annotation(annotation_ids=annotation_id)[0]
         if ann.category_name not in self.floating_text_block_categories:
-            raise ValueError(
-                f"Annotation {annotation_id} with category_name {ann.category_name} is not a floating text "
-                f"block category. Cannot get context. Make sure to make this category a floating text "
-                f"block"
+            raise ImageError(
+                f"Cannot get context. Make sure to parametrize this category to a floating text: "
+                f"annotation_id: {annotation_id},"
+                f"category_name: {ann.category_name}"
             )
         block_with_order = self._order("layouts")
         position = block_with_order.index(ann)
diff --git a/deepdoctection/datasets/adapter.py b/deepdoctection/datasets/adapter.py
index f24c15ab..cef23a46 100644
--- a/deepdoctection/datasets/adapter.py
+++ b/deepdoctection/datasets/adapter.py
@@ -165,4 +165,4 @@ def __len__(self) -> int:
         return len(self.df)
 
     def __getitem__(self, item: Any) -> None:
-        raise NotImplementedError
+        raise NotImplementedError()
diff --git a/deepdoctection/datasets/base.py b/deepdoctection/datasets/base.py
index c41fb6b6..1cb555f8 100644
--- a/deepdoctection/datasets/base.py
+++ b/deepdoctection/datasets/base.py
@@ -51,9 +51,11 @@ def __init__(self) -> None:
         self._dataflow_builder.splits = self._dataset_info.splits
 
         if not self.dataset_available() and self.is_built_in():
-            print(
-                f"Dataset {self._dataset_info.name} not locally found. Please download at {self._dataset_info.url}"
-                f" and place under {self._dataflow_builder.get_workdir()}"
+            logger.warning(
+                LoggingRecord(
+                    f"Dataset {self._dataset_info.name} not locally found. Please download at {self._dataset_info.url}"
+                    f" and place under {self._dataflow_builder.get_workdir()}"
+                )
             )
 
     @property
diff --git a/deepdoctection/datasets/dataflow_builder.py b/deepdoctection/datasets/dataflow_builder.py
index b79e34ce..7b31c290 100644
--- a/deepdoctection/datasets/dataflow_builder.py
+++ b/deepdoctection/datasets/dataflow_builder.py
@@ -110,7 +110,7 @@ def build(self, **kwargs: Union[str, int]) -> DataFlow:
         :param kwargs: A custom set of arguments/values
         :return: dataflow
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     def get_annotation_file(self, split: str) -> str:
         """Get single annotation file."""
diff --git a/deepdoctection/datasets/info.py b/deepdoctection/datasets/info.py
index b3e68c15..a491bb81 100644
--- a/deepdoctection/datasets/info.py
+++ b/deepdoctection/datasets/info.py
@@ -306,7 +306,7 @@ def set_cat_to_sub_cat(self, cat_to_sub_cat: Dict[TypeOrStr, TypeOrStr]) -> None
 
         _cat_to_sub_cat = {get_type(key): get_type(value) for key, value in cat_to_sub_cat.items()}
         if not self._allow_update:
-            raise PermissionError("Replacing categories with sub categories is not allowed")
+            raise RuntimeWarning("Replacing categories with sub categories is not allowed")
         self._categories_update = self.init_categories
         categories = self.get_categories(name_as_key=True)
         cats_or_sub_cats = [
@@ -332,7 +332,7 @@ def filter_categories(self, categories: Union[TypeOrStr, List[TypeOrStr]]) -> No
         """
 
         if not self._allow_update:
-            raise PermissionError("Filtering categories is not allowed")
+            raise RuntimeWarning("Filtering categories is not allowed")
         if isinstance(categories, (ObjectTypes, str)):
             categories = [get_type(categories)]
         else:
diff --git a/deepdoctection/eval/accmetric.py b/deepdoctection/eval/accmetric.py
index 63a57ad6..f04c406b 100644
--- a/deepdoctection/eval/accmetric.py
+++ b/deepdoctection/eval/accmetric.py
@@ -87,7 +87,7 @@ def accuracy(label_gt: Sequence[int], label_predictions: Sequence[int], masks: O
     np_label_gt, np_label_pr = np.asarray(label_gt), np.asarray(label_predictions)
     if len(np_label_gt) != len(np_label_pr):
         raise ValueError(
-            f"length of label_gt ({len(np_label_gt)}) and label_predictions" f" ({len(np_label_pr)}) must be equal"
+            f"length label_gt: {len(np_label_gt)}, length label_predictions: ({len(np_label_pr)}) but must be equal"
         )
     if masks is not None:
         np_label_gt, np_label_pr = _mask_some_gt_and_pr_labels(np_label_gt, np_label_pr, masks)
diff --git a/deepdoctection/eval/base.py b/deepdoctection/eval/base.py
index ded9ff0b..0c4f15e2 100644
--- a/deepdoctection/eval/base.py
+++ b/deepdoctection/eval/base.py
@@ -25,6 +25,7 @@
 from ..dataflow import DataFlow
 from ..datasets.info import DatasetCategories
 from ..utils.detection_types import JsonDict
+from ..utils.error import DependencyError
 from ..utils.file_utils import Requirement
 
 
@@ -52,7 +53,7 @@ def __new__(cls, *args, **kwargs):  # type: ignore # pylint: disable=W0613
         requirements = cls.get_requirements()
         name = cls.__name__ if hasattr(cls, "__name__") else cls.__class__.__name__
         if not all(requirement[1] for requirement in requirements):
-            raise ImportError(
+            raise DependencyError(
                 "\n".join(
                     [f"{name} has the following dependencies:"]
                     + [requirement[2] for requirement in requirements if not requirement[1]]
@@ -66,7 +67,7 @@ def get_requirements(cls) -> List[Requirement]:
         """
         Get a list of requirements for running the detector
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @classmethod
     @abstractmethod
@@ -80,7 +81,7 @@ def get_distance(
         :param dataflow_predictions: Dataflow with predictions.
         :param categories:  DatasetCategories with respect to the underlying dataset.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @classmethod
     @abstractmethod
@@ -95,7 +96,7 @@ def dump(
         :param dataflow_predictions: Dataflow with predictions.
         :param categories: DatasetCategories with respect to the underlying dataset.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @classmethod
     def result_list_to_dict(cls, results: List[JsonDict]) -> JsonDict:
diff --git a/deepdoctection/eval/eval.py b/deepdoctection/eval/eval.py
index 614b7557..b66b79e5 100644
--- a/deepdoctection/eval/eval.py
+++ b/deepdoctection/eval/eval.py
@@ -171,7 +171,7 @@ def __init__(
                         "metric has no attribute sub_cats and cannot be used for token classification datasets"
                     )
             else:
-                raise NotImplementedError
+                raise NotImplementedError()
 
         else:
             self.wandb_table_agent = None
@@ -271,7 +271,7 @@ def _clean_up_predict_dataflow_annotations(self, df_pr: DataFlow) -> DataFlow:
             sub_cats_to_remove = meta_anns["sub_categories"]
             df_pr = MapData(df_pr, remove_cats(sub_categories=sub_cats_to_remove))
         else:
-            raise NotImplementedError
+            raise NotImplementedError()
 
         return df_pr
 
diff --git a/deepdoctection/eval/tp_eval_callback.py b/deepdoctection/eval/tp_eval_callback.py
index 05bca92f..4c36a4cc 100644
--- a/deepdoctection/eval/tp_eval_callback.py
+++ b/deepdoctection/eval/tp_eval_callback.py
@@ -83,10 +83,11 @@ def __init__(
         self.num_gpu = get_num_gpu()
         self.category_names = category_names
         self.sub_categories = sub_categories
-        assert isinstance(pipeline_component.predictor, TPFrcnnDetector), (
-            f"pipeline_component.predictor must be of "
-            f"type TPFrcnnDetector but is type {type(pipeline_component.predictor)}"
-        )
+        if not isinstance(pipeline_component.predictor, TPFrcnnDetector):
+            raise TypeError(
+                f"pipeline_component.predictor must be of type TPFrcnnDetector but is "
+                f"type {type(pipeline_component.predictor)}"
+            )
         self.cfg = pipeline_component.predictor.model.cfg
         if _use_replicated(self.cfg):
             self.evaluator = Evaluator(dataset, pipeline_component, metric, num_threads=self.num_gpu * 2)
diff --git a/deepdoctection/extern/pt/ptutils.py b/deepdoctection/extern/pt/ptutils.py
index 3543517b..767081db 100644
--- a/deepdoctection/extern/pt/ptutils.py
+++ b/deepdoctection/extern/pt/ptutils.py
@@ -20,6 +20,7 @@
 """
 
 
+from ...utils.error import DependencyError
 from ...utils.file_utils import pytorch_available
 
 
@@ -31,7 +32,7 @@ def set_torch_auto_device() -> "torch.device":  # type: ignore
         from torch import cuda, device  # pylint: disable=C0415
 
         return device("cuda" if cuda.is_available() else "cpu")
-    raise ModuleNotFoundError("Pytorch must be installed")
+    raise DependencyError("Pytorch must be installed")
 
 
 def get_num_gpu() -> int:
@@ -45,4 +46,4 @@ def get_num_gpu() -> int:
         from torch import cuda  # pylint: disable=C0415
 
         return cuda.device_count()
-    raise ModuleNotFoundError("Pytorch must be installed")
+    raise DependencyError("Pytorch must be installed")
diff --git a/deepdoctection/extern/tessocr.py b/deepdoctection/extern/tessocr.py
index b80ae368..0d6b25d9 100644
--- a/deepdoctection/extern/tessocr.py
+++ b/deepdoctection/extern/tessocr.py
@@ -30,7 +30,8 @@
 
 from ..utils.context import save_tmp_file, timeout_manager
 from ..utils.detection_types import ImageType, Requirement
-from ..utils.file_utils import _TESS_PATH, TesseractNotFound, get_tesseract_requirement
+from ..utils.error import DependencyError, TesseractError
+from ..utils.file_utils import _TESS_PATH, get_tesseract_requirement
 from ..utils.metacfg import config_to_cli_str, set_config_by_yaml
 from ..utils.settings import LayoutType, ObjectTypes
 from .base import DetectionResult, ObjectDetector, PredictorBase
@@ -57,18 +58,6 @@
 }
 
 
-class TesseractError(RuntimeError):
-    """
-    Tesseract Error
-    """
-
-    def __init__(self, status: int, message: str) -> None:
-        super().__init__()
-        self.status = status
-        self.message = message
-        self.args = (status, message)
-
-
 def _subprocess_args() -> Dict[str, Any]:
     # See https://github.com/pyinstaller/pyinstaller/wiki/Recipe-subprocess
     # for reference and comments.
@@ -109,7 +98,7 @@ def _run_tesseract(tesseract_args: List[str]) -> None:
     except OSError as error:
         if error.errno != ENOENT:
             raise error from error
-        raise TesseractNotFound("Tesseract not found. Please install or add to your PATH.") from error
+        raise DependencyError("Tesseract not found. Please install or add to your PATH.") from error
 
     with timeout_manager(proc, 0) as error_string:
         if proc.returncode:
diff --git a/deepdoctection/extern/tp/tpcompat.py b/deepdoctection/extern/tp/tpcompat.py
index 550559ce..35dad087 100644
--- a/deepdoctection/extern/tp/tpcompat.py
+++ b/deepdoctection/extern/tp/tpcompat.py
@@ -55,7 +55,7 @@ def get_inference_tensor_names(self) -> Tuple[List[str], List[str]]:
 
         :return: Tuple of list input and list output names. The names must coincide with tensor within the model.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class TensorpackPredictor(ABC):
@@ -113,7 +113,7 @@ def set_model(
         Implement the config generation, its modification and instantiate a version of the model. See
         `pipe.tpfrcnn.TPFrcnnDetector` for an example
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @abstractmethod
     def predict(self, np_img: Any) -> Any:
@@ -121,7 +121,7 @@ def predict(self, np_img: Any) -> Any:
         Implement, how `self.tp_predictor` is invoked and raw prediction results are generated. Do use only raw
         objects and nothing, which is related to the DD API.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @property
     def model(self) -> ModelDescWithConfig:
diff --git a/deepdoctection/extern/tp/tpfrcnn/preproc.py b/deepdoctection/extern/tp/tpfrcnn/preproc.py
index 0435ebdc..0912074b 100644
--- a/deepdoctection/extern/tp/tpfrcnn/preproc.py
+++ b/deepdoctection/extern/tp/tpfrcnn/preproc.py
@@ -18,6 +18,7 @@
 
 from ....datapoint.convert import box_to_point4, point4_to_box
 from ....utils.detection_types import ImageType, JsonDict
+from ....utils.error import MalformedData
 from ....utils.logger import log_once
 from .common import filter_boxes_inside_shape, np_iou
 from .modeling.model_fpn import get_all_anchors_fpn
@@ -27,12 +28,6 @@
 # pylint: enable=import-error
 
 
-class MalformedData(BaseException):
-    """
-    Exception class for malformed data
-    """
-
-
 def augment(dp: JsonDict, imgaug_list: List[ImageAugmentor], add_mask: bool) -> JsonDict:
     """
     Augment an image according to a list of augmentors.
@@ -62,7 +57,7 @@ def augment(dp: JsonDict, imgaug_list: List[ImageAugmentor], add_mask: bool) ->
         assert np.min(np_area(gt_boxes)) > 0, "some boxes have zero area"
 
     if add_mask:
-        raise NotImplementedError
+        raise NotImplementedError()
 
     return dp
 
diff --git a/deepdoctection/mapper/d2struct.py b/deepdoctection/mapper/d2struct.py
index f38a84f1..1b90bc1b 100644
--- a/deepdoctection/mapper/d2struct.py
+++ b/deepdoctection/mapper/d2struct.py
@@ -93,7 +93,7 @@ def image_to_d2_frcnn_training(
         annotations.append(mapped_ann)
 
         if add_mask:
-            raise NotImplementedError
+            raise NotImplementedError("Segmentation in deepdoctection is not supported")
 
     output["annotations"] = annotations
 
diff --git a/deepdoctection/mapper/hfstruct.py b/deepdoctection/mapper/hfstruct.py
index 2194906c..84a1c2a9 100644
--- a/deepdoctection/mapper/hfstruct.py
+++ b/deepdoctection/mapper/hfstruct.py
@@ -81,7 +81,7 @@ def image_to_hf_detr_training(
         annotations.append(mapped_ann)
 
     if add_mask:
-        raise NotImplementedError
+        raise NotImplementedError("Segmentation in deepdoctection is not supported")
 
     output["annotations"] = annotations
 
diff --git a/deepdoctection/mapper/laylmstruct.py b/deepdoctection/mapper/laylmstruct.py
index c312e33f..60e2c228 100644
--- a/deepdoctection/mapper/laylmstruct.py
+++ b/deepdoctection/mapper/laylmstruct.py
@@ -146,7 +146,7 @@ def image_to_raw_layoutlm_features(
             raise TypeError(f"char_cat must be of type ContainerAnnotation but is of type {type(char_cat)}")
         word = char_cat.value
         if not isinstance(word, str):
-            raise ValueError(f"word must be of type str but is of type {type(word)}")
+            raise TypeError(f"word must be of type str but is of type {type(word)}")
         all_words.append(word)
 
         box = ann.get_bounding_box(dp.image_id)
diff --git a/deepdoctection/mapper/maputils.py b/deepdoctection/mapper/maputils.py
index f29930f0..e67115cf 100644
--- a/deepdoctection/mapper/maputils.py
+++ b/deepdoctection/mapper/maputils.py
@@ -28,8 +28,8 @@
 from tabulate import tabulate
 from termcolor import colored
 
-from ..datapoint.box import BoundingBoxError
 from ..utils.detection_types import DP, BaseExceptionType, S, T
+from ..utils.error import AnnotationError, BoundingBoxError, ImageError, UUIDError
 from ..utils.logger import LoggingRecord, logger
 from ..utils.settings import ObjectTypes
 
@@ -72,7 +72,18 @@ def __exit__(
         """
         if (
             exc_type
-            in (KeyError, ValueError, IndexError, AssertionError, TypeError, BoundingBoxError, FileNotFoundError)
+            in (
+                KeyError,
+                ValueError,
+                IndexError,
+                AssertionError,
+                TypeError,
+                FileNotFoundError,
+                BoundingBoxError,
+                AnnotationError,
+                ImageError,
+                UUIDError,
+            )
             and exc_tb is not None
         ):
             frame_summary = traceback.extract_tb(exc_tb)[0]
diff --git a/deepdoctection/mapper/prodigystruct.py b/deepdoctection/mapper/prodigystruct.py
index 327103e3..70fa8ff2 100644
--- a/deepdoctection/mapper/prodigystruct.py
+++ b/deepdoctection/mapper/prodigystruct.py
@@ -128,7 +128,7 @@ def prodigy_to_image(
             else:
                 label = span["label"]
             if not isinstance(label, str):
-                raise ValueError("label could not assigned to be a string")
+                raise TypeError("label must be a string")
 
             annotation = ImageAnnotation(
                 category_name=label,
diff --git a/deepdoctection/mapper/pubstruct.py b/deepdoctection/mapper/pubstruct.py
index a3e8256b..7c93982a 100644
--- a/deepdoctection/mapper/pubstruct.py
+++ b/deepdoctection/mapper/pubstruct.py
@@ -75,12 +75,14 @@ def _cell_token(html: Sequence[str]) -> List[List[int]]:
 def _item_spans(html: Sequence[str], index_cells: Sequence[Sequence[int]], item: str) -> List[List[int]]:
     item_spans = [
         [
-            int(html[index_cell - 1].replace(item + "=", "").replace('"', ""))
-            if (item in html[index_cell - 1] and html[index_cell] == ">")
-            else (
-                int(html[index_cell - 2].replace(item + "=", "").replace('"', ""))
-                if (item in html[index_cell - 2] and html[index_cell] == ">")
-                else 1
+            (
+                int(html[index_cell - 1].replace(item + "=", "").replace('"', ""))
+                if (item in html[index_cell - 1] and html[index_cell] == ">")
+                else (
+                    int(html[index_cell - 2].replace(item + "=", "").replace('"', ""))
+                    if (item in html[index_cell - 2] and html[index_cell] == ">")
+                    else 1
+                )
             )
             for index_cell in index_cell_per_row
         ]
@@ -210,9 +212,7 @@ def _add_items(image: Image, item_type: str, categories_name_as_key: Dict[str, s
         items = image.get_annotation(category_names=TableType.item)
         item_type_anns = [ann for ann in items if ann.get_sub_category(TableType.item).category_name == item_type]
         item_type_anns.sort(
-            key=lambda x: x.bounding_box.cx  # type: ignore
-            if item_type == LayoutType.column
-            else x.bounding_box.cy  # type: ignore
+            key=lambda x: (x.bounding_box.cx if item_type == LayoutType.column else x.bounding_box.cy)  # type: ignore
         )
         if table.bounding_box:
             tmp_item_xy = table.bounding_box.uly + 1.0 if item_type == LayoutType.row else table.bounding_box.ulx + 1.0
@@ -389,7 +389,7 @@ def pub_to_image_uncur(  # pylint: disable=R0914
     with MappingContextManager(str(idx)) as mapping_context:
         max_rs, max_cs = 0, 0
         if idx is None:
-            raise ValueError("No valid datapoint external id")
+            raise TypeError("imgid is None but must be a string")
 
         image = Image(file_name=os.path.split(dp["filename"])[1], location=dp["filename"], external_id=idx)
 
diff --git a/deepdoctection/mapper/tpstruct.py b/deepdoctection/mapper/tpstruct.py
index d6c170bd..8704169d 100644
--- a/deepdoctection/mapper/tpstruct.py
+++ b/deepdoctection/mapper/tpstruct.py
@@ -67,7 +67,7 @@ def image_to_tp_frcnn_training(
         all_categories.append(ann.category_id)
 
         if add_mask:
-            raise NotImplementedError
+            raise NotImplementedError()
 
     output["gt_boxes"] = np.asarray(all_boxes, dtype="float32")
     output["gt_labels"] = np.asarray(all_categories, dtype="int32")
diff --git a/deepdoctection/pipe/base.py b/deepdoctection/pipe/base.py
index 9eebb15f..be07c7c0 100644
--- a/deepdoctection/pipe/base.py
+++ b/deepdoctection/pipe/base.py
@@ -75,7 +75,7 @@ def serve(self, dp: Image) -> None:
         As a simplified interface `serve` does not have to return a dp. The data point is passed on within
         pipelines internally (via `pass_datapoint`).
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     def pass_datapoint(self, dp: Image) -> Image:
         """
@@ -109,7 +109,7 @@ def clone(self) -> "PipelineComponent":
         """
         Clone an instance
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     @abstractmethod
     def get_meta_annotation(self) -> JsonDict:
@@ -122,7 +122,7 @@ def get_meta_annotation(self) -> JsonDict:
         `summaries` with values: A list of summary sub categories
         :return: Dict with meta infos as just described
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     def _meta_has_all_types(self) -> None:
         if not {"image_annotations", "sub_categories", "relationships", "summaries"}.issubset(
@@ -154,7 +154,7 @@ def __init__(
 
     @abstractmethod
     def clone(self) -> "PredictorPipelineComponent":
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class LanguageModelPipelineComponent(PipelineComponent, ABC):
@@ -183,7 +183,7 @@ def clone(self) -> "LanguageModelPipelineComponent":
         """
         Clone an instance
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class ImageTransformPipelineComponent(PipelineComponent, ABC):
@@ -206,7 +206,7 @@ def clone(self) -> "ImageTransformPipelineComponent":
         """
         Clone an instance
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class Pipeline(ABC):
@@ -254,7 +254,7 @@ def _entry(self, **kwargs: Any) -> DataFlow:
 
         :param kwargs: Arguments, for dynamic customizing of the processing or for the transfer of processing types
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     def _build_pipe(self, df: DataFlow) -> DataFlow:
         """
@@ -277,7 +277,7 @@ def analyze(self, **kwargs: Any) -> DataFlow:
 
         can be triggered.
         """
-        raise NotImplementedError
+        raise NotImplementedError()
 
     def get_meta_annotation(self) -> JsonDict:
         """
diff --git a/deepdoctection/pipe/doctectionpipe.py b/deepdoctection/pipe/doctectionpipe.py
index 538c5f0e..ea465e9d 100644
--- a/deepdoctection/pipe/doctectionpipe.py
+++ b/deepdoctection/pipe/doctectionpipe.py
@@ -82,7 +82,6 @@ def _proto_process(
     else:
         path_tmp = path
     logger.info(LoggingRecord(f"Processing {file_name}", {"path": path_tmp, "df": path_tmp, "file_name": file_name}))
-    # logger.info("Processing %s", file_name, {"path": path_tmp, "df": path_tmp, "file_name": file_name})
     return dp
 
 
diff --git a/deepdoctection/pipe/language.py b/deepdoctection/pipe/language.py
index 6d422942..b06f5007 100644
--- a/deepdoctection/pipe/language.py
+++ b/deepdoctection/pipe/language.py
@@ -25,6 +25,7 @@
 from ..datapoint.view import Page
 from ..extern.base import LanguageDetector, ObjectDetector
 from ..utils.detection_types import JsonDict
+from ..utils.error import ImageError
 from ..utils.settings import PageType, TypeOrStr, get_type
 from .base import PipelineComponent
 from .registry import pipeline_component_registry
@@ -86,7 +87,7 @@ def serve(self, dp: Image) -> None:
             text = page.text_no_line_break
         else:
             if dp.image is None:
-                raise ValueError("dp.image cannot be None")
+                raise ImageError("image cannot be None")
             detect_result_list = self.text_detector.predict(dp.image)
             # this is a concatenation of all detection result. No reading order
             text = " ".join([result.text for result in detect_result_list if result.text is not None])
@@ -98,7 +99,7 @@ def serve(self, dp: Image) -> None:
     def clone(self) -> PipelineComponent:
         predictor = self.predictor.clone()
         if not isinstance(predictor, LanguageDetector):
-            raise ValueError(f"Predictor must be of type LanguageDetector, but is of type {type(predictor)}")
+            raise TypeError(f"Predictor must be of type LanguageDetector, but is of type {type(predictor)}")
         return self.__class__(
             predictor,
             copy(self.text_container),
diff --git a/deepdoctection/pipe/layout.py b/deepdoctection/pipe/layout.py
index 3cff4905..e0997b70 100644
--- a/deepdoctection/pipe/layout.py
+++ b/deepdoctection/pipe/layout.py
@@ -25,6 +25,7 @@
 from ..datapoint.image import Image
 from ..extern.base import ObjectDetector, PdfMiner
 from ..utils.detection_types import JsonDict
+from ..utils.error import ImageError
 from ..utils.transform import PadTransform
 from .base import PredictorPipelineComponent
 from .registry import pipeline_component_registry
@@ -79,7 +80,7 @@ def serve(self, dp: Image) -> None:
             if anns:
                 return
         if dp.image is None:
-            raise ValueError("image cannot be None")
+            raise ImageError("image cannot be None")
         np_image = dp.image
         if self.padder:
             np_image = self.padder.apply_image(np_image)
@@ -114,5 +115,5 @@ def clone(self) -> "PredictorPipelineComponent":
         if self.padder:
             padder_clone = self.padder.clone()
         if not isinstance(predictor, ObjectDetector):
-            raise ValueError(f"predictor must be of type ObjectDetector, but is of type {type(predictor)}")
+            raise TypeError(f"predictor must be of type ObjectDetector, but is of type {type(predictor)}")
         return self.__class__(predictor, self.to_image, self.crop_image, padder_clone, self.skip_if_layout_extracted)
diff --git a/deepdoctection/pipe/lm.py b/deepdoctection/pipe/lm.py
index 28b1a3cb..e121e94d 100644
--- a/deepdoctection/pipe/lm.py
+++ b/deepdoctection/pipe/lm.py
@@ -252,7 +252,7 @@ def _init_sanity_checks(self) -> None:
             self.language_model.model.__class__.__name__, use_xlm_tokenizer
         )
         if not isinstance(self.tokenizer, type(tokenizer_reference)):
-            raise ValueError(
+            raise TypeError(
                 f"You want to use {type(self.tokenizer)} but you should use {type(tokenizer_reference)} "
                 f"in this framework"
             )
@@ -366,7 +366,7 @@ def _init_sanity_checks(self) -> None:
             self.language_model.model.__class__.__name__, use_xlm_tokenizer
         )
         if not isinstance(self.tokenizer, type(tokenizer_reference)):
-            raise ValueError(
+            raise TypeError(
                 f"You want to use {type(self.tokenizer)} but you should use {type(tokenizer_reference)} "
                 f"in this framework"
             )
diff --git a/deepdoctection/pipe/refine.py b/deepdoctection/pipe/refine.py
index 2067b11d..62a75b8b 100644
--- a/deepdoctection/pipe/refine.py
+++ b/deepdoctection/pipe/refine.py
@@ -33,6 +33,7 @@
 from ..extern.base import DetectionResult
 from ..mapper.maputils import MappingContextManager
 from ..utils.detection_types import JsonDict
+from ..utils.error import ImageError
 from ..utils.settings import CellType, LayoutType, Relationships, TableType, get_type
 from .base import PipelineComponent
 from .registry import pipeline_component_registry
@@ -302,7 +303,7 @@ def generate_html_string(table: ImageAnnotation) -> List[str]:
     :return: HTML representation of the table
     """
     if table.image is None:
-        raise ValueError("table.image cannot be None")
+        raise ImageError("table.image cannot be None")
     table_image = table.image
     cells = table_image.get_annotation(
         category_names=[
@@ -412,7 +413,7 @@ def serve(self, dp: Image) -> None:
         tables = dp.get_annotation(category_names=self._table_name)
         for table in tables:
             if table.image is None:
-                raise ValueError("table.image cannot be None")
+                raise ImageError("table.image cannot be None")
             tiles_to_cells_list = tiles_to_cells(dp, table)
             connected_components, tile_to_cell_dict = connected_component_tiles(tiles_to_cells_list)
             rectangle_tiling = generate_rectangle_tiling(connected_components)
diff --git a/deepdoctection/pipe/segment.py b/deepdoctection/pipe/segment.py
index a42d3699..d7c97758 100644
--- a/deepdoctection/pipe/segment.py
+++ b/deepdoctection/pipe/segment.py
@@ -33,6 +33,7 @@
 from ..mapper.maputils import MappingContextManager
 from ..mapper.match import match_anns_by_intersection
 from ..utils.detection_types import JsonDict
+from ..utils.error import ImageError
 from ..utils.settings import CellType, LayoutType, ObjectTypes, Relationships, TableType
 from .base import PipelineComponent
 from .refine import generate_html_string
@@ -136,12 +137,12 @@ def stretch_item_per_table(
 
     rows = dp.get_annotation(category_names=row_name, annotation_ids=item_ann_ids)
     if table.image is None:
-        raise ValueError("table.image cannot be None")
+        raise ImageError("table.image cannot be None")
     table_embedding_box = table.get_bounding_box(dp.image_id)
 
     for row in rows:
         if row.image is None:
-            raise ValueError("row.image cannot be None")
+            raise ImageError("row.image cannot be None")
         row_embedding_box = row.get_bounding_box(dp.image_id)
         row_embedding_box.ulx = table_embedding_box.ulx + 1.0
         row_embedding_box.lrx = table_embedding_box.lrx - 1.0
@@ -166,7 +167,7 @@ def stretch_item_per_table(
 
     for col in cols:
         if col.image is None:
-            raise ValueError("row.image cannot be None")
+            raise ImageError("row.image cannot be None")
         col_embedding_box = col.get_bounding_box(dp.image_id)
         col_embedding_box.uly = table_embedding_box.uly + 1.0
         col_embedding_box.lry = table_embedding_box.lry - 1.0
@@ -194,7 +195,7 @@ def _tile_by_stretching_rows_left_and_rightwise(
     dp: Image, items: List[ImageAnnotation], table: ImageAnnotation, item_name: str
 ) -> None:
     if table.image is None:
-        raise ValueError("table.image cannot be None")
+        raise ImageError("table.image cannot be None")
     table_embedding_box = table.get_bounding_box(dp.image_id)
 
     tmp_item_xy = table_embedding_box.uly + 1.0 if item_name == LayoutType.row else table_embedding_box.ulx + 1.0
@@ -206,7 +207,7 @@ def _tile_by_stretching_rows_left_and_rightwise(
             image_annotation={"category_name": item.category_name, "annotation_id": item.annotation_id},
         ):
             if item.image is None:
-                raise ValueError("item.image cannot be None")
+                raise ImageError("item.image cannot be None")
             item_embedding_box = item.get_bounding_box(dp.image_id)
             if idx != len(items) - 1:
                 next_item_embedding_box = items[idx + 1].get_bounding_box(dp.image_id)
@@ -258,7 +259,7 @@ def _tile_by_stretching_rows_leftwise_column_downwise(
     dp: Image, items: List[ImageAnnotation], table: ImageAnnotation, item_name: str
 ) -> None:
     if table.image is None:
-        raise ValueError("table.image cannot be None")
+        raise ImageError("table.image cannot be None")
     table_embedding_box = table.get_bounding_box(dp.image_id)
 
     tmp_item_xy = table_embedding_box.uly + 1.0 if item_name == LayoutType.row else table_embedding_box.ulx + 1.0
@@ -270,7 +271,7 @@ def _tile_by_stretching_rows_leftwise_column_downwise(
             image_annotation={"category_name": item.category_name, "annotation_id": item.annotation_id},
         ):
             if item.image is None:
-                raise ValueError("item.image cannot be None")
+                raise ImageError("item.image cannot be None")
             item_embedding_box = item.get_bounding_box(dp.image_id)
             new_embedding_box = BoundingBox(
                 ulx=item_embedding_box.ulx if item_name == LayoutType.row else tmp_item_xy,
@@ -339,9 +340,9 @@ def tile_tables_with_items_per_table(
     items = dp.get_annotation(category_names=item_name, annotation_ids=item_ann_ids)
 
     items.sort(
-        key=lambda x: x.get_bounding_box(dp.image_id).cx
-        if item_name == LayoutType.column
-        else x.get_bounding_box(dp.image_id).cy
+        key=lambda x: (
+            x.get_bounding_box(dp.image_id).cx if item_name == LayoutType.column else x.get_bounding_box(dp.image_id).cy
+        )
     )
 
     if stretch_rule == "left":
@@ -737,9 +738,11 @@ def serve(self, dp: Image) -> None:
 
                 # we will assume that either all or no image attribute has been generated
                 items.sort(
-                    key=lambda x: x.get_bounding_box(dp.image_id).cx  # pylint: disable=W0640
-                    if item_name == LayoutType.column  # pylint: disable=W0640
-                    else x.get_bounding_box(dp.image_id).cy  # pylint: disable=W0640
+                    key=lambda x: (
+                        x.get_bounding_box(dp.image_id).cx  # pylint: disable=W0640
+                        if item_name == LayoutType.column  # pylint: disable=W0640
+                        else x.get_bounding_box(dp.image_id).cy  # pylint: disable=W0640
+                    )
                 )
 
                 for item_number, item in enumerate(items, 1):
@@ -939,9 +942,11 @@ def serve(self, dp: Image) -> None:
 
                 # we will assume that either all or no image attribute has been generated
                 items.sort(
-                    key=lambda x: x.get_bounding_box(dp.image_id).cx
-                    if item_name == LayoutType.column  # pylint: disable=W0640
-                    else x.get_bounding_box(dp.image_id).cy
+                    key=lambda x: (
+                        x.get_bounding_box(dp.image_id).cx
+                        if item_name == LayoutType.column  # pylint: disable=W0640
+                        else x.get_bounding_box(dp.image_id).cy
+                    )
                 )
 
                 for item_number, item in enumerate(items, 1):
diff --git a/deepdoctection/pipe/text.py b/deepdoctection/pipe/text.py
index 5925cea4..070426f6 100644
--- a/deepdoctection/pipe/text.py
+++ b/deepdoctection/pipe/text.py
@@ -26,6 +26,7 @@
 from ..extern.base import ObjectDetector, PdfMiner, TextRecognizer
 from ..extern.tessocr import TesseractOcrDetector
 from ..utils.detection_types import ImageType, JsonDict
+from ..utils.error import ImageError
 from ..utils.settings import PageType, TypeOrStr, WordType, get_type
 from .base import PredictorPipelineComponent
 from .registry import pipeline_component_registry
@@ -89,7 +90,10 @@ def __init__(
         super().__init__(self._get_name(text_extract_detector.name), text_extract_detector)
         if self.extract_from_category:
             if not isinstance(self.predictor, (ObjectDetector, TextRecognizer)):
-                raise TypeError("Predicting from a cropped image requires to pass an ObjectDetector or TextRecognizer.")
+                raise TypeError(
+                    f"Predicting from a cropped image requires to pass an ObjectDetector or "
+                    f"TextRecognizer. Got {type(self.predictor)}"
+                )
         if run_time_ocr_language_selection:
             assert isinstance(
                 self.predictor, TesseractOcrDetector
@@ -171,13 +175,13 @@ def get_predictor_input(
 
         if isinstance(text_roi, ImageAnnotation):
             if text_roi.image is None:
-                raise ValueError("text_roi.image cannot be None")
+                raise ImageError("text_roi.image cannot be None")
             if text_roi.image.image is None:
-                raise ValueError("text_roi.image.image cannot be None")
+                raise ImageError("text_roi.image.image cannot be None")
             return text_roi.image.image
         if isinstance(self.predictor, ObjectDetector):
             if not isinstance(text_roi, Image):
-                raise ValueError("text_roi must be an image")
+                raise ImageError("text_roi must be an image")
             return text_roi.image
         if isinstance(text_roi, list):
             assert all(roi.image is not None for roi in text_roi)
@@ -201,9 +205,11 @@ def get_meta_annotation(self) -> JsonDict:
             [
                 (
                     "image_annotations",
-                    self.predictor.possible_categories()
-                    if isinstance(self.predictor, (ObjectDetector, PdfMiner))
-                    else [],
+                    (
+                        self.predictor.possible_categories()
+                        if isinstance(self.predictor, (ObjectDetector, PdfMiner))
+                        else []
+                    ),
                 ),
                 ("sub_categories", sub_cat_dict),
                 ("relationships", {}),
@@ -218,5 +224,5 @@ def _get_name(text_detector_name: str) -> str:
     def clone(self) -> "PredictorPipelineComponent":
         predictor = self.predictor.clone()
         if not isinstance(predictor, (ObjectDetector, PdfMiner, TextRecognizer)):
-            raise ValueError(f"predictor must be of type ObjectDetector or PdfMiner, but is of type {type(predictor)}")
+            raise ImageError(f"predictor must be of type ObjectDetector or PdfMiner, but is of type {type(predictor)}")
         return self.__class__(predictor, deepcopy(self.extract_from_category), self.run_time_ocr_language_selection)
diff --git a/deepdoctection/train/d2_frcnn_train.py b/deepdoctection/train/d2_frcnn_train.py
index 20524462..131861a5 100644
--- a/deepdoctection/train/d2_frcnn_train.py
+++ b/deepdoctection/train/d2_frcnn_train.py
@@ -43,6 +43,7 @@
 from ..mapper.d2struct import image_to_d2_frcnn_training
 from ..pipe.base import PredictorPipelineComponent
 from ..pipe.registry import pipeline_component_registry
+from ..utils.error import DependencyError
 from ..utils.file_utils import get_wandb_requirement, wandb_available
 from ..utils.logger import LoggingRecord, logger
 from ..utils.utils import string_to_dict
@@ -153,16 +154,18 @@ def build_hooks(self) -> List[HookBase]:
         ret = [
             hooks.IterationTimer(),
             hooks.LRScheduler(),
-            hooks.PreciseBN(
-                # Run at the same freq as (but before) evaluation.
-                cfg.TEST.EVAL_PERIOD,
-                self.model,  # pylint: disable=E1101
-                # Build a new data loader to not affect training
-                self.build_train_loader(cfg),
-                cfg.TEST.PRECISE_BN.NUM_ITER,
-            )
-            if cfg.TEST.PRECISE_BN.ENABLED and get_bn_modules(self.model)  # pylint: disable=E1101
-            else None,
+            (
+                hooks.PreciseBN(
+                    # Run at the same freq as (but before) evaluation.
+                    cfg.TEST.EVAL_PERIOD,
+                    self.model,  # pylint: disable=E1101
+                    # Build a new data loader to not affect training
+                    self.build_train_loader(cfg),
+                    cfg.TEST.PRECISE_BN.NUM_ITER,
+                )
+                if cfg.TEST.PRECISE_BN.ENABLED and get_bn_modules(self.model)  # pylint: disable=E1101
+                else None
+            ),
         ]
 
         # Do PreciseBN before checkpointer, because it updates the model and need to
@@ -201,7 +204,7 @@ def build_writers(self) -> List[EventWriter]:
         if self.cfg.WANDB.USE_WANDB:
             _, _wandb_available, err_msg = get_wandb_requirement()
             if not _wandb_available:
-                raise ImportError(err_msg)
+                raise DependencyError(err_msg)
             if self.cfg.WANDB.PROJECT is None:
                 raise ValueError("When using W&B, you must specify a project, i.e. WANDB.PROJECT")
             writers_list.append(WandbWriter(self.cfg.WANDB.PROJECT, self.cfg.WANDB.REPO, self.cfg))
@@ -269,7 +272,7 @@ def setup_evaluator(
 
     @classmethod
     def build_evaluator(cls, cfg, dataset_name):  # type: ignore
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 def train_d2_faster_rcnn(
diff --git a/deepdoctection/train/hf_detr_train.py b/deepdoctection/train/hf_detr_train.py
index 57bb2aef..ae568177 100644
--- a/deepdoctection/train/hf_detr_train.py
+++ b/deepdoctection/train/hf_detr_train.py
@@ -97,9 +97,9 @@ def setup_evaluator(
 
     def evaluate(
         self,
-        eval_dataset: Optional[Dataset[Any]] = None,
-        ignore_keys: Optional[List[str]] = None,
-        metric_key_prefix: str = "eval",
+        eval_dataset: Optional[Dataset[Any]] = None,  # pylint: disable=W0613
+        ignore_keys: Optional[List[str]] = None,  # pylint: disable=W0613
+        metric_key_prefix: str = "eval",  # pylint: disable=W0613
     ) -> Dict[str, float]:
         """
         Overwritten method from `Trainer`. Arguments will not be used.
@@ -193,9 +193,11 @@ def train_hf_detr(
         "remove_unused_columns": False,
         "per_device_train_batch_size": 2,
         "max_steps": number_samples,
-        "evaluation_strategy": "steps"
-        if (dataset_val is not None and metric is not None and pipeline_component_name is not None)
-        else "no",
+        "evaluation_strategy": (
+            "steps"
+            if (dataset_val is not None and metric is not None and pipeline_component_name is not None)
+            else "no"
+        ),
         "eval_steps": 5000,
     }
 
diff --git a/deepdoctection/train/hf_layoutlm_train.py b/deepdoctection/train/hf_layoutlm_train.py
index 876accef..d8be5dd2 100644
--- a/deepdoctection/train/hf_layoutlm_train.py
+++ b/deepdoctection/train/hf_layoutlm_train.py
@@ -63,6 +63,7 @@
 from ..pipe.lm import get_tokenizer_from_architecture
 from ..pipe.registry import pipeline_component_registry
 from ..utils.env_info import get_device
+from ..utils.error import DependencyError
 from ..utils.file_utils import wandb_available
 from ..utils.logger import LoggingRecord, logger
 from ..utils.settings import DatasetType, LayoutType, ObjectTypes, WordType
@@ -180,15 +181,17 @@ def setup_evaluator(
 
     def evaluate(
         self,
-        eval_dataset: Optional[Dataset[Any]] = None,
-        ignore_keys: Optional[List[str]] = None,
-        metric_key_prefix: str = "eval",
+        eval_dataset: Optional[Dataset[Any]] = None,  # pylint: disable=W0613
+        ignore_keys: Optional[List[str]] = None,  # pylint: disable=W0613
+        metric_key_prefix: str = "eval",  # pylint: disable=W0613
     ) -> Dict[str, float]:
         """
         Overwritten method from `Trainer`. Arguments will not be used.
         """
-        assert self.evaluator is not None
-        assert self.evaluator.pipe_component is not None
+        if self.evaluator is None:
+            raise ValueError("Evaluator not set up. Please use `setup_evaluator` before running evaluation")
+        if self.evaluator.pipe_component is None:
+            raise ValueError("Pipeline component not set up. Please use `setup_evaluator` before running evaluation")
 
         # memory metrics - must set up as early as possible
         self._memory_tracker.start()
@@ -222,7 +225,7 @@ def _get_model_class_and_tokenizer(
         raise KeyError("model_type and architectures not available in configs")
 
     if not model_cls:
-        raise ValueError("model not eligible to run with this framework")
+        raise UserWarning("model not eligible to run with this framework")
 
     return config_cls, model_cls, model_wrapper_cls, tokenizer_fast
 
@@ -347,7 +350,7 @@ def train_hf_layoutlm(
                 name_as_key=True,
             )[LayoutType.word][WordType.token_class]
     else:
-        raise ValueError("Dataset type not supported for training")
+        raise UserWarning("Dataset type not supported for training")
 
     config_cls, model_cls, model_wrapper_cls, tokenizer_fast = _get_model_class_and_tokenizer(
         path_config_json, dataset_type, use_xlm_tokenizer
@@ -374,9 +377,11 @@ def train_hf_layoutlm(
         "remove_unused_columns": False,
         "per_device_train_batch_size": 8,
         "max_steps": number_samples,
-        "evaluation_strategy": "steps"
-        if (dataset_val is not None and metric is not None and pipeline_component_name is not None)
-        else "no",
+        "evaluation_strategy": (
+            "steps"
+            if (dataset_val is not None and metric is not None and pipeline_component_name is not None)
+            else "no"
+        ),
         "eval_steps": 100,
         "use_wandb": False,
         "wandb_project": None,
@@ -416,7 +421,7 @@ def train_hf_layoutlm(
     run = None
     if use_wandb:
         if not wandb_available():
-            raise ModuleNotFoundError("WandB must be installed separately")
+            raise DependencyError("WandB must be installed separately")
         run = wandb.init(project=wandb_project, config=conf_dict)  # type: ignore
         run._label(repo=wandb_repo)  # type: ignore # pylint: disable=W0212
     else:
diff --git a/deepdoctection/utils/__init__.py b/deepdoctection/utils/__init__.py
index ccef61af..3e6a6543 100644
--- a/deepdoctection/utils/__init__.py
+++ b/deepdoctection/utils/__init__.py
@@ -6,7 +6,10 @@
 """
 from typing import Optional, Tuple, Union, no_type_check
 
+from .concurrency import *
 from .context import *
+from .env_info import *
+from .error import *
 from .file_utils import *
 from .fs import *
 from .identifier import *
diff --git a/deepdoctection/utils/context.py b/deepdoctection/utils/context.py
index 1bf2d33a..3f31411b 100644
--- a/deepdoctection/utils/context.py
+++ b/deepdoctection/utils/context.py
@@ -61,7 +61,7 @@ def timeout_manager(proc, seconds: Optional[int] = None) -> Iterator[str]:  # ty
             proc.terminate()
             proc.kill()
             proc.returncode = -1
-            raise RuntimeError("Tesseract process timeout")  # pylint: disable=W0707
+            raise RuntimeError(f"timeout for process id: {proc.pid}")  # pylint: disable=W0707
     finally:
         if proc.stdin is not None:
             proc.stdin.close()
diff --git a/deepdoctection/utils/env_info.py b/deepdoctection/utils/env_info.py
index 67dad4ba..f91d4045 100644
--- a/deepdoctection/utils/env_info.py
+++ b/deepdoctection/utils/env_info.py
@@ -520,7 +520,7 @@ def get_device(ignore_cpu: bool = True) -> str:
         return "mps"
     if not ignore_cpu:
         return "cpu"
-    raise ValueError("Could not find either GPU nor MPS")
+    raise RuntimeWarning("Could not find either GPU nor MPS")
 
 
 def auto_select_viz_library() -> None:
diff --git a/deepdoctection/utils/error.py b/deepdoctection/utils/error.py
new file mode 100644
index 00000000..71cd7ef6
--- /dev/null
+++ b/deepdoctection/utils/error.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# File: error.py
+
+# Copyright 2024 Dr. Janis Meyer. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Module for custom exceptions
+"""
+
+
+class BoundingBoxError(BaseException):
+    """Special exception only for `datapoint.box.BoundingBox`"""
+
+
+class AnnotationError(BaseException):
+    """Special exception only for `datapoint.annotation.Annotation`"""
+
+
+class ImageError(BaseException):
+    """Special exception only for `datapoint.image.Image`"""
+
+
+class UUIDError(BaseException):
+    """Special exception only for `utils.identifier`"""
+
+
+class DependencyError(BaseException):
+    """Special exception only for missing dependencies. We do not use the internals ImportError or
+    ModuleNotFoundError."""
+
+
+class DataFlowTerminatedError(BaseException):
+    """
+    An exception indicating that the DataFlow is unable to produce any more
+    data, i.e. something wrong happened so that calling `__iter__`
+    cannot give a valid iterator anymore.
+    In most DataFlow this will never be raised.
+    """
+
+
+class DataFlowResetStateNotCalledError(BaseException):
+    """
+    An exception indicating that `reset_state()` has not been called before starting
+    iteration.
+    """
+
+    def __init__(self) -> None:
+        super().__init__("Iterating a dataflow requires .reset_state() to be called first")
+
+
+class MalformedData(BaseException):
+    """
+    Exception class for malformed data. Use this class if something does not look right with the data
+    """
+
+
+class FileExtensionError(BaseException):
+    """
+    Exception class for wrong file extensions.
+    """
+
+
+class TesseractError(RuntimeError):
+    """
+    Tesseract Error
+    """
+
+    def __init__(self, status: int, message: str) -> None:
+        super().__init__()
+        self.status = status
+        self.message = message
+        self.args = (status, message)
diff --git a/deepdoctection/utils/file_utils.py b/deepdoctection/utils/file_utils.py
index ed42a362..a9c08474 100644
--- a/deepdoctection/utils/file_utils.py
+++ b/deepdoctection/utils/file_utils.py
@@ -22,6 +22,7 @@
 from packaging import version
 
 from .detection_types import Requirement
+from .error import DependencyError
 from .logger import LoggingRecord, logger
 from .metacfg import AttrDict
 
@@ -263,7 +264,7 @@ def set_tesseract_path(tesseract_path: str) -> None:
     :param tesseract_path: Tesseract installation path.
     """
     if tesseract_path is None:
-        raise ValueError("tesseract_path is empty.")
+        raise TypeError("tesseract_path cannot be None")
 
     global _TESS_AVAILABLE  # pylint: disable=W0603
     global _TESS_PATH  # pylint: disable=W0603
@@ -288,12 +289,6 @@ def tesseract_available() -> bool:
 # copy paste from https://github.com/madmaze/pytesseract/blob/master/pytesseract/pytesseract.py
 
 
-class TesseractNotFound(BaseException):
-    """
-    Exception class for Tesseract being not found
-    """
-
-
 def get_tesseract_version() -> Union[int, version.Version]:
     """
     Returns Version object of the Tesseract version. We need at least Tesseract 3.05
@@ -306,7 +301,7 @@ def get_tesseract_version() -> Union[int, version.Version]:
             stdin=subprocess.DEVNULL,
         )
     except OSError:
-        raise TesseractNotFound(_TESS_ERR_MSG) from OSError
+        raise DependencyError(_TESS_ERR_MSG) from OSError
 
     raw_version = output.decode("utf-8")
     str_version, *_ = raw_version.lstrip(string.printable[10:]).partition(" ")
@@ -348,12 +343,6 @@ def pdf_to_cairo_available() -> bool:
     return bool(_PDF_TO_CAIRO_AVAILABLE)
 
 
-class PopplerNotFound(BaseException):
-    """
-    Exception class for Poppler being not found
-    """
-
-
 def get_poppler_version() -> Union[int, version.Version]:
     """
     Returns Version object of the Poppler version. We need at least Tesseract 3.05
@@ -371,7 +360,7 @@ def get_poppler_version() -> Union[int, version.Version]:
             [command, "-v"], stderr=subprocess.STDOUT, env=environ, stdin=subprocess.DEVNULL
         )
     except OSError:
-        raise PopplerNotFound() from OSError
+        raise DependencyError(_POPPLER_ERR_MSG) from OSError
 
     raw_version = output.decode("utf-8")
     list_version = raw_version.split("\n", maxsplit=1)[0].split(" ")[-1].split(".")
diff --git a/deepdoctection/utils/fs.py b/deepdoctection/utils/fs.py
index 46e6e655..7d139936 100644
--- a/deepdoctection/utils/fs.py
+++ b/deepdoctection/utils/fs.py
@@ -34,7 +34,7 @@
 from .pdf_utils import get_pdf_file_reader, get_pdf_file_writer
 from .settings import CONFIGS, DATASET_DIR, MODEL_DIR, PATH
 from .tqdm import get_tqdm
-from .utils import FileExtensionError, is_file_extension
+from .utils import is_file_extension
 from .viz import viz_handler
 
 __all__ = [
@@ -44,9 +44,7 @@
     "maybe_path_or_pdf",
     "download",
     "mkdir_p",
-    "is_file_extension",
     "load_json",
-    "FileExtensionError",
     "sub_path",
     "get_package_path",
     "get_configs_dir_path",
@@ -125,8 +123,8 @@ def inner(byte, b_size, t_size=None):  # type: ignore
     assert size > 0, f"Downloaded an empty file from {url}!"
 
     if expect_size is not None and size != expect_size:
-        logger.error(LoggingRecord(f"File downloaded from {url} does not match the expected size!"))
-        logger.error(
+        logger.warning(LoggingRecord(f"File downloaded from {url} does not match the expected size!"))
+        logger.warning(
             LoggingRecord("You may have downloaded a broken file, or the upstream may have modified the file.")
         )
 
@@ -210,13 +208,15 @@ def get_load_image_func(
     :return: The function loading the file (and converting to its desired format)
     """
 
-    assert is_file_extension(path, [".png", ".jpeg", ".jpg", ".pdf", ".tif"]), f"image type not allowed: {path}"
+    assert is_file_extension(path, [".png", ".jpeg", ".jpg", ".pdf", ".tif"]), f"image type not allowed: " f"{path}"
 
     if is_file_extension(path, [".png", ".jpeg", ".jpg", ".tif"]):
         return load_image_from_file
     if is_file_extension(path, [".pdf"]):
         return load_bytes_from_pdf_file
-    return NotImplemented
+    raise NotImplementedError(
+        "File extension not supported by any loader. Please specify a file type and raise an issue"
+    )
 
 
 def maybe_path_or_pdf(path: Pathlike) -> int:
diff --git a/deepdoctection/utils/pdf_utils.py b/deepdoctection/utils/pdf_utils.py
index abcf3b99..9a976678 100644
--- a/deepdoctection/utils/pdf_utils.py
+++ b/deepdoctection/utils/pdf_utils.py
@@ -32,9 +32,10 @@
 
 from .context import save_tmp_file, timeout_manager
 from .detection_types import ImageType, Pathlike
-from .file_utils import PopplerNotFound, pdf_to_cairo_available, pdf_to_ppm_available, qpdf_available
+from .error import DependencyError, FileExtensionError
+from .file_utils import pdf_to_cairo_available, pdf_to_ppm_available, qpdf_available
 from .logger import LoggingRecord, logger
-from .utils import FileExtensionError, is_file_extension
+from .utils import is_file_extension
 from .viz import viz_handler
 
 __all__ = ["decrypt_pdf_document", "get_pdf_file_reader", "get_pdf_file_writer", "PDFStreamer", "pdf_to_np_array"]
@@ -165,7 +166,7 @@ def _input_to_cli_str(
     elif pdf_to_cairo_available():
         command = "pdftocairo"
     else:
-        raise PopplerNotFound("Poppler not found. Please install or add to your PATH.")
+        raise DependencyError("Poppler not found. Please install or add to your PATH.")
 
     if platform.system() == "Windows":
         command = command + ".exe"
@@ -201,7 +202,7 @@ def _run_poppler(poppler_args: List[str]) -> None:
     except OSError as error:
         if error.errno != ENOENT:
             raise error from error
-        raise PopplerNotFound("Poppler not found. Please install or add to your PATH.") from error
+        raise DependencyError("Poppler not found. Please install or add to your PATH.") from error
 
     with timeout_manager(proc, 0):
         if proc.returncode:
diff --git a/deepdoctection/utils/settings.py b/deepdoctection/utils/settings.py
index c4819591..43a71516 100644
--- a/deepdoctection/utils/settings.py
+++ b/deepdoctection/utils/settings.py
@@ -324,7 +324,9 @@ def token_class_tag_to_token_class_with_tag(token: ObjectTypes, tag: ObjectTypes
     """
     if isinstance(token, TokenClasses) and isinstance(tag, BioTag):
         return _TOKEN_AND_TAG_TO_TOKEN_CLASS_WITH_TAG[(token, tag)]
-    raise TypeError("Token must be of type TokenClasses and tag must be of type BioTag")
+    raise TypeError(
+        f"Token must be of type TokenClasses, is of {type(token)} and tag " f"{type(tag)} must be of type BioTag"
+    )
 
 
 def token_class_with_tag_to_token_class_and_tag(
diff --git a/deepdoctection/utils/transform.py b/deepdoctection/utils/transform.py
index 151bae44..2efebb7b 100644
--- a/deepdoctection/utils/transform.py
+++ b/deepdoctection/utils/transform.py
@@ -47,7 +47,7 @@ class BaseTransform(ABC):
     @abstractmethod
     def apply_image(self, img: ImageType) -> ImageType:
         """The transformation that should be applied to the image"""
-        raise NotImplementedError
+        raise NotImplementedError()
 
 
 class ResizeTransform(BaseTransform):
diff --git a/deepdoctection/utils/utils.py b/deepdoctection/utils/utils.py
index 9aff81ad..218c70f8 100644
--- a/deepdoctection/utils/utils.py
+++ b/deepdoctection/utils/utils.py
@@ -144,12 +144,6 @@ def get_rng(obj: Any = None) -> np.random.RandomState:
     return np.random.RandomState(seed)
 
 
-class FileExtensionError(BaseException):
-    """
-    An exception indicating that a file does not seem to have an expected type
-    """
-
-
 def is_file_extension(file_name: Pathlike, extension: Union[str, Sequence[str]]) -> bool:
     """
     Check if a given file name has a given extension
diff --git a/deepdoctection/utils/viz.py b/deepdoctection/utils/viz.py
index 48806367..6b34835c 100644
--- a/deepdoctection/utils/viz.py
+++ b/deepdoctection/utils/viz.py
@@ -38,6 +38,7 @@
 
 from .detection_types import ImageType
 from .env_info import auto_select_viz_library
+from .error import DependencyError
 from .file_utils import get_opencv_requirement, get_pillow_requirement, opencv_available, pillow_available
 
 if opencv_available():
@@ -352,12 +353,12 @@ def _select_package() -> str:
         if maybe_cv2:
             requirements = get_opencv_requirement()
             if not requirements[1]:
-                raise ImportError(requirements[2])
+                raise DependencyError(requirements[2])
             return maybe_cv2
 
         requirements = get_pillow_requirement()
         if not requirements[1]:
-            raise ImportError(requirements[2])
+            raise DependencyError(requirements[2])
         return "pillow"
 
     def _set_vars(self, package: str) -> None:


Test patch:
diff --git a/deepdoctection/datasets/instances/layouttest.py b/deepdoctection/datasets/instances/layouttest.py
index 2a84bea5..1dd676ae 100644
--- a/deepdoctection/datasets/instances/layouttest.py
+++ b/deepdoctection/datasets/instances/layouttest.py
@@ -49,12 +49,7 @@
     " – Permissive – Version 1.0 License. Dr. Janis Meyer does not own the copyright of the images. \n"
     " Use of the images must abide by the PMC Open Access Subset Terms of Use."
 )
-_URL = [
-    "https://www.googleapis.com/drive/v3/files/1ZD4Ef4gd2FIfp7vR8jbnrZeXD3gSWNqE?alt"
-    "=media&key=AIzaSyDuoPG6naK-kRJikScR7cP_1sQBF1r3fWU",
-    "https://www.googleapis.com/drive/v3/files/18HD62LFLa1iAmqffo4SyjuEQ32MzyNQ0?alt"
-    "=media&key=AIzaSyDuoPG6naK-kRJikScR7cP_1sQBF1r3fWU",
-]
+
 _SPLITS: Mapping[str, str] = {"test": "test", "predict": "predict"}
 _TYPE = DatasetType.object_detection
 _LOCATION = "testlayout"
@@ -77,7 +72,7 @@ class LayoutTest(_BuiltInDataset):
 
     @classmethod
     def _info(cls) -> DatasetInfo:
-        return DatasetInfo(name=_NAME, description=_DESCRIPTION, license=_LICENSE, url=_URL, splits=_SPLITS, type=_TYPE)
+        return DatasetInfo(name=_NAME, description=_DESCRIPTION, license=_LICENSE, splits=_SPLITS, type=_TYPE)
 
     def _categories(self) -> DatasetCategories:
         return DatasetCategories(init_categories=_INIT_CATEGORIES)
diff --git a/tests/datapoint/test_image.py b/tests/datapoint/test_image.py
index 2b1e62dd..bd565d99 100644
--- a/tests/datapoint/test_image.py
+++ b/tests/datapoint/test_image.py
@@ -28,6 +28,7 @@
 from deepdoctection.dataflow import DataFlow, MapData, SerializerJsonlines
 from deepdoctection.datapoint import BoundingBox, CategoryAnnotation, Image, ImageAnnotation
 from deepdoctection.utils import get_uuid
+from deepdoctection.utils.error import ImageError
 from deepdoctection.utils.settings import get_type
 
 from ..test_utils import anns_to_ids, collect_datapoint_from_dataflow, get_test_path
@@ -82,7 +83,7 @@ def test_image_id_cannot_be_reassigned(image: WhiteImage) -> None:
         test_image = Image(file_name=image.file_name, location=image.loc, external_id=image.external_id)
 
         # Act and assert
-        with raises(ValueError):
+        with raises(ImageError):
             test_image.image_id = "ec2aac06-c261-3669-b8bd-4486a54ce740"
 
     @staticmethod
@@ -200,7 +201,7 @@ def test_dump_same_annotation_not_possible(image: WhiteImage) -> None:
         # Act and Assert
         test_image.dump(cat)
 
-        with raises(ValueError):
+        with raises(ImageError):
             test_image.dump(cat)
 
     @staticmethod
diff --git a/tests/datasets/test_info.py b/tests/datasets/test_info.py
index c857f8d0..4baf69e1 100644
--- a/tests/datasets/test_info.py
+++ b/tests/datasets/test_info.py
@@ -268,6 +268,6 @@ def test_merge_categories_cannot_update_or_filter() -> None:
         merge = get_merged_categories(cat_1, cat_2)
 
         # Act & Assert
-        with pytest.raises(PermissionError):
+        with pytest.raises(RuntimeWarning):
             merge.filter_categories(categories="BAZ")
             merge.set_cat_to_sub_cat({"FOO": "FOO_1"})
diff --git a/tests/extern/test_tessocr.py b/tests/extern/test_tessocr.py
index 8f509146..460db1ed 100644
--- a/tests/extern/test_tessocr.py
+++ b/tests/extern/test_tessocr.py
@@ -26,7 +26,7 @@
 from deepdoctection.extern.base import DetectionResult
 from deepdoctection.extern.tessocr import TesseractOcrDetector, tesseract_line_to_detectresult
 from deepdoctection.utils.detection_types import ImageType
-from deepdoctection.utils.file_utils import TesseractNotFound
+from deepdoctection.utils.error import DependencyError
 from tests.data import Annotations
 
 from .data import WORD_RESULTS
@@ -66,7 +66,7 @@ def test_tesseract_ocr_raises_tesseract_not_found_error_when_dependencies_not_sa
         """
 
         # Act and Assert
-        with pytest.raises(TesseractNotFound):
+        with pytest.raises(DependencyError):
             TesseractOcrDetector(path_yaml=path_to_tesseract_yaml)
 
     @staticmethod