Skip to content

Commit

Permalink
feat: compile flag for installer (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
KineticCookie authored Jul 23, 2024
1 parent de20d90 commit 8d8c7da
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/poetry_plugin_bundle/bundlers/venv_bundler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def __init__(self) -> None:
self._executable: str | None = None
self._remove: bool = False
self._activated_groups: set[str] | None = None
self._compile: bool = False

def set_path(self, path: Path) -> VenvBundler:
self._path = path
Expand All @@ -47,6 +48,11 @@ def set_remove(self, remove: bool = True) -> VenvBundler:

return self

def set_compile(self, compile: bool = False) -> VenvBundler:
self._compile = compile

return self

def bundle(self, poetry: Poetry, io: IO) -> bool:
from pathlib import Path
from tempfile import TemporaryDirectory
Expand Down Expand Up @@ -141,6 +147,8 @@ def locked_repository(self) -> LockfileRepository:
installer.only_groups(self._activated_groups)
installer.requires_synchronization()

installer.executor.enable_bytecode_compilation(self._compile)

return_code = installer.run()
if return_code:
self._write(
Expand Down
9 changes: 9 additions & 0 deletions src/poetry_plugin_bundle/console/commands/bundle/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class BundleVenvCommand(BundleCommand):
"Clear the existing virtual environment if it exists. ",
flag=True,
),
option(
"compile",
None,
"Compile Python source files to bytecode."
" (This option has no effect if modern-installation is disabled"
" because the old installer always compiles.)",
flag=True,
),
]

bundler_name = "venv"
Expand All @@ -45,4 +53,5 @@ def configure_bundler(self, bundler: VenvBundler) -> None: # type: ignore[overr
bundler.set_path(Path(self.argument("path")))
bundler.set_executable(self.option("python"))
bundler.set_remove(self.option("clear"))
bundler.set_compile(self.option("compile"))
bundler.set_activated_groups(self.activated_groups)
37 changes: 37 additions & 0 deletions tests/bundlers/test_venv_bundler.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,43 @@ def test_bundler_can_filter_dependency_groups(
assert expected == io.fetch_output()


@pytest.mark.parametrize("compile", [True, False])
def test_bundler_passes_compile_flag(
io: BufferedIO,
tmp_venv: VirtualEnv,
poetry: Poetry,
mocker: MockerFixture,
compile: bool,
) -> None:
mocker.patch("poetry.installation.executor.Executor._execute_operation")

bundler = VenvBundler()
bundler.set_path(tmp_venv.path)
bundler.set_remove(True)
bundler.set_compile(compile)

# bundle passes the flag from set_compile to enable_bytecode_compilation method
mocker = mocker.patch(
"poetry.installation.executor.Executor.enable_bytecode_compilation"
)

assert bundler.bundle(poetry, io)

mocker.assert_called_once_with(compile)

path = str(tmp_venv.path)
python_version = ".".join(str(v) for v in sys.version_info[:3])
expected = f"""\
• Bundling simple-project (1.2.3) into {path}
• Bundling simple-project (1.2.3) into {path}: Removing existing virtual environment
• Bundling simple-project (1.2.3) into {path}: Creating a virtual environment using Python {python_version}
• Bundling simple-project (1.2.3) into {path}: Installing dependencies
• Bundling simple-project (1.2.3) into {path}: Installing simple-project (1.2.3)
• Bundled simple-project (1.2.3) into {path}
"""
assert expected == io.fetch_output()


def test_bundler_editable_deps(
io: BufferedIO, tmpdir: str, poetry: Poetry, mocker: MockerFixture, config: Config
) -> None:
Expand Down
17 changes: 16 additions & 1 deletion tests/console/commands/bundle/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ def test_venv_calls_venv_bundler(
) -> None:
mock = mocker.patch(
"poetry_plugin_bundle.bundlers.venv_bundler.VenvBundler.bundle",
side_effect=[True, False, False, False],
side_effect=[True, False, False, False, False],
)
set_path = mocker.spy(VenvBundler, "set_path")
set_executable = mocker.spy(VenvBundler, "set_executable")
set_remove = mocker.spy(VenvBundler, "set_remove")
set_activated_groups = mocker.spy(VenvBundler, "set_activated_groups")
set_compile = mocker.spy(VenvBundler, "set_compile")

app_tester.application.catch_exceptions(False)
assert app_tester.execute("bundle venv /foo") == 0
Expand All @@ -33,36 +34,50 @@ def test_venv_calls_venv_bundler(
)
assert app_tester.execute("bundle venv /foo --only dev") == 1
assert app_tester.execute("bundle venv /foo --without main --with dev") == 1
assert app_tester.execute("bundle venv /foo --compile") == 1

assert isinstance(app_tester.application, Application)
assert [
mocker.call(app_tester.application.poetry, mocker.ANY),
mocker.call(app_tester.application.poetry, mocker.ANY),
mocker.call(app_tester.application.poetry, mocker.ANY),
mocker.call(app_tester.application.poetry, mocker.ANY),
mocker.call(app_tester.application.poetry, mocker.ANY),
] == mock.call_args_list

assert set_path.call_args_list == [
mocker.call(mocker.ANY, Path("/foo")),
mocker.call(mocker.ANY, Path("/foo")),
mocker.call(mocker.ANY, Path("/foo")),
mocker.call(mocker.ANY, Path("/foo")),
mocker.call(mocker.ANY, Path("/foo")),
]
assert set_executable.call_args_list == [
mocker.call(mocker.ANY, None),
mocker.call(mocker.ANY, "python3.8"),
mocker.call(mocker.ANY, None),
mocker.call(mocker.ANY, None),
mocker.call(mocker.ANY, None),
]
assert set_remove.call_args_list == [
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, True),
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, False),
]
assert set_activated_groups.call_args_list == [
mocker.call(mocker.ANY, {"main"}),
mocker.call(mocker.ANY, {"main", "dev"}),
mocker.call(mocker.ANY, {"dev"}),
mocker.call(mocker.ANY, {"dev"}),
mocker.call(mocker.ANY, {"main"}),
]

assert set_compile.call_args_list == [
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, False),
mocker.call(mocker.ANY, True),
]

0 comments on commit 8d8c7da

Please sign in to comment.