├── .cargo └── config.toml.disabled ├── .config └── 1espt │ └── PipelineAutobaseliningConfig.yml ├── .devcontainer ├── .p10k.zsh ├── Dockerfile ├── alpine-arm64 │ ├── Dockerfile │ └── devcontainer.json ├── alpine-x64 │ ├── Dockerfile │ └── devcontainer.json ├── devcontainer.json ├── fedora │ ├── Dockerfile │ └── devcontainer.json ├── linux-arm64 │ ├── Dockerfile │ └── devcontainer.json ├── linux-armhf │ ├── Dockerfile │ └── devcontainer.json ├── linux-homebrew │ ├── Dockerfile │ └── devcontainer.json ├── linux-x64 │ ├── Dockerfile │ └── devcontainer.json └── setup.sh ├── .github └── workflows │ ├── build.yml │ ├── lint.yml │ └── pr-check.yml ├── .gitignore ├── .vscode ├── extensions.json ├── settings.json └── shared.code-snippets ├── CODE_OF_CONDUCT.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── azure-pipelines ├── README.md ├── playground.yml ├── pre-release.yml └── stable.yml ├── crates ├── pet-conda │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── conda_info.rs │ │ ├── conda_rc.rs │ │ ├── env_variables.rs │ │ ├── environment_locations.rs │ │ ├── environments.rs │ │ ├── lib.rs │ │ ├── manager.rs │ │ ├── package.rs │ │ ├── telemetry.rs │ │ └── utils.rs │ └── tests │ │ ├── ci_test.rs │ │ ├── common.rs │ │ ├── conda_rc_test.rs │ │ ├── environment_locations_test.rs │ │ ├── environments_test.rs │ │ ├── lib_test.rs │ │ ├── manager_test.rs │ │ ├── package_test.rs │ │ ├── unix │ │ ├── anaconda3-2023.03-without-history │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ ├── python │ │ │ │ ├── python3 │ │ │ │ ├── python3.1 │ │ │ │ └── python3.10 │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.1.0-py310hca03da5_0.json │ │ │ │ ├── conda-build-3.23.3-py310hca03da5_0.json │ │ │ │ ├── pytest-7.1.2-py310hca03da5_0.json │ │ │ │ ├── python-3.10.9-hc0d8a6c_1.json │ │ │ │ ├── python-dateutil-2.8.2-pyhd3eb1b0_0.json │ │ │ │ └── python-fastjsonschema-2.16.2-py310hca03da5_0.json │ │ │ ├── condabin │ │ │ │ └── conda │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ ├── anaconda3-2023.03 │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ ├── python │ │ │ │ ├── python3 │ │ │ │ ├── python3.1 │ │ │ │ └── python3.10 │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.1.0-py310hca03da5_0.json │ │ │ │ ├── conda-build-3.23.3-py310hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── pytest-7.1.2-py310hca03da5_0.json │ │ │ │ ├── python-3.10.9-hc0d8a6c_1.json │ │ │ │ ├── python-dateutil-2.8.2-pyhd3eb1b0_0.json │ │ │ │ └── python-fastjsonschema-2.16.2-py310hca03da5_0.json │ │ │ ├── condabin │ │ │ │ └── conda │ │ │ └── envs │ │ │ │ ├── env_python_3 │ │ │ │ ├── bin │ │ │ │ │ ├── conda │ │ │ │ │ ├── python │ │ │ │ │ ├── python3 │ │ │ │ │ ├── python3.1 │ │ │ │ │ └── python3.12 │ │ │ │ └── conda-meta │ │ │ │ │ ├── history │ │ │ │ │ ├── pygments-2.17.2-pyhd8ed1ab_0.json │ │ │ │ │ ├── python-3.12.2-hdf0ec26_0_cpython.json │ │ │ │ │ ├── python-dateutil-2.8.2-pyhd8ed1ab_0.json │ │ │ │ │ └── python_abi-3.12-4_cp312.json │ │ │ │ ├── myenv │ │ │ │ ├── bin │ │ │ │ │ ├── python │ │ │ │ │ ├── python3 │ │ │ │ │ ├── python3.1 │ │ │ │ │ └── python3.10 │ │ │ │ └── conda-meta │ │ │ │ │ ├── history │ │ │ │ │ ├── pip-24.0-py310hca03da5_0.json │ │ │ │ │ ├── python-3.10.14-hb885b13_1.json │ │ │ │ │ └── readline-8.2-h1a28f6b_0.json │ │ │ │ └── without_python │ │ │ │ └── conda-meta │ │ │ │ └── history │ │ ├── conda_env_without_manager │ │ │ └── env_python_3 │ │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ ├── python │ │ │ │ ├── python3 │ │ │ │ ├── python3.1 │ │ │ │ └── python3.12 │ │ │ │ └── conda-meta │ │ │ │ ├── history │ │ │ │ ├── pygments-2.17.2-pyhd8ed1ab_0.json │ │ │ │ ├── python-3.12.2-hdf0ec26_0_cpython.json │ │ │ │ ├── python-dateutil-2.8.2-pyhd8ed1ab_0.json │ │ │ │ └── python_abi-3.12-4_cp312.json │ │ ├── conda_env_without_manager_but_found_in_history │ │ │ ├── env_python_3 │ │ │ │ ├── bin │ │ │ │ │ ├── conda │ │ │ │ │ ├── python │ │ │ │ │ ├── python3 │ │ │ │ │ ├── python3.1 │ │ │ │ │ └── python3.12 │ │ │ │ └── conda-meta │ │ │ │ │ ├── history │ │ │ │ │ ├── history_template │ │ │ │ │ ├── pygments-2.17.2-pyhd8ed1ab_0.json │ │ │ │ │ ├── python-3.12.2-hdf0ec26_0_cpython.json │ │ │ │ │ ├── python-dateutil-2.8.2-pyhd8ed1ab_0.json │ │ │ │ │ └── python_abi-3.12-4_cp312.json │ │ │ └── some_other_location │ │ │ │ └── conda_install │ │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ ├── python │ │ │ │ ├── python3 │ │ │ │ ├── python3.1 │ │ │ │ └── python3.10 │ │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.1.0-py310hca03da5_0.json │ │ │ │ ├── conda-build-3.23.3-py310hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── pytest-7.1.2-py310hca03da5_0.json │ │ │ │ ├── python-3.10.9-hc0d8a6c_1.json │ │ │ │ ├── python-dateutil-2.8.2-pyhd3eb1b0_0.json │ │ │ │ └── python-fastjsonschema-2.16.2-py310hca03da5_0.json │ │ │ │ ├── condabin │ │ │ │ └── conda │ │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ ├── conda_envs │ │ │ └── user_home │ │ │ │ └── miniconda3 │ │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ ├── python │ │ │ │ ├── python3 │ │ │ │ ├── python3.1 │ │ │ │ └── python3.10 │ │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.1.0-py310hca03da5_0.json │ │ │ │ ├── conda-build-3.23.3-py310hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── pytest-7.1.2-py310hca03da5_0.json │ │ │ │ ├── python-3.10.9-hc0d8a6c_1.json │ │ │ │ ├── python-dateutil-2.8.2-pyhd3eb1b0_0.json │ │ │ │ └── python-fastjsonschema-2.16.2-py310hca03da5_0.json │ │ │ │ ├── condabin │ │ │ │ └── conda │ │ │ │ └── envs │ │ │ │ ├── env_python_3 │ │ │ │ ├── bin │ │ │ │ │ ├── conda │ │ │ │ │ ├── python │ │ │ │ │ ├── python3 │ │ │ │ │ ├── python3.1 │ │ │ │ │ └── python3.12 │ │ │ │ └── conda-meta │ │ │ │ │ ├── history │ │ │ │ │ ├── pygments-2.17.2-pyhd8ed1ab_0.json │ │ │ │ │ ├── python-3.12.2-hdf0ec26_0_cpython.json │ │ │ │ │ ├── python-dateutil-2.8.2-pyhd8ed1ab_0.json │ │ │ │ │ └── python_abi-3.12-4_cp312.json │ │ │ │ ├── myenv │ │ │ │ ├── bin │ │ │ │ │ ├── python │ │ │ │ │ ├── python3 │ │ │ │ │ ├── python3.1 │ │ │ │ │ └── python3.10 │ │ │ │ └── conda-meta │ │ │ │ │ ├── history │ │ │ │ │ ├── pip-24.0-py310hca03da5_0.json │ │ │ │ │ ├── python-3.10.14-hb885b13_1.json │ │ │ │ │ └── readline-8.2-h1a28f6b_0.json │ │ │ │ └── without_python │ │ │ │ └── conda-meta │ │ │ │ └── history │ │ ├── conda_rc │ │ │ └── user_home │ │ │ │ └── .condarc │ │ ├── conda_rc_conda_root_var │ │ │ └── user_home │ │ │ │ ├── .condarc │ │ │ │ └── conda_root_variable_path │ │ │ │ └── .condarc │ │ ├── conda_rc_root │ │ │ ├── root │ │ │ │ └── etc │ │ │ │ │ └── conda │ │ │ │ │ └── .condarc │ │ │ └── user_home │ │ │ │ └── .condarc │ │ └── user_home_with_environments_txt │ │ │ └── .conda │ │ │ └── environments.txt │ │ └── utils_test.rs ├── pet-core │ ├── Cargo.toml │ └── src │ │ ├── arch.rs │ │ ├── env.rs │ │ ├── lib.rs │ │ ├── manager.rs │ │ ├── os_environment.rs │ │ ├── python_environment.rs │ │ ├── pyvenv_cfg.rs │ │ ├── reporter.rs │ │ └── telemetry │ │ ├── inaccurate_python_info.rs │ │ ├── missing_conda_info.rs │ │ ├── missing_poetry_info.rs │ │ ├── mod.rs │ │ └── refresh_performance.rs ├── pet-env-var-path │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pet-fs │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── path.rs ├── pet-global-virtualenvs │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pet-homebrew │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── env_variables.rs │ │ ├── environment_locations.rs │ │ ├── environments.rs │ │ ├── lib.rs │ │ └── sym_links.rs ├── pet-jsonrpc │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── server.rs ├── pet-linux-global-python │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pet-mac-commandlinetools │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-mac-python-org │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-mac-xcode │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-pipenv │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── env_variables.rs │ │ └── lib.rs ├── pet-pixi │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-poetry │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── config.rs │ │ ├── env_variables.rs │ │ ├── environment.rs │ │ ├── environment_locations.rs │ │ ├── environment_locations_spawn.rs │ │ ├── lib.rs │ │ ├── manager.rs │ │ ├── pyproject_toml.rs │ │ └── telemetry.rs │ └── tests │ │ ├── common.rs │ │ ├── config_test.rs │ │ └── unix │ │ ├── global_config_with_values │ │ └── user_home │ │ │ └── config_dir │ │ │ └── config.toml │ │ └── local_config_with_values │ │ ├── project_dir │ │ └── poetry.toml │ │ └── user_home │ │ └── config_dir │ │ └── config.toml ├── pet-pyenv │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── env_variables.rs │ │ ├── environment_locations.rs │ │ ├── environments.rs │ │ ├── lib.rs │ │ └── manager.rs │ └── tests │ │ ├── common.rs │ │ ├── pyenv_test.rs │ │ └── unix │ │ ├── pyenv │ │ ├── home │ │ │ └── opt │ │ │ │ └── homebrew │ │ │ │ └── bin │ │ │ │ └── pyenv │ │ └── user_home │ │ │ └── .pyenv │ │ │ └── versions │ │ │ ├── .DS_Store │ │ │ ├── 3.12.1 │ │ │ └── bin │ │ │ │ └── python │ │ │ ├── 3.12.1a3 │ │ │ └── bin │ │ │ │ └── python │ │ │ ├── 3.13-dev │ │ │ └── bin │ │ │ │ └── python │ │ │ ├── 3.9.9 │ │ │ └── bin │ │ │ │ └── python │ │ │ ├── anaconda-4.0.0 │ │ │ ├── bin │ │ │ │ ├── conda │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ ├── .conda_envs_dir_test │ │ │ │ ├── one │ │ │ │ ├── conda-meta │ │ │ │ │ ├── python-3.11.1-hdf0ec26_0_cpython.json │ │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ │ └── python │ │ │ │ └── two │ │ │ │ ├── conda-meta │ │ │ │ ├── python-3.11.1-hdf0ec26_0_cpython.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ │ └── python │ │ │ ├── anaconda3-2021.04 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── mambaforge-4.10.1-4 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── mambaforge │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── miniconda-latest │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── miniconda3-3.10-22.11.1-1 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── miniconda3-3.10.1 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── miniconda3-4.0.5 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── miniforge3-4.11.0-1 │ │ │ ├── bin │ │ │ │ └── python │ │ │ ├── conda-meta │ │ │ │ ├── conda-23.11.0-py311hca03da5_0.json │ │ │ │ ├── history │ │ │ │ ├── python-3.11.5-hb885b13_0.json │ │ │ │ └── python-slugify-5.0.2-pyhd3eb1b0_0.json │ │ │ └── envs │ │ │ │ └── .conda_envs_dir_test │ │ │ ├── my-virtual-env │ │ │ ├── bin │ │ │ │ └── python │ │ │ └── pyvenv.cfg │ │ │ ├── nogil-3.9.10-1 │ │ │ ├── bin │ │ │ │ └── python │ │ │ └── include │ │ │ │ └── python3.9 │ │ │ │ └── patchlevel.h │ │ │ └── pypy3.9-7.3.15 │ │ │ ├── bin │ │ │ └── python │ │ │ └── include │ │ │ └── pypy3.9 │ │ │ └── patchlevel.h │ │ └── pyenv_without_envs │ │ ├── home │ │ └── opt │ │ │ └── homebrew │ │ │ └── bin │ │ │ └── pyenv │ │ └── user_home │ │ └── somefile.txt ├── pet-python-utils │ ├── Cargo.toml │ ├── src │ │ ├── cache.rs │ │ ├── env.rs │ │ ├── executable.rs │ │ ├── fs_cache.rs │ │ ├── headers.rs │ │ ├── lib.rs │ │ ├── platform_dirs.rs │ │ └── version.rs │ └── tests │ │ ├── cache_test.rs │ │ ├── common.rs │ │ ├── executable_test.rs │ │ ├── sys_prefix_test.rs │ │ └── unix │ │ ├── executables │ │ ├── .venv │ │ │ ├── bin │ │ │ │ ├── python │ │ │ │ └── python3 │ │ │ └── pyvenv.cfg │ │ ├── conda_without_python │ │ │ └── conda-meta │ │ │ │ └── history │ │ └── python3.9.9 │ │ │ ├── bin │ │ │ ├── python3 │ │ │ └── python3.9.9 │ │ │ └── include │ │ │ └── patchlevel.h │ │ ├── headers │ │ ├── python3.10-dev │ │ │ ├── bin │ │ │ │ ├── python3 │ │ │ │ └── python3.9.9 │ │ │ └── include │ │ │ │ └── python3.10 │ │ │ │ └── patchlevel.h │ │ ├── python3.13 │ │ │ ├── bin │ │ │ │ ├── python3 │ │ │ │ └── python3.9.9 │ │ │ └── include │ │ │ │ └── python3.13 │ │ │ │ └── patchlevel.h │ │ └── python3.9.9 │ │ │ ├── bin │ │ │ ├── python3 │ │ │ └── python3.9.9 │ │ │ └── include │ │ │ └── patchlevel.h │ │ └── pyvenv_cfg │ │ ├── .venv │ │ ├── bin │ │ │ ├── python │ │ │ └── python3 │ │ └── pyvenv.cfg │ │ ├── hatch_env │ │ ├── bin │ │ │ └── python │ │ └── pyvenv.cfg │ │ └── python3.9.9_without_headers │ │ └── bin │ │ └── python ├── pet-reporter │ ├── Cargo.toml │ └── src │ │ ├── cache.rs │ │ ├── collect.rs │ │ ├── environment.rs │ │ ├── jsonrpc.rs │ │ ├── lib.rs │ │ └── stdio.rs ├── pet-telemetry │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pet-venv │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-virtualenv │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── pet-virtualenvwrapper │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── env_variables.rs │ │ ├── environment_locations.rs │ │ ├── environments.rs │ │ └── lib.rs ├── pet-windows-registry │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── environments.rs │ │ └── lib.rs ├── pet-windows-store │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── env_variables.rs │ │ ├── environment_locations.rs │ │ ├── environments.rs │ │ └── lib.rs └── pet │ ├── Cargo.toml │ ├── README.md │ ├── src │ ├── find.rs │ ├── jsonrpc.rs │ ├── lib.rs │ ├── locators.rs │ ├── main.rs │ └── resolve.rs │ └── tests │ ├── ci_homebrew_container.rs │ ├── ci_jupyter_container.rs │ ├── ci_poetry.rs │ ├── ci_test.rs │ ├── common.rs │ └── interpreterInfo.py └── docs ├── JSONRPC.md └── sample.js /.cargo/config.toml.disabled: -------------------------------------------------------------------------------- 1 | # [source.crates-io] 2 | # replace-with = 'ms-crates-io' 3 | 4 | # [registries.ms-crates-io] 5 | # index = "sparse+https://pkgs.dev.azure.com/vscode/_packaging/crates/Cargo/index/" 6 | 7 | # Windows: -Ctarget-feature=+crt-static: Statically link the CRT (required to link the spectre-mitigated CRT). 8 | # Other: -Ctarget-feature=+crt-static: Statically link the CRT 9 | [build] 10 | rustflags = ["-Ctarget-feature=+crt-static"] 11 | 12 | # -Cehcont_guard: Enable EH Continuation Metadata (https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-eh-continuation-metadata). 13 | # -Ccontrol-flow-guard: Enable Control Flow Guard, needed for OneBranch's post-build analysis (https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-control-flow-guard). 14 | # -Ctarget-feature=+crt-static: Statically link the CRT (required to link the spectre-mitigated CRT). 15 | [target.'cfg(target_os = "windows")'] 16 | rustflags = ["-Cehcont_guard", "-Ccontrol-flow-guard"] 17 | 18 | # -Clink-args=/DYNAMICBASE /CETCOMPAT: Enable "shadow stack" (https://learn.microsoft.com/en-us/cpp/build/reference/cetcompat) 19 | [target.'cfg(all(target_os = "windows", any(target_arch = "i686", target_arch = "x86_64")))'] 20 | rustflags = ["-Clink-args=/DYNAMICBASE /CETCOMPAT"] -------------------------------------------------------------------------------- /.config/1espt/PipelineAutobaseliningConfig.yml: -------------------------------------------------------------------------------- 1 | ## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details. 2 | 3 | pipelines: 4 | 591: 5 | retail: 6 | source: 7 | credscan: 8 | lastModifiedDate: 2024-10-01 9 | eslint: 10 | lastModifiedDate: 2024-10-01 11 | psscriptanalyzer: 12 | lastModifiedDate: 2024-10-01 13 | armory: 14 | lastModifiedDate: 2024-10-01 15 | binary: 16 | credscan: 17 | lastModifiedDate: 2024-10-01 18 | binskim: 19 | lastModifiedDate: 2025-02-10 20 | spotbugs: 21 | lastModifiedDate: 2024-10-01 22 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Based off, https://github.com/github/codespaces-jupyter 2 | FROM mcr.microsoft.com/devcontainers/universal:2 3 | 4 | RUN apt install curl -y 5 | RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 6 | -t powerlevel10k/powerlevel10k \ 7 | -p git \ 8 | -p git-extras \ 9 | -p https://github.com/zsh-users/zsh-completions 10 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 11 | RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 12 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 13 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 14 | # Install Rust 15 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y 16 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 17 | ENV PATH="/root/.cargo/bin:${PATH}" 18 | -------------------------------------------------------------------------------- /.devcontainer/alpine-arm64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm64v8/python:3.11-alpine 2 | RUN apk add gcc libc-dev linux-headers musl-dev zlib zlib-dev python3-dev curl 3 | RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 4 | -t powerlevel10k/powerlevel10k \ 5 | -p git \ 6 | -p git-extras \ 7 | -p https://github.com/zsh-users/zsh-completions 8 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 9 | RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 10 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 11 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 12 | # Install Rust 13 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y 14 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 15 | ENV PATH="/root/.cargo/bin:${PATH}" 16 | -------------------------------------------------------------------------------- /.devcontainer/alpine-arm64/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alpine-arm64", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/alpine-x64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amd64/python:3.11-alpine 2 | RUN apk add gcc libc-dev linux-headers musl-dev zlib zlib-dev python3-dev curl 3 | RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 4 | -t powerlevel10k/powerlevel10k \ 5 | -p git \ 6 | -p git-extras \ 7 | -p https://github.com/zsh-users/zsh-completions 8 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 9 | RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 10 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 11 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 12 | # Install Rust 13 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y 14 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 15 | ENV PATH="/root/.cargo/bin:${PATH}" 16 | -------------------------------------------------------------------------------- /.devcontainer/alpine-x64/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alpine-x64", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | // Based off, https://github.com/github/codespaces-jupyter 3 | // Making this the top level container so it works on codespaces, 4 | // Cannot always use locally as this is only x64 compatible 5 | "name": "codespaces-jupyter", 6 | "image": "mcr.microsoft.com/devcontainers/universal:2", 7 | "waitFor": "onCreateCommand", 8 | "postCreateCommand": "bash ./.devcontainer/setup.sh", 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-python.python@prerelease", 13 | "esbenp.prettier-vscode", 14 | "rust-lang.rust-analyzer", 15 | "EditorConfig.EditorConfig" 16 | ] 17 | } 18 | }, 19 | "workspaceFolder": "/workspaces/python-environment-tools" 20 | } -------------------------------------------------------------------------------- /.devcontainer/fedora/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora 2 | 3 | # Setup Python 4 | # https://developer.fedoraproject.org/tech/languages/python/multiple-pythons.html 5 | RUN sudo dnf install python3.9 python3.11 -y 6 | # zsh 7 | RUN sudo dnf install zsh git -y 8 | RUN sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" -y 9 | # Install Homebrew 10 | # Not supported on arm64 11 | # Install pyenv 12 | # Install Rust 13 | # https://developer.fedoraproject.org/tech/languages/rust/rust-installation.html 14 | RUN sudo dnf install rust cargo rustup -y 15 | -------------------------------------------------------------------------------- /.devcontainer/fedora/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fedora", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/linux-arm64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm64v8/ubuntu 2 | 3 | RUN apt-get update 4 | # zsh 5 | RUN apt-get install wget -y 6 | RUN sh -c "$(wget -qO- https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 7 | -t powerlevel10k/powerlevel10k \ 8 | -p git \ 9 | -p git-extras \ 10 | -p https://github.com/zsh-users/zsh-completions 11 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 12 | RUN wget -O ~/.p10k.zsh https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh 13 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 14 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 15 | # Install Rust 16 | RUN curl https://sh.rustup.rs -sSf | bash -s -- -y 17 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 18 | ENV PATH="/root/.cargo/bin:${PATH}" 19 | # Install Python 20 | RUN apt-get install -y build-essential 21 | RUN apt-get install -y --no-install-recommends software-properties-common build-essential 22 | RUN add-apt-repository -y ppa:deadsnakes/ppa 23 | RUN apt-get install python3.9 python3.10 python3-pip -y 24 | -------------------------------------------------------------------------------- /.devcontainer/linux-arm64/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-arm64", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/linux-armhf/Dockerfile: -------------------------------------------------------------------------------- 1 | # FROM arm32v7/ubuntu 2 | FROM arm32v7/python 3 | RUN apt-get update 4 | RUN apt-get install libatomic1 5 | # Install Rust 6 | RUN curl https://sh.rustup.rs -sSf | bash -s -- -y 7 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 8 | ENV PATH="/root/.cargo/bin:${PATH}" 9 | # Install Python 10 | # This image seems to come with Python 3.11 and 3.12 -------------------------------------------------------------------------------- /.devcontainer/linux-armhf/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-armhf", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/linux-homebrew/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM homebrew/brew 2 | 3 | RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 4 | -t powerlevel10k/powerlevel10k \ 5 | -p git \ 6 | -p git-extras \ 7 | -p https://github.com/zsh-users/zsh-completions 8 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 9 | RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 10 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 11 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 12 | 13 | # Install Python 14 | # homebrew/brew:4.4.6 broke running `brew install` as root. 15 | # As a workaround, running `brew update` and ignoring errors coming from it fixes `brew install`. 16 | RUN brew update || true 17 | RUN brew install python@3.12 python@3.11 18 | 19 | # Install Rust 20 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y 21 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 22 | ENV PATH="/root/.cargo/bin:${PATH}" 23 | -------------------------------------------------------------------------------- /.devcontainer/linux-homebrew/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-homebrew", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/linux-x64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amd64/ubuntu:24.04 2 | 3 | # Setup Python 4 | RUN apt-get update && \ 5 | apt-get install -y --no-install-recommends software-properties-common && \ 6 | add-apt-repository -y ppa:deadsnakes/ppa 7 | RUN apt-get install python3.9 python3.10 python3-pip -y 8 | # RUN apt install zsh -y 9 | # RUN chsh -s $(which zsh) 10 | # RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" 11 | # RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v1.1.1/zsh-in-docker.sh)" -- \ 12 | RUN apt install curl -y 13 | RUN sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 14 | -t powerlevel10k/powerlevel10k \ 15 | -p git \ 16 | -p git-extras \ 17 | -p https://github.com/zsh-users/zsh-completions 18 | RUN git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 19 | RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 20 | RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 21 | RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 22 | # Install Linuxbrew 23 | RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)" 24 | USER root 25 | ENV PATH="/home/linuxbrew/.linuxbrew/bin:${PATH}" 26 | RUN /home/linuxbrew/.linuxbrew/bin/brew install python@3.10 -q 27 | RUN /home/linuxbrew/.linuxbrew/bin/brew install python@3.12 -q 28 | # Install pyenv 29 | RUN sh -c "$(curl https://pyenv.run)" 30 | RUN echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc 31 | RUN echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc 32 | RUN echo 'eval "$(pyenv init -)"' >> ~/.zshrc 33 | # RUN pyenv install 3.10.11 34 | # Install Rust 35 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y 36 | RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 37 | ENV PATH="/root/.cargo/bin:${PATH}" 38 | -------------------------------------------------------------------------------- /.devcontainer/linux-x64/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-x64", 3 | "build": { 4 | "context": "../..", 5 | "dockerfile": "./Dockerfile" 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "ms-python.python@prerelease", 11 | "esbenp.prettier-vscode", 12 | "rust-lang.rust-analyzer", 13 | "EditorConfig.EditorConfig" 14 | ] 15 | } 16 | }, 17 | "workspaceFolder": "/workspaces/python-environment-tools" 18 | } -------------------------------------------------------------------------------- /.devcontainer/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # sh -c "$(curl -fsSL https://github.com/deluan/zsh-in-docker/releases/download/v1.1.5/zsh-in-docker.sh)" -- \ 5 | # -t powerlevel10k/powerlevel10k \ 6 | # -p git \ 7 | # -p git-extras \ 8 | # -p https://github.com/zsh-users/zsh-completions 9 | # git clone https://github.com/romkatv/powerlevel10k $HOME/.oh-my-zsh/custom/themes/powerlevel10k 10 | # curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/containerChanges/.devcontainer/.p10k.zsh > ~/.p10k.zsh 11 | # echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc 12 | # echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc 13 | 14 | # Install Rust 15 | curl https://sh.rustup.rs -sSf | sh -s -- -y 16 | echo 'source $HOME/.cargo/env' >> $HOME/.bashrc 17 | PATH="/root/.cargo/bin:${PATH}" 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release* 8 | - release/* 9 | - release-* 10 | 11 | jobs: 12 | build: 13 | name: Build 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | include: 19 | - os: windows-latest 20 | target: x86_64-pc-windows-msvc 21 | - os: windows-latest 22 | target: aarch64-pc-windows-msvc 23 | - os: ubuntu-latest 24 | target: x86_64-unknown-linux-musl 25 | # - os: ubuntu-latest 26 | # target: aarch64-unknown-linux-gnu 27 | # - os: ubuntu-latest 28 | # target: arm-unknown-linux-gnueabihf 29 | - os: macos-latest 30 | target: x86_64-apple-darwin 31 | - os: macos-14 32 | target: aarch64-apple-darwin 33 | # - os: ubuntu-latest 34 | # target: x86_64-unknown-linux-gnu 35 | # - os: ubuntu-latest 36 | # target: aarch64-unknown-linux-musl 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v4 40 | 41 | - name: Rust Tool Chain setup 42 | uses: dtolnay/rust-toolchain@stable 43 | with: 44 | toolchain: stable 45 | targets: ${{ matrix.target }} 46 | 47 | - name: Cargo Fetch 48 | run: cargo fetch 49 | 50 | - name: Build 51 | run: cargo build --release --target ${{ matrix.target }} 52 | 53 | - name: Upload Artifact 54 | uses: actions/upload-artifact@v4 55 | with: 56 | name: pet-${{ matrix.target }} 57 | path: target/${{ matrix.target }}/release/pet* 58 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches-ignore: 7 | - main 8 | - release* 9 | 10 | jobs: 11 | clippy: 12 | name: Clippy and Format Check 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Rust Tool Chain setup 19 | uses: dtolnay/rust-toolchain@stable 20 | with: 21 | toolchain: stable 22 | 23 | - name: Install clippy 24 | run: rustup component add clippy 25 | 26 | - name: Cargo Fetch 27 | run: cargo fetch 28 | 29 | - name: Check 30 | run: cargo fmt --all -- --check 31 | 32 | - name: Run Clippy 33 | run: cargo clippy --all-features -- -Dwarnings 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | # Directory with generated environments (generally created on CI) 13 | .DS_Store 14 | 15 | # Testing directories 16 | ./.venv/ 17 | tmp/ 18 | temp/ 19 | docs/node_modules/ 20 | docs/package.json 21 | docs/package-lock.json -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "rust-lang.rust-analyzer", 5 | "EditorConfig.EditorConfig" 6 | ] 7 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "[rust]": { 5 | "editor.defaultFormatter": "rust-lang.rust-analyzer" 6 | }, 7 | "[toml]": { 8 | "editor.defaultFormatter": "tamasfe.even-better-toml" 9 | }, 10 | "git.branchProtection": [ 11 | "main", 12 | "release/*" 13 | ], 14 | "git.branchProtectionPrompt": "alwaysCommitToNewBranch" 15 | } -------------------------------------------------------------------------------- /.vscode/shared.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | // Each snippet is defined under a snippet name and has a scope, prefix, body and 3 | // description. The scope defines in watch languages the snippet is applicable. The prefix is what is 4 | // used to trigger the snippet and the body will be expanded and inserted.Possible variables are: 5 | // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 6 | // Placeholders with the same ids are connected. 7 | "MSFT Copyright Header": { 8 | "scope": "rust", 9 | "prefix": [ 10 | "header", 11 | "copyright", 12 | "lic" 13 | ], 14 | "body": [ 15 | "// Copyright (c) Microsoft Corporation.", 16 | "// Licensed under the MIT License.", 17 | "", 18 | "$2" 19 | ], 20 | "description": "License Header" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*"] 3 | resolver = "2" 4 | 5 | [workspace.package] 6 | license = "MIT" 7 | 8 | [profile.release] 9 | # Enable all optimizations 10 | opt-level = 3 11 | # Enable full link-time-optimizations 12 | lto = true 13 | codegen-units = 1 14 | # Enable full debug info for optimized builds. 15 | debug = "full" 16 | # Split debuginfo into its own file to reduce binary size. 17 | split-debuginfo = "packed" 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python environment tools for Visual Studio Code 2 | 3 | Performant Python environment tooling and support, such as locating all global Python installs and virtual environments. 4 | 5 | This project will be consumed by the [Python extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python) directly. You can find the code to consume `pet` in the Python extension [source code](https://github.com/microsoft/vscode-python/blob/main/src/client/pythonEnvironments/base/locators/common/nativePythonFinder.ts). For more information on JSNORPC requests/notifications for this tool, please reference [/docs/JSONRPC.md](https://github.com/microsoft/python-environment-tools/blob/main/docs/JSONRPC.md). 6 | 7 | ## Environment Types Supported 8 | 9 | - python.org 10 | - Windows Store 11 | - PyEnv 12 | - PyEnv-Win 13 | - PyEnv-Virtualenv 14 | - Conda 15 | - Miniconda 16 | - Miniforge 17 | - PipEnv 18 | - Homebrew 19 | - VirtualEnvWrapper 20 | - VirtualEnvWrapper-Win 21 | - Venv 22 | - VirtualEnv 23 | - Python on your PATH 24 | 25 | ## Features 26 | 27 | - Discovery of all global Python installs 28 | - Discovery of all Python virtual environments 29 | 30 | ## Key Methodology 31 | 32 | Our approach prioritizes performance and efficiency by leveraging Rust. We minimize I/O operations by collecting all necessary environment information at once, which reduces repeated I/O and the need to spawn additional processes, significantly enhancing overall performance. 33 | 34 | ## Contributing 35 | 36 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 37 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 38 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 39 | 40 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 41 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 42 | provided by the bot. You will only need to do this once across all repos using our CLA. 43 | 44 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 45 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 46 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 47 | 48 | ## Trademarks 49 | 50 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 51 | trademarks or logos is subject to and must follow 52 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 53 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 54 | Any use of third-party trademarks or logos are subject to those third-party's policies. 55 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the [existing 6 | issues](https://github.com/microsoft/python-environment-tools/issues) before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | ## Microsoft Support Policy 10 | 11 | Support for this project is limited to the resources listed above. 12 | -------------------------------------------------------------------------------- /azure-pipelines/README.md: -------------------------------------------------------------------------------- 1 | pre-release.yml: This should build from the `main` branch and publish to the Azure Pipeline feed. This will be consumed by extensions that are also doing pre-release builds. Signing is required on this build. 2 | 3 | stable.yml: This should build from the `release/*` branch and publish to the Azure Pipeline feed. This will be consumed by extensions when publishing stable builds. Signing is required on this build. 4 | 5 | playground.yml: This pipeline is for engineering/testing purposes so we can do fixes and tests without affecting the pipeline feeds. This will not publish to the Azure Pipeline feed. Signing is not required on this build. 6 | -------------------------------------------------------------------------------- /azure-pipelines/playground.yml: -------------------------------------------------------------------------------- 1 | trigger: none 2 | pr: none 3 | # Should only ever be manually run. 4 | 5 | resources: 6 | repositories: 7 | - repository: templates 8 | type: github 9 | name: microsoft/vscode-engineering 10 | ref: main 11 | endpoint: Monaco 12 | 13 | extends: 14 | template: azure-pipelines/rust-package/pipeline.yml@templates 15 | parameters: 16 | binaryName: "pet" 17 | signing: false 18 | apiScanSoftwareVersion: 2024 # major version of `pet` for internal reporting 19 | 20 | buildPlatforms: 21 | - name: linux 22 | target: x86_64-unknown-linux-musl 23 | - name: linux 24 | target: aarch64-unknown-linux-gnu 25 | - name: linux 26 | target: armv7-unknown-linux-gnueabihf 27 | - name: darwin 28 | target: aarch64-apple-darwin 29 | - name: darwin 30 | target: x86_64-apple-darwin 31 | - name: windows 32 | target: aarch64-pc-windows-msvc 33 | - name: windows 34 | target: x86_64-pc-windows-msvc 35 | 36 | preBuildSteps: 37 | - pwsh: Rename-Item -Path "./.cargo/config.toml.disabled" -NewName "config.toml" 38 | displayName: "Enable Azure Build config for Rust" 39 | -------------------------------------------------------------------------------- /azure-pipelines/pre-release.yml: -------------------------------------------------------------------------------- 1 | # Run on a schedule 2 | trigger: 3 | branches: 4 | include: 5 | - main 6 | pr: none 7 | 8 | resources: 9 | repositories: 10 | - repository: templates 11 | type: github 12 | name: microsoft/vscode-engineering 13 | ref: main 14 | endpoint: Monaco 15 | 16 | extends: 17 | template: azure-pipelines/rust-package/pipeline.yml@templates 18 | parameters: 19 | binaryName: "pet" 20 | signing: true 21 | apiScanSoftwareVersion: 2024 # major version of `pet` for internal reporting 22 | tsa: 23 | enabled: true 24 | config: 25 | areaPath: "Visual Studio Code Python Extensions" 26 | serviceTreeID: 6e6194bc-7baa-4486-86d0-9f5419626d46 27 | 28 | buildPlatforms: 29 | - name: linux 30 | target: x86_64-unknown-linux-musl 31 | - name: linux 32 | target: aarch64-unknown-linux-gnu 33 | - name: linux 34 | target: armv7-unknown-linux-gnueabihf 35 | - name: darwin 36 | target: aarch64-apple-darwin 37 | - name: darwin 38 | target: x86_64-apple-darwin 39 | - name: windows 40 | target: aarch64-pc-windows-msvc 41 | - name: windows 42 | target: x86_64-pc-windows-msvc 43 | 44 | preBuildSteps: 45 | - pwsh: Rename-Item -Path "./.cargo/config.toml.disabled" -NewName "config.toml" 46 | displayName: "Enable Azure Build config for Rust" 47 | -------------------------------------------------------------------------------- /azure-pipelines/stable.yml: -------------------------------------------------------------------------------- 1 | trigger: none 2 | pr: none 3 | # Should only ever be manually run. 4 | 5 | resources: 6 | repositories: 7 | - repository: templates 8 | type: github 9 | name: microsoft/vscode-engineering 10 | ref: main 11 | endpoint: Monaco 12 | 13 | extends: 14 | template: azure-pipelines/rust-package/pipeline.yml@templates 15 | parameters: 16 | binaryName: "pet" 17 | signing: true 18 | apiScanPublishSymbols: true 19 | apiScanSoftwareVersion: 2024 # major version of `pet` for internal reporting 20 | tsa: 21 | enabled: true 22 | config: 23 | areaPath: "Visual Studio Code Python Extensions" 24 | serviceTreeID: 6e6194bc-7baa-4486-86d0-9f5419626d46 25 | 26 | buildPlatforms: 27 | - name: linux 28 | target: x86_64-unknown-linux-musl 29 | - name: linux 30 | target: aarch64-unknown-linux-gnu 31 | - name: linux 32 | target: armv7-unknown-linux-gnueabihf 33 | - name: darwin 34 | target: aarch64-apple-darwin 35 | - name: darwin 36 | target: x86_64-apple-darwin 37 | - name: windows 38 | target: aarch64-pc-windows-msvc 39 | - name: windows 40 | target: x86_64-pc-windows-msvc 41 | 42 | preBuildSteps: 43 | - pwsh: Rename-Item -Path "./.cargo/config.toml.disabled" -NewName "config.toml" 44 | displayName: "Enable Azure Build config for Rust" 45 | -------------------------------------------------------------------------------- /crates/pet-conda/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-conda" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-fs = { path = "../pet-fs" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | serde = { version = "1.0.152", features = ["derive"] } 14 | serde_json = "1.0.93" 15 | lazy_static = "1.4.0" 16 | pet-core = { path = "../pet-core" } 17 | log = "0.4.21" 18 | regex = "1.10.4" 19 | pet-reporter = { path = "../pet-reporter" } 20 | env_logger = "0.10.2" 21 | yaml-rust2 = "0.8.1" 22 | 23 | [features] 24 | ci = [] 25 | -------------------------------------------------------------------------------- /crates/pet-conda/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::PathBuf; 5 | 6 | use pet_core::os_environment::Environment; 7 | 8 | #[derive(Debug, Clone)] 9 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 10 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 11 | pub struct EnvVariables { 12 | pub home: Option, 13 | /// Only used in tests, None in production. 14 | pub root: Option, 15 | pub path: Option, 16 | pub userprofile: Option, 17 | pub allusersprofile: Option, 18 | pub programdata: Option, 19 | pub homedrive: Option, 20 | pub conda_root: Option, 21 | /// https://github.com/jupyter/docker-stacks/issues/1086 22 | pub conda_dir: Option, 23 | pub conda: Option, 24 | pub conda_prefix: Option, 25 | pub mamba_root_prefix: Option, 26 | /// https://docs.conda.io/projects/conda/en/22.11.x/user-guide/configuration/use-condarc.html 27 | pub conda_envs_path: Option, 28 | pub condarc: Option, 29 | pub mambarc: Option, 30 | // https://anaconda-project.readthedocs.io/en/latest/config.html 31 | pub anaconda_project_envs_path: Option, 32 | // https://anaconda-project.readthedocs.io/en/latest/config.html 33 | pub project_dir: Option, 34 | pub xdg_config_home: Option, 35 | pub known_global_search_locations: Vec, 36 | } 37 | 38 | impl EnvVariables { 39 | pub fn from(env: &dyn Environment) -> Self { 40 | EnvVariables { 41 | home: env.get_user_home(), 42 | root: env.get_root(), 43 | path: env.get_env_var("PATH".to_string()), 44 | userprofile: env.get_env_var("USERPROFILE".to_string()), 45 | allusersprofile: env.get_env_var("ALLUSERSPROFILE".to_string()), 46 | programdata: env.get_env_var("PROGRAMDATA".to_string()), 47 | homedrive: env.get_env_var("HOMEDRIVE".to_string()), 48 | conda_dir: env.get_env_var("CONDA_DIR".to_string()), 49 | conda_root: env.get_env_var("CONDA_ROOT".to_string()), 50 | conda: env.get_env_var("CONDA".to_string()), 51 | conda_prefix: env.get_env_var("CONDA_PREFIX".to_string()), 52 | mamba_root_prefix: env.get_env_var("MAMBA_ROOT_PREFIX".to_string()), 53 | conda_envs_path: env.get_env_var("CONDA_ENVS_PATH".to_string()), 54 | anaconda_project_envs_path: env.get_env_var("ANACONDA_PROJECT_ENVS_PATH".to_string()), 55 | project_dir: env.get_env_var("PROJECT_DIR".to_string()), 56 | condarc: env.get_env_var("CONDARC".to_string()), 57 | mambarc: env.get_env_var("MAMBARC".to_string()), 58 | xdg_config_home: env.get_env_var("XDG_CONFIG_HOME".to_string()), 59 | known_global_search_locations: env.get_know_global_search_locations(), 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/pet-conda/src/utils.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::{Path, PathBuf}; 5 | 6 | /// conda-meta must exist as this contains a mandatory `history` file. 7 | pub fn is_conda_install(path: &Path) -> bool { 8 | if (path.join("condabin").exists() || path.join("envs").exists()) 9 | && path.join("conda-meta").exists() 10 | { 11 | // For https://github.com/microsoft/vscode-python/issues/24247 12 | // Possible the env has a condabin or envs folder but its not the install directory. 13 | // & in fact its just a regular conda env. 14 | // Easy way is to check if the grand parent folder is a conda install directory. 15 | if let Some(parent) = path.parent() { 16 | if let Some(parent) = parent.parent() { 17 | // If the grand parent is a conda install directory, 18 | // then this is definitely not a conda install dir. 19 | if (parent.join("condabin").exists() || parent.join("envs").exists()) 20 | && parent.join("conda-meta").exists() 21 | { 22 | return false; 23 | } 24 | } 25 | } 26 | 27 | return true; 28 | } 29 | 30 | false 31 | } 32 | 33 | /// conda-meta must exist as this contains a mandatory `history` file. 34 | /// The root conda installation folder is also a conda environment (its the base environment). 35 | pub fn is_conda_env(path: &Path) -> bool { 36 | path.join("conda-meta").is_dir() 37 | } 38 | 39 | /// Only used in tests, noop in production. 40 | /// 41 | /// Change the root of the path to a new root. 42 | /// Lets assume some config file is located in the root directory /etc/config/config.toml. 43 | /// We cannot test this unless we create such a file on the root of the filesystem. 44 | /// Thats very risky and not recommended (ideally we want to create stuff in separate test folders). 45 | /// The solution is to change the root of the path to a test folder. 46 | pub fn change_root_of_path(path: &Path, new_root: &Option) -> PathBuf { 47 | if cfg!(windows) { 48 | return path.to_path_buf(); 49 | } 50 | if let Some(new_root) = new_root { 51 | // This only applies in tests. 52 | // We need this, as the root folder cannot be mocked. 53 | // Strip the first `/` (this path is only for testing purposes) 54 | new_root.join(&path.to_string_lossy()[1..]) 55 | } else { 56 | path.to_path_buf() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_conda::env_variables::EnvVariables; 5 | use pet_core::os_environment::Environment; 6 | use std::{collections::HashMap, path::PathBuf}; 7 | 8 | #[allow(dead_code)] 9 | pub fn resolve_test_path(paths: &[&str]) -> PathBuf { 10 | let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); 11 | 12 | paths.iter().for_each(|p| root.push(p)); 13 | 14 | root 15 | } 16 | 17 | #[allow(dead_code)] 18 | pub fn create_env_variables(home: PathBuf, root: PathBuf) -> EnvVariables { 19 | EnvVariables { 20 | home: Some(home), 21 | root: Some(root), 22 | allusersprofile: None, 23 | conda_prefix: None, 24 | conda_root: None, 25 | conda: None, 26 | condarc: None, 27 | homedrive: None, 28 | known_global_search_locations: vec![], 29 | path: None, 30 | programdata: None, 31 | userprofile: None, 32 | xdg_config_home: None, 33 | conda_envs_path: None, 34 | conda_dir: None, 35 | anaconda_project_envs_path: None, 36 | project_dir: None, 37 | mamba_root_prefix: None, 38 | mambarc: None, 39 | } 40 | } 41 | 42 | #[allow(dead_code)] 43 | pub struct TestEnvironment { 44 | vars: HashMap, 45 | home: Option, 46 | root: Option, 47 | globals_locations: Vec, 48 | } 49 | #[allow(dead_code)] 50 | pub fn create_test_environment( 51 | vars: HashMap, 52 | home: Option, 53 | globals_locations: Vec, 54 | root: Option, 55 | ) -> TestEnvironment { 56 | impl Environment for TestEnvironment { 57 | fn get_env_var(&self, key: String) -> Option { 58 | self.vars.get(&key).cloned() 59 | } 60 | fn get_root(&self) -> Option { 61 | self.root.clone() 62 | } 63 | fn get_user_home(&self) -> Option { 64 | self.home.clone() 65 | } 66 | fn get_know_global_search_locations(&self) -> Vec { 67 | self.globals_locations.clone() 68 | } 69 | } 70 | TestEnvironment { 71 | vars, 72 | home, 73 | root, 74 | globals_locations, 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/environment_locations_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | 6 | #[cfg(unix)] 7 | #[test] 8 | fn non_existent_envrionments_txt() { 9 | use common::{create_env_variables, resolve_test_path}; 10 | use pet_conda::environment_locations::get_conda_envs_from_environment_txt; 11 | 12 | let root = resolve_test_path(&["unix", "root_empty"]).into(); 13 | let home = resolve_test_path(&["unix", "bogus directory"]).into(); 14 | let env = create_env_variables(home, root); 15 | 16 | let environments = get_conda_envs_from_environment_txt(&env); 17 | 18 | assert!(environments.is_empty()); 19 | } 20 | 21 | #[cfg(unix)] 22 | #[test] 23 | fn list_conda_envs_in_install_location() { 24 | use common::resolve_test_path; 25 | use pet_conda::environment_locations::get_environments; 26 | 27 | let path = resolve_test_path(&["unix", "anaconda3-2023.03"]); 28 | 29 | let mut locations = get_environments(&path); 30 | locations.sort(); 31 | 32 | assert_eq!( 33 | locations, 34 | vec![ 35 | resolve_test_path(&["unix", "anaconda3-2023.03"]), 36 | resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "env_python_3"]), 37 | resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "myenv"]), 38 | resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "without_python"]), 39 | ] 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/environments_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | use common::resolve_test_path; 6 | use pet_conda::environments::CondaEnvironment; 7 | use pet_core::arch::Architecture; 8 | 9 | #[cfg(unix)] 10 | #[test] 11 | fn find_root_conda_env() { 12 | let path = resolve_test_path(&["unix", "anaconda3-2023.03"]); 13 | 14 | let env = CondaEnvironment::from(&path, &None).unwrap(); 15 | 16 | assert_eq!(env.prefix, path.clone()); 17 | assert_eq!(env.arch, Some(Architecture::X64)); 18 | assert_eq!(env.conda_dir, Some(path.clone())); 19 | assert_eq!( 20 | env.executable, 21 | Some(path.clone().join("bin").join("python")) 22 | ); 23 | assert_eq!(env.version, Some("3.10.9".into())); 24 | } 25 | 26 | #[cfg(unix)] 27 | #[test] 28 | fn find_root_conda_env_without_history_file() { 29 | let path = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]); 30 | 31 | let env = CondaEnvironment::from(&path, &None).unwrap(); 32 | 33 | assert_eq!(env.prefix, path.clone()); 34 | assert_eq!(env.arch, Some(Architecture::X64)); 35 | assert_eq!(env.conda_dir, Some(path.clone())); 36 | assert_eq!( 37 | env.executable, 38 | Some(path.clone().join("bin").join("python")) 39 | ); 40 | assert_eq!(env.version, Some("3.10.9".into())); 41 | } 42 | 43 | #[cfg(unix)] 44 | #[test] 45 | fn find_conda_env() { 46 | let conda_dir = resolve_test_path(&["unix", "anaconda3-2023.03"]); 47 | let path = resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "env_python_3"]); 48 | 49 | let env = CondaEnvironment::from(&path, &None).unwrap(); 50 | 51 | assert_eq!(env.prefix, path.clone()); 52 | assert_eq!(env.arch, Some(Architecture::X64)); 53 | assert_eq!(env.conda_dir, Some(conda_dir.clone())); 54 | assert_eq!( 55 | env.executable, 56 | Some(path.clone().join("bin").join("python")) 57 | ); 58 | assert_eq!(env.version, Some("3.12.2".into())); 59 | } 60 | 61 | #[cfg(unix)] 62 | #[test] 63 | fn find_conda_env_without_python() { 64 | let conda_dir = resolve_test_path(&["unix", "anaconda3-2023.03"]); 65 | let path = resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "without_python"]); 66 | 67 | let env = CondaEnvironment::from(&path, &None).unwrap(); 68 | 69 | assert_eq!(env.prefix, path.clone()); 70 | assert_eq!(env.arch, None); 71 | assert_eq!(env.conda_dir, Some(conda_dir.clone())); 72 | assert_eq!(env.executable, None); 73 | assert_eq!(env.version, None); 74 | } 75 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/manager_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | 6 | #[cfg(unix)] 7 | #[test] 8 | fn finds_manager_from_root_env() { 9 | use common::resolve_test_path; 10 | use pet_conda::manager::CondaManager; 11 | 12 | let path = resolve_test_path(&["unix", "anaconda3-2023.03"]); 13 | 14 | let manager = CondaManager::from(&path).unwrap(); 15 | 16 | assert_eq!(manager.executable, path.join("bin").join("conda")); 17 | assert_eq!(manager.version, Some("23.1.0".into())); 18 | } 19 | 20 | #[cfg(unix)] 21 | #[test] 22 | fn finds_manager_from_root_within_an_env() { 23 | use common::resolve_test_path; 24 | use pet_conda::manager::CondaManager; 25 | 26 | let conda_dir = resolve_test_path(&["unix", "anaconda3-2023.03"]); 27 | let path = resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "env_python_3"]); 28 | 29 | let manager = CondaManager::from(&path).unwrap(); 30 | 31 | assert_eq!(manager.executable, conda_dir.join("bin").join("conda")); 32 | assert_eq!(manager.version, Some("23.1.0".into())); 33 | 34 | // Try a conda env without Python 35 | let path = resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "without_python"]); 36 | 37 | let manager = CondaManager::from(&path).unwrap(); 38 | 39 | assert_eq!(manager.executable, conda_dir.join("bin").join("conda")); 40 | assert_eq!(manager.version, Some("23.1.0".into())); 41 | } 42 | 43 | #[cfg(unix)] 44 | #[test] 45 | fn does_not_find_conda_env_for_bogus_dirs() { 46 | use common::resolve_test_path; 47 | use pet_conda::manager::CondaManager; 48 | 49 | let path = resolve_test_path(&["unix", "bogus_directory"]); 50 | 51 | assert_eq!(CondaManager::from(&path).is_none(), true); 52 | } 53 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/package_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | use pet_conda::package::{self, CondaPackageInfo}; 6 | use std::path::PathBuf; 7 | 8 | use common::resolve_test_path; 9 | 10 | #[cfg(unix)] 11 | #[test] 12 | fn empty_result_for_bogus_paths() { 13 | let path: PathBuf = resolve_test_path(&["unix", "bogus_path"]).into(); 14 | let pkg = CondaPackageInfo::from(&path, &package::Package::Conda); 15 | 16 | assert!(pkg.is_none()); 17 | } 18 | 19 | #[cfg(unix)] 20 | #[test] 21 | fn get_conda_package_info() { 22 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03"]).into(); 23 | let pkg = CondaPackageInfo::from(&path, &package::Package::Conda).unwrap(); 24 | 25 | assert_eq!(pkg.package, package::Package::Conda); 26 | assert_eq!(pkg.version, "23.1.0".to_string()); 27 | assert_eq!( 28 | pkg.path, 29 | resolve_test_path(&[ 30 | "unix", 31 | "anaconda3-2023.03", 32 | "conda-meta", 33 | "conda-23.1.0-py310hca03da5_0.json" 34 | ]) 35 | ); 36 | } 37 | 38 | #[cfg(unix)] 39 | #[test] 40 | fn get_python_package_info() { 41 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03"]).into(); 42 | let pkg = CondaPackageInfo::from(&path, &package::Package::Python).unwrap(); 43 | 44 | assert_eq!(pkg.package, package::Package::Python); 45 | assert_eq!(pkg.version, "3.10.9".to_string()); 46 | assert_eq!( 47 | pkg.path, 48 | resolve_test_path(&[ 49 | "unix", 50 | "anaconda3-2023.03", 51 | "conda-meta", 52 | "python-3.10.9-hc0d8a6c_1.json" 53 | ]) 54 | ); 55 | } 56 | 57 | #[cfg(unix)] 58 | #[test] 59 | fn get_conda_package_info_without_history() { 60 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]).into(); 61 | let pkg = CondaPackageInfo::from(&path, &package::Package::Conda).unwrap(); 62 | 63 | assert_eq!(pkg.package, package::Package::Conda); 64 | assert_eq!(pkg.version, "23.1.0".to_string()); 65 | assert_eq!( 66 | pkg.path, 67 | resolve_test_path(&[ 68 | "unix", 69 | "anaconda3-2023.03-without-history", 70 | "conda-meta", 71 | "conda-23.1.0-py310hca03da5_0.json" 72 | ]) 73 | ); 74 | } 75 | 76 | #[cfg(unix)] 77 | #[test] 78 | fn get_python_package_info_without_history() { 79 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]).into(); 80 | let pkg = CondaPackageInfo::from(&path, &package::Package::Python).unwrap(); 81 | 82 | assert_eq!(pkg.package, package::Package::Python); 83 | assert_eq!(pkg.version, "3.10.9".to_string()); 84 | assert_eq!( 85 | pkg.path, 86 | resolve_test_path(&[ 87 | "unix", 88 | "anaconda3-2023.03-without-history", 89 | "conda-meta", 90 | "python-3.10.9-hc0d8a6c_1.json" 91 | ]) 92 | ); 93 | } 94 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/condabin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/condabin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03-without-history/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/condabin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/condabin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3.12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/bin/python3.12 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/env_python_3/conda-meta/python_abi-3.12-4_cp312.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "4_cp312", 3 | "build_number": 4, 4 | "channel": "https://conda.anaconda.org/conda-forge/osx-arm64", 5 | "constrains": [ 6 | "python 3.12.* *_cpython" 7 | ], 8 | "depends": [], 9 | "extracted_package_dir": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 10 | "files": [], 11 | "fn": "python_abi-3.12-4_cp312.conda", 12 | "license": "BSD-3-Clause", 13 | "link": { 14 | "source": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 15 | "type": 1 16 | }, 17 | "md5": "bbb3a02c78b2d8219d7213f76d644a2a", 18 | "name": "python_abi", 19 | "package_tarball_full_path": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312.conda", 20 | "paths_data": { 21 | "paths": [], 22 | "paths_version": 1 23 | }, 24 | "requested_spec": "None", 25 | "sha256": "db25428e4f24f8693ffa39f3ff6dfbb8fd53bc298764b775b57edab1c697560f", 26 | "size": 6508, 27 | "subdir": "osx-arm64", 28 | "timestamp": 1695147497000, 29 | "url": "https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda", 30 | "version": "3.12" 31 | } -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/myenv/conda-meta/history: -------------------------------------------------------------------------------- 1 | ==> 2024-05-08 12:20:05 <== 2 | # cmd: /Users/donjayamanne/.pyenv/versions/miniconda3-latest/bin/conda create -n myenv python=3.10 3 | # conda version: 24.3.0 4 | +defaults/noarch::tzdata-2024a-h04d1e81_0 5 | +defaults/osx-arm64::bzip2-1.0.8-h80987f9_6 6 | +defaults/osx-arm64::ca-certificates-2024.3.11-hca03da5_0 7 | +defaults/osx-arm64::libffi-3.4.4-hca03da5_1 8 | +defaults/osx-arm64::ncurses-6.4-h313beb8_0 9 | +defaults/osx-arm64::openssl-3.0.13-h1a28f6b_1 10 | +defaults/osx-arm64::pip-24.0-py310hca03da5_0 11 | +defaults/osx-arm64::python-3.10.14-hb885b13_1 12 | +defaults/osx-arm64::readline-8.2-h1a28f6b_0 13 | +defaults/osx-arm64::setuptools-69.5.1-py310hca03da5_0 14 | +defaults/osx-arm64::sqlite-3.45.3-h80987f9_0 15 | +defaults/osx-arm64::tk-8.6.14-h6ba3021_0 16 | +defaults/osx-arm64::wheel-0.43.0-py310hca03da5_0 17 | +defaults/osx-arm64::xz-5.4.6-h80987f9_1 18 | +defaults/osx-arm64::zlib-1.2.13-h18a0788_1 19 | # update specs: ['python=3.10'] 20 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/anaconda3-2023.03/envs/without_python/conda-meta/history: -------------------------------------------------------------------------------- 1 | ==> 2024-02-29 08:48:22 <== 2 | # cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda7 -y 3 | # conda version: 23.11.0 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3.12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/bin/python3.12 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager/env_python_3/conda-meta/python_abi-3.12-4_cp312.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "4_cp312", 3 | "build_number": 4, 4 | "channel": "https://conda.anaconda.org/conda-forge/osx-arm64", 5 | "constrains": [ 6 | "python 3.12.* *_cpython" 7 | ], 8 | "depends": [], 9 | "extracted_package_dir": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 10 | "files": [], 11 | "fn": "python_abi-3.12-4_cp312.conda", 12 | "license": "BSD-3-Clause", 13 | "link": { 14 | "source": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 15 | "type": 1 16 | }, 17 | "md5": "bbb3a02c78b2d8219d7213f76d644a2a", 18 | "name": "python_abi", 19 | "package_tarball_full_path": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312.conda", 20 | "paths_data": { 21 | "paths": [], 22 | "paths_version": 1 23 | }, 24 | "requested_spec": "None", 25 | "sha256": "db25428e4f24f8693ffa39f3ff6dfbb8fd53bc298764b775b57edab1c697560f", 26 | "size": 6508, 27 | "subdir": "osx-arm64", 28 | "timestamp": 1695147497000, 29 | "url": "https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda", 30 | "version": "3.12" 31 | } -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3.12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/bin/python3.12 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/env_python_3/conda-meta/python_abi-3.12-4_cp312.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "4_cp312", 3 | "build_number": 4, 4 | "channel": "https://conda.anaconda.org/conda-forge/osx-arm64", 5 | "constrains": [ 6 | "python 3.12.* *_cpython" 7 | ], 8 | "depends": [], 9 | "extracted_package_dir": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 10 | "files": [], 11 | "fn": "python_abi-3.12-4_cp312.conda", 12 | "license": "BSD-3-Clause", 13 | "link": { 14 | "source": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 15 | "type": 1 16 | }, 17 | "md5": "bbb3a02c78b2d8219d7213f76d644a2a", 18 | "name": "python_abi", 19 | "package_tarball_full_path": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312.conda", 20 | "paths_data": { 21 | "paths": [], 22 | "paths_version": 1 23 | }, 24 | "requested_spec": "None", 25 | "sha256": "db25428e4f24f8693ffa39f3ff6dfbb8fd53bc298764b775b57edab1c697560f", 26 | "size": 6508, 27 | "subdir": "osx-arm64", 28 | "timestamp": 1695147497000, 29 | "url": "https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda", 30 | "version": "3.12" 31 | } -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/condabin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/condabin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_env_without_manager_but_found_in_history/some_other_location/conda_install/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/condabin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/condabin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/conda -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3.12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/bin/python3.12 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/env_python_3/conda-meta/python_abi-3.12-4_cp312.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "4_cp312", 3 | "build_number": 4, 4 | "channel": "https://conda.anaconda.org/conda-forge/osx-arm64", 5 | "constrains": [ 6 | "python 3.12.* *_cpython" 7 | ], 8 | "depends": [], 9 | "extracted_package_dir": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 10 | "files": [], 11 | "fn": "python_abi-3.12-4_cp312.conda", 12 | "license": "BSD-3-Clause", 13 | "link": { 14 | "source": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312", 15 | "type": 1 16 | }, 17 | "md5": "bbb3a02c78b2d8219d7213f76d644a2a", 18 | "name": "python_abi", 19 | "package_tarball_full_path": "/Users/donjayamanne/miniconda3/pkgs/python_abi-3.12-4_cp312.conda", 20 | "paths_data": { 21 | "paths": [], 22 | "paths_version": 1 23 | }, 24 | "requested_spec": "None", 25 | "sha256": "db25428e4f24f8693ffa39f3ff6dfbb8fd53bc298764b775b57edab1c697560f", 26 | "size": 6508, 27 | "subdir": "osx-arm64", 28 | "timestamp": 1695147497000, 29 | "url": "https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda", 30 | "version": "3.12" 31 | } -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3.1 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/bin/python3.10 -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/myenv/conda-meta/history: -------------------------------------------------------------------------------- 1 | ==> 2024-05-08 12:20:05 <== 2 | # cmd: /Users/donjayamanne/.pyenv/versions/miniconda3-latest/bin/conda create -n myenv python=3.10 3 | # conda version: 24.3.0 4 | +defaults/noarch::tzdata-2024a-h04d1e81_0 5 | +defaults/osx-arm64::bzip2-1.0.8-h80987f9_6 6 | +defaults/osx-arm64::ca-certificates-2024.3.11-hca03da5_0 7 | +defaults/osx-arm64::libffi-3.4.4-hca03da5_1 8 | +defaults/osx-arm64::ncurses-6.4-h313beb8_0 9 | +defaults/osx-arm64::openssl-3.0.13-h1a28f6b_1 10 | +defaults/osx-arm64::pip-24.0-py310hca03da5_0 11 | +defaults/osx-arm64::python-3.10.14-hb885b13_1 12 | +defaults/osx-arm64::readline-8.2-h1a28f6b_0 13 | +defaults/osx-arm64::setuptools-69.5.1-py310hca03da5_0 14 | +defaults/osx-arm64::sqlite-3.45.3-h80987f9_0 15 | +defaults/osx-arm64::tk-8.6.14-h6ba3021_0 16 | +defaults/osx-arm64::wheel-0.43.0-py310hca03da5_0 17 | +defaults/osx-arm64::xz-5.4.6-h80987f9_1 18 | +defaults/osx-arm64::zlib-1.2.13-h18a0788_1 19 | # update specs: ['python=3.10'] 20 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_envs/user_home/miniconda3/envs/without_python/conda-meta/history: -------------------------------------------------------------------------------- 1 | ==> 2024-02-29 08:48:22 <== 2 | # cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda7 -y 3 | # conda version: 23.11.0 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_rc/user_home/.condarc: -------------------------------------------------------------------------------- 1 | envs_dirs: 2 | - /Users/donjayamanne/temp/sample-conda-envs-folder2 3 | - /Users/donjayamanne/temp/sample-conda-envs-folder 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_rc_conda_root_var/user_home/.condarc: -------------------------------------------------------------------------------- 1 | envs_dirs: 2 | - /Users/donjayamanne/temp/sample-conda-envs-folder2 3 | - /Users/donjayamanne/temp/sample-conda-envs-folder 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_rc_conda_root_var/user_home/conda_root_variable_path/.condarc: -------------------------------------------------------------------------------- 1 | envs_dirs: 2 | - /Users/donjayamanne/sample-conda-envs-folder2-from_conda_root 3 | - /Users/donjayamanne/sample-conda-envs-folder-from_conda_root 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_rc_root/root/etc/conda/.condarc: -------------------------------------------------------------------------------- 1 | envs_dirs: 2 | - /Users/donjayamanne/root-folder2 3 | - /Users/donjayamanne/root-folder 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/conda_rc_root/user_home/.condarc: -------------------------------------------------------------------------------- 1 | envs_dirs: 2 | - /Users/donjayamanne/temp/sample-conda-envs-folder2 3 | - /Users/donjayamanne/temp/sample-conda-envs-folder 4 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/unix/user_home_with_environments_txt/.conda/environments.txt: -------------------------------------------------------------------------------- 1 | /Users/username/miniconda3 2 | /Users/username/miniconda3/envs/xyz 3 | /Users/username/miniconda3/envs/conda1 4 | /Users/username/miniconda3/envs/conda2 5 | /Users/username/miniconda3/envs/conda3 6 | /Users/username/miniconda3/envs/conda4 7 | /Users/username/miniconda3/envs/conda5 8 | /Users/username/miniconda3/envs/conda6 9 | /Users/username/miniconda3/envs/conda7 10 | /Users/username/miniconda3/envs/conda8 11 | /Users/username/.pyenv/versions/miniconda3-latest 12 | /Users/username/.pyenv/versions/miniconda3-latest/envs/myenv 13 | /Users/username/.pyenv/versions/miniforge3-4.10.1-1 14 | /Users/username/.pyenv/versions/anaconda3-2023.03 15 | /Users/username/miniforge3/envs/sample1 16 | /Users/username/temp/conda_work_folder 17 | /Users/username/temp/conda_work_folder_3.12 18 | /Users/username/temp/conda_work_folder__no_python 19 | /Users/username/temp/conda_work_folder_from_root 20 | /Users/username/temp/sample-conda-envs-folder/hello_world 21 | /Users/username/temp/sample-conda-envs-folder2/another 22 | /Users/username/temp/sample-conda-envs-folder2/xyz 23 | -------------------------------------------------------------------------------- /crates/pet-conda/tests/utils_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | use common::resolve_test_path; 6 | use pet_conda::utils; 7 | use std::path::PathBuf; 8 | 9 | #[cfg(unix)] 10 | #[test] 11 | fn is_conda_install() { 12 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03"]).into(); 13 | assert!(utils::is_conda_install(&path)); 14 | 15 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]).into(); 16 | assert!(utils::is_conda_install(&path)); 17 | } 18 | 19 | #[cfg(unix)] 20 | #[test] 21 | fn is_not_conda_install() { 22 | let path: PathBuf = resolve_test_path(&["unix", "some bogus directory"]).into(); 23 | assert_eq!(utils::is_conda_install(&path), false); 24 | 25 | // Conda env is not an install location. 26 | let path: PathBuf = 27 | resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "env_python_3"]).into(); 28 | assert_eq!(utils::is_conda_install(&path), false); 29 | } 30 | 31 | #[cfg(unix)] 32 | #[test] 33 | fn is_conda_env() { 34 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03"]).into(); 35 | assert!(utils::is_conda_env(&path)); 36 | 37 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]).into(); 38 | assert!(utils::is_conda_env(&path)); 39 | 40 | let path: PathBuf = 41 | resolve_test_path(&["unix", "anaconda3-2023.03", "envs", "env_python_3"]).into(); 42 | assert!(utils::is_conda_env(&path)); 43 | } 44 | 45 | #[cfg(unix)] 46 | #[test] 47 | fn is_not_conda_env() { 48 | let path: PathBuf = resolve_test_path(&["unix", "some bogus directory"]).into(); 49 | assert_eq!(utils::is_conda_env(&path), false); 50 | 51 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03"]).into(); 52 | assert!(utils::is_conda_env(&path)); 53 | 54 | let path: PathBuf = resolve_test_path(&["unix", "anaconda3-2023.03-without-history"]).into(); 55 | assert!(utils::is_conda_env(&path)); 56 | } 57 | -------------------------------------------------------------------------------- /crates/pet-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | clap = { version = "4.5.4", features = ["derive", "cargo"] } 12 | pet-fs = { path = "../pet-fs" } 13 | serde = { version = "1.0.152", features = ["derive"] } 14 | lazy_static = "1.4.0" 15 | regex = "1.10.4" 16 | log = "0.4.21" 17 | serde_json = "1.0.93" 18 | -------------------------------------------------------------------------------- /crates/pet-core/src/arch.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use serde::{Deserialize, Serialize}; 5 | 6 | #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] 7 | #[serde(rename_all = "camelCase")] 8 | pub enum Architecture { 9 | X64, 10 | X86, 11 | } 12 | 13 | impl Ord for Architecture { 14 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 15 | format!("{self:?}").cmp(&format!("{other:?}")) 16 | } 17 | } 18 | impl PartialOrd for Architecture { 19 | fn partial_cmp(&self, other: &Self) -> Option { 20 | Some(self.cmp(other)) 21 | } 22 | } 23 | 24 | impl std::fmt::Display for Architecture { 25 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 26 | write!( 27 | f, 28 | "{}", 29 | if *self == Architecture::X64 { 30 | "x64" 31 | } else { 32 | "x86" 33 | } 34 | ) 35 | .unwrap_or_default(); 36 | Ok(()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /crates/pet-core/src/env.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::PathBuf; 5 | 6 | use pet_fs::path::norm_case; 7 | 8 | use crate::pyvenv_cfg::PyVenvCfg; 9 | 10 | #[derive(Debug)] 11 | pub struct PythonEnv { 12 | /// Executable of the Python environment. 13 | /// 14 | /// Can be `/usr/bin/python` or `/opt/homebrew/bin/python3.12`. 15 | /// Or even the fully (resolved &) qualified path to the python executable such as `/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/bin/python3.12`. 16 | /// 17 | /// Note: This can be a symlink as well. 18 | pub executable: PathBuf, 19 | /// Environment prefix 20 | pub prefix: Option, 21 | /// Version of the Python environment. 22 | pub version: Option, 23 | /// Possible symlink (or known alternative link). 24 | /// For instance: 25 | /// 26 | /// If `executable` is `/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/bin/python3.12`, 27 | /// then `symlink`` can be `/opt/homebrew/bin/python3.12` (or vice versa). 28 | pub symlinks: Option>, 29 | } 30 | 31 | impl PythonEnv { 32 | pub fn new(executable: PathBuf, prefix: Option, version: Option) -> Self { 33 | let mut prefix = prefix.clone(); 34 | if let Some(value) = prefix { 35 | prefix = norm_case(value).into(); 36 | } 37 | // if the prefix is not defined, try to get this. 38 | // For instance, if the file is bin/python or Scripts/python 39 | // And we have a pyvenv.cfg file in the parent directory, then we can get the prefix. 40 | if prefix.is_none() { 41 | let mut exe = executable.clone(); 42 | exe.pop(); 43 | if exe.ends_with("Scripts") || exe.ends_with("bin") { 44 | exe.pop(); 45 | if PyVenvCfg::find(&exe).is_some() { 46 | prefix = Some(exe); 47 | } 48 | } 49 | } 50 | Self { 51 | executable: norm_case(executable), 52 | prefix, 53 | version, 54 | symlinks: None, 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /crates/pet-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::PathBuf; 5 | 6 | use env::PythonEnv; 7 | use manager::EnvManager; 8 | use python_environment::{PythonEnvironment, PythonEnvironmentKind}; 9 | use reporter::Reporter; 10 | 11 | pub mod arch; 12 | pub mod env; 13 | pub mod manager; 14 | pub mod os_environment; 15 | pub mod python_environment; 16 | pub mod pyvenv_cfg; 17 | pub mod reporter; 18 | pub mod telemetry; 19 | 20 | #[derive(Debug, Clone, PartialEq, Eq)] 21 | pub struct LocatorResult { 22 | pub managers: Vec, 23 | pub environments: Vec, 24 | } 25 | 26 | #[derive(Debug, Default, Clone)] 27 | pub struct Configuration { 28 | /// These are paths like workspace folders, where we can look for environments. 29 | pub workspace_directories: Option>, 30 | pub executables: Option>, 31 | pub conda_executable: Option, 32 | pub poetry_executable: Option, 33 | /// Custom locations where environments can be found. 34 | /// These are different from search_paths, as these are specific directories where environments are expected. 35 | /// environment_directories on the other hand can be any directory such as a workspace folder, where envs might never exist. 36 | pub environment_directories: Option>, 37 | /// Directory to cache the Python environment details. 38 | pub cache_directory: Option, 39 | } 40 | 41 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 42 | pub enum LocatorKind { 43 | Conda, 44 | Homebrew, 45 | LinuxGlobal, 46 | MacCommandLineTools, 47 | MacPythonOrg, 48 | MacXCode, 49 | PipEnv, 50 | Pixi, 51 | Poetry, 52 | PyEnv, 53 | Venv, 54 | VirtualEnv, 55 | VirtualEnvWrapper, 56 | WindowsRegistry, 57 | WindowsStore, 58 | } 59 | 60 | pub trait Locator: Send + Sync { 61 | /// Returns the name of the locator. 62 | fn get_kind(&self) -> LocatorKind; 63 | /// Configures the locator with the given configuration. 64 | /// Override this method if you need to have some custom configuration. 65 | /// E.g. storing some of the configuration information in the locator. 66 | fn configure(&self, _config: &Configuration) { 67 | // 68 | } 69 | /// Returns a list of supported categories for this locator. 70 | fn supported_categories(&self) -> Vec; 71 | /// Given a Python executable, and some optional data like prefix, 72 | /// this method will attempt to convert it to a PythonEnvironment that can be supported by this particular locator. 73 | /// If an environment is not supported by this locator, then None is returned. 74 | /// 75 | /// Note: The returned environment could have some missing information. 76 | /// This is because the `from` will do a best effort to get the environment information without spawning Python. 77 | fn try_from(&self, env: &PythonEnv) -> Option; 78 | /// Finds all environments specific to this locator. 79 | fn find(&self, reporter: &dyn Reporter); 80 | } 81 | -------------------------------------------------------------------------------- /crates/pet-core/src/manager.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use serde::{Deserialize, Serialize}; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug, Hash)] 8 | pub enum EnvManagerType { 9 | Conda, 10 | Poetry, 11 | Pyenv, 12 | } 13 | 14 | impl Ord for EnvManagerType { 15 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 16 | format!("{self:?}").cmp(&format!("{other:?}")) 17 | } 18 | } 19 | impl PartialOrd for EnvManagerType { 20 | fn partial_cmp(&self, other: &Self) -> Option { 21 | Some(self.cmp(other)) 22 | } 23 | } 24 | 25 | #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] 26 | #[serde(rename_all = "camelCase")] 27 | #[derive(Debug)] 28 | pub struct EnvManager { 29 | pub executable: PathBuf, 30 | pub version: Option, 31 | pub tool: EnvManagerType, 32 | } 33 | impl Ord for EnvManager { 34 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 35 | match self.executable.cmp(&other.executable) { 36 | std::cmp::Ordering::Equal => {} 37 | ord => return ord, 38 | } 39 | match self.version.cmp(&other.version) { 40 | std::cmp::Ordering::Equal => {} 41 | ord => return ord, 42 | } 43 | self.tool.cmp(&other.tool) 44 | } 45 | } 46 | 47 | impl PartialOrd for EnvManager { 48 | fn partial_cmp(&self, other: &Self) -> Option { 49 | Some(self.cmp(other)) 50 | } 51 | } 52 | 53 | impl EnvManager { 54 | pub fn new(executable_path: PathBuf, tool: EnvManagerType, version: Option) -> Self { 55 | Self { 56 | executable: executable_path, 57 | version, 58 | tool, 59 | } 60 | } 61 | } 62 | 63 | impl std::fmt::Display for EnvManager { 64 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 65 | writeln!(f, "Manager ({:?})", self.tool).unwrap_or_default(); 66 | writeln!( 67 | f, 68 | " Executable : {}", 69 | self.executable.to_str().unwrap_or_default() 70 | ) 71 | .unwrap_or_default(); 72 | if let Some(version) = &self.version { 73 | writeln!(f, " Version : {version}").unwrap_or_default(); 74 | } 75 | Ok(()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /crates/pet-core/src/reporter.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::{ 5 | manager::EnvManager, python_environment::PythonEnvironment, telemetry::TelemetryEvent, 6 | }; 7 | 8 | pub trait Reporter: Send + Sync { 9 | fn report_manager(&self, manager: &EnvManager); 10 | fn report_environment(&self, env: &PythonEnvironment); 11 | fn report_telemetry(&self, event: &TelemetryEvent); 12 | } 13 | -------------------------------------------------------------------------------- /crates/pet-core/src/telemetry/inaccurate_python_info.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::python_environment::PythonEnvironmentKind; 7 | 8 | /// Information about an environment that was discovered to be inaccurate. 9 | /// If the discovered information is None, then it means that the information was not found. 10 | /// And we will not report that as an inaccuracy. 11 | #[derive(Serialize, Deserialize)] 12 | #[serde(rename_all = "camelCase")] 13 | #[derive(Debug, Clone, Copy)] 14 | pub struct InaccuratePythonEnvironmentInfo { 15 | /// Python Env kind 16 | pub kind: Option, 17 | /// Whether the actual exe is not what we expected. 18 | pub invalid_executable: Option, 19 | /// Whether the actual exe was not even in the list of symlinks that we expected. 20 | pub executable_not_in_symlinks: Option, 21 | /// Whether the prefix is not what we expected. 22 | pub invalid_prefix: Option, 23 | /// Whether the version is not what we expected. 24 | pub invalid_version: Option, 25 | /// Whether the architecture is not what we expected. 26 | pub invalid_arch: Option, 27 | } 28 | 29 | impl std::fmt::Display for InaccuratePythonEnvironmentInfo { 30 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 31 | writeln!(f, "Environment {:?} incorrectly identified", self.kind).unwrap_or_default(); 32 | if self.invalid_executable.unwrap_or_default() { 33 | writeln!(f, " Executable is incorrect").unwrap_or_default(); 34 | } 35 | if self.executable_not_in_symlinks.unwrap_or_default() { 36 | writeln!(f, " Executable is not in the list of symlinks").unwrap_or_default(); 37 | } 38 | if self.invalid_prefix.unwrap_or_default() { 39 | writeln!(f, " Prefix is incorrect").unwrap_or_default(); 40 | } 41 | if self.invalid_version.unwrap_or_default() { 42 | writeln!(f, " Version is incorrect").unwrap_or_default(); 43 | } 44 | if self.invalid_arch.unwrap_or_default() { 45 | writeln!(f, " Architecture is incorrect").unwrap_or_default(); 46 | } 47 | Ok(()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /crates/pet-core/src/telemetry/missing_poetry_info.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Telemetry sent when 7 | /// 1. We are able to spawn poetry 8 | /// 2. We have found some new envs after spawning poetry 9 | #[derive(Serialize, Deserialize)] 10 | #[serde(rename_all = "camelCase")] 11 | #[derive(Debug, Clone, Copy)] 12 | pub struct MissingPoetryEnvironments { 13 | /// Total number of missing envs. 14 | pub missing: u16, 15 | /// Total number of missing envs, where the envs are created in the virtualenvs_path directory. 16 | pub missing_in_path: u16, 17 | /// Whether the user provided a executable. 18 | pub user_provided_poetry_exe: Option, 19 | /// Whether we managed to find the poetry exe or not. 20 | pub poetry_exe_not_found: Option, 21 | /// Whether we failed to find the global config file. 22 | pub global_config_not_found: Option, 23 | /// Whether the cache-dir returned by Poetry exe was not found by us 24 | /// This indicated the fact that we are unable to parse the poetry config file or something else. 25 | pub cache_dir_not_found: Option, 26 | /// Whether the cache-dir we found is different from what is returned by Poetry exe 27 | pub cache_dir_is_different: Option, 28 | /// Whether the virtualenvs path returned by Poetry exe was not found by us 29 | /// This indicated the fact that we are unable to parse the poetry config file or something else. 30 | pub virtualenvs_path_not_found: Option, 31 | /// Whether the virtualenvs_path we found is different from what is returned by Poetry exe 32 | pub virtualenvs_path_is_different: Option, 33 | /// Whether the virtualenvs.in-project setting value is differnt from what is returned by Poetry exe 34 | pub in_project_is_different: Option, 35 | } 36 | -------------------------------------------------------------------------------- /crates/pet-core/src/telemetry/refresh_performance.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::collections::BTreeMap; 5 | 6 | use serde::{Deserialize, Serialize}; 7 | 8 | /// Telemetry with metrics for finding all environments as a result of refresh. 9 | /// All durations are in milliseconds. 10 | #[derive(Serialize, Deserialize)] 11 | #[serde(rename_all = "camelCase")] 12 | #[derive(Debug, Clone)] 13 | pub struct RefreshPerformance { 14 | /// Total time taken to find all envs. 15 | pub total: u128, 16 | /// Breakdown of Global VirtualEnvs, Path, Workspace and the locators. 17 | pub breakdown: BTreeMap, 18 | /// Breakdown of each individual locators such as conda, pyenv, etc. 19 | pub locators: BTreeMap, 20 | } 21 | -------------------------------------------------------------------------------- /crates/pet-env-var-path/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-env-var-path" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-fs = { path = "../pet-fs" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-python-utils = { path = "../pet-python-utils" } 15 | pet-conda = { path = "../pet-conda" } 16 | log = "0.4.21" 17 | lazy_static = "1.4.0" 18 | regex = "1.10.4" 19 | -------------------------------------------------------------------------------- /crates/pet-env-var-path/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | pub fn get_search_paths_from_env_variables(environment: &dyn Environment) -> Vec { 8 | // Exclude files from this folder, as they would have been discovered elsewhere (widows_store) 9 | // Also the exe is merely a pointer to another file. 10 | if let Some(home) = environment.get_user_home() { 11 | let apps_path = home 12 | .join("AppData") 13 | .join("Local") 14 | .join("Microsoft") 15 | .join("WindowsApps"); 16 | 17 | environment 18 | .get_know_global_search_locations() 19 | .clone() 20 | .into_iter() 21 | .filter(|p| !p.starts_with(apps_path.clone())) 22 | .collect::>() 23 | } else { 24 | Vec::new() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/pet-fs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-fs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | log = "0.4.21" 12 | -------------------------------------------------------------------------------- /crates/pet-fs/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | pub mod path; 5 | -------------------------------------------------------------------------------- /crates/pet-global-virtualenvs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-global-virtualenvs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-fs = { path = "../pet-fs" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-conda = { path = "../pet-conda" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-homebrew/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-homebrew" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-fs = { path = "../pet-fs" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-conda = { path = "../pet-conda" } 15 | serde = { version = "1.0.152", features = ["derive"] } 16 | serde_json = "1.0.93" 17 | lazy_static = "1.4.0" 18 | pet-core = { path = "../pet-core" } 19 | log = "0.4.21" 20 | regex = "1.10.4" 21 | -------------------------------------------------------------------------------- /crates/pet-homebrew/README.md: -------------------------------------------------------------------------------- 1 | # Hombrew 2 | 3 | ## Notes 4 | 5 | - Install folders & symlinks documented here https://formulae.brew.sh/formula/python@3.9 6 | - Homebrew install locations documented here https://docs.brew.sh/Installation 7 | 8 | ## Known Issues 9 | 10 | - `sys.prefix` is not easy to identify. Hence left empty for now. 11 | If we can find a way to identify `sys.prefix` consistenly for all platforms, then we can populate this field. 12 | 13 | ## Pseduo code for algorithm 14 | 15 | ```rust 16 | homebrew_dir = // find this folder (either "HOMEBREW_PREFIX" or default to directory defined here https://docs.brew.sh/Installation) 17 | for file under "/bin": 18 | if we have a python executable and its a symlink, then proceed 19 | if not, then skip this file 20 | 21 | resolve the symlink and verify the file is in one of the known homebrew directories. 22 | if not, then skip this file 23 | 24 | Extract the version from the file path. 25 | 26 | Compute the env_path by extracting the version information. 27 | The env_path is known directories on MacOS (Intel & Silicon) and Linux. 28 | 29 | Identify all known Symlinks for the python executable. 30 | There are a number of symlinks for each Python environment executable. Best to identify them all. 31 | As we have no idea which ones will be used by users. 32 | 33 | Note: Identifying `sys_prefix` is not easy, hence left empty for now. 34 | ``` 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /crates/pet-homebrew/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Debug, Clone)] 8 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 9 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 10 | pub struct EnvVariables { 11 | #[allow(dead_code)] 12 | pub home: Option, 13 | #[allow(dead_code)] 14 | pub root: Option, 15 | #[allow(dead_code)] 16 | pub path: Option, 17 | pub homebrew_prefix: Option, 18 | #[allow(dead_code)] 19 | pub known_global_search_locations: Vec, 20 | } 21 | 22 | impl EnvVariables { 23 | pub fn from(env: &dyn Environment) -> Self { 24 | EnvVariables { 25 | home: env.get_user_home(), 26 | root: env.get_root(), 27 | path: env.get_env_var("PATH".to_string()), 28 | homebrew_prefix: env.get_env_var("HOMEBREW_PREFIX".to_string()), 29 | known_global_search_locations: env.get_know_global_search_locations(), 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/pet-homebrew/src/environment_locations.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::env_variables::EnvVariables; 5 | use lazy_static::lazy_static; 6 | use regex::Regex; 7 | use std::path::PathBuf; 8 | 9 | lazy_static! { 10 | static ref PYTHON_VERSION: Regex = 11 | Regex::new(r"/(\d+\.\d+\.\d+)/").expect("error parsing Version regex for Homebrew"); 12 | } 13 | 14 | // fn get_homebrew_prefix_env_var(env_vars: &EnvVariables) -> Option { 15 | // if let Some(homebrew_prefix) = &env_vars.homebrew_prefix { 16 | // let homebrew_prefix_bin = PathBuf::from(homebrew_prefix).join("bin"); 17 | // if fs::metadata(&homebrew_prefix_bin).is_ok() { 18 | // return Some(homebrew_prefix_bin); 19 | // } 20 | // } 21 | // None 22 | // } 23 | 24 | pub fn get_homebrew_prefix_bin(env_vars: &EnvVariables) -> Vec { 25 | // Homebrew install folders documented here https://docs.brew.sh/Installation 26 | // /opt/homebrew for Apple Silicon, 27 | // /usr/local for macOS Intel 28 | // /home/linuxbrew/.linuxbrew for Linux 29 | // If user has rosetta enabled, then its possible we have homebrew installed via rosetta as well as apple silicon 30 | // I.e. we can have multiple home brews on the same machine, hence search all, 31 | let mut homebrew_prefixes = [ 32 | "/home/linuxbrew/.linuxbrew/bin", 33 | "/opt/homebrew/bin", 34 | "/usr/local/bin", 35 | ] 36 | .iter() 37 | .map(PathBuf::from) 38 | .filter(|p| p.exists()) 39 | .collect::>(); 40 | 41 | // Check the environment variables 42 | if let Some(homebrew_prefix) = &env_vars.homebrew_prefix { 43 | let homebrew_prefix_bin = PathBuf::from(homebrew_prefix).join("bin"); 44 | if homebrew_prefix_bin.exists() && !homebrew_prefixes.contains(&homebrew_prefix_bin) { 45 | homebrew_prefixes.push(homebrew_prefix_bin); 46 | } 47 | } 48 | 49 | homebrew_prefixes 50 | } 51 | -------------------------------------------------------------------------------- /crates/pet-jsonrpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-jsonrpc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | serde = { version = "1.0.152", features = ["derive"] } 12 | serde_json = "1.0.93" 13 | pet-core = { path = "../pet-core" } 14 | log = "0.4.21" 15 | env_logger = "0.10.2" 16 | -------------------------------------------------------------------------------- /crates/pet-jsonrpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use serde::{Deserialize, Serialize}; 5 | use std::io::{self, Write}; 6 | 7 | pub mod server; 8 | 9 | #[derive(Serialize, Deserialize)] 10 | #[serde(rename_all = "camelCase")] 11 | #[derive(Debug)] 12 | struct AnyMethodMessage { 13 | pub jsonrpc: String, 14 | pub method: &'static str, 15 | pub params: Option, 16 | } 17 | 18 | pub fn send_message(method: &'static str, params: Option) { 19 | let payload = AnyMethodMessage { 20 | jsonrpc: "2.0".to_string(), 21 | method, 22 | params, 23 | }; 24 | let message = serde_json::to_string(&payload).unwrap(); 25 | print!( 26 | "Content-Length: {}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n{}", 27 | message.len(), 28 | message 29 | ); 30 | let _ = io::stdout().flush(); 31 | } 32 | pub fn send_reply(id: u32, payload: Option) { 33 | let payload = serde_json::json!({ 34 | "jsonrpc": "2.0", 35 | "result": payload, 36 | "id": id 37 | }); 38 | let message = serde_json::to_string(&payload).unwrap(); 39 | print!( 40 | "Content-Length: {}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n{}", 41 | message.len(), 42 | message 43 | ); 44 | let _ = io::stdout().flush(); 45 | } 46 | 47 | pub fn send_error(id: Option, code: i32, message: String) { 48 | let payload = serde_json::json!({ 49 | "jsonrpc": "2.0", 50 | "error": { "code": code, "message": message }, 51 | "id": id 52 | }); 53 | let message = serde_json::to_string(&payload).unwrap(); 54 | print!( 55 | "Content-Length: {}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n{}", 56 | message.len(), 57 | message 58 | ); 59 | let _ = io::stdout().flush(); 60 | } 61 | -------------------------------------------------------------------------------- /crates/pet-linux-global-python/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-linux-global-python" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-fs = { path = "../pet-fs" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-mac-commandlinetools/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-mac-commandlinetools" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-fs = { path = "../pet-fs" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-mac-commandlinetools/README.md: -------------------------------------------------------------------------------- 1 | # Python from Mac Command Line Tools 2 | 3 | ## Notes 4 | 5 | - Look for Python in 6 | - /Library/Developer/CommandLineTools/usr/bin 7 | - /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions 8 | - Sometimes, `/usr/bin/python3` can be a copy of Python for the above locations. 9 | - Unfortunately these are not symlinks, but we need to `spawn` the process to get the actual `sys.executable` information. 10 | - `/Library/Developer/CommandLineTools/usr/bin/python?` are generally symlinks to the Python executable in `/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions//bin/python?`. 11 | - Version 12 | - If we spawn such as `/usr/bin/python3`, then we have the version (for at least one of the Python versions). 13 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 14 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 15 | 16 | ## Known Issues 17 | 18 | - `/usr/bin/python3` can be a copy of Python for Python from one of the above locations. 19 | Unfortunately these are not symlinks, but we need to `spawn` the process to get the actual `sys.executable` information. 20 | -------------------------------------------------------------------------------- /crates/pet-mac-python-org/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-mac-python-org" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-fs = { path = "../pet-fs" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-mac-python-org/README.md: -------------------------------------------------------------------------------- 1 | # Python from Python.org on Mac 2 | 3 | ## Notes 4 | 5 | - Look for Python in 6 | - /Library/Frameworks/Python.framework/Versions/ 7 | - Sometimes, `/usr/local/bin/python?` can be a symlink to Python in one of the above locations. 8 | - Why `sometimes`, thats because any other installation can end up overwrite the symlink in `/usr/local/bin/python?` with something else. 9 | - `/Library/Frameworks/Python.framework/Versions/Current/bin/python?` can be a symlink to Python in one of the above locations. 10 | - Version 11 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 12 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 13 | -------------------------------------------------------------------------------- /crates/pet-mac-xcode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-mac-xcode" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-python-utils = { path = "../pet-python-utils" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-fs = { path = "../pet-fs" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-mac-xcode/README.md: -------------------------------------------------------------------------------- 1 | # Python from Mac XCode 2 | 3 | ## Notes 4 | 5 | - Look for Python in such as: 6 | - /Applications/Xcode.app/Contents/Developer/usr/bin/python3 7 | - /Applications/Xcode_15.0.1.app/Contents/Developer/usr/bin/python3 (such paths are on CI, see here https://github.com/microsoft/python-environment-tools/issues/38) 8 | - Sometimes, `/usr/bin/python3` can be a copy of Python for the above locations. 9 | - Unfortunately these are not symlinks, but we need to `spawn` the process to get the actual `sys.executable` information. 10 | - Version 11 | - If we spawn such as `/usr/bin/python3`, then we have the version (for at least one of the Python versions). 12 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 13 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 14 | 15 | ## Known Issues 16 | 17 | - `/usr/bin/python3` can be a copy of Python for Python from one of the above locations. 18 | Unfortunately these are not symlinks, but we need to `spawn` the process to get the actual `sys.executable` information. 19 | - `find` will never return python installed in XCode. 20 | - The assumption is that if users are using Python installed in XCode, then it will be in `/usr/bin/python3`. 21 | - I.e. its very unlikely users will be using Python by looking for it in `/Applications/Xcode.app/Contents/Developer/usr/bin/python3`. 22 | - If this is not true, then we can always search for Python in such directories and list them. 23 | -------------------------------------------------------------------------------- /crates/pet-pipenv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-pipenv" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-fs = { path = "../pet-fs" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-python-utils = { path = "../pet-python-utils" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-pipenv/README.md: -------------------------------------------------------------------------------- 1 | # Pipenv 2 | 3 | ## Notes 4 | 5 | - Where are pipenv envionments located? 6 | - Pipenv environments are generally located in the `WORKON_HOME`, `~/.venvs` directory. 7 | - Locations are computed from the `WORKON_HOME` environment variable. 8 | - However there are other commonly known locations, found in https://github.com/pypa/pipenv/blob/main/pipenv/utils/shell.py#L184 9 | - And then there are other locations found in documentation on the pipenv https://pipenv.pypa.io/en/latest/virtualenv.html 10 | - Note: Its possible that `WORKON_HOME` variable is not accessible for whatever reason (e.g. its setup in a shell script that is not sourced). Hence its safer to look for all known locations. 11 | - `.project` 12 | - A Python environment is `pipenv` enviornment if: 13 | - A Pytohn envioronment contains a `.project` (this contains the path to the project that the environment is associated with.) 14 | - The project directory contains a `Pipfile` 15 | - Version 16 | - Follow the symlink of the Python file and identify the Pthon install location 17 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 18 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 19 | - On Windows => Extract the version from `pyvenv.cfg` if the python exe and the `pyvenv.cfg` file were created at the same time (max 60s difference). 20 | - Its possible for the Python environment used to create virtual envs to change. 21 | - E.g. assume we create a virtual env using Python 3.9, now `pyvenv.cfg` would contain the version 3.9.0. 22 | - Now assume we upgrade Python 3.9 to Python 3.10, now the `pyvenv.cfg` file still contains 3.9.0. 23 | - However the python executable in the virtual env would point to the same original path and now we have pyhon 3.10 exe there. 24 | - Find is not implemented for this locator 25 | - This is because all environments are located in known locations, hence there is no need to search for them. 26 | - For each environment the callers will invoke the `try_from` method to see if the environment is a `pipenv` environment. 27 | -------------------------------------------------------------------------------- /crates/pet-pipenv/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | 6 | #[derive(Debug, Clone)] 7 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 8 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 9 | pub struct EnvVariables { 10 | #[allow(dead_code)] 11 | pub pipenv_max_depth: u16, 12 | pub pipenv_pipfile: String, 13 | } 14 | 15 | impl EnvVariables { 16 | pub fn from(env: &dyn Environment) -> Self { 17 | EnvVariables { 18 | pipenv_max_depth: env 19 | .get_env_var("PIPENV_MAX_DEPTH".to_string()) 20 | .map(|s| s.parse::().ok().unwrap_or(3)) 21 | .unwrap_or(3), 22 | pipenv_pipfile: env 23 | .get_env_var("PIPENV_PIPFILE".to_string()) 24 | .unwrap_or("Pipfile".to_string()), 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/pet-pixi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-pixi" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-conda = { path = "../pet-conda" } 12 | pet-core = { path = "../pet-core" } 13 | pet-python-utils = { path = "../pet-python-utils" } 14 | log = "0.4.21" 15 | -------------------------------------------------------------------------------- /crates/pet-pixi/README.md: -------------------------------------------------------------------------------- 1 | # Pixi 2 | 3 | ## Notes 4 | 5 | - Pixi environments are detected by: 6 | - Searching for Python interpreters in `.pixi/envs` subdirectories within workspace folders 7 | - Checking for a `conda-meta/pixi` file in potential Pixi environment directories (`.pixi/envs/{env_name}`) 8 | - Determining the version of the Python interpreter from the `conda-meta/python-{version}.json` file 9 | 10 | This process ensures fast detection without spawning processes. 11 | Note that the Pixi locator should run before Conda since Conda could incorrectly identify Pixi environments as Conda environments. 12 | -------------------------------------------------------------------------------- /crates/pet-pixi/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::{Path, PathBuf}; 5 | 6 | use pet_conda::package::{CondaPackageInfo, Package}; 7 | use pet_core::{ 8 | env::PythonEnv, 9 | python_environment::{PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind}, 10 | reporter::Reporter, 11 | Locator, LocatorKind, 12 | }; 13 | use pet_python_utils::executable::find_executables; 14 | 15 | pub fn is_pixi_env(path: &Path) -> bool { 16 | path.join("conda-meta").join("pixi").is_file() 17 | } 18 | 19 | fn get_pixi_prefix(env: &PythonEnv) -> Option { 20 | env.prefix.clone().or_else(|| { 21 | env.executable.parent().and_then(|parent_dir| { 22 | if is_pixi_env(parent_dir) { 23 | Some(parent_dir.to_path_buf()) 24 | } else if parent_dir.ends_with("bin") || parent_dir.ends_with("Scripts") { 25 | parent_dir 26 | .parent() 27 | .filter(|parent| is_pixi_env(parent)) 28 | .map(|parent| parent.to_path_buf()) 29 | } else { 30 | None 31 | } 32 | }) 33 | }) 34 | } 35 | 36 | pub struct Pixi {} 37 | 38 | impl Pixi { 39 | pub fn new() -> Pixi { 40 | Pixi {} 41 | } 42 | } 43 | impl Default for Pixi { 44 | fn default() -> Self { 45 | Self::new() 46 | } 47 | } 48 | 49 | impl Locator for Pixi { 50 | fn get_kind(&self) -> LocatorKind { 51 | LocatorKind::Pixi 52 | } 53 | fn supported_categories(&self) -> Vec { 54 | vec![PythonEnvironmentKind::Pixi] 55 | } 56 | 57 | fn try_from(&self, env: &PythonEnv) -> Option { 58 | get_pixi_prefix(env).and_then(|prefix| { 59 | if !is_pixi_env(&prefix) { 60 | return None; 61 | } 62 | 63 | let name = prefix 64 | .file_name() 65 | .and_then(|name| name.to_str()) 66 | .unwrap_or_default() 67 | .to_string(); 68 | 69 | let symlinks = find_executables(&prefix); 70 | 71 | let version = CondaPackageInfo::from(&prefix, &Package::Python) 72 | .map(|package_info| package_info.version); 73 | 74 | Some( 75 | PythonEnvironmentBuilder::new(Some(PythonEnvironmentKind::Pixi)) 76 | .executable(Some(env.executable.clone())) 77 | .name(Some(name)) 78 | .prefix(Some(prefix)) 79 | .symlinks(Some(symlinks)) 80 | .version(version) 81 | .build(), 82 | ) 83 | }) 84 | } 85 | 86 | fn find(&self, _reporter: &dyn Reporter) {} 87 | } 88 | -------------------------------------------------------------------------------- /crates/pet-poetry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-poetry" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | serde = { version = "1.0.152", features = ["derive"] } 12 | serde_json = "1.0.93" 13 | lazy_static = "1.4.0" 14 | pet-core = { path = "../pet-core" } 15 | pet-python-utils = { path = "../pet-python-utils" } 16 | pet-virtualenv = { path = "../pet-virtualenv" } 17 | pet-reporter = { path = "../pet-reporter" } 18 | pet-fs = { path = "../pet-fs" } 19 | log = "0.4.21" 20 | regex = "1.10.4" 21 | sha2 = "0.10.6" 22 | base64 = "0.22.0" 23 | toml = "0.8.14" 24 | -------------------------------------------------------------------------------- /crates/pet-poetry/README.md: -------------------------------------------------------------------------------- 1 | # Poetry 2 | 3 | ## Notes 4 | 5 | - Where are poetry envionments located? 6 | - The paths were determined by inspecting the source for Poetry code. 7 | - `config.toml` is the global Poetry config file 8 | - `poetry.toml` is the local Poetry config/project file 9 | - Using the `config.toml` and known global locations, enumerate all known Poetry Environments 10 | - Given a project directory (workspace folder), compute the hash for that directory 11 | - Look for an environment with the same hash. 12 | - Given a project directory (workspace folder), determine the local poetry config (`poetry.toml`) 13 | - Check the setting `virtualenvs.in-project` and `POETRY_VIRTUALENVS_IN_PROJECT` 14 | - Based on the above value any existing `.venv` directory in the project directory will be treated as a Poetry environment. 15 | - Version 16 | - Follow the symlink of the Python file and identify the Pthon install location 17 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 18 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 19 | - On Windows => Extract the version from `pyvenv.cfg` if the python exe and the `pyvenv.cfg` file were created at the same time (max 60s difference). 20 | - Its possible for the Python environment used to create virtual envs to change. 21 | - E.g. assume we create a virtual env using Python 3.9, now `pyvenv.cfg` would contain the version 3.9.0. 22 | - Now assume we upgrade Python 3.9 to Python 3.10, now the `pyvenv.cfg` file still contains 3.9.0. 23 | - However the python executable in the virtual env would point to the same original path and now we have pyhon 3.10 exe there. 24 | -------------------------------------------------------------------------------- /crates/pet-poetry/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Debug, Clone)] 8 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 9 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 10 | pub struct EnvVariables { 11 | pub home: Option, 12 | /// Only used in tests, None in production. 13 | pub root: Option, 14 | /// Maps to env var `APPDATA` 15 | pub app_data: Option, 16 | /// Maps to env var `POETRY_VIRTUALENVS_PATH` 17 | pub poetry_virtualenvs_path: Option, 18 | /// Maps to env var `POETRY_HOME` 19 | pub poetry_home: Option, 20 | /// Maps to env var `POETRY_CONFIG_DIR` 21 | pub poetry_config_dir: Option, 22 | /// Maps to env var `POETRY_CACHE_DIR` 23 | pub poetry_cache_dir: Option, 24 | /// Maps to env var `POETRY_VIRTUALENVS_IN_PROJECT` 25 | pub poetry_virtualenvs_in_project: Option, 26 | /// Maps to env var `PATH` 27 | pub path: Option, 28 | } 29 | 30 | impl EnvVariables { 31 | pub fn from(env: &dyn Environment) -> Self { 32 | let mut poetry_home = None; 33 | let home = env.get_user_home(); 34 | if let (Some(home), Some(poetry_home_value)) = 35 | (&home, &env.get_env_var("POETRY_HOME".to_string())) 36 | { 37 | if poetry_home_value.starts_with('~') { 38 | poetry_home = Some(PathBuf::from( 39 | poetry_home_value.replace('~', home.to_str().unwrap()), 40 | )); 41 | } else { 42 | poetry_home = Some(PathBuf::from(poetry_home_value)); 43 | } 44 | } 45 | 46 | EnvVariables { 47 | home, 48 | path: env.get_env_var("PATH".to_string()), 49 | root: env.get_root(), 50 | app_data: env.get_env_var("APPDATA".to_string()).map(PathBuf::from), 51 | poetry_virtualenvs_path: env 52 | .get_env_var("POETRY_VIRTUALENVS_PATH".to_string()) 53 | .map(PathBuf::from), 54 | poetry_cache_dir: env 55 | .get_env_var("POETRY_CACHE_DIR".to_string()) 56 | .map(PathBuf::from), 57 | poetry_config_dir: env 58 | .get_env_var("POETRY_CONFIG_DIR".to_string()) 59 | .map(PathBuf::from), 60 | poetry_virtualenvs_in_project: env 61 | .get_env_var("POETRY_VIRTUALENVS_IN_PROJECT".to_string()) 62 | .map(|v| v == "1" || v.to_lowercase() == "true"), 63 | poetry_home, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /crates/pet-poetry/src/environment.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::PathBuf; 5 | 6 | use pet_core::python_environment::{ 7 | PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind, 8 | }; 9 | use pet_python_utils::{executable::find_executables, version}; 10 | 11 | use crate::manager::PoetryManager; 12 | 13 | pub fn create_poetry_env( 14 | prefix: &PathBuf, 15 | project_dir: PathBuf, 16 | manager: Option, 17 | ) -> Option { 18 | if !prefix.exists() { 19 | return None; 20 | } 21 | let executables = find_executables(prefix); 22 | if executables.is_empty() { 23 | return None; 24 | } 25 | let version = version::from_creator_for_virtual_env(prefix); 26 | Some( 27 | PythonEnvironmentBuilder::new(Some(PythonEnvironmentKind::Poetry)) 28 | .executable(Some(executables[0].clone())) 29 | .prefix(Some(prefix.clone())) 30 | .version(version) 31 | .manager(manager.map(|m| m.to_manager())) 32 | .project(Some(project_dir.clone())) 33 | .symlinks(Some(executables)) 34 | .build(), 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /crates/pet-poetry/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use pet_poetry::env_variables::EnvVariables; 6 | use std::{collections::HashMap, path::PathBuf}; 7 | 8 | #[allow(dead_code)] 9 | pub fn resolve_test_path(paths: &[&str]) -> PathBuf { 10 | let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); 11 | 12 | paths.iter().for_each(|p| root.push(p)); 13 | 14 | root 15 | } 16 | 17 | #[allow(dead_code)] 18 | pub fn create_env_variables(home: PathBuf, root: PathBuf) -> EnvVariables { 19 | EnvVariables { 20 | home: Some(home), 21 | root: Some(root), 22 | path: None, 23 | app_data: None, 24 | poetry_cache_dir: None, 25 | poetry_config_dir: None, 26 | poetry_home: None, 27 | poetry_virtualenvs_in_project: None, 28 | poetry_virtualenvs_path: None, 29 | } 30 | } 31 | 32 | #[allow(dead_code)] 33 | pub struct TestEnvironment { 34 | vars: HashMap, 35 | home: Option, 36 | root: Option, 37 | } 38 | #[allow(dead_code)] 39 | pub fn create_test_environment( 40 | vars: HashMap, 41 | home: Option, 42 | root: Option, 43 | ) -> TestEnvironment { 44 | impl Environment for TestEnvironment { 45 | fn get_env_var(&self, key: String) -> Option { 46 | self.vars.get(&key).cloned() 47 | } 48 | fn get_root(&self) -> Option { 49 | self.root.clone() 50 | } 51 | fn get_user_home(&self) -> Option { 52 | self.home.clone() 53 | } 54 | fn get_know_global_search_locations(&self) -> Vec { 55 | vec![] 56 | } 57 | } 58 | TestEnvironment { vars, home, root } 59 | } 60 | -------------------------------------------------------------------------------- /crates/pet-poetry/tests/unix/global_config_with_values/user_home/config_dir/config.toml: -------------------------------------------------------------------------------- 1 | cache-dir = "/path/to/cache/directory" 2 | 3 | [virtualenvs] 4 | in-project = true # Some comments 5 | create = false # Some comments 6 | path = "some/path/virtualenvs" # Some comments 7 | -------------------------------------------------------------------------------- /crates/pet-poetry/tests/unix/local_config_with_values/project_dir/poetry.toml: -------------------------------------------------------------------------------- 1 | cache-dir = "/directory" 2 | 3 | [virtualenvs] 4 | in-project = false # Some comments 5 | create = false # Some comments 6 | -------------------------------------------------------------------------------- /crates/pet-poetry/tests/unix/local_config_with_values/user_home/config_dir/config.toml: -------------------------------------------------------------------------------- 1 | cache-dir = "/path/to/cache/directory" 2 | 3 | [virtualenvs] 4 | in-project = true # Some comments 5 | create = false # Some comments 6 | path = "some/path/virtualenvs" # Some comments 7 | -------------------------------------------------------------------------------- /crates/pet-pyenv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-pyenv" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | serde = { version = "1.0.152", features = ["derive"] } 12 | serde_json = "1.0.93" 13 | lazy_static = "1.4.0" 14 | pet-core = { path = "../pet-core" } 15 | pet-python-utils = { path = "../pet-python-utils" } 16 | pet-reporter = { path = "../pet-reporter" } 17 | pet-fs = { path = "../pet-fs" } 18 | pet-conda = { path = "../pet-conda" } 19 | log = "0.4.21" 20 | regex = "1.10.4" 21 | -------------------------------------------------------------------------------- /crates/pet-pyenv/README.md: -------------------------------------------------------------------------------- 1 | # Pyenv 2 | 3 | ## Notes 4 | 5 | - Where is pyenv located? 6 | - For windows its generally `~/.pyenv/pyenv-win` else `~/.pyenv` 7 | - `versions` sub directory for `pyenv` contains all Python versions installed using pyenv 8 | - On windows, if the directory ends with `-win32`, then its a 32bit Windows Python installation. 9 | - Version 10 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 11 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 12 | -------------------------------------------------------------------------------- /crates/pet-pyenv/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Debug, Clone)] 8 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 9 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 10 | pub struct EnvVariables { 11 | pub home: Option, 12 | pub root: Option, 13 | pub path: Option, 14 | pub pyenv_root: Option, 15 | pub pyenv: Option, 16 | pub known_global_search_locations: Vec, 17 | } 18 | 19 | impl EnvVariables { 20 | pub fn from(env: &dyn Environment) -> Self { 21 | EnvVariables { 22 | home: env.get_user_home(), 23 | root: env.get_root(), 24 | path: env.get_env_var("PATH".to_string()), 25 | pyenv_root: env.get_env_var("PYENV_ROOT".to_string()), 26 | pyenv: env.get_env_var("PYENV".to_string()), 27 | known_global_search_locations: env.get_know_global_search_locations(), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/pet-pyenv/src/environment_locations.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::env_variables::EnvVariables; 5 | use pet_fs::path::norm_case; 6 | use std::path::PathBuf; 7 | 8 | #[cfg(windows)] 9 | pub fn get_home_pyenv_dir(env_vars: &EnvVariables) -> Option { 10 | let home = env_vars.home.clone()?; 11 | Some(norm_case(home.join(".pyenv").join("pyenv-win"))) 12 | } 13 | 14 | #[cfg(unix)] 15 | pub fn get_home_pyenv_dir(env_vars: &EnvVariables) -> Option { 16 | let home = env_vars.home.clone()?; 17 | Some(norm_case(home.join(".pyenv"))) 18 | } 19 | 20 | pub fn get_binary_from_known_paths(env_vars: &EnvVariables) -> Option { 21 | for known_path in &env_vars.known_global_search_locations { 22 | let exe = if cfg!(windows) { 23 | known_path.join("pyenv.exe") 24 | } else { 25 | known_path.join("pyenv") 26 | }; 27 | if exe.is_file() { 28 | return Some(norm_case(exe)); 29 | } 30 | } 31 | None 32 | } 33 | 34 | pub fn get_pyenv_dir(env_vars: &EnvVariables) -> Option { 35 | // Check if the pyenv environment variables exist: PYENV on Windows, PYENV_ROOT on Unix. 36 | // They contain the path to pyenv's installation folder. 37 | // If they don't exist, use the default path: ~/.pyenv/pyenv-win on Windows, ~/.pyenv on Unix. 38 | // If the interpreter path starts with the path to the pyenv folder, then it is a pyenv environment. 39 | // See https://github.com/pyenv/pyenv#locating-the-python-installation for general usage, 40 | // And https://github.com/pyenv-win/pyenv-win for Windows specifics. 41 | 42 | match &env_vars.pyenv_root { 43 | Some(dir) => Some(PathBuf::from(dir)), 44 | None => env_vars.pyenv.as_ref().map(PathBuf::from), 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::{collections::HashMap, path::PathBuf}; 5 | 6 | use pet_core::os_environment::Environment; 7 | use pet_pyenv::env_variables::EnvVariables; 8 | 9 | #[allow(dead_code)] 10 | pub fn resolve_test_path(paths: &[&str]) -> PathBuf { 11 | let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); 12 | 13 | paths.iter().for_each(|p| root.push(p)); 14 | 15 | root 16 | } 17 | 18 | #[allow(dead_code)] 19 | pub fn create_env_variables(home: PathBuf, root: PathBuf) -> EnvVariables { 20 | EnvVariables { 21 | home: Some(home), 22 | root: Some(root), 23 | path: None, 24 | pyenv_root: None, 25 | pyenv: None, 26 | known_global_search_locations: vec![], 27 | } 28 | } 29 | 30 | #[allow(dead_code)] 31 | pub struct TestEnvironment { 32 | vars: HashMap, 33 | home: Option, 34 | root: Option, 35 | globals_locations: Vec, 36 | } 37 | #[allow(dead_code)] 38 | pub fn create_test_environment( 39 | vars: HashMap, 40 | home: Option, 41 | globals_locations: Vec, 42 | root: Option, 43 | ) -> TestEnvironment { 44 | impl Environment for TestEnvironment { 45 | fn get_env_var(&self, key: String) -> Option { 46 | self.vars.get(&key).cloned() 47 | } 48 | fn get_root(&self) -> Option { 49 | self.root.clone() 50 | } 51 | fn get_user_home(&self) -> Option { 52 | self.home.clone() 53 | } 54 | fn get_know_global_search_locations(&self) -> Vec { 55 | self.globals_locations.clone() 56 | } 57 | } 58 | TestEnvironment { 59 | vars, 60 | home, 61 | root, 62 | globals_locations, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/home/opt/homebrew/bin/pyenv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/home/opt/homebrew/bin/pyenv -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/.DS_Store -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.12.1/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.12.1/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.12.1a3/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.12.1a3/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.13-dev/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.13-dev/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.9.9/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/3.9.9/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/bin/conda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/bin/conda -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/one/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/one/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/one/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/one/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/two/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/two/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/two/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda-4.0.0/envs/two/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/anaconda3-2021.04/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge-4.10.1-4/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/mambaforge/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda-latest/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10-22.11.1-1/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-3.10.1/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniconda3-4.0.5/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/conda-meta/python-slugify-5.0.2-pyhd3eb1b0_0.json -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/envs/.conda_envs_dir_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/miniforge3-4.11.0-1/envs/.conda_envs_dir_test -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/my-virtual-env/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/my-virtual-env/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/my-virtual-env/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /Users/donjayamanne/.pyenv/versions/3.10.13/bin 2 | include-system-site-packages = false 3 | version = 3.10.13 4 | -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/nogil-3.9.10-1/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/nogil-3.9.10-1/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/nogil-3.9.10-1/include/python3.9/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Python version identification scheme. 3 | 4 | When the major or minor version changes, the VERSION variable in 5 | configure.ac must also be changed. 6 | 7 | There is also (independent) API version information in modsupport.h. 8 | */ 9 | 10 | /* Values for PY_RELEASE_LEVEL */ 11 | #define PY_RELEASE_LEVEL_ALPHA 0xA 12 | #define PY_RELEASE_LEVEL_BETA 0xB 13 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 14 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 15 | /* Higher for patch releases */ 16 | 17 | /* Version parsed out into numeric values */ 18 | /*--start constants--*/ 19 | #define PY_MAJOR_VERSION 3 20 | #define PY_MINOR_VERSION 9 21 | #define PY_MICRO_VERSION 10 22 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL 23 | #define PY_RELEASE_SERIAL 0 24 | 25 | #define PY_NOGIL 1 26 | #define Py_NOGIL 1 27 | 28 | /* Version as a string */ 29 | #define PY_VERSION "3.9.10" 30 | /*--end constants--*/ 31 | 32 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 33 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 34 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 35 | (PY_MINOR_VERSION << 16) | \ 36 | (PY_MICRO_VERSION << 8) | \ 37 | (PY_RELEASE_LEVEL << 4) | \ 38 | (PY_RELEASE_SERIAL << 0)) 39 | -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/pypy3.9-7.3.15/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/pypy3.9-7.3.15/bin/python -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv/user_home/.pyenv/versions/pypy3.9-7.3.15/include/pypy3.9/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Newfangled version identification scheme. 3 | 4 | This scheme was added in Python 1.5.2b2; before that time, only PATCHLEVEL 5 | was available. To test for presence of the scheme, test for 6 | defined(PY_MAJOR_VERSION). 7 | 8 | When the major or minor version changes, the VERSION variable in 9 | configure.in must also be changed. 10 | 11 | There is also (independent) API version information in modsupport.h. 12 | */ 13 | 14 | /* Values for PY_RELEASE_LEVEL */ 15 | #define PY_RELEASE_LEVEL_ALPHA 0xA 16 | #define PY_RELEASE_LEVEL_BETA 0xB 17 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 18 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 19 | /* Higher for patch releases */ 20 | 21 | /* Version parsed out into numeric values */ 22 | #define PY_MAJOR_VERSION 3 23 | #define PY_MINOR_VERSION 9 24 | #define PY_MICRO_VERSION 18 25 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL 26 | #define PY_RELEASE_SERIAL 0 27 | 28 | /* Version as a string */ 29 | #define PY_VERSION "3.9.18" 30 | 31 | /* PyPy version as a string: make sure to keep this in sync with: 32 | * module/sys/version.py 33 | * doc/conf.py 34 | */ 35 | #define PYPY_VERSION "7.3.15" 36 | #define PYPY_VERSION_NUM 0x07030f00 37 | /* Defined to mean a PyPy where cpyext holds more regular references 38 | to PyObjects, e.g. staying alive as long as the internal PyPy object 39 | stays alive. */ 40 | #define PYPY_CPYEXT_GC 1 41 | #define PyPy_Borrow(a, b) ((void) 0) 42 | 43 | /* Subversion Revision number of this file (not of the repository). 44 | * Empty since Mercurial migration. */ 45 | #define PY_PATCHLEVEL_REVISION "" 46 | 47 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 48 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 49 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 50 | (PY_MINOR_VERSION << 16) | \ 51 | (PY_MICRO_VERSION << 8) | \ 52 | (PY_RELEASE_LEVEL << 4) | \ 53 | (PY_RELEASE_SERIAL << 0)) 54 | -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv_without_envs/home/opt/homebrew/bin/pyenv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv_without_envs/home/opt/homebrew/bin/pyenv -------------------------------------------------------------------------------- /crates/pet-pyenv/tests/unix/pyenv_without_envs/user_home/somefile.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-pyenv/tests/unix/pyenv_without_envs/user_home/somefile.txt -------------------------------------------------------------------------------- /crates/pet-python-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-python-utils" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | lazy_static = "1.4.0" 12 | regex = "1.10.4" 13 | pet-fs = { path = "../pet-fs" } 14 | pet-core = { path = "../pet-core" } 15 | serde = { version = "1.0.152", features = ["derive"] } 16 | log = "0.4.21" 17 | serde_json = "1.0.93" 18 | sha2 = "0.10.6" 19 | env_logger = "0.10.2" 20 | 21 | [features] 22 | ci = [] 23 | ci-jupyter-container = [] 24 | ci-homebrew-container = [] 25 | ci-poetry-global = [] 26 | ci-poetry-project = [] 27 | ci-poetry-custom = [] 28 | -------------------------------------------------------------------------------- /crates/pet-python-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | pub mod cache; 5 | pub mod env; 6 | pub mod executable; 7 | pub mod fs_cache; 8 | mod headers; 9 | pub mod platform_dirs; 10 | pub mod version; 11 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::PathBuf; 5 | 6 | #[allow(dead_code)] 7 | pub fn resolve_test_path(paths: &[&str]) -> PathBuf { 8 | let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); 9 | 10 | paths.iter().for_each(|p| root.push(p)); 11 | 12 | root 13 | } 14 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/executable_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | use pet_python_utils::executable; 6 | use std::path::PathBuf; 7 | 8 | use common::resolve_test_path; 9 | 10 | #[cfg(unix)] 11 | #[test] 12 | fn find_executables() { 13 | // .venv 14 | let path: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); 15 | let mut executables = executable::find_executables(&path.clone()); 16 | executables.sort(); 17 | 18 | assert_eq!( 19 | executables, 20 | vec![ 21 | resolve_test_path(&["unix", "executables", ".venv", "bin", "python"]), 22 | resolve_test_path(&["unix", "executables", ".venv", "bin", "python3"]), 23 | ] 24 | ); 25 | 26 | // Python3.9.9 27 | let path: PathBuf = resolve_test_path(&["unix", "executables", "python3.9.9"]).into(); 28 | let mut executables = executable::find_executables(&path.clone()); 29 | executables.sort(); 30 | 31 | assert_eq!( 32 | executables, 33 | vec![ 34 | resolve_test_path(&["unix", "executables", "python3.9.9", "bin", "python3"]), 35 | resolve_test_path(&["unix", "executables", "python3.9.9", "bin", "python3.9.9"]), 36 | ] 37 | ); 38 | 39 | // Conda without Python. 40 | let path: PathBuf = resolve_test_path(&["unix", "executables", "conda_without_python"]).into(); 41 | let executables = executable::find_executables(&path.clone()); 42 | 43 | assert_eq!(executables.len(), 0); 44 | 45 | // Bogus dir 46 | let path: PathBuf = resolve_test_path(&["unix_bogus_dir"]).into(); 47 | let executables = executable::find_executables(&path.clone()); 48 | 49 | assert_eq!(executables.len(), 0); 50 | } 51 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/sys_prefix_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | mod common; 5 | use pet_python_utils::version; 6 | use std::path::PathBuf; 7 | 8 | use common::resolve_test_path; 9 | 10 | #[cfg(unix)] 11 | #[test] 12 | fn version_from_sys_prefix() { 13 | let path: PathBuf = resolve_test_path(&["unix", "pyvenv_cfg", ".venv"]).into(); 14 | let version = version::from_prefix(&path).unwrap(); 15 | assert_eq!(version, "3.12.1"); 16 | 17 | let path: PathBuf = resolve_test_path(&["unix", "pyvenv_cfg", ".venv", "bin"]).into(); 18 | let version = version::from_prefix(&path).unwrap(); 19 | assert_eq!(version, "3.12.1"); 20 | } 21 | 22 | #[cfg(unix)] 23 | #[test] 24 | fn version_from_sys_prefix_using_version_info_format() { 25 | let path: PathBuf = resolve_test_path(&["unix", "pyvenv_cfg", "hatch_env"]).into(); 26 | let version = version::from_prefix(&path).unwrap(); 27 | assert_eq!(version, "3.9.6.final.0"); 28 | 29 | let path: PathBuf = resolve_test_path(&["unix", "pyvenv_cfg", "hatch_env", "bin"]).into(); 30 | let version = version::from_prefix(&path).unwrap(); 31 | assert_eq!(version, "3.9.6.final.0"); 32 | } 33 | 34 | #[cfg(unix)] 35 | #[test] 36 | fn no_version_without_pyvenv_cfg_and_without_headers() { 37 | let path: PathBuf = 38 | resolve_test_path(&["unix", "pyvenv_cfg", "python3.9.9_without_headers"]).into(); 39 | let version = version::from_prefix(&path); 40 | assert!(version.is_none()); 41 | 42 | let path: PathBuf = 43 | resolve_test_path(&["unix", "pyvenv_cfg", "python3.9.9_without_headers", "bin"]).into(); 44 | let version = version::from_prefix(&path); 45 | assert!(version.is_none()); 46 | 47 | let path: PathBuf = resolve_test_path(&[ 48 | "unix", 49 | "pyvenv_cfg", 50 | "python3.9.9_without_headers", 51 | "bin", 52 | "python", 53 | ]) 54 | .into(); 55 | let version = version::from_prefix(&path); 56 | assert!(version.is_none()); 57 | } 58 | 59 | #[cfg(unix)] 60 | #[test] 61 | fn no_version_for_invalid_paths() { 62 | let path: PathBuf = resolve_test_path(&["unix_1234"]).into(); 63 | let version = version::from_prefix(&path); 64 | assert!(version.is_none()); 65 | } 66 | 67 | #[cfg(unix)] 68 | #[test] 69 | fn version_from_header_files() { 70 | let path: PathBuf = resolve_test_path(&["unix", "headers", "python3.9.9"]).into(); 71 | let version = version::from_prefix(&path).unwrap(); 72 | assert_eq!(version, "3.9.9"); 73 | 74 | let path: PathBuf = resolve_test_path(&["unix", "headers", "python3.9.9", "bin"]).into(); 75 | let version = version::from_prefix(&path).unwrap(); 76 | assert_eq!(version, "3.9.9"); 77 | 78 | let path: PathBuf = resolve_test_path(&["unix", "headers", "python3.10-dev", "bin"]).into(); 79 | let version = version::from_prefix(&path).unwrap(); 80 | assert_eq!(version, "3.10.14+"); 81 | 82 | let path: PathBuf = resolve_test_path(&["unix", "headers", "python3.13", "bin"]).into(); 83 | let version = version::from_prefix(&path).unwrap(); 84 | assert_eq!(version, "3.13.0a5"); 85 | } 86 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/.venv/bin/python: -------------------------------------------------------------------------------- 1 | SystemTime { tv_sec: 1721186754, tv_nsec: 324707000 } -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/.venv/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/executables/.venv/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/.venv/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin 2 | include-system-site-packages = false 3 | version = 3.12.1 4 | executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 5 | command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv 6 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/conda_without_python/conda-meta/history: -------------------------------------------------------------------------------- 1 | ==> 2024-02-29 08:48:22 <== 2 | # cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda7 -y 3 | # conda version: 23.11.0 4 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/python3.9.9/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/executables/python3.9.9/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/python3.9.9/bin/python3.9.9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/executables/python3.9.9/bin/python3.9.9 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/executables/python3.9.9/include/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Python version identification scheme. 3 | 4 | When the major or minor version changes, the VERSION variable in 5 | configure.ac must also be changed. 6 | 7 | There is also (independent) API version information in modsupport.h. 8 | */ 9 | 10 | /* Values for PY_RELEASE_LEVEL */ 11 | #define PY_RELEASE_LEVEL_ALPHA 0xA 12 | #define PY_RELEASE_LEVEL_BETA 0xB 13 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 14 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 15 | /* Higher for patch releases */ 16 | 17 | /* Version parsed out into numeric values */ 18 | /*--start constants--*/ 19 | #define PY_MAJOR_VERSION 3 20 | #define PY_MINOR_VERSION 9 21 | #define PY_MICRO_VERSION 9 22 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL 23 | #define PY_RELEASE_SERIAL 0 24 | 25 | /* Version as a string */ 26 | #define PY_VERSION "3.9.9" 27 | /*--end constants--*/ 28 | 29 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 30 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 31 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 32 | (PY_MINOR_VERSION << 16) | \ 33 | (PY_MICRO_VERSION << 8) | \ 34 | (PY_RELEASE_LEVEL << 4) | \ 35 | (PY_RELEASE_SERIAL << 0)) 36 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.10-dev/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.10-dev/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.10-dev/bin/python3.9.9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.10-dev/bin/python3.9.9 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.10-dev/include/python3.10/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Python version identification scheme. 3 | 4 | When the major or minor version changes, the VERSION variable in 5 | configure.ac must also be changed. 6 | 7 | There is also (independent) API version information in modsupport.h. 8 | */ 9 | 10 | /* Values for PY_RELEASE_LEVEL */ 11 | #define PY_RELEASE_LEVEL_ALPHA 0xA 12 | #define PY_RELEASE_LEVEL_BETA 0xB 13 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 14 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 15 | /* Higher for patch releases */ 16 | 17 | /* Version parsed out into numeric values */ 18 | /*--start constants--*/ 19 | #define PY_MAJOR_VERSION 3 20 | #define PY_MINOR_VERSION 10 21 | #define PY_MICRO_VERSION 14 22 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL 23 | #define PY_RELEASE_SERIAL 0 24 | 25 | /* Version as a string */ 26 | #define PY_VERSION "3.10.14+" 27 | /*--end constants--*/ 28 | 29 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 30 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 31 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 32 | (PY_MINOR_VERSION << 16) | \ 33 | (PY_MICRO_VERSION << 8) | \ 34 | (PY_RELEASE_LEVEL << 4) | \ 35 | (PY_RELEASE_SERIAL << 0)) 36 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.13/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.13/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.13/bin/python3.9.9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.13/bin/python3.9.9 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.13/include/python3.13/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Python version identification scheme. 3 | 4 | When the major or minor version changes, the VERSION variable in 5 | configure.ac must also be changed. 6 | 7 | There is also (independent) API version information in modsupport.h. 8 | */ 9 | 10 | /* Values for PY_RELEASE_LEVEL */ 11 | #define PY_RELEASE_LEVEL_ALPHA 0xA 12 | #define PY_RELEASE_LEVEL_BETA 0xB 13 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 14 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 15 | /* Higher for patch releases */ 16 | 17 | /* Version parsed out into numeric values */ 18 | /*--start constants--*/ 19 | #define PY_MAJOR_VERSION 3 20 | #define PY_MINOR_VERSION 13 21 | #define PY_MICRO_VERSION 0 22 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA 23 | #define PY_RELEASE_SERIAL 5 24 | 25 | /* Version as a string */ 26 | #define PY_VERSION "3.13.0a5" 27 | /*--end constants--*/ 28 | 29 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 30 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 31 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 32 | (PY_MINOR_VERSION << 16) | \ 33 | (PY_MICRO_VERSION << 8) | \ 34 | (PY_RELEASE_LEVEL << 4) | \ 35 | (PY_RELEASE_SERIAL << 0)) 36 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.9.9/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.9.9/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.9.9/bin/python3.9.9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/headers/python3.9.9/bin/python3.9.9 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/headers/python3.9.9/include/patchlevel.h: -------------------------------------------------------------------------------- 1 | 2 | /* Python version identification scheme. 3 | 4 | When the major or minor version changes, the VERSION variable in 5 | configure.ac must also be changed. 6 | 7 | There is also (independent) API version information in modsupport.h. 8 | */ 9 | 10 | /* Values for PY_RELEASE_LEVEL */ 11 | #define PY_RELEASE_LEVEL_ALPHA 0xA 12 | #define PY_RELEASE_LEVEL_BETA 0xB 13 | #define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ 14 | #define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ 15 | /* Higher for patch releases */ 16 | 17 | /* Version parsed out into numeric values */ 18 | /*--start constants--*/ 19 | #define PY_MAJOR_VERSION 3 20 | #define PY_MINOR_VERSION 9 21 | #define PY_MICRO_VERSION 9 22 | #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL 23 | #define PY_RELEASE_SERIAL 0 24 | 25 | /* Version as a string */ 26 | #define PY_VERSION "3.9.9" 27 | /*--end constants--*/ 28 | 29 | /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 30 | Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ 31 | #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ 32 | (PY_MINOR_VERSION << 16) | \ 33 | (PY_MICRO_VERSION << 8) | \ 34 | (PY_RELEASE_LEVEL << 4) | \ 35 | (PY_RELEASE_SERIAL << 0)) 36 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/.venv/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/pyvenv_cfg/.venv/bin/python -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/.venv/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/pyvenv_cfg/.venv/bin/python3 -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/.venv/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin 2 | include-system-site-packages = false 3 | version = 3.12.1 4 | executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 5 | command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv 6 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/hatch_env/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/pyvenv_cfg/hatch_env/bin/python -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/hatch_env/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /Library/Developer/CommandLineTools/usr/bin 2 | implementation = CPython 3 | version_info = 3.9.6.final.0 4 | virtualenv = 20.26.2 5 | include-system-site-packages = false 6 | base-prefix = /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9 7 | base-exec-prefix = /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9 8 | base-executable = /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3.9 9 | -------------------------------------------------------------------------------- /crates/pet-python-utils/tests/unix/pyvenv_cfg/python3.9.9_without_headers/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/python-environment-tools/f122ce710251659ed11dc67b52b6f8a9c31e73cc/crates/pet-python-utils/tests/unix/pyvenv_cfg/python3.9.9_without_headers/bin/python -------------------------------------------------------------------------------- /crates/pet-reporter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-reporter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-jsonrpc = { path = "../pet-jsonrpc" } 13 | log = "0.4.21" 14 | env_logger = "0.10.2" 15 | serde = { version = "1.0.152", features = ["derive"] } 16 | serde_json = "1.0.93" 17 | -------------------------------------------------------------------------------- /crates/pet-reporter/src/cache.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::environment::get_environment_key; 5 | use pet_core::{manager::EnvManager, python_environment::PythonEnvironment, reporter::Reporter}; 6 | use std::{ 7 | collections::HashMap, 8 | path::PathBuf, 9 | sync::{Arc, Mutex}, 10 | }; 11 | 12 | /// Poorly named, needs to be renamed, 13 | /// The purpose of this reporter was to act as a cache, but since then 14 | /// the requirements of caching have changed and this is no longer a cache. 15 | /// This is merely a decorator class that ensures we do not report the same env/manager more than once. 16 | pub struct CacheReporter { 17 | reporter: Arc, 18 | reported_managers: Arc>>, 19 | reported_environments: Arc>>, 20 | } 21 | 22 | impl CacheReporter { 23 | pub fn new(reporter: Arc) -> Self { 24 | Self { 25 | reporter, 26 | reported_managers: Arc::new(Mutex::new(HashMap::new())), 27 | reported_environments: Arc::new(Mutex::new(HashMap::new())), 28 | } 29 | } 30 | } 31 | impl Reporter for CacheReporter { 32 | fn report_telemetry(&self, event: &pet_core::telemetry::TelemetryEvent) { 33 | self.reporter.report_telemetry(event); 34 | } 35 | fn report_manager(&self, manager: &EnvManager) { 36 | let mut reported_managers = self.reported_managers.lock().unwrap(); 37 | if !reported_managers.contains_key(&manager.executable) { 38 | reported_managers.insert(manager.executable.clone(), manager.clone()); 39 | self.reporter.report_manager(manager); 40 | } 41 | } 42 | 43 | fn report_environment(&self, env: &PythonEnvironment) { 44 | if let Some(key) = get_environment_key(env) { 45 | let mut reported_environments = self.reported_environments.lock().unwrap(); 46 | if !reported_environments.contains_key(&key) { 47 | reported_environments.insert(key.clone(), env.clone()); 48 | self.reporter.report_environment(env); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /crates/pet-reporter/src/collect.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::{manager::EnvManager, python_environment::PythonEnvironment, reporter::Reporter}; 5 | use std::sync::{Arc, Mutex}; 6 | 7 | /// Used to just collect the environments and managers and will not report anytihng anywhere. 8 | pub struct CollectReporter { 9 | pub managers: Arc>>, 10 | pub environments: Arc>>, 11 | } 12 | 13 | impl Default for CollectReporter { 14 | fn default() -> Self { 15 | Self::new() 16 | } 17 | } 18 | 19 | impl CollectReporter { 20 | pub fn new() -> CollectReporter { 21 | CollectReporter { 22 | managers: Arc::new(Mutex::new(vec![])), 23 | environments: Arc::new(Mutex::new(vec![])), 24 | } 25 | } 26 | } 27 | impl Reporter for CollectReporter { 28 | fn report_telemetry(&self, _event: &pet_core::telemetry::TelemetryEvent) { 29 | // 30 | } 31 | fn report_manager(&self, manager: &EnvManager) { 32 | self.managers.lock().unwrap().push(manager.clone()); 33 | } 34 | 35 | fn report_environment(&self, env: &PythonEnvironment) { 36 | self.environments.lock().unwrap().push(env.clone()); 37 | } 38 | } 39 | 40 | pub fn create_reporter() -> CollectReporter { 41 | CollectReporter::new() 42 | } 43 | -------------------------------------------------------------------------------- /crates/pet-reporter/src/environment.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use log::error; 5 | use pet_core::python_environment::{PythonEnvironment, PythonEnvironmentKind}; 6 | use std::path::PathBuf; 7 | 8 | pub fn get_environment_key(env: &PythonEnvironment) -> Option { 9 | if let Some(exe) = &env.executable { 10 | Some(exe.clone()) 11 | } else if let Some(prefix) = &env.prefix { 12 | // If this is a conda env without Python, then the exe will be prefix/bin/python 13 | if env.kind == Some(PythonEnvironmentKind::Conda) { 14 | Some(prefix.join("bin").join(if cfg!(windows) { 15 | "python.exe" 16 | } else { 17 | "python" 18 | })) 19 | } else { 20 | Some(prefix.clone()) 21 | } 22 | } else { 23 | error!( 24 | "Failed to report environment due to lack of exe & prefix: {:?}", 25 | env 26 | ); 27 | None 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/pet-reporter/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | pub mod cache; 5 | pub mod collect; 6 | pub mod environment; 7 | pub mod jsonrpc; 8 | pub mod stdio; 9 | -------------------------------------------------------------------------------- /crates/pet-reporter/src/stdio.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use env_logger::Builder; 5 | use log::LevelFilter; 6 | use pet_core::{ 7 | manager::{EnvManager, EnvManagerType}, 8 | python_environment::{PythonEnvironment, PythonEnvironmentKind}, 9 | reporter::Reporter, 10 | }; 11 | use serde::{Deserialize, Serialize}; 12 | use std::{ 13 | collections::HashMap, 14 | sync::{Arc, Mutex}, 15 | }; 16 | 17 | pub struct StdioReporter { 18 | print_list: bool, 19 | managers: Arc>>, 20 | environments: Arc, u16>>>, 21 | kind: Option, 22 | } 23 | 24 | pub struct Summary { 25 | pub managers: HashMap, 26 | pub environments: HashMap, u16>, 27 | } 28 | 29 | impl StdioReporter { 30 | pub fn get_summary(&self) -> Summary { 31 | let managers = self.managers.lock().unwrap(); 32 | let environments = self.environments.lock().unwrap(); 33 | Summary { 34 | managers: managers.clone(), 35 | environments: environments.clone(), 36 | } 37 | } 38 | } 39 | impl Reporter for StdioReporter { 40 | fn report_telemetry(&self, _event: &pet_core::telemetry::TelemetryEvent) { 41 | // 42 | } 43 | fn report_manager(&self, manager: &EnvManager) { 44 | let mut managers = self.managers.lock().unwrap(); 45 | let count = managers.get(&manager.tool).unwrap_or(&0) + 1; 46 | managers.insert(manager.tool, count); 47 | if self.print_list { 48 | println!("{manager}") 49 | } 50 | } 51 | 52 | fn report_environment(&self, env: &PythonEnvironment) { 53 | if self.kind.is_some() && env.kind != self.kind { 54 | return; 55 | } 56 | let mut environments = self.environments.lock().unwrap(); 57 | let count = environments.get(&env.kind).unwrap_or(&0) + 1; 58 | environments.insert(env.kind, count); 59 | if self.print_list { 60 | println!("{env}") 61 | } 62 | } 63 | } 64 | 65 | pub fn create_reporter(print_list: bool, kind: Option) -> StdioReporter { 66 | StdioReporter { 67 | print_list, 68 | managers: Arc::new(Mutex::new(HashMap::new())), 69 | environments: Arc::new(Mutex::new(HashMap::new())), 70 | kind, 71 | } 72 | } 73 | 74 | #[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)] 75 | pub enum LogLevel { 76 | #[serde(rename = "debug")] 77 | Debug, 78 | #[serde(rename = "info")] 79 | Info, 80 | #[serde(rename = "warning")] 81 | Warning, 82 | #[serde(rename = "error")] 83 | Error, 84 | } 85 | 86 | #[derive(Serialize, Deserialize)] 87 | #[serde(rename_all = "camelCase")] 88 | pub struct Log { 89 | pub message: String, 90 | pub level: LogLevel, 91 | } 92 | 93 | pub fn initialize_logger(log_level: LevelFilter) { 94 | Builder::new().filter(None, log_level).init(); 95 | } 96 | -------------------------------------------------------------------------------- /crates/pet-telemetry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-telemetry" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-fs = { path = "../pet-fs" } 13 | pet-python-utils = { path = "../pet-python-utils" } 14 | log = "0.4.21" 15 | env_logger = "0.10.2" 16 | lazy_static = "1.4.0" 17 | regex = "1.10.4" 18 | -------------------------------------------------------------------------------- /crates/pet-venv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-venv" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-virtualenv = { path = "../pet-virtualenv" } 13 | pet-python-utils = { path = "../pet-python-utils" } 14 | log = "0.4.21" 15 | -------------------------------------------------------------------------------- /crates/pet-venv/README.md: -------------------------------------------------------------------------------- 1 | # Venv 2 | 3 | ## Notes 4 | 5 | - A Python environment containing a `pyvenv.cfg` file is a virtual environment. 6 | - Note: `poetry`, `pipenv`, `virtualenvwrapper`, etc all create virtual environments that have a `pyvenv.cfg` file. 7 | - Hence when determining whether an Environment is a `venv` environment, we need to first if it is some other type like `poetry` or the like. 8 | - Version 9 | - Follow the symlink of the Python file and identify the Pthon install location 10 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 11 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 12 | - On Windows => Extract the version from `pyvenv.cfg` if the python exe and the `pyvenv.cfg` file were created at the same time (max 60s difference). 13 | - Its possible for the Python environment used to create virtual envs to change. 14 | - E.g. assume we create a virtual env using Python 3.9, now `pyvenv.cfg` would contain the version 3.9.0. 15 | - Now assume we upgrade Python 3.9 to Python 3.10, now the `pyvenv.cfg` file still contains 3.9.0. 16 | - However the python executable in the virtual env would point to the same original path and now we have pyhon 3.10 exe there. 17 | -------------------------------------------------------------------------------- /crates/pet-venv/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use std::path::Path; 5 | 6 | use pet_core::{ 7 | env::PythonEnv, 8 | python_environment::{PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind}, 9 | pyvenv_cfg::PyVenvCfg, 10 | reporter::Reporter, 11 | Locator, LocatorKind, 12 | }; 13 | use pet_python_utils::executable::find_executables; 14 | use pet_python_utils::version; 15 | 16 | fn is_venv_internal(env: &PythonEnv) -> Option { 17 | // env path cannot be empty. 18 | Some( 19 | PyVenvCfg::find(env.executable.parent()?).is_some() 20 | || PyVenvCfg::find(&env.prefix.clone()?).is_some(), 21 | ) 22 | } 23 | pub fn is_venv(env: &PythonEnv) -> bool { 24 | is_venv_internal(env).unwrap_or_default() 25 | } 26 | pub fn is_venv_dir(path: &Path) -> bool { 27 | PyVenvCfg::find(path).is_some() 28 | } 29 | pub struct Venv {} 30 | 31 | impl Venv { 32 | pub fn new() -> Venv { 33 | Venv {} 34 | } 35 | } 36 | impl Default for Venv { 37 | fn default() -> Self { 38 | Self::new() 39 | } 40 | } 41 | impl Locator for Venv { 42 | fn get_kind(&self) -> LocatorKind { 43 | LocatorKind::Venv 44 | } 45 | fn supported_categories(&self) -> Vec { 46 | vec![PythonEnvironmentKind::Venv] 47 | } 48 | 49 | fn try_from(&self, env: &PythonEnv) -> Option { 50 | if is_venv(env) { 51 | let mut prefix = env.prefix.clone(); 52 | if prefix.is_none() { 53 | prefix = Some(env.executable.parent()?.parent()?.to_path_buf()); 54 | } 55 | let version = match env.version { 56 | Some(ref v) => Some(v.clone()), 57 | None => match &prefix { 58 | Some(prefix) => version::from_creator_for_virtual_env(prefix), 59 | None => None, 60 | }, 61 | }; 62 | let mut symlinks = vec![]; 63 | if let Some(ref prefix) = prefix { 64 | symlinks.append(&mut find_executables(prefix)); 65 | } 66 | 67 | // Get the name from the prefix if it exists. 68 | let cfg = PyVenvCfg::find(env.executable.parent()?) 69 | .or_else(|| PyVenvCfg::find(&env.prefix.clone()?)); 70 | let name = cfg.and_then(|cfg| cfg.prompt); 71 | 72 | Some( 73 | PythonEnvironmentBuilder::new(Some(PythonEnvironmentKind::Venv)) 74 | .name(name) 75 | .executable(Some(env.executable.clone())) 76 | .version(version) 77 | .prefix(prefix) 78 | .symlinks(Some(symlinks)) 79 | .build(), 80 | ) 81 | } else { 82 | None 83 | } 84 | } 85 | 86 | fn find(&self, _reporter: &dyn Reporter) { 87 | // There are no common global locations for virtual environments. 88 | // We expect the user of this class to call `is_compatible` 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /crates/pet-virtualenv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-virtualenv" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-core = { path = "../pet-core" } 12 | pet-fs = { path = "../pet-fs" } 13 | pet-python-utils = { path = "../pet-python-utils" } 14 | log = "0.4.21" 15 | -------------------------------------------------------------------------------- /crates/pet-virtualenv/README.md: -------------------------------------------------------------------------------- 1 | # Virtualenv 2 | 3 | ## Notes 4 | 5 | - A Python environment containing a activation scripts such as `/bin/activate` or `Scripts/activate.bat` or the like is a virtual environment. 6 | - Note: `poetry`, `pipenv`, `virtualenvwrapper`, etc all create virtual environments that have a `pyvenv.cfg` file. 7 | - Hence when determining whether an Environment is a `virtualenv` environment, we need to first if it is some other type like `poetry` or the like. 8 | - Similarly an environment containing `pyvenv.cfg` is generally not considered a `virtualenv`, as it could be a `venv`, `poetry`, `pipenv`, etc. 9 | - Version 10 | - Follow the symlink of the Python file and identify the Pthon install location 11 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 12 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 13 | - On Windows => Extract the version from `pyvenv.cfg` if the python exe and the `pyvenv.cfg` file were created at the same time (max 60s difference). 14 | - Its possible for the Python environment used to create virtual envs to change. 15 | - E.g. assume we create a virtual env using Python 3.9, now `pyvenv.cfg` would contain the version 3.9.0. 16 | - Now assume we upgrade Python 3.9 to Python 3.10, now the `pyvenv.cfg` file still contains 3.9.0. 17 | - However the python executable in the virtual env would point to the same original path and now we have pyhon 3.10 exe there. 18 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-virtualenvwrapper" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(target_os = "windows")'.dependencies] 8 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 9 | 10 | [dependencies] 11 | pet-fs = { path = "../pet-fs" } 12 | pet-core = { path = "../pet-core" } 13 | pet-virtualenv = { path = "../pet-virtualenv" } 14 | pet-python-utils = { path = "../pet-python-utils" } 15 | log = "0.4.21" 16 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/README.md: -------------------------------------------------------------------------------- 1 | # Virtualenvwrapper 2 | 3 | ## Notes 4 | 5 | - They are regular Python environments created a specific location 6 | - The location is defined in the `WORKON_HOME` environment variable. 7 | - Else defaults to `~/.virtualenvs` 8 | - They too have a have a `.project` file in the root of the environment 9 | This file contains the path to the project directory thats associated with this environment. 10 | - They have a `.pyvenv.cfg` file in the root of the environment 11 | This file contains the version of Python used in this environment. 12 | - A Python environment containing a `pyvenv.cfg` file is a virtual environment. 13 | - Note: `poetry`, `pipenv`, `virtualenvwrapper`, etc all create virtual environments that have a `pyvenv.cfg` file. 14 | - Hence when determining whether an Environment is a `virtualenvwrapper` environment, we need to first if it is some other type like `poetry` or the like. 15 | - Version 16 | - Follow the symlink of the Python file and identify the Pthon install location 17 | - Extract the version of Python from the `patchlevel.h` file from the entry `#define PY_VERSION` 18 | - These files are located in `/include/patchlevel.h` or `/Headers/patchlevel.h` 19 | - On Windows => Extract the version from `pyvenv.cfg` if the python exe and the `pyvenv.cfg` file were created at the same time (max 60s difference). 20 | - Its possible for the Python environment used to create virtual envs to change. 21 | - E.g. assume we create a virtual env using Python 3.9, now `pyvenv.cfg` would contain the version 3.9.0. 22 | - Now assume we upgrade Python 3.9 to Python 3.10, now the `pyvenv.cfg` file still contains 3.9.0. 23 | - However the python executable in the virtual env would point to the same original path and now we have pyhon 3.10 exe there. 24 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Debug, Clone)] 8 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 9 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 10 | pub struct EnvVariables { 11 | pub home: Option, 12 | pub workon_home: Option, 13 | } 14 | 15 | impl EnvVariables { 16 | pub fn from(env: &dyn Environment) -> Self { 17 | EnvVariables { 18 | home: env.get_user_home(), 19 | workon_home: env.get_env_var("WORKON_HOME".to_string()), 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/src/environment_locations.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::env_variables::EnvVariables; 5 | use pet_fs::path::norm_case; 6 | use std::path::PathBuf; 7 | 8 | #[cfg(windows)] 9 | fn get_default_virtualenvwrapper_path(env_vars: &EnvVariables) -> Option { 10 | // In Windows, the default path for WORKON_HOME is %USERPROFILE%\Envs. 11 | // If 'Envs' is not available we should default to '.virtualenvs'. Since that 12 | // is also valid for windows. 13 | 14 | if let Some(user_home) = &env_vars.home { 15 | let home = user_home.join("Envs"); 16 | if home.exists() { 17 | return Some(norm_case(home)); 18 | } 19 | let home = user_home.join("virtualenvs"); 20 | if home.exists() { 21 | return Some(norm_case(home)); 22 | } 23 | } 24 | None 25 | } 26 | 27 | #[cfg(unix)] 28 | fn get_default_virtualenvwrapper_path(env_vars: &EnvVariables) -> Option { 29 | if let Some(home) = &env_vars.home { 30 | let home = home.join(".virtualenvs"); 31 | if home.exists() { 32 | return Some(norm_case(&home)); 33 | } 34 | } 35 | None 36 | } 37 | 38 | pub fn get_work_on_home_path(environment: &EnvVariables) -> Option { 39 | // The WORKON_HOME variable contains the path to the root directory of all virtualenvwrapper environments. 40 | // If the interpreter path belongs to one of them then it is a virtualenvwrapper type of environment. 41 | if let Some(work_on_home) = &environment.workon_home { 42 | // TODO: Why do we need to canonicalize the path? 43 | if let Ok(work_on_home) = std::fs::canonicalize(work_on_home) { 44 | if work_on_home.exists() { 45 | return Some(norm_case(&work_on_home)); 46 | } 47 | } 48 | } 49 | get_default_virtualenvwrapper_path(environment) 50 | } 51 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/src/environments.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use crate::{env_variables::EnvVariables, environment_locations::get_work_on_home_path}; 5 | use pet_core::env::PythonEnv; 6 | use pet_fs::path::norm_case; 7 | use pet_virtualenv::is_virtualenv; 8 | use std::{fs, path::PathBuf}; 9 | 10 | pub fn is_virtualenvwrapper(env: &PythonEnv, environment: &EnvVariables) -> bool { 11 | if env.prefix.is_none() { 12 | return false; 13 | } 14 | 15 | // For environment to be a virtualenvwrapper based it has to follow these two rules: 16 | // 1. It should be in a sub-directory under the WORKON_HOME 17 | // 2. It should be a valid virtualenv environment 18 | if let Some(work_on_home_dir) = get_work_on_home_path(environment) { 19 | if env.executable.starts_with(work_on_home_dir) && is_virtualenv(env) { 20 | return true; 21 | } 22 | } 23 | 24 | false 25 | } 26 | 27 | pub fn get_project(env: &PythonEnv) -> Option { 28 | let project_file = env.prefix.clone()?.join(".project"); 29 | let contents = fs::read_to_string(project_file).ok()?; 30 | let project_folder = norm_case(PathBuf::from(contents.trim().to_string())); 31 | if fs::metadata(&project_folder).is_ok() { 32 | Some(norm_case(&project_folder)) 33 | } else { 34 | None 35 | } 36 | } 37 | 38 | // pub fn list_python_environments(path: &PathBuf) -> Option> { 39 | // let mut python_envs: Vec = vec![]; 40 | // for venv_dir in fs::read_dir(path) 41 | // .ok()? 42 | // .filter_map(Result::ok) 43 | // .map(|e| e.path()) 44 | // { 45 | // if fs::metadata(&venv_dir).is_err() { 46 | // continue; 47 | // } 48 | // if let Some(executable) = find_executable(&venv_dir) { 49 | // python_envs.push(PythonEnv::new( 50 | // executable.clone(), 51 | // Some(venv_dir.clone()), 52 | // version::from_pyvenv_cfg(&venv_dir), 53 | // )); 54 | // } 55 | // } 56 | 57 | // Some(python_envs) 58 | // } 59 | -------------------------------------------------------------------------------- /crates/pet-virtualenvwrapper/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use env_variables::EnvVariables; 5 | use environments::{get_project, is_virtualenvwrapper}; 6 | use pet_core::{ 7 | env::PythonEnv, 8 | os_environment::Environment, 9 | python_environment::{PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind}, 10 | reporter::Reporter, 11 | Locator, LocatorKind, 12 | }; 13 | use pet_python_utils::executable::find_executables; 14 | use pet_python_utils::version; 15 | 16 | mod env_variables; 17 | mod environment_locations; 18 | mod environments; 19 | 20 | pub struct VirtualEnvWrapper { 21 | pub env_vars: EnvVariables, 22 | } 23 | 24 | impl VirtualEnvWrapper { 25 | pub fn from(environment: &dyn Environment) -> VirtualEnvWrapper { 26 | VirtualEnvWrapper { 27 | env_vars: EnvVariables::from(environment), 28 | } 29 | } 30 | } 31 | 32 | impl Locator for VirtualEnvWrapper { 33 | fn get_kind(&self) -> LocatorKind { 34 | LocatorKind::VirtualEnvWrapper 35 | } 36 | fn supported_categories(&self) -> Vec { 37 | vec![PythonEnvironmentKind::VirtualEnvWrapper] 38 | } 39 | 40 | fn try_from(&self, env: &PythonEnv) -> Option { 41 | if !is_virtualenvwrapper(env, &self.env_vars) { 42 | return None; 43 | } 44 | let version = match env.version { 45 | Some(ref v) => Some(v.clone()), 46 | None => match &env.prefix { 47 | Some(prefix) => version::from_creator_for_virtual_env(prefix), 48 | None => None, 49 | }, 50 | }; 51 | let mut symlinks = vec![]; 52 | let mut name = None; 53 | if let Some(ref prefix) = env.prefix { 54 | symlinks.append(&mut find_executables(prefix)); 55 | name = prefix.file_name().and_then(|f| f.to_str()); 56 | } 57 | 58 | Some( 59 | PythonEnvironmentBuilder::new(Some(PythonEnvironmentKind::VirtualEnvWrapper)) 60 | .name(name.map(String::from)) 61 | .executable(Some(env.executable.clone())) 62 | .version(version) 63 | .prefix(env.prefix.clone()) 64 | .project(get_project(env)) 65 | .symlinks(Some(symlinks)) 66 | .build(), 67 | ) 68 | } 69 | 70 | fn find(&self, _reporter: &dyn Reporter) {} 71 | } 72 | -------------------------------------------------------------------------------- /crates/pet-windows-registry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-windows-registry" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(windows)'.dependencies] 8 | winreg = "0.55.0" 9 | 10 | [target.'cfg(target_os = "windows")'.dependencies] 11 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 12 | 13 | [dependencies] 14 | pet-windows-store = { path = "../pet-windows-store" } 15 | pet-python-utils = { path = "../pet-python-utils" } 16 | pet-virtualenv = { path = "../pet-virtualenv" } 17 | pet-core = { path = "../pet-core" } 18 | pet-fs = { path = "../pet-fs" } 19 | pet-conda = { path = "../pet-conda" } 20 | log = "0.4.21" 21 | lazy_static = "1.4.0" 22 | regex = "1.10.4" 23 | -------------------------------------------------------------------------------- /crates/pet-windows-registry/README.md: -------------------------------------------------------------------------------- 1 | # Windows Registry 2 | 3 | ## Notes 4 | 5 | - Looks for all installations under `HKLM/Software/Python` & `HKCU/Software/Python` 6 | - The registry contains information about the Python installations (prefix, version, display name, etc) 7 | - If a conda installation if found, pass that directory to the conda locator to get all conda environments. 8 | 9 | ```rust 10 | for company of [PythonCore, ContinuumAnalytics]: 11 | for key in [HKLM, HKCU]: 12 | for installed_version in `/Software/Python/` 13 | // installed_version are values like 3.12, 3.10, 3.9, etc 14 | install_key = `/Software/Python//InstallPath` 15 | env_path = `install_key/(Default)` 16 | exe = `install_key/(ExecutablePath)` 17 | 18 | if this is a conda install: 19 | Pass this directory to the conda locator to get all conda environments. 20 | continue 21 | 22 | if `exe` exists on disc: 23 | version = `install_key/(Version)` // SysVersion contains only first 2 parts of version 24 | display_name = `install_key/(DisplayName)` 25 | 👍 track this environment 26 | 27 | ``` 28 | -------------------------------------------------------------------------------- /crates/pet-windows-store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet-windows-store" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(windows)'.dependencies] 8 | winreg = "0.55.0" 9 | 10 | [target.'cfg(target_os = "windows")'.dependencies] 11 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 12 | 13 | [dependencies] 14 | pet-core = { path = "../pet-core" } 15 | pet-fs = { path = "../pet-fs" } 16 | pet-python-utils = { path = "../pet-python-utils" } 17 | pet-virtualenv = { path = "../pet-virtualenv" } 18 | log = "0.4.21" 19 | lazy_static = "1.4.0" 20 | regex = "1.10.4" 21 | -------------------------------------------------------------------------------- /crates/pet-windows-store/src/env_variables.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use pet_core::os_environment::Environment; 5 | use std::path::PathBuf; 6 | 7 | #[derive(Debug, Clone)] 8 | // NOTE: Do not implement Default trait, as we do not want to ever forget to set the values. 9 | // Lets be explicit, this way we never miss a value (in Windows or Unix). 10 | pub struct EnvVariables { 11 | pub home: Option, 12 | } 13 | 14 | impl EnvVariables { 15 | pub fn from(env: &dyn Environment) -> Self { 16 | EnvVariables { 17 | home: env.get_user_home(), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /crates/pet-windows-store/src/environment_locations.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #[cfg(windows)] 5 | use crate::env_variables::EnvVariables; 6 | #[cfg(windows)] 7 | use std::path::PathBuf; 8 | 9 | #[cfg(windows)] 10 | pub fn get_search_locations(environment: &EnvVariables) -> Option { 11 | Some( 12 | environment 13 | .home 14 | .clone()? 15 | .join("AppData") 16 | .join("Local") 17 | .join("Microsoft") 18 | .join("WindowsApps"), 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /crates/pet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [target.'cfg(windows)'.dependencies] 8 | pet-windows-store = { path = "../pet-windows-store" } 9 | pet-windows-registry = { path = "../pet-windows-registry" } 10 | 11 | [target.'cfg(target_os = "windows")'.dependencies] 12 | msvc_spectre_libs = { version = "0.1.1", features = ["error"] } 13 | 14 | [target.'cfg(unix)'.dependencies] 15 | pet-homebrew = { path = "../pet-homebrew" } 16 | 17 | [dependencies] 18 | pet-core = { path = "../pet-core" } 19 | pet-conda = { path = "../pet-conda" } 20 | pet-pixi = { path = "../pet-pixi" } 21 | pet-jsonrpc = { path = "../pet-jsonrpc" } 22 | pet-fs = { path = "../pet-fs" } 23 | pet-pyenv = { path = "../pet-pyenv" } 24 | pet-poetry = { path = "../pet-poetry" } 25 | pet-reporter = { path = "../pet-reporter" } 26 | pet-virtualenvwrapper = { path = "../pet-virtualenvwrapper" } 27 | pet-python-utils = { path = "../pet-python-utils" } 28 | pet-env-var-path = { path = "../pet-env-var-path" } 29 | pet-mac-commandlinetools = { path = "../pet-mac-commandlinetools" } 30 | pet-linux-global-python = { path = "../pet-linux-global-python" } 31 | pet-mac-xcode = { path = "../pet-mac-xcode" } 32 | pet-mac-python-org = { path = "../pet-mac-python-org" } 33 | pet-venv = { path = "../pet-venv" } 34 | pet-virtualenv = { path = "../pet-virtualenv" } 35 | pet-pipenv = { path = "../pet-pipenv" } 36 | pet-telemetry = { path = "../pet-telemetry" } 37 | pet-global-virtualenvs = { path = "../pet-global-virtualenvs" } 38 | log = "0.4.21" 39 | clap = { version = "4.5.4", features = ["derive", "cargo"] } 40 | serde = { version = "1.0.152", features = ["derive"] } 41 | serde_json = "1.0.93" 42 | env_logger = "0.10.2" 43 | lazy_static = "1.4.0" 44 | 45 | [dev-dependencies] 46 | regex = "1.10.4" 47 | 48 | [features] 49 | ci = [] 50 | ci-jupyter-container = [] 51 | ci-homebrew-container = [] 52 | ci-poetry-global = [] 53 | ci-poetry-project = [] 54 | ci-poetry-custom = [] 55 | -------------------------------------------------------------------------------- /crates/pet/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | use lazy_static::lazy_static; 5 | use regex::Regex; 6 | use std::path::PathBuf; 7 | 8 | lazy_static! { 9 | static ref PYTHON_VERSION: Regex = Regex::new("([\\d+\\.?]*).*") 10 | .expect("error parsing Version regex for Python Version in test"); 11 | static ref PYTHON_FULLVERSION: Regex = Regex::new("(\\d+\\.?\\d+\\.?\\d+).*") 12 | .expect("error parsing Version regex for Python Version in test"); 13 | } 14 | 15 | #[allow(dead_code)] 16 | pub fn resolve_test_path(paths: &[&str]) -> PathBuf { 17 | let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); 18 | 19 | paths.iter().for_each(|p| root.push(p)); 20 | 21 | root 22 | } 23 | 24 | #[allow(dead_code)] 25 | pub fn does_version_match(version: &String, expected_version: &String) -> bool { 26 | let version = get_version(version); 27 | expected_version.starts_with(&version) 28 | } 29 | 30 | fn get_version(value: &String) -> String { 31 | // Regex to extract just the d.d.d version from the full version string 32 | let captures = PYTHON_VERSION.captures(value).unwrap(); 33 | let version = captures.get(1).unwrap().as_str().to_string(); 34 | if version.ends_with('.') { 35 | version[..version.len() - 1].to_string() 36 | } else { 37 | version 38 | } 39 | } 40 | 41 | #[allow(dead_code)] 42 | pub fn is_valid_version(value: &String) -> bool { 43 | PYTHON_FULLVERSION.is_match(value) 44 | } 45 | -------------------------------------------------------------------------------- /crates/pet/tests/interpreterInfo.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT License. 3 | 4 | import json 5 | import sys 6 | 7 | obj = { 8 | "version_info": tuple(sys.version_info), 9 | "sys_prefix": sys.prefix, 10 | "sys_version": sys.version, 11 | "is64_bit": sys.maxsize > 2**32, 12 | "executable": sys.executable, 13 | } 14 | 15 | # Everything after this is the information we need 16 | print("503bebe7-c838-4cea-a1bc-0f2963bcb657") 17 | print(json.dumps(obj)) 18 | --------------------------------------------------------------------------------