class Dependabot::Python::FileParser::PoetryFilesParser

Constants

POETRY_DEPENDENCY_TYPES
UNSUPPORTED_DEPENDENCY_TYPES

python-poetry.org/docs/dependency-specification/

Attributes

dependency_files[R]

Public Class Methods

new(dependency_files:) click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 21
def initialize(dependency_files:)
  @dependency_files = dependency_files
end

Public Instance Methods

dependency_set() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 25
def dependency_set
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new

  dependency_set += pyproject_dependencies
  dependency_set += lockfile_dependencies if lockfile

  dependency_set
end

Private Instance Methods

check_requirements(req) click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 110
def check_requirements(req)
  requirement = req.is_a?(String) ? req : req["version"]
  Python::Requirement.requirements_array(requirement)
rescue Gem::Requirement::BadRequirementError => e
  raise Dependabot::DependencyFileNotEvaluatable, e.message
end
lockfile() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 144
def lockfile
  poetry_lock || pyproject_lock
end
lockfile_dependencies() click to toggle source

Create a DependencySet where each element has no requirement. Any requirements will be added when combining the DependencySet with other DependencySets.

# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 81
def lockfile_dependencies
  dependencies = Dependabot::FileParsers::Base::DependencySet.new

  parsed_lockfile.fetch("package", []).each do |details|
    next if %w(directory git url).include?(details.dig("source", "type"))

    dependencies <<
      Dependency.new(
        name: normalise(details.fetch("name")),
        version: details.fetch("version"),
        requirements: [],
        package_manager: "pip",
        subdependency_metadata: [{
          production: details["category"] != "dev"
        }]
      )
  end

  dependencies
end
normalise(name) click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 117
def normalise(name)
  NameNormaliser.normalise(name)
end
parse_requirements_from(req, type) click to toggle source

@param req can be an Array, Hash or String that represents the constraints for a dependency

# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 63
def parse_requirements_from(req, type)
  [req].flatten.compact.map do |requirement|
    next if requirement.is_a?(Hash) && (UNSUPPORTED_DEPENDENCY_TYPES & requirement.keys).any?

    check_requirements(requirement)

    {
      requirement: requirement.is_a?(String) ? requirement : requirement["version"],
      file: pyproject.name,
      source: nil,
      groups: [type]
    }
  end.compact
end
parsed_lockfile() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 148
def parsed_lockfile
  return parsed_poetry_lock if poetry_lock
  return parsed_pyproject_lock if pyproject_lock
end
parsed_poetry_lock() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 133
def parsed_poetry_lock
  @parsed_poetry_lock ||= TomlRB.parse(poetry_lock.content)
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
  raise Dependabot::DependencyFileNotParseable, poetry_lock.path
end
parsed_pyproject() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 121
def parsed_pyproject
  @parsed_pyproject ||= TomlRB.parse(pyproject.content)
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
  raise Dependabot::DependencyFileNotParseable, pyproject.path
end
parsed_pyproject_lock() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 127
def parsed_pyproject_lock
  @parsed_pyproject_lock ||= TomlRB.parse(pyproject_lock.content)
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
  raise Dependabot::DependencyFileNotParseable, pyproject_lock.path
end
poetry_lock() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 158
def poetry_lock
  @poetry_lock ||=
    dependency_files.find { |f| f.name == "poetry.lock" }
end
pyproject() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 139
def pyproject
  @pyproject ||=
    dependency_files.find { |f| f.name == "pyproject.toml" }
end
pyproject_dependencies() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 38
def pyproject_dependencies
  dependencies = Dependabot::FileParsers::Base::DependencySet.new

  POETRY_DEPENDENCY_TYPES.each do |type|
    deps_hash = parsed_pyproject.dig("tool", "poetry", type) || {}

    deps_hash.each do |name, req|
      next if normalise(name) == "python"

      requirements = parse_requirements_from(req, type)
      next if requirements.empty?

      dependencies << Dependency.new(
        name: normalise(name),
        version: version_from_lockfile(name),
        requirements: requirements,
        package_manager: "pip"
      )
    end
  end

  dependencies
end
pyproject_lock() click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 153
def pyproject_lock
  @pyproject_lock ||=
    dependency_files.find { |f| f.name == "pyproject.lock" }
end
version_from_lockfile(dep_name) click to toggle source
# File lib/dependabot/python/file_parser/poetry_files_parser.rb, line 102
def version_from_lockfile(dep_name)
  return unless parsed_lockfile

  parsed_lockfile.fetch("package", []).
    find { |p| normalise(p.fetch("name")) == normalise(dep_name) }&.
    fetch("version", nil)
end