diff --git a/test/test_wbi_core.py b/test/test_wbi_core.py index 4bb39419..1d3d2569 100644 --- a/test/test_wbi_core.py +++ b/test/test_wbi_core.py @@ -6,7 +6,7 @@ Sense, String, TabularData, Time) from wikibaseintegrator.datatypes.extra import EDTF, LocalMedia from wikibaseintegrator.entities import ItemEntity -from wikibaseintegrator.models import Descriptions +from wikibaseintegrator.models.descriptions import Descriptions from wikibaseintegrator.wbi_config import config as wbi_config from wikibaseintegrator.wbi_enums import ActionIfExists, WikibaseDatePrecision, WikibaseRank, WikibaseSnakType from wikibaseintegrator.wbi_helpers import generate_entity_instances, search_entities diff --git a/wikibaseintegrator/datatypes/basedatatype.py b/wikibaseintegrator/datatypes/basedatatype.py index 94c62b7b..55b4700f 100644 --- a/wikibaseintegrator/datatypes/basedatatype.py +++ b/wikibaseintegrator/datatypes/basedatatype.py @@ -3,7 +3,7 @@ import re from typing import Any, List, Type, Union -from wikibaseintegrator.models import Claim +from wikibaseintegrator.models.claim import Claim class BaseDataType(Claim): diff --git a/wikibaseintegrator/datatypes/globecoordinate.py b/wikibaseintegrator/datatypes/globecoordinate.py index 30e206ec..6978fac1 100644 --- a/wikibaseintegrator/datatypes/globecoordinate.py +++ b/wikibaseintegrator/datatypes/globecoordinate.py @@ -2,7 +2,7 @@ from typing import Any from wikibaseintegrator.datatypes.basedatatype import BaseDataType -from wikibaseintegrator.models import Claim +from wikibaseintegrator.models.claim import Claim from wikibaseintegrator.wbi_config import config diff --git a/wikibaseintegrator/entities/baseentity.py b/wikibaseintegrator/entities/baseentity.py index ffd8543f..583a9f2d 100644 --- a/wikibaseintegrator/entities/baseentity.py +++ b/wikibaseintegrator/entities/baseentity.py @@ -8,7 +8,8 @@ from wikibaseintegrator import wbi_fastrun from wikibaseintegrator.datatypes import BaseDataType -from wikibaseintegrator.models.claims import Claim, Claims +from wikibaseintegrator.models.claim import Claim +from wikibaseintegrator.models.claims import Claims from wikibaseintegrator.wbi_enums import ActionIfExists from wikibaseintegrator.wbi_exceptions import MissingEntityException, ModificationFailed, MWApiError from wikibaseintegrator.wbi_helpers import delete_page, mediawiki_api_call_helper diff --git a/wikibaseintegrator/entities/item.py b/wikibaseintegrator/entities/item.py index 227fe2cf..3867d650 100644 --- a/wikibaseintegrator/entities/item.py +++ b/wikibaseintegrator/entities/item.py @@ -4,10 +4,10 @@ from typing import Any, Dict, Union from wikibaseintegrator.entities.baseentity import BaseEntity -from wikibaseintegrator.models import LanguageValues from wikibaseintegrator.models.aliases import Aliases from wikibaseintegrator.models.descriptions import Descriptions from wikibaseintegrator.models.labels import Labels +from wikibaseintegrator.models.language_values import LanguageValues from wikibaseintegrator.models.sitelinks import Sitelinks diff --git a/wikibaseintegrator/entities/mediainfo.py b/wikibaseintegrator/entities/mediainfo.py index a0a5dbbf..4baf919f 100644 --- a/wikibaseintegrator/entities/mediainfo.py +++ b/wikibaseintegrator/entities/mediainfo.py @@ -4,10 +4,11 @@ from typing import Any, Dict, List, Union from wikibaseintegrator.entities.baseentity import BaseEntity -from wikibaseintegrator.models import Claims, LanguageValues from wikibaseintegrator.models.aliases import Aliases +from wikibaseintegrator.models.claims import Claims from wikibaseintegrator.models.descriptions import Descriptions from wikibaseintegrator.models.labels import Labels +from wikibaseintegrator.models.language_values import LanguageValues from wikibaseintegrator.wbi_helpers import mediawiki_api_call_helper diff --git a/wikibaseintegrator/models/__init__.py b/wikibaseintegrator/models/__init__.py index cff30bec..e69de29b 100644 --- a/wikibaseintegrator/models/__init__.py +++ b/wikibaseintegrator/models/__init__.py @@ -1,13 +0,0 @@ -from .aliases import Alias, Aliases -from .basemodel import BaseModel -from .claims import Claim, Claims -from .descriptions import Descriptions -from .forms import Form, Forms -from .labels import Labels -from .language_values import LanguageValue, LanguageValues -from .lemmas import Lemmas -from .qualifiers import Qualifiers -from .references import Reference, References -from .senses import Glosses, Sense, Senses -from .sitelinks import Sitelink, Sitelinks -from .snaks import Snak, Snaks diff --git a/wikibaseintegrator/models/alias.py b/wikibaseintegrator/models/alias.py new file mode 100644 index 00000000..20eee198 --- /dev/null +++ b/wikibaseintegrator/models/alias.py @@ -0,0 +1,5 @@ +import wikibaseintegrator.models.language_value as language_value + + +class Alias(language_value.LanguageValue): + pass diff --git a/wikibaseintegrator/models/aliases.py b/wikibaseintegrator/models/aliases.py index 20e599d0..66e43f4f 100644 --- a/wikibaseintegrator/models/aliases.py +++ b/wikibaseintegrator/models/aliases.py @@ -2,8 +2,8 @@ from typing import Dict, List, Optional, Union +from wikibaseintegrator.models.alias import Alias from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.language_values import LanguageValue from wikibaseintegrator.wbi_config import config from wikibaseintegrator.wbi_enums import ActionIfExists @@ -91,7 +91,3 @@ def from_json(self, json_data: Dict[str, List]) -> Aliases: # def __contains__(self, item): # all_aliases = [item for sublist in list(self.aliases.values()) for item in sublist] # return item in list(map(lambda x: x.value, all_aliases)) - - -class Alias(LanguageValue): - pass diff --git a/wikibaseintegrator/models/claim.py b/wikibaseintegrator/models/claim.py new file mode 100644 index 00000000..8c23a998 --- /dev/null +++ b/wikibaseintegrator/models/claim.py @@ -0,0 +1,251 @@ +from __future__ import annotations + +import copy +from typing import Any, Callable, Dict, List, Optional, Union + +import wikibaseintegrator.models.basemodel +from wikibaseintegrator.models.qualifiers import Qualifiers +from wikibaseintegrator.models.reference import Reference +from wikibaseintegrator.models.references import References +from wikibaseintegrator.models.snak import Snak +from wikibaseintegrator.models.snaks import Snaks +from wikibaseintegrator.wbi_enums import WikibaseRank + + +class Claim(wikibaseintegrator.models.basemodel.BaseModel): + DTYPE = 'claim' + + def __init__(self, qualifiers: Qualifiers = None, rank: WikibaseRank = None, references: Union[References, List[Union[Claim, List[Claim]]]] = None) -> None: + """ + + :param qualifiers: + :param rank: + :param references: A References object, a list of Claim object or a list of list of Claim object + """ + self.mainsnak = Snak(datatype=self.DTYPE) + self.type = 'statement' + self.qualifiers = qualifiers or Qualifiers() + self.qualifiers_order = [] + self.id = None + self.rank = rank or WikibaseRank.NORMAL + self.removed = False + + self.references = References() + + if isinstance(references, References): + self.references = references + elif isinstance(references, list): + for ref_list in references: + ref = Reference() + if isinstance(ref_list, list): + snaks = Snaks() + for ref_claim in ref_list: + if isinstance(ref_claim, Claim): + snaks.add(Snak().from_json(ref_claim.get_json()['mainsnak'])) + else: + raise ValueError("The references must be a References object or a list of Claim object") + ref.snaks = snaks + elif isinstance(ref_list, Claim): + ref.snaks = Snaks().add(Snak().from_json(ref_list.get_json()['mainsnak'])) + elif isinstance(ref_list, Reference): + ref = ref_list + self.references.add(reference=ref) + elif references is not None: + raise ValueError("The references must be a References object or a list of Claim object") + + @property + def mainsnak(self) -> Snak: + return self.__mainsnak + + @mainsnak.setter + def mainsnak(self, value: Snak): + self.__mainsnak = value + + @property + def type(self) -> Union[str, Dict]: + return self.__type + + @type.setter + def type(self, value: Union[str, Dict]): + self.__type = value + + @property + def qualifiers(self) -> Qualifiers: + return self.__qualifiers + + @qualifiers.setter + def qualifiers(self, value: Qualifiers) -> None: + assert isinstance(value, (Qualifiers, list)) + self.__qualifiers: Qualifiers = Qualifiers().set(value) if isinstance(value, list) else value + + @property + def qualifiers_order(self) -> List[str]: + return self.__qualifiers_order + + @qualifiers_order.setter + def qualifiers_order(self, value: List[str]): + self.__qualifiers_order = value + + @property + def id(self) -> Optional[str]: + return self.__id + + @id.setter + def id(self, value: Optional[str]): + self.__id = value + + @property + def rank(self) -> WikibaseRank: + return self.__rank + + @rank.setter + def rank(self, value: WikibaseRank): + """Parse the rank. The enum thows an error if it is not one of the recognized values""" + self.__rank = WikibaseRank(value) + + @property + def references(self) -> References: + return self.__references + + @references.setter + def references(self, value: References): + self.__references = value + + @property + def removed(self) -> bool: + return self.__removed + + @removed.setter + def removed(self, value: bool): + self.__removed = value + + def remove(self, remove=True) -> None: + self.removed = remove + + def update(self, claim: Claim) -> None: + self.mainsnak = claim.mainsnak + self.qualifiers = claim.qualifiers + self.qualifiers_order = claim.qualifiers_order + self.rank = claim.rank + self.references = claim.references + + def from_json(self, json_data: Dict[str, Any]) -> Claim: + """ + + :param json_data: a JSON representation of a Claim + """ + self.mainsnak = Snak().from_json(json_data['mainsnak']) + self.type = str(json_data['type']) + if 'qualifiers' in json_data: + self.qualifiers = Qualifiers().from_json(json_data['qualifiers']) + if 'qualifiers-order' in json_data: + self.qualifiers_order = list(json_data['qualifiers-order']) + self.id = str(json_data['id']) + self.rank: WikibaseRank = WikibaseRank(json_data['rank']) + if 'references' in json_data: + self.references = References().from_json(json_data['references']) + + return self + + def get_json(self) -> Dict[str, Any]: + json_data: Dict[str, Union[str, List[Dict], List[str], Dict[str, str], Dict[str, List], None]] = { + 'mainsnak': self.mainsnak.get_json(), + 'type': self.type, + 'id': self.id, + 'rank': self.rank.value + } + # Remove id if it's a temporary one + if not self.id: + del json_data['id'] + if len(self.qualifiers) > 0: + json_data['qualifiers'] = self.qualifiers.get_json() + json_data['qualifiers-order'] = list(self.qualifiers_order) + if len(self.references) > 0: + json_data['references'] = self.references.get_json() + if self.removed: + if self.id: + json_data['remove'] = '' + return json_data + + def has_equal_qualifiers(self, other: Claim) -> bool: + # check if the qualifiers are equal with the 'other' object + self_qualifiers = copy.deepcopy(self.qualifiers) + other_qualifiers = copy.deepcopy(other.qualifiers) + + if len(self_qualifiers) != len(other_qualifiers): + return False + + for property_number in self_qualifiers.qualifiers: + if property_number not in other_qualifiers.qualifiers: + return False + + if len(self_qualifiers.qualifiers[property_number]) != len(other_qualifiers.qualifiers[property_number]): + return False + + flg = [False for _ in range(len(self_qualifiers.qualifiers[property_number]))] + for count, i in enumerate(self_qualifiers.qualifiers[property_number]): + for q in other_qualifiers: + if i == q: + flg[count] = True + if not all(flg): + return False + + return True + + # TODO: rewrite this? + def __contains__(self, item): + if isinstance(item, Claim): + return self == item + + if isinstance(item, str): + return self.mainsnak.datavalue == item + + return super().__contains__(item) + + def __eq__(self, other): + if isinstance(other, Claim): + return self.mainsnak.datavalue == other.mainsnak.datavalue and self.mainsnak.property_number == other.mainsnak.property_number and self.has_equal_qualifiers(other) + + if isinstance(other, str): + return self.mainsnak.property_number == other + + raise super().__eq__(other) + + def equals(self, that: Claim, include_ref: bool = False, fref: Callable = None) -> bool: + """ + Tests for equality of two statements. + If comparing references, the order of the arguments matters!!! + self is the current statement, the next argument is the new statement. + Allows passing in a function to use to compare the references 'fref'. Default is equality. + fref accepts two arguments 'oldrefs' and 'newrefs', each of which are a list of references, + where each reference is a list of statements + """ + + if not include_ref: + # return the result of BaseDataType.__eq__, which is testing for equality of value and qualifiers + return self == that + + if self != that: + return False + + if fref is None: + return Claim.refs_equal(self, that) + + return fref(self, that) + + @staticmethod + def refs_equal(olditem: Claim, newitem: Claim) -> bool: + """ + tests for exactly identical references + """ + + oldrefs = olditem.references + newrefs = newitem.references + + def ref_equal(oldref: References, newref: References) -> bool: + return (len(oldref) == len(newref)) and all(x in oldref for x in newref) + + return len(oldrefs) == len(newrefs) and all(any(ref_equal(oldref, newref) for oldref in oldrefs) for newref in newrefs) + + def get_sparql_value(self) -> str: + pass diff --git a/wikibaseintegrator/models/claims.py b/wikibaseintegrator/models/claims.py index 2049485c..844f4c00 100644 --- a/wikibaseintegrator/models/claims.py +++ b/wikibaseintegrator/models/claims.py @@ -1,13 +1,10 @@ from __future__ import annotations -import copy -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any, Dict, List, Union from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.qualifiers import Qualifiers -from wikibaseintegrator.models.references import Reference, References -from wikibaseintegrator.models.snaks import Snak, Snaks -from wikibaseintegrator.wbi_enums import ActionIfExists, WikibaseRank +from wikibaseintegrator.models.claim import Claim +from wikibaseintegrator.wbi_enums import ActionIfExists class Claims(BaseModel): @@ -125,242 +122,3 @@ def __iter__(self): for claim in self.claims.values(): iterate.extend(claim) return iter(iterate) - - -class Claim(BaseModel): - DTYPE = 'claim' - - def __init__(self, qualifiers: Qualifiers = None, rank: WikibaseRank = None, references: Union[References, List[Union[Claim, List[Claim]]]] = None) -> None: - """ - - :param qualifiers: - :param rank: - :param references: A References object, a list of Claim object or a list of list of Claim object - """ - self.mainsnak = Snak(datatype=self.DTYPE) - self.type = 'statement' - self.qualifiers = qualifiers or Qualifiers() - self.qualifiers_order = [] - self.id = None - self.rank = rank or WikibaseRank.NORMAL - self.removed = False - - self.references = References() - - if isinstance(references, References): - self.references = references - elif isinstance(references, list): - for ref_list in references: - ref = Reference() - if isinstance(ref_list, list): - snaks = Snaks() - for ref_claim in ref_list: - if isinstance(ref_claim, Claim): - snaks.add(Snak().from_json(ref_claim.get_json()['mainsnak'])) - else: - raise ValueError("The references must be a References object or a list of Claim object") - ref.snaks = snaks - elif isinstance(ref_list, Claim): - ref.snaks = Snaks().add(Snak().from_json(ref_list.get_json()['mainsnak'])) - elif isinstance(ref_list, Reference): - ref = ref_list - self.references.add(reference=ref) - elif references is not None: - raise ValueError("The references must be a References object or a list of Claim object") - - @property - def mainsnak(self) -> Snak: - return self.__mainsnak - - @mainsnak.setter - def mainsnak(self, value: Snak): - self.__mainsnak = value - - @property - def type(self) -> Union[str, Dict]: - return self.__type - - @type.setter - def type(self, value: Union[str, Dict]): - self.__type = value - - @property - def qualifiers(self) -> Qualifiers: - return self.__qualifiers - - @qualifiers.setter - def qualifiers(self, value: Qualifiers) -> None: - assert isinstance(value, (Qualifiers, list)) - self.__qualifiers: Qualifiers = Qualifiers().set(value) if isinstance(value, list) else value - - @property - def qualifiers_order(self) -> List[str]: - return self.__qualifiers_order - - @qualifiers_order.setter - def qualifiers_order(self, value: List[str]): - self.__qualifiers_order = value - - @property - def id(self) -> Optional[str]: - return self.__id - - @id.setter - def id(self, value: Optional[str]): - self.__id = value - - @property - def rank(self) -> WikibaseRank: - return self.__rank - - @rank.setter - def rank(self, value: WikibaseRank): - """Parse the rank. The enum thows an error if it is not one of the recognized values""" - self.__rank = WikibaseRank(value) - - @property - def references(self) -> References: - return self.__references - - @references.setter - def references(self, value: References): - self.__references = value - - @property - def removed(self) -> bool: - return self.__removed - - @removed.setter - def removed(self, value: bool): - self.__removed = value - - def remove(self, remove=True) -> None: - self.removed = remove - - def update(self, claim: Claim) -> None: - self.mainsnak = claim.mainsnak - self.qualifiers = claim.qualifiers - self.qualifiers_order = claim.qualifiers_order - self.rank = claim.rank - self.references = claim.references - - def from_json(self, json_data: Dict[str, Any]) -> Claim: - """ - - :param json_data: a JSON representation of a Claim - """ - self.mainsnak = Snak().from_json(json_data['mainsnak']) - self.type = str(json_data['type']) - if 'qualifiers' in json_data: - self.qualifiers = Qualifiers().from_json(json_data['qualifiers']) - if 'qualifiers-order' in json_data: - self.qualifiers_order = list(json_data['qualifiers-order']) - self.id = str(json_data['id']) - self.rank: WikibaseRank = WikibaseRank(json_data['rank']) - if 'references' in json_data: - self.references = References().from_json(json_data['references']) - - return self - - def get_json(self) -> Dict[str, Any]: - json_data: Dict[str, Union[str, List[Dict], List[str], Dict[str, str], Dict[str, List], None]] = { - 'mainsnak': self.mainsnak.get_json(), - 'type': self.type, - 'id': self.id, - 'rank': self.rank.value - } - # Remove id if it's a temporary one - if not self.id: - del json_data['id'] - if len(self.qualifiers) > 0: - json_data['qualifiers'] = self.qualifiers.get_json() - json_data['qualifiers-order'] = list(self.qualifiers_order) - if len(self.references) > 0: - json_data['references'] = self.references.get_json() - if self.removed: - if self.id: - json_data['remove'] = '' - return json_data - - def has_equal_qualifiers(self, other: Claim) -> bool: - # check if the qualifiers are equal with the 'other' object - self_qualifiers = copy.deepcopy(self.qualifiers) - other_qualifiers = copy.deepcopy(other.qualifiers) - - if len(self_qualifiers) != len(other_qualifiers): - return False - - for property_number in self_qualifiers.qualifiers: - if property_number not in other_qualifiers.qualifiers: - return False - - if len(self_qualifiers.qualifiers[property_number]) != len(other_qualifiers.qualifiers[property_number]): - return False - - flg = [False for _ in range(len(self_qualifiers.qualifiers[property_number]))] - for count, i in enumerate(self_qualifiers.qualifiers[property_number]): - for q in other_qualifiers: - if i == q: - flg[count] = True - if not all(flg): - return False - - return True - - # TODO: rewrite this? - def __contains__(self, item): - if isinstance(item, Claim): - return self == item - - if isinstance(item, str): - return self.mainsnak.datavalue == item - - return super().__contains__(item) - - def __eq__(self, other): - if isinstance(other, Claim): - return self.mainsnak.datavalue == other.mainsnak.datavalue and self.mainsnak.property_number == other.mainsnak.property_number and self.has_equal_qualifiers(other) - - if isinstance(other, str): - return self.mainsnak.property_number == other - - raise super().__eq__(other) - - def equals(self, that: Claim, include_ref: bool = False, fref: Callable = None) -> bool: - """ - Tests for equality of two statements. - If comparing references, the order of the arguments matters!!! - self is the current statement, the next argument is the new statement. - Allows passing in a function to use to compare the references 'fref'. Default is equality. - fref accepts two arguments 'oldrefs' and 'newrefs', each of which are a list of references, - where each reference is a list of statements - """ - - if not include_ref: - # return the result of BaseDataType.__eq__, which is testing for equality of value and qualifiers - return self == that - - if self != that: - return False - - if fref is None: - return Claim.refs_equal(self, that) - - return fref(self, that) - - @staticmethod - def refs_equal(olditem: Claim, newitem: Claim) -> bool: - """ - tests for exactly identical references - """ - - oldrefs = olditem.references - newrefs = newitem.references - - def ref_equal(oldref: References, newref: References) -> bool: - return (len(oldref) == len(newref)) and all(x in oldref for x in newref) - - return len(oldrefs) == len(newrefs) and all(any(ref_equal(oldref, newref) for oldref in oldrefs) for newref in newrefs) - - def get_sparql_value(self) -> str: - pass diff --git a/wikibaseintegrator/models/descriptions.py b/wikibaseintegrator/models/descriptions.py index 872e730c..bb888ea1 100644 --- a/wikibaseintegrator/models/descriptions.py +++ b/wikibaseintegrator/models/descriptions.py @@ -2,7 +2,8 @@ from typing import Dict -from wikibaseintegrator.models.language_values import LanguageValue, LanguageValues +from wikibaseintegrator.models.language_value import LanguageValue +from wikibaseintegrator.models.language_values import LanguageValues class Descriptions(LanguageValues): diff --git a/wikibaseintegrator/models/form.py b/wikibaseintegrator/models/form.py new file mode 100644 index 00000000..84737667 --- /dev/null +++ b/wikibaseintegrator/models/form.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from typing import Any, Dict, List, Union + +from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.models.claims import Claims +from wikibaseintegrator.models.language_values import LanguageValues +from wikibaseintegrator.models.representations import Representations + + +class Form(BaseModel): + def __init__(self, form_id: str = None, representations: Representations = None, grammatical_features: Union[str, int, List[str]] = None, claims: Claims = None): + self.id = form_id + self.representations: Representations = representations or LanguageValues() + self.grammatical_features = grammatical_features or [] + self.claims = claims or Claims() + + @property + def id(self): + return self.__id + + @id.setter + def id(self, value): + self.__id = value + + @property + def representations(self): + return self.__representations + + @representations.setter + def representations(self, value): + self.__representations = value + + @property + def grammatical_features(self): + return self.__grammatical_features + + @grammatical_features.setter + def grammatical_features(self, value: Union[str, int, List[str]]): + if not hasattr(self, '__grammatical_features') or value is None: + self.__grammatical_features = [] + + if isinstance(value, int): + self.__grammatical_features.append('Q' + str(value)) + elif isinstance(value, str): + self.__grammatical_features.append(value) + elif isinstance(value, list): + self.__grammatical_features = value + else: + raise TypeError(f"value must be a str, an int or a list of strings, got '{type(value)}'") + + @property + def claims(self): + return self.__claims + + @claims.setter + def claims(self, value): + self.__claims = value + + def from_json(self, json_data: Dict[str, Any]) -> Form: + self.id = json_data['id'] + self.representations = Representations().from_json(json_data['representations']) + self.grammatical_features = json_data['grammaticalFeatures'] + self.claims = Claims().from_json(json_data['claims']) + + return self + + def get_json(self) -> Dict[str, Union[str, Dict, List]]: + json_data: Dict[str, Union[str, Dict, List]] = { + 'id': self.id, + 'representations': self.representations.get_json(), + 'grammaticalFeatures': self.grammatical_features, + 'claims': self.claims.get_json() + } + + if self.id is None: + json_data['add'] = '' + del json_data['id'] + + return json_data diff --git a/wikibaseintegrator/models/forms.py b/wikibaseintegrator/models/forms.py index eb90dbd7..538c0804 100644 --- a/wikibaseintegrator/models/forms.py +++ b/wikibaseintegrator/models/forms.py @@ -1,10 +1,9 @@ from __future__ import annotations -from typing import Any, Dict, List, Union +from typing import Dict, List from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.claims import Claims -from wikibaseintegrator.models.language_values import LanguageValues +from wikibaseintegrator.models.form import Form class Forms(BaseModel): @@ -39,79 +38,3 @@ def get_json(self) -> List[Dict]: json_data.append(form.get_json()) return json_data - - -class Form(BaseModel): - def __init__(self, form_id: str = None, representations: Representations = None, grammatical_features: Union[str, int, List[str]] = None, claims: Claims = None): - self.id = form_id - self.representations: Representations = representations or LanguageValues() - self.grammatical_features = grammatical_features or [] - self.claims = claims or Claims() - - @property - def id(self): - return self.__id - - @id.setter - def id(self, value): - self.__id = value - - @property - def representations(self): - return self.__representations - - @representations.setter - def representations(self, value): - self.__representations = value - - @property - def grammatical_features(self): - return self.__grammatical_features - - @grammatical_features.setter - def grammatical_features(self, value: Union[str, int, List[str]]): - if not hasattr(self, '__grammatical_features') or value is None: - self.__grammatical_features = [] - - if isinstance(value, int): - self.__grammatical_features.append('Q' + str(value)) - elif isinstance(value, str): - self.__grammatical_features.append(value) - elif isinstance(value, list): - self.__grammatical_features = value - else: - raise TypeError(f"value must be a str, an int or a list of strings, got '{type(value)}'") - - @property - def claims(self): - return self.__claims - - @claims.setter - def claims(self, value): - self.__claims = value - - def from_json(self, json_data: Dict[str, Any]) -> Form: - self.id = json_data['id'] - self.representations = Representations().from_json(json_data['representations']) - self.grammatical_features = json_data['grammaticalFeatures'] - self.claims = Claims().from_json(json_data['claims']) - - return self - - def get_json(self) -> Dict[str, Union[str, Dict, List]]: - json_data: Dict[str, Union[str, Dict, List]] = { - 'id': self.id, - 'representations': self.representations.get_json(), - 'grammaticalFeatures': self.grammatical_features, - 'claims': self.claims.get_json() - } - - if self.id is None: - json_data['add'] = '' - del json_data['id'] - - return json_data - - -class Representations(LanguageValues): - pass diff --git a/wikibaseintegrator/models/glosses.py b/wikibaseintegrator/models/glosses.py new file mode 100644 index 00000000..54fa1fc7 --- /dev/null +++ b/wikibaseintegrator/models/glosses.py @@ -0,0 +1,5 @@ +from wikibaseintegrator.models.language_values import LanguageValues + + +class Glosses(LanguageValues): + pass diff --git a/wikibaseintegrator/models/labels.py b/wikibaseintegrator/models/labels.py index 6c186446..9c300d84 100644 --- a/wikibaseintegrator/models/labels.py +++ b/wikibaseintegrator/models/labels.py @@ -2,7 +2,8 @@ from typing import Dict -from wikibaseintegrator.models.language_values import LanguageValue, LanguageValues +from wikibaseintegrator.models.language_value import LanguageValue +from wikibaseintegrator.models.language_values import LanguageValues class Labels(LanguageValues): diff --git a/wikibaseintegrator/models/language_value.py b/wikibaseintegrator/models/language_value.py new file mode 100644 index 00000000..e6fd2efa --- /dev/null +++ b/wikibaseintegrator/models/language_value.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from typing import Dict, Optional + +from wikibaseintegrator.models.basemodel import BaseModel + + +class LanguageValue(BaseModel): + def __init__(self, language: str, value: str = None): + self.language = language + self.value = value + self.removed = False + + @property + def language(self) -> str: + return self.__language + + @language.setter + def language(self, value: Optional[str]): + if value is None: + raise ValueError("language can't be None") + + if value == '': + raise ValueError("language can't be empty") + + if not isinstance(value, str): + raise ValueError("language must be a str") + + self.__language = value + + @property + def value(self) -> Optional[str]: + """ + The value of the LanguageValue instance. + :return: A string with the value of the LanguageValue instance. + """ + return self.__value + + @value.setter + def value(self, value: Optional[str]): + self.__value = value + + @property + def removed(self) -> bool: + return self.__removed + + @removed.setter + def removed(self, value: bool): + self.__removed = value + + def remove(self) -> LanguageValue: + self.removed = True + + return self + + def from_json(self, json_data: Dict[str, str]) -> LanguageValue: + self.language = json_data['language'] + self.value = json_data['value'] + + return self + + def get_json(self) -> Dict[str, Optional[str]]: + json_data = { + 'language': self.language, + 'value': self.value + } + if self.removed: + json_data['remove'] = '' + return json_data + + def __contains__(self, item): + return item in self.value + + def __eq__(self, other): + if isinstance(other, LanguageValue): + return self.value == other.value and self.language == other.language + + return self.value == other + + def __len__(self): + return len(self.value) + + def __str__(self): + return self.value diff --git a/wikibaseintegrator/models/language_values.py b/wikibaseintegrator/models/language_values.py index b83dd2ea..c42f57a3 100644 --- a/wikibaseintegrator/models/language_values.py +++ b/wikibaseintegrator/models/language_values.py @@ -3,6 +3,7 @@ from typing import Dict, Optional from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.models.language_value import LanguageValue from wikibaseintegrator.wbi_config import config from wikibaseintegrator.wbi_enums import ActionIfExists @@ -103,82 +104,3 @@ def __contains__(self, language: str) -> bool: def __iter__(self): return iter(self.values.values()) - - -class LanguageValue(BaseModel): - def __init__(self, language: str, value: str = None): - self.language = language - self.value = value - self.removed = False - - @property - def language(self) -> str: - return self.__language - - @language.setter - def language(self, value: Optional[str]): - if value is None: - raise ValueError("language can't be None") - - if value == '': - raise ValueError("language can't be empty") - - if not isinstance(value, str): - raise ValueError("language must be a str") - - self.__language = value - - @property - def value(self) -> Optional[str]: - """ - The value of the LanguageValue instance. - :return: A string with the value of the LanguageValue instance. - """ - return self.__value - - @value.setter - def value(self, value: Optional[str]): - self.__value = value - - @property - def removed(self) -> bool: - return self.__removed - - @removed.setter - def removed(self, value: bool): - self.__removed = value - - def remove(self) -> LanguageValue: - self.removed = True - - return self - - def from_json(self, json_data: Dict[str, str]) -> LanguageValue: - self.language = json_data['language'] - self.value = json_data['value'] - - return self - - def get_json(self) -> Dict[str, Optional[str]]: - json_data = { - 'language': self.language, - 'value': self.value - } - if self.removed: - json_data['remove'] = '' - return json_data - - def __contains__(self, item): - return item in self.value - - def __eq__(self, other): - if isinstance(other, LanguageValue): - return self.value == other.value and self.language == other.language - - return self.value == other - - def __len__(self): - return len(self.value) - - def __str__(self): - return self.value diff --git a/wikibaseintegrator/models/lemmas.py b/wikibaseintegrator/models/lemmas.py index 01a9b268..0ec6e719 100644 --- a/wikibaseintegrator/models/lemmas.py +++ b/wikibaseintegrator/models/lemmas.py @@ -2,7 +2,8 @@ from typing import Dict -from wikibaseintegrator.models.language_values import LanguageValue, LanguageValues +from wikibaseintegrator.models.language_value import LanguageValue +from wikibaseintegrator.models.language_values import LanguageValues class Lemmas(LanguageValues): diff --git a/wikibaseintegrator/models/qualifiers.py b/wikibaseintegrator/models/qualifiers.py index dcd50670..74e2e277 100644 --- a/wikibaseintegrator/models/qualifiers.py +++ b/wikibaseintegrator/models/qualifiers.py @@ -3,11 +3,11 @@ from typing import TYPE_CHECKING, Dict, List, Union from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.snaks import Snak +from wikibaseintegrator.models.snak import Snak from wikibaseintegrator.wbi_enums import ActionIfExists if TYPE_CHECKING: - from wikibaseintegrator.models.claims import Claim + from wikibaseintegrator.models.claim import Claim class Qualifiers(BaseModel): diff --git a/wikibaseintegrator/models/reference.py b/wikibaseintegrator/models/reference.py new file mode 100644 index 00000000..d178c0c7 --- /dev/null +++ b/wikibaseintegrator/models/reference.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Dict, List, Union + +from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.models.snak import Snak +from wikibaseintegrator.models.snaks import Snaks +from wikibaseintegrator.wbi_enums import ActionIfExists + +if TYPE_CHECKING: + from wikibaseintegrator.models.claim import Claim + + +class Reference(BaseModel): + def __init__(self, snaks: Snaks = None, snaks_order: List = None): + self.hash = None + self.snaks = snaks or Snaks() + self.snaks_order = snaks_order or [] + + @property + def hash(self): + return self.__hash + + @hash.setter + def hash(self, value): + self.__hash = value + + @property + def snaks(self): + return self.__snaks + + @snaks.setter + def snaks(self, value): + self.__snaks = value + + @property + def snaks_order(self): + return self.__snaks_order + + @snaks_order.setter + def snaks_order(self, value): + self.__snaks_order = value + + # TODO: implement action_if_exists + def add(self, snak: Union[Snak, Claim] = None, action_if_exists: ActionIfExists = ActionIfExists.REPLACE_ALL) -> Reference: + from wikibaseintegrator.models.claims import Claim + if isinstance(snak, Claim): + snak = Snak().from_json(snak.get_json()['mainsnak']) + + if snak is not None: + assert isinstance(snak, Snak) + + self.snaks.add(snak) + + return self + + def from_json(self, json_data: Dict[str, Any]) -> Reference: + self.hash = json_data['hash'] + self.snaks = Snaks().from_json(json_data['snaks']) + self.snaks_order = json_data['snaks-order'] + + return self + + def get_json(self) -> Dict[str, Union[Dict, List]]: + json_data: Dict[str, Union[Dict, List]] = { + 'snaks': self.snaks.get_json(), + 'snaks-order': self.snaks_order + } + return json_data + + def __iter__(self): + return iter(self.snaks) + + def __len__(self): + return len(self.snaks) diff --git a/wikibaseintegrator/models/references.py b/wikibaseintegrator/models/references.py index 3869c6b5..da532dec 100644 --- a/wikibaseintegrator/models/references.py +++ b/wikibaseintegrator/models/references.py @@ -1,13 +1,15 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Dict, List, Optional, Union from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.snaks import Snak, Snaks +from wikibaseintegrator.models.reference import Reference +from wikibaseintegrator.models.snak import Snak +from wikibaseintegrator.models.snaks import Snaks from wikibaseintegrator.wbi_enums import ActionIfExists if TYPE_CHECKING: - from wikibaseintegrator.models.claims import Claim + from wikibaseintegrator.models.claim import Claim class References(BaseModel): @@ -77,67 +79,3 @@ def __iter__(self): def __len__(self): return len(self.references) - - -class Reference(BaseModel): - def __init__(self, snaks: Snaks = None, snaks_order: List = None): - self.hash = None - self.snaks = snaks or Snaks() - self.snaks_order = snaks_order or [] - - @property - def hash(self): - return self.__hash - - @hash.setter - def hash(self, value): - self.__hash = value - - @property - def snaks(self): - return self.__snaks - - @snaks.setter - def snaks(self, value): - self.__snaks = value - - @property - def snaks_order(self): - return self.__snaks_order - - @snaks_order.setter - def snaks_order(self, value): - self.__snaks_order = value - - # TODO: implement action_if_exists - def add(self, snak: Union[Snak, Claim] = None, action_if_exists: ActionIfExists = ActionIfExists.REPLACE_ALL) -> Reference: - from wikibaseintegrator.models.claims import Claim - if isinstance(snak, Claim): - snak = Snak().from_json(snak.get_json()['mainsnak']) - - if snak is not None: - assert isinstance(snak, Snak) - - self.snaks.add(snak) - - return self - - def from_json(self, json_data: Dict[str, Any]) -> Reference: - self.hash = json_data['hash'] - self.snaks = Snaks().from_json(json_data['snaks']) - self.snaks_order = json_data['snaks-order'] - - return self - - def get_json(self) -> Dict[str, Union[Dict, List]]: - json_data: Dict[str, Union[Dict, List]] = { - 'snaks': self.snaks.get_json(), - 'snaks-order': self.snaks_order - } - return json_data - - def __iter__(self): - return iter(self.snaks) - - def __len__(self): - return len(self.snaks) diff --git a/wikibaseintegrator/models/representations.py b/wikibaseintegrator/models/representations.py new file mode 100644 index 00000000..d9ccfbcf --- /dev/null +++ b/wikibaseintegrator/models/representations.py @@ -0,0 +1,5 @@ +from wikibaseintegrator.models.language_values import LanguageValues + + +class Representations(LanguageValues): + pass diff --git a/wikibaseintegrator/models/sense.py b/wikibaseintegrator/models/sense.py new file mode 100644 index 00000000..8bbd852c --- /dev/null +++ b/wikibaseintegrator/models/sense.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from typing import Any, Dict, Union + +from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.models.claims import Claims +from wikibaseintegrator.models.glosses import Glosses +from wikibaseintegrator.models.language_values import LanguageValues + + +class Sense(BaseModel): + def __init__(self, sense_id: str = None, glosses: Glosses = None, claims: Claims = None): + self.id = sense_id + self.glosses: LanguageValues = glosses or Glosses() + self.claims = claims or Claims() + self.removed = False + + def from_json(self, json_data: Dict[str, Any]) -> Sense: + self.id = json_data['id'] + self.glosses = Glosses().from_json(json_data['glosses']) + self.claims = Claims().from_json(json_data['claims']) + + return self + + def get_json(self) -> Dict[str, Union[str, Dict]]: + json_data: Dict[str, Union[str, Dict]] = { + 'id': str(self.id), + 'glosses': self.glosses.get_json(), + 'claims': self.claims.get_json() + } + + if self.id is None: + json_data['add'] = '' + del json_data['id'] + + if self.removed: + json_data['remove'] = '' + + return json_data + + def remove(self) -> Sense: + self.removed = True + return self diff --git a/wikibaseintegrator/models/senses.py b/wikibaseintegrator/models/senses.py index 5a8cbb0a..cb054e1a 100644 --- a/wikibaseintegrator/models/senses.py +++ b/wikibaseintegrator/models/senses.py @@ -1,10 +1,9 @@ from __future__ import annotations -from typing import Any, Dict, List, Optional, Union +from typing import Dict, List, Optional from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.models.claims import Claims -from wikibaseintegrator.models.language_values import LanguageValues +from wikibaseintegrator.models.sense import Sense from wikibaseintegrator.wbi_enums import ActionIfExists @@ -36,42 +35,3 @@ def get_json(self) -> List[Dict]: json_data.append(sense.get_json()) return json_data - - -class Sense(BaseModel): - def __init__(self, sense_id: str = None, glosses: Glosses = None, claims: Claims = None): - self.id = sense_id - self.glosses: LanguageValues = glosses or Glosses() - self.claims = claims or Claims() - self.removed = False - - def from_json(self, json_data: Dict[str, Any]) -> Sense: - self.id = json_data['id'] - self.glosses = Glosses().from_json(json_data['glosses']) - self.claims = Claims().from_json(json_data['claims']) - - return self - - def get_json(self) -> Dict[str, Union[str, Dict]]: - json_data: Dict[str, Union[str, Dict]] = { - 'id': str(self.id), - 'glosses': self.glosses.get_json(), - 'claims': self.claims.get_json() - } - - if self.id is None: - json_data['add'] = '' - del json_data['id'] - - if self.removed: - json_data['remove'] = '' - - return json_data - - def remove(self) -> Sense: - self.removed = True - return self - - -class Glosses(LanguageValues): - pass diff --git a/wikibaseintegrator/models/sitelink.py b/wikibaseintegrator/models/sitelink.py new file mode 100644 index 00000000..89989ed7 --- /dev/null +++ b/wikibaseintegrator/models/sitelink.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from typing import List + +from wikibaseintegrator.models.basemodel import BaseModel + + +class Sitelink(BaseModel): + def __init__(self, site: str = None, title: str = None, badges: List[str] = None): + self.site = site + self.title = title + self.badges: List[str] = badges or [] + + def __str__(self): + return self.title diff --git a/wikibaseintegrator/models/sitelinks.py b/wikibaseintegrator/models/sitelinks.py index e833c44c..66f7a876 100644 --- a/wikibaseintegrator/models/sitelinks.py +++ b/wikibaseintegrator/models/sitelinks.py @@ -3,6 +3,7 @@ from typing import Dict, List, Optional from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.models.sitelink import Sitelink class Sitelinks(BaseModel): @@ -25,13 +26,3 @@ def from_json(self, json_data: Dict[str, Dict]) -> Sitelinks: self.set(site=json_data[sitelink]['site'], title=json_data[sitelink]['title'], badges=json_data[sitelink]['badges']) return self - - -class Sitelink(BaseModel): - def __init__(self, site: str = None, title: str = None, badges: List[str] = None): - self.site = site - self.title = title - self.badges: List[str] = badges or [] - - def __str__(self): - return self.title diff --git a/wikibaseintegrator/models/snak.py b/wikibaseintegrator/models/snak.py new file mode 100644 index 00000000..59a70247 --- /dev/null +++ b/wikibaseintegrator/models/snak.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import re +from typing import Any, Dict + +from wikibaseintegrator.models.basemodel import BaseModel +from wikibaseintegrator.wbi_enums import WikibaseSnakType + + +class Snak(BaseModel): + def __init__(self, snaktype: WikibaseSnakType = WikibaseSnakType.KNOWN_VALUE, property_number: str = None, hash: str = None, datavalue: Dict = None, datatype: str = None): + self.snaktype = snaktype + self.property_number = property_number + self.hash = hash + self.datavalue = datavalue or {} + self.datatype = datatype + + @property + def snaktype(self): + return self.__snaktype + + @snaktype.setter + def snaktype(self, value: WikibaseSnakType): + """Parse the snaktype. The enum thows an error if it is not one of the recognized values""" + self.__snaktype = WikibaseSnakType(value) + + @property + def property_number(self): + return self.__property_number + + @property_number.setter + def property_number(self, value): + if isinstance(value, int): + self.__property_number = 'P' + str(value) + elif value is not None: + pattern = re.compile(r'^P?([0-9]+)$') + matches = pattern.match(value) + + if not matches: + raise ValueError('Invalid property_number, format must be "P[0-9]+"') + + self.__property_number = 'P' + str(matches.group(1)) + else: + self.__property_number = value + + @property + def hash(self): + return self.__hash + + @hash.setter + def hash(self, value): + self.__hash = value + + @property + def datavalue(self): + return self.__datavalue + + @datavalue.setter + def datavalue(self, value): + if value is not None: + self.snaktype = WikibaseSnakType.KNOWN_VALUE + self.__datavalue = value + + @property + def datatype(self): + return self.__datatype + + @datatype.setter + def datatype(self, value): + self.__datatype = value + + def from_json(self, json_data: Dict[str, Any]) -> Snak: + self.snaktype: WikibaseSnakType = WikibaseSnakType(json_data['snaktype']) + self.property_number = json_data['property'] + if 'hash' in json_data: + self.hash = json_data['hash'] + if 'datavalue' in json_data: + self.datavalue = json_data['datavalue'] + if 'datatype' in json_data: # datatype can be null with MediaInfo + self.datatype = json_data['datatype'] + return self + + def get_json(self) -> Dict[str, str]: + json_data = { + 'snaktype': self.snaktype.value, + 'property': self.property_number, + 'datatype': self.datatype, + 'datavalue': self.datavalue + } + + if self.snaktype in [WikibaseSnakType.NO_VALUE, WikibaseSnakType.UNKNOWN_VALUE]: + del json_data['datavalue'] + + # datatype can be null with MediaInfo + if not self.datatype: + del json_data['datatype'] + + return json_data + + def __eq__(self, other): + return self.snaktype == other.snaktype and self.property_number == other.property_number and self.datatype == other.datatype and self.datavalue == other.datavalue diff --git a/wikibaseintegrator/models/snaks.py b/wikibaseintegrator/models/snaks.py index eceaaef8..26eb0c2a 100644 --- a/wikibaseintegrator/models/snaks.py +++ b/wikibaseintegrator/models/snaks.py @@ -1,10 +1,9 @@ from __future__ import annotations -import re -from typing import Any, Dict, List +from typing import Dict, List from wikibaseintegrator.models.basemodel import BaseModel -from wikibaseintegrator.wbi_enums import WikibaseSnakType +from wikibaseintegrator.models.snak import Snak class Snaks(BaseModel): @@ -48,97 +47,3 @@ def __iter__(self): def __len__(self): return len(self.snaks) - - -class Snak(BaseModel): - def __init__(self, snaktype: WikibaseSnakType = WikibaseSnakType.KNOWN_VALUE, property_number: str = None, hash: str = None, datavalue: Dict = None, datatype: str = None): - self.snaktype = snaktype - self.property_number = property_number - self.hash = hash - self.datavalue = datavalue or {} - self.datatype = datatype - - @property - def snaktype(self): - return self.__snaktype - - @snaktype.setter - def snaktype(self, value: WikibaseSnakType): - """Parse the snaktype. The enum thows an error if it is not one of the recognized values""" - self.__snaktype = WikibaseSnakType(value) - - @property - def property_number(self): - return self.__property_number - - @property_number.setter - def property_number(self, value): - if isinstance(value, int): - self.__property_number = 'P' + str(value) - elif value is not None: - pattern = re.compile(r'^P?([0-9]+)$') - matches = pattern.match(value) - - if not matches: - raise ValueError('Invalid property_number, format must be "P[0-9]+"') - - self.__property_number = 'P' + str(matches.group(1)) - else: - self.__property_number = value - - @property - def hash(self): - return self.__hash - - @hash.setter - def hash(self, value): - self.__hash = value - - @property - def datavalue(self): - return self.__datavalue - - @datavalue.setter - def datavalue(self, value): - if value is not None: - self.snaktype = WikibaseSnakType.KNOWN_VALUE - self.__datavalue = value - - @property - def datatype(self): - return self.__datatype - - @datatype.setter - def datatype(self, value): - self.__datatype = value - - def from_json(self, json_data: Dict[str, Any]) -> Snak: - self.snaktype: WikibaseSnakType = WikibaseSnakType(json_data['snaktype']) - self.property_number = json_data['property'] - if 'hash' in json_data: - self.hash = json_data['hash'] - if 'datavalue' in json_data: - self.datavalue = json_data['datavalue'] - if 'datatype' in json_data: # datatype can be null with MediaInfo - self.datatype = json_data['datatype'] - return self - - def get_json(self) -> Dict[str, str]: - json_data = { - 'snaktype': self.snaktype.value, - 'property': self.property_number, - 'datatype': self.datatype, - 'datavalue': self.datavalue - } - - if self.snaktype in [WikibaseSnakType.NO_VALUE, WikibaseSnakType.UNKNOWN_VALUE]: - del json_data['datavalue'] - - # datatype can be null with MediaInfo - if not self.datatype: - del json_data['datatype'] - - return json_data - - def __eq__(self, other): - return self.snaktype == other.snaktype and self.property_number == other.property_number and self.datatype == other.datatype and self.datavalue == other.datavalue diff --git a/wikibaseintegrator/wbi_fastrun.py b/wikibaseintegrator/wbi_fastrun.py index 7ce7cc31..562672b4 100644 --- a/wikibaseintegrator/wbi_fastrun.py +++ b/wikibaseintegrator/wbi_fastrun.py @@ -9,13 +9,13 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union from wikibaseintegrator.datatypes import BaseDataType -from wikibaseintegrator.models import Claim +from wikibaseintegrator.models.claim import Claim from wikibaseintegrator.wbi_config import config from wikibaseintegrator.wbi_enums import ActionIfExists, WikibaseDatatype from wikibaseintegrator.wbi_helpers import execute_sparql_query, format_amount if TYPE_CHECKING: - from wikibaseintegrator.models import Claims + from wikibaseintegrator.models.claims import Claims log = logging.getLogger(__name__)