def set_type_and_class(self, values, protoclaims): """Identify type (P31) and class (P289) and add to claims. Adds the claim to the protoclaims dict. @param values: the values extracted using the rules @type values: dict @param protoclaims: the dict of claims to add @type protoclaims: dict """ if values.get(u'navalVessel.type'): ship_class = [] ship_type = [] for val in values[u'navalVessel.type']: item = self.kulturnav2Wikidata(val) if item: q = int(item.title()[1:]) if q in self.class_list: ship_class.append(WD.Statement(item)) elif q in self.type_list: ship_type.append(WD.Statement(item)) else: pywikibot.output(u'Q%d not matched as either ship' u'type or ship class' % q) if ship_class: protoclaims[u'P289'] = ship_class if ship_type: protoclaims[u'P31'] = ship_type
def make_base_protoclaims(self, values, protoclaims): """Construct the protoclaims common for all KulturnavBots. Adds the claim to the protoclaims dict. @param values: the values extracted using the rules @type values: dict @param protoclaims: the dict of claims to add @type protoclaims: dict """ # kulturnav protoclaim incl. qualifier protoclaims[u'P%s' % self.KULTURNAV_ID_P] = \ WD.Statement(values[u'identifier']).addQualifier( WD.Qualifier( P=self.CATALOG_P, itis=self.wd.QtoItemPage(self.DATASET_Q)), force=True) # authority control protoclaims if values.get(u'libris-id'): protoclaims[u'P906'] = WD.Statement(values[u'libris-id']) if values.get(u'viaf-id'): protoclaims[u'P214'] = WD.Statement(values[u'viaf-id']) if values.get(u'getty_aat'): protoclaims[u'P1014'] = WD.Statement(values[u'getty_aat']) if values.get(u'ulan'): protoclaims[u'P245'] = WD.Statement(values[u'ulan'])
def set_ship_events(self, values, protoclaims): """Identify any events (P793) for a ship then add to claims. Adds the claim(s) to the protoclaims dict. Events are only added IFF they have an associated date. @todo: commissioned: Q14475832 @param values: the values extracted using the rules @type values: dict @param protoclaims: the dict of claims to add @type protoclaims: dict """ events = [] # built: Q474200 event = WD.Statement(self.wd.QtoItemPage('Q474200')) if self.set_date_qualifier(values, 'built', event, prop=helpers.END_P): self.set_location_qualifier(values, 'built', event) # u'built.shipyard' events.append(event) # launched: Q596643 event = WD.Statement(self.wd.QtoItemPage('Q596643')) if self.set_date_qualifier(values, 'launched', event): # u'launched.shipyard' events.append(event) # decommissioned: Q7497952 event = WD.Statement(self.wd.QtoItemPage('Q7497952')) if self.set_date_qualifier(values, 'decommissioned', event): events.append(event) # set all events if events: protoclaims[u'P793'] = events
def claims(self, values): """Add protoclaims. @param values: the values extracted using the rules @type values: dict @return: the protoclaims @rtype: dict PID-WD.Statement pairs """ # handle altNames together with names values[u'entity.name'] = KulturnavBotSMM.prep_names(values) # bundle type and otherType values[u'navalVessel.type'] = KulturnavBotSMM.prep_types(values) protoclaims = { # operator = Swedish Navy u'P137': WD.Statement(self.wd.QtoItemPage(self.SWENAVY_Q)) } # P31 - instance of # ship class unless a submarine class_Q = self.SHIPCLASS_Q if values[u'navalVessel.type'] and \ any(x.endswith(self.SUBMARINETYPE_K) for x in values[u'navalVessel.type']): class_Q = self.SUBMARINECLASS_Q protoclaims[u'P31'] = WD.Statement(self.wd.QtoItemPage(class_Q)) # P279 - subgroup self.set_subgroup(values, protoclaims) # P287 - Designer (Constructor) self.set_constructor(values, protoclaims) return protoclaims
def test_statement_inequality(self): s = WD.Statement('novalue') s_special = WD.Statement('novalue', special=True) s_force = WD.Statement('novalue') s_force.force = True self.assertNotEquals(s, s_special) self.assertNotEquals(s, s_force) self.assertNotEquals(s_force, s_special)
def test_statement_equality_qualifier_order(self): s_1 = WD.Statement('foo') s_2 = WD.Statement('foo') s_3 = WD.Statement('foo') s_1.addQualifier(self.q_1).addQualifier(self.q_2) s_2.addQualifier(self.q_2).addQualifier(self.q_1) s_3.addQualifier(self.q_1) self.assertEquals(s_1, s_2) self.assertNotEquals(s_1, s_3)
def test_statement_init_special(self): self.assertTrue(WD.Statement('somevalue', special=True).special) self.assertTrue(WD.Statement('novalue', special=True).special) with self.assertRaises(pwbError) as cm: WD.Statement('foo', special=True) self.assertEqual( str(cm.exception), 'You tried to create a special statement with a non-allowed ' 'snakvalue: foo')
def test_statement_equality(self): s = WD.Statement('foo') s_same = WD.Statement('foo') s_different = WD.Statement('bar') self.assertEquals(s, s) self.assertEquals(s, s_same) self.assertNotEquals(s, s_different) # Comparison with other classes always gives false, weird but expected self.assertFalse(s == 'foo') self.assertFalse(s != 'foo')
def get_death_place(bot, values): """Get birth place from either birthPlace or birthPlace_P7. @param bot: the instance of the bot calling upon the template @param bot: KulturnavBot @param values: the values extracted using the rules @type values: dict @return: the death place statment @rtype: WD.Statement """ if values.get(u'deathPlace'): return WD.Statement(bot.dbpedia2Wikidata(values[u'deathPlace'])) elif values.get(u'deathPlace_P7'): return WD.Statement(bot.location2Wikidata( values[u'deathPlace_P7']))
def test_statement_add_bad_reference_error(self): s = WD.Statement('foo') with self.assertRaises(pwbError) as cm: s.add_reference('foo') self.assertEqual( str(cm.exception), 'add_reference was called with something other ' 'than a Reference object: foo')
def test_statement_none_qualifier(self): s = WD.Statement('foo') s.addQualifier(None) self.assertEquals(s.quals, []) s.addQualifier(None, force=True) s.force = False
def test_statement_init(self): s = WD.Statement('foo') self.assertFalse(s.force) self.assertFalse(s.special) self.assertEquals(s.quals, []) self.assertEquals(s.itis, 'foo') self.assertEquals(s.ref, None)
def set_claim_with_start_and_end(self, prop, target_values, main_key, protoclaims): """ Add a claim with start and end date qualifiers to protoclaims. Requires the value to be resolvable using kulturnav2Wikidata. @param prop: the property of the claim @type prop: str @param target_values: the values for the claim @type target_values: dict|list (of dict)|None @param main_key: the key for the main entry of the target_values dict @type main_key: str @param protoclaims: the dict of claims to add @type protoclaims: dict """ if target_values: target_values = helpers.listify(target_values) claims = [] for val in target_values: claim = WD.Statement(self.kulturnav2Wikidata(val[main_key])) claims.append( helpers.add_start_end_qualifiers(claim, val[u'start'], val[u'end'])) if claims: protoclaims[prop] = claims
def set_creator(self, target_item, reference, creator_q=None, related_info=None): """Set a creator/P170 claim for a creator or creator combo. Allows for simple claims as well as more complex "in the manner of" etc. @param target_item: item to which claim is added @type target_item: pywikibot.ItemPage @param reference: the reference for the statment @type reference: WD.Reference @param related_info: related info as a dict with P/itis pairs @type related_info: dict @param creator_q: the Q-id of the creator @type creator_q: str """ creator_q = creator_q or ANON_Q creator_statement = WD.Statement(self.wd.QtoItemPage(creator_q)) # set any related qualifiers if related_info: creator_statement.addQualifier( WD.Qualifier(P=related_info['P'], itis=related_info['itis'])) # set claim self.wd.addNewClaim(u'P170', creator_statement, target_item, reference)
def add_inventory_and_collection_claim(self, painting_item, painting_id, painting, uri): """Add an inventory_no, with qualifier, and a collection/P195 claim. This will add the collection qualifier to any matching claim missing it. @param painting_item: item to which claim is added @type painting_item: pywikibot.ItemPage @param painting_id: the common (older) id of the painting in the Nationalmuseum collection @type painting_id: str @param painting: information object for the painting @type painting: dict @param uri: reference url on nationalmuseum.se @type uri: str """ nationalmuseum_item = self.wd.QtoItemPage(INSTITUTION_Q) collection_p = u'P195' # abort if conflicting info if self.painting_id_prop in painting_item.claims and \ not self.wd.has_claim(self.painting_id_prop, painting_id, painting_item): pywikibot.output( u'%s has conflicting inv. no (%s). Expected %s' % (painting_item, self.painting_id_prop, painting_id)) return # add inventory number with collection self.wd.addNewClaim( self.painting_id_prop, WD.Statement(painting_id).addQualifier(WD.Qualifier( P=collection_p, itis=nationalmuseum_item), force=True), painting_item, self.make_url_reference(uri)) # add collection (or subcollection) subcol = self.prefix_map[painting_id.split(' ')[0]]['subcol'] collection_item = nationalmuseum_item if subcol is not None: collection_item = self.wd.QtoItemPage(subcol) self.wd.addNewClaim(collection_p, WD.Statement(collection_item), painting_item, self.make_europeana_reference(painting))
def test_statement_add_second_reference_error(self): s = WD.Statement('foo').add_reference(self.ref) with self.assertRaises(pwbError) as cm: s.add_reference(self.ref) self.assertEqual( str(cm.exception), 'add_reference was called when the statement already had ' 'a reference assigned to it.')
def matchBirth(self, value): """Convert value of birth to statement. param value: str|unicode return: WD.Statement|None """ if value is None or not value.strip(): return None return WD.Statement(helpers.iso_to_WbTime(value))
def get_coordinate_statement(self, lat, lon, heritage_type): """Construct a Statement for the provided coordinates.""" statement = WdS.Statement( pywikibot.Coordinate(float(lat), float(lon), globe='earth', precision=DEFAULT_PREC)) statement.add_reference(self.coord_ref[heritage_type]) return statement
def matchDeath(self, value): """Extract death date from status. param value: str|unicode return: WD.Statement|None """ if value and value.startswith('Avliden'): value = value[len('Avliden'):].strip() return WD.Statement(helpers.iso_to_WbTime(value)) return None
def test_statement_qualifier(self): s = WD.Statement('foo') s.addQualifier(self.q_1) self.assertEquals(s.quals, [self.q_1]) self.assertEquals(s._quals, set([self.q_1])) self.assertEquals(s, s) s.addQualifier(self.q_2) self.assertEquals(s._quals, set([self.q_1, self.q_2])) self.assertEquals(s, s)
def matchGender(self, value): """Match value of gender against known mappings. param value: str|unicode return: WD.Statement|None """ if value in self.mappings['kon']['Q'].keys(): item = self.wd.QtoItemPage(self.mappings['kon']['Q'][value]) return WD.Statement(item) return None
def get_claims(bot, values): """Retrieve the basic claims for a person. @param bot: the instance of the bot calling upon the template @param bot: KulturnavBot @param values: the values extracted using the rules @type values: dict @return: the protoclaims @rtype: dict PID-WD.Statement pairs """ protoclaims = {} # instance of HUMAN = Q5 protoclaims[u'P31'] = WD.Statement(bot.wd.QtoItemPage(u'Q5')) if values.get(u'deathDate') and values.get(u'deathDate') != 'unknown': protoclaims[u'P570'] = WD.Statement( helpers.iso_to_WbTime(values[u'deathDate'])) protoclaims[u'P20'] = Person.get_death_place(bot, values) if values.get(u'birthDate') and values.get(u'birthDate') != 'unknown': protoclaims[u'P569'] = WD.Statement( helpers.iso_to_WbTime(values[u'birthDate'])) protoclaims[u'P19'] = Person.get_birth_place(bot, values) if values.get(u'gender'): # db_gender returns a WD.Statement protoclaims[u'P21'] = bot.db_gender(values[u'gender']) if values.get(u'firstName'): protoclaims[u'P735'] = WD.Statement( bot.db_name(values[u'firstName'], u'firstName')) if values.get(u'lastName'): protoclaims[u'P734'] = WD.Statement( bot.db_name(values[u'lastName'], u'lastName')) protoclaims[u'P27'] = Person.get_nationality(bot, values) return protoclaims
def make_protoclaims(self, data): """ Construct potential claims for an entry. :param data: dict of data for a single heritage object """ protoclaims = dict() # P17: country protoclaims['P17'] = WdS.Statement(self.country) # P1435: heritage status heritage_type = self.get_heritage_type(data.get('type')) statement = WdS.Statement(self.status[heritage_type]) if data.get('register_date'): statement.addQualifier( WdS.Qualifier('P580', self.parse_date(data.get('register_date')))) protoclaims['P1435'] = statement # P31: class protoclaims['P31'] = WdS.Statement( self.instance_type[data.get('class').lower()]) # P3008: place_id protoclaims[self.place_id_p] = WdS.Statement(data['place_id']) # P131: state protoclaims['P131'] = WdS.Statement( self.get_state(data['state'], data['address'])) # P2046: area if data.get('hectares'): protoclaims['P2046'] = WdS.Statement( pywikibot.WbQuantity(data['hectares'], unit=self.hectares, site=self.wd.repo)) # P969: address if ',' in data['address']: protoclaims['P969'] = WdS.Statement(data['address']) # P276: place protoclaims['P276'] = WdS.Statement( self.get_place(data['state'], data['address'])) # P625: coordinate if data.get('lat') and data.get('lon'): protoclaims['P625'] = self.get_coordinate_statement( data.get('lat'), data.get('lon'), heritage_type) return protoclaims
def add_depicted_claim(self, item, lido_data, ref): """Add a depicted/P180.""" prop = u'P180' if not lido_data.get('subjects'): return None for subject in lido_data.get('subjects'): nsid = subject.get(u'other_id') if nsid in self.people_items: person_item = self.wd.QtoItemPage(self.people_items[nsid]) self.wd.addNewClaim(prop, WD.Statement(person_item), item, ref)
def set_is_instance(self, qid, protoclaims): """Set instance_of (P31) to the given Q no. Adds the claim, with the suitable property, to the protoclaims dict. @param qid: the Q-no for the claim (with or without "Q") @type qid: str @param protoclaims: the dict of claims to add @type protoclaims: dict """ protoclaims[u'P31'] = WD.Statement(self.wd.QtoItemPage(qid))
def matchName(self, value, nameType): """Match value of name against its wikidata entity. param value: str|unicode param nameType: str|unicode return: WD.Statement|None """ item = helpers.match_name(value, nameType, self.wd) if item: return WD.Statement(item) return None
def add_dimension_claims(self, item, lido_data, ref): """ Add height/P2048 and width/P2049 claims. Only add non-framed measurements with just height and width. """ height_p = u'P2048' width_p = u'P2049' # diameter_p = u'P2386' # thickness_p = u'P2610' dimensions = lido_data.get('measurements').get('_') # non-framed if not dimensions or not dimensions.get('unit'): return None elif not dimensions.get('width') or not dimensions.get('height') \ or dimensions.get('depth'): # skip complicated cases for now return None elif not helpers.get_unit_q(dimensions.get('unit')): pywikibot.output(u'"%s" is an unmapped unit' % dimensions.get('unit')) return None # prepare all parts before adding claims unit = helpers.get_unit_q(dimensions.get('unit')) # unit = self.wd.QtoItemPage(unit) unit = entity_url_hack(unit) height = pywikibot.WbQuantity( dimensions.get('height'), # unit=unit, entity=unit, site=self.wd.repo) width = pywikibot.WbQuantity( dimensions.get('width'), # unit=unit, entity=unit, site=self.wd.repo) # make claims self.wd.addNewClaim(height_p, WD.Statement(height), item, ref) self.wd.addNewClaim(width_p, WD.Statement(width), item, ref)
def add_natmus_id(self, painting_item, obj_id, uri): """Add a natmus_painting_id/P2539 claim. @param painting_item: item to which claim is added @type painting_item: pywikibot.ItemPage @param obj_id: the nationalmuseum database id @type obj_id: str @param uri: reference url on nationalmuseum.se @type uri: str """ self.wd.addNewClaim(u'P2539', WD.Statement(obj_id), painting_item, self.make_url_reference(uri))
def claims(self, values): """Add protoclaims. @param values: the values extracted using the rules @type values: dict @return: the protoclaims @rtype: dict PID-WD.Statement pairs """ protoclaims = {} self.set_is_instance(self.SHIPYARD_Q, protoclaims) self.set_location(values, protoclaims) self.set_owner(values, protoclaims) # handle values if values.get(u'establishment.date'): protoclaims[u'P571'] = WD.Statement( helpers.iso_to_WbTime(values[u'establishment.date'])) if values.get(u'termination.date'): protoclaims[u'P576'] = WD.Statement( helpers.iso_to_WbTime(values[u'termination.date'])) return protoclaims
def db_gender(self, value): """Match gender values to items. Note that this returns a Statment unlike most other functions @param value: The gender value @type value: str @return: The gender item as a statement @rtype: WD.Statement or None """ known = { u'male': u'Q6581097', u'female': u'Q6581072', u'unknown': u'somevalue' } # a special case if value not in known.keys(): pywikibot.output(u'invalid gender entry: %s' % value) return if known[value] in (u'somevalue', u'novalue'): return WD.Statement(known[value], special=True) else: return WD.Statement(self.wd.QtoItemPage(known[value]))