class Dependabot::Python::UpdateChecker
Constants
- MAIN_PYPI_INDEXES
- VERSION_REGEX
Public Instance Methods
latest_resolvable_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 35 def latest_resolvable_version @latest_resolvable_version ||= case resolver_type when :pipenv pipenv_version_resolver.latest_resolvable_version( requirement: unlocked_requirement_string ) when :poetry poetry_version_resolver.latest_resolvable_version( requirement: unlocked_requirement_string ) when :pip_compile pip_compile_version_resolver.latest_resolvable_version( requirement: unlocked_requirement_string ) when :requirements pip_version_resolver.latest_resolvable_version else raise "Unexpected resolver type #{resolver_type}" end end
latest_resolvable_version_with_no_unlock()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 56 def latest_resolvable_version_with_no_unlock @latest_resolvable_version_with_no_unlock ||= case resolver_type when :pipenv pipenv_version_resolver.latest_resolvable_version( requirement: current_requirement_string ) when :poetry poetry_version_resolver.latest_resolvable_version( requirement: current_requirement_string ) when :pip_compile pip_compile_version_resolver.latest_resolvable_version( requirement: current_requirement_string ) when :requirements pip_version_resolver.latest_resolvable_version_with_no_unlock else raise "Unexpected resolver type #{resolver_type}" end end
latest_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 31 def latest_version @latest_version ||= fetch_latest_version end
lowest_resolvable_security_fix_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 81 def lowest_resolvable_security_fix_version raise "Dependency not vulnerable!" unless vulnerable? return @lowest_resolvable_security_fix_version if defined?(@lowest_resolvable_security_fix_version) @lowest_resolvable_security_fix_version = fetch_lowest_resolvable_security_fix_version end
lowest_security_fix_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 77 def lowest_security_fix_version latest_version_finder.lowest_security_fix_version end
requirements_update_strategy()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 99 def requirements_update_strategy # If passed in as an option (in the base class) honour that option return @requirements_update_strategy.to_sym if @requirements_update_strategy # Otherwise, check if this is a poetry library or not poetry_library? ? :widen_ranges : :bump_versions end
updated_requirements()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 90 def updated_requirements RequirementsUpdater.new( requirements: dependency.requirements, latest_resolvable_version: preferred_resolvable_version&.to_s, update_strategy: requirements_update_strategy, has_lockfile: !(pipfile_lock || poetry_lock || pyproject_lock).nil? ).updated_requirements end
Private Instance Methods
current_requirement_string()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 209 def current_requirement_string reqs = dependency.requirements return if reqs.none? requirement = case resolver_type when :pipenv then reqs.find { |r| r[:file] == "Pipfile" } when :poetry then reqs.find { |r| r[:file] == "pyproject.toml" } when :pip_compile then reqs.find { |r| r[:file].end_with?(".in") } when :requirements then reqs.find { |r| r[:file].end_with?(".txt") } end requirement&.fetch(:requirement) end
exact_requirement?(reqs)
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 170 def exact_requirement?(reqs) reqs = reqs.map { |r| r.fetch(:requirement) } reqs = reqs.compact reqs = reqs.flat_map { |r| r.split(",").map(&:strip) } reqs.any? { |r| Python::Requirement.new(r).exact? } end
fetch_latest_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 254 def fetch_latest_version latest_version_finder.latest_version end
fetch_lowest_resolvable_security_fix_version()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 121 def fetch_lowest_resolvable_security_fix_version fix_version = lowest_security_fix_version return latest_resolvable_version if fix_version.nil? return pip_version_resolver.lowest_resolvable_security_fix_version if resolver_type == :requirements resolver = case resolver_type when :pip_compile then pip_compile_version_resolver when :pipenv then pipenv_version_resolver when :poetry then poetry_version_resolver else raise "Unexpected resolver type #{resolver_type}" end resolver.resolvable?(version: fix_version) ? fix_version : nil end
latest_version_finder()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 258 def latest_version_finder @latest_version_finder ||= LatestVersionFinder.new( dependency: dependency, dependency_files: dependency_files, credentials: credentials, ignored_versions: ignored_versions, raise_on_ignored: @raise_on_ignored, security_advisories: security_advisories ) end
latest_version_resolvable_with_full_unlock?()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 109 def latest_version_resolvable_with_full_unlock? # Full unlock checks aren't implemented for pip because they're not # relevant (pip doesn't have a resolver). This method always returns # false to ensure `updated_dependencies_after_full_unlock` is never # called. false end
normalised_name(name)
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 291 def normalised_name(name) NameNormaliser.normalise(name) end
pip_compile_files()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 315 def pip_compile_files dependency_files.select { |f| f.name.end_with?(".in") } end
pip_compile_version_resolver()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 181 def pip_compile_version_resolver @pip_compile_version_resolver ||= PipCompileVersionResolver.new(**resolver_args) end
pip_version_resolver()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 190 def pip_version_resolver @pip_version_resolver ||= PipVersionResolver.new( dependency: dependency, dependency_files: dependency_files, credentials: credentials, ignored_versions: ignored_versions, raise_on_ignored: @raise_on_ignored, security_advisories: security_advisories ) end
pipenv_version_resolver()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 177 def pipenv_version_resolver @pipenv_version_resolver ||= PipenvVersionResolver.new(**resolver_args) end
pipfile()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 295 def pipfile dependency_files.find { |f| f.name == "Pipfile" } end
pipfile_lock()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 299 def pipfile_lock dependency_files.find { |f| f.name == "Pipfile.lock" } end
poetry_library?()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 269 def poetry_library? return false unless pyproject # Hit PyPi and check whether there are details for a library with a # matching name and description details = TomlRB.parse(pyproject.content).dig("tool", "poetry") return false unless details index_response = Excon.get( "https://pypi.org/pypi/#{normalised_name(details['name'])}/json/", idempotent: true, **SharedHelpers.excon_defaults ) return false unless index_response.status == 200 pypi_info = JSON.parse(index_response.body)["info"] || {} pypi_info["summary"] == details["description"] rescue URI::InvalidURIError false end
poetry_lock()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 311 def poetry_lock dependency_files.find { |f| f.name == "poetry.lock" } end
poetry_version_resolver()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 186 def poetry_version_resolver @poetry_version_resolver ||= PoetryVersionResolver.new(**resolver_args) end
pyproject()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 303 def pyproject dependency_files.find { |f| f.name == "pyproject.toml" } end
pyproject_lock()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 307 def pyproject_lock dependency_files.find { |f| f.name == "pyproject.lock" } end
resolver_args()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 201 def resolver_args { dependency: dependency, dependency_files: dependency_files, credentials: credentials } end
resolver_type()
click to toggle source
rubocop:disable Metrics/PerceivedComplexity
# File lib/dependabot/python/update_checker.rb, line 139 def resolver_type reqs = dependency.requirements req_files = reqs.map { |r| r.fetch(:file) } # If there are no requirements then this is a sub-dependency. It # must come from one of Pipenv, Poetry or pip-tools, and can't come # from the first two unless they have a lockfile. return subdependency_resolver if reqs.none? # Otherwise, this is a top-level dependency, and we can figure out # which resolver to use based on the filename of its requirements return :pipenv if req_files.any? { |f| f == "Pipfile" } return :poetry if req_files.any? { |f| f == "pyproject.toml" } return :pip_compile if req_files.any? { |f| f.end_with?(".in") } if dependency.version && !exact_requirement?(reqs) subdependency_resolver else :requirements end end
subdependency_resolver()
click to toggle source
rubocop:enable Metrics/PerceivedComplexity
# File lib/dependabot/python/update_checker.rb, line 162 def subdependency_resolver return :pipenv if pipfile_lock return :poetry if poetry_lock || pyproject_lock return :pip_compile if pip_compile_files.any? raise "Claimed to be a sub-dependency, but no lockfile exists!" end
unlocked_requirement_string()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 224 def unlocked_requirement_string lower_bound_req = updated_version_req_lower_bound # Add the latest_version as an upper bound. This means # ignore conditions are considered when checking for the latest # resolvable version. # # NOTE: This isn't perfect. If v2.x is ignored and v3 is out but # unresolvable then the `latest_version` will be v3, and # we won't be ignoring v2.x releases like we should be. return lower_bound_req if latest_version.nil? return lower_bound_req unless Python::Version.correct?(latest_version) lower_bound_req + ", <= #{latest_version}" end
updated_dependencies_after_full_unlock()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 117 def updated_dependencies_after_full_unlock raise NotImplementedError end
updated_version_req_lower_bound()
click to toggle source
# File lib/dependabot/python/update_checker.rb, line 240 def updated_version_req_lower_bound return ">= #{dependency.version}" if dependency.version version_for_requirement = dependency.requirements.map { |r| r[:requirement] }.compact. reject { |req_string| req_string.start_with?("<") }. select { |req_string| req_string.match?(VERSION_REGEX) }. map { |req_string| req_string.match(VERSION_REGEX) }. select { |version| Gem::Version.correct?(version) }. max_by { |version| Gem::Version.new(version) } ">= #{version_for_requirement || 0}" end