EditorConfig File Locator and Interpreter for Python
npx @tessl/cli install tessl/pypi-editorconfig@0.17.0EditorConfig File Locator and Interpreter for Python provides the same functionality as the EditorConfig C Core, serving as both a command line program and an importable library for maintaining consistent coding styles across different text editors and projects. The package implements the EditorConfig file format specification, allowing developers to define and enforce coding style rules (indentation, line endings, character encoding, etc.) through .editorconfig files that are automatically recognized by compatible text editors and development tools.
pip install EditorConfigPrimary library usage (recommended):
from editorconfig import get_properties, EditorConfigErrorAdvanced handler and exceptions (explicit imports required):
from editorconfig.handler import EditorConfigHandler
from editorconfig.exceptions import ParsingError, PathError, VersionErrorAlternatively available from main module:
from editorconfig import EditorConfigHandler, ParsingError, PathError, VersionErrorUtility functions (explicit imports required):
from editorconfig.fnmatch import fnmatch, fnmatchcase, translate
from editorconfig.versiontools import join_version, split_versionfrom editorconfig import get_properties, EditorConfigError
filename = "/home/user/project/src/main.py"
try:
options = get_properties(filename)
except EditorConfigError:
print("Error occurred while getting EditorConfig properties")
else:
for key, value in options.items():
print(f"{key}={value}")
# Example output:
# indent_style=space
# indent_size=4
# end_of_line=lf
# charset=utf-8
# trim_trailing_whitespace=true
# insert_final_newline=truePrimary function to get EditorConfig properties for any file path by locating and parsing relevant .editorconfig files in the directory hierarchy.
def get_properties(filename: str) -> OrderedDict[str, str]:
"""
Locate and parse EditorConfig files for the given filename.
Args:
filename (str): Absolute path to the file to get properties for
Returns:
OrderedDict[str, str]: Configuration properties as key-value pairs
Raises:
EditorConfigError: Base exception for EditorConfig-related errors
ParsingError: If EditorConfig file could not be parsed
PathError: If invalid filepath is specified
VersionError: If invalid version number is specified
"""Direct access to the EditorConfig handler for custom configuration filename, version compatibility, and fine-grained control over the parsing process.
class EditorConfigHandler:
"""
Allows locating and parsing of EditorConfig files for given filename.
Provides more control over the configuration resolution process than
the simple get_properties() function.
"""
def __init__(self, filepath: str, conf_filename: str = '.editorconfig',
version: VersionTuple = VERSION):
"""
Create EditorConfigHandler for matching given filepath.
Args:
filepath (str): Absolute path to target file
conf_filename (str): Configuration filename (default: '.editorconfig')
version (VersionTuple): EditorConfig version for compatibility
"""
def get_configurations(self) -> OrderedDict[str, str]:
"""
Find EditorConfig files and return all options matching filepath.
Returns:
OrderedDict[str, str]: Configuration options as key-value pairs
Raises:
VersionError: If self.version is invalid EditorConfig version
PathError: If self.filepath is not a valid absolute filepath
ParsingError: If improperly formatted EditorConfig file found
"""def get_filenames(path: str, filename: str) -> list[str]:
"""
Yield full filepath for filename in each directory in and above path.
Args:
path (str): Directory path to start search from
filename (str): Name of file to search for (usually '.editorconfig')
Returns:
list[str]: List of full file paths in directory hierarchy
"""EditorConfig-specific file pattern matching with support for shell-style patterns, glob patterns, and brace expansion used in .editorconfig file sections.
def fnmatch(name: str, pat: str) -> bool:
"""
Test whether FILENAME matches PATTERN using EditorConfig patterns.
Supports EditorConfig pattern matching including:
- * (matches everything except path separator)
- ** (matches everything including path separators)
- ? (matches any single character)
- [seq] (matches any character in seq)
- [!seq] (matches any char not in seq)
- {s1,s2,s3} (matches any of the strings given)
Args:
name (str): Filename to test
pat (str): EditorConfig pattern to match against
Returns:
bool: True if filename matches pattern
"""def fnmatchcase(name: str, pat: str) -> bool:
"""
Test whether FILENAME matches PATTERN, including case (case-sensitive).
Args:
name (str): Filename to test
pat (str): EditorConfig pattern to match against
Returns:
bool: True if filename matches pattern (case-sensitive)
"""def translate(pat: str, nested: bool = False) -> tuple[str, list[tuple[int, int]]]:
"""
Translate an EditorConfig shell PATTERN to a regular expression.
Args:
pat (str): EditorConfig pattern to translate
nested (bool): Whether this is a nested translation
Returns:
tuple[str, list[tuple[int, int]]]: Regex string and numeric groups
"""Tools for handling and comparing EditorConfig version numbers, ensuring compatibility across different EditorConfig implementations.
def join_version(version_tuple: VersionTuple) -> str:
"""
Return a string representation of version from given VERSION tuple.
Args:
version_tuple (VersionTuple): VERSION tuple to convert
Returns:
str: String version representation (e.g., "0.17.1")
"""def split_version(version: str) -> Optional[VersionTuple]:
"""
Return VERSION tuple for given string representation of version.
Args:
version (str): String version to parse
Returns:
Optional[VersionTuple]: VersionTuple or None if invalid
"""Complete command-line tool for direct EditorConfig file processing with support for custom configuration files and version compatibility testing.
def main() -> None:
"""
Main entry point for command line interface.
Usage: editorconfig [OPTIONS] FILENAME
Options:
-f: Specify conf filename other than ".editorconfig"
-b: Specify version (used by devs to test compatibility)
-h, --help: Print help message
-v, --version: Display version information
"""def version() -> None:
"""Print version information to stdout."""def usage(command: str, error: bool = False) -> None:
"""
Print usage information.
Args:
command (str): Command name to display in usage
error (bool): Whether this is error usage (prints to stderr)
"""Specialized INI parser with EditorConfig-specific features for handling configuration file syntax, section matching, and property resolution.
class EditorConfigParser:
"""
Parser for EditorConfig-style configuration files.
Based on RawConfigParser with EditorConfig-specific modifications:
- Special characters can be used in section names
- Octothorpe can be used for comments (not just at beginning of line)
- Only tracks INI options in sections that match target filename
- Stops parsing when root=true is found
"""
def __init__(self, filename: str):
"""
Initialize parser for specific target filename.
Args:
filename (str): Target filename for section matching
"""
def matches_filename(self, config_filename: str, glob: str) -> bool:
"""
Return True if section glob matches target filename.
Args:
config_filename (str): Path to the config file
glob (str): Glob pattern from config file section
Returns:
bool: True if pattern matches target filename
"""
def read(self, filename: str) -> None:
"""
Read and parse single EditorConfig file.
Args:
filename (str): Path to EditorConfig file to parse
"""
def optionxform(self, optionstr: str) -> str:
"""
Transform option names to lowercase.
Args:
optionstr (str): Option name to transform
Returns:
str: Lowercase option name
"""EditorConfig provides a comprehensive exception hierarchy for different error conditions that may occur during configuration file processing.
class EditorConfigError(Exception):
"""Parent class of all exceptions raised by EditorConfig."""from configparser import ParsingError as _ParsingError
class ParsingError(_ParsingError, EditorConfigError):
"""Error raised if an EditorConfig file could not be parsed."""class PathError(ValueError, EditorConfigError):
"""Error raised if invalid filepath is specified."""class VersionError(ValueError, EditorConfigError):
"""Error raised if invalid version number is specified."""from collections import OrderedDict
from typing import Optional
VersionTuple = tuple[int, int, int, str]VERSION = (0, 17, 1, "final") # Current package version tuple
__version__ = "0.17.1" # Package version stringfrom editorconfig import get_properties
# Get properties for a Python file
filename = "/home/user/project/src/main.py"
properties = get_properties(filename)
# Properties might include:
# {'indent_style': 'space', 'indent_size': '4', 'end_of_line': 'lf'}from editorconfig.handler import EditorConfigHandler
# Create handler with custom config filename
handler = EditorConfigHandler(
filepath="/home/user/project/src/main.py",
conf_filename=".my-editorconfig"
)
# Get configurations
options = handler.get_configurations()
for key, value in options.items():
print(f"{key}={value}")from editorconfig.fnmatch import fnmatch
# Test if filename matches EditorConfig pattern
matches = fnmatch("src/main.py", "*.py") # True
matches = fnmatch("src/test.js", "*.py") # False
matches = fnmatch("src/components/Button.tsx", "**/*.{ts,tsx}") # Truefrom editorconfig import get_properties
from editorconfig.exceptions import ParsingError, PathError, VersionError
try:
properties = get_properties("/path/to/file.py")
except ParsingError as e:
print(f"Configuration file parsing error: {e}")
except PathError as e:
print(f"Invalid file path: {e}")
except VersionError as e:
print(f"Version compatibility error: {e}")# Get properties for a file
editorconfig /path/to/file.py
# Use custom config filename
editorconfig -f .my-editorconfig /path/to/file.py
# Test compatibility with specific version
editorconfig -b 0.15.0 /path/to/file.py
# Show help
editorconfig --help
# Show version
editorconfig --version