Skip to content

Commit

Permalink
feat: allow provider to keep symlink even when resolve_symlinks is True
Browse files Browse the repository at this point in the history
  • Loading branch information
frostming committed Jul 2, 2022
1 parent 2aa5956 commit 1fdc49d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
arch: x86

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up PDM
uses: pdm-project/setup-pdm@main
with:
Expand All @@ -36,7 +36,7 @@ jobs:
echo "::set-output name=PIP_CACHE::$(pip cache dir)"
echo "::set-output name=PDM_CACHE::$(pdm config cache_dir)"
- name: Cache Packages
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
${{ steps.set_variables.outputs.PIP_CACHE }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Build artifacts
Expand Down
12 changes: 11 additions & 1 deletion src/findpython/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ def setup_providers(self) -> list[BaseProvider]:
providers.append(provider)
return providers

def add_provider(self, provider: BaseProvider, pos: int | None = None) -> None:
"""Add provider to the provider list.
If pos is given, it will be inserted at the given position.
"""
if pos is not None:
self._providers.insert(pos, provider)
else:
self._providers.append(provider)

def find_all(
self,
major: int | str | None = None,
Expand Down Expand Up @@ -136,12 +145,13 @@ def dedup_key(python_version: PythonVersion) -> str:
return python_version.interpreter.as_posix()
if self.no_same_file:
return python_version.binary_hash()
if self.resolve_symlinks:
if self.resolve_symlinks and not python_version.keep_symlink:
return python_version.real_path.as_posix()
return python_version.executable.as_posix()

def sort_key(python_version: PythonVersion) -> tuple[int, int]:
return (
python_version.executable.is_symlink(),
get_suffix_preference(python_version.name),
-len(python_version.executable.as_posix()),
)
Expand Down
1 change: 1 addition & 0 deletions src/findpython/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class PythonVersion:
_version: Version | None = None
_architecture: str | None = None
_interpreter: Path | None = None
keep_symlink: bool = False

def is_valid(self) -> bool:
"""Return True if the python is not broken."""
Expand Down
11 changes: 9 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def __init__(self) -> None:
self.versions = {}

def add_python(
self, executable, version=None, architecture="64bit", interpreter=None
self,
executable,
version=None,
architecture="64bit",
interpreter=None,
keep_symlink=False,
):
if version is not None:
version = parse(version)
Expand All @@ -22,7 +27,9 @@ def add_python(
executable.parent.mkdir(parents=True, exist_ok=True)
executable.touch(exist_ok=True)
executable.chmod(0o744)
py_ver = PythonVersion(executable, version, architecture, interpreter)
py_ver = PythonVersion(
executable, version, architecture, interpreter, keep_symlink
)
if version is not None:
py_ver._get_version = lambda: version
self.versions[executable] = py_ver
Expand Down
15 changes: 15 additions & 0 deletions tests/test_finder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
from pathlib import Path

import pytest
from packaging.version import Version

from findpython import Finder
Expand Down Expand Up @@ -86,6 +87,20 @@ def test_find_python_deduplicate_same_file(mocked_python, tmp_path, switch):
assert (new_python in all_pythons) is not switch


@pytest.mark.skipif(os.name == "nt", reason="Not supported on Windows")
def test_find_python_deduplicate_symlinks(mocked_python, tmp_path):
python = mocked_python.add_python(tmp_path / "python3.9", "3.9.0")
(tmp_path / "python3").symlink_to(python.executable)
symlink1 = mocked_python.add_python(tmp_path / "python3", "3.9.0")
(tmp_path / "python").symlink_to(python.executable)
symlink2 = mocked_python.add_python(tmp_path / "python", "3.9.0", keep_symlink=True)
finder = Finder(resolve_symlinks=True)
all_pythons = finder.find_all()
assert python in all_pythons
assert symlink1 not in all_pythons
assert symlink2 in all_pythons


def test_find_python_deduplicate_same_interpreter(mocked_python, tmp_path, switch):
if os.name == "nt":
suffix = ".bat"
Expand Down

0 comments on commit 1fdc49d

Please sign in to comment.