Skip to content

Commit 311554a

Browse files
committed
Enable explicitly specifying pre-releases without enabling pre-releases
1 parent f0cb3ba commit 311554a

File tree

8 files changed

+287
-3
lines changed

8 files changed

+287
-3
lines changed

hab/parsers/distro.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,25 @@ def matching_versions(self, specification):
2424
"""Returns a list of versions available matching the version specification.
2525
See `packaging.requirements` for details on valid requirements, but it
2626
should be the same as pip requirements.
27+
28+
This respects `self.resolver.prereleases`, so pre-releases will only be
29+
returned if that is set to True or if this specification uses an
30+
"Inclusive ordered comparison"(`<=`, `>=`) and the specification
31+
contains any of the pre-release specifiers (`.dev1`). You will need
32+
to enable prereleases to use "Exclusive ordered comparison"(`<`, `>`)s.
33+
This is consistent with how pip handles these options.
2734
"""
2835
if isinstance(specification, Requirement):
2936
specifier = specification.specifier
3037
elif isinstance(specification, SpecifierSet):
3138
specifier = specification
3239
else:
3340
specifier = Requirement(specification).specifier
34-
return specifier.filter(
35-
self.versions.keys(), prereleases=self.resolver.prereleases
36-
)
41+
# If a pre-release specifier was provided, it should enable pre-releases
42+
# even if the site doesn't. This replicates explicitly passing a pre-release
43+
# version to pip even if you don't pass `--pre`.
44+
prereleases = self.resolver.prereleases or specifier.prereleases
45+
return specifier.filter(self.versions.keys(), prereleases=prereleases)
3746

3847
@property
3948
def versions(self):
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "pre-release",
3+
"aliases": {
4+
"windows": [
5+
[
6+
"pre", {
7+
"cmd": "python"
8+
}
9+
]
10+
],
11+
"linux": [
12+
[
13+
"pre", {
14+
"cmd": "python"
15+
}
16+
]
17+
]
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "pre-release",
3+
"aliases": {
4+
"windows": [
5+
[
6+
"pre", {
7+
"cmd": "python"
8+
}
9+
]
10+
],
11+
"linux": [
12+
[
13+
"pre", {
14+
"cmd": "python"
15+
}
16+
]
17+
]
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "pre-release",
3+
"aliases": {
4+
"windows": [
5+
[
6+
"pre", {
7+
"cmd": "python"
8+
}
9+
]
10+
],
11+
"linux": [
12+
[
13+
"pre", {
14+
"cmd": "python"
15+
}
16+
]
17+
]
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "pre-release2",
3+
"aliases": {
4+
"windows": [
5+
[
6+
"pre2", {
7+
"cmd": "python"
8+
}
9+
]
10+
],
11+
"linux": [
12+
[
13+
"pre2", {
14+
"cmd": "python"
15+
}
16+
]
17+
]
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "pre-release2",
3+
"aliases": {
4+
"windows": [
5+
[
6+
"pre2", {
7+
"cmd": "python"
8+
}
9+
]
10+
],
11+
"linux": [
12+
[
13+
"pre2", {
14+
"cmd": "python"
15+
}
16+
]
17+
]
18+
}
19+
}

tests/site_main_check.habcache

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,116 @@
14041404
},
14051405
"version": "2024.0"
14061406
},
1407+
"{config-root}/distros/pre-release2/1.0/.hab.json": {
1408+
"name": "pre-release2",
1409+
"aliases": {
1410+
"windows": [
1411+
[
1412+
"pre2",
1413+
{
1414+
"cmd": "python"
1415+
}
1416+
]
1417+
],
1418+
"linux": [
1419+
[
1420+
"pre2",
1421+
{
1422+
"cmd": "python"
1423+
}
1424+
]
1425+
]
1426+
},
1427+
"version": "1.0"
1428+
},
1429+
"{config-root}/distros/pre-release2/1.1.dev2/.hab.json": {
1430+
"name": "pre-release2",
1431+
"aliases": {
1432+
"windows": [
1433+
[
1434+
"pre2",
1435+
{
1436+
"cmd": "python"
1437+
}
1438+
]
1439+
],
1440+
"linux": [
1441+
[
1442+
"pre2",
1443+
{
1444+
"cmd": "python"
1445+
}
1446+
]
1447+
]
1448+
},
1449+
"version": "1.1.dev2"
1450+
},
1451+
"{config-root}/distros/pre-release/1.0.dev1/.hab.json": {
1452+
"name": "pre-release",
1453+
"aliases": {
1454+
"windows": [
1455+
[
1456+
"pre",
1457+
{
1458+
"cmd": "python"
1459+
}
1460+
]
1461+
],
1462+
"linux": [
1463+
[
1464+
"pre",
1465+
{
1466+
"cmd": "python"
1467+
}
1468+
]
1469+
]
1470+
},
1471+
"version": "1.0.dev1"
1472+
},
1473+
"{config-root}/distros/pre-release/1.0/.hab.json": {
1474+
"name": "pre-release",
1475+
"aliases": {
1476+
"windows": [
1477+
[
1478+
"pre",
1479+
{
1480+
"cmd": "python"
1481+
}
1482+
]
1483+
],
1484+
"linux": [
1485+
[
1486+
"pre",
1487+
{
1488+
"cmd": "python"
1489+
}
1490+
]
1491+
]
1492+
},
1493+
"version": "1.0"
1494+
},
1495+
"{config-root}/distros/pre-release/1.1.dev2/.hab.json": {
1496+
"name": "pre-release",
1497+
"aliases": {
1498+
"windows": [
1499+
[
1500+
"pre",
1501+
{
1502+
"cmd": "python"
1503+
}
1504+
]
1505+
],
1506+
"linux": [
1507+
[
1508+
"pre",
1509+
{
1510+
"cmd": "python"
1511+
}
1512+
]
1513+
]
1514+
},
1515+
"version": "1.1.dev2"
1516+
},
14071517
"{config-root}/distros/the_dcc/1.0/.hab.json": {
14081518
"name": "the_dcc",
14091519
"environment": {},

tests/test_resolver.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from packaging.requirements import Requirement
99

1010
from hab import NotSet, Resolver, Site, utils
11+
from hab.errors import InvalidRequirementError
1112
from hab.solvers import Solver
1213

1314

@@ -245,6 +246,13 @@ def test_distros(self, resolver):
245246
" maya2020==2020.1",
246247
"maya2024",
247248
" maya2024==2024.0",
249+
"pre-release",
250+
" pre-release==1.0",
251+
" pre-release==1.0.dev1",
252+
" pre-release==1.1.dev2",
253+
"pre-release2",
254+
" pre-release2==1.0",
255+
" pre-release2==1.1.dev2",
248256
"the_dcc",
249257
" the_dcc==1.0",
250258
" the_dcc==1.1",
@@ -293,6 +301,13 @@ def test_distros_truncate(self, resolver):
293301
" maya2020==2020.1",
294302
"maya2024",
295303
" maya2024==2024.0",
304+
"pre-release",
305+
" pre-release==1.0",
306+
" ...",
307+
" pre-release==1.1.dev2",
308+
"pre-release2",
309+
" pre-release2==1.0",
310+
" pre-release2==1.1.dev2",
296311
"the_dcc",
297312
" the_dcc==1.0",
298313
" ...",
@@ -563,6 +578,61 @@ def test_forced_requirements(
563578
for i, v in enumerate(versions):
564579
assert v.name == check_versions[i]
565580

581+
@pytest.mark.parametrize(
582+
"requirements,prereleases,check",
583+
(
584+
# Full release requirements respect `--pre` flag
585+
(["pre-release"], False, ["pre-release==1.0"]),
586+
(["pre-release"], True, ["pre-release==1.1.dev2"]),
587+
(["pre-release==1.0"], True, ["pre-release==1.0"]),
588+
(["pre-release==1.0"], False, ["pre-release==1.0"]),
589+
(["pre-release<=2.0"], True, ["pre-release==1.1.dev2"]),
590+
(["pre-release<=2.0"], False, ["pre-release==1.0"]),
591+
(["pre-release>=1.0"], True, ["pre-release==1.1.dev2"]),
592+
(["pre-release>=1.0"], False, ["pre-release==1.0"]),
593+
# Forced pre-release requirements will find pre-release distros
594+
# regardless of the `--pre` flag.
595+
(["pre-release==1.0rc99"], True, False),
596+
(["pre-release==1.0rc99"], False, False),
597+
(["pre-release==1.0.dev1"], True, ["pre-release==1.0.dev1"]),
598+
(["pre-release==1.0.dev1"], False, ["pre-release==1.0.dev1"]),
599+
(["pre-release<=1.0rc99"], True, ["pre-release==1.0.dev1"]),
600+
(["pre-release<=1.0rc99"], False, ["pre-release==1.0.dev1"]),
601+
# Forced pre-release requirements don't affect other requirements
602+
# regardless of the `--pre` flag.
603+
(
604+
["pre-release<=1.0rc99", "pre-release2"],
605+
False,
606+
["pre-release==1.0.dev1", "pre-release2==1.0"],
607+
),
608+
(
609+
["pre-release<=1.0rc99", "pre-release2"],
610+
True,
611+
["pre-release==1.0.dev1", "pre-release2==1.1.dev2"],
612+
),
613+
),
614+
)
615+
def test_pre_releases(self, habcached_resolver, requirements, prereleases, check):
616+
"""Check how prereleases and specifying a version with prereleases works.
617+
618+
If the global prereleases is False, ignore any pre-release versions
619+
unless the version specifier itself specifies a pre-release. See
620+
`hab.parsers.distro.Distro.matching_versions` for details.
621+
"""
622+
habcached_resolver.prereleases = prereleases
623+
uri = "not_set/no_distros"
624+
625+
if check is False:
626+
with pytest.raises(InvalidRequirementError):
627+
habcached_resolver.resolve(uri, forced_requirements=requirements)
628+
else:
629+
cfg = habcached_resolver.resolve(uri, forced_requirements=requirements)
630+
versions = cfg.versions
631+
632+
assert len(versions) == len(check)
633+
for i, v in enumerate(versions):
634+
assert v.name == check[i]
635+
566636
def test_forced_requirements_uri(self, resolver, helpers):
567637
resolver_forced = Resolver(
568638
site=resolver.site,

0 commit comments

Comments
 (0)