Replace qualifiers

This notebook helps you to replace the property of qualifiers of some statements. For example, you can use the following code to replace the professional or sports partner qualifier on all ISU figure skater ID statements with a identifier shared with qualifier (same value):

from paws.TweetsFactsAndQueries.replaceQualifiers import *

query='''
SELECT DISTINCT ?item WHERE {
  ?item p:P2694/pq:P1327 ?partner.
}
'''

replaceQualifiers(query, 'P2694', 'P1327', 'P4070')

To run this code, open https://paws.wmflabs.org, log in with your MediaWiki account (the edits will be made with that account as well), create a new Python 3 notebook, paste the above code into the first cell and press Ctrl+Enter to run it. If anything goes wrong (e. g. if something in your contributions doesn’t look right), you can press the “stop” button in the toolbar (“⏹️”, tooltip “interrupt the kernel”) to immediately stop the program.

By default, if a statement has multiple qualifiers with the property ID to be replaced, they are all replaced. You can disable this with the allowMultipleQualifiers parameter:

replaceQualifiers(query, 'P2694', 'P1327', 'P4070', allowMultipleQualifiers=False)

The rest of this notebook describes the implementation.

General boilerplate (source).

import pywikibot as pwb
from pywikibot import pagegenerators as pg
site = pwb.Site("wikidata", "wikidata") # or pwb.Site("test", "wikidata") for test.wikidata.org
repo = site.data_repository()

Needed for custom edit groups support in replaceQualifiers.

import random

def newEditGroup():
    return "{:x}".format(random.randrange(0, 2**48))

Needed to print warnings to standard error in replaceQualifiers.

from sys import stderr

A simple function to format an edit summary for replacing qualifiers. Used by two functions below.

def replaceQualifierSummary(
    statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    extraSummary=None
):
    params = statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId
    summary = '[[Property:%s]] statement: replace [[Property:%s]] qualifier with [[Property:%s]]' % params
    if extraSummary is not None:
        summary = '%s (%s)' % (summary, extraSummary)
    return summary

A function to replace the qualifiers on statements of a single item.

Multiple statements are always allowed, and processed one-by-one; multiple qualifiers are allowed by default, but may be disabled with the allowMultipleQualifiers parameter, in which case a ValueError is raised if a statement has more than one qualifier to be replaced.

Note that each qualifier replacement uses two edits: first the new qualifier is added, then the old one is removed. Perhaps this can be improved in the future, but for now it’s the simplest option.

def replaceQualifier(
    itemId, statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    summary=None,
    allowMultipleQualifiers=True,
):
    if summary is None:
        summary = replaceQualifierSummary(statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId)
    item = pwb.ItemPage(repo, itemId)
    item_data = item.get()
    for statement in item_data['claims'].get(statementPropertyId, []):
        qualifiers = statement.qualifiers.get(oldQualifierPropertyId, [])
        if not allowMultipleQualifiers and len(qualifiers) > 1:
            params = statement.snak, itemId, len(qualifiers), oldQualifierPropertyId
            raise ValueError('Statement %s of [[%s]] has %d [[Property:%s]] qualifiers' % params)
        for oldQualifier in qualifiers.copy(): # original list is modified by statement.removeQualier()
            newQualifier = pwb.Claim(repo, newQualifierPropertyId)
            newQualifier.setTarget(oldQualifier.getTarget())
            statement.addQualifier(newQualifier, summary=summary)
            statement.removeQualifier(oldQualifier, summary=summary)

A function to replace the qualifiers on statements of a set of items, selected by a SPARQL query.

Multiple qualifiers are allowed by default, but may be disabled with the allowMultipleParameters parameter. If multiple qualifiers are encountered on an item, processing of that item will be aborted (including potential other statements of that item), a message will be logged to standard error, and then processing of the remaining items will continue.

If the summary is not specified, a default summary with a fresh custom edit group is used. To place multiple uses of this method in the same edit group, explicitly specify the summary, like this:

editGroup = newEditGroup()
summary = replaceQualifierSummary(
    statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    extraSummary=('[[:toollabs:editgroups/b/CB/%s|details]]' % editGroup),
)
replaceQualifiers(
    query1, statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    summary=summary,
)
replaceQualifiers(
    query2, statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    summary=summary,
)
def replaceQualifiers(
    query, statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
    summary=None,
    allowMultipleQualifiers=True,
):
    if summary is None:
        editGroup = newEditGroup()
        summary = replaceQualifierSummary(
            statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
            extraSummary=('[[:toollabs:editgroups/b/CB/%s|details]]' % editGroup),
        )
    for item in pg.WikidataSPARQLPageGenerator(query, site):
        try:
            replaceQualifier(
                item.id, statementPropertyId, oldQualifierPropertyId, newQualifierPropertyId,
                summary=summary,
                allowMultipleQualifiers=allowMultipleQualifiers
            )
        except ValueError as e:
            if not allowMultipleQualifiers:
                print(e.args[0], file=stderr)
                continue
            else:
                raise e