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.

107 lines
4.1 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22. """
  23. Based on:
  24. * https://gist.github.com/844388
  25. * http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py
  26. with modifications.
  27. """
  28. from collections import OrderedDict
  29. import yaml
  30. __all__ = ["OrderedLoader", "OrderedDumper"]
  31. class OrderedLoader(yaml.Loader):
  32. """A YAML loader that loads mappings into ordered dictionaries."""
  33. def __init__(self, *args, **kwargs):
  34. super(OrderedLoader, self).__init__(*args, **kwargs)
  35. constructor = type(self).construct_yaml_map
  36. self.add_constructor(u"tag:yaml.org,2002:map", constructor)
  37. self.add_constructor(u"tag:yaml.org,2002:omap", constructor)
  38. def construct_yaml_map(self, node):
  39. data = OrderedDict()
  40. yield data
  41. value = self.construct_mapping(node)
  42. data.update(value)
  43. def construct_mapping(self, node, deep=False):
  44. if isinstance(node, yaml.MappingNode):
  45. self.flatten_mapping(node)
  46. else:
  47. raise yaml.constructor.ConstructorError(None, None,
  48. "expected a mapping node, but found {0}".format(node.id),
  49. node.start_mark)
  50. mapping = OrderedDict()
  51. for key_node, value_node in node.value:
  52. key = self.construct_object(key_node, deep=deep)
  53. try:
  54. hash(key)
  55. except TypeError, exc:
  56. raise yaml.constructor.ConstructorError(
  57. "while constructing a mapping", node.start_mark,
  58. "found unacceptable key ({0})".format(exc),
  59. key_node.start_mark)
  60. value = self.construct_object(value_node, deep=deep)
  61. mapping[key] = value
  62. return mapping
  63. class OrderedDumper(yaml.SafeDumper):
  64. """A YAML dumper that dumps ordered dictionaries into mappings."""
  65. def __init__(self, *args, **kwargs):
  66. super(OrderedDumper, self).__init__(*args, **kwargs)
  67. self.add_representer(OrderedDict, type(self).represent_dict)
  68. def represent_mapping(self, tag, mapping, flow_style=None):
  69. value = []
  70. node = yaml.MappingNode(tag, value, flow_style=flow_style)
  71. if self.alias_key is not None:
  72. self.represented_objects[self.alias_key] = node
  73. best_style = True
  74. if hasattr(mapping, "items"):
  75. mapping = list(mapping.items())
  76. for item_key, item_value in mapping:
  77. node_key = self.represent_data(item_key)
  78. node_value = self.represent_data(item_value)
  79. if not (isinstance(node_key, yaml.ScalarNode) and not
  80. node_key.style):
  81. best_style = False
  82. if not (isinstance(node_value, yaml.ScalarNode) and not
  83. node_value.style):
  84. best_style = False
  85. value.append((node_key, node_value))
  86. if flow_style is None:
  87. if self.default_flow_style is not None:
  88. node.flow_style = self.default_flow_style
  89. else:
  90. node.flow_style = best_style
  91. return node