1
0

handler.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. """EditorConfig file handler
  2. Provides ``EditorConfigHandler`` class for locating and parsing
  3. EditorConfig files relevant to a given filepath.
  4. Licensed under PSF License (see LICENSE.txt file).
  5. """
  6. import os
  7. from editorconfig import VERSION
  8. from editorconfig.ini import EditorConfigParser
  9. from editorconfig.exceptions import PathError, VersionError
  10. __all__ = ['EditorConfigHandler']
  11. def get_filenames(path, filename):
  12. """Yield full filepath for filename in each directory in and above path"""
  13. path_list = []
  14. while True:
  15. path_list.append(os.path.join(path, filename))
  16. newpath = os.path.dirname(path)
  17. if path == newpath:
  18. break
  19. path = newpath
  20. return path_list
  21. class EditorConfigHandler(object):
  22. """
  23. Allows locating and parsing of EditorConfig files for given filename
  24. In addition to the constructor a single public method is provided,
  25. ``get_configurations`` which returns the EditorConfig options for
  26. the ``filepath`` specified to the constructor.
  27. """
  28. def __init__(self, filepath, conf_filename='.editorconfig',
  29. version=VERSION):
  30. """Create EditorConfigHandler for matching given filepath"""
  31. self.filepath = filepath
  32. self.conf_filename = conf_filename
  33. self.version = version
  34. self.options = None
  35. def get_configurations(self):
  36. """
  37. Find EditorConfig files and return all options matching filepath
  38. Special exceptions that may be raised by this function include:
  39. - ``VersionError``: self.version is invalid EditorConfig version
  40. - ``PathError``: self.filepath is not a valid absolute filepath
  41. - ``ParsingError``: improperly formatted EditorConfig file found
  42. """
  43. self.check_assertions()
  44. path, filename = os.path.split(self.filepath)
  45. conf_files = get_filenames(path, self.conf_filename)
  46. # Attempt to find and parse every EditorConfig file in filetree
  47. for filename in conf_files:
  48. parser = EditorConfigParser(self.filepath)
  49. parser.read(filename)
  50. # Merge new EditorConfig file's options into current options
  51. old_options = self.options
  52. self.options = parser.options
  53. if old_options:
  54. self.options.update(old_options)
  55. # Stop parsing if parsed file has a ``root = true`` option
  56. if parser.root_file:
  57. break
  58. self.preprocess_values()
  59. return self.options
  60. def check_assertions(self):
  61. """Raise error if filepath or version have invalid values"""
  62. # Raise ``PathError`` if filepath isn't an absolute path
  63. if not os.path.isabs(self.filepath):
  64. raise PathError("Input file must be a full path name.")
  65. # Raise ``VersionError`` if version specified is greater than current
  66. if self.version is not None and self.version[:3] > VERSION[:3]:
  67. raise VersionError(
  68. "Required version is greater than the current version.")
  69. def preprocess_values(self):
  70. """Preprocess option values for consumption by plugins"""
  71. opts = self.options
  72. # Lowercase option value for certain options
  73. for name in ["end_of_line", "indent_style", "indent_size",
  74. "insert_final_newline", "trim_trailing_whitespace",
  75. "charset"]:
  76. if name in opts:
  77. opts[name] = opts[name].lower()
  78. # Set indent_size to "tab" if indent_size is unspecified and
  79. # indent_style is set to "tab".
  80. if (opts.get("indent_style") == "tab" and
  81. not "indent_size" in opts and self.version >= (0, 10, 0)):
  82. opts["indent_size"] = "tab"
  83. # Set tab_width to indent_size if indent_size is specified and
  84. # tab_width is unspecified
  85. if ("indent_size" in opts and "tab_width" not in opts and
  86. opts["indent_size"] != "tab"):
  87. opts["tab_width"] = opts["indent_size"]
  88. # Set indent_size to tab_width if indent_size is "tab"
  89. if ("indent_size" in opts and "tab_width" in opts and
  90. opts["indent_size"] == "tab"):
  91. opts["indent_size"] = opts["tab_width"]