#input vars
main_property = 'P1685'
qualifier_property = 'P642'
new_qualifier_property = 'P972'
allowed_qualifier_targets = {} #leave empty for everything to be processed; change to format {'Q1234', 'Q5678'} if you want to limit the targets to be operated on

limit = 1000

logFileName = 'migrator1log.txt'

edit_summary = qualifier_property + ' is no longer used with ' + main_property + '; migrating' + main_property + '/' + qualifier_property + ' to ' + '/' + new_qualifier_property
no_promptbox = 1 #set to 1 to operate on entire query automatically, 0 to prompt once per item

# query_filename = 'qualifier_migrate.rq'
QUERY = """SELECT DISTINCT ?item ?itemLabel ?property ?propertyLabel ?value ?asObject ?asObjectLabel
WHERE
{
  wd:""" + main_property + """ wikibase:claim ?p .
  ?prop pq:""" + qualifier_property + """ ?asObject .
  hint:Query hint:optimizer "None" .	
  ?item ?p ?prop . 
  ?property wikibase:claim ?p .  
  ?property wikibase:statementProperty ?ps .
  ?prop ?ps ?value .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en,bg"  }    
}
ORDER BY ASC(?value) 
LIMIT """ + str(limit)

#start of actual script
import pywikibot
from pywikibot import pagegenerators as pg

import datetime

site = pywikibot.Site("wikidata", "wikidata")
wikidata_site = site #compatibility stuff
repo = site.data_repository()    

def getLabelFromObject(WDObject):
    item_dict = WDObject.get()
    item_label = False
    if 'labels' in item_dict:
        if 'en' in item_dict['labels']:
            item_label = item_dict['labels']['en']
    label = item_label
    if (label):
        return label
    else:
        return WDObject.getID()

def getLabelFromWDID(ID): #works for properties only. need separate function for items. why why why
    site = pywikibot.Site("wikidata", "wikidata")
    repo = site.data_repository()
    item = pywikibot.PropertyPage(repo, ID)
    return getLabelFromObject(item)

main_property_label = getLabelFromWDID(main_property)
qualifier_property_label = getLabelFromWDID(qualifier_property)
new_qualifier_property_label = getLabelFromWDID(new_qualifier_property)

#replaced by including SPARQL inside this program
#with open(query_filename, 'r') as query_file:
#    QUERY = query_file.read()

generator = pg.WikidataSPARQLPageGenerator(QUERY, site=wikidata_site)
generator = site.preloadpages(generator, pageprops=True)

break_flag = 0
edit_count = 0

f = open(logFileName, 'a')
print(datetime.datetime.now(), file=f)

for item in generator:
    #operate on the most recent one for testing
    item_dict = item.get()
    item_label = getLabelFromObject(item)
            
    print('Now working on ', item.getID(), ' ', item_label)#, 'Ready? ("yes" to go, "break" to stop)')
    print(item.getID(), file=f)

    for claim_object in item_dict['claims'][main_property]:
        claim_target = claim_object.getTarget()
        claim_target_label = getLabelFromObject(claim_target) if type(claim_target) ==pywikibot.page.ItemPage else '[none]'
        
        if qualifier_property in claim_object.qualifiers:
            for qualifier_object in claim_object.qualifiers[qualifier_property]:
                qualifier_target = qualifier_object.getTarget()
                if (len(allowed_qualifier_targets) > 0 and 
                    qualifier_target.getID() not in allowed_qualifier_targets):
                    continue
                    
                qualifier_target_label = getLabelFromObject(qualifier_target) if type(qualifier_target) == pywikibot.page.ItemPage else '[none]'
                    
                print(item_label, main_property_label, claim_target_label, 
                      qualifier_property_label, qualifier_target_label, 
                      'change to', new_qualifier_property_label, '!')

                acceptable_prompt_set = {'y', 'yes', 'n', 'no', 'break'}
                promptbox = ''
                if (no_promptbox == 1):
                    promptbox = 'yes'
                while (promptbox not in acceptable_prompt_set):
                    promptbox = input()  #becomes automatic if set to 'y'

                if promptbox == 'y' or promptbox == 'yes':
                    qualifier_dict = qualifier_object.toJSON()
                    qualifier_dict['property'] =  new_qualifier_property #set up the qualifier change
                    print('Changing to', new_qualifier_property_label)
                    new_qualifier_object = qualifier_object.qualifierFromJSON(site = wikidata_site, data = qualifier_dict)
                    claim_object.addQualifier(new_qualifier_object, summary=edit_summary)
                    edit_count = edit_count + 1

                elif promptbox == 'n' or promptbox == 'no':
                    print('Skipped')
                    
                elif promptbox == 'break':
                    break_flag = 1
                    break

        if break_flag == 1:
            break
    if break_flag == 1:
        break

print('All done, thanks for using! We edited', edit_count, 'qualifiers.')
f.close()
Retrieving 3 pages from wikidata:wikidata.
Now working on  Q1062055   Forretress
Forretress Pokédex / Pokémon browser number [none] of Almia Pokémon Browser change to catalog !
Changing to catalog
Forretress Pokédex / Pokémon browser number [none] of Oblivia Pokémon Browser change to catalog !
Changing to catalog
Forretress Pokédex / Pokémon browser number [none] of Oblivia past Pokémon browser change to catalog !
Changing to catalog
Now working on  Q1062028   Ariados
Ariados Pokédex / Pokémon browser number [none] of Fiore Pokémon browser change to catalog !
Changing to catalog
Ariados Pokédex / Pokémon browser number [none] of Almia Pokémon Browser change to catalog !
Changing to catalog
Ariados Pokédex / Pokémon browser number [none] of Oblivia Pokémon Browser change to catalog !
Changing to catalog
Now working on  Q1069898   Pelipper
Pelipper Pokédex / Pokémon browser number [none] of Fiore Pokémon browser change to catalog !
Changing to catalog
Pelipper Pokédex / Pokémon browser number [none] of Almia Pokémon Browser change to catalog !
Changing to catalog
Pelipper Pokédex / Pokémon browser number [none] of Oblivia Pokémon Browser change to catalog !
Changing to catalog
Pelipper Pokédex / Pokémon browser number [none] of Oblivia past Pokémon browser change to catalog !
Changing to catalog
All done, thanks for using! We edited 10 qualifiers.
print(QUERY)
SELECT DISTINCT ?item ?itemLabel ?property ?propertyLabel ?value ?asObject ?asObjectLabel
WHERE
{
  wd:P1685 wikibase:claim ?p .
  ?prop pq:P642 ?asObject .
  hint:Query hint:optimizer "None" .	
  ?item ?p ?prop . 
  ?property wikibase:claim ?p .  
  ?property wikibase:statementProperty ?ps .
  ?prop ?ps ?value .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en,bg"  }    
}
ORDER BY ASC(?value) 
LIMIT 1000