A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

functions.py 5.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. # -*- coding: utf-8 -*-
  2. """
  3. EarwigBot's Wiki Toolset: Misc Functions
  4. This module, a component of the wiki.tools package, contains miscellaneous
  5. functions that are not methods of any class, like get_site().
  6. There's no need to import this module explicitly. All functions here are
  7. automatically available from wiki.tools.
  8. """
  9. from getpass import getpass
  10. from core import config
  11. from wiki.tools.exceptions import SiteNotFoundError
  12. from wiki.tools.site import Site
  13. __all__ = ["get_site"]
  14. def _load_config():
  15. """Called by a config-requiring function, such as get_site(), when config
  16. has not been loaded. This will usually happen only if we're running code
  17. directly from Python's interpreter and not the bot itself, because
  18. earwigbot.py or core/main.py will already call these functions.
  19. """
  20. is_encrypted = config.verify_config()
  21. if is_encrypted: # passwords in the config file are encrypted
  22. key = getpass("Enter key to unencrypt bot passwords: ")
  23. config.parse_config(key)
  24. else:
  25. config.parse_config(None)
  26. def _get_site_object_from_dict(name, d):
  27. """Return a Site object based on the contents of a dict, probably acquired
  28. through our config file, and a separate name.
  29. """
  30. try:
  31. project = d["project"]
  32. except KeyError:
  33. project = None
  34. try:
  35. lang = d["lang"]
  36. except KeyError:
  37. lang = None
  38. try:
  39. base_url = d["baseURL"]
  40. except KeyError:
  41. base_url = None
  42. try:
  43. article_path = d["articlePath"]
  44. except KeyError:
  45. article_path = None
  46. try:
  47. script_path = d["scriptPath"]
  48. except KeyError:
  49. script_path = None
  50. try:
  51. sql_server = d["sqlServer"]
  52. except KeyError:
  53. sql_server = None
  54. try:
  55. sql_db = d["sqlDB"]
  56. except KeyError:
  57. sql_db = None
  58. try:
  59. namespaces = d["namespaces"]
  60. except KeyError:
  61. namespaces = None
  62. try:
  63. login = (config.wiki["username"], config.wiki["password"])
  64. except KeyError:
  65. login = (None, None)
  66. return Site(name=name, project=project, lang=lang, base_url=base_url,
  67. article_path=article_path, script_path=script_path,
  68. sql=(sql_server, sql_db), namespaces=namespaces, login=login)
  69. def get_site(name=None, project=None, lang=None):
  70. """Returns a Site instance based on information from our config file.
  71. With no arguments, returns the default site as specified by our config
  72. file. This is default = config.wiki["defaultSite"];
  73. config.wiki["sites"][default].
  74. With `name` specified, returns the site specified by
  75. config.wiki["sites"][name].
  76. With `project` and `lang` specified, returns the site specified by the
  77. member of config.wiki["sites"], `s`, for which s["project"] == project and
  78. s["lang"] == lang.
  79. We will attempt to login to the site automatically
  80. using config.wiki["username"] and config.wiki["password"] if both are
  81. defined.
  82. Specifying a project without a lang or a lang without a project will raise
  83. TypeError. If all three args are specified, `name` will be first tried,
  84. then `project` and `lang`. If, with any number of args, a site cannot be
  85. found in the config, SiteNotFoundError is raised.
  86. """
  87. # check if config has been loaded, and load it if it hasn't
  88. if not config.is_config_loaded():
  89. _load_config()
  90. # someone specified a project without a lang (or a lang without a project)!
  91. if (project is None and lang is not None) or (project is not None and
  92. lang is None):
  93. e = "Keyword arguments 'lang' and 'project' must be specified together."
  94. raise TypeError(e)
  95. # no args given, so return our default site (project is None implies lang
  96. # is None, so we don't need to add that in)
  97. if name is None and project is None:
  98. try: # ...so use the default site
  99. default = config.wiki["defaultSite"]
  100. except KeyError:
  101. e = "Default site is not specified in config."
  102. raise SiteNotFoundError(e)
  103. try:
  104. site = config.wiki["sites"][default]
  105. except KeyError:
  106. e = "Default site specified by config is not in the config's sites list."
  107. raise SiteNotFoundError(e)
  108. return _get_site_object_from_dict(default, site)
  109. # name arg given, but don't look at others unless `name` isn't found
  110. if name is not None:
  111. try:
  112. site = config.wiki["sites"][name]
  113. except KeyError:
  114. if project is None: # implies lang is None, so only name was given
  115. e = "Site '{0}' not found in config.".format(name)
  116. raise SiteNotFoundError(e)
  117. for sitename, site in config.wiki["sites"].items():
  118. if site["project"] == project and site["lang"] == lang:
  119. return _get_site_object_from_dict(sitename, site)
  120. e = "Neither site '{0}' nor site '{1}:{2}' found in config."
  121. e.format(name, project, lang)
  122. raise SiteNotFoundError(e)
  123. else:
  124. return _get_site_object_from_dict(name, site)
  125. # if we end up here, then project and lang are both not None
  126. for sitename, site in config.wiki["sites"].items():
  127. if site["project"] == project and site["lang"] == lang:
  128. return _get_site_object_from_dict(sitename, site)
  129. e = "Site '{0}:{1}' not found in config.".format(project, lang)
  130. raise SiteNotFoundError(e)