Files
CleverRDFlib/docs/error_handling.md
CoreRasurae f14c0bad8c
CI / lint (pull_request) Successful in 1m35s
CI / typecheck (pull_request) Successful in 1m38s
CI / behave (3.11) (pull_request) Successful in 1m48s
CI / behave (3.12) (pull_request) Successful in 1m47s
CI / behave (3.13) (pull_request) Successful in 1m43s
CI / build (pull_request) Successful in 1m33s
CI / lint (push) Successful in 1m31s
CI / typecheck (push) Successful in 1m29s
CI / behave (3.11) (push) Successful in 1m37s
CI / behave (3.12) (push) Successful in 1m44s
CI / behave (3.13) (push) Successful in 1m36s
CI / build (push) Successful in 1m31s
docs: Initial documentation of CleverRDFLib
ISSUES CLOSED: #2
2025-12-22 10:50:03 +00:00

10 KiB

Error Detection and Handling

CleverRDFLib provides comprehensive error detection and handling mechanisms to help you identify and respond to issues during ontology loading and processing.

Error Types

The framework defines several exception types, all inheriting from CleverRDFLibException:

Core Exceptions

  • CleverRDFLibException: Base exception for all framework exceptions
  • OntologyLoaderFailedException: Raised when ontology loading fails
  • ClassNodeNotFoundException: Raised when a required class node cannot be found
  • ClassHierarchyBuildException: Raised when a fatal error occurs during hierarchy building
  • ReadOnlyPropertyException: Raised when attempting to modify a read-only property
  • GraphLoaderHandlerInsertionFailed: Raised when handler insertion fails

Conversion Exceptions

  • PropertyConversionException: Raised during property conversion
  • ClassConversionException: Raised during class conversion
  • DataTypeConversionException: Raised during datatype conversion
  • InconsistentClassHierarchyException: Raised when inconsistencies are detected

Loading Errors

Checking for Errors

After loading an ontology, the LoadingResult object provides access to all errors and warnings. This is the primary way to retrieve error information:

from cleverrdf_lib import OntologyLoader

loader = OntologyLoader()
result = loader.load_ontology("ontology.ttl")

# Check if loading was successful
if not result.is_successful_for_main_ontology:
    print("Loading failed!")
    for error in result.errors:
        print(f"URI: {error['uri']}")
        print(f"Message: {error['message']}")
        if 'exception' in error:
            print(f"Exception: {error['exception']}")

!!! note "LoadingResult for Error Retrieval" The LoadingResult object returned by load_ontology() contains all errors and warnings from the loading process. This is the standard way to access error information after loading completes. Observers are optional and are primarily used for custom error handling, real-time monitoring, or integration with external systems.

Error Structure

Each error in result.errors is a dictionary with the following structure:

{
    "uri": str,           # The URI that failed to load
    "message": str,       # Human-readable error message
    "exception": Exception # The underlying exception (if available)
}

Handling Loading Failures

Normal loading failures (e.g., non-existent files) do not raise exceptions. Instead, errors are reported to observers and collected in the LoadingResult. Check the result for errors:

from cleverrdf_lib import OntologyLoader

loader = OntologyLoader()
result = loader.load_ontology("nonexistent.ttl")

# Normal loading failures are reported in the result, not as exceptions
if not result.is_successful_for_main_ontology:
    print("Loading failed!")
    for error in result.errors:
        print(f"URI: {error['uri']}")
        print(f"Message: {error['message']}")

Exceptions are only raised for software bugs or unexpected errors (e.g., invalid configuration, programming errors). It's good practice to catch these:

from cleverrdf_lib import OntologyLoader
from cleverrdf_lib.core.exceptions import OntologyLoaderFailedException

try:
    loader = OntologyLoader()
    # This may raise an exception for software bugs or unexpected errors
    result = loader.load_ontology("ontology.ttl")
except OntologyLoaderFailedException as e:
    # This catches unexpected errors, not normal loading failures
    print(f"Unexpected error loading ontology: {e}")
    if e.get_cause():
        print(f"Caused by: {e.get_cause()}")
    raise  # Re-raise if you can't handle it
else:
    # Check for normal loading failures in the result
    if not result.is_successful_for_main_ontology:
        print("Loading failed - check result.errors for details")

Warnings

Warnings are non-fatal issues that don't prevent loading but may indicate problems:

result = loader.load_ontology("ontology.ttl")

# Check for warnings
if result.warnings:
    print("Warnings encountered:")
    for warning in result.warnings:
        print(f"  - {warning}")

Warnings can include:

  • OWL validation warnings
  • Missing domain/range definitions
  • Inconsistent property definitions
  • Deprecated resources

Build Errors

Errors can occur during class hierarchy building:

from cleverrdf_lib.core.class_hierarchy import ClassHierarchy
from cleverrdf_lib.core.exceptions import ClassHierarchyBuildException, ClassNodeNotFoundException

try:
    hierarchy = ClassHierarchy(graph)
    hierarchy.build()
except ClassHierarchyBuildException as e:
    print(f"Build failed: {e}")
except ClassNodeNotFoundException as e:
    print(f"Missing class node: {e}")

Observer-Based Error Detection

Observers are optional and provide a way to handle errors in real-time during loading, or to integrate with custom error handling systems. For most use cases, accessing errors through LoadingResult is sufficient.

When to Use Observers

Use observers when you need:

  • Real-time error handling: React to errors as they occur during loading
  • Custom error processing: Log to external systems, send notifications, etc.
  • Progressive error collection: Build up error information incrementally
  • Integration with monitoring systems: Connect to logging frameworks or alerting systems

Example: Custom Error Observer

from cleverrdf_lib.observers.base_observer import BaseLoadingObserver
from cleverrdf_lib.core.interfaces.interfaces import LoadingObserver

class ErrorCollector(BaseLoadingObserver):
    """Observer that performs side effects when loading errors occur."""
    
    def on_loading_failed(self, uri: str, error: Exception) -> None:
        """Called when loading fails - perform side effects like logging or notifications."""
        # Perform side effects (logging, notifications, etc.)
        print(f"Error loading {uri}: {error}")
        # Could also log to external system, send alerts, etc.

# Register the observer (optional)
from cleverrdf_lib import OntologyLoader

error_collector = ErrorCollector()
loader = OntologyLoader(loading_observers=[error_collector])

result = loader.load_ontology("ontology.ttl")

# Check errors from LoadingResult (standard approach)
if not result.is_successful_for_main_ontology:
    for error in result.errors:
        print(f"Failed to load {error['uri']}: {error['message']}")

!!! note "Observers are Optional" Observers are not required for error handling. The LoadingResult object already contains all errors and warnings. Use observers only when you need custom, real-time error handling or integration with external systems.

Build Inconsistencies

Inconsistencies are detected during hierarchy building. While observers can be used for real-time inconsistency detection, the primary way to access inconsistency information is through the build observer events or by checking the build process.

Standard Approach: Using LoadingResult

The LoadingResult contains warnings that may include inconsistency information:

from cleverrdf_lib import OntologyLoader

loader = OntologyLoader()
result = loader.load_ontology("ontology.ttl")
hierarchy = result.class_hierarchy  # Build the hierarchy

# Check warnings for inconsistency information
if result.warnings:
    for warning in result.warnings:
        print(f"Warning: {warning}")
        # Warnings may include inconsistency messages

Optional: Using Build Observers

Build observers are optional and provide real-time inconsistency detection during hierarchy building:

from cleverrdf_lib.observers.base_hierarchy_oberver import BaseClassHierarchyBuildObserver

class InconsistencyCollector(BaseClassHierarchyBuildObserver):
    """Observer that collects build inconsistencies in real-time."""
    
    def __init__(self):
        self.inconsistencies = []
    
    def on_build_inconsistency(self, iri: str, elem_iri: str, msg: str) -> None:
        """Called when an inconsistency is detected - allows real-time handling."""
        self.inconsistencies.append({
            "ontology_iri": iri,
            "element_iri": elem_iri,
            "message": msg
        })
        # Could also log to external system, send alerts, etc.

# Register the observer (optional)
from cleverrdf_lib import OntologyLoader

inconsistency_collector = InconsistencyCollector()
loader = OntologyLoader(hierarchy_build_observers=[inconsistency_collector])

result = loader.load_ontology("ontology.ttl")
hierarchy = result.class_hierarchy  # Build triggers inconsistency detection

# Check collected inconsistencies from observer
if inconsistency_collector.inconsistencies:
    for inc in inconsistency_collector.inconsistencies:
        print(f"Inconsistency in {inc['element_iri']}: {inc['message']}")

!!! note "Observers for Custom Handling" Build observers are optional and are primarily used for custom inconsistency handling, real-time monitoring, or integration with external systems. For standard use cases, checking LoadingResult.warnings after building the hierarchy is sufficient.

Validation Errors

OWL validation errors are reported as warnings in the LoadingResult:

result = loader.load_ontology("ontology.ttl")

# Access validation result
validation_result = result.owl_validation_result

if not validation_result.is_valid:
    print("Validation errors:")
    for error in validation_result.errors:
        print(f"  - {error}")
    
    print("Validation warnings:")
    for warning in validation_result.warnings:
        print(f"  - {warning}")

Best Practices

  1. Always check is_successful_for_main_ontology: Before accessing the hierarchy, verify loading succeeded (see Loading Result API for differences between success checking methods)
  2. Use LoadingResult for errors: Access errors and warnings through result.errors and result.warnings after loading
  3. Handle exceptions: Wrap loading operations in try-except blocks for fatal errors
  4. Observers are optional: Use observers only when you need custom, real-time error handling or integration with external systems
  5. Check warnings: Review warnings to identify potential issues
  6. Validate on load: Enable validation to catch OWL-specific issues early

Next Steps