Beispiel #1
0
def analyzer_poetry_lock(*, location: ScanLocation):
    lock = parse_toml(location.location.read_text())

    for pkg in lock["package"]:
        pkg_version = Version(pkg["version"])
        pkg_name = str(pkg["name"])

        try:
            pypi = package.PypiPackage.from_pypi(pkg_name)
            latest = Version(pypi.get_latest_release())

            if latest > pkg_version:
                yield Detection(
                    detection_type="OutdatedPackage",
                    message=
                    f"Package {pkg_name}=={pkg_version} in poetry.lock is outdated, newest version is {latest}",
                    signature=
                    f"outpdate_pkg#{str(location)}#{pkg_name}#{pkg_version}",
                    score=get_score_or_default("requirement-outdated", 5),
                    location=location.location,
                    extra={
                        "package": pkg_name,
                        "specs": f"=={pkg_version}",
                        "latest": str(latest)
                    },
                    tags={"outdated_package"})
        except NoSuchPackage:
            pass
Beispiel #2
0
def analyze_pyproject(*, location: ScanLocation):
    if location.location.name == "poetry.lock":
        yield from analyzer_poetry_lock(location=location)
        return

    if location.location.name != "pyproject.toml":
        return

    pyproject = parse_toml(location.location.read_text())  # TODO
Beispiel #3
0
 def nodes_or_groups_from_dir(self, directory):
     path = join(self.path, directory)
     if not isdir(path):
         return
     for root_dir, _dirs, files in walk(path):
         for filename in files:
             filepath = join(root_dir, filename)
             if not filename.endswith(".toml") or \
                     not isfile(filepath) or \
                     filename.startswith("_"):
                 continue
             infodict = dict(parse_toml(get_file_contents(filepath)))
             infodict['file_path'] = filepath
             yield filename[:-5], infodict
Beispiel #4
0
    def handle(self) -> int:
        from poetry.core.semver.helpers import parse_constraint
        from tomlkit import inline_table
        from tomlkit import parse as parse_toml
        from tomlkit import table

        from poetry.factory import Factory

        packages = self.argument("name")
        if self.option("dev"):
            self.line_error(
                "<warning>The --dev option is deprecated, "
                "use the `--group dev` notation instead.</warning>")
            group = "dev"
        else:
            group = self.option("group")

        if self.option("extras") and len(packages) > 1:
            raise ValueError(
                "You can only specify one package when using the --extras option"
            )

        content = self.poetry.file.read()
        poetry_content = content["tool"]["poetry"]

        if group == "default":
            if "dependencies" not in poetry_content:
                poetry_content["dependencies"] = table()

            section = poetry_content["dependencies"]
        else:
            if "group" not in poetry_content:
                group_table = table()
                group_table._is_super_table = True
                poetry_content.value._insert_after("dependencies", "group",
                                                   group_table)

            groups = poetry_content["group"]
            if group not in groups:
                group_table = parse_toml(
                    f"[tool.poetry.group.{group}.dependencies]\n\n"
                )["tool"]["poetry"]["group"][group]
                poetry_content["group"][group] = group_table

            if "dependencies" not in poetry_content["group"][group]:
                poetry_content["group"][group]["dependencies"] = table()

            section = poetry_content["group"][group]["dependencies"]

        existing_packages = self.get_existing_packages_from_input(
            packages, section)

        if existing_packages:
            self.notify_about_existing_packages(existing_packages)

        packages = [name for name in packages if name not in existing_packages]

        if not packages:
            self.line("Nothing to add.")
            return 0

        requirements = self._determine_requirements(
            packages,
            allow_prereleases=self.option("allow-prereleases"),
            source=self.option("source"),
        )

        for _constraint in requirements:
            if "version" in _constraint:
                # Validate version constraint
                parse_constraint(_constraint["version"])

            constraint = inline_table()
            for name, value in _constraint.items():
                if name == "name":
                    continue

                constraint[name] = value

            if self.option("optional"):
                constraint["optional"] = True

            if self.option("allow-prereleases"):
                constraint["allow-prereleases"] = True

            if self.option("extras"):
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                constraint["extras"] = self.option("extras")

            if self.option("editable"):
                if "git" in _constraint or "path" in _constraint:
                    constraint["develop"] = True
                else:
                    self.line_error(
                        "\n"
                        "<error>Failed to add packages. "
                        "Only vcs/path dependencies support editable installs. "
                        f"<c1>{_constraint['name']}</c1> is neither.")
                    self.line_error("\nNo changes were applied.")
                    return 1

            if self.option("python"):
                constraint["python"] = self.option("python")

            if self.option("platform"):
                constraint["platform"] = self.option("platform")

            if self.option("source"):
                constraint["source"] = self.option("source")

            if len(constraint) == 1 and "version" in constraint:
                constraint = constraint["version"]

            section[_constraint["name"]] = constraint

            with contextlib.suppress(ValueError):
                self.poetry.package.dependency_group(group).remove_dependency(
                    _constraint["name"])

            self.poetry.package.add_dependency(
                Factory.create_dependency(
                    _constraint["name"],
                    constraint,
                    groups=[group],
                    root_dir=self.poetry.file.parent,
                ))

        # Refresh the locker
        self.poetry.set_locker(
            self.poetry.locker.__class__(self.poetry.locker.lock.path,
                                         poetry_content))
        self._installer.set_locker(self.poetry.locker)

        # Cosmetic new line
        self.line("")

        self._installer.set_package(self.poetry.package)
        self._installer.dry_run(self.option("dry-run"))
        self._installer.verbose(self._io.is_verbose())
        self._installer.update(True)
        if self.option("lock"):
            self._installer.lock()

        self._installer.whitelist([cast(str, r["name"]) for r in requirements])

        status = self._installer.run()

        if status == 0 and not self.option("dry-run"):
            self.poetry.file.write(content)

        return status