dict_diff.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. @author: Pierre Thibault (pierre.thibault1 -at- gmail.com)
  5. @license: MIT
  6. @since: 2011-06-17
  7. Usage: dict_diff [OPTION]... dict1 dict2
  8. Show the differences for two dictionaries.
  9. -h, --help Display this help message.
  10. dict1 and dict2 are two web2py dictionary files to compare. These are the files
  11. located in the "languages" directory of a web2py app. The tools show the
  12. differences between the two files.
  13. '''
  14. __docformat__ = "epytext en"
  15. import getopt
  16. import os.path
  17. import sys
  18. def main(argv):
  19. """Parse the arguments and start the main process."""
  20. try:
  21. opts, args = getopt.getopt(argv, "h", ["help"])
  22. except getopt.GetoptError:
  23. exit_with_parsing_error()
  24. for opt, arg in opts:
  25. arg = arg # To avoid a warning from Pydev
  26. if opt in ("-h", "--help"):
  27. usage()
  28. sys.exit()
  29. if len(args) == 2:
  30. params = list(get_dicts(*args))
  31. params.extend(get_dict_names(*args))
  32. compare_dicts(*params)
  33. else:
  34. exit_with_parsing_error()
  35. def exit_with_parsing_error():
  36. """Report invalid arguments and usage."""
  37. print("Invalid argument(s).")
  38. usage()
  39. sys.exit(2)
  40. def usage():
  41. """Display the documentation"""
  42. print(__doc__)
  43. def get_dicts(dict_path1, dict_path2):
  44. """
  45. Parse the dictionaries.
  46. @param dict_path1: The path to the first dictionary.
  47. @param dict_path2: The path to the second dictionary.
  48. @return: The two dictionaries as a sequence.
  49. """
  50. return eval(open(dict_path1).read()), eval(open(dict_path2).read())
  51. def get_dict_names(dict1_path, dict2_path):
  52. """
  53. Get the name of the dictionaries for the end user. Use the base name of the
  54. files. If the two base names are identical, returns "dict1" and "dict2."
  55. @param dict1_path: The path to the first dictionary.
  56. @param dict2_path: The path to the second dictionary.
  57. @return: The two dictionary names as a sequence.
  58. """
  59. dict1_name = os.path.basename(dict1_path)
  60. dict2_name = os.path.basename(dict2_path)
  61. if dict1_name == dict2_name:
  62. dict1_name = "dict1"
  63. dict2_name = "dict2"
  64. return dict1_name, dict2_name
  65. def compare_dicts(dict1, dict2, dict1_name, dict2_name):
  66. """
  67. Compare the two dictionaries. Print out the result.
  68. @param dict1: The first dictionary.
  69. @param dict1: The second dictionary.
  70. @param dict1_name: The name of the first dictionary.
  71. @param dict2_name: The name of the second dictionary.
  72. """
  73. dict1_keyset = set(dict1.keys())
  74. dict2_keyset = set(dict2.keys())
  75. print_key_diff(dict1_keyset - dict2_keyset, dict1_name, dict2_name)
  76. print_key_diff(dict2_keyset - dict1_keyset, dict2_name, dict1_name)
  77. print "Value differences:"
  78. has_value_differences = False
  79. for key in dict1_keyset & dict2_keyset:
  80. if dict1[key] != dict2[key]:
  81. print " %s:" % (key,)
  82. print " %s: %s" % (dict1_name, dict1[key],)
  83. print " %s: %s" % (dict2_name, dict2[key],)
  84. print
  85. has_value_differences = True
  86. if not has_value_differences:
  87. print " None"
  88. def print_key_diff(key_diff, dict1_name, dict2_name):
  89. """
  90. Prints the keys in the first dictionary and are in the second dictionary.
  91. @param key_diff: Keys in dictionary 1 not in dictionary 2.
  92. @param dict1_name: Name used for the first dictionary.
  93. @param dict2_name: Name used for the second dictionary.
  94. """
  95. print "Keys in %s not in %s:" % (dict1_name, dict2_name)
  96. if len(key_diff):
  97. for key in key_diff:
  98. print " %s" % (key,)
  99. else:
  100. print " None"
  101. print
  102. if __name__ == "__main__":
  103. main(sys.argv[1:]) # Start the process (without the application name)