diff --git a/craft_parts/plugins/python_plugin.py b/craft_parts/plugins/python_plugin.py index 14da3a732..e748ad0e5 100644 --- a/craft_parts/plugins/python_plugin.py +++ b/craft_parts/plugins/python_plugin.py @@ -59,7 +59,7 @@ class PythonPlugin(Plugin): It can be used for python projects where you would want to do: - import python modules with a requirements.txt - - build a python project that has a setup.py + - build a python project that has a setup.py or pyproject.toml - install packages straight from pip This plugin uses the common plugin keywords as well as those for "sources". @@ -153,7 +153,9 @@ def get_build_commands(self) -> List[str]: requirements_cmd = f"{pip} install {constraints} -U {requirements}" build_commands.append(requirements_cmd) - build_commands.append(f"[ -f setup.py ] && {pip} install {constraints} -U .") + build_commands.append( + f"[ -f setup.py ] || [ -f pyproject.toml ] && {pip} install {constraints} -U ." + ) # Now fix shebangs. script_interpreter = self._get_script_interpreter() diff --git a/tests/integration/plugins/test_python.py b/tests/integration/plugins/test_python.py index 68ed63511..226289205 100644 --- a/tests/integration/plugins/test_python.py +++ b/tests/integration/plugins/test_python.py @@ -60,6 +60,33 @@ def test_python_plugin(new_dir): assert primed_script.open().readline().rstrip() == "#!/usr/bin/env python3" +def test_python_plugin_with_pyproject_toml(new_dir): + """Prime a simple python source.""" + source_location = Path(__file__).parent / "test_python_pyproject_toml" + + parts_yaml = textwrap.dedent( + f"""\ + parts: + foo: + plugin: python + source: {source_location} + """ + ) + parts = yaml.safe_load(parts_yaml) + + lf = LifecycleManager( + parts, application_name="test_python_pyproject_toml", cache_dir=new_dir + ) + actions = lf.plan(Step.PRIME) + + with lf.action_executor() as ctx: + ctx.execute(actions) + + primed_script = Path(lf.project_info.prime_dir, "bin", "mytestpyprojecttoml") + assert primed_script.exists() + assert primed_script.open().readline().rstrip() == "#!/usr/bin/env python3" + + def test_python_plugin_symlink(new_dir): """Run in the standard scenario with no overrides.""" parts_yaml = textwrap.dedent( diff --git a/tests/integration/plugins/test_python_pyproject_toml/mytestpyprojecttoml/__init__.py b/tests/integration/plugins/test_python_pyproject_toml/mytestpyprojecttoml/__init__.py new file mode 100644 index 000000000..47de3bbc5 --- /dev/null +++ b/tests/integration/plugins/test_python_pyproject_toml/mytestpyprojecttoml/__init__.py @@ -0,0 +1,2 @@ +def main(): + print("it works also with pyproject.toml!") diff --git a/tests/integration/plugins/test_python_pyproject_toml/pyproject.toml b/tests/integration/plugins/test_python_pyproject_toml/pyproject.toml new file mode 100644 index 000000000..3aa4338e1 --- /dev/null +++ b/tests/integration/plugins/test_python_pyproject_toml/pyproject.toml @@ -0,0 +1,11 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "plugin_test_pyproject_toml" +description = "My package description" +version = "0.0.1" + +[project.scripts] +mytestpyprojecttoml = "mytestpyprojecttoml:main" \ No newline at end of file diff --git a/tests/unit/plugins/test_python_plugin.py b/tests/unit/plugins/test_python_plugin.py index d11277873..765c6991d 100644 --- a/tests/unit/plugins/test_python_plugin.py +++ b/tests/unit/plugins/test_python_plugin.py @@ -98,7 +98,7 @@ def test_get_build_commands(plugin, new_dir): f'"${{PARTS_PYTHON_INTERPRETER}}" -m venv ${{PARTS_PYTHON_VENV_ARGS}} "{new_dir}/parts/p1/install"', f'PARTS_PYTHON_VENV_INTERP_PATH="{new_dir}/parts/p1/install/bin/${{PARTS_PYTHON_INTERPRETER}}"', f"{new_dir}/parts/p1/install/bin/pip install -U pip setuptools wheel", - f"[ -f setup.py ] && {new_dir}/parts/p1/install/bin/pip install -U .", + f"[ -f setup.py ] || [ -f pyproject.toml ] && {new_dir}/parts/p1/install/bin/pip install -U .", ] + get_build_commands(new_dir) @@ -121,7 +121,7 @@ def test_get_build_commands_with_all_properties(new_dir): f'PARTS_PYTHON_VENV_INTERP_PATH="{new_dir}/parts/p1/install/bin/${{PARTS_PYTHON_INTERPRETER}}"', f"{new_dir}/parts/p1/install/bin/pip install -c 'constraints.txt' -U pip 'some-pkg; sys_platform != '\"'\"'win32'\"'\"''", f"{new_dir}/parts/p1/install/bin/pip install -c 'constraints.txt' -U -r 'requirements.txt'", - f"[ -f setup.py ] && {new_dir}/parts/p1/install/bin/pip install -c 'constraints.txt' -U .", + f"[ -f setup.py ] || [ -f pyproject.toml ] && {new_dir}/parts/p1/install/bin/pip install -c 'constraints.txt' -U .", ] + get_build_commands(new_dir) @@ -173,7 +173,7 @@ def test_call_should_remove_symlinks(plugin, new_dir, mocker): f'"${{PARTS_PYTHON_INTERPRETER}}" -m venv ${{PARTS_PYTHON_VENV_ARGS}} "{new_dir}/parts/p1/install"', f'PARTS_PYTHON_VENV_INTERP_PATH="{new_dir}/parts/p1/install/bin/${{PARTS_PYTHON_INTERPRETER}}"', f"{new_dir}/parts/p1/install/bin/pip install -U pip setuptools wheel", - f"[ -f setup.py ] && {new_dir}/parts/p1/install/bin/pip install -U .", + f"[ -f setup.py ] || [ -f pyproject.toml ] && {new_dir}/parts/p1/install/bin/pip install -U .", f'find "{new_dir}/parts/p1/install" -type f -executable -print0 | xargs -0 \\\n' f' sed -i "1 s|^#\\!${{PARTS_PYTHON_VENV_INTERP_PATH}}.*$|#!/usr/bin/env ${{PARTS_PYTHON_INTERPRETER}}|"\n', f"echo Removing python symlinks in {new_dir}/parts/p1/install/bin\n"