Code editing task: dependency_solver
Topic: DSA; change kind: perfective

Original code:
from typing import List, Literal


class Semver:
    def __init__(self, major: int, minor: int, patch: int):
        self.major = major
        self.minor = minor
        self.patch = patch

    def __str__(self):
        return f'{self.major}.{self.minor}.{self.patch}'

    def __eq__(self, other):
        return self.major == other.major and \
            self.minor == other.minor and \
            self.patch == other.patch

    def __lt__(self, other):
        if self.major < other.major:
            return True
        elif self.major == other.major:
            if self.minor < other.minor:
                return True
            elif self.minor == other.minor:
                return self.patch < other.patch
        return False

    def __gt__(self, other):
        if self.major > other.major:
            return True
        elif self.major == other.major:
            if self.minor > other.minor:
                return True
            elif self.minor == other.minor:
                return self.patch > other.patch
        return False

    def __le__(self, other):
        return self < other or self == other

    def __ge__(self, other):
        return self > other or self == other

    def __hash__(self):
        return hash((self.major, self.minor, self.patch))


class PackageVersion:
    def __init__(self, version: Semver, dependencies: List["SemverConstraint"] = []):
        self.version = version
        self.dependencies = dependencies


class Package:
    def __init__(self, name: str, versions: List[PackageVersion]):
        self.name = name
        self.versions = versions

    def max_satisfying_version(self, constraints: List["SemverConstraint"]):
        max_version = None
        for version in self.versions:
            if all([constraint.satisfies(version.version) for constraint in constraints]):
                if max_version is None or version.version > max_version.version:
                    max_version = version
        return max_version


class SemverConstraint:
    def __init__(
        self,
        package: str,
        constraint: Literal["==", ">=", "<=", ">", "<"],
        version: Semver,
    ):
        self.package = package
        assert constraint in ["==", ">=", "<=", ">", "<"], \
            f'Constraint must be one of "==", ">=", "<=", ">", "<", not {constraint}'
        self.constraint = constraint
        self.version = version

    def __str__(self):
        return f'{self.package} {self.constraint} {self.version}'

    def satisfies(self, version: Semver):
        if self.constraint == "==":
            return version == self.version
        elif self.constraint == ">=":
            return version >= self.version
        elif self.constraint == "<=":
            return version <= self.version
        elif self.constraint == ">":
            return version > self.version
        elif self.constraint == "<":
            return version < self.version

Instruction (descriptive):
Add assertions in the `PackageVersion` constructor to ensure that there are no duplicate dependencies with the same name.
Additionally, add assertions in the `Package` constructor to ensure that there are no versions with the same version number.

Instruction (lazy):
Make sure that there are no duplicate versions and duplicate dependencies when creating a `Package` or `PackageVersion`.

Edited code:
from typing import List, Literal


class Semver:
    def __init__(self, major: int, minor: int, patch: int):
        self.major = major
        self.minor = minor
        self.patch = patch

    def __str__(self):
        return f'{self.major}.{self.minor}.{self.patch}'

    def __eq__(self, other):
        return self.major == other.major and \
            self.minor == other.minor and \
            self.patch == other.patch

    def __lt__(self, other):
        if self.major < other.major:
            return True
        elif self.major == other.major:
            if self.minor < other.minor:
                return True
            elif self.minor == other.minor:
                return self.patch < other.patch
        return False

    def __gt__(self, other):
        if self.major > other.major:
            return True
        elif self.major == other.major:
            if self.minor > other.minor:
                return True
            elif self.minor == other.minor:
                return self.patch > other.patch
        return False

    def __le__(self, other):
        return self < other or self == other

    def __ge__(self, other):
        return self > other or self == other

    def __hash__(self):
        return hash((self.major, self.minor, self.patch))


class PackageVersion:
    def __init__(self, version: Semver, dependencies: List["SemverConstraint"] = []):
        self.version = version
        self.dependencies = dependencies
        # make sure there are no duplicate dependencies
        deps = set()
        for dep in dependencies:
            if dep.package in deps:
                raise ValueError(f'Duplicate dependency {dep}')
            deps.add(dep.package)


class Package:
    def __init__(self, name: str, versions: List[PackageVersion]):
        self.name = name
        self.versions = versions
        # make sure there are no duplicate versions
        vers = set()
        for version in versions:
            if version.version in vers:
                raise ValueError(f'Duplicate version {version.version}')
            vers.add(version.version)

    def max_satisfying_version(self, constraints: List["SemverConstraint"]):
        max_version = None
        for version in self.versions:
            if all([constraint.satisfies(version.version) for constraint in constraints]):
                if max_version is None or version.version > max_version.version:
                    max_version = version
        return max_version


class SemverConstraint:
    def __init__(
        self,
        package: str,
        constraint: Literal["==", ">=", "<=", ">", "<"],
        version: Semver,
    ):
        self.package = package
        assert constraint in ["==", ">=", "<=", ">", "<"], \
            f'Constraint must be one of "==", ">=", "<=", ">", "<", not {constraint}'
        self.constraint = constraint
        self.version = version

    def __str__(self):
        return f'{self.package} {self.constraint} {self.version}'

    def satisfies(self, version: Semver):
        if self.constraint == "==":
            return version == self.version
        elif self.constraint == ">=":
            return version >= self.version
        elif self.constraint == "<=":
            return version <= self.version
        elif self.constraint == ">":
            return version > self.version
        elif self.constraint == "<":
            return version < self.version

Tests:
### START TESTS ###
if True:  # pragma: no cover
    # foo has no dependencies
    foo = Package(
        "foo",
        [
            PackageVersion(Semver(0, 0, 1)),
            PackageVersion(Semver(1, 0, 0)),
            PackageVersion(Semver(1, 1, 0)),
            PackageVersion(Semver(1, 2, 3)),
            PackageVersion(Semver(1, 2, 4)),
            PackageVersion(Semver(1, 2, 5)),
            PackageVersion(Semver(2, 0, 0)),
        ],
    )

    # bar depends on foo, only after version 1.0.0
    foo_constraint1 = SemverConstraint("foo", ">=", Semver(1, 0, 0))
    foo_constraint2 = SemverConstraint("foo", "<", Semver(2, 0, 0))
    bar = Package(
        "bar",
        [
            PackageVersion(Semver(0, 0, 1)),
            PackageVersion(Semver(0, 2, 1)),
            PackageVersion(Semver(1, 0, 0), [foo_constraint1]),
            PackageVersion(Semver(1, 1, 0), [foo_constraint1]),
            PackageVersion(Semver(1, 2, 0), [foo_constraint1]),
            PackageVersion(Semver(2, 0, 0), [foo_constraint2]),
        ],
    )

    # baz depends on bar and also foo (but only after version 1.2.3)
    foo_constraint3 = SemverConstraint("foo", ">=", Semver(1, 2, 3))
    bar_constraint = SemverConstraint("bar", "==", Semver(2, 0, 0))
    baz = Package(
        "baz",
        [
            PackageVersion(Semver(0, 0, 1)),
            PackageVersion(Semver(0, 2, 1), [bar_constraint]),
            PackageVersion(Semver(1, 0, 0), [bar_constraint]),
            PackageVersion(Semver(1, 1, 0), [bar_constraint]),
            PackageVersion(Semver(1, 2, 0), [bar_constraint]),
            PackageVersion(Semver(1, 2, 3), [bar_constraint, foo_constraint3]),
            PackageVersion(Semver(1, 2, 4), [bar_constraint]),
        ]
    )

    # boo depends on baz, at wildly different versions
    baz_constraint1 = SemverConstraint("baz", "==", Semver(0, 0, 1))
    baz_constraint2 = SemverConstraint("baz", "<", Semver(1, 0, 0))
    baz_constraint3 = SemverConstraint("baz", ">", Semver(1, 0, 0))
    baz_constraint4 = SemverConstraint("baz", "<=", Semver(1, 2, 3))

    boo = Package(
        "boo",
        [
            PackageVersion(Semver(0, 0, 1), [baz_constraint1]),
            PackageVersion(Semver(0, 2, 1), [baz_constraint1]),
            PackageVersion(Semver(1, 0, 0), [baz_constraint2]),
            PackageVersion(Semver(1, 1, 0), [baz_constraint2]),
            PackageVersion(Semver(1, 2, 0), [baz_constraint2]),
            PackageVersion(Semver(1, 2, 3), [baz_constraint3]),
            PackageVersion(Semver(1, 2, 4), [baz_constraint3]),
            PackageVersion(Semver(1, 2, 5), [baz_constraint3]),
            PackageVersion(Semver(2, 0, 0), [baz_constraint4]),
        ]
    )

    # WORLD is a list of all packages
    WORLD = [
        foo,
        bar,
        baz,
        boo,
    ]

    assert Semver(1, 2, 3) == Semver(1, 2, 3)
    assert Semver(1, 2, 3) != Semver(1, 2, 4)
    assert Semver(1, 2, 3) < Semver(1, 2, 4)
    assert Semver(1, 2, 3) <= Semver(1, 2, 4)
    assert Semver(1, 2, 3) <= Semver(1, 2, 3)
    assert Semver(1, 2, 4) > Semver(1, 2, 3)
    assert not (Semver(1, 2, 3) > Semver(1, 2, 4))
    assert not (Semver(1, 2, 3) < Semver(1, 2, 3))
    assert not (Semver(1, 2, 3) > Semver(1, 2, 3))
    assert not (Semver(1, 2, 3) < Semver(1, 0, 0))
    assert Semver(2, 2, 3) > Semver(1, 2, 4)
    assert Semver(3, 2, 3) < Semver(4, 2, 3)
    assert Semver(3, 2, 3) < Semver(4, 2, 3)
    assert Semver(3, 2, 3) < Semver(3, 4, 3)
    assert Semver(1, 2, 4) >= Semver(1, 2, 3)
    assert Semver(1, 2, 4) >= Semver(1, 2, 4)
    assert Semver(1, 3, 4) > Semver(1, 2, 4)

    # hashable
    assert hash(Semver(1, 2, 3)) == hash(Semver(1, 2, 3))
    assert hash(Semver(1, 2, 3)) != hash(Semver(1, 2, 4))

    sem = Semver(1, 2, 3)
    constraint = SemverConstraint("foo", "==", sem)
    assert constraint.satisfies(Semver(1, 2, 3))
    assert not constraint.satisfies(Semver(1, 2, 4))

    constraint = SemverConstraint("foo", ">=", sem)
    assert constraint.satisfies(Semver(1, 2, 3))
    assert constraint.satisfies(Semver(1, 2, 4))
    assert not constraint.satisfies(Semver(1, 2, 2))

    constraint = SemverConstraint("foo", "<=", sem)
    assert constraint.satisfies(Semver(1, 2, 3))
    assert constraint.satisfies(Semver(1, 2, 2))
    assert not constraint.satisfies(Semver(1, 2, 4))

    constraint = SemverConstraint("foo", ">", sem)
    assert constraint.satisfies(Semver(1, 2, 4))
    assert not constraint.satisfies(Semver(1, 2, 3))
    assert not constraint.satisfies(Semver(1, 2, 2))

    constraint = SemverConstraint("foo", "<", sem)
    assert constraint.satisfies(Semver(1, 2, 2))
    assert not constraint.satisfies(Semver(1, 2, 3))
    assert not constraint.satisfies(Semver(1, 2, 4))

    max1 = foo.max_satisfying_version(
        [SemverConstraint("foo", "==", Semver(1, 2, 3))])
    assert max1
    assert max1.version == Semver(1, 2, 3)
    max2 = foo.max_satisfying_version(
        [SemverConstraint("foo", ">=", Semver(1, 2, 3))])
    assert max2
    assert max2.version == Semver(2, 0, 0)

    max1 = bar.max_satisfying_version(
        [SemverConstraint("foo", "==", Semver(3, 2, 3))])
    assert max1 is None

    # dup dep
    try:
        PackageVersion(Semver(0, 0, 1), [
            baz_constraint1, baz_constraint1])
    except:
        pass
    else:
        assert False

    # dup dep 2
    try:
        PackageVersion(Semver(0, 0, 1), [
                       baz_constraint1, baz_constraint2, baz_constraint1])
    except:
        pass
    else:
        assert False

    # dup dep 3
    try:
        PackageVersion(Semver(0, 0, 1), [
            foo_constraint1, foo_constraint2, foo_constraint1])
    except:
        pass
    else:
        assert False

    # dup dep 4
    try:
        PackageVersion(Semver(0, 0, 1), [
            foo_constraint1, foo_constraint2])
    except:
        pass
    else:
        assert False

    # dup version
    try:
        Package(
            "dup",
            [
                PackageVersion(Semver(0, 0, 1)),
                PackageVersion(Semver(0, 0, 1)),
            ]
        )
    except:
        pass
    else:
        assert False

    # dup version 2
    try:
        Package(
            "dup",
            [
                PackageVersion(Semver(0, 0, 1)),
                PackageVersion(Semver(1, 0, 0)),
                PackageVersion(Semver(0, 0, 1)),
            ]
        )
    except:
        pass
    else:
        assert False

    # dup version 3
    try:
        Package(
            "dup",
            [
                PackageVersion(Semver(0, 0, 1)),
                PackageVersion(Semver(1, 0, 0)),
                PackageVersion(Semver(1, 0, 0)),
            ]
        )
    except:
        pass
    else:
        assert False

    # dup version 4
    try:
        Package(
            "dup",
            [
                PackageVersion(Semver(0, 0, 1)),
                PackageVersion(Semver(1, 2, 0)),
                PackageVersion(Semver(1, 0, 3)),
                PackageVersion(Semver(1, 0, 1)),
                PackageVersion(Semver(1, 2, 0)),
            ]
        )
    except:
        pass
    else:
        assert False