From bf4dcf8f501b5a14a618ad19a4bdd7d52b0e86e3 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:23:37 +0530 Subject: [PATCH 01/13] Replace `appdirs` with `platformdirs` --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 076a755..49a2459 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ - "appdirs", + "platformdirs", "networkx", "pyyaml", "requests", From 3e3fc97b1dcfe3c3179d5bb3d9452c79377c41fc Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:24:20 +0530 Subject: [PATCH 02/13] Use `user_cache_dir` from `platformdirs` --- empack/pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/empack/pack.py b/empack/pack.py index 652aba8..a3ac2c1 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -7,7 +7,7 @@ from tempfile import TemporaryDirectory from typing import Callable, Optional -from appdirs import user_cache_dir +from platformdirs import user_cache_dir from .filter_env import filter_env, filter_pkg, iterate_env_pkg_meta from .micromamba_wrapper import create_environment From e66b5fa34c9a71901954540942258495731fd447 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:24:46 +0530 Subject: [PATCH 03/13] Set `DEFAULT_CONFIG_PATH` to `user_config_dir` --- empack/pack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/empack/pack.py b/empack/pack.py index a3ac2c1..ee51d39 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -7,7 +7,7 @@ from tempfile import TemporaryDirectory from typing import Callable, Optional -from platformdirs import user_cache_dir +from platformdirs import user_cache_dir, user_config_dir from .filter_env import filter_env, filter_pkg, iterate_env_pkg_meta from .micromamba_wrapper import create_environment @@ -16,7 +16,7 @@ EMPACK_CACHE_DIR = Path(user_cache_dir("empack")) PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -DEFAULT_CONFIG_PATH = Path(sys.prefix) / "share" / "empack" / "empack_config.yaml" +DEFAULT_CONFIG_PATH = Path(user_config_dir("empack")) / "empack_config.yaml" def filename_base_from_meta(pkg_meta): From 8739917b77dcfad7f99e10145df881cbb60c5a2c Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:30:21 +0530 Subject: [PATCH 04/13] Move `empack_config.yaml` to inside the project --- {config => empack}/empack_config.yaml | 0 empack/pack.py | 5 +++-- pyproject.toml | 3 --- tests/conftest.py | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) rename {config => empack}/empack_config.yaml (100%) diff --git a/config/empack_config.yaml b/empack/empack_config.yaml similarity index 100% rename from config/empack_config.yaml rename to empack/empack_config.yaml diff --git a/empack/pack.py b/empack/pack.py index ee51d39..53fe533 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -7,7 +7,7 @@ from tempfile import TemporaryDirectory from typing import Callable, Optional -from platformdirs import user_cache_dir, user_config_dir +from platformdirs import user_cache_dir from .filter_env import filter_env, filter_pkg, iterate_env_pkg_meta from .micromamba_wrapper import create_environment @@ -16,7 +16,8 @@ EMPACK_CACHE_DIR = Path(user_cache_dir("empack")) PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -DEFAULT_CONFIG_PATH = Path(user_config_dir("empack")) / "empack_config.yaml" +# Ensure that the config is tied to a particular installation of empack +DEFAULT_CONFIG_PATH = Path(__file__).parent / "empack_config.yaml" def filename_base_from_meta(pkg_meta): diff --git a/pyproject.toml b/pyproject.toml index 49a2459..dd19ea7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,9 +48,6 @@ empack = "empack.cli.main:app" [project.urls] Homepage = "https://github.com/emscripten-forge/empack" -[tool.hatch.build.targets.wheel.shared-data] -config = "share/empack" - [tool.hatch.build.targets.sdist] exclude = [ ".github", diff --git a/tests/conftest.py b/tests/conftest.py index 6eaf048..666412c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,9 +5,9 @@ import pytest from empack.file_patterns import pkg_file_filter_from_yaml +from empack.pack import DEFAULT_CONFIG_PATH -THIS_DIR = os.path.dirname(os.path.realpath(__file__)) -CONFIG_PATH = os.path.join(THIS_DIR, "..", "config", "empack_config.yaml") +CONFIG_PATH = DEFAULT_CONFIG_PATH FILE_FILTERS = pkg_file_filter_from_yaml(CONFIG_PATH) CHANNELS = ["conda-forge", "https://repo.mamba.pm/emscripten-forge"] From 615a34b3a4704af921a0f56c1f40d7881d06b12c Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 20:08:42 +0530 Subject: [PATCH 05/13] Revert "Move `empack_config.yaml` to inside the project" This reverts commit 8739917b77dcfad7f99e10145df881cbb60c5a2c. --- {empack => config}/empack_config.yaml | 0 empack/pack.py | 5 ++--- pyproject.toml | 3 +++ tests/conftest.py | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) rename {empack => config}/empack_config.yaml (100%) diff --git a/empack/empack_config.yaml b/config/empack_config.yaml similarity index 100% rename from empack/empack_config.yaml rename to config/empack_config.yaml diff --git a/empack/pack.py b/empack/pack.py index 53fe533..ee51d39 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -7,7 +7,7 @@ from tempfile import TemporaryDirectory from typing import Callable, Optional -from platformdirs import user_cache_dir +from platformdirs import user_cache_dir, user_config_dir from .filter_env import filter_env, filter_pkg, iterate_env_pkg_meta from .micromamba_wrapper import create_environment @@ -16,8 +16,7 @@ EMPACK_CACHE_DIR = Path(user_cache_dir("empack")) PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -# Ensure that the config is tied to a particular installation of empack -DEFAULT_CONFIG_PATH = Path(__file__).parent / "empack_config.yaml" +DEFAULT_CONFIG_PATH = Path(user_config_dir("empack")) / "empack_config.yaml" def filename_base_from_meta(pkg_meta): diff --git a/pyproject.toml b/pyproject.toml index dd19ea7..49a2459 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,9 @@ empack = "empack.cli.main:app" [project.urls] Homepage = "https://github.com/emscripten-forge/empack" +[tool.hatch.build.targets.wheel.shared-data] +config = "share/empack" + [tool.hatch.build.targets.sdist] exclude = [ ".github", diff --git a/tests/conftest.py b/tests/conftest.py index 666412c..6eaf048 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,9 +5,9 @@ import pytest from empack.file_patterns import pkg_file_filter_from_yaml -from empack.pack import DEFAULT_CONFIG_PATH -CONFIG_PATH = DEFAULT_CONFIG_PATH +THIS_DIR = os.path.dirname(os.path.realpath(__file__)) +CONFIG_PATH = os.path.join(THIS_DIR, "..", "config", "empack_config.yaml") FILE_FILTERS = pkg_file_filter_from_yaml(CONFIG_PATH) CHANNELS = ["conda-forge", "https://repo.mamba.pm/emscripten-forge"] From 7b318ff6c852c164ec6dc1c235239ea1028c198d Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 20:10:57 +0530 Subject: [PATCH 06/13] Revert "Set `DEFAULT_CONFIG_PATH` to `user_config_dir`" This reverts commit e66b5fa34c9a71901954540942258495731fd447. --- empack/pack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/empack/pack.py b/empack/pack.py index ee51d39..a3ac2c1 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -7,7 +7,7 @@ from tempfile import TemporaryDirectory from typing import Callable, Optional -from platformdirs import user_cache_dir, user_config_dir +from platformdirs import user_cache_dir from .filter_env import filter_env, filter_pkg, iterate_env_pkg_meta from .micromamba_wrapper import create_environment @@ -16,7 +16,7 @@ EMPACK_CACHE_DIR = Path(user_cache_dir("empack")) PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -DEFAULT_CONFIG_PATH = Path(user_config_dir("empack")) / "empack_config.yaml" +DEFAULT_CONFIG_PATH = Path(sys.prefix) / "share" / "empack" / "empack_config.yaml" def filename_base_from_meta(pkg_meta): From 76e940588713500365cadf2c40992716e2fb189b Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:23:33 +0530 Subject: [PATCH 07/13] Port `_do_i_own` helper method --- empack/pack.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/empack/pack.py b/empack/pack.py index a3ac2c1..c987c73 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -17,6 +17,39 @@ PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) DEFAULT_CONFIG_PATH = Path(sys.prefix) / "share" / "empack" / "empack_config.yaml" +def _do_i_own(path: str) -> bool: + """Verify if the current user has write access to the given path. Sourced from + https://github.com/jupyter/jupyter_core/blob/fa513c1550bbd1ebcc14a4a79eb8c5d95e3e23c9/jupyter_core/paths.py#L75-L99 + """ + # Copyright (c) Jupyter Development Team. + # Distributed under the terms of the Modified BSD License. + + # Derived from IPython.utils.path, which is + # Copyright (c) IPython Development Team. + # Distributed under the terms of the Modified BSD License. + + p = Path(path).resolve() + + while not p.exists() and p != p.parent: + p = p.parent + + # simplest check: owner by name + # not always implemented or available + try: + return p.owner() == os.getlogin() + except Exception: # noqa: S110 + pass + + if hasattr(os, "geteuid"): + try: + st = p.stat() + return st.st_uid == os.geteuid() + except (NotImplementedError, OSError): + # geteuid not always implemented + pass + + # no ownership checks worked, check write access + return os.access(p, os.W_OK) def filename_base_from_meta(pkg_meta): From 273966b19d026509e764d2587b5e80efa3b1425c Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:24:25 +0530 Subject: [PATCH 08/13] Check for both conda/virtualenv style venvs --- empack/pack.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/empack/pack.py b/empack/pack.py index c987c73..39a9f72 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -16,7 +16,8 @@ EMPACK_CACHE_DIR = Path(user_cache_dir("empack")) PACKED_PACKAGES_CACHE_DIR = EMPACK_CACHE_DIR / "packed_packages_cache" PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -DEFAULT_CONFIG_PATH = Path(sys.prefix) / "share" / "empack" / "empack_config.yaml" + + def _do_i_own(path: str) -> bool: """Verify if the current user has write access to the given path. Sourced from https://github.com/jupyter/jupyter_core/blob/fa513c1550bbd1ebcc14a4a79eb8c5d95e3e23c9/jupyter_core/paths.py#L75-L99 @@ -52,6 +53,43 @@ def _do_i_own(path: str) -> bool: return os.access(p, os.W_OK) +def get_config_path() -> Path: + # Copyright (c) Jupyter Development Team. + # Distributed under the terms of the Modified BSD License. + + # Derived from IPython.utils.path, which is + # Copyright (c) IPython Development Team. + # Distributed under the terms of the Modified BSD License. + + + # 1. Check for config in environment's share directory. This is applicable + # for conda/mamba/micromamba style environments. + prefix = None + if ("CONDA_PREFIX" in os.environ and + sys.prefix.startswith(os.environ["CONDA_PREFIX"]) and + os.environ.get("CONDA_DEFAULT_ENV", "base") != "base" and + _do_i_own(sys.prefix)): + prefix = Path(os.environ["CONDA_PREFIX"]) + else: + prefix = Path(sys.prefix) + + config_path = prefix / "share" / "empack" / "empack_config.yaml" + if config_path.exists(): + return config_path + + # 2. For virtual environments via virtualenv/venv/uv, check if share/ is next + # to the environment base directory. This is also applicable for the case + # where there's no virtual environment at all (--user install). + if sys.prefix != sys.base_prefix and _do_i_own(sys.prefix): + venv_parent = Path(sys.prefix).parent + parent_share = venv_parent / "share" / "empack" / "empack_config.yaml" + if parent_share.exists(): + return parent_share + + +DEFAULT_CONFIG_PATH = get_config_path() + + def filename_base_from_meta(pkg_meta): name = pkg_meta["name"] version = pkg_meta["version"] From 77f55e3f9a9dda6af5e44d28d79704175f46ffce Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 25 Jan 2025 02:48:12 +0530 Subject: [PATCH 09/13] Fix type annotation --- empack/pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/empack/pack.py b/empack/pack.py index 39a9f72..d8c1f06 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -18,7 +18,7 @@ PACKED_PACKAGES_CACHE_DIR.mkdir(parents=True, exist_ok=True) -def _do_i_own(path: str) -> bool: +def _do_i_own(path: str | Path) -> bool: """Verify if the current user has write access to the given path. Sourced from https://github.com/jupyter/jupyter_core/blob/fa513c1550bbd1ebcc14a4a79eb8c5d95e3e23c9/jupyter_core/paths.py#L75-L99 """ From 59cde9c30d1aac4d1c9c89737c554321031ecc42 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 25 Jan 2025 02:48:25 +0530 Subject: [PATCH 10/13] Add docstring --- empack/pack.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/empack/pack.py b/empack/pack.py index d8c1f06..c5effcd 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -54,6 +54,15 @@ def _do_i_own(path: str | Path) -> bool: def get_config_path() -> Path: + """Find the empack configuration file by checking common locations. + + This function checks for the config file in the following order: + 1. Inside the environment's share directory (conda-style environments) + 2. Inside a share/ directory next to a virtual environment + + Returns: + Path: Location of the empack_config.yaml file + """ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. From f8b075f91fb92dd6b9ef00fefd645632f35ba211 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:00:36 +0530 Subject: [PATCH 11/13] Fix linter error --- empack/pack.py | 11 ++++++----- empack/repodata.py | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/empack/pack.py b/empack/pack.py index c5effcd..a792c8c 100644 --- a/empack/pack.py +++ b/empack/pack.py @@ -70,14 +70,15 @@ def get_config_path() -> Path: # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. - # 1. Check for config in environment's share directory. This is applicable # for conda/mamba/micromamba style environments. prefix = None - if ("CONDA_PREFIX" in os.environ and - sys.prefix.startswith(os.environ["CONDA_PREFIX"]) and - os.environ.get("CONDA_DEFAULT_ENV", "base") != "base" and - _do_i_own(sys.prefix)): + if ( + "CONDA_PREFIX" in os.environ + and sys.prefix.startswith(os.environ["CONDA_PREFIX"]) + and os.environ.get("CONDA_DEFAULT_ENV", "base") != "base" + and _do_i_own(sys.prefix) + ): prefix = Path(os.environ["CONDA_PREFIX"]) else: prefix = Path(sys.prefix) diff --git a/empack/repodata.py b/empack/repodata.py index d985a52..f37c20b 100644 --- a/empack/repodata.py +++ b/empack/repodata.py @@ -66,9 +66,9 @@ def download_and_shrink_repodata(repodata_urls, outdir=None): raise RuntimeError("need'arch' / 'noarch' keys in repodata_urls") # download - repodata_urls[ - "arch" - ] = "https://beta.mamba.pm/get/emscripten-forge/emscripten-wasm32/repodata.json.bz2" + repodata_urls["arch"] = ( + "https://beta.mamba.pm/get/emscripten-forge/emscripten-wasm32/repodata.json.bz2" + ) repodata_urls["noarch"] = "https://beta.mamba.pm/get/conda-forge/noarch/repodata.json.bz2" repodata_response = {k: requests.get(url, timeout=10) for k, url in repodata_urls.items()} From ed052c862e4d8fddf653fe27ae505b62d02ac6c3 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:01:51 +0530 Subject: [PATCH 12/13] Install appdirs for tests --- .github/workflows/workflow.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index b8b9771..43eec48 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -48,6 +48,12 @@ jobs: run: | python -m pip install git+https://github.com/emscripten-forge/pyjs-code-runner --no-deps --ignore-installed + # Remove after https://github.com/emscripten-forge/pyjs-code-runner/pull/15 is merged. + - name: Install appdirs + shell: bash -l {0} + run: | + python -m pip install appdirs + - name: Run pytest shell: bash -l {0} run: | From 3b3a32ea25eb9ffe149109f5c201c51f90ca7e18 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 27 Jan 2025 19:25:03 +0530 Subject: [PATCH 13/13] Fix linter error again --- empack/repodata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/empack/repodata.py b/empack/repodata.py index f37c20b..d985a52 100644 --- a/empack/repodata.py +++ b/empack/repodata.py @@ -66,9 +66,9 @@ def download_and_shrink_repodata(repodata_urls, outdir=None): raise RuntimeError("need'arch' / 'noarch' keys in repodata_urls") # download - repodata_urls["arch"] = ( - "https://beta.mamba.pm/get/emscripten-forge/emscripten-wasm32/repodata.json.bz2" - ) + repodata_urls[ + "arch" + ] = "https://beta.mamba.pm/get/emscripten-forge/emscripten-wasm32/repodata.json.bz2" repodata_urls["noarch"] = "https://beta.mamba.pm/get/conda-forge/noarch/repodata.json.bz2" repodata_response = {k: requests.get(url, timeout=10) for k, url in repodata_urls.items()}