Class: Dependabot::Python::LanguageVersionManager

Inherits:
Object
  • Object
show all
Defined in:
lib/dependabot/python/language_version_manager.rb

Constant Summary collapse

PRE_INSTALLED_PYTHON_VERSIONS =

This list must match the versions specified at the top of ‘python/Dockerfile`

%w(
  3.12.5
  3.11.9
  3.10.13
  3.9.18
  3.8.18
).freeze

Instance Method Summary collapse

Constructor Details

#initialize(python_requirement_parser:) ⇒ LanguageVersionManager

Returns a new instance of LanguageVersionManager.



19
20
21
# File 'lib/dependabot/python/language_version_manager.rb', line 19

def initialize(python_requirement_parser:)
  @python_requirement_parser = python_requirement_parser
end

Instance Method Details

#install_required_pythonObject



23
24
25
26
27
28
29
30
# File 'lib/dependabot/python/language_version_manager.rb', line 23

def install_required_python
  # The leading space is important in the version check
  return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_major_minor}.")

  SharedHelpers.run_shell_command(
    "tar -axf /usr/local/.pyenv/versions/#{python_version}.tar.zst -C /usr/local/.pyenv/versions"
  )
end

#python_major_minorObject



32
33
34
# File 'lib/dependabot/python/language_version_manager.rb', line 32

def python_major_minor
  @python_major_minor ||= T.must(Python::Version.new(python_version).segments[0..1]).join(".")
end

#python_requirement_stringObject



40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/dependabot/python/language_version_manager.rb', line 40

def python_requirement_string
  if user_specified_python_version
    if user_specified_python_version.start_with?(/\d/)
      parts = user_specified_python_version.split(".")
      parts.fill("*", (parts.length)..2).join(".")
    else
      user_specified_python_version
    end
  else
    python_version_matching_imputed_requirements || PRE_INSTALLED_PYTHON_VERSIONS.first
  end
end

#python_versionObject



36
37
38
# File 'lib/dependabot/python/language_version_manager.rb', line 36

def python_version
  @python_version ||= python_version_from_supported_versions
end

#python_version_from_supported_versionsObject

Raises:

  • (ToolVersionNotSupported)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/dependabot/python/language_version_manager.rb', line 53

def python_version_from_supported_versions
  requirement_string = python_requirement_string

  # If the requirement string isn't already a range (eg ">3.10"), coerce it to "major.minor.*".
  # The patch version is ignored because a non-matching patch version is unlikely to affect resolution.
  requirement_string = requirement_string.gsub(/\.\d+$/, ".*") if requirement_string.start_with?(/\d/)

  # Try to match one of our pre-installed Python versions
  requirement = T.must(Python::Requirement.requirements_array(requirement_string).first)
  version = PRE_INSTALLED_PYTHON_VERSIONS.find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
  return version if version

  # Otherwise we have to raise
  supported_versions = PRE_INSTALLED_PYTHON_VERSIONS.map { |x| x.gsub(/\.\d+$/, ".*") }.join(", ")
  raise ToolVersionNotSupported.new("Python", python_requirement_string, supported_versions)
end

#python_version_matching(requirements) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'lib/dependabot/python/language_version_manager.rb', line 82

def python_version_matching(requirements)
  PRE_INSTALLED_PYTHON_VERSIONS.find do |version_string|
    version = Python::Version.new(version_string)
    requirements.all? do |req|
      next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)

      req.satisfied_by?(version)
    end
  end
end

#python_version_matching_imputed_requirementsObject



74
75
76
77
78
79
80
# File 'lib/dependabot/python/language_version_manager.rb', line 74

def python_version_matching_imputed_requirements
  compiled_file_python_requirement_markers =
    @python_requirement_parser.imputed_requirements.map do |r|
      Dependabot::Python::Requirement.new(r)
    end
  python_version_matching(compiled_file_python_requirement_markers)
end

#user_specified_python_versionObject



70
71
72
# File 'lib/dependabot/python/language_version_manager.rb', line 70

def user_specified_python_version
  @python_requirement_parser.user_specified_requirements.first
end