From 7bfc864fa312ff7a5ed516853c9669dc2c3260ce Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 1 Nov 2024 19:51:55 +1000 Subject: [PATCH 01/12] Fix automated layer versioning Closes #24 --- src/venvstacks/pack_venv.py | 20 ++- src/venvstacks/stacks.py | 176 +++++++++++++++++---------- tests/sample_project/venvstacks.toml | 8 +- 3 files changed, 130 insertions(+), 74 deletions(-) diff --git a/src/venvstacks/pack_venv.py b/src/venvstacks/pack_venv.py index d60c282..b95a091 100755 --- a/src/venvstacks/pack_venv.py +++ b/src/venvstacks/pack_venv.py @@ -196,12 +196,15 @@ def _supports_symlinks(target_path: Path) -> bool: def export_venv( source_dir: StrPath, target_dir: StrPath, + sitecustomize_source: StrPath | None = None, run_postinstall: Callable[[Path, Path], None] | None = None, ) -> Path: """Export the given build environment, skipping archive creation and unpacking * injects a suitable `postinstall.py` script for the environment being exported - * excludes __pycache__ folders and package metadata RECORD files + * excludes `__pycache__` folders and package metadata `RECORD` files + * allows build environment `sitecustomize.py` to be replaced with a deployed variant + * excludes `*sitecustomize.py` files from the tree copy if a specific source is given * replaces symlinks with copies on Windows or if the target doesn't support symlinks If supplied, *run_postinstall* is called with the path to the environment's Python @@ -213,7 +216,15 @@ def export_venv( """ source_path = as_normalized_path(source_dir) target_path = as_normalized_path(target_dir) - excluded = shutil.ignore_patterns("__pycache__", "RECORD") + patterns_to_ignore = ["__pycache__", "RECORD"] + if sitecustomize_source is not None: + # The deployed `sitecustomize.py` should be saved alongside the + # build version with a name like `_deployed_sitecustomize.py` + sc_source_path = as_normalized_path(sitecustomize_source) + sc_relative_path = sc_source_path.relative_to(source_path) + sc_target_path = target_path / sc_relative_path.with_name("sitecustomize.py") + patterns_to_ignore.append("*sitecustomize.py") + excluded = shutil.ignore_patterns(*patterns_to_ignore) # Avoid symlinks on Windows, as they need elevated privileges to create # Also avoid them if the target folder doesn't support symlink creation # (that way exports to FAT/FAT32/VFAT file systems should work, even if @@ -228,6 +239,8 @@ def export_venv( symlinks=publish_symlinks, dirs_exist_ok=True, ) + if sitecustomize_source is not None: + shutil.copy2(sc_source_path, sc_target_path) postinstall_path = _inject_postinstall_script(target_path) if run_postinstall is not None: run_postinstall(target_path, postinstall_path) @@ -237,6 +250,7 @@ def export_venv( def create_archive( source_dir: StrPath, archive_base_name: StrPath, + sitecustomize_source: StrPath | None = None, *, install_target: str | None = None, clamp_mtime: datetime | None = None, @@ -261,7 +275,7 @@ def create_archive( install_target = source_path.name with tempfile.TemporaryDirectory(dir=work_dir) as tmp_dir: target_path = Path(tmp_dir) / install_target - env_path = export_venv(source_path, target_path) + env_path = export_venv(source_path, target_path, sitecustomize_source) if not show_progress: def report_progress(_: Any) -> None: diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index 5ba244b..fe4c939 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -27,6 +27,7 @@ Any, ClassVar, Iterable, + Iterator, Literal, Mapping, MutableMapping, @@ -645,6 +646,7 @@ def create_archive( self, env_path: Path, previous_metadata: ArchiveMetadata | None = None, + sitecustomize_source_path: Path | None = None, work_path: Path | None = None, ) -> tuple[ArchiveMetadata, Path]: if env_path.name != self.env_name: @@ -669,6 +671,7 @@ def create_archive( pack_venv.create_archive( env_path, archive_base_path, + sitecustomize_source_path, clamp_mtime=last_locked, work_dir=work_path, install_target=build_metadata["install_target"], @@ -798,6 +801,7 @@ def export_environment( self, env_path: Path, previous_metadata: ExportMetadata | None = None, + sitecustomize_source_path: Path | None = None, ) -> tuple[ExportMetadata, Path]: if env_path.name != self.env_name: err_msg = ( @@ -822,6 +826,7 @@ def _run_postinstall(export_path: Path, postinstall_path: Path) -> None: exported_path = pack_venv.export_venv( env_path, export_path, + sitecustomize_source_path, _run_postinstall, ) assert self.export_path == exported_path # pack_venv ensures this is true @@ -990,6 +995,7 @@ class _PythonEnvironment(ABC): base_python_path: Path | None = field(init=False, repr=False) tools_python_path: Path | None = field(init=False, repr=False) py_version: str = field(init=False, repr=False) + sitecustomize_source_path: Path | None = field(default=None, init=False, repr=False) # Operation flags allow for requested commands to be applied only to selected layers # Notes: @@ -1023,6 +1029,11 @@ def env_name(self) -> EnvNameBuild: def install_target(self) -> EnvNameDeploy: return self.env_lock.get_deployed_name(self.env_spec.env_name) + def get_deployed_path(self, build_path: Path) -> Path: + env_deployed_path = Path(self.install_target) + relative_path = build_path.relative_to(self.env_path) + return env_deployed_path / relative_path + def __post_init__(self) -> None: self.env_path = self.build_path / self.env_name self.pylib_path = self._get_py_scheme_path("purelib") @@ -1313,7 +1324,9 @@ def create_archive( output_path, target_platform, tag_output, previous_metadata, force ) work_path = self.build_path # /tmp is likely too small for ML environments - return build_request.create_archive(env_path, previous_metadata, work_path) + return build_request.create_archive( + env_path, previous_metadata, self.sitecustomize_source_path, work_path + ) def request_export( self, @@ -1339,7 +1352,9 @@ def export_environment( # Define the input metadata that gets published in the export manifest export_request = self.request_export(output_path, previous_metadata, force) - return export_request.export_environment(env_path, previous_metadata) + return export_request.export_environment( + env_path, previous_metadata, self.sitecustomize_source_path + ) class RuntimeEnv(_PythonEnvironment): @@ -1417,11 +1432,13 @@ def create_build_environment(self, *, clean: bool = False) -> None: class _VirtualEnvironment(_PythonEnvironment): _include_system_site_packages = False + base_runtime: RuntimeEnv | None = field(init=False, repr=False) linked_constraints_paths: list[Path] = field(init=False, repr=False) def __post_init__(self) -> None: self.py_version = self.env_spec.runtime.py_version super().__post_init__() + self.base_runtime = None self.linked_constraints_paths = [] @property @@ -1430,13 +1447,17 @@ def env_spec(self) -> _VirtualEnvironmentSpec: assert isinstance(self._env_spec, _VirtualEnvironmentSpec) return self._env_spec - def link_base_runtime_paths(self, runtime: RuntimeEnv) -> None: + def link_base_runtime(self, runtime: RuntimeEnv) -> None: + if self.base_runtime is not None: + raise BuildEnvError(f"Layered environment base runtime already linked {self}") + # Link the runtime environment + self.base_runtime = runtime # Link executable paths self.base_python_path = runtime.python_path self.tools_python_path = runtime.tools_python_path - if self.linked_constraints_paths: - raise BuildEnvError("Layered environment base runtime already linked") + # Link runtime layer dependency constraints self.linked_constraints_paths[:] = [runtime.requirements_path] + print(f"Linked {self}") def get_constraint_paths(self) -> list[Path]: return self.linked_constraints_paths @@ -1464,12 +1485,12 @@ def _ensure_virtual_environment(self) -> subprocess.CompletedProcess[str]: str(self.env_path), ] result = run_python_command(command) - self._link_layered_environment() + self._generate_sitecustomize() fs_sync() print(f"Virtual environment configured in {str(self.env_path)!r}") return result - def _link_layered_environment(self) -> None: + def _generate_sitecustomize(self) -> None: pass # Nothing to do by default, subclasses override if necessary def _update_existing_environment(self, *, lock_only: bool = False) -> None: @@ -1515,8 +1536,6 @@ class ApplicationEnv(_VirtualEnvironment): category = LayerCategories.APPLICATIONS launch_module_name: str = field(init=False, repr=False) - linked_pylib_paths: list[Path] = field(init=False, repr=False) - linked_dynlib_paths: list[Path] = field(init=False, repr=False) linked_frameworks: list[FrameworkEnv] = field(init=False, repr=False) @property @@ -1527,65 +1546,69 @@ def env_spec(self) -> ApplicationSpec: def __post_init__(self) -> None: super().__post_init__() + self.sitecustomize_source_path = self.pylib_path / "_deployed_sitecustomize.py" self.launch_module_name = self.env_spec.launch_module_path.stem - self.linked_pylib_paths = [] - self.linked_dynlib_paths = [] self.linked_frameworks = [] + def _linked_environments(self) -> Iterator[_PythonEnvironment]: + for fw_env in self.linked_frameworks: + yield fw_env + runtime_env = self.base_runtime + assert runtime_env is not None + yield runtime_env + + def _linked_pylib_build_paths(self) -> Iterator[Path]: + for env in self._linked_environments(): + yield env.pylib_path + + def _linked_dynlib_build_paths(self) -> Iterator[Path]: + for env in self._linked_environments(): + dynlib_path = env.dynlib_path + if dynlib_path is not None: + yield dynlib_path + + def _linked_pylib_deployed_paths(self) -> Iterator[Path]: + for env in self._linked_environments(): + yield env.get_deployed_path(env.pylib_path) + + def _linked_dynlib_deployed_paths(self) -> Iterator[Path]: + for env in self._linked_environments(): + dynlib_path = env.dynlib_path + if dynlib_path is not None: + yield env.get_deployed_path(dynlib_path) + def link_layered_environments( self, runtime: RuntimeEnv, frameworks: Mapping[LayerBaseName, FrameworkEnv] ) -> None: - self.link_base_runtime_paths(runtime) + self.link_base_runtime(runtime) constraints_paths = self.linked_constraints_paths if not constraints_paths: raise BuildEnvError("Failed to add base environment constraints path") # The runtime site-packages folder is added here rather than via pyvenv.cfg # to ensure it appears in sys.path after the framework site-packages folders - pylib_paths = self.linked_pylib_paths - dynlib_paths = self.linked_dynlib_paths fw_envs = self.linked_frameworks - if pylib_paths or dynlib_paths or fw_envs: + if fw_envs: raise BuildEnvError("Layered application environment already linked") - for env_spec in self.env_spec.frameworks: - env = frameworks[env_spec.name] - fw_envs.append(env) - constraints_paths.append(env.requirements_path) - install_target_path = Path(env.install_target) - - def _fw_env_path(build_path: Path) -> Path: - relative_path = build_path.relative_to(env.env_path) - return install_target_path / relative_path - - pylib_paths.append(_fw_env_path(env.pylib_path)) - if env.dynlib_path is not None: - dynlib_paths.append(_fw_env_path(env.pylib_path)) - runtime_target_path = Path(runtime.install_target) - - def _runtime_path(build_path: Path) -> Path: - relative_path = build_path.relative_to(runtime.env_path) - return runtime_target_path / relative_path - - pylib_paths.append(_runtime_path(runtime.pylib_path)) - if runtime.dynlib_path is not None: - dynlib_paths.append(_runtime_path(runtime.dynlib_path)) - - def _link_layered_environment(self) -> None: - # Create sitecustomize file - sc_dir_path = self.pylib_path + for fw_env_spec in self.env_spec.frameworks: + fw_env = frameworks[fw_env_spec.name] + fw_envs.append(fw_env) + constraints_paths.append(fw_env.requirements_path) + + @staticmethod + def _render_sitecustomize( + relative_prefix: Path, + pylib_paths: Iterable[Path], + dynlib_paths: Iterable[Path], + ) -> str: sc_contents = [ "# Automatically generated by venvstacks", "import site", "import os", "from os.path import abspath, dirname, join as joinpath", - "# Allow loading modules and packages from framework environments", + "# Allow loading modules and packages from linked environments", "this_dir = dirname(abspath(__file__))", ] - # Add framework and runtime folders to sys.path - parent_path = self.env_path.parent - relative_prefix = Path( - os.path.relpath(str(parent_path), start=str(sc_dir_path)) - ) - for pylib_path in self.linked_pylib_paths: + for pylib_path in pylib_paths: relative_path = relative_prefix / pylib_path sc_contents.extend( [ @@ -1593,31 +1616,54 @@ def _link_layered_environment(self) -> None: "site.addsitedir(path_entry)", ] ) - # Add DLL search folders if needed - dynlib_paths = self.linked_dynlib_paths - if _WINDOWS_BUILD and dynlib_paths: + dynlib_entries: list[str] = [] + for dynlib_path in dynlib_paths: + if not dynlib_path.exists(): + # Nothing added DLLs to this folder at build time, so skip it + continue + relative_path = relative_prefix / dynlib_path + dynlib_entries.extend( + [ + f"dll_dir = abspath(joinpath(this_dir, {str(relative_path)!r}))", + "os.add_dll_directory(dll_dir)", + ] + ) + if dynlib_entries: sc_contents.extend( [ "", "# Allow loading misplaced DLLs on Windows", + *dynlib_entries, ] ) - for dynlib_path in dynlib_paths: - if not dynlib_path.exists(): - # Nothing added DLLs to this folder at build time, so skip it - continue - relative_path = relative_prefix / dynlib_path - sc_contents.extend( - [ - f"dll_dir = abspath(joinpath(this_dir, {str(relative_path)!r}))", - "os.add_dll_directory(dll_dir)", - ] - ) sc_contents.append("") + return "\n".join(sc_contents) + + def _generate_sitecustomize(self) -> None: + # Create build & deployment sitecustomize files + sc_dir_path = self.pylib_path + # Add framework and runtime folders to sys.path + parent_path = self.env_path.parent + relative_prefix = Path( + os.path.relpath(str(parent_path), start=str(sc_dir_path)) + ) + sc_contents = self._render_sitecustomize( + relative_prefix, + self._linked_pylib_build_paths(), + self._linked_dynlib_build_paths(), + ) + deployed_sc_contents = self._render_sitecustomize( + relative_prefix, + self._linked_pylib_deployed_paths(), + self._linked_dynlib_deployed_paths(), + ) sc_path = self.pylib_path / "sitecustomize.py" print(f"Generating {sc_path!r}...") - with open(sc_path, "w", encoding="utf-8") as f: - f.write("\n".join(sc_contents)) + sc_path.write_text(sc_contents) + deployed_sc_path = self.sitecustomize_source_path + assert deployed_sc_path is not None + print(f"Generating {deployed_sc_path!r}...") + deployed_sc_path.write_text(deployed_sc_contents) def _update_existing_environment(self, *, lock_only: bool = False) -> None: super()._update_existing_environment(lock_only=lock_only) @@ -1805,7 +1851,7 @@ def define_build_environment( ) for fw_env in frameworks.values(): runtime = runtimes[fw_env.env_spec.runtime.name] - fw_env.link_base_runtime_paths(runtime) + fw_env.link_base_runtime(runtime) print("Defining application environments:") applications = self._define_envs( build_path, index_config, ApplicationEnv, self.applications diff --git a/tests/sample_project/venvstacks.toml b/tests/sample_project/venvstacks.toml index 9ceb843..17cb920 100644 --- a/tests/sample_project/venvstacks.toml +++ b/tests/sample_project/venvstacks.toml @@ -65,9 +65,7 @@ requirements = [ [[frameworks]] name = "scipy" -# Automatic versioning currently breaks venv layering -# https://github.com/lmstudio-ai/venvstacks/issues/24 -# versioned = true +versioned = true runtime = "cpython@3.11" requirements = [ "scipy", @@ -96,9 +94,7 @@ requirements = [ [[applications]] name = "scipy-import" -# Automatic versioning currently breaks venv layering -# https://github.com/lmstudio-ai/venvstacks/issues/24 -# versioned = true +versioned = true launch_module = "launch_modules/scipy_import.py" frameworks = ["scipy"] requirements = [ From 90cf3ec502c111c23504cb06d94391d11398e626 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 4 Nov 2024 14:26:53 +1000 Subject: [PATCH 02/12] Force site customization encoding and newlines --- src/venvstacks/stacks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index fe4c939..f9da726 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -1659,11 +1659,11 @@ def _generate_sitecustomize(self) -> None: ) sc_path = self.pylib_path / "sitecustomize.py" print(f"Generating {sc_path!r}...") - sc_path.write_text(sc_contents) + sc_path.write_text(sc_contents, encoding="utf-8", newline="\n") deployed_sc_path = self.sitecustomize_source_path assert deployed_sc_path is not None print(f"Generating {deployed_sc_path!r}...") - deployed_sc_path.write_text(deployed_sc_contents) + deployed_sc_path.write_text(deployed_sc_contents, encoding="utf-8", newline="\n") def _update_existing_environment(self, *, lock_only: bool = False) -> None: super()._update_existing_environment(lock_only=lock_only) From e4df1c33e4988916ae686a9b9875dc1572303e2e Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 4 Nov 2024 14:28:18 +1000 Subject: [PATCH 03/12] Force newlines in postinstall scripts --- src/venvstacks/pack_venv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/venvstacks/pack_venv.py b/src/venvstacks/pack_venv.py index b95a091..07762ce 100755 --- a/src/venvstacks/pack_venv.py +++ b/src/venvstacks/pack_venv.py @@ -176,7 +176,7 @@ def _inject_postinstall_script( else: script_contents = _BASE_RUNTIME_POST_INSTALL_SCRIPT script_path = env_path / script_name - script_path.write_text(script_contents, encoding="utf-8") + script_path.write_text(script_contents, encoding="utf-8", newline="\n") return script_path From a0ad20c51dfc839ec541368aeb56fa6cddee93f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:09:25 +1000 Subject: [PATCH 04/12] Update expected output (2024-11-04 04:58:20+00:00) (#65) Update expected test output files from automated/expected-output/20241104-045820-e4df1c3 (source PR: #64) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../env_metadata/app-scipy-client.json | 6 +-- .../env_metadata/app-scipy-import.json | 10 ++--- .../env_metadata/app-sklearn-import.json | 2 +- .../env_metadata/framework-scipy.json | 8 ++-- .../linux_x86_64/venvstacks.json | 26 ++++++------ .../env_metadata/app-scipy-client.json | 6 +-- .../env_metadata/app-scipy-import.json | 8 ++-- .../env_metadata/framework-scipy.json | 8 ++-- .../macosx_arm64/venvstacks.json | 22 +++++----- .../env_metadata/app-scipy-client.json | 6 +-- .../env_metadata/app-scipy-import.json | 10 ++--- .../win_amd64/env_metadata/cpython@3.11.json | 4 +- .../win_amd64/env_metadata/cpython@3.12.json | 4 +- .../env_metadata/framework-http-client.json | 4 +- .../env_metadata/framework-scipy.json | 8 ++-- .../env_metadata/framework-sklearn.json | 4 +- .../win_amd64/venvstacks.json | 40 +++++++++---------- 17 files changed, 88 insertions(+), 88 deletions(-) diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json index 6636940..efc5c26 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "84c38c5717c3ff4e5fc9a13b22045b8c7fa2a96682648e419e22983e9023f554" + "sha256": "a2352d92b495315ac2fb5d011d7527fd8d7ad018e5feacf4aeddfd87d61251d0" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 1504, + "archive_size": 1508, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.205589+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json index 36b7bde..c5bcebd 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "4c30fb1472a1905d0369b700bd922f317f8ab4875e7b02a9c997dedf5cb0b175" + "sha256": "30169e6d298e1fc3d4cba0d9b07da0e835ab4e0dfd82ab4b4eabd28e79432d9c" }, - "archive_name": "app-scipy-import.tar.xz", - "archive_size": 1412, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.tar.xz", + "archive_size": 1416, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.173589+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-sklearn-import.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-sklearn-import.json index 76a2b85..863350c 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-sklearn-import.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-sklearn-import.json @@ -3,7 +3,7 @@ "app_launch_module_hash": "sha256:f66c01bbcca47cd31d79d2fb5377de0de18631ffc3c904629d46f6cad2918694", "archive_build": 1, "archive_hashes": { - "sha256": "ba0b38bb3c8539b9882bdfd752f1407961f26fe8a2c1af3d1bed62d83478b8e7" + "sha256": "b08bfd48cc54bfb3123f64bda0c023e7d82c2d31ea310c258da7ef761165d49e" }, "archive_name": "app-sklearn-import.tar.xz", "archive_size": 1420, diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json index b22ca25..84030b0 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "bd8bf5b409d03d78e878f3a5d7e350daea0e94cc983a6146997a1bd0d1834bf5" + "sha256": "a66860607012b4ddd1855abbca4e3dea80681ae42d49a5f2ea76bf93bcd1084a" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 23956040, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 23959992, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:42.825586+00:00", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json b/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json index f1bd931..b72452e 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "4c30fb1472a1905d0369b700bd922f317f8ab4875e7b02a9c997dedf5cb0b175" + "sha256": "30169e6d298e1fc3d4cba0d9b07da0e835ab4e0dfd82ab4b4eabd28e79432d9c" }, - "archive_name": "app-scipy-import.tar.xz", - "archive_size": 1412, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.tar.xz", + "archive_size": 1416, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.173589+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "84c38c5717c3ff4e5fc9a13b22045b8c7fa2a96682648e419e22983e9023f554" + "sha256": "a2352d92b495315ac2fb5d011d7527fd8d7ad018e5feacf4aeddfd87d61251d0" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 1504, + "archive_size": 1508, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.205589+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", @@ -47,7 +47,7 @@ "app_launch_module_hash": "sha256:f66c01bbcca47cd31d79d2fb5377de0de18631ffc3c904629d46f6cad2918694", "archive_build": 1, "archive_hashes": { - "sha256": "ba0b38bb3c8539b9882bdfd752f1407961f26fe8a2c1af3d1bed62d83478b8e7" + "sha256": "b08bfd48cc54bfb3123f64bda0c023e7d82c2d31ea310c258da7ef761165d49e" }, "archive_name": "app-sklearn-import.tar.xz", "archive_size": 1420, @@ -67,11 +67,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "bd8bf5b409d03d78e878f3a5d7e350daea0e94cc983a6146997a1bd0d1834bf5" + "sha256": "a66860607012b4ddd1855abbca4e3dea80681ae42d49a5f2ea76bf93bcd1084a" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 23956040, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 23959992, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:42.825586+00:00", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json index a9a8af9..ebc6f13 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "2cdf88d7a5ed2dca88d7a59e2b5d9744503cf824218371948000f1b08486df4e" + "sha256": "1c47823146319078f9f7fc5d27605205c9d99449d85b7719fe9e21ec39dea457" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 1484, + "archive_size": 1488, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.147967+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json index 2cbf816..73b7e21 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "5034f1fa0a0731af9e88699519a508e72662b003c30e14814ce72e00ef8a6223" + "sha256": "066c98a2355bf314ebdd66c9eaf5d01514cf9b738d761aefaefe6dd57154b6b3" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 1392, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.121208+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json index 331a486..b19a6fb 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "45d6b5abeddedc12978b54d8ff4a29db76495bd5ab7b7a051ed45b8aa8fc76b9" + "sha256": "b201312705774dc3b748e71ac27fefbf54d750c11618b8048303cf84ea43713b" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 15077296, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 15074628, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:32.960668+00:00", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json b/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json index 86778c7..998b4f9 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "5034f1fa0a0731af9e88699519a508e72662b003c30e14814ce72e00ef8a6223" + "sha256": "066c98a2355bf314ebdd66c9eaf5d01514cf9b738d761aefaefe6dd57154b6b3" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 1392, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.121208+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "2cdf88d7a5ed2dca88d7a59e2b5d9744503cf824218371948000f1b08486df4e" + "sha256": "1c47823146319078f9f7fc5d27605205c9d99449d85b7719fe9e21ec39dea457" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 1484, + "archive_size": 1488, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.147967+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", @@ -47,11 +47,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "45d6b5abeddedc12978b54d8ff4a29db76495bd5ab7b7a051ed45b8aa8fc76b9" + "sha256": "b201312705774dc3b748e71ac27fefbf54d750c11618b8048303cf84ea43713b" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 15077296, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 15074628, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:32.960668+00:00", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json index a32e876..98e8bd7 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "69060c0e0a74290723c5e65a343e463112a249da960d8bf29997933cd1565787" + "sha256": "ca18363cd4b9cc9a567ee2a1624ae61f413297bd00595ddbe7cb4b5aaa3f7e52" }, "archive_name": "app-scipy-client.zip", - "archive_size": 255147, + "archive_size": 255109, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.468633+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:3bff0428616a2f1724732e78e7788e753dd5f1aa10aa5d3b87707b8dbde121de", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json index be1e7d7..36b698a 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "1907700fc74c6a0bc62d851dce87bfed6a0ad52d0fec5863c9eadd1e26c029ff" + "sha256": "e987f9c43f8df61602699686e28f5178e7547c509e3d838285d7c22d995974b3" }, - "archive_name": "app-scipy-import.zip", - "archive_size": 254658, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.zip", + "archive_size": 254660, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.386938+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:9aba38b5efe287f35d58825dce6b1c47ed556b930056e6edc00ca9e1a165796b", "runtime_name": "cpython@3.11.10", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.11.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.11.json index 5346397..b543ee2 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.11.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.11.json @@ -1,10 +1,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "70a00f1e469d6c4ab82e0d74946ca6da0fb97ee480b294d93e6b217d8a9f3cd0" + "sha256": "96810b28fc38dfd207fe6d3ff30b89f3fbf34f519fbe3a1337c035abdfed714b" }, "archive_name": "cpython@3.11.zip", - "archive_size": 46592259, + "archive_size": 46592251, "install_target": "cpython@3.11", "layer_name": "cpython@3.11", "lock_version": 1, diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.12.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.12.json index 508e5a9..09cc807 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.12.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/cpython@3.12.json @@ -1,10 +1,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "ab8860e56b834ff4b9eacd11e8a0c705c83edac6b1627990f5317e1514314d76" + "sha256": "ff79b5b4d9c7546d2c3c05313877c66c501c38eb1d48eed148237a65fc54bbbf" }, "archive_name": "cpython@3.12.zip", - "archive_size": 45864491, + "archive_size": 45864483, "install_target": "cpython@3.12", "layer_name": "cpython@3.12", "lock_version": 1, diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-http-client.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-http-client.json index 6af3112..9763d44 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-http-client.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-http-client.json @@ -1,10 +1,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "b0193afc9d1f4a51b9fcb60903d335696804d2b35115986c68e4ebf5aaf1b621" + "sha256": "050eca5f2fa105b2750cd2a6b3de51310ca8e5ac453f843d2198629e5aa8f13d" }, "archive_name": "framework-http-client.zip", - "archive_size": 817522, + "archive_size": 817511, "install_target": "framework-http-client", "layer_name": "framework-http-client", "lock_version": 1, diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json index c86bc68..b94c31b 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "132cd5e29dae8d082c453b276e5e207e5f82f29458db62d6c7df2a01b8225f92" + "sha256": "643389d3e7f7c37fdf768ca02377f7e2ab019e7c0f6a448e6f61d40c390ce572" }, - "archive_name": "framework-scipy.zip", - "archive_size": 45078361, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.zip", + "archive_size": 45084834, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:24:35.999197+00:00", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-sklearn.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-sklearn.json index 6bb7c4f..d50c2d4 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-sklearn.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-sklearn.json @@ -1,10 +1,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "eaaa57b8f636eb0258bf4b4ac11a7a76a4691b1659d9a14bd8b908129f75e936" + "sha256": "dd67aa8431b52d526fdb1eeb6109a30f44d36d1b56356590e9bb96ad474d71be" }, "archive_name": "framework-sklearn.zip", - "archive_size": 56185753, + "archive_size": 56185742, "install_target": "framework-sklearn", "layer_name": "framework-sklearn", "lock_version": 1, diff --git a/tests/sample_project/expected_manifests/win_amd64/venvstacks.json b/tests/sample_project/expected_manifests/win_amd64/venvstacks.json index d06983c..910a6c9 100644 --- a/tests/sample_project/expected_manifests/win_amd64/venvstacks.json +++ b/tests/sample_project/expected_manifests/win_amd64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "1907700fc74c6a0bc62d851dce87bfed6a0ad52d0fec5863c9eadd1e26c029ff" + "sha256": "e987f9c43f8df61602699686e28f5178e7547c509e3d838285d7c22d995974b3" }, - "archive_name": "app-scipy-import.zip", - "archive_size": 254658, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.zip", + "archive_size": 254660, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.386938+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:9aba38b5efe287f35d58825dce6b1c47ed556b930056e6edc00ca9e1a165796b", "runtime_name": "cpython@3.11.10", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "69060c0e0a74290723c5e65a343e463112a249da960d8bf29997933cd1565787" + "sha256": "ca18363cd4b9cc9a567ee2a1624ae61f413297bd00595ddbe7cb4b5aaa3f7e52" }, "archive_name": "app-scipy-client.zip", - "archive_size": 255147, + "archive_size": 255109, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.468633+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:3bff0428616a2f1724732e78e7788e753dd5f1aa10aa5d3b87707b8dbde121de", @@ -47,11 +47,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "132cd5e29dae8d082c453b276e5e207e5f82f29458db62d6c7df2a01b8225f92" + "sha256": "643389d3e7f7c37fdf768ca02377f7e2ab019e7c0f6a448e6f61d40c390ce572" }, - "archive_name": "framework-scipy.zip", - "archive_size": 45078361, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.zip", + "archive_size": 45084834, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:24:35.999197+00:00", @@ -62,10 +62,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "eaaa57b8f636eb0258bf4b4ac11a7a76a4691b1659d9a14bd8b908129f75e936" + "sha256": "dd67aa8431b52d526fdb1eeb6109a30f44d36d1b56356590e9bb96ad474d71be" }, "archive_name": "framework-sklearn.zip", - "archive_size": 56185753, + "archive_size": 56185742, "install_target": "framework-sklearn", "layer_name": "framework-sklearn", "lock_version": 1, @@ -77,10 +77,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "b0193afc9d1f4a51b9fcb60903d335696804d2b35115986c68e4ebf5aaf1b621" + "sha256": "050eca5f2fa105b2750cd2a6b3de51310ca8e5ac453f843d2198629e5aa8f13d" }, "archive_name": "framework-http-client.zip", - "archive_size": 817522, + "archive_size": 817511, "install_target": "framework-http-client", "layer_name": "framework-http-client", "lock_version": 1, @@ -94,10 +94,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "70a00f1e469d6c4ab82e0d74946ca6da0fb97ee480b294d93e6b217d8a9f3cd0" + "sha256": "96810b28fc38dfd207fe6d3ff30b89f3fbf34f519fbe3a1337c035abdfed714b" }, "archive_name": "cpython@3.11.zip", - "archive_size": 46592259, + "archive_size": 46592251, "install_target": "cpython@3.11", "layer_name": "cpython@3.11", "lock_version": 1, @@ -109,10 +109,10 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "ab8860e56b834ff4b9eacd11e8a0c705c83edac6b1627990f5317e1514314d76" + "sha256": "ff79b5b4d9c7546d2c3c05313877c66c501c38eb1d48eed148237a65fc54bbbf" }, "archive_name": "cpython@3.12.zip", - "archive_size": 45864491, + "archive_size": 45864483, "install_target": "cpython@3.12", "layer_name": "cpython@3.12", "lock_version": 1, From c98717869aaad5b1710d862da317519dc14b5963 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 4 Nov 2024 16:11:58 +1000 Subject: [PATCH 05/12] Strengthen export path checks --- src/venvstacks/stacks.py | 8 ++++++-- tests/test_minimal_project.py | 20 +++++++++++--------- tests/test_sample_project.py | 8 +++++--- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index f9da726..d0b8ce7 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -1449,7 +1449,9 @@ def env_spec(self) -> _VirtualEnvironmentSpec: def link_base_runtime(self, runtime: RuntimeEnv) -> None: if self.base_runtime is not None: - raise BuildEnvError(f"Layered environment base runtime already linked {self}") + raise BuildEnvError( + f"Layered environment base runtime already linked {self}" + ) # Link the runtime environment self.base_runtime = runtime # Link executable paths @@ -1663,7 +1665,9 @@ def _generate_sitecustomize(self) -> None: deployed_sc_path = self.sitecustomize_source_path assert deployed_sc_path is not None print(f"Generating {deployed_sc_path!r}...") - deployed_sc_path.write_text(deployed_sc_contents, encoding="utf-8", newline="\n") + deployed_sc_path.write_text( + deployed_sc_contents, encoding="utf-8", newline="\n" + ) def _update_existing_environment(self, *, lock_only: bool = False) -> None: super()._update_existing_environment(lock_only=lock_only) diff --git a/tests/test_minimal_project.py b/tests/test_minimal_project.py index 3aefa28..a68670e 100644 --- a/tests/test_minimal_project.py +++ b/tests/test_minimal_project.py @@ -532,26 +532,28 @@ def get_exported_python( self.check_deployed_environments(layered_metadata, get_exported_python) - def check_environment_exports(self, export_paths: ExportedEnvironmentPaths) -> None: + def check_environment_exports( + self, export_path: Path, export_paths: ExportedEnvironmentPaths + ) -> None: metadata_path, snippet_paths, env_paths = export_paths exported_manifests = ManifestData(metadata_path, snippet_paths) - env_name_to_path: dict[str, Path] = {} + deployed_name_to_path: dict[str, Path] = {} for env_metadata, env_path in zip(exported_manifests.snippet_data, env_paths): # TODO: Check more details regarding expected metadata contents self.assertTrue(env_path.exists()) - env_name = EnvNameDeploy(env_metadata["install_target"]) - self.assertEqual(env_path.name, env_name) - env_name_to_path[env_name] = env_path + deployed_name = EnvNameDeploy(env_metadata["install_target"]) + self.assertEqual(env_path, export_path / deployed_name) + deployed_name_to_path[deployed_name] = env_path layered_metadata = exported_manifests.combined_data["layers"] def get_exported_python( env: ExportMetadata, ) -> tuple[EnvNameDeploy, Path, list[str]]: - env_name = env["install_target"] - env_path = env_name_to_path[env_name] + deployed_name = env["install_target"] + env_path = deployed_name_to_path[deployed_name] env_python = get_env_python(env_path) env_sys_path = get_sys_path(env_python) - return env_name, env_python, env_sys_path + return deployed_name, env_python, env_sys_path self.check_deployed_environments(layered_metadata, get_exported_python) @@ -654,7 +656,7 @@ def test_locking_and_publishing(self) -> None: with self.subTest("Check environment export"): export_path = self.working_path / "_export🦎" export_result = build_env.export_environments(export_path) - self.check_environment_exports(export_result) + self.check_environment_exports(export_path, export_result) subtests_passed += 1 # Test stage: ensure published archives and manifests have the expected name # and that unpacking them allows launch module execution diff --git a/tests/test_sample_project.py b/tests/test_sample_project.py index ff4487d..9c56640 100644 --- a/tests/test_sample_project.py +++ b/tests/test_sample_project.py @@ -322,14 +322,16 @@ def check_deployed_environments( ) self.assertEqual(launch_result.stderr, "") - def check_environment_exports(self, export_paths: ExportedEnvironmentPaths) -> None: + def check_environment_exports( + self, export_path: Path, export_paths: ExportedEnvironmentPaths + ) -> None: metadata_path, snippet_paths, env_paths = export_paths exported_manifests = ManifestData(metadata_path, snippet_paths) deployed_name_to_path: dict[str, Path] = {} for env_metadata, env_path in zip(exported_manifests.snippet_data, env_paths): self.assertTrue(env_path.exists()) deployed_name = EnvNameDeploy(env_metadata["install_target"]) - self.assertEqual(env_path.name, deployed_name) + self.assertEqual(env_path, export_path / deployed_name) deployed_name_to_path[deployed_name] = env_path layered_metadata = exported_manifests.combined_data["layers"] @@ -450,7 +452,7 @@ def test_build_is_reproducible(self) -> None: with self.subTest("Check environment export"): export_path = self.working_path / "_export🦎" export_result = build_env.export_environments(export_path) - self.check_environment_exports(export_result) + self.check_environment_exports(export_path, export_result) subtests_passed += 1 # Work aroung pytest-subtests not failing the test case when subtests fail From 88518101070d0e53e5a86951f6d78cabc3d782c1 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Thu, 7 Nov 2024 22:16:14 +1000 Subject: [PATCH 06/12] Remove now obsolete API additions --- src/venvstacks/stacks.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index 0a4124a..e8a0ee2 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -647,7 +647,6 @@ def create_archive( self, env_path: Path, previous_metadata: ArchiveMetadata | None = None, - sitecustomize_source_path: Path | None = None, work_path: Path | None = None, ) -> tuple[ArchiveMetadata, Path]: if env_path.name != self.env_name: @@ -672,7 +671,6 @@ def create_archive( pack_venv.create_archive( env_path, archive_base_path, - sitecustomize_source_path, clamp_mtime=last_locked, work_dir=work_path, install_target=build_metadata["install_target"], @@ -788,7 +786,6 @@ def export_environment( self, env_path: Path, previous_metadata: ExportMetadata | None = None, - sitecustomize_source_path: Path | None = None, ) -> tuple[ExportMetadata, Path]: if env_path.name != self.env_name: err_msg = ( @@ -813,7 +810,6 @@ def _run_postinstall(_export_path: Path, postinstall_path: Path) -> None: exported_path = pack_venv.export_venv( env_path, export_path, - sitecustomize_source_path, _run_postinstall, ) assert self.export_path == exported_path # pack_venv ensures this is true @@ -982,7 +978,6 @@ class _PythonEnvironment(ABC): base_python_path: Path | None = field(init=False, repr=False) tools_python_path: Path | None = field(init=False, repr=False) py_version: str = field(init=False, repr=False) - sitecustomize_source_path: Path | None = field(default=None, init=False, repr=False) # Operation flags allow for requested commands to be applied only to selected layers # Notes: @@ -1387,7 +1382,7 @@ def create_archive( ) work_path = self.build_path # /tmp is likely too small for ML environments return build_request.create_archive( - env_path, previous_metadata, self.sitecustomize_source_path, work_path + env_path, previous_metadata, work_path ) def request_export( @@ -1415,7 +1410,7 @@ def export_environment( # Define the input metadata that gets published in the export manifest export_request = self.request_export(output_path, previous_metadata, force) return export_request.export_environment( - env_path, previous_metadata, self.sitecustomize_source_path + env_path, previous_metadata, ) @@ -1632,7 +1627,6 @@ def env_spec(self) -> ApplicationSpec: def __post_init__(self) -> None: super().__post_init__() - self.sitecustomize_source_path = self.pylib_path / "_deployed_sitecustomize.py" self.launch_module_name = self.env_spec.launch_module_path.stem self.linked_frameworks = [] From 2e474c8413ac5f5e4296f24f66899c06b6bc355a Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 8 Nov 2024 13:17:13 +1000 Subject: [PATCH 07/12] Tidy up env base Python config --- src/venvstacks/stacks.py | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index e8a0ee2..f83ce2a 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -956,6 +956,10 @@ def get_build_platform() -> TargetPlatform: @dataclass class _PythonEnvironment(ABC): + + # Python environment used to run tools like `uv` and `pip` + tools_python_path: ClassVar[Path] = Path(sys.executable) + # Specified in concrete subclasses kind: ClassVar[LayerVariants] category: ClassVar[LayerCategories] @@ -974,11 +978,12 @@ class _PythonEnvironment(ABC): python_path: Path = field(init=False, repr=False) env_lock: EnvironmentLock = field(init=False) - # Set in subclass or externally after creation - base_python_path: Path | None = field(init=False, repr=False) - tools_python_path: Path | None = field(init=False, repr=False) + # Derived from layer spec in subclass __post_init__ py_version: str = field(init=False, repr=False) + # Set in subclass __post_init__, or when build environments are created + base_python_path: Path | None = field(init=False, repr=False) + # Operation flags allow for requested commands to be applied only to selected layers # Notes: # - the "build if needed" (want_build=None) option is fairly ineffective, since @@ -1017,6 +1022,9 @@ def get_deployed_path(self, build_path: Path) -> Path: return env_deployed_path / relative_path def __post_init__(self) -> None: + # Concrete subclasses must set the version before finishing the base initialisation + # Assert its existence here to make failures to do so easier to diagnose + assert self.py_version is not None, "Subclass failed to set 'py_version'" self.env_path = self.build_path / self.env_name self.pylib_path = self._get_py_scheme_path("purelib") self.executables_path = self._get_py_scheme_path("scripts") @@ -1089,9 +1097,8 @@ def from_external_path(target_build_path: Path) -> str: if link_external_base: base_python = from_external_path(base_python_path) else: - # "base_python" in the runtime layer refers solely to - # the external environment used to set up the base - # runtime layer, rather than being a linked environment + # "base_python" in a runtime layer refers to the layer itself + assert layer_python == from_internal_path(base_python_path) base_python = layer_python return postinstall.LayerConfig( @@ -1427,20 +1434,11 @@ def _get_python_dir_path(self) -> Path: return super()._get_python_dir_path() def __post_init__(self) -> None: - self.py_version = py_version = self.env_spec.py_version + # Ensure Python version is set before finishing base class initialisation + self.py_version = self.env_spec.py_version super().__post_init__() - tools_env_path = self.build_path / "build-tools" - if tools_env_path.exists(): - tools_bin_path = Path( - _get_py_scheme_path("scripts", tools_env_path, py_version) - ) - tools_python_path = tools_bin_path / _binary_with_extension("python") - else: - # No build tools environment created by wrapper script, so use the running Python - tools_python_path = Path(sys.executable) - # Runtimes have no base Python other than the build tools Python - self.base_python_path = tools_python_path - self.tools_python_path = tools_python_path + # Runtimes are their own base Python + self.base_python_path = self.python_path @property def env_spec(self) -> RuntimeSpec: @@ -1495,8 +1493,10 @@ class _VirtualEnvironment(_PythonEnvironment): linked_constraints_paths: list[Path] = field(init=False, repr=False) def __post_init__(self) -> None: + # Ensure Python version is set before finishing base class initialisation self.py_version = self.env_spec.runtime.py_version super().__post_init__() + # Base runtime env will be linked when creating the build environments self.base_runtime = None self.linked_constraints_paths = [] @@ -1517,7 +1517,6 @@ def link_base_runtime(self, runtime: RuntimeEnv) -> None: self.base_runtime = runtime # Link executable paths self.base_python_path = runtime.python_path - self.tools_python_path = runtime.tools_python_path # Link runtime layer dependency constraints if self.linked_constraints_paths: self._fail_build("Layered environment base runtime already linked") From 2d6d69bc6ead7363f518dccfd995f7734a6cce41 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 8 Nov 2024 13:52:36 +1000 Subject: [PATCH 08/12] Adjust for post-install changes --- src/venvstacks/stacks.py | 93 ++++++++++++++++++----------------- tests/support.py | 13 ++++- tests/test_minimal_project.py | 2 +- tests/test_sample_project.py | 2 +- 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index f83ce2a..17b5b8f 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -956,7 +956,6 @@ def get_build_platform() -> TargetPlatform: @dataclass class _PythonEnvironment(ABC): - # Python environment used to run tools like `uv` and `pip` tools_python_path: ClassVar[Path] = Path(sys.executable) @@ -1016,10 +1015,11 @@ def env_name(self) -> EnvNameBuild: def install_target(self) -> EnvNameDeploy: return self.env_lock.get_deployed_name(self.env_spec.env_name) - def get_deployed_path(self, build_path: Path) -> Path: + def get_deployed_path(self, build_path: Path) -> str: + """Get relative deployment location for a build env path""" env_deployed_path = Path(self.install_target) relative_path = build_path.relative_to(self.env_path) - return env_deployed_path / relative_path + return str(env_deployed_path / relative_path) def __post_init__(self) -> None: # Concrete subclasses must set the version before finishing the base initialisation @@ -1055,8 +1055,8 @@ def get_deployed_config(self) -> postinstall.LayerConfig: def _get_deployed_config( self, - pylib_paths: Iterable[Path], - dynlib_paths: Iterable[Path], + pylib_dirs: Iterable[str], + dynlib_dirs: Iterable[str], link_external_base: bool = True, ) -> postinstall.LayerConfig: # Helper for subclass get_deployed_config implementations @@ -1067,18 +1067,13 @@ def _get_deployed_config( build_env_name = build_env_path.name build_path = build_env_path.parent - def from_internal_path(target_build_path: Path) -> str: - # Input path is an absolute path inside the environment - # Output path is relative to the base of the environment - return str(target_build_path.relative_to(build_env_path)) - - def from_relative_path(relative_build_path: Path) -> str: + def relative_to_env(relative_build_path: Path) -> str: # Input path is relative to the base of the build directory # Output path is relative to the base of the environment # Note: we avoid `walk_up=True` here, firstly to maintain # Python 3.11 compatibility, but also to limit the # the relative paths to *peer* environments, rather - # than all potentially value relative path calculations + # than all potentially valid relative path calculations if relative_build_path.is_absolute(): self._fail_build(f"{relative_build_path} is not a relative path") if relative_build_path.parts[0] == build_env_name: @@ -1087,11 +1082,16 @@ def from_relative_path(relative_build_path: Path) -> str: # Emit relative reference to peer environment return str(Path("..", *relative_build_path.parts)) + def from_internal_path(target_build_path: Path) -> str: + # Input path is an absolute path inside the environment + # Output path is relative to the base of the environment + return str(target_build_path.relative_to(build_env_path)) + def from_external_path(target_build_path: Path) -> str: # Input path is an absolute path, potentially from a peer environment # Output path is relative to the base of the environment relative_build_path = target_build_path.relative_to(build_path) - return from_relative_path(relative_build_path) + return relative_to_env(relative_build_path) layer_python = from_internal_path(self.python_path) if link_external_base: @@ -1106,8 +1106,8 @@ def from_external_path(target_build_path: Path) -> str: py_version=self.py_version, base_python=base_python, site_dir=from_internal_path(self.pylib_path), - pylib_dirs=[from_relative_path(p) for p in pylib_paths], - dynlib_dirs=[from_relative_path(p) for p in dynlib_paths], + pylib_dirs=[relative_to_env(Path(d)) for d in pylib_dirs], + dynlib_dirs=[relative_to_env(Path(d)) for d in dynlib_dirs], ) def _write_deployed_config(self) -> None: @@ -1388,9 +1388,7 @@ def create_archive( output_path, target_platform, tag_output, previous_metadata, force ) work_path = self.build_path # /tmp is likely too small for ML environments - return build_request.create_archive( - env_path, previous_metadata, work_path - ) + return build_request.create_archive(env_path, previous_metadata, work_path) def request_export( self, @@ -1417,7 +1415,8 @@ def export_environment( # Define the input metadata that gets published in the export manifest export_request = self.request_export(output_path, previous_metadata, force) return export_request.export_environment( - env_path, previous_metadata, + env_path, + previous_metadata, ) @@ -1506,7 +1505,31 @@ def env_spec(self) -> _VirtualEnvironmentSpec: assert isinstance(self._env_spec, _VirtualEnvironmentSpec) return self._env_spec - # TODO: define interfaces for get_linked_pylib_paths and get_linked_dynlib_paths + def _linked_environments(self) -> Iterator[_PythonEnvironment]: + runtime_env = self.base_runtime + # This is only ever invoked *after* the environment has been linked + assert runtime_env is not None + yield runtime_env + + def _iter_build_pylib_dirs(self) -> Iterator[str]: + for env in self._linked_environments(): + yield str(env.pylib_path.relative_to(self.build_path)) + + def _iter_build_dynlib_dirs(self) -> Iterator[str]: + for env in self._linked_environments(): + dynlib_path = env.dynlib_path + if dynlib_path is not None: + yield str(dynlib_path.relative_to(self.build_path)) + + def _iter_deployed_pylib_dirs(self) -> Iterator[str]: + for env in self._linked_environments(): + yield env.get_deployed_path(env.pylib_path) + + def _iter_deployed_dynlib_dirs(self) -> Iterator[str]: + for env in self._linked_environments(): + dynlib_path = env.dynlib_path + if dynlib_path is not None: + yield env.get_deployed_path(dynlib_path) def link_base_runtime(self, runtime: RuntimeEnv) -> None: if self.base_runtime is not None: @@ -1526,7 +1549,7 @@ def link_base_runtime(self, runtime: RuntimeEnv) -> None: def get_deployed_config(self) -> postinstall.LayerConfig: """Layer config to be published in `venvstacks_layer.json`""" return self._get_deployed_config( - self.get_linked_pylib_paths(), self.get_linked_dynlib_paths() + self._iter_deployed_pylib_dirs(), self._iter_deployed_dynlib_dirs() ) def get_constraint_paths(self) -> list[Path]: @@ -1561,8 +1584,8 @@ def _ensure_virtual_environment(self) -> subprocess.CompletedProcess[str]: def _link_build_environment(self) -> None: # Create sitecustomize file for the build environment build_path = self.build_path - build_pylib_paths = [build_path / p for p in self.get_linked_pylib_paths()] - build_dynlib_paths = [build_path / p for p in self.get_linked_dynlib_paths()] + build_pylib_paths = [build_path / p for p in self._iter_build_pylib_dirs()] + build_dynlib_paths = [build_path / p for p in self._iter_build_dynlib_dirs()] sc_contents = postinstall.generate_sitecustomize( build_pylib_paths, build_dynlib_paths ) @@ -1632,29 +1655,7 @@ def __post_init__(self) -> None: def _linked_environments(self) -> Iterator[_PythonEnvironment]: for fw_env in self.linked_frameworks: yield fw_env - runtime_env = self.base_runtime - assert runtime_env is not None - yield runtime_env - - def _linked_pylib_build_paths(self) -> Iterator[Path]: - for env in self._linked_environments(): - yield env.pylib_path - - def _linked_dynlib_build_paths(self) -> Iterator[Path]: - for env in self._linked_environments(): - dynlib_path = env.dynlib_path - if dynlib_path is not None: - yield dynlib_path - - def _linked_pylib_deployed_paths(self) -> Iterator[Path]: - for env in self._linked_environments(): - yield env.get_deployed_path(env.pylib_path) - - def _linked_dynlib_deployed_paths(self) -> Iterator[Path]: - for env in self._linked_environments(): - dynlib_path = env.dynlib_path - if dynlib_path is not None: - yield env.get_deployed_path(dynlib_path) + yield from super()._linked_environments() def link_layered_environments( self, runtime: RuntimeEnv, frameworks: Mapping[LayerBaseName, FrameworkEnv] diff --git a/tests/support.py b/tests/support.py index 8b790f6..d26fc25 100644 --- a/tests/support.py +++ b/tests/support.py @@ -243,6 +243,12 @@ class DeploymentTestCase(unittest.TestCase): def assertPathExists(self, expected_path: Path) -> None: self.assertTrue(expected_path.exists(), f"No such path: {str(expected_path)}") + def assertPathContains(self, containing_path: Path, contained_path: Path) -> None: + self.assertTrue( + contained_path.is_relative_to(containing_path), + f"{str(containing_path)!r} is not a parent folder of {str(contained_path)!r}", + ) + def assertSysPathEntry(self, expected: str, env_sys_path: Sequence[str]) -> None: self.assertTrue( any(expected in path_entry for path_entry in env_sys_path), @@ -364,13 +370,16 @@ def check_deployed_environments( # Nothing at all should be emitted on stderr self.assertEqual(launch_result.stderr, "") - def check_environment_exports(self, export_paths: ExportedEnvironmentPaths) -> None: + def check_environment_exports( + self, export_path: Path, export_paths: ExportedEnvironmentPaths + ) -> None: metadata_path, snippet_paths, env_paths = export_paths exported_manifests = ManifestData(metadata_path, snippet_paths) env_name_to_path: dict[str, Path] = {} for env_metadata, env_path in zip(exported_manifests.snippet_data, env_paths): # TODO: Check more details regarding expected metadata contents - self.assertTrue(env_path.exists()) + self.assertPathExists(env_path) + self.assertPathContains(export_path, env_path) env_name = EnvNameDeploy(env_metadata["install_target"]) self.assertEqual(env_path.name, env_name) env_name_to_path[env_name] = env_path diff --git a/tests/test_minimal_project.py b/tests/test_minimal_project.py index 30932e1..7bd2160 100644 --- a/tests/test_minimal_project.py +++ b/tests/test_minimal_project.py @@ -489,7 +489,7 @@ def get_deployed_env_details( def test_create_environments(self) -> None: # Fast test to check the links between build envs are set up correctly - # (if this fails, there's no point even trying to full slow test case) + # (if this fails, there's no point even trying the full slow test case) build_env = self.build_env build_env.create_environments() self.check_build_environments(self.build_env.all_environments()) diff --git a/tests/test_sample_project.py b/tests/test_sample_project.py index 4755b2e..1e3b184 100644 --- a/tests/test_sample_project.py +++ b/tests/test_sample_project.py @@ -267,7 +267,7 @@ def setUp(self) -> None: def test_create_environments(self) -> None: # Fast test to check the links between build envs are set up correctly - # (if this fails, there's no point even trying to full slow test case) + # (if this fails, there's no point even trying the full slow test case) build_env = self.build_env build_env.create_environments() self.check_build_environments(self.build_env.all_environments()) From 594bf97f3fb9960e4d3323b30e057279ddf4b828 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 8 Nov 2024 13:58:19 +1000 Subject: [PATCH 09/12] Minor cleanup tweaks --- src/venvstacks/stacks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/venvstacks/stacks.py b/src/venvstacks/stacks.py index 17b5b8f..82a68fe 100755 --- a/src/venvstacks/stacks.py +++ b/src/venvstacks/stacks.py @@ -1584,8 +1584,8 @@ def _ensure_virtual_environment(self) -> subprocess.CompletedProcess[str]: def _link_build_environment(self) -> None: # Create sitecustomize file for the build environment build_path = self.build_path - build_pylib_paths = [build_path / p for p in self._iter_build_pylib_dirs()] - build_dynlib_paths = [build_path / p for p in self._iter_build_dynlib_dirs()] + build_pylib_paths = [build_path / d for d in self._iter_build_pylib_dirs()] + build_dynlib_paths = [build_path / d for d in self._iter_build_dynlib_dirs()] sc_contents = postinstall.generate_sitecustomize( build_pylib_paths, build_dynlib_paths ) @@ -1653,6 +1653,7 @@ def __post_init__(self) -> None: self.linked_frameworks = [] def _linked_environments(self) -> Iterator[_PythonEnvironment]: + # Linked frameworks are emitted before the base runtime layer for fw_env in self.linked_frameworks: yield fw_env yield from super()._linked_environments() From 152524ad1f810cb84b06da1df824889a1fab92f9 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 8 Nov 2024 14:05:49 +1000 Subject: [PATCH 10/12] Trigger output updates when draft PRs are marked as ready --- .github/workflows/update-expected-output.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-expected-output.yml b/.github/workflows/update-expected-output.yml index b3b2672..71bef16 100644 --- a/.github/workflows/update-expected-output.yml +++ b/.github/workflows/update-expected-output.yml @@ -2,9 +2,10 @@ name: Update expected output on: pull_request: - # Don't update PRs on every push. PRs can be closed and - # reopened if the update action should be run again. - types: [opened, reopened] + # Don't update PRs on every push. PRs can be switched + # to draft status and back (or closed and reopened), + # if the update action should be run again. + types: [opened, reopened, ready_for_review] branches: - "**" paths: From e4b61278e384c46caf3a1517fe95185cf1459237 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:21:12 +1000 Subject: [PATCH 11/12] Update expected output (2024-11-08 04:06:31+00:00) (#76) Update expected test output files from automated/expected-output/20241108-040631-152524a (source PR: #64) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../env_metadata/app-scipy-client.json | 6 ++--- .../env_metadata/app-scipy-import.json | 8 +++---- .../env_metadata/framework-scipy.json | 8 +++---- .../linux_x86_64/venvstacks.json | 22 ++++++++--------- .../env_metadata/app-scipy-client.json | 6 ++--- .../env_metadata/app-scipy-import.json | 8 +++---- .../env_metadata/framework-scipy.json | 8 +++---- .../macosx_arm64/venvstacks.json | 22 ++++++++--------- .../env_metadata/app-scipy-client.json | 6 ++--- .../env_metadata/app-scipy-import.json | 10 ++++---- .../env_metadata/framework-scipy.json | 8 +++---- .../win_amd64/venvstacks.json | 24 +++++++++---------- 12 files changed, 68 insertions(+), 68 deletions(-) diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json index 8a70e77..351ad8f 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "bb594ea66705fe5a122e930e2c48f1aaf6f720d568e37e0b590db95fb7261dea" + "sha256": "d932e554c35c9ce2cd1d594cb20e8a37c0195a5b82ffcb50627a96fc122e79a2" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 3004, + "archive_size": 3008, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.205589+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json index 64b962f..91213b7 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "8d69cfe0f408ba396dde664cd58c18b4541e6937f470e6e4f06a03d6ec069e46" + "sha256": "ec5be5ebc608e24bf32642cf0e071ce975f4650dac69c233c36124e53f4c10f9" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 2912, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.173589+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json index ae73caf..91978f2 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "e8ef68225cfa6a016539a4db3c5dc1b984f53de0df51181eefeb0e9449771ea9" + "sha256": "622e3056ccf54d8723bf983c92f35bf4138d2fee5da3cdd56d25391f18906aab" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 23957800, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 23961760, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:42.825586+00:00", diff --git a/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json b/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json index c9818e3..973d2e5 100644 --- a/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json +++ b/tests/sample_project/expected_manifests/linux_x86_64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "8d69cfe0f408ba396dde664cd58c18b4541e6937f470e6e4f06a03d6ec069e46" + "sha256": "ec5be5ebc608e24bf32642cf0e071ce975f4650dac69c233c36124e53f4c10f9" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 2912, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.173589+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "bb594ea66705fe5a122e930e2c48f1aaf6f720d568e37e0b590db95fb7261dea" + "sha256": "d932e554c35c9ce2cd1d594cb20e8a37c0195a5b82ffcb50627a96fc122e79a2" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 3004, + "archive_size": 3008, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:43.205589+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", @@ -67,11 +67,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "e8ef68225cfa6a016539a4db3c5dc1b984f53de0df51181eefeb0e9449771ea9" + "sha256": "622e3056ccf54d8723bf983c92f35bf4138d2fee5da3cdd56d25391f18906aab" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 23957800, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 23961760, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:42.825586+00:00", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json index 2282818..290b09b 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "bf065fe724e53e03886117ff0a7d61e29910da9c46b4a14799581cfc1238c77f" + "sha256": "f0338c45382c53320d30dc99e4370075de52593adb46a969f0692e772dcfb3ca" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 2980, + "archive_size": 2984, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.147967+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json index 40a1486..cd4588b 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "3ab7e8458a233e96790809ad0437209bcbf1823d7883220a44554b1c3fd51afa" + "sha256": "3ef2198496159dca41b2fa5cdea6ec0afb40b6060f95f23dc3da02e99e2d435f" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 2896, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.121208+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json index 996c5bd..0735cfd 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "6872599275f0b5448926033968ba5f3467b07bf09ac19af8538975a39bf7b712" + "sha256": "32f6135ea3b938e47c8897b0da7a51c6992397edbefe2b27358665b1c83d29aa" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 15078848, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 15076180, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:32.960668+00:00", diff --git a/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json b/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json index 1006d12..08d663a 100644 --- a/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json +++ b/tests/sample_project/expected_manifests/macosx_arm64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "3ab7e8458a233e96790809ad0437209bcbf1823d7883220a44554b1c3fd51afa" + "sha256": "3ef2198496159dca41b2fa5cdea6ec0afb40b6060f95f23dc3da02e99e2d435f" }, - "archive_name": "app-scipy-import.tar.xz", + "archive_name": "app-scipy-import@1.tar.xz", "archive_size": 2896, - "install_target": "app-scipy-import", + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.121208+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:36b0dbfec94b7de6507f348f0823cd02fdca2ea79eeafe92d571c26ae347d150", "runtime_name": "cpython@3.11", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "bf065fe724e53e03886117ff0a7d61e29910da9c46b4a14799581cfc1238c77f" + "sha256": "f0338c45382c53320d30dc99e4370075de52593adb46a969f0692e772dcfb3ca" }, "archive_name": "app-scipy-client.tar.xz", - "archive_size": 2980, + "archive_size": 2984, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:23:33.147967+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:fb8a843c694d03d7ee74b457cdac2bd82b6b439de0ed308d72fe698c6c9c6cf4", @@ -47,11 +47,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "6872599275f0b5448926033968ba5f3467b07bf09ac19af8538975a39bf7b712" + "sha256": "32f6135ea3b938e47c8897b0da7a51c6992397edbefe2b27358665b1c83d29aa" }, - "archive_name": "framework-scipy.tar.xz", - "archive_size": 15078848, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.tar.xz", + "archive_size": 15076180, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:23:32.960668+00:00", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json index 0c350fb..4bf772b 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-client.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "9f3de2bf483797a9a93629feca94756de57d82e62b157a4836b96fa14a289180" + "sha256": "ca15fb796933f031340de069d53f6d3a821e481b1372eb4ff001368ac92a214c" }, "archive_name": "app-scipy-client.zip", - "archive_size": 257112, + "archive_size": 257117, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.468633+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:3bff0428616a2f1724732e78e7788e753dd5f1aa10aa5d3b87707b8dbde121de", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json index f679796..b68d0a2 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/app-scipy-import.json @@ -3,16 +3,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "3f4e2a19a1611db1139f9e68a268a963dd30139690ee6d8325896265007bf823" + "sha256": "9eae1f6e63422d58ccef53ae199ac55884c50f19e1faf5ecd98c2dfc651ce723" }, - "archive_name": "app-scipy-import.zip", - "archive_size": 256621, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.zip", + "archive_size": 256677, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.386938+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:9aba38b5efe287f35d58825dce6b1c47ed556b930056e6edc00ca9e1a165796b", "runtime_name": "cpython@3.11.10", diff --git a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json index 34fa1a6..827d795 100644 --- a/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json +++ b/tests/sample_project/expected_manifests/win_amd64/env_metadata/framework-scipy.json @@ -1,11 +1,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "71146182f2bcf36ed9af674ac146ee32228e8d0a2890fb9c51ebd87e7fe58b45" + "sha256": "ac2c6a48192ac3657c5cbec001aeddf48ddd45881ac86a0cfa9eb5b839d2e3d4" }, - "archive_name": "framework-scipy.zip", - "archive_size": 45080726, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.zip", + "archive_size": 45087226, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:24:35.999197+00:00", diff --git a/tests/sample_project/expected_manifests/win_amd64/venvstacks.json b/tests/sample_project/expected_manifests/win_amd64/venvstacks.json index b21d903..73a7469 100644 --- a/tests/sample_project/expected_manifests/win_amd64/venvstacks.json +++ b/tests/sample_project/expected_manifests/win_amd64/venvstacks.json @@ -6,16 +6,16 @@ "app_launch_module_hash": "sha256:d806d778921ad216c1f950886d27b4b77e5561fe3467046fec258805980cc6d1", "archive_build": 1, "archive_hashes": { - "sha256": "3f4e2a19a1611db1139f9e68a268a963dd30139690ee6d8325896265007bf823" + "sha256": "9eae1f6e63422d58ccef53ae199ac55884c50f19e1faf5ecd98c2dfc651ce723" }, - "archive_name": "app-scipy-import.zip", - "archive_size": 256621, - "install_target": "app-scipy-import", + "archive_name": "app-scipy-import@1.zip", + "archive_size": 256677, + "install_target": "app-scipy-import@1", "layer_name": "app-scipy-import", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.386938+00:00", "required_layers": [ - "framework-scipy" + "framework-scipy@1" ], "requirements_hash": "sha256:9aba38b5efe287f35d58825dce6b1c47ed556b930056e6edc00ca9e1a165796b", "runtime_name": "cpython@3.11.10", @@ -26,16 +26,16 @@ "app_launch_module_hash": "sha256/bbe4da6de13a8f13a05cdd2bb3b90884861a6636b1450248d03aea799a7fc828", "archive_build": 1, "archive_hashes": { - "sha256": "9f3de2bf483797a9a93629feca94756de57d82e62b157a4836b96fa14a289180" + "sha256": "ca15fb796933f031340de069d53f6d3a821e481b1372eb4ff001368ac92a214c" }, "archive_name": "app-scipy-client.zip", - "archive_size": 257112, + "archive_size": 257117, "install_target": "app-scipy-client", "layer_name": "app-scipy-client", "lock_version": 1, "locked_at": "2024-10-15T10:24:36.468633+00:00", "required_layers": [ - "framework-scipy", + "framework-scipy@1", "framework-http-client" ], "requirements_hash": "sha256:3bff0428616a2f1724732e78e7788e753dd5f1aa10aa5d3b87707b8dbde121de", @@ -47,11 +47,11 @@ { "archive_build": 1, "archive_hashes": { - "sha256": "71146182f2bcf36ed9af674ac146ee32228e8d0a2890fb9c51ebd87e7fe58b45" + "sha256": "ac2c6a48192ac3657c5cbec001aeddf48ddd45881ac86a0cfa9eb5b839d2e3d4" }, - "archive_name": "framework-scipy.zip", - "archive_size": 45080726, - "install_target": "framework-scipy", + "archive_name": "framework-scipy@1.zip", + "archive_size": 45087226, + "install_target": "framework-scipy@1", "layer_name": "framework-scipy", "lock_version": 1, "locked_at": "2024-10-15T10:24:35.999197+00:00", From bc00964f3dc84a8c543ae723112a8ca6b00b8cee Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Fri, 8 Nov 2024 16:55:03 +1000 Subject: [PATCH 12/12] Docs fixes, add release note --- ...08_162952_ncoghlan_fix_automatic_layer_versioning.rst | 9 +++++++++ docs/api/stacks/venvstacks.stacks.ApplicationEnv.rst | 5 ++--- docs/api/stacks/venvstacks.stacks.FrameworkEnv.rst | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 changelog.d/20241108_162952_ncoghlan_fix_automatic_layer_versioning.rst diff --git a/changelog.d/20241108_162952_ncoghlan_fix_automatic_layer_versioning.rst b/changelog.d/20241108_162952_ncoghlan_fix_automatic_layer_versioning.rst new file mode 100644 index 0000000..55d7fbf --- /dev/null +++ b/changelog.d/20241108_162952_ncoghlan_fix_automatic_layer_versioning.rst @@ -0,0 +1,9 @@ +Added +----- + +- Setting ``versioned = True`` in a layer definition will append a + lock version number to the layer name that automatically increments + each time the locked requirements change for that layer (``layer@1``, + ``layer@2``, etc). Layer dependency declarations and build environments, + use the unversioned name, but deployed environments and their metadata + will use the versioned name (implemented in :issue:`24`). diff --git a/docs/api/stacks/venvstacks.stacks.ApplicationEnv.rst b/docs/api/stacks/venvstacks.stacks.ApplicationEnv.rst index 8fa92f4..dca1c1e 100644 --- a/docs/api/stacks/venvstacks.stacks.ApplicationEnv.rst +++ b/docs/api/stacks/venvstacks.stacks.ApplicationEnv.rst @@ -15,7 +15,7 @@ venvstacks.stacks.ApplicationEnv ~ApplicationEnv.export_environment ~ApplicationEnv.get_constraint_paths ~ApplicationEnv.install_requirements - ~ApplicationEnv.link_base_runtime_paths + ~ApplicationEnv.link_base_runtime ~ApplicationEnv.link_layered_environments ~ApplicationEnv.lock_requirements ~ApplicationEnv.report_python_site_details @@ -26,6 +26,7 @@ venvstacks.stacks.ApplicationEnv .. autosummary:: + ~FrameworkEnv.base_runtime ~ApplicationEnv.category ~ApplicationEnv.env_name ~ApplicationEnv.env_spec @@ -33,9 +34,7 @@ venvstacks.stacks.ApplicationEnv ~ApplicationEnv.kind ~ApplicationEnv.launch_module_name ~ApplicationEnv.linked_constraints_paths - ~ApplicationEnv.linked_dynlib_paths ~ApplicationEnv.linked_frameworks - ~ApplicationEnv.linked_pylib_paths ~ApplicationEnv.want_build ~ApplicationEnv.want_lock ~ApplicationEnv.want_publish diff --git a/docs/api/stacks/venvstacks.stacks.FrameworkEnv.rst b/docs/api/stacks/venvstacks.stacks.FrameworkEnv.rst index 14e21ee..d0aa889 100644 --- a/docs/api/stacks/venvstacks.stacks.FrameworkEnv.rst +++ b/docs/api/stacks/venvstacks.stacks.FrameworkEnv.rst @@ -16,7 +16,7 @@ venvstacks.stacks.FrameworkEnv ~FrameworkEnv.export_environment ~FrameworkEnv.get_constraint_paths ~FrameworkEnv.install_requirements - ~FrameworkEnv.link_base_runtime_paths + ~FrameworkEnv.link_base_runtime ~FrameworkEnv.lock_requirements ~FrameworkEnv.report_python_site_details ~FrameworkEnv.request_export @@ -26,6 +26,7 @@ venvstacks.stacks.FrameworkEnv .. autosummary:: + ~FrameworkEnv.base_runtime ~FrameworkEnv.category ~FrameworkEnv.env_name ~FrameworkEnv.env_spec