diff options
Diffstat (limited to 'tabsvsspaces')
-rw-r--r-- | tabsvsspaces/__init__.py | 4 | ||||
-rw-r--r-- | tabsvsspaces/__main__.py | 4 | ||||
-rw-r--r-- | tabsvsspaces/_main.py | 31 | ||||
-rw-r--r-- | tabsvsspaces/pathtype.py | 63 | ||||
-rw-r--r-- | tabsvsspaces/print_stats.py | 17 | ||||
-rw-r--r-- | tabsvsspaces/stats.py | 26 |
6 files changed, 145 insertions, 0 deletions
diff --git a/tabsvsspaces/__init__.py b/tabsvsspaces/__init__.py new file mode 100644 index 0000000..483cd32 --- /dev/null +++ b/tabsvsspaces/__init__.py @@ -0,0 +1,4 @@ +from .find_stats import find_stats, find_all_files, find_stats_for_file, IGNORED_FOLDERS +from .print_stats import print_stats +from .stats import Statistics +from ._main import main
\ No newline at end of file diff --git a/tabsvsspaces/__main__.py b/tabsvsspaces/__main__.py new file mode 100644 index 0000000..c7c70d0 --- /dev/null +++ b/tabsvsspaces/__main__.py @@ -0,0 +1,4 @@ +from . import main + +if __name__ == '__main__': + main() diff --git a/tabsvsspaces/_main.py b/tabsvsspaces/_main.py new file mode 100644 index 0000000..b9f6389 --- /dev/null +++ b/tabsvsspaces/_main.py @@ -0,0 +1,31 @@ +import argparse +from pathlib import Path + +from tabsvsspaces.pathtype import PathType +from tabsvsspaces.find_stats import find_stats +from tabsvsspaces.print_stats import print_stats +from tabsvsspaces.stats import Statistics + + +def main(args=None): + parser = argparse.ArgumentParser( + prog='tabsvsspaces', + description='Shows statistics about the usage of tabs and spaces in a given folder' + ) + parser.add_argument('folder', + type=PathType(type='dir', exists=True)) + parser.add_argument('--by-extension', '-e', + dest='extension', + action='store_true', + help='show distribution by file extension' + ) + parser.add_argument('--verbose', '-v', + dest='verbose', + action='store_true', + help='show debug information') + ns = parser.parse_args(args) + folder: str = ns.folder + extension: bool = ns.extension + verbose: bool = ns.verbose + stats: Statistics = find_stats(Path(folder), verbose=verbose) + print_stats(stats, extension) diff --git a/tabsvsspaces/pathtype.py b/tabsvsspaces/pathtype.py new file mode 100644 index 0000000..39128cc --- /dev/null +++ b/tabsvsspaces/pathtype.py @@ -0,0 +1,63 @@ +# As usual: copied form stack overflow +# https://stackoverflow.com/a/33181083 + +from argparse import ArgumentTypeError as err +import os + + +class PathType(object): + def __init__(self, exists=True, type='file', dash_ok=True): + """exists: + True: a path that does exist + False: a path that does not exist, in a valid parent directory + None: don't care + type: file, dir, symlink, None, or a function returning True for valid paths + None: don't care + dash_ok: whether to allow "-" as stdin/stdout""" + + assert exists in (True, False, None) + assert type in ('file', 'dir', 'symlink', None) or hasattr(type, '__call__') + + self._exists = exists + self._type = type + self._dash_ok = dash_ok + + def __call__(self, string): + if string == '-': + # the special argument "-" means sys.std{in,out} + if self._type == 'dir': + raise err('standard input/output (-) not allowed as directory path') + elif self._type == 'symlink': + raise err('standard input/output (-) not allowed as symlink path') + elif not self._dash_ok: + raise err('standard input/output (-) not allowed') + else: + e = os.path.exists(string) + if self._exists: + if not e: + raise err("path does not exist: '%s'" % string) + + if self._type is None: + pass + elif self._type == 'file': + if not os.path.isfile(string): + raise err("path is not a file: '%s'" % string) + elif self._type == 'symlink': + if not os.path.symlink(string): + raise err("path is not a symlink: '%s'" % string) + elif self._type == 'dir': + if not os.path.isdir(string): + raise err("path is not a directory: '%s'" % string) + elif not self._type(string): + raise err("path not valid: '%s'" % string) + else: + if not self._exists and e: + raise err("path exists: '%s'" % string) + + p = os.path.dirname(os.path.normpath(string)) or '.' + if not os.path.isdir(p): + raise err("parent path is not a directory: '%s'" % p) + elif not os.path.exists(p): + raise err("parent directory does not exist: '%s'" % p) + + return string diff --git a/tabsvsspaces/print_stats.py b/tabsvsspaces/print_stats.py new file mode 100644 index 0000000..1963744 --- /dev/null +++ b/tabsvsspaces/print_stats.py @@ -0,0 +1,17 @@ +from tabsvsspaces.stats import Statistics + + +def print_stats(stats: Statistics, by_extension: bool): + print('spaces:', stats.all_spaces) + print('tabs:', stats.all_tabs) + print('mixed:', stats.all_mixed) + if by_extension: + for ext in set(stats.space_dict.keys()) | stats.tab_dict.keys() | stats.mixed_line_dict.keys(): + print(ext + ':') + print(' ', 'spaces:', stats.space_dict[ext]) + print(' ', 'tabs:', stats.tab_dict[ext]) + print(' ', 'mixed:', stats.mixed_line_dict[ext]) + if stats.all_mixed > 0: + print('files_with_mixed_lines:') + for file in stats.mixed_files: + print(' -', file) diff --git a/tabsvsspaces/stats.py b/tabsvsspaces/stats.py new file mode 100644 index 0000000..42e4461 --- /dev/null +++ b/tabsvsspaces/stats.py @@ -0,0 +1,26 @@ +from collections import defaultdict +from typing import Set + + +class Statistics: + def __init__(self): + self.space_dict = defaultdict(int) + self.tab_dict = defaultdict(int) + self.mixed_line_dict = defaultdict(int) + self.mixed_files: Set[str] = set() + self.all_tabs = 0 + self.all_spaces = 0 + self.all_mixed = 0 + + def add_spaces(self, extension='', count=1): + self.space_dict[extension] += count + self.all_spaces += count + + def add_tabs(self, extension='', count=1): + self.tab_dict[extension] += count + self.all_tabs += count + + def add_mixed_line(self, extension='', count=1, filename=''): + self.mixed_line_dict[extension] += count + self.mixed_files.add(filename) + self.all_mixed += count |