import argparse import logging import os import pathlib import re import typing base_path = pathlib.Path(__file__).parent.parent src_path = base_path / 'portalocker' dist_path = base_path / 'dist' _default_output_path = base_path / 'dist' / 'portalocker.py' _NAMES_RE = re.compile(r'(?P<names>[^()]+)$') _RELATIVE_IMPORT_RE = re.compile( r'^from \.(?P<from>.*?) import (?P<paren>\(?)(?P<names>[^()]+)$', ) _USELESS_ASSIGNMENT_RE = re.compile(r'^(?P<name>\w+) = \1\n$') _TEXT_TEMPLATE = """''' {} ''' """ logger = logging.getLogger(__name__) def main(argv=None): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(required=True) combine_parser = subparsers.add_parser( 'combine', help='Combine all Python files into a single unified `portalocker.py` ' 'file for easy distribution', ) combine_parser.add_argument( '--output-file', '-o', type=argparse.FileType('w'), default=str(_default_output_path), ) combine_parser.set_defaults(func=combine) args = parser.parse_args(argv) args.func(args) def _read_file(path: pathlib.Path, seen_files: typing.Set[pathlib.Path]): if path in seen_files: return names = set() seen_files.add(path) paren = False from_ = None for line in path.open(): if paren: if ')' in line: line = line.split(')', 1)[1] paren = False continue match = _NAMES_RE.match(line) else: match = _RELATIVE_IMPORT_RE.match(line) if match: if not paren: paren = bool(match.group('paren')) from_ = match.group('from') if from_: names.add(from_) yield from _read_file(src_path / f'{from_}.py', seen_files) else: for name in match.group('names').split(','): name = name.strip() names.add(name) yield from _read_file(src_path / f'{name}.py', seen_files) else: yield _clean_line(line, names) def _clean_line(line, names): # Replace `some_import.spam` with `spam` if names: joined_names = '|'.join(names) line = re.sub(fr'\b({joined_names})\.', '', line) # Replace useless assignments (e.g. `spam = spam`) return _USELESS_ASSIGNMENT_RE.sub('', line) def combine(args): output_file = args.output_file pathlib.Path(output_file.name).parent.mkdir(parents=True, exist_ok=True) output_file.write( _TEXT_TEMPLATE.format((base_path / 'README.rst').read_text()), ) output_file.write( _TEXT_TEMPLATE.format((base_path / 'LICENSE').read_text()), ) seen_files: typing.Set[pathlib.Path] = set() for line in _read_file(src_path / '__init__.py', seen_files): output_file.write(line) output_file.flush() output_file.close() logger.info(f'Wrote combined file to {output_file.name}') # Run black and ruff if available. If not then just run the file. os.system(f'black {output_file.name}') os.system(f'ruff --fix {output_file.name}') os.system(f'python3 {output_file.name}') if __name__ == '__main__': logging.basicConfig(level=logging.INFO) main()
Memory