-
Notifications
You must be signed in to change notification settings - Fork 8
/
general.py
121 lines (86 loc) · 4.55 KB
/
general.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""General constraints applicable to base types"""
from typing import Iterable
from pywikibot import Claim
import model.api
import properties.wikidata_properties as wp
from constraints.api import Constraint, Fix, ClaimFix
from utils import copy_delayed
def has_property(prop: wp.WikidataProperty) -> Constraint:
"""Constraint for 'item has a certain property'"""
def check(item: model.api.BaseType) -> bool:
return prop.pid in item.claims
return Constraint(validator=check, name=f"has_property({prop.name})")
def inherits_property(prop: wp.WikidataProperty) -> Constraint:
"""Constraint for 'item inherits property from parent item'
The definition of a "parent" depends on the item itself. For example,
the parent item of an Episode is a Season, and the episode is
expected to inherit properties such as country of origin (P495)
"""
def check(item: model.api.Heirarchical) -> bool:
# If this constraint exists on an item, we expect it to have a parent
# So not having a parent is equivalent of failing this constraint
if item.parent is None:
return False
item_claims = item.claims
parent_claims = item.parent.claims
if prop.pid not in item_claims or prop.pid not in parent_claims:
return False
item_targets = [claim.getTarget() for claim in item_claims[prop.pid]]
parent_targets = [claim.getTarget() for claim in parent_claims[prop.pid]]
item_titles = {t.title() for t in item_targets}
parent_titles = {t.title() for t in parent_targets}
return item_titles == parent_titles
def fix(item: model.api.Heirarchical) -> Iterable[Fix]:
if item.parent is None or prop.pid not in item.parent.claims:
return []
return copy_delayed(item.parent.itempage, item.itempage, [prop])
return Constraint(check, fixer=fix, name=f"inherits_property({prop.name})")
def follows_something() -> Constraint:
"""Alias for has_property(wp.FOLLOWS), but with an autofix"""
def check(item: model.api.Chainable) -> bool:
# Returning true if this property exists anywhere as a qualifier
# is very loose, and will possibly pass this check liberally.
# This is acceptable considering the alternative, which is duplicating information
# on the item in multiple places
# See https://www.wikidata.org/wiki/Wikidata:Requests_for_permissions/Bot/TheFireBenderBot
if _has_property_as_qualifier(item, wp.FOLLOWS):
return True
return wp.FOLLOWS.pid in item.claims
def fix(item: model.api.Chainable) -> Iterable[Fix]:
follows = item.previous
if follows is None:
print(f"autofix for follows_something({item.qid}) failed")
return []
new_claim = Claim(item.repo, wp.FOLLOWS.pid)
new_claim.setTarget(follows.itempage)
summary = f"Setting {wp.FOLLOWS.pid} ({wp.FOLLOWS.name})"
return [ClaimFix(new_claim, summary, item.itempage)]
return Constraint(check, fixer=fix, name=f"follows_something()")
def is_followed_by_something() -> Constraint:
"""Alias for has_property(wp.FOLLOWED_BY), but with an autofix"""
def check(item: model.api.Chainable) -> bool:
# Returning true if this property exists anywhere as a qualifier
# is very loose, and will possibly pass this check liberally.
# This is acceptable considering the alternative, which is duplicating information
# on the item in multiple places
# See https://www.wikidata.org/wiki/Wikidata:Requests_for_permissions/Bot/TheFireBenderBot
if _has_property_as_qualifier(item, wp.FOLLOWED_BY):
return True
return wp.FOLLOWED_BY.pid in item.claims
def fix(item: model.api.Chainable) -> Iterable[Fix]:
is_followed_by = item.next
if is_followed_by is None:
print(f"autofix for is_followed_by({item.qid}) failed")
return []
new_claim = Claim(item.repo, wp.FOLLOWED_BY.pid)
new_claim.setTarget(is_followed_by.itempage)
summary = f"Setting {wp.FOLLOWED_BY.pid} ({wp.FOLLOWED_BY.name})"
return [ClaimFix(new_claim, summary, item.itempage)]
return Constraint(check, fixer=fix, name=f"is_followed_by_something()")
def _has_property_as_qualifier(item, prop: wp.WikidataProperty):
for _, claims in item.claims.items():
for claim in claims:
if prop.pid in claim.qualifiers:
print(f"[DEBUG] {item} has {prop} in {claim.id}'s qualifier")
return True
return False