| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- """EditorConfig file handler
- Provides ``EditorConfigHandler`` class for locating and parsing
- EditorConfig files relevant to a given filepath.
- Licensed under PSF License (see LICENSE.txt file).
- """
- import os
- from editorconfig import VERSION
- from editorconfig.ini import EditorConfigParser
- from editorconfig.exceptions import PathError, VersionError
- __all__ = ['EditorConfigHandler']
- def get_filenames(path, filename):
- """Yield full filepath for filename in each directory in and above path"""
- path_list = []
- while True:
- path_list.append(os.path.join(path, filename))
- newpath = os.path.dirname(path)
- if path == newpath:
- break
- path = newpath
- return path_list
- class EditorConfigHandler(object):
- """
- Allows locating and parsing of EditorConfig files for given filename
- In addition to the constructor a single public method is provided,
- ``get_configurations`` which returns the EditorConfig options for
- the ``filepath`` specified to the constructor.
- """
- def __init__(self, filepath, conf_filename='.editorconfig',
- version=VERSION):
- """Create EditorConfigHandler for matching given filepath"""
- self.filepath = filepath
- self.conf_filename = conf_filename
- self.version = version
- self.options = None
- def get_configurations(self):
- """
- Find EditorConfig files and return all options matching filepath
- Special exceptions that may be raised by this function include:
- - ``VersionError``: self.version is invalid EditorConfig version
- - ``PathError``: self.filepath is not a valid absolute filepath
- - ``ParsingError``: improperly formatted EditorConfig file found
- """
- self.check_assertions()
- path, filename = os.path.split(self.filepath)
- conf_files = get_filenames(path, self.conf_filename)
- # Attempt to find and parse every EditorConfig file in filetree
- for filename in conf_files:
- parser = EditorConfigParser(self.filepath)
- parser.read(filename)
- # Merge new EditorConfig file's options into current options
- old_options = self.options
- self.options = parser.options
- if old_options:
- self.options.update(old_options)
- # Stop parsing if parsed file has a ``root = true`` option
- if parser.root_file:
- break
- self.preprocess_values()
- return self.options
- def check_assertions(self):
- """Raise error if filepath or version have invalid values"""
- # Raise ``PathError`` if filepath isn't an absolute path
- if not os.path.isabs(self.filepath):
- raise PathError("Input file must be a full path name.")
- # Raise ``VersionError`` if version specified is greater than current
- if self.version is not None and self.version[:3] > VERSION[:3]:
- raise VersionError(
- "Required version is greater than the current version.")
- def preprocess_values(self):
- """Preprocess option values for consumption by plugins"""
- opts = self.options
- # Lowercase option value for certain options
- for name in ["end_of_line", "indent_style", "indent_size",
- "insert_final_newline", "trim_trailing_whitespace",
- "charset"]:
- if name in opts:
- opts[name] = opts[name].lower()
- # Set indent_size to "tab" if indent_size is unspecified and
- # indent_style is set to "tab".
- if (opts.get("indent_style") == "tab" and
- not "indent_size" in opts and self.version >= (0, 10, 0)):
- opts["indent_size"] = "tab"
- # Set tab_width to indent_size if indent_size is specified and
- # tab_width is unspecified
- if ("indent_size" in opts and "tab_width" not in opts and
- opts["indent_size"] != "tab"):
- opts["tab_width"] = opts["indent_size"]
- # Set indent_size to tab_width if indent_size is "tab"
- if ("indent_size" in opts and "tab_width" in opts and
- opts["indent_size"] == "tab"):
- opts["indent_size"] = opts["tab_width"]
|