Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/manage/indexutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,11 @@ def find_all(self, tags, *, seen_ids=None, loose_company=False, with_prerelease=
seen_ids.add(i["id"].casefold())
yield i

def find_to_install(self, tag, *, loose_company=False, prefer_prerelease=False):
def find_to_install(self, tag, *, loose_company=False, prefer_prerelease=None):
tag_list = [tag] if tag else []
LOGGER.debug("Finding %s to install", tag_list)
if prefer_prerelease is None:
prefer_prerelease = any(t.prefers_prerelease for t in tag_list)
for i in self.find_all(tag_list, loose_company=loose_company, with_prerelease=prefer_prerelease):
return {**i, "source": self.source_url}
if not loose_company:
Expand Down
9 changes: 9 additions & 0 deletions src/manage/installs.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ def get_install_to_run(
default_platform=default_platform,
)

if tag.prefers_prerelease:
for i, t in best:
try:
if Version(i["sort-version"]).is_prerelease:
return _patch_install_to_run(i, t)
except ValueError as ex:
LOGGER.debug("Failed to parse %s to check for prerelease",
i["sort-version"])

if best:
return _patch_install_to_run(*best[0])

Expand Down
16 changes: 10 additions & 6 deletions src/manage/list_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,19 @@ def execute(cmd):
if first_exc:
raise SystemExit(1) from first_exc
if cmd.one:
# Pick the first non-prerelease that'll install for our platform
best = [i for i in installs
if any(t.endswith(plat) for t in i.get("install-for", []))]
for i in best:
if not i["sort-version"].is_prerelease:
installs = [i]
break
else:
if any(t.prefers_prerelease for t in tags):
# First result will be the latest prerelease (or release)
installs = best[:1] or installs
else:
# Pick the first non-prerelease that'll install for our platform
for i in best:
if not i["sort-version"].is_prerelease:
installs = [i]
break
else:
installs = best[:1] or installs
elif cmd.install_dir:
try:
installs = cmd.get_installs(include_unmanaged=cmd.unmanaged)
Expand Down
24 changes: 24 additions & 0 deletions src/manage/tagutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ def startswith(self, other):
return not self.s
return self.s.startswith(other.s)

def endswith(self, other):
if not isinstance(other, type(self)):
return False
if not other.s:
return True
return self.s.endswith(other.s)

def __hash__(self):
return hash(self.s)

Expand Down Expand Up @@ -213,6 +220,12 @@ def match(self, pattern):
def satisfied_by(self, tag):
return tag.match(self)

@property
def prefers_prerelease(self, dev_text=_AscendingText("dev")):
if self._sortkey and self._sortkey[-1] == dev_text:
return True
return False

def __str__(self):
if self.is_core:
return f"{self.tag}{self.platform}"
Expand Down Expand Up @@ -340,6 +353,10 @@ def __init__(self, spec):
def __repr__(self):
return "<TagRange({})>".format(", ".join(repr(r) for r in self.ranges))

@property
def prefers_prerelease(self):
return any(r.prefers_prerelease for r in self.ranges)

def satisfied_by(self, tag):
return all(r(tag) for r in self.ranges)

Expand All @@ -359,6 +376,10 @@ def __init__(self, tag):
assert isinstance(tag, CompanyTag)
self.tag = tag

@property
def prefers_prerelease(self):
return self.tag.prefers_prerelease

def __repr__(self):
return f"{self.OP}{self.tag}"

Expand Down Expand Up @@ -404,6 +425,9 @@ class RangeExclude(Range):
def __call__(self, other):
return not other.matches_bound(self.tag)

@property
def prefers_prerelease(self):
return False

def tag_or_range(tag):
if not isinstance(tag, str):
Expand Down
20 changes: 19 additions & 1 deletion tests/test_tagutils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from manage.tagutils import CompanyTag, TagRange
from manage.tagutils import CompanyTag, TagRange, tag_or_range


@pytest.mark.parametrize("tag_str", [
Expand Down Expand Up @@ -42,6 +42,24 @@ def test_tag_match():
assert not CompanyTag("PythonCore\\4.56").match(CompanyTag("", "3"))


def test_prefer_prerelease():
assert not tag_or_range("3").prefers_prerelease
assert not tag_or_range("3-64").prefers_prerelease
assert not tag_or_range("3.13").prefers_prerelease
assert tag_or_range("3-dev").prefers_prerelease
assert tag_or_range("3.13-DEV").prefers_prerelease
assert tag_or_range("3.13-dev-64").prefers_prerelease

assert not tag_or_range(">3").prefers_prerelease
assert not tag_or_range("<3-64").prefers_prerelease
assert not tag_or_range("==3.13").prefers_prerelease
assert not tag_or_range("!=3.13").prefers_prerelease
assert not tag_or_range("!=3.13-dev").prefers_prerelease
assert tag_or_range(">3-dev").prefers_prerelease
assert tag_or_range("<3.13-DEV").prefers_prerelease
assert tag_or_range("==3.13-dev-64").prefers_prerelease


def test_tag_platform_match():
assert CompanyTag("3.10-64").match(CompanyTag("3.10"))
assert CompanyTag("3.10-64").match(CompanyTag("3.10-64"))
Expand Down
Loading