From 612a99a7a02f3dda6c4694dfdf126aee5f44d52b Mon Sep 17 00:00:00 2001 From: Dominik Holland Date: Wed, 7 Aug 2024 14:06:55 +0200 Subject: [PATCH] Fix more things related to the pathlib port Add more tests to improve coverage --- qface/app.py | 10 ++-- qface/generator.py | 8 ++-- tests/app_templates/filters.py | 0 tests/app_templates/rules.yaml | 4 ++ tests/app_templates/templates/module.txt | 1 + tests/templates/rules.yaml | 4 ++ tests/test_app.py | 59 ++++++++++++++++++++++++ tests/test_generator.py | 37 ++++++++++++++- 8 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 tests/app_templates/filters.py create mode 100644 tests/app_templates/rules.yaml create mode 100644 tests/app_templates/templates/module.txt create mode 100644 tests/templates/rules.yaml create mode 100644 tests/test_app.py diff --git a/qface/app.py b/qface/app.py index b4452d7..c74a234 100644 --- a/qface/app.py +++ b/qface/app.py @@ -10,7 +10,7 @@ from qface.utils import load_filters from qface.shell import sh -here = Path(__file__).dirname() +here = Path(__file__).parent logging.basicConfig() @@ -19,7 +19,7 @@ def run_generator(spec, src, dst, features, force): project = Path(dst).name system = FileSystem.parse(src) - extra_filters_path = spec.dirname() / 'filters.py' + extra_filters_path = spec.parent / 'filters.py' extra_filters = load_filters(extra_filters_path) ctx = { @@ -29,7 +29,7 @@ def run_generator(spec, src, dst, features, force): } generator = RuleGenerator( - search_path=spec.dirname() / 'templates', + search_path=spec.parent / 'templates', destination=dst, context=ctx, features=features, @@ -40,7 +40,7 @@ def run_generator(spec, src, dst, features, force): @click.command() -@click.option('--rules', type=click.Path(exists=True, file_okay=True)) +@click.option('--rules', type=click.Path(exists=True, file_okay=True), required=True) @click.option('--target', type=click.Path(exists=False, file_okay=False)) @click.option('--reload/--no-reload', default=False, help="Auto reload script on changes") @click.option('--scaffold/--no-scaffold', default=False, help="Add extrac scaffolding code") @@ -55,7 +55,7 @@ def main(rules, target, reload, source, watch, scaffold, feature, force, run): argv = sys.argv.copy() argv.remove('--reload') watch_list = list(source) - watch_list.append(rules.dirname()) + watch_list.append(rules.parent) if watch: watch_list.append(watch) monitor(args=argv, watch=watch_list) diff --git a/qface/generator.py b/qface/generator.py index 9763774..9b6286e 100644 --- a/qface/generator.py +++ b/qface/generator.py @@ -79,6 +79,8 @@ class Generator(object): """ enables strict code generation """ def __init__(self, search_path, context={}, force=False): + if not isinstance(search_path, (list, tuple)): + search_path = [search_path] loader = ChoiceLoader([ FileSystemLoader(search_path), PackageLoader('qface') @@ -209,7 +211,7 @@ def _has_different_content(self, data, path): if not path.exists(): return True dataHash = hashlib.new('md5', data.encode('utf-8')).digest() - pathHash = path.read_hash('md5') + pathHash = hashlib.new('md5', path.read_bytes()).digest() return dataHash != pathHash def register_filter(self, name, callback): @@ -410,10 +412,6 @@ def load_yaml(document: Path, required=False): sys.exit(-1) return {} try: - # Silence the deprecation warning in newer path.py - # but keep supporting older versions - if not hasattr(Path, 'read_text'): - document.read_text = document.text return yaml.load(document.read_text(), Loader=Loader) except yaml.YAMLError as exc: error = document diff --git a/tests/app_templates/filters.py b/tests/app_templates/filters.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/app_templates/rules.yaml b/tests/app_templates/rules.yaml new file mode 100644 index 0000000..1193959 --- /dev/null +++ b/tests/app_templates/rules.yaml @@ -0,0 +1,4 @@ +frontend: + module: + documents: + - '{{module.module_name|lower}}module.txt': 'module.txt' diff --git a/tests/app_templates/templates/module.txt b/tests/app_templates/templates/module.txt new file mode 100644 index 0000000..d2ea91c --- /dev/null +++ b/tests/app_templates/templates/module.txt @@ -0,0 +1 @@ +{{module}} \ No newline at end of file diff --git a/tests/templates/rules.yaml b/tests/templates/rules.yaml new file mode 100644 index 0000000..1193959 --- /dev/null +++ b/tests/templates/rules.yaml @@ -0,0 +1,4 @@ +frontend: + module: + documents: + - '{{module.module_name|lower}}module.txt': 'module.txt' diff --git a/tests/test_app.py b/tests/test_app.py new file mode 100644 index 0000000..e3637b8 --- /dev/null +++ b/tests/test_app.py @@ -0,0 +1,59 @@ +import logging +import logging.config +import subprocess +import os +import tempfile +from pathlib import Path + + +# logging.config.fileConfig('logging.ini') +logging.basicConfig() + +log = logging.getLogger(__name__) + +here = Path(__file__).parent + +inputPath = Path('tests/in') +log.debug('input path folder: {0}'.format(inputPath.absolute())) + +env = os.environ.copy() +env['PYTHONPATH'] = str(here.parent) + +def test_help(): + result = subprocess.run(['python3', './qface/app.py', "--help"], stdout=subprocess.PIPE, env=env) + assert result.returncode == 0 + assert """ +Usage: app.py [OPTIONS] [SOURCE]... + +Options: + --rules PATH [required] + --target DIRECTORY + --reload / --no-reload Auto reload script on changes + --scaffold / --no-scaffold Add extrac scaffolding code + --watch DIRECTORY + --feature TEXT + --run TEXT run script after generation + --force / --no-force forces overwriting of files + --help Show this message and exit. +""", result.stdout + +def test_generate(): + tmpDir = tempfile.TemporaryDirectory() + result = subprocess.run(['python3', './qface/app.py', "--rules", "tests/app_templates/rules.yaml", "--target", tmpDir.name, "--force", "tests/in/com.pelagicore.ivi.tuner.qface"], stdout=subprocess.PIPE, env=env) + assert result.returncode == 0 + assert """ +merge: com.pelagicore.ivi.tuner.yaml +process: frontend +""", result.stdout + +def test_generate_and_run(): + tmpDir = tempfile.TemporaryDirectory() + result = subprocess.run(['python3', './qface/app.py', "--rules", "tests/app_templates/rules.yaml", "--target", tmpDir.name, "--force", "tests/in/com.pelagicore.ivi.tuner.qface", "--run", "echo DONE"], stdout=subprocess.PIPE, env=env) + assert result.returncode == 0 + assert """ +merge: com.pelagicore.ivi.tuner.yaml +process: frontend +$ echo DONE +DONE +""", result.stdout + diff --git a/tests/test_generator.py b/tests/test_generator.py index 8a496b3..60a7919 100644 --- a/tests/test_generator.py +++ b/tests/test_generator.py @@ -1,4 +1,4 @@ -from qface.generator import FileSystem, Generator +from qface.generator import FileSystem, Generator, RuleGenerator from qface.utils import load_filters from unittest.mock import patch from io import StringIO @@ -79,6 +79,30 @@ def test_destination_prefix(): assert Path(path).exists() == True shutil.rmtree(out, ignore_errors=True) +def test_regeneration(): + system = FileSystem.parse(inputPath) + out = Path('tests/out') + shutil.rmtree(out, ignore_errors=True) + out.mkdir(parents=True, exist_ok=True) + generator = Generator(search_path='tests/templates') + for module in system.modules: + dst_template = '{{out}}/{{module|lower}}.txt' + ctx = {'out': out.absolute(), 'module': module} + generator.write(dst_template, 'module.txt', ctx) + generator.write(dst_template, 'module.txt', ctx) + path = generator.apply(dst_template, ctx) + assert Path(path).exists() == True + shutil.rmtree(out, ignore_errors=True) + +def test_rulegenerator(): + system = FileSystem.parse(inputPath) + out = Path('tests/out') + shutil.rmtree(out, ignore_errors=True) + out.mkdir(parents=True, exist_ok=True) + generator = RuleGenerator(search_path='tests/templates', destination=out) + generator.process_rules('tests/templates/rules.yaml', system) + shutil.rmtree(out, ignore_errors=True) + @patch('sys.stderr', new_callable=StringIO) def test_error_template_syntax_error(mock_stderr): tmpDir = tempfile.TemporaryDirectory() @@ -117,3 +141,14 @@ def test_error_template_doesnt_exist(mock_stderr): path = generator.apply(dst_template, ctx) assert Path(path).exists() == False assert mock_stderr.getvalue() == "/doesnt_exist.txt: error: Template not found\n" + +@patch('sys.stderr', new_callable=StringIO) +def test_error_yaml_doesnt_exist(mock_stderr): + tmpDir = tempfile.TemporaryDirectory() + system = FileSystem.parse(inputPath) + out = Path('tests/out') + shutil.rmtree(out, ignore_errors=True) + out.mkdir(parents=True, exist_ok=True) + generator = RuleGenerator(search_path='tests/templates', destination=out) + generator.process_rules('doesnt_exist.txt', system) + assert mock_stderr.getvalue() == "yaml document does not exists: doesnt_exist.txt\n"