ISSUES CLOSED: #2
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 exceptionsOntologyLoaderFailedException: Raised when ontology loading failsClassNodeNotFoundException: Raised when a required class node cannot be foundClassHierarchyBuildException: Raised when a fatal error occurs during hierarchy buildingReadOnlyPropertyException: Raised when attempting to modify a read-only propertyGraphLoaderHandlerInsertionFailed: Raised when handler insertion fails
Conversion Exceptions
PropertyConversionException: Raised during property conversionClassConversionException: Raised during class conversionDataTypeConversionException: Raised during datatype conversionInconsistentClassHierarchyException: 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
- Always check
is_successful_for_main_ontology: Before accessing the hierarchy, verify loading succeeded (see Loading Result API for differences between success checking methods) - Use LoadingResult for errors: Access errors and warnings through
result.errorsandresult.warningsafter loading - Handle exceptions: Wrap loading operations in try-except blocks for fatal errors
- Observers are optional: Use observers only when you need custom, real-time error handling or integration with external systems
- Check warnings: Review warnings to identify potential issues
- Validate on load: Enable validation to catch OWL-specific issues early
Next Steps
- Learn about OWL Extensions and Validation
- Explore Observers API for detailed error monitoring