示例#1
0
    def __init__(self, name, version, pretty_version=None):
        """
        Creates a new in memory package.
        """
        self._pretty_name = name
        self._name = canonicalize_name(name)

        if not isinstance(version, Version):
            self._version = Version.parse(version)
            self._pretty_version = pretty_version or version
        else:
            self._version = version
            self._pretty_version = pretty_version or self._version.text

        self.description = ""

        self._authors = []
        self._maintainers = []

        self.homepage = None
        self.repository_url = None
        self.documentation_url = None
        self.keywords = []
        self._license = None
        self.readme = None

        self.source_name = ""
        self.source_type = ""
        self.source_reference = ""
        self.source_url = ""

        self.requires = []
        self.dev_requires = []
        self.extras = {}
        self.requires_extras = []

        self.category = "main"
        self.hashes = []
        self.optional = False

        self.classifiers = []

        self._python_versions = "*"
        self._python_constraint = parse_constraint("*")
        self._python_marker = AnyMarker()

        self.platform = None
        self.marker = AnyMarker()

        self.root_dir = None

        self.develop = True
示例#2
0
    def __init__(
            self,
            name,  # type: str
            constraint,  # type: str
            optional=False,  # type: bool
            category="main",  # type: str
            allows_prereleases=False,  # type: bool
            source_name=None,  # type: Optional[str]
            global_options=[],  # type: list[str]
    ):
        self._name = canonicalize_name(name)
        self._pretty_name = name

        try:
            if not isinstance(constraint, VersionConstraint):
                self._constraint = parse_constraint(constraint)
            else:
                self._constraint = constraint
        except ValueError:
            self._constraint = parse_constraint("*")

        self._pretty_constraint = str(constraint)
        self._optional = optional
        self._category = category

        if isinstance(self._constraint, VersionRange) and self._constraint.min:
            allows_prereleases = (allows_prereleases
                                  or self._constraint.min.is_prerelease())

        self._allows_prereleases = allows_prereleases
        self._source_name = source_name

        self._python_versions = "*"
        self._python_constraint = parse_constraint("*")
        self._transitive_python_versions = None
        self._transitive_python_constraint = None
        self._transitive_marker = None

        self._extras = []
        self._in_extras = []

        self.global_opts = list(global_options)

        self._activated = not self._optional

        self.is_root = False
        self.marker = AnyMarker()
示例#3
0
    def _solve(self, use_latest=None):
        self._branches.append(self._package.python_versions)

        locked = {}
        for package in self._locked.packages:
            locked[package.name] = DependencyPackage(package.to_dependency(),
                                                     package)

        try:
            result = resolve_version(self._package,
                                     self._provider,
                                     locked=locked,
                                     use_latest=use_latest)

            packages = result.packages
        except CompatibilityError as e:
            return self.solve_in_compatibility_mode(e.constraints,
                                                    use_latest=use_latest)
        except SolveFailure as e:
            raise SolverProblemError(e)

        graph = self._build_graph(self._package, packages)

        depths = []
        final_packages = []
        for package in packages:
            category, optional, marker, depth = self._get_tags_for_package(
                package, graph)

            if marker is None:
                marker = AnyMarker()
            if marker.is_empty():
                continue

            package.category = category
            package.optional = optional
            package.marker = marker

            depths.append(depth)
            final_packages.append(package)

        return final_packages, depths
示例#4
0
class Package(object):

    AVAILABLE_PYTHONS = {"2", "2.7", "3", "3.4", "3.5", "3.6", "3.7"}

    def __init__(self, name, version, pretty_version=None):
        """
        Creates a new in memory package.
        """
        self._pretty_name = name
        self._name = canonicalize_name(name)

        if not isinstance(version, Version):
            self._version = Version.parse(version)
            self._pretty_version = pretty_version or version
        else:
            self._version = version
            self._pretty_version = pretty_version or self._version.text

        self.description = ""

        self._authors = []
        self._maintainers = []

        self.homepage = None
        self.repository_url = None
        self.documentation_url = None
        self.keywords = []
        self._license = None
        self.readme = None

        self.source_name = ""
        self.source_type = ""
        self.source_reference = ""
        self.source_url = ""

        self.requires = []
        self.dev_requires = []
        self.extras = {}
        self.requires_extras = []

        self.category = "main"
        self.hashes = []
        self.optional = False

        self.classifiers = []

        self._python_versions = "*"
        self._python_constraint = parse_constraint("*")
        self._python_marker = AnyMarker()

        self.platform = None
        self.marker = AnyMarker()

        self.root_dir = None

        self.develop = True

    @property
    def name(self):
        return self._name

    @property
    def pretty_name(self):
        return self._pretty_name

    @property
    def version(self):
        return self._version

    @property
    def pretty_version(self):
        return self._pretty_version

    @property
    def unique_name(self):
        if self.is_root():
            return self._name

        return self.name + "-" + self._version.text

    @property
    def pretty_string(self):
        return self.pretty_name + " " + self.pretty_version

    @property
    def full_pretty_version(self):
        if self.source_type in ["file", "directory"]:
            return "{} {}".format(self._pretty_version, self.source_url)

        if self.source_type not in ["hg", "git"]:
            return self._pretty_version

        # if source reference is a sha1 hash -- truncate
        if len(self.source_reference) == 40:
            return "{} {}".format(self._pretty_version, self.source_reference[0:7])

        return "{} {}".format(self._pretty_version, self.source_reference)

    @property
    def authors(self):  # type: () -> list
        return self._authors

    @property
    def author_name(self):  # type: () -> str
        return self._get_author()["name"]

    @property
    def author_email(self):  # type: () -> str
        return self._get_author()["email"]

    @property
    def maintainers(self):  # type: () -> list
        return self._maintainers

    @property
    def maintainer_name(self):  # type: () -> str
        return self._get_maintainer()["name"]

    @property
    def maintainer_email(self):  # type: () -> str
        return self._get_maintainer()["email"]

    @property
    def all_requires(self):
        return self.requires + self.dev_requires

    def _get_author(self):  # type: () -> dict
        if not self._authors:
            return {"name": None, "email": None}

        m = AUTHOR_REGEX.match(self._authors[0])

        name = m.group("name")
        email = m.group("email")

        return {"name": name, "email": email}

    def _get_maintainer(self):  # type: () -> dict
        if not self._maintainers:
            return {"name": None, "email": None}

        m = AUTHOR_REGEX.match(self._maintainers[0])

        name = m.group("name")
        email = m.group("email")

        return {"name": name, "email": email}

    @property
    def python_versions(self):
        return self._python_versions

    @python_versions.setter
    def python_versions(self, value):
        self._python_versions = value
        self._python_constraint = parse_constraint(value)
        self._python_marker = parse_marker(
            create_nested_marker("python_version", self._python_constraint)
        )

    @property
    def python_constraint(self):
        return self._python_constraint

    @property
    def python_marker(self):
        return self._python_marker

    @property
    def license(self):
        return self._license

    @license.setter
    def license(self, value):
        if value is None:
            self._license = value
        elif isinstance(value, License):
            self._license = value
        else:
            self._license = license_by_id(value)

    @property
    def all_classifiers(self):
        classifiers = copy.copy(self.classifiers)

        # Automatically set python classifiers
        if self.python_versions == "*":
            python_constraint = parse_constraint("~2.7 || ^3.4")
        else:
            python_constraint = self.python_constraint

        for version in sorted(self.AVAILABLE_PYTHONS):
            if len(version) == 1:
                constraint = parse_constraint(version + ".*")
            else:
                constraint = Version.parse(version)

            if python_constraint.allows_any(constraint):
                classifiers.append(
                    "Programming Language :: Python :: {}".format(version)
                )

        # Automatically set license classifiers
        if self.license:
            classifiers.append(self.license.classifier)

        classifiers = set(classifiers)

        return sorted(classifiers)

    @property
    def urls(self):
        urls = {}

        if self.homepage:
            urls["Homepage"] = self.homepage

        if self.repository_url:
            urls["Repository"] = self.repository_url

        if self.documentation_url:
            urls["Documentation"] = self.documentation_url

        return urls

    def is_prerelease(self):
        return self._version.is_prerelease()

    def is_root(self):
        return False

    def add_dependency(
        self,
        name,  # type: str
        constraint=None,  # type: Union[str, dict, None]
        category="main",  # type: str
    ):  # type: (...) -> Dependency
        if constraint is None:
            constraint = "*"

        if isinstance(constraint, dict):
            optional = constraint.get("optional", False)
            python_versions = constraint.get("python")
            platform = constraint.get("platform")
            markers = constraint.get("markers")
            allows_prereleases = constraint.get("allows-prereleases", False)

            if "git" in constraint:
                # VCS dependency
                dependency = VCSDependency(
                    name,
                    "git",
                    constraint["git"],
                    branch=constraint.get("branch", None),
                    tag=constraint.get("tag", None),
                    rev=constraint.get("rev", None),
                    optional=optional,
                )
            elif "file" in constraint:
                file_path = Path(constraint["file"])

                dependency = FileDependency(
                    name, file_path, category=category, base=self.root_dir
                )
            elif "path" in constraint:
                path = Path(constraint["path"])

                if self.root_dir:
                    is_file = (self.root_dir / path).is_file()
                else:
                    is_file = path.is_file()

                if is_file:
                    dependency = FileDependency(
                        name,
                        path,
                        category=category,
                        optional=optional,
                        base=self.root_dir,
                    )
                else:
                    dependency = DirectoryDependency(
                        name,
                        path,
                        category=category,
                        optional=optional,
                        base=self.root_dir,
                        develop=constraint.get("develop", True),
                    )
            else:
                version = constraint["version"]

                dependency = Dependency(
                    name,
                    version,
                    optional=optional,
                    category=category,
                    allows_prereleases=allows_prereleases,
                    source_name=constraint.get("source"),
                )

            if not markers:
                marker = AnyMarker()
                if python_versions:
                    dependency.python_versions = python_versions
                    marker = marker.intersect(
                        parse_marker(
                            create_nested_marker(
                                "python_version", dependency.python_constraint
                            )
                        )
                    )

                if platform:
                    marker = marker.intersect(
                        parse_marker(
                            create_nested_marker(
                                "sys_platform", parse_generic_constraint(platform)
                            )
                        )
                    )
            else:
                marker = parse_marker(markers)

            if not marker.is_any():
                dependency.marker = marker

            if "extras" in constraint:
                for extra in constraint["extras"]:
                    dependency.extras.append(extra)
        else:
            dependency = Dependency(name, constraint, category=category)

        if category == "dev":
            self.dev_requires.append(dependency)
        else:
            self.requires.append(dependency)

        return dependency

    def to_dependency(self):
        from . import dependency_from_pep_508

        name = "{} (=={})".format(self._name, self._version)

        if not self.marker.is_any():
            name += " ; {}".format(str(self.marker))

        return dependency_from_pep_508(name)

    @contextmanager
    def with_python_versions(self, python_versions):
        original_python_versions = self.python_versions

        self.python_versions = python_versions

        yield

        self.python_versions = original_python_versions

    def clone(self):  # type: () -> Package
        clone = self.__class__(self.pretty_name, self.version)
        clone.category = self.category
        clone.optional = self.optional
        clone.python_versions = self.python_versions
        clone.marker = self.marker
        clone.extras = self.extras
        clone.source_type = self.source_type
        clone.source_url = self.source_url
        clone.source_reference = self.source_reference

        for dep in self.requires:
            clone.requires.append(dep)

        for dep in self.dev_requires:
            clone.dev_requires.append(dep)

        return clone

    def __hash__(self):
        return hash((self._name, self._version))

    def __eq__(self, other):
        if not isinstance(other, Package):
            return NotImplemented

        return self._name == other.name and self._version == other.version

    def __str__(self):
        return self.unique_name

    def __repr__(self):
        return "<Package {}>".format(self.unique_name)
示例#5
0
    def add_dependency(
        self,
        name,  # type: str
        constraint=None,  # type: Union[str, dict, None]
        category="main",  # type: str
    ):  # type: (...) -> Dependency
        if constraint is None:
            constraint = "*"

        if isinstance(constraint, dict):
            optional = constraint.get("optional", False)
            python_versions = constraint.get("python")
            platform = constraint.get("platform")
            markers = constraint.get("markers")
            allows_prereleases = constraint.get("allows-prereleases", False)

            if "git" in constraint:
                # VCS dependency
                dependency = VCSDependency(
                    name,
                    "git",
                    constraint["git"],
                    branch=constraint.get("branch", None),
                    tag=constraint.get("tag", None),
                    rev=constraint.get("rev", None),
                    optional=optional,
                )
            elif "file" in constraint:
                file_path = Path(constraint["file"])

                dependency = FileDependency(
                    name, file_path, category=category, base=self.root_dir
                )
            elif "path" in constraint:
                path = Path(constraint["path"])

                if self.root_dir:
                    is_file = (self.root_dir / path).is_file()
                else:
                    is_file = path.is_file()

                if is_file:
                    dependency = FileDependency(
                        name,
                        path,
                        category=category,
                        optional=optional,
                        base=self.root_dir,
                    )
                else:
                    dependency = DirectoryDependency(
                        name,
                        path,
                        category=category,
                        optional=optional,
                        base=self.root_dir,
                        develop=constraint.get("develop", True),
                    )
            else:
                version = constraint["version"]

                dependency = Dependency(
                    name,
                    version,
                    optional=optional,
                    category=category,
                    allows_prereleases=allows_prereleases,
                    source_name=constraint.get("source"),
                )

            if not markers:
                marker = AnyMarker()
                if python_versions:
                    dependency.python_versions = python_versions
                    marker = marker.intersect(
                        parse_marker(
                            create_nested_marker(
                                "python_version", dependency.python_constraint
                            )
                        )
                    )

                if platform:
                    marker = marker.intersect(
                        parse_marker(
                            create_nested_marker(
                                "sys_platform", parse_generic_constraint(platform)
                            )
                        )
                    )
            else:
                marker = parse_marker(markers)

            if not marker.is_any():
                dependency.marker = marker

            if "extras" in constraint:
                for extra in constraint["extras"]:
                    dependency.extras.append(extra)
        else:
            dependency = Dependency(name, constraint, category=category)

        if category == "dev":
            self.dev_requires.append(dependency)
        else:
            self.requires.append(dependency)

        return dependency
示例#6
0
class Dependency(object):
    def __init__(
            self,
            name,  # type: str
            constraint,  # type: str
            optional=False,  # type: bool
            category="main",  # type: str
            allows_prereleases=False,  # type: bool
    ):
        self._name = canonicalize_name(name)
        self._pretty_name = name

        try:
            if not isinstance(constraint, VersionConstraint):
                self._constraint = parse_constraint(constraint)
            else:
                self._constraint = constraint
        except ValueError:
            self._constraint = parse_constraint("*")

        self._pretty_constraint = str(constraint)
        self._optional = optional
        self._category = category

        if isinstance(self._constraint, VersionRange) and self._constraint.min:
            allows_prereleases = (allows_prereleases
                                  or self._constraint.min.is_prerelease())

        self._allows_prereleases = allows_prereleases

        self._python_versions = "*"
        self._python_constraint = parse_constraint("*")
        self._transitive_python_versions = None
        self._transitive_python_constraint = None

        self._extras = []
        self._in_extras = []

        self._activated = not self._optional

        self.is_root = False
        self.marker = AnyMarker()

    @property
    def name(self):
        return self._name

    @property
    def constraint(self):
        return self._constraint

    @property
    def pretty_constraint(self):
        return self._pretty_constraint

    @property
    def pretty_name(self):
        return self._pretty_name

    @property
    def category(self):
        return self._category

    @property
    def python_versions(self):
        return self._python_versions

    @python_versions.setter
    def python_versions(self, value):
        self._python_versions = value
        self._python_constraint = parse_constraint(value)
        if not self._python_constraint.is_any():
            self.marker = self.marker.intersect(
                parse_marker(
                    self._create_nested_marker("python_version",
                                               self._python_constraint)))

    @property
    def transitive_python_versions(self):
        if self._transitive_python_versions is None:
            return self._python_versions

        return self._transitive_python_versions

    @transitive_python_versions.setter
    def transitive_python_versions(self, value):
        self._transitive_python_versions = value
        self._transitive_python_constraint = parse_constraint(value)

    @property
    def python_constraint(self):
        return self._python_constraint

    @property
    def transitive_python_constraint(self):
        if self._transitive_python_constraint is None:
            return self._python_constraint

        return self._transitive_python_constraint

    @property
    def extras(self):  # type: () -> list
        return self._extras

    @property
    def in_extras(self):  # type: () -> list
        return self._in_extras

    @property
    def base_pep_508_name(self):  # type: () -> str
        requirement = self.pretty_name

        if self.extras:
            requirement += "[{}]".format(",".join(self.extras))

        if isinstance(self.constraint, VersionUnion):
            requirement += " ({})".format(",".join(
                [str(c).replace(" ", "") for c in self.constraint.ranges]))
        elif isinstance(self.constraint, Version):
            requirement += " (=={})".format(self.constraint.text)
        elif not self.constraint.is_any():
            requirement += " ({})".format(
                str(self.constraint).replace(" ", ""))

        return requirement

    def allows_prereleases(self):
        return self._allows_prereleases

    def is_optional(self):
        return self._optional

    def is_activated(self):
        return self._activated

    def is_vcs(self):
        return False

    def is_file(self):
        return False

    def is_directory(self):
        return False

    def accepts(self, package):  # type: (poetry.packages.Package) -> bool
        """
        Determines if the given package matches this dependency.
        """
        return (self._name == package.name
                and self._constraint.allows(package.version)
                and (not package.is_prerelease() or self.allows_prereleases()))

    def to_pep_508(self, with_extras=True):  # type: (bool) -> str
        requirement = self.base_pep_508_name

        markers = []
        if not self.marker.is_any():
            marker = self.marker
            if not with_extras:
                marker = marker.without_extras()

            if not marker.is_empty():
                markers.append(str(marker))
        else:
            # Python marker
            if self.python_versions != "*":
                python_constraint = self.python_constraint

                markers.append(
                    self._create_nested_marker("python_version",
                                               python_constraint))

        in_extras = " || ".join(self._in_extras)
        if in_extras and with_extras:
            markers.append(
                self._create_nested_marker(
                    "extra", parse_generic_constraint(in_extras)))

        if markers:
            if self.is_vcs():
                requirement += " "

            if len(markers) > 1:
                markers = ["({})".format(m) for m in markers]
                requirement += "; {}".format(" and ".join(markers))
            else:
                requirement += "; {}".format(markers[0])

        return requirement

    def _create_nested_marker(self, name, constraint):
        if isinstance(constraint, (MultiConstraint, UnionConstraint)):
            parts = []
            for c in constraint.constraints:
                multi = False
                if isinstance(c, (MultiConstraint, UnionConstraint)):
                    multi = True

                parts.append((multi, self._create_nested_marker(name, c)))

            glue = " and "
            if isinstance(constraint, UnionConstraint):
                parts = [
                    "({})".format(part[1]) if part[0] else part[1]
                    for part in parts
                ]
                glue = " or "
            else:
                parts = [part[1] for part in parts]

            marker = glue.join(parts)
        elif isinstance(constraint, Constraint):
            marker = '{} {} "{}"'.format(name, constraint.operator,
                                         constraint.version)
        elif isinstance(constraint, VersionUnion):
            parts = []
            for c in constraint.ranges:
                parts.append(self._create_nested_marker(name, c))

            glue = " or "
            parts = ["({})".format(part) for part in parts]

            marker = glue.join(parts)
        elif isinstance(constraint, Version):
            marker = '{} == "{}"'.format(name, constraint.text)
        else:
            if constraint.min is not None:
                op = ">="
                if not constraint.include_min:
                    op = ">"

                version = constraint.min.text
                if constraint.max is not None:
                    text = '{} {} "{}"'.format(name, op, version)

                    op = "<="
                    if not constraint.include_max:
                        op = "<"

                    version = constraint.max

                    text += ' and {} {} "{}"'.format(name, op, version)

                    return text
            elif constraint.max is not None:
                op = "<="
                if not constraint.include_max:
                    op = "<"

                version = constraint.max
            else:
                return ""

            marker = '{} {} "{}"'.format(name, op, version)

        return marker

    def activate(self):
        """
        Set the dependency as mandatory.
        """
        self._activated = True

    def deactivate(self):
        """
        Set the dependency as optional.
        """
        if not self._optional:
            self._optional = True

        self._activated = False

    def with_constraint(self, constraint):
        new = Dependency(
            self.pretty_name,
            constraint,
            optional=self.is_optional(),
            category=self.category,
            allows_prereleases=self.allows_prereleases(),
        )

        new.is_root = self.is_root
        new.python_versions = self.python_versions

        for extra in self.extras:
            new.extras.append(extra)

        for in_extra in self.in_extras:
            new.in_extras.append(in_extra)

        return new

    def __eq__(self, other):
        if not isinstance(other, Dependency):
            return NotImplemented

        return self._name == other.name and self._constraint == other.constraint

    def __ne__(self, other):
        return not self == other

    def __hash__(self):
        return hash((self._name, self._pretty_constraint))

    def __str__(self):
        if self.is_root:
            return self._pretty_name

        return "{} ({})".format(self._pretty_name, self._pretty_constraint)

    def __repr__(self):
        return "<{} {}>".format(self.__class__.__name__, str(self))