Source code for scripts.coordinate_import

#!/usr/bin/env python3
r"""Coordinate importing script.

Usage:

    python pwb.py coordinate_import -site:wikipedia:en \
    -cat:Category:Coordinates_not_on_Wikidata

This will work on all pages in the category "coordinates not on Wikidata"
and will import the coordinates on these pages to Wikidata.

The data from the "GeoData" extension
(https://www.mediawiki.org/wiki/Extension:GeoData)
is used so that extension has to be setup properly. You can look at the
[[Special:Nearby]] page on your local Wiki to see if it's populated.

You can use any typical pagegenerator to provide with a list of pages:

    python pwb.py coordinate_import -lang:it -family:wikipedia -namespace:0 \
    -transcludes:Infobox_stazione_ferroviaria

You can also run over a set of items on the repo without coordinates and
try to import them from any connected page. To do this, you have to
explicitly provide the repo as the site using -site argument.

Example:

    python pwb.py coordinate_import -site:wikidata:wikidata -namespace:0 \
    -querypage:Deadendpages


The following command line parameters are supported:

-always  If used, the bot won't ask if it should add the specified text.

-create  Create items for pages without one.

.. note:: This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`.
   All options can be set within a settings file which is scripts.ini by
   default.

&params;
"""
#
# (C) Pywikibot team, 2013-2024
#
# Distributed under the terms of MIT license.
#
from __future__ import annotations

import pywikibot
from pywikibot import pagegenerators
from pywikibot.bot import ConfigParserBot, WikidataBot
from pywikibot.exceptions import CoordinateGlobeUnknownError


docuReplacements = {'&params;': pagegenerators.parameterHelp}  # noqa: N816


[docs] class CoordImportRobot(ConfigParserBot, WikidataBot): """A bot to import coordinates to Wikidata. .. versionchanged:: 7.0 CoordImportRobot is a ConfigParserBot """ use_from_page = None def __init__(self, **kwargs) -> None: """Initializer.""" self.available_options['create'] = False super().__init__(**kwargs) self.cacheSources() self.prop = 'P625' self.create_missing_item = self.opt.create
[docs] def has_coord_qualifier(self, claims) -> str | None: """Check if self.prop is used as property for a qualifier. :param claims: the Wikibase claims to check in :type claims: dict :return: the first property for which self.prop is used as qualifier, or None if any """ for prop in claims: for claim in claims[prop]: if self.prop in claim.qualifiers: return prop return None
[docs] def item_has_coordinates(self, item) -> bool: """Check if the item has coordinates. :return: whether the item has coordinates """ claims = item.get().get('claims') if self.prop in claims: pywikibot.info(f'Item {item.title()} already contains coordinates ' f'({self.prop})') return True prop = self.has_coord_qualifier(claims) if prop: pywikibot.info(f'Item {item.title()} already contains coordinates ' f'({self.prop}) as qualifier for {prop}') return True return False
[docs] def treat_page_and_item(self, page, item) -> None: """Treat page/item.""" if self.item_has_coordinates(item): return if page is None: # running over items, search in linked pages for p in item.iterlinks(): if p.site.has_extension('GeoData') \ and self.try_import_coordinates_from_page(p, item): break return self.try_import_coordinates_from_page(page, item)
[docs] def try_import_coordinates_from_page(self, page, item) -> bool: """Try import coordinate from the given page to the given item. :return: whether any coordinates were found and the import was successful """ coordinate = page.coordinates(primary_only=True) if not coordinate: return False newclaim = pywikibot.Claim(self.repo, self.prop) newclaim.setTarget(coordinate) source = self.getSource(page.site) if source: newclaim.addSource(source) pywikibot.info( f'Adding {coordinate.lat}, {coordinate.lon} to {item.title()}') # TODO: handle exceptions using self.user_add_claim try: item.addClaim(newclaim) except CoordinateGlobeUnknownError as e: pywikibot.info(f'Skipping unsupported globe: {e.args}') return False return True
[docs] def main(*args: str) -> None: """Process command line arguments and invoke bot. If args is an empty list, sys.argv is used. :param args: command line argument """ # Process global args and prepare generator args parser local_args = pywikibot.handle_args(args) generator_factory = pagegenerators.GeneratorFactory() # Process pagegenerators args local_args = generator_factory.handle_args(local_args) create_new = False for arg in local_args: if arg == '-create': create_new = True # FIXME: this preloading preloads neither coordinates nor Wikibase items # but preloads wikitext which we don't need generator = generator_factory.getCombinedGenerator(preload=True) coordbot = CoordImportRobot(generator=generator, create=create_new) coordbot.run()
if __name__ == '__main__': main()