Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: fix the CI failures on packaging > 22 #115

Merged
merged 6 commits into from
Jan 31, 2023
Merged
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
30 changes: 13 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,35 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- run: pip install .[lint,test]
- run: black --check .
- run: isort .
- run: flake8 .
- run: mypy src/ tests/
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- run: pip install nox
- run: nox -s lint
package:
name: Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- run: pip install .[release]
- run: python -m build .
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- run: pip install nox
- run: nox -s release -- --version '' --repo '' --prebump ''
test:
name: Test
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
needs: [lint]
strategy:
fail-fast: true
matrix:
python:
- "2.7"
- "3.10"
- "3.9"
- "3.8"
- "3.7"
- "3.6"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- run: pip install .[test]
- run: pytest tests
- run: pip install nox
- run: nox -s tests-${{ matrix.python }}
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def lint(session):
session.run("mypy", "src", "tests")


@nox.session(python=["3.9", "3.8", "3.7", "3.6", "3.5", "2.7"])
@nox.session(python=["3.10", "3.9", "3.8", "3.7", "3.6", "2.7"])
def tests(session):
session.install(".[test]")

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ universal = 1
[flake8]
max-line-length = 88
select = C,E,F,W,B
ignore = E203, W503
ignore = E203, W503, F401
uranusjr marked this conversation as resolved.
Show resolved Hide resolved
exclude =
.git,
.venv,
Expand Down
140 changes: 105 additions & 35 deletions tests/functional/cocoapods/test_resolvers_cocoapods.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import string

import commentjson # type: ignore
import packaging.specifiers
import packaging.version
import pytest

from resolvelib import AbstractProvider, ResolutionImpossible, Resolver
Expand All @@ -17,40 +15,112 @@


INPUTS_DIR = os.path.abspath(os.path.join(__file__, "..", "inputs"))

CASE_DIR = os.path.join(INPUTS_DIR, "case")

CASE_NAMES = [name for name in os.listdir(CASE_DIR) if name.endswith(".json")]


def _convert_specifier(s):
if not s:
return s
m = re.match(r"^([<>=~!]*)\s*(.+)$", s)
def _parse_version(v):
parts = []
for part in re.split(r"[.-]", v):
if part[:1] in "0123456789":
parts.append(part.zfill(8))
else:
parts.append("*" + part)
parts.append("*z") # end mark
return tuple(parts)


class Version:
def __init__(self, v):
self.v = v
self._comp_key = _parse_version(v)

def __repr__(self):
return self.v

@property
def is_prerelease(self):
return any(part[0] == "*" for part in self._comp_key[:-1])

def __len__(self):
return len(self._comp_key)

def __eq__(self, o):
if not isinstance(o, Version):
return NotImplemented
left = self
if len(left) < len(o):
left = left.pad(len(o) - len(left))
elif len(left) > len(o):
o = o.pad(len(left) - len(o))
return left._comp_key == o._comp_key

def __lt__(self, o):
return self._comp_key < o._comp_key

def __le__(self, o):
return self._comp_key <= o._comp_key

def __gt__(self, o):
return self._comp_key > o._comp_key

def __ge__(self, o):
return self._comp_key >= o._comp_key

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

def pad(self, n):
return Version(self.v + ".0" * n)


def _compatible_gt(a, b):
"""a ~> b"""
if a < b:
return False
a_digits = [part for part in a._comp_key if part[0] != "*"]
b_digits = [part for part in b._comp_key if part[0] != "*"]
target_len = len(b_digits)
return a_digits[: target_len - 1] == b_digits[: target_len - 1]


_compare_ops = {
"=": operator.eq,
">": operator.gt,
">=": operator.ge,
"<": operator.lt,
"<=": operator.le,
"~>": _compatible_gt,
"!=": operator.ne,
}


def _version_in_spec(version, spec):
if not spec:
return not version.is_prerelease
m = re.match(r"([><=~!]*)\s*(.*)", spec)
op, ver = m.groups()
if not op or op == "=":
return "== {}".format(ver)
elif op == "~>":
if len(ver) == 1:
# PEP 440 can't handle "~= X" (no minor part). This translates to
# a simple ">= X" because it means we accept major version changes.
return ">= {}".format(ver)
return "~= {0}, >= {0}".format(ver)
return s
if not op:
op = "="
spec_ver = Version(ver)
allow_prereleases = spec_ver.is_prerelease
if not allow_prereleases and version.is_prerelease:
return False
if len(spec_ver) > len(version):
version = version.pad(len(spec_ver) - len(version))
return _compare_ops[op](version, spec_ver)


def _iter_convert_specifiers(inp):
for raw in inp.split(","):
cov = _convert_specifier(raw.strip())
if not cov:
continue
yield cov
yield raw.strip()


def _parse_specifier_set(inp):
return packaging.specifiers.SpecifierSet(
", ".join(_iter_convert_specifiers(inp)),
)
def _version_in_specset(version, specset):
for spec in _iter_convert_specifiers(specset):
if not _version_in_spec(version, spec):
return False
return True


def _safe_json_load(filename):
Expand All @@ -74,7 +144,7 @@ def _clean_identifier(s):

def _iter_resolved(dependencies):
for entry in dependencies:
yield (entry["name"], packaging.version.parse(entry["version"]))
yield (entry["name"], Version(entry["version"]))
for sub in _iter_resolved(entry["dependencies"]):
yield sub

Expand All @@ -91,11 +161,11 @@ def __init__(self, filename):
self.index = _safe_json_load(index_name)

self.root_requirements = [
Requirement(_clean_identifier(key), _parse_specifier_set(spec))
Requirement(_clean_identifier(key), spec)
for key, spec in case_data["requested"].items()
]
self.pinned_versions = {
entry["name"]: packaging.version.parse(entry["version"])
entry["name"]: Version(entry["version"])
for entry in case_data["base"]
}
self.expected_resolution = dict(_iter_resolved(case_data["resolved"]))
Expand All @@ -121,17 +191,17 @@ def _iter_matches(self, name, requirements, incompatibilities):
return
bad_versions = {c.ver for c in incompatibilities[name]}
for entry in data:
version = packaging.version.parse(entry["version"])
if any(version not in r.spec for r in requirements[name]):
version = Version(entry["version"])
if any(
not _version_in_specset(version, r.spec)
for r in requirements[name]
):
continue
if version in bad_versions:
continue
# Some fixtures incorrectly set dependencies to an empty list.
dependencies = entry["dependencies"] or {}
dependencies = [
Requirement(k, _parse_specifier_set(v))
for k, v in dependencies.items()
]
dependencies = [Requirement(k, v) for k, v in dependencies.items()]
yield Candidate(entry["name"], version, dependencies)

def find_matches(self, identifier, requirements, incompatibilities):
Expand All @@ -148,7 +218,7 @@ def find_matches(self, identifier, requirements, incompatibilities):
yield c

def is_satisfied_by(self, requirement, candidate):
return candidate.ver in requirement.spec
return _version_in_specset(candidate.ver, requirement.spec)

def get_dependencies(self, candidate):
return candidate.deps
Expand Down
2 changes: 1 addition & 1 deletion tests/test_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def test_pin_conflict_with_self(monkeypatch, reporter):
Verify correct behavior of attempting to pin a candidate version that conflicts
with a previously pinned (now invalidated) version for that same candidate (#91).
"""
Candidate = Tuple[
Candidate = Tuple[ # noqa: F841
str, Version, Sequence[str]
] # name, version, requirements
all_candidates = {
Expand Down