From 141bf8039418540d67317a95751a1db9f7cd2443 Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Tue, 5 May 2026 18:00:48 +0530 Subject: [PATCH 1/2] fix(conflicts): consolidate duplicate detect_conflicts into single dispatcher method Fixes #533 - Removes duplicate `detect_conflicts` definition that was silently overridden, causing AttributeError for callers passing `method=` or `property_name=` kwargs - Merges dispatcher logic into the surviving method with `method="all"` default supporting: "all", "value", "property", "type", "relationship", "temporal", "logical", "entity" - Fixes `method="relationship"` incorrectly defaulting `relationships` to the entities list; now defaults to `[]` with dict normalization - Removes unreachable dead code block after try/except raise in `detect_entity_conflicts` --- semantica/conflicts/conflict_detector.py | 89 ++++++++++-------------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/semantica/conflicts/conflict_detector.py b/semantica/conflicts/conflict_detector.py index 5443e539..d7396c14 100644 --- a/semantica/conflicts/conflict_detector.py +++ b/semantica/conflicts/conflict_detector.py @@ -133,48 +133,6 @@ class ConflictDetector: self.detected_conflicts: Dict[str, Conflict] = {} - def detect_conflicts( - self, - entities: Union[List[Dict[str, Any]], Dict[str, Any]], - method: str = "entity", - property_name: Optional[str] = None, - entity_type: Optional[str] = None, - **kwargs, - ) -> List[Conflict]: - """ - Detect conflicts using the specified method (convenience method). - - Args: - entities: Entities to check (List of dicts or a KG dict) - method: Detection method ("entity", "value", "type", "relationship", "temporal", "logical") - property_name: Property name for "value" method - entity_type: Optional entity type filter - **kwargs: Additional arguments - - Returns: - List of detected conflicts - """ - # If passed a KG dict, extract entities - if isinstance(entities, dict) and "entities" in entities: - entities = entities["entities"] - - if method == "value": - if not property_name: - raise ValueError("property_name is required for value conflict detection") - return self.detect_value_conflicts(entities, property_name, entity_type) - elif method == "type": - return self.detect_type_conflicts(entities) - elif method == "relationship": - relationships = kwargs.get("relationships", []) - return self.detect_relationship_conflicts(relationships) - elif method == "temporal": - return self.detect_temporal_conflicts(entities) - elif method == "logical": - return self.detect_logical_conflicts(entities) - else: - # Default to entity-wide detection - return self.detect_entity_conflicts(entities, entity_type) - def detect_value_conflicts( self, entities: Union[List[Dict[str, Any]], Dict[str, Any]], @@ -596,11 +554,6 @@ class ConflictDetector: tracking_id, status="failed", message=str(e) ) raise - for field_name in fields_to_check: - conflicts = self.detect_value_conflicts(entities, field_name, entity_type) - all_conflicts.extend(conflicts) - - return all_conflicts def _calculate_conflict_confidence( self, values: List[Any], sources: List[Dict[str, Any]] @@ -1252,20 +1205,25 @@ class ConflictDetector: def detect_conflicts( self, entities: Union[List[Dict[str, Any]], Dict[str, Any]], + method: str = "all", + property_name: Optional[str] = None, entity_type: Optional[str] = None, + **kwargs, ) -> List[Conflict]: """ - Detect all conflicts for entities (general method). - - This method detects all types of conflicts: value, type, relationship, - temporal, and logical conflicts. + Detect conflicts using the specified method. Args: - entities: List of entity dictionaries or Graph dictionary (containing "entities" key) + entities: List of entity dictionaries or Graph dictionary + method: Detection method — "all" (default), "value", "property", "type", + "relationship", "temporal", "logical", or "entity" + property_name: Property name required for ``method="value"`` and ``method="property"`` entity_type: Optional entity type filter + **kwargs: Extra arguments forwarded to the underlying method + (e.g. ``relationships=`` for ``method="relationship"``) Returns: - List of all detected conflicts + List of detected conflicts """ # Handle graph dictionary input if isinstance(entities, dict): @@ -1275,6 +1233,31 @@ class ConflictDetector: # If it's a single entity dict, wrap in list entities = [entities] + # Dispatch to a specific sub-method when one is requested + if method == "value": + if not property_name: + raise ValueError("property_name is required for method='value'") + return self.detect_value_conflicts(entities, property_name, entity_type) + elif method == "property": + if not property_name: + raise ValueError("property_name is required for method='property'") + return self.detect_property_conflicts(entities, property_name) + elif method == "type": + return self.detect_type_conflicts(entities) + elif method == "relationship": + relationships = kwargs.get("relationships", []) + if isinstance(relationships, dict): + relationships = relationships.get("relationships", [relationships]) + return self.detect_relationship_conflicts(relationships) + elif method == "temporal": + return self.detect_temporal_conflicts(entities) + elif method == "logical": + return self.detect_logical_conflicts(entities) + elif method == "entity": + return self.detect_entity_conflicts(entities, entity_type) + elif method != "all": + raise ValueError(f"Unknown conflict detection method: {method!r}") + tracking_id = self.progress_tracker.start_tracking( file=None, module="conflicts", From 0439cf884de6737430a05a4f0b64170d37d5a9c2 Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Tue, 5 May 2026 18:13:06 +0530 Subject: [PATCH 2/2] docs(changelog): record ConflictDetector.detect_conflicts duplicate definition fix (#533) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6385009..d4bde94f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **Fix: `ConflictDetector.detect_conflicts()` raises `AttributeError` when called with `method=` or `property_name=` kwargs** (issue #533, PR conflicts, by @KaifAhmad1): + - `detect_conflicts` was defined twice in `conflict_detector.py`; Python silently overwrote the first (dispatcher) definition with the second (comprehensive), which accepted no `method` or `property_name` parameters — causing `AttributeError` or `TypeError` for any caller using those kwargs. + - Removed the first (dead) definition and merged its dispatcher logic into the surviving method. New signature: `detect_conflicts(entities, method="all", property_name=None, entity_type=None, **kwargs)`. + - Supported `method` values: `"all"` (default, comprehensive), `"value"`, `"property"`, `"type"`, `"relationship"`, `"temporal"`, `"logical"`, `"entity"`. Unknown values raise `ValueError`. + - Fixed `method="relationship"` silently defaulting `relationships` to the entities list, which caused entity dicts to be iterated as relationship dicts producing silent wrong results (`None_None_None` keys). Now defaults to `[]` with dict normalization. + - Removed unreachable dead code (`for field_name in fields_to_check` loop after `try/except raise`) in `detect_entity_conflicts`. + - **Fix: `semantica[all]` installation fails on Windows due to `faiss-gpu` dependency** (issue #532, PR #utlis, by @KaifAhmad1): - `[all]` bundled the `[gpu]` extra (`faiss-gpu>=1.7.0`, `cupy>=10.0.0`), which has no Windows builds, causing `pip install "semantica[all]"` to fail with `No matching distribution found for faiss-gpu>=1.7.0`. - Removed `gpu` from both `[all]` lines in `pyproject.toml` — `[all]` now installs only cross-platform dependencies. Users on Linux who need GPU acceleration can install `semantica[gpu]` explicitly.