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
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
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
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