diff --git a/semantica/embeddings/methods.py b/semantica/embeddings/methods.py index 31b27d18..4128ffd8 100644 --- a/semantica/embeddings/methods.py +++ b/semantica/embeddings/methods.py @@ -120,8 +120,9 @@ def generate_embeddings( # Check for custom method in registry custom_method = method_registry.get("generation", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, data, data_type=data_type, **kwargs + logger, method, custom_method, data, data_type=data_type, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -167,7 +168,10 @@ def embed_text( # Check for custom method in registry custom_method = method_registry.get("text", method) if custom_method: - result = call_custom_method(logger, method, custom_method, text, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, text, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -224,7 +228,10 @@ def calculate_similarity( # Check for custom method in registry custom_method = method_registry.get("similarity", method) if custom_method: - result = call_custom_method(logger, method, custom_method, embedding1, embedding2, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, embedding1, embedding2, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -268,7 +275,10 @@ def pool_embeddings( # Check for custom method in registry custom_method = method_registry.get("pooling", method) if custom_method: - result = call_custom_method(logger, method, custom_method, embeddings, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, embeddings, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/semantica/export/methods.py b/semantica/export/methods.py index 4cb54060..d0940128 100644 --- a/semantica/export/methods.py +++ b/semantica/export/methods.py @@ -222,8 +222,9 @@ def export_rdf( # Check for custom method in registry custom_method = method_registry.get("rdf", method) if custom_method and custom_method is not export_rdf: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, data, file_path, format=format, **kwargs + logger, method, custom_method, data, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -270,8 +271,9 @@ def export_json( # Check for custom method in registry custom_method = method_registry.get("json", method) if custom_method and custom_method is not export_json: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, data, file_path, format=format, **kwargs + logger, method, custom_method, data, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -315,7 +317,10 @@ def export_csv( # Check for custom method in registry custom_method = method_registry.get("csv", method) if custom_method and custom_method is not export_csv: - result = call_custom_method(logger, method, custom_method, data, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, data, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -357,7 +362,10 @@ def export_arrow( # Check for custom method in registry custom_method = method_registry.get("arrow", method) if custom_method and custom_method is not export_arrow: - result = call_custom_method(logger, method, custom_method, data, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, data, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -414,8 +422,9 @@ def export_parquet( # Check for custom method in registry custom_method = method_registry.get("parquet", method) if custom_method and custom_method is not export_parquet: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, data, file_path, compression=compression, **kwargs + logger, method, custom_method, data, file_path, compression=compression, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -464,8 +473,9 @@ def export_graph( # Check for custom method in registry custom_method = method_registry.get("graph", method) if custom_method and custom_method is not export_graph: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, graph_data, file_path, format=format, **kwargs + logger, method, custom_method, graph_data, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -529,7 +539,10 @@ def export_yaml( # Check for custom method in registry custom_method = method_registry.get("yaml", method) if custom_method and custom_method is not export_yaml: - result = call_custom_method(logger, method, custom_method, data, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, data, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -583,8 +596,9 @@ def export_owl( # Check for custom method in registry custom_method = method_registry.get("owl", method) if custom_method and custom_method is not export_owl: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, ontology, file_path, format=format, **kwargs + logger, method, custom_method, ontology, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -634,8 +648,9 @@ def export_vector( # Check for custom method in registry custom_method = method_registry.get("vector", method) if custom_method and custom_method is not export_vector: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, vectors, file_path, format=format, **kwargs + logger, method, custom_method, vectors, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -681,8 +696,9 @@ def export_lpg( # Check for custom method in registry custom_method = method_registry.get("lpg", method) if custom_method and custom_method is not export_lpg: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, knowledge_graph, file_path, **kwargs + logger, method, custom_method, knowledge_graph, file_path, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -723,8 +739,9 @@ def export_neo4j_csv( """ custom_method = method_registry.get("neo4j_csv", method) if custom_method and custom_method is not export_neo4j_csv: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, knowledge_graph, output_dir, **kwargs + logger, method, custom_method, knowledge_graph, output_dir, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -792,8 +809,9 @@ def export_arango( # Check for custom method in registry custom_method = method_registry.get("arango", method) if custom_method and custom_method is not export_arango: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, knowledge_graph, file_path, **kwargs + logger, method, custom_method, knowledge_graph, file_path, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -842,8 +860,9 @@ def generate_report( # Check for custom method in registry custom_method = method_registry.get("report", method) if custom_method and custom_method is not generate_report: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, data, file_path, format=format, **kwargs + logger, method, custom_method, data, file_path, format=format, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/semantica/ingest/methods.py b/semantica/ingest/methods.py index 84624a45..5ec01f17 100644 --- a/semantica/ingest/methods.py +++ b/semantica/ingest/methods.py @@ -249,7 +249,10 @@ def ingest_file( # Check for custom method in registry custom_method = method_registry.get("file", method) if custom_method and custom_method != ingest_file: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -312,7 +315,10 @@ def ingest_parquet( """ custom_method = method_registry.get("parquet", method) if custom_method and custom_method != ingest_parquet: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -388,7 +394,10 @@ def ingest_arrow( """ custom_method = method_registry.get("arrow", method) if custom_method and custom_method != ingest_arrow: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -469,7 +478,10 @@ def ingest_xml( """ custom_method = method_registry.get("xml", method) if custom_method and custom_method != ingest_xml: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -530,7 +542,10 @@ def ingest_web( # Check for custom method in registry custom_method = method_registry.get("web", method) if custom_method and custom_method != ingest_web: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -617,7 +632,10 @@ def ingest_public_api( """ custom_method = method_registry.get("public_api", method) if custom_method and custom_method != ingest_public_api: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -701,7 +719,10 @@ def ingest_feed( # Check for custom method in registry custom_method = method_registry.get("feed", method) if custom_method and custom_method != ingest_feed: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -767,7 +788,10 @@ def ingest_stream( # Check for custom method in registry custom_method = method_registry.get("stream", method) if custom_method and custom_method != ingest_stream: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -841,7 +865,10 @@ def ingest_repository( # Check for custom method in registry custom_method = method_registry.get("repo", method) if custom_method and custom_method != ingest_repository: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -910,7 +937,10 @@ def ingest_email( # Check for custom method in registry custom_method = method_registry.get("email", method) if custom_method and custom_method != ingest_email: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -986,7 +1016,10 @@ def ingest_ontology( # Check for custom method in registry custom_method = method_registry.get("ontology", method) if custom_method and custom_method != ingest_ontology: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -1049,7 +1082,10 @@ def ingest_database( if method: custom_method = method_registry.get("db", method) if custom_method and custom_method != ingest_database: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -1153,7 +1189,10 @@ def ingest_mcp( # Check for custom method in registry custom_method = method_registry.get("mcp", method) if custom_method and custom_method != ingest_mcp: - result = call_custom_method(logger, method, custom_method, source, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, source, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/semantica/kg/methods.py b/semantica/kg/methods.py index c96c96e1..fb9475f0 100644 --- a/semantica/kg/methods.py +++ b/semantica/kg/methods.py @@ -190,7 +190,10 @@ def build_kg( # Check for custom method in registry custom_method = method_registry.get("build", method) if custom_method: - result = call_custom_method(logger, method, custom_method, sources, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, sources, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -235,7 +238,10 @@ def analyze_graph( # Check for custom method in registry custom_method = method_registry.get("analyze", method) if custom_method: - result = call_custom_method(logger, method, custom_method, graph, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, graph, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -436,7 +442,10 @@ def analyze_connectivity( # Check for custom method in registry custom_method = method_registry.get("connectivity", method) if custom_method: - result = call_custom_method(logger, method, custom_method, graph, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, graph, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/semantica/normalize/methods.py b/semantica/normalize/methods.py index 74f3c5fa..fd058362 100644 --- a/semantica/normalize/methods.py +++ b/semantica/normalize/methods.py @@ -169,7 +169,10 @@ def normalize_text(text: str, method: str = "default", **kwargs) -> str: """ custom_method = method_registry.get("text", method) if custom_method: - result = call_custom_method(logger, method, custom_method, text, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, text, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -210,7 +213,10 @@ def clean_text(text: str, method: str = "default", **kwargs) -> str: """ custom_method = method_registry.get("clean", method) if custom_method: - result = call_custom_method(logger, method, custom_method, text, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, text, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -257,8 +263,9 @@ def normalize_entity( """ custom_method = method_registry.get("entity", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, entity_name, entity_type, **kwargs + logger, method, custom_method, entity_name, entity_type, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -303,8 +310,9 @@ def resolve_aliases( """ custom_method = method_registry.get("entity", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, entity_name, entity_type, **kwargs + logger, method, custom_method, entity_name, entity_type, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -349,7 +357,10 @@ def disambiguate_entity( """ custom_method = method_registry.get("entity", method) if custom_method: - result = call_custom_method(logger, method, custom_method, entity_name, **context) + fallback = context.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, entity_name, fallback_on_custom_error=fallback, **context + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -401,8 +412,9 @@ def normalize_date( """ custom_method = method_registry.get("date", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, date_input, format, timezone, **kwargs + logger, method, custom_method, date_input, format, timezone, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -441,7 +453,10 @@ def normalize_time(time_input: Any, method: str = "default", **kwargs) -> str: """ custom_method = method_registry.get("date", method) if custom_method: - result = call_custom_method(logger, method, custom_method, time_input, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, time_input, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -484,7 +499,10 @@ def normalize_number( """ custom_method = method_registry.get("number", method) if custom_method: - result = call_custom_method(logger, method, custom_method, number_input, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, number_input, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -525,7 +543,10 @@ def normalize_quantity( """ custom_method = method_registry.get("number", method) if custom_method: - result = call_custom_method(logger, method, custom_method, quantity_input, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, quantity_input, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -578,8 +599,9 @@ def clean_data( """ custom_method = method_registry.get("clean", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, dataset, remove_duplicates, validate, handle_missing, **kwargs + logger, method, custom_method, dataset, remove_duplicates, validate, handle_missing, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -630,8 +652,9 @@ def detect_duplicates( """ custom_method = method_registry.get("clean", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, dataset, threshold, key_fields, **kwargs + logger, method, custom_method, dataset, threshold, key_fields, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -676,7 +699,10 @@ def detect_language( """ custom_method = method_registry.get("language", method) if custom_method: - result = call_custom_method(logger, method, custom_method, text, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, text, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -734,7 +760,10 @@ def handle_encoding( """ custom_method = method_registry.get("encoding", method) if custom_method: - result = call_custom_method(logger, method, custom_method, data, operation, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, data, operation, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/semantica/parse/methods.py b/semantica/parse/methods.py index ba175041..4e9e9365 100644 --- a/semantica/parse/methods.py +++ b/semantica/parse/methods.py @@ -179,7 +179,10 @@ def parse_document( """ custom_method = method_registry.get("document", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, file_type, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, file_type, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -287,8 +290,9 @@ def parse_web_content( """ custom_method = method_registry.get("web", method) if custom_method: + fallback = kwargs.pop("fallback_on_custom_error", False) result = call_custom_method( - logger, method, custom_method, content, content_type, base_url, **kwargs + logger, method, custom_method, content, content_type, base_url, fallback_on_custom_error=fallback, **kwargs ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -342,7 +346,10 @@ def parse_structured_data( """ custom_method = method_registry.get("structured", method) if custom_method: - result = call_custom_method(logger, method, custom_method, data, data_format, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, data, data_format, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -386,7 +393,10 @@ def parse_email( """ custom_method = method_registry.get("email", method) if custom_method: - result = call_custom_method(logger, method, custom_method, email_content, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, email_content, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -433,7 +443,10 @@ def parse_code( """ custom_method = method_registry.get("code", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, language, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, language, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -483,7 +496,10 @@ def parse_media( """ custom_method = method_registry.get("media", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, media_type, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, media_type, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -526,7 +542,10 @@ def parse_pdf( """ custom_method = method_registry.get("document", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -567,7 +586,10 @@ def parse_docx( """ custom_method = method_registry.get("document", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -607,7 +629,10 @@ def parse_json(file_path: Union[str, Path], method: str = "default", **kwargs) - """ custom_method = method_registry.get("structured", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -651,7 +676,10 @@ def parse_csv( """ custom_method = method_registry.get("structured", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, delimiter, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, delimiter, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -687,7 +715,10 @@ def parse_xml(file_path: Union[str, Path], method: str = "default", **kwargs) -> """ custom_method = method_registry.get("structured", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result @@ -732,7 +763,10 @@ def parse_image( """ custom_method = method_registry.get("media", method) if custom_method: - result = call_custom_method(logger, method, custom_method, file_path, **kwargs) + fallback = kwargs.pop("fallback_on_custom_error", False) + result = call_custom_method( + logger, method, custom_method, file_path, fallback_on_custom_error=fallback, **kwargs + ) if result is not CUSTOM_METHOD_FELL_BACK: return result diff --git a/tests/utils/test_custom_method_can_refuse.py b/tests/utils/test_custom_method_can_refuse.py index c736e815..f51e28e3 100644 --- a/tests/utils/test_custom_method_can_refuse.py +++ b/tests/utils/test_custom_method_can_refuse.py @@ -154,3 +154,72 @@ def test_no_module_still_swallows_custom_method_failures(module_name): assert "falling back to default" not in source, ( f"semantica/{module_name}/methods.py still swallows custom method failures" ) + + +# ── Review findings on the first revision of this fix ──────────────────────── + +def test_the_reserved_flag_never_reaches_the_default_implementation(monkeypatch, tmp_path): + """ + `**kwargs` unpacking builds a fresh dict inside the helper, so popping there + left the caller's own kwargs untouched and the flag was forwarded on to the + default path. The helper documents the flag as never forwarded, so that + promise was false for exactly the case the flag exists for. + """ + seen = {} + + class Spy: + def __init__(self, **config): + seen.update(config) + + def export(self, *args, **kwargs): + (tmp_path / "written").write_text("default ran") + + monkeypatch.setattr(export_methods, "RDFExporter", Spy) + + def gate(data, file_path, **kwargs): + raise Refused("rejected") + + method_registry.register("rdf", "gate", gate) + export_methods.export_rdf( + KG, str(tmp_path / "out.ttl"), method="gate", fallback_on_custom_error=True + ) + + assert (tmp_path / "written").exists(), "the default path did not run" + assert "fallback_on_custom_error" not in seen, ( + f"the reserved flag was forwarded to the default implementation: {seen}" + ) + + +def test_the_reserved_flag_never_reaches_a_successful_custom_method(tmp_path): + seen = {} + + def writer(data, file_path, **kwargs): + seen.update(kwargs) + return "ok" + + method_registry.register("rdf", "writer", writer) + result = export_methods.export_rdf( + KG, str(tmp_path / "out.ttl"), method="writer", fallback_on_custom_error=True + ) + + assert result == "ok" + assert "fallback_on_custom_error" not in seen, seen + + +@pytest.mark.parametrize( + "module_name", ["export", "ingest", "parse", "normalize", "embeddings", "kg"], +) +def test_every_site_consumes_the_flag_before_forwarding(module_name): + """A site that forgets the pop reintroduces the leak silently.""" + import semantica + + source = ( + Path(semantica.__file__).parent / module_name / "methods.py" + ).read_text(encoding="utf-8") + + calls = source.count("result = call_custom_method(") + pops = source.count('.pop("fallback_on_custom_error", False)') + assert calls == pops, ( + f"semantica/{module_name}/methods.py has {calls} call site(s) but " + f"{pops} consume the reserved flag" + )