diff --git a/pytest.ini b/pytest.ini index 5d05ec3d7d2227a533d336ab67e403e5b208b8a8..7dc0d3812dee41d0511ea766ec4e8b032760bf60 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,6 +3,10 @@ testpaths = src/pystencilssfg tests/ python_files = "test_*.py" # Need to ignore the generator scripts, otherwise they would be executed # during test collection -addopts = --doctest-modules --ignore=tests/generator_scripts/scripts --ignore=--ignore=tests/data +addopts = + --doctest-modules + --ignore=tests/generator_scripts/scripts + --ignore=tests/generator_scripts/config + --ignore=tests/data doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL diff --git a/src/pystencilssfg/generator.py b/src/pystencilssfg/generator.py index d145abde44be9b84bdfa233f11340483515537fb..cc9cd6252604cd9bedb42a995c7c242a61e117d4 100644 --- a/src/pystencilssfg/generator.py +++ b/src/pystencilssfg/generator.py @@ -5,6 +5,7 @@ from .config import SfgConfig, CommandLineParameters, OutputMode, GLOBAL_NAMESPA from .context import SfgContext from .composer import SfgComposer from .emission import AbstractEmitter, OutputSpec +from .exceptions import SfgException class SourceFileGenerator: @@ -33,6 +34,13 @@ class SourceFileGenerator: import __main__ + if not hasattr(__main__, "__file__"): + raise SfgException( + "Invalid execution environment: " + "It seems that you are trying to run the `SourceFileGenerator` in an environment " + "without a valid entry point, such as a REPL or a multiprocessing fork." + ) + scriptpath = __main__.__file__ scriptname = path.split(scriptpath)[1] basename = path.splitext(scriptname)[0] diff --git a/tests/generator/test_config.py b/tests/generator/test_config.py index 8942f6a5d3d6a1de77b497f145412b86c8e23494..b22e4e5681b58febdf1a983a66675f321f006625 100644 --- a/tests/generator/test_config.py +++ b/tests/generator/test_config.py @@ -89,32 +89,3 @@ def test_from_commandline(sample_config_module): assert cli_args.configuration_module is not None assert cli_args.configuration_module.magic_string == "Spam and eggs" assert cli_args.configuration_module.magic_number == 0xCAFE - - -def test_generator_config(monkeypatch, tmp_path, sample_config_module): - import sys - - args = [ - "genscript.py", - "--sfg-file-extensions", - ".c++,.h++", - "--sfg-config-module", - sample_config_module, - "test1", - "test2", - ] - monkeypatch.setattr(sys, "argv", args) - - cfg = SfgConfig(output_directory=str(tmp_path.absolute())) - - with SourceFileGenerator(cfg) as sfg: - ctx = sfg.context - - assert ctx.outer_namespace == "myproject" - assert ctx.argv == ["test1", "test2"] - assert isinstance(ctx.project_info, dict) - assert ctx.project_info == { - "use_openmp": True, - "use_cuda": True, - "float_format": "float32", - } diff --git a/tests/generator_scripts/config/TestConfigModule_cfg.py b/tests/generator_scripts/config/TestConfigModule_cfg.py new file mode 100644 index 0000000000000000000000000000000000000000..e118b43e3a10ff131d63accb748400b8298af85b --- /dev/null +++ b/tests/generator_scripts/config/TestConfigModule_cfg.py @@ -0,0 +1,14 @@ +from pystencilssfg import SfgConfig + + +def configure_sfg(cfg: SfgConfig): + cfg.outer_namespace = "myproject" + cfg.codestyle.indent_width = 3 + + +def project_info(): + return { + "use_openmp": True, + "use_cuda": True, + "float_format": "float32", + } diff --git a/tests/generator_scripts/scripts/TestConfigModule.py b/tests/generator_scripts/scripts/TestConfigModule.py new file mode 100644 index 0000000000000000000000000000000000000000..35b41923ac7a2defd5dc5b459939e046f48f1ce4 --- /dev/null +++ b/tests/generator_scripts/scripts/TestConfigModule.py @@ -0,0 +1,15 @@ +from pystencilssfg import SourceFileGenerator + +with SourceFileGenerator() as sfg: + ctx = sfg.context + + assert ctx.outer_namespace == "myproject" + assert ctx.codestyle.indent_width == 3 + + assert not ctx.argv + assert isinstance(ctx.project_info, dict) + assert ctx.project_info == { + "use_openmp": True, + "use_cuda": True, + "float_format": "float32", + } diff --git a/tests/generator_scripts/scripts/TestExtraCommandLineArgs.py b/tests/generator_scripts/scripts/TestExtraCommandLineArgs.py new file mode 100644 index 0000000000000000000000000000000000000000..2cf989321a160c714ee6ecb972061359d40d1439 --- /dev/null +++ b/tests/generator_scripts/scripts/TestExtraCommandLineArgs.py @@ -0,0 +1,6 @@ +from pystencilssfg import SourceFileGenerator + +with SourceFileGenerator(keep_unknown_argv=True) as sfg: + ctx = sfg.context + + assert ctx.argv == ["--precision", "float32", "test1", "test2"] diff --git a/tests/generator_scripts/scripts/TestIllegalArgs.py b/tests/generator_scripts/scripts/TestIllegalArgs.py new file mode 100644 index 0000000000000000000000000000000000000000..ce0a0cbf4dd29f36e508d33b48c3e68e4adaaf58 --- /dev/null +++ b/tests/generator_scripts/scripts/TestIllegalArgs.py @@ -0,0 +1,4 @@ +from pystencilssfg import SourceFileGenerator + +with SourceFileGenerator() as sfg: + ... diff --git a/tests/generator_scripts/test_generator_scripts.py b/tests/generator_scripts/test_generator_scripts.py index d3173dce73f14458c02ad400b73f4d52d21cf947..16adba2ec1ff9731f799609a5635cc49f3de5a0f 100644 --- a/tests/generator_scripts/test_generator_scripts.py +++ b/tests/generator_scripts/test_generator_scripts.py @@ -9,6 +9,7 @@ import subprocess THIS_DIR = path.split(__file__)[0] SCRIPTS_DIR = path.join(THIS_DIR, "scripts") +CONFIG_DIR = path.join(THIS_DIR, "config") EXPECTED_DIR = path.join(THIS_DIR, "expected") @@ -30,6 +31,12 @@ class ScriptInfo: Output files will all be placed in the ``out`` folder. """ + args: tuple[str, ...] = () + """Command-line arguments to be passed to the generator script""" + + should_fail: bool = False + """Whether the exeuction of this script should fail.""" + compilable_output: str | None = None """File extension of the output file that can be compiled. @@ -50,6 +57,37 @@ When adding new generator scripts to the `scripts` directory, do not forget to include them here. """ SCRIPTS = [ + ScriptInfo.make( + "TestConfigModule", + ("h++", "c++"), + args=( + "--sfg-file-extensions", + ".c++,.h++", + "--sfg-config-module", + path.join(CONFIG_DIR, "TestConfigModule_cfg.py"), + ), + ), + ScriptInfo.make( + "TestIllegalArgs", + ("h++", "c++"), + args=( + "--sfg-file-extensionss", + ".c++,.h++", + ), + should_fail=True + ), + ScriptInfo.make( + "TestExtraCommandLineArgs", + ("h++", "c++"), + args=( + "--sfg-file-extensions", + ".c++,.h++", + "--precision", + "float32", + "test1", + "test2" + ), + ), ScriptInfo.make("Structural", ("hpp", "cpp")), ScriptInfo.make("SimpleJacobi", ("hpp", "cpp"), compilable_output="cpp"), ScriptInfo.make("SimpleClasses", ("hpp", "cpp")), @@ -75,12 +113,17 @@ def test_generator_script(script_info: ScriptInfo): shutil.rmtree(output_dir) os.makedirs(output_dir, exist_ok=True) - args = ["python", script_file, "--sfg-output-dir", output_dir] + args = ["python", script_file, "--sfg-output-dir", output_dir] + list(script_info.args) result = subprocess.run(args) + if script_info.should_fail: + if result.returncode == 0: + pytest.fail(f"Generator script {script_name} was supposed to fail, but didn't.") + return + if result.returncode != 0: - raise AssertionError(f"Generator script {script_name} failed.") + pytest.fail(f"Generator script {script_name} failed.") # Check generated files expected_files = set(