User:GeneaBot/Code/object item
< User:GeneaBot | Code
# -*- coding: utf-8 -*-
import pywikibot
from util_date import *
from util_pwb import *
from object_constraint_violation import *
from object_display import *
from object_source import *
from object_claim import *
class Item:
# Class defining a item on Wikidata
#
# Fields :
# self.ident : identifier in Wikidata (Qxxxx)
# self.item : dictionnary of labels, descriptions, statements from Wikidata
# self.claimsWanted :
# self.claims : list of claims of item
#
#
# Methods :
# self.__init__ (ident, claimsWanted, claimsRequired)
# self.__repr__ ()
# self.__str__ ()
# self.display (Format, Run)
# self.GetError ()
# self.AddClaim (pProperty, pValue, pReferences=[], pQualifiers=[])
# self.GetTargetValues (pProperty)
# self.GetTargetValuesSources (pProperty)
# self.GetQualifiersFromWD (claim)
# self.GetSourcesFromWD (claim)
# self.WriteToWD ()
#
#
# static attributes :
# Item.List : List of all items
# Item.ListOfProperty : List of properties used by Item
#
#
# static methods :
# Item.Get (Ident, claimsWanted, claimsRequired, source)
#
#
List = dict()
ListIdent = []
ListOfProperty = [
'P31', # instance of Common property
'P21', # sex or gender Human properties
'P106', # occupation
'P735', # given name
'P53', # noble family
'P569', # date of birth
'P19', # place of birth
'P570', # date of death
'P20', # place of death
'P22', # father
'P25', # mother
'P26', # spouse
'P40', # child
'P7', # brother
'P9', # sister
'P39', # function
'P97', # noble title
'P94', # blason
'P279', # subclass of Title properties
'P361', # part of
'P460', # said to be the same as
'P1001',# jurisdition Function properties
'P571' # inception
]
#
#
#
def Get(ident, claimsWanted, claimsRequired, source):
DisplayMessages.call("O", "Item." + ident + ".Get", 5, "ident=" + str(ident))
DisplayMessages.debug("O", "Item." + ident + ".Get", 2, "ident=" + ident + ", list=" + str(Item.ListIdent) + " (" + str(len(Item.ListIdent)) + ")")
if ident in Item.ListIdent:
item = Item.List[ident]
item.AddClaimsWanted(claimsWanted, source)
else:
item = Item(ident, claimsWanted, claimsRequired, source)
return item
Get = staticmethod(Get)
#
#
#
#
#
def WikidataUpdate(Update, Anchor):
DisplayMessages.call("O", "Item..WikidataUpdate", 5, "Update=" + str(Update))
DisplayLog.AppendLogTitle("List of items to modified")
Error = False
# Display names of modified items and compute Error
DisplayLog.AppendItem('{| width="100%" border=0')
NbLig = int((len(Item.ListIdent) + 2) / 3)
lig = 0
while lig < NbLig:
DisplayLog.AppendItem("|-")
col = 0
while col < 3:
index = lig + NbLig * col
if index < len(Item.ListIdent):
ident = Item.ListIdent[index]
item = Item.List[ident]
InternalLink = " ([[#" + Anchor + "_" + item.ident + "|changes]])"
if item.GetError():
DisplayLog.AppendItem("|[[File:Red x.svg|15px]]" + item.display('linkname') + InternalLink)
DisplayMessages.debug("O", "Item..WikidataUpdate", 1, "error on " + item.disp[True] )
Error = True
elif item.GetWarning():
DisplayLog.AppendItem("|[[File:Farm-Fresh error.png|15px]]" + item.display('linkname') + InternalLink)
else:
DisplayLog.AppendItem("|" + item.display('linkname') + InternalLink)
else:
DisplayLog.AppendItem("|")
col += 1
lig += 1
DisplayLog.AppendItem("|}")
#
# Display items without english and french label
ListItem = WikiData.GetItemWithoutLabel("en")
DisplayMessages.debug("O", "Item..WikidataUpdate", 1, "List of items without english label=" + str(ListItem))
if not ListItem == []:
DisplayLog.AppendLogTitle("'''List of items without english label'''")
for item in ListItem:
DisplayLog.AppendItem("{{Q|" + item + "}}\n")
ListItem = WikiData.GetItemWithoutLabel("fr")
DisplayMessages.debug("O", "Item..WikidataUpdate", 1, "List of items without french label=" + str(ListItem))
if not ListItem == []:
DisplayLog.AppendLogTitle("'''List of items without french label'''")
for item in ListItem:
DisplayLog.AppendItem("{{Q|" + item + "}}\n")
#
DisplayLog.AppendLogTitle("Detailed changes")
DisplayMessages.debug("O", "Item..WikidataUpdate", 8, "Item.ListIdent=" + str(Item.ListIdent))
DisplayLog.AppendItem('{| class=wikitable width="100%"\n')
if Error :
Run = 'simu'
elif Update :
Run = 'update'
else:
Run = 'simu'
DisplayMessages.debug("O", "Item..WikidataUpdate", 5, "Error = " + str(Error) + ", Update = " + str(Update) + ", Run = " + Run )
TpsWrite = 0
for ident in Item.ListIdent:
item = Item.List[ident]
DisplayLog.AppendItem(item.display('table', Run, '{{anchor|' + Anchor + '_' + item.ident + '}}', True))
if Update :
item.WriteToWD()
else:
TpsWrite += item.WriteCount()
DisplayLog.AppendItem("|}\n")
if not TpsWrite == 0:
minWrite = int(TpsWrite / 60)
secWrite = TpsWrite - 60 * minWrite
heuWrite = int(minWrite / 60)
minWrite = minWrite - 60 * heuWrite
DisplayMessages.message("O", "Item..WikidataUpdate", "TpsWrite=" + str(TpsWrite) + " s, " + \
str(heuWrite) + "h" + str(minWrite) + "m" + str(secWrite) + "s")
WikidataUpdate = staticmethod(WikidataUpdate)
#
#
#
#
#
# ident = Qxxxxx
# claimsWanted = dictionary of property and values for claims (specific to instance)
# claimsRequired = list of property and values for claims (specific to subclass)
def __init__(self, ident, claimsWanted, claimsRequired, source):
DisplayMessages.call("O", "Item." + ident + ".__init__", 5, "ident=" + ident + \
", claimsWanted=" + str(claimsWanted) + \
", claimsRequired=" + str(claimsRequired) + \
", source=" + repr(source) + ")" )
Item.List[ident] = self
Item.ListIdent.append(ident)
self.error = False
self.warning = False
self.ident = ident
self.item = pywikibot.ItemPage(WikiData.GetRepositery(), self.ident)
self.item.get()
self.disp = dict()
if 'en' in self.item.labels:
Text = self.item.labels['en']
List = Text.split('œ')
Text = "oe".join(List)
List = Text.split('—')
Text = "-".join(List)
self.label = Text
self.disp[True] = self.label + ' (' + self.ident + ')'
self.disp[False]= '[[' + self.ident + '|' + self.label + ' (' + self.ident + ')]]'
else:
self.label = "no english label for element '" + self.ident + "'"
self.disp[True] = '(' + self.ident + ')'
self.disp[False]= '{{Q|' + self.ident + '}}'
DisplayMessages.debug("O", "Item." + ident + ".__init__", 2, "append ident " + self.disp[True] + " to list, that is now : " + str(Item.ListIdent))
self.claimsWanted = dict()
self.listClaims = dict()
self.claims = []
for claim in claimsRequired:
prop = claim[0]
value = claim[1]
if not prop in claimsWanted:
claimsWanted[prop]= [ value ]
self.AddClaimsWanted(claimsWanted, source)
#
#
#
#
def __repr__(self):
return self.display('normal')
#
#
#
#
def __str__(self):
return self.display('long')
#
#
#
#
def display(self, Format, Run="simu", Anchor="", History=False):
if Format == 'linkname':
text = self.disp[False]
else:
Begin = {'long' :"",
'table' :'|- align=center\n! colspan=3 |',
'normal':"",
'short' :"" }
Ident = {'long' :"",
'table' :"",
'normal':" ",
'short' :" " }
Mef = {'long' :"'''",
'table' :"'''",
'normal':"'''",
'short' :"'''" }
nameItem = dict()
nameItem['long'] = self.disp[False]
nameItem['table'] = '<big>' + self.disp[False] + '</big>'
nameItem['normal']= self.disp[True]
nameItem['short'] = self.disp[True]
if History:
history = ' ([{{fullurl:' + self.ident + '|action=history}} history])'
else:
history = ''
debug = DisplayMessages.GetDebug()
DisplayMessages.SetDebug(1)
text = Anchor + Mef[Format] + nameItem[Format] + history + Mef[Format]
statement = dict()
for claim in self.claims:
prop = claim.mainClaim.property
if not prop in statement:
statement[prop] = []
textClaim = claim.display(Format, Run)
statement[prop].append(textClaim)
for prop in Item.ListOfProperty:
if prop in statement:
for txtClaim in statement[prop]:
text += "\n" + Ident[Format] + txtClaim
del statement[prop]
for prop in statement:
for txtClaim in statement[prop]:
text += "\n" + Ident[Format] + txtClaim
DisplayMessages.SetDebug(debug)
text = Begin[Format] + text
return text
#
#
#
#
def GetError(self):
return self.error
#
#
#
#
def GetWarning(self):
return self.warning
#
#
#
#
#
def AddClaimsWanted(self, claimsWanted, source):
DisplayMessages.call("O", "Item." + self.ident + ".AddClaimsWanted", 5, "item=" + self.disp[True] + ", claimsWanted=" + str(claimsWanted))
toAdd = False
for prop in claimsWanted.keys():
if not prop in self.listClaims.keys():
self.listClaims[prop] = []
for value in claimsWanted[prop]:
if not value == 'None' or self.listClaims[prop]==[]:
if not value in self.listClaims[prop]:
self.listClaims[prop].append(value)
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaimsWanted", 9, "item=" + self.disp[True] + \
", adding value " + str(value) + ", to property " + str(prop))
toAdd=True
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaimsWanted", 9, "item=" + self.disp[True] + ", self.listClaims=" + str(self.listClaims) + ", toAdd=" + str(toAdd))
#ajout des propriétés dans l'ordre défini par ListOfProperty
if toAdd:
for prop in Item.ListOfProperty:
if prop in claimsWanted.keys():
for value in claimsWanted[prop]:
self.AddClaim( prop, value, source )
#ajout des propriétés qui ne sont pas dans ListOfProperty
for prop in claimsWanted.keys():
if not prop in Item.ListOfProperty:
DisplayMessages.warning("O", "Item." + self.ident + ".AddClaimsWanted", "property " + GetIdentAndLabel(prop, "P") + " is not in Item.ListOfProperty")
for value in claimsWanted[prop]:
self.AddClaim( prop, value, source )
#
#
#
#
def AddClaim(self, pProperty, pValue, pSource, pQualifiers=[], warning=""):
DisplayMessages.call("O", "Item." + self.ident + ".AddClaim", 5, "item(" + self.disp[True] + ")" \
", pProperty=" + pProperty + \
", pValue=" + pValue + \
", pSource=" + repr(pSource) + \
", pQualifiers=" + repr(pQualifiers) + \
", warning=" + repr(warning) + ")")
toAdd = True
#if pProperty in Item.ListOptionalProperty:
# if pValue == Item.ListOptionalProperty[pProperty]:
# listValues = self.GetTargetValues(pProperty)
# if not listValues == []:
# DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 6, "claim with this property already set")
# toAdd = False
# valid = True
if toAdd:
if pProperty in self.claimsWanted:
ValueQualifier = BuildValue(pProperty, pValue, pQualifiers)
if ValueQualifier in self.claimsWanted[pProperty]:
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 6, "claim already set")
toAdd = False
valid = True
else:
self.claimsWanted[pProperty] =[]
if not pProperty in self.listClaims.keys():
self.listClaims[pProperty] = []
if toAdd:
ValueQualifier = BuildValue(pProperty, pValue, pQualifiers)
self.claimsWanted[pProperty].append( ValueQualifier )
if not pValue in self.listClaims[pProperty]:
self.listClaims[pProperty].append( pValue )
for source in pSource.list:
source.toAdd = True
ClaimTarget = dict()
if pValue in Item.List :
ItemValue = Item.List[pValue]
ClaimTarget = ItemValue.claimsWanted
ClaimToAdd = False
Check = ConstraintViolation(self.ident, pProperty, pValue, pQualifiers, self.item, self.listClaims, ClaimTarget )
violation = str(Check)
if not violation == "" and violation[:8] == "already:":
value = violation[8:]
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "claim already set, value is " + value)
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "values in local claims : " + str(self.listClaims[pProperty]))
if not value in self.listClaims[pProperty]:
qualifiers = self.GetQualifiersFromWD(self.item.claims[pProperty][0])
qualifiers = MergeQualifiers(qualifiers, pQualifiers)
sources = self.GetSourcesFromWD(self.item.claims[pProperty][0])
# Constraint violation for qualifier
newClaim = Claim("info", pProperty, value, sources, qualifiers, "", "")
ClaimToAdd = True
else:
if not violation == "":
DisplayMessages.warning("O", "Item." + self.ident + ".AddClaim", "constraint violation on item " + \
self.disp[True] + ", property " + GetIdentAndLabel(pProperty, 'P') + " : " + violation)
Target = self.GetTargetValues(pProperty)
if pValue in Target:
i = 0
claimPresent = False
while i < len(Target):
if pValue == Target[i]:
qualifiers = self.GetQualifiersFromWD(self.item.claims[pProperty][i])
qualifiers = MergeQualifiers(qualifiers, pQualifiers)
sources = self.GetSourcesFromWD(self.item.claims[pProperty][i])
listSrc = sources.GetListProperty()
listr = []
for src in listSrc:
if not src == 'P143' :
listr.append(src)
if listr==[]:
sources = sources + pSource
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "claim already set, source are " + str(listSrc) +\
", listr=" + str(listr))
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 9, "item=" + self.display("short") )
j = 0
for claim in self.claims:
if self.claims[j].Test(pProperty, pValue):
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "remove claim " + repr(self.claims[j]) )
del self.claims[j]
j += 1
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 9, "item=" + self.display("short") )
# Constraint violation for qualifier
newClaim = Claim("info", pProperty, pValue, sources, qualifiers, "", warning)
ClaimToAdd = True
claimPresent = True
i+=1
if not claimPresent:
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "normally, this instruction will not be run")
# Constraint violation for qualifier
newClaim = Claim("add", pProperty, pValue, pSource, pQualifiers, violation, warning)
ClaimToAdd = True
else:
DisplayMessages.debug("O", "Item." + self.ident + ".AddClaim", 5, "value not present for the property, add claim")
# Constraint violation for qualifier
newClaim = Claim("add", pProperty, pValue, pSource, pQualifiers, violation, warning)
ClaimToAdd = True
valid = True
if ClaimToAdd:
self.claims.append( newClaim )
if newClaim.error:
self.error=True
valid = False
if newClaim.warning:
self.warning=True
valid = True
if not violation == "":
valid = False
return valid
#
#
#
#
def GetTargetValues(self, pProperty):
DisplayMessages.call("O", "Item." + self.ident + ".GetTargetValues", 5, "item(" + self.disp[True] + ')' \
", pProperty=" + pProperty )
ListValues = []
i = 0
while 1:
try:
value = ExtractItem(self.item.claims[pProperty][i])
except KeyError: # no claim with this property
break
except IndexError: # all claims with this property have been seen
break
ListValues.append(value)
i += 1
DisplayMessages.debug("O", "Item." + self.ident + ".GetTargetValues", 6, "ListValues=" + str(ListValues) )
return ListValues
#
#
#
#
def GetTargetValuesSources(self, pProperty):
DisplayMessages.call("O", "Item." + self.ident + ".GetTargetValuesSources", 5, "item(" + self.disp[True] + ')' \
", pProperty=" + pProperty )
ListValues = []
i = 0
while 1:
try:
value = ExtractItem(self.item.claims[pProperty][i])
except KeyError: # no claim with this property
break
except IndexError: # all claims with this property have been seen
break
sources = self.GetSourcesFromWD(self.item.claims[pProperty][i])
ListValues.append([value, sources])
i += 1
DisplayMessages.debug("O", "Item." + self.ident + ".GetTargetValuesSources", 6, "ListValues=" + str(ListValues) )
return ListValues
#
#
#
#
def GetQualifiersFromWD(self, claim):
DisplayMessages.call("O", "Item." + self.ident + ".GetQualifiersFromWD", 5, "item(" + self.disp[True] + ')' \
", claim=" + str(claim.getID()) + ":" + ExtractItem(claim) )
qualifiers = []
for pQua in claim.qualifiers:
iQua = 0
while 1:
try:
vQua = ExtractItem(claim.qualifiers[pQua][iQua])
except IndexError:
break
DisplayMessages.debug("O", "Item." + self.ident + ".GetQualifiersFromWD", 6, "prop=" + str(pQua) + ", val=" + str(vQua) )
qualifiers.append( [ False, pQua, vQua, ""] )
iQua += 1
return qualifiers
#
#
#
#
def GetSourcesFromWD(self, claim):
DisplayMessages.call("O", "Item." + self.ident + ".GetSourcesFromWD", 5, "item(" + self.disp[True] + ')' \
", claim=" + str(claim.getID()) + ":" + ExtractItem(claim) )
sources = Source()
for collection in claim.sources:
for prop, val in collection.items():
for elt in val:
vRef = ExtractItem(elt)
if not vRef == "":
DisplayMessages.debug("O", "Item." + self.ident + ".GetSourcesFromWD", 6, "prop=" + str(prop) + ", val=" + str(vRef) )
sources.AddReference( prop, vRef, False )
else:
DisplayMessages.message("O", "Item." + self.ident + ".GetSourcesFromWD", "prop=" + str(prop) + ", ExtractItem returns Null value : Reference not added" )
return sources
#
#
#
#
def WriteToWD(self):
DisplayMessages.call("O", "Item." + self.ident + ".WriteToWD", 5, "item(" + self.disp[True] + ')' )
if self.error:
DisplayMessages.warning("O", "Item." + self.ident + ".WriteToWD", "error on Item, claims not written on Wikidata" )
else:
#DisplayMessages.debug("O", "Item." + self.ident + ".WriteToWD", 9, repr(self) )
for claim in self.claims:
claim.WriteToWD(self.item, self.disp[True])
#
#
#
#
def WriteCount(self):
DisplayMessages.call("O", "Item." + self.ident + ".WriteCount", 5, "item(" + self.disp[True] + ')' )
TpsWrite = 0
if not self.error:
for claim in self.claims:
TpsWrite += claim.WriteCount()
DisplayMessages.debug("O", "Item." + self.ident + ".WriteCount", 9, "TpsWrite = " + str(TpsWrite) )
return TpsWrite
def MergeQualifiers(ListQual1, ListQual2):
for qua2 in ListQual2:
pre2 = False
for qua1 in ListQual1:
if qua2[1] == qua1[1] and qua2[2] == qua1[2]:
pre2 = True
if not pre2:
ListQual1.append(qua2)
return ListQual1
# Fonction called by AddClaim
def BuildValue(pProperty, pValue, pQualifiers):
Text = pValue
if pProperty == 'P39':
ListQual = ['P580', 'P582', 'P1365', 'P1366']
elif pProperty == 'P97':
ListQual = ['P580', 'P582', 'P155', 'P156']
else:
ListQual = []
for qua1 in ListQual:
for qua2 in pQualifiers:
if qua1 == qua2[1]:
Text += ":" + qua2[2]
break;
return Text
def testItem(NumTest, Format, Run, Ident, listClaimsWanted, claimsRequired, source, write):
print( "" )
print( "---------------------------" )
text = "test " + str(NumTest) + ":\n"
text += "Item(Ident=" + Ident + \
", listClaimsWanted=" + str(listClaimsWanted) + \
", claimsRequired=" + str(claimsRequired) + \
", source=" + repr(source)
text += ")"
print( text )
print( "" )
dictClaimsWanted = dict()
for claimWanted in listClaimsWanted:
Property = claimWanted[0]
Value = claimWanted[1]
if not Property in dictClaimsWanted:
dictClaimsWanted[Property]= []
dictClaimsWanted[Property].append(Value)
DisplayMessages.debug("T", "testItem", 9, "dictClaimsWanted=" + str(dictClaimsWanted) )
localItem = Item(Ident, dictClaimsWanted, claimsRequired, source)
text = localItem.display(Format, Run)
print( localItem.display(Format, Run) )
print( "" )
if write:
localItem.WriteToWD()
def mainTestItem(*args):
param = CallParameter(*args)
NumCase = param.GetValue('case', 0)
Display = param.GetValue('display', 'short')
DisplayMessages.SetFileName("test_object_item.txt")
ListDisplay = Display.split(':')
Format = ListDisplay[0]
if len(ListDisplay) >= 2:
Run = ListDisplay[1]
else:
Run = 'simu'
humanClaimsRequired = [ [ 'P31' , 'Q5' ], [ 'P106', 'Q2478141' ], [ 'P569', 'None' ], [ 'P570', 'None' ], [ 'P19' , 'None' ], [ 'P20' , 'None' ] ]
if NumCase == 0 or NumCase == 1 :
source = Source()
testItem(1, Format, Run, 'Q729206', [['P97','Q21100112'], ['P97','Q21100106'], ['P21','Q6581097'] ], humanClaimsRequired, source, False)
if NumCase == 0 or NumCase == 2 :
source2 = Source()
source2.AddReference('P248', 'Q13419312', True)
source2.AddReference('P854', 'http://fmg.ac/Projects/MedLands/GASCONY.htm', True)
testItem(2, Format, Run, 'Q4133930', [['P31','Q5'] ], [], source2, False)
if NumCase == 0 or NumCase == 3 :
source3 = Source()
source3.AddReference('P854', 'http://genealogy.euweb.cz/lorraine/lorraine6.html', True)
testItem(3, Format, Run, 'Q131706', [['P20', 'Q1741']], [], source3, False)
if NumCase == 4:
source4 = Source()
source4.AddReference('P854', 'http://genealogy.euweb.cz/lorraine/lorraine6.html', True)
ClaimsWanted = []
ClaimsWanted.append( ['P21', 'Q6581097'] )
ClaimsWanted.append( ['P22', 'Q366025'] )
ClaimsWanted.append( ['P25', 'Q269239'] )
ClaimsWanted.append( ['P40', 'Q282712'] )
ClaimsWanted.append( ['P26', 'Q2335676'] )
ClaimsWanted.append( ['P569', '14 Aug 1536'] )
ClaimsWanted.append( ['P19', 'Q817418'] )
ClaimsWanted.append( ['P570', '14 Dec 1566'] )
ClaimsWanted.append( ['P20', 'None'] )
ClaimsWanted.append( ['P31', 'Q5'] )
ClaimsWanted.append( ['P735', 'Q2624417'] )
ClaimsWanted.append( ['P53', 'Q1336538'] )
testItem(4, Format, Run, 'Q2297325', ClaimsWanted, [], source4, True)
DisplayMessages.End()
if __name__ == "__main__":
mainTestItem()