From 928f602d496137bae67f36e91538623c07e99cd6 Mon Sep 17 00:00:00 2001 From: Myst <1592048+LeMyst@users.noreply.github.com> Date: Sun, 7 Jan 2024 14:23:42 +0100 Subject: [PATCH] Add ActionIfExists.MERGE_REFS_OR_APPEND (#619) * Add ActionIfExists.MERGE_REFS_OR_APPEND (#607) (#618) * Lint files --------- Co-authored-by: Tiago Lubiana --- wikibaseintegrator/models/claims.py | 52 ++++++++++++++++++++++++++++- wikibaseintegrator/wbi_enums.py | 2 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/wikibaseintegrator/models/claims.py b/wikibaseintegrator/models/claims.py index a542b56f..95a6b374 100644 --- a/wikibaseintegrator/models/claims.py +++ b/wikibaseintegrator/models/claims.py @@ -1,6 +1,7 @@ from __future__ import annotations import copy +import warnings from abc import abstractmethod from typing import Any, Callable @@ -97,7 +98,26 @@ def add(self, claims: Claims | list[Claim] | Claim, action_if_exists: ActionIfEx elif action_if_exists == ActionIfExists.REPLACE_ALL: if claim not in self.claims[property]: self.claims[property].append(claim) - + elif action_if_exists == ActionIfExists.MERGE_REFS_OR_APPEND: + claim_exists = False + for existing_claim in self.claims[property]: + existing_claim_json = existing_claim.get_json() + claim_to_add_json = claim.get_json() + + # Check if the values match, including qualifiers + if (claim_to_add_json["mainsnak"]["datavalue"]["value"] == existing_claim_json["mainsnak"]["datavalue"]["value"]) and claim.quals_equal(claim, existing_claim): + claim_exists = True + + # Check if current reference block is present on references + if not Claim.ref_present(newitem=claim, olditem=existing_claim): + for ref_to_add in claim.references: + if ref_to_add not in existing_claim.references: + existing_claim.references.add(ref_to_add) + break + + # If the claim value does not exist, append it + if not claim_exists: + self.claims[property].append(claim) return self def from_json(self, json_data: dict[str, Any]) -> Claims: @@ -363,6 +383,17 @@ def equals(self, that: Claim, include_ref: bool = False, fref: Callable | None = return fref(self, that) + @staticmethod + def quals_equal(olditem: Claim, newitem: Claim) -> bool: + """ + Tests for exactly identical qualifiers. + """ + + oldqual = olditem.qualifiers + newqual = newitem.qualifiers + + return (len(oldqual) == len(newqual)) and all(x in oldqual for x in newqual) + @staticmethod def refs_equal(olditem: Claim, newitem: Claim) -> bool: """ @@ -377,6 +408,25 @@ def ref_equal(oldref: References, newref: References) -> bool: return len(oldrefs) == len(newrefs) and all(any(ref_equal(oldref, newref) for oldref in oldrefs) for newref in newrefs) + @staticmethod + def ref_present(olditem: Claim, newitem: Claim) -> bool: + """ + Tests if (1) there is a single ref in the new item and + (2) if this single ref is present among the claims of the old item. + """ + + oldrefs = olditem.references + newrefs = newitem.references + + if len(newrefs) != 1: + warnings.warn("New item has more or less than 1 reference block.") + return False + + def ref_equal(oldref: References, newref: References) -> bool: + return (len(oldref) == len(newref)) and all(x in oldref for x in newref) + + return any(any(ref_equal(oldref, newref) for oldref in oldrefs) for newref in newrefs) + @abstractmethod def get_sparql_value(self) -> str: pass diff --git a/wikibaseintegrator/wbi_enums.py b/wikibaseintegrator/wbi_enums.py index 22e13ede..9e390b5d 100644 --- a/wikibaseintegrator/wbi_enums.py +++ b/wikibaseintegrator/wbi_enums.py @@ -9,11 +9,13 @@ class ActionIfExists(Enum): FORCE_APPEND: Forces the addition of the new element to the property, even if it already exists. KEEP: Does nothing if the property already has elements stated. REPLACE_ALL: Replace all elements with the same property number. + MERGE_REFS_OR_APPEND: Add the new element to the property if it does not exist, otherwise merge the references, adding the references for the new claim as a new reference block. """ APPEND_OR_REPLACE = auto() FORCE_APPEND = auto() KEEP = auto() REPLACE_ALL = auto() + MERGE_REFS_OR_APPEND = auto() class WikibaseDatatype(Enum):