dependabot-python 0.390.0 → 0.392.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/python/authed_url_builder.rb +2 -1
  3. data/lib/dependabot/python/dependency_grapher/requirements_layers.rb +4 -4
  4. data/lib/dependabot/python/file_fetcher.rb +1 -1
  5. data/lib/dependabot/python/file_parser/python_requirement_parser.rb +2 -2
  6. data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +27 -32
  7. data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +1 -1
  8. data/lib/dependabot/python/file_updater/pipfile_manifest_updater.rb +7 -7
  9. data/lib/dependabot/python/file_updater/poetry_file_updater/pep621_updater.rb +14 -10
  10. data/lib/dependabot/python/file_updater/poetry_file_updater.rb +23 -23
  11. data/lib/dependabot/python/file_updater/pyproject_preparer.rb +2 -5
  12. data/lib/dependabot/python/file_updater/requirement_file_updater.rb +19 -15
  13. data/lib/dependabot/python/file_updater/requirement_replacer.rb +5 -5
  14. data/lib/dependabot/python/file_updater/setup_file_sanitizer.rb +11 -12
  15. data/lib/dependabot/python/file_updater.rb +1 -1
  16. data/lib/dependabot/python/package/package_registry_finder.rb +3 -3
  17. data/lib/dependabot/python/pipenv_runner.rb +1 -1
  18. data/lib/dependabot/python/poetry_plugin_installer.rb +1 -1
  19. data/lib/dependabot/python/requirement.rb +9 -6
  20. data/lib/dependabot/python/shared_file_fetcher.rb +5 -5
  21. data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +19 -21
  22. data/lib/dependabot/python/update_checker/pip_version_resolver.rb +3 -1
  23. data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +4 -4
  24. data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +7 -7
  25. data/lib/dependabot/python/update_checker/requirements_updater.rb +48 -40
  26. data/lib/dependabot/python/update_checker.rb +13 -13
  27. data/lib/dependabot/python/version.rb +1 -1
  28. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dae20e628b553254a3e6e3309a2dfcb08ae3bf3647cb819268a2e22177e178f5
4
- data.tar.gz: 71599724f9356febf9445b8e534b22c3a8fee051ef27e15f15c14bfe31dcaf43
3
+ metadata.gz: 70504f97ff35fbf437e2895455b6371d858c38921b3f4839a11aaddc31d04911
4
+ data.tar.gz: 131699694996cabca8daec6c5a96f5a4dba34ec11601a22d7a8f54e6a855852f
5
5
  SHA512:
6
- metadata.gz: eff4f144ef97647719580c94eaeed7a27a083300ceac4aab05d952b3e795d806a1776ecc696f14180add8a217fed0200f7b0392f0abe3cd8c9305a3c2fd90dab
7
- data.tar.gz: 33c451ea7f321010b17337aabcb161ab0b488ae2c40899ead0b0a4cac2092cc34e9b8fa79737d58e3f9bdd0ef1445cd21331a624e572b5c40eca1b14ba987aa8
6
+ metadata.gz: 56501fd6454a91206147b03fa795570e6a494e5d5c9733c8945656b174893352cd4adaa3bd2b4ee6c87565c3cc59dc861f62500d4c86fdfa3ea82c50afadda3f
7
+ data.tar.gz: 8e1983671535f8886b5f7b920893a747d80b16535b74159c07da2ae82c1226dd66276fea515f28503217565955827ab03d51d5ac78dee42dce46d6bcd0cbe869
@@ -17,7 +17,8 @@ module Dependabot
17
17
  return url unless token
18
18
 
19
19
  basic_auth_details =
20
- if token.ascii_only? && token.include?(":") then token
20
+ if token.ascii_only? && token.include?(":")
21
+ token
21
22
  elsif Base64.decode64(token).ascii_only? &&
22
23
  Base64.decode64(token).include?(":")
23
24
  Base64.decode64(token)
@@ -29,24 +29,24 @@ module Dependabot
29
29
  # Matches "requirements" preceded by a hyphen, period, underscore, start-of-string, or slash,
30
30
  # followed by non-whitespace chars and ".txt".
31
31
  # Examples: requirements.txt, requirements.prod.txt, requirements/production.txt
32
- REQUIREMENTS_TXT_REGEX = T.let(%r{(?:[-._]|^|/)requirements[^\s]*\.txt$}i, Regexp)
32
+ REQUIREMENTS_TXT_REGEX = %r{(?:[-._]|^|/)requirements[^\s]*\.txt$}i
33
33
 
34
34
  # More lenient: matches "require" at the start of the filename or after a hyphen/period/underscore/
35
35
  # slash delimiter, with an optional hyphen/underscore/slash suffix. The leading delimiter prevents
36
36
  # matching "require" as a substring of another word (e.g. "prequire.txt", "acquire.txt").
37
37
  # Examples: require.txt, require-test.txt, py3-require.txt, pyenv_require_e2e.txt
38
- REQUIRE_TXT_REGEX = T.let(%r{(?:[-._]|^|/)require(?:[-_/][^\s.]*)?\.txt$}i, Regexp)
38
+ REQUIRE_TXT_REGEX = %r{(?:[-._]|^|/)require(?:[-_/][^\s.]*)?\.txt$}i
39
39
 
40
40
  # Matches "dependencies" / "dependency" preceded by a hyphen, period, underscore,
41
41
  # start-of-string, or slash, followed by non-whitespace chars and ".txt".
42
42
  # Examples: dependencies.txt, my-dependencies.txt, dependencies/python/ansible-lint.txt
43
- DEPENDENCIES_TXT_REGEX = T.let(%r{(?:[-._]|^|/)dependenc(?:y|ies)[^\s]*\.txt$}i, Regexp)
43
+ DEPENDENCIES_TXT_REGEX = %r{(?:[-._]|^|/)dependenc(?:y|ies)[^\s]*\.txt$}i
44
44
 
45
45
  # More lenient: matches "depend" / "depends" at the start of the filename or after a hyphen/period/
46
46
  # underscore/slash delimiter, with an optional hyphen/underscore/slash suffix. The leading delimiter
47
47
  # prevents matching "depend" as a substring of another word (e.g. "codependent.txt").
48
48
  # Examples: depend.txt, depends.txt, depend-test.txt, py3-depends.txt
49
- DEPEND_TXT_REGEX = T.let(%r{(?:[-._]|^|/)depend(?:s)?(?:[-_/][^\s.]*)?\.txt$}i, Regexp)
49
+ DEPEND_TXT_REGEX = %r{(?:[-._]|^|/)depend(?:s)?(?:[-_/][^\s.]*)?\.txt$}i
50
50
 
51
51
  # Whether a .txt filename looks like a real pip manifest rather than an unrelated .txt file.
52
52
  sig { params(path: String).returns(T::Boolean) }
@@ -15,7 +15,7 @@ module Dependabot
15
15
  class FileFetcher < Dependabot::Python::SharedFileFetcher
16
16
  extend T::Sig
17
17
 
18
- ECOSYSTEM_SPECIFIC_FILES = T.let(%w(Pipfile setup.py setup.cfg).freeze, T::Array[String])
18
+ ECOSYSTEM_SPECIFIC_FILES = %w(Pipfile setup.py setup.cfg).freeze
19
19
 
20
20
  sig { override.returns(T::Array[String]) }
21
21
  def self.ecosystem_specific_required_files
@@ -114,7 +114,7 @@ module Dependabot
114
114
  end.reject(&:empty?)
115
115
 
116
116
  file_version = content_lines.first
117
- return if file_version&.empty?
117
+ return if file_version && file_version.empty?
118
118
  return unless T.must(pyenv_versions).include?("#{file_version}\n")
119
119
 
120
120
  file_version
@@ -126,7 +126,7 @@ module Dependabot
126
126
 
127
127
  file_version = T.must(T.must(runtime_file).content)
128
128
  .match(/(?<=python-).*/)&.to_s&.strip
129
- return if file_version&.empty?
129
+ return if file_version && file_version.empty?
130
130
  return unless T.must(pyenv_versions).include?("#{file_version}\n")
131
131
 
132
132
  file_version
@@ -25,23 +25,18 @@ module Dependabot
25
25
  require_relative "requirement_file_updater"
26
26
  require_relative "setup_file_sanitizer"
27
27
 
28
- UNSAFE_PACKAGES = T.let(%w(setuptools distribute pip).freeze, T::Array[String])
29
- INCOMPATIBLE_VERSIONS_REGEX = T.let(
30
- Regexp.new(
31
- "(?:not supported between instances of 'InstallationCandidate'" \
32
- "|There are incompatible versions in the resolved dependencies).*\\z",
33
- Regexp::MULTILINE
34
- ),
35
- Regexp
36
- )
37
- WARNINGS = T.let(/\s*# WARNING:.*\Z/m, Regexp)
38
- UNSAFE_NOTE = T.let(/\s*# The following packages are considered to be unsafe.*\Z/m, Regexp)
39
- RESOLVER_REGEX = T.let(/(?<=--resolver=)(\w+)/, Regexp)
40
- UNSAFE_PACKAGE_OPTION_REGEX = T.let(/--unsafe-package(?:=|\s+)(?<name>[^\s\\]+)/, Regexp)
41
- NATIVE_COMPILATION_ERROR = T.let(
42
- "pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1",
43
- String
28
+ UNSAFE_PACKAGES = %w(setuptools distribute pip).freeze
29
+ INCOMPATIBLE_VERSIONS_REGEX = Regexp.new(
30
+ "(?:not supported between instances of 'InstallationCandidate'" \
31
+ "|There are incompatible versions in the resolved dependencies).*\\z",
32
+ Regexp::MULTILINE
44
33
  )
34
+ WARNINGS = /\s*# WARNING:.*\Z/m
35
+ UNSAFE_NOTE = /\s*# The following packages are considered to be unsafe.*\Z/m
36
+ RESOLVER_REGEX = /(?<=--resolver=)(\w+)/
37
+ UNSAFE_PACKAGE_OPTION_REGEX = /--unsafe-package(?:=|\s+)(?<name>[^\s\\]+)/
38
+ NATIVE_COMPILATION_ERROR =
39
+ "pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1"
45
40
 
46
41
  sig { returns(T::Array[Dependabot::Dependency]) }
47
42
  attr_reader :dependencies
@@ -60,10 +55,10 @@ module Dependabot
60
55
  index_urls: T.nilable(T::Array[T.nilable(String)])
61
56
  ).void
62
57
  end
63
- def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil) # rubocop:disable Metrics/AbcSize
64
- @dependencies = T.let(dependencies, T::Array[Dependabot::Dependency])
65
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
66
- @index_urls = T.let(index_urls, T.nilable(T::Array[T.nilable(String)]))
58
+ def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
59
+ @dependencies = dependencies
60
+ @dependency_files = dependency_files
61
+ @index_urls = index_urls
67
62
  @build_isolation = T.let(true, T::Boolean)
68
63
  @sanitized_setup_file_content = T.let({}, T::Hash[String, String])
69
64
  @requirement_map = T.let(nil, T.nilable(T::Hash[String, T::Array[String]]))
@@ -73,7 +68,7 @@ module Dependabot
73
68
  @setup_cfg_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
74
69
  @pip_compile_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
75
70
  @compiled_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
76
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
71
+ @credentials = credentials
77
72
  end
78
73
 
79
74
  sig { returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
@@ -199,9 +194,9 @@ module Dependabot
199
194
  def update_uncompiled_files(updated_files)
200
195
  updated_filenames = updated_files.map(&:name)
201
196
  old_reqs = T.must(T.must(dependency).previous_requirements)
202
- .reject { |r| updated_filenames.include?(r[:file]) }
197
+ .reject { |r| updated_filenames.include?(r.file) }
203
198
  new_reqs = T.must(dependency).requirements
204
- .reject { |r| updated_filenames.include?(r[:file]) }
199
+ .reject { |r| updated_filenames.include?(r.file) }
205
200
 
206
201
  return [] if new_reqs.none?
207
202
 
@@ -329,15 +324,15 @@ module Dependabot
329
324
  return file.content unless file.name.end_with?(".in")
330
325
 
331
326
  old_req = T.must(T.must(dependency).previous_requirements)
332
- .find { |r| r[:file] == file.name }
327
+ .find { |r| r.file == file.name }
333
328
 
334
329
  return file.content unless old_req
335
- return file.content if old_req == "==#{T.must(dependency).version}"
330
+ return file.content if old_req.requirement_string == "==#{T.must(dependency).version}"
336
331
 
337
332
  RequirementReplacer.new(
338
333
  content: T.must(file.content),
339
334
  dependency_name: T.must(dependency).name,
340
- old_requirement: old_req[:requirement],
335
+ old_requirement: old_req.requirement_string,
341
336
  new_requirement: "==#{T.must(dependency).version}",
342
337
  index_urls: @index_urls
343
338
  ).updated_content
@@ -348,17 +343,17 @@ module Dependabot
348
343
  return file.content unless file.name.end_with?(".in")
349
344
 
350
345
  old_req = T.must(T.must(dependency).previous_requirements)
351
- .find { |r| r[:file] == file.name }
346
+ .find { |r| r.file == file.name }
352
347
  new_req = T.must(dependency).requirements
353
- .find { |r| r[:file] == file.name }
354
- return file.content unless old_req&.fetch(:requirement)
348
+ .find { |r| r.file == file.name }
349
+ return file.content unless old_req&.requirement_string
355
350
  return file.content if old_req == new_req
356
351
 
357
352
  RequirementReplacer.new(
358
353
  content: T.must(file.content),
359
354
  dependency_name: T.must(dependency).name,
360
- old_requirement: old_req[:requirement],
361
- new_requirement: T.must(new_req)[:requirement],
355
+ old_requirement: old_req.requirement_string,
356
+ new_requirement: T.must(T.must(new_req).requirement_string),
362
357
  index_urls: @index_urls
363
358
  ).updated_content
364
359
  end
@@ -679,7 +674,7 @@ module Dependabot
679
674
  def filenames_to_compile
680
675
  files_from_reqs =
681
676
  T.must(dependency).requirements
682
- .map { |r| r[:file] }
677
+ .filter_map(&:file)
683
678
  .select { |fn| fn.end_with?(".in") }
684
679
 
685
680
  files_from_compiled_files =
@@ -22,7 +22,7 @@ module Dependabot
22
22
  require_relative "pipfile_manifest_updater"
23
23
  require_relative "setup_file_sanitizer"
24
24
 
25
- DEPENDENCY_TYPES = T.let(%w(packages dev-packages).freeze, T::Array[String])
25
+ DEPENDENCY_TYPES = %w(packages dev-packages).freeze
26
26
 
27
27
  sig { returns(T::Array[Dependabot::Dependency]) }
28
28
  attr_reader :dependencies
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/python/file_updater"
@@ -53,15 +53,15 @@ module Dependabot
53
53
 
54
54
  # Loop through each changed requirement
55
55
  reqs.each do |new_req, old_req|
56
- raise "Bad req match" unless new_req[:file] == T.must(old_req)[:file]
57
- next if new_req[:requirement] == T.must(old_req)[:requirement]
58
- next unless new_req[:file] == manifest.name
56
+ raise "Bad req match" unless new_req.file == T.must(old_req).file
57
+ next if new_req.requirement == T.must(old_req).requirement
58
+ next unless new_req.file == manifest.name
59
59
 
60
60
  updated_content = update_manifest_req(
61
61
  content: updated_content,
62
62
  dep: dependency,
63
- old_req: T.must(old_req).fetch(:requirement),
64
- new_req: new_req.fetch(:requirement)
63
+ old_req: T.must(T.must(old_req).requirement_string),
64
+ new_req: T.must(new_req.requirement_string)
65
65
  )
66
66
  end
67
67
 
@@ -118,7 +118,7 @@ module Dependabot
118
118
  changed_requirements =
119
119
  dependency.requirements - T.must(dependency.previous_requirements)
120
120
 
121
- changed_requirements.any? { |f| f[:file] == manifest.name }
121
+ changed_requirements.any? { |f| f.file == manifest.name }
122
122
  end
123
123
  end
124
124
  end
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -19,8 +19,8 @@ module Dependabot
19
19
  sig do
20
20
  params(
21
21
  content: String,
22
- new_r: T::Hash[Symbol, T.untyped],
23
- old_r: T::Hash[Symbol, T.untyped]
22
+ new_r: Dependabot::DependencyRequirement,
23
+ old_r: Dependabot::DependencyRequirement
24
24
  ).returns(T.nilable(String))
25
25
  end
26
26
  def replace(content, new_r, old_r)
@@ -96,8 +96,8 @@ module Dependabot
96
96
  params(
97
97
  content: String,
98
98
  source_req: String,
99
- new_r: T::Hash[Symbol, T.untyped],
100
- old_r: T::Hash[Symbol, T.untyped]
99
+ new_r: Dependabot::DependencyRequirement,
100
+ old_r: Dependabot::DependencyRequirement
101
101
  ).returns(T.nilable(String))
102
102
  end
103
103
  def replace_with_source_requirement(content, source_req, new_r, old_r)
@@ -105,7 +105,11 @@ module Dependabot
105
105
  return unless match
106
106
 
107
107
  declaration = T.must(match[:declaration])
108
- new_req_str = rewrite_pep508_requirement(source_req, old_r[:requirement], new_r[:requirement])
108
+ new_req_str = rewrite_pep508_requirement(
109
+ source_req,
110
+ T.must(old_r.requirement_string),
111
+ T.must(new_r.requirement_string)
112
+ )
109
113
  content.sub(declaration, declaration.sub(source_req, new_req_str))
110
114
  end
111
115
 
@@ -116,13 +120,13 @@ module Dependabot
116
120
  sig do
117
121
  params(
118
122
  content: String,
119
- new_r: T::Hash[Symbol, T.untyped],
120
- old_r: T::Hash[Symbol, T.untyped]
123
+ new_r: Dependabot::DependencyRequirement,
124
+ old_r: Dependabot::DependencyRequirement
121
125
  ).returns(T.nilable(String))
122
126
  end
123
127
  def replace_with_normalized_requirement(content, new_r, old_r)
124
- old_req = old_r[:requirement]
125
- new_req = new_r[:requirement]
128
+ old_req = T.must(old_r.requirement_string)
129
+ new_req = T.must(new_r.requirement_string)
126
130
 
127
131
  match = content.match(normalized_declaration_regex(old_req))
128
132
  return unless match
@@ -45,7 +45,7 @@ module Dependabot
45
45
  @dependencies = dependencies
46
46
  @dependency_files = dependency_files
47
47
  @credentials = credentials
48
- @cooldown = T.let(cooldown, T.nilable(Dependabot::Package::ReleaseCooldownOptions))
48
+ @cooldown = cooldown
49
49
  @updated_dependency_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
50
50
  @prepared_pyproject = T.let(nil, T.nilable(String))
51
51
  @pyproject = T.let(nil, T.nilable(Dependabot::DependencyFile))
@@ -99,7 +99,7 @@ module Dependabot
99
99
  updated_content = content.dup
100
100
 
101
101
  dependency.requirements.zip(T.must(dependency.previous_requirements)).each do |new_r, old_r|
102
- next unless new_r[:file] == pyproject&.name && T.must(old_r)[:file] == pyproject&.name
102
+ next unless new_r.file == pyproject&.name && T.must(old_r).file == pyproject&.name
103
103
 
104
104
  updated_content = replace_dep(dependency, T.must(updated_content), new_r, T.must(old_r))
105
105
  end
@@ -109,7 +109,7 @@ module Dependabot
109
109
  updated_content
110
110
  end
111
111
 
112
- sig { params(dep: Dependabot::Dependency, content: String, new_r: T::Hash[Symbol, T.untyped], old_r: T::Hash[Symbol, T.untyped]).returns(String) }
112
+ sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(String) }
113
113
  def replace_dep(dep, content, new_r, old_r)
114
114
  return update_git_tag(dep, content, new_r, old_r) if git_dependency?(new_r) && git_dependency?(old_r)
115
115
 
@@ -119,10 +119,10 @@ module Dependabot
119
119
  content
120
120
  end
121
121
 
122
- sig { params(dep: Dependabot::Dependency, content: String, new_r: T::Hash[Symbol, T.untyped], old_r: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
122
+ sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
123
123
  def replace_poetry_dep(dep, content, new_r, old_r)
124
- new_req = new_r[:requirement]
125
- old_req = old_r[:requirement]
124
+ new_req = T.must(new_r.requirement_string)
125
+ old_req = T.must(old_r.requirement_string)
126
126
 
127
127
  declaration_regex = declaration_regex(dep, old_r)
128
128
  declaration_match = content.match(declaration_regex)
@@ -135,10 +135,10 @@ module Dependabot
135
135
  content.sub(T.must(declaration), new_declaration)
136
136
  end
137
137
 
138
- sig { params(dep: Dependabot::Dependency, content: String, new_r: T::Hash[Symbol, T.untyped], old_r: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
138
+ sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
139
139
  def replace_poetry_table_dep(dep, content, new_r, old_r)
140
- old_req = old_r[:requirement]
141
- new_req = new_r[:requirement]
140
+ old_req = T.must(old_r.requirement_string)
141
+ new_req = T.must(new_r.requirement_string)
142
142
  regex = table_declaration_regex(dep, new_r)
143
143
 
144
144
  return unless content.match(regex)
@@ -151,20 +151,20 @@ module Dependabot
151
151
  end
152
152
  end
153
153
 
154
- sig { params(dep: Dependabot::Dependency, content: String, new_r: T::Hash[Symbol, T.untyped], old_r: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
154
+ sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
155
155
  def replace_pep621_dep(dep, content, new_r, old_r)
156
156
  Pep621Updater.new(dep: dep).replace(content, new_r, old_r)
157
157
  end
158
158
 
159
- sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
159
+ sig { params(req: Dependabot::DependencyRequirement).returns(T::Boolean) }
160
160
  def git_dependency?(req)
161
- req.dig(:source, :type) == "git"
161
+ req.source_string("type") == "git"
162
162
  end
163
163
 
164
- sig { params(dep: Dependabot::Dependency, content: String, new_r: T::Hash[Symbol, T.untyped], old_r: T::Hash[Symbol, T.untyped]).returns(String) }
164
+ sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(String) }
165
165
  def update_git_tag(dep, content, new_r, old_r)
166
- old_tag = old_r.dig(:source, :ref)
167
- new_tag = new_r.dig(:source, :ref)
166
+ old_tag = old_r.source_string("ref")
167
+ new_tag = new_r.source_string("ref")
168
168
 
169
169
  return content if old_tag == new_tag
170
170
 
@@ -172,7 +172,7 @@ module Dependabot
172
172
  # Example: fastapi = { git = "...", extras = ["all"], tag = "0.110.0" }
173
173
  git_dep_regex = /
174
174
  ^(\s*)#{Regexp.escape(dep.name)}(\s*=\s*\{[^}]*tag\s*=\s*)
175
- ["']#{Regexp.escape(old_tag)}["']([^}]*\})
175
+ ["']#{Regexp.escape(T.must(old_tag))}["']([^}]*\})
176
176
  /mx
177
177
 
178
178
  content.gsub(git_dep_regex) do
@@ -233,7 +233,7 @@ module Dependabot
233
233
  # Skip Git dependencies - they use tags/refs, not versions
234
234
  next if git_dependency_being_updated?(dep)
235
235
 
236
- if dep.requirements.find { |r| r[:file] == pyproject&.name }
236
+ if dep.requirements.find { |r| r.file == pyproject&.name }
237
237
  lock_declaration_to_new_version!(poetry_object, dep)
238
238
  else
239
239
  create_declaration_at_new_version!(poetry_object, dep)
@@ -302,7 +302,7 @@ module Dependabot
302
302
 
303
303
  sig { params(dep: Dependabot::Dependency).returns(T::Boolean) }
304
304
  def git_dependency_being_updated?(dep)
305
- dep.requirements.any? { |r| r.dig(:source, :type) == "git" }
305
+ dep.requirements.any? { |r| r.source_string("type") == "git" }
306
306
  end
307
307
 
308
308
  sig { params(pyproject_content: String).returns(String) }
@@ -382,17 +382,17 @@ module Dependabot
382
382
  end
383
383
  end
384
384
 
385
- sig { params(dep: Dependabot::Dependency, old_req: T::Hash[Symbol, T.untyped]).returns(Regexp) }
385
+ sig { params(dep: Dependabot::Dependency, old_req: Dependabot::DependencyRequirement).returns(Regexp) }
386
386
  def declaration_regex(dep, old_req)
387
- group = old_req[:groups].first
387
+ group = T.must(old_req.groups).first
388
388
 
389
389
  header_regex = "#{group}(?:\\.dependencies)?\\]\s*(?:\s*#.*?)*?"
390
390
  /#{header_regex}(?:\r?\n).*?(?<declaration>(?:^\s*|["'])#{escape(dep)}["']?\s*=[^\r\n]*)(?=\r?\n|$)/mi
391
391
  end
392
392
 
393
- sig { params(dep: Dependabot::Dependency, old_req: T::Hash[Symbol, T.untyped]).returns(Regexp) }
393
+ sig { params(dep: Dependabot::Dependency, old_req: Dependabot::DependencyRequirement).returns(Regexp) }
394
394
  def table_declaration_regex(dep, old_req)
395
- /tool\.poetry\.#{old_req[:groups].first}\.#{escape(dep)}\](?:\r?\n).*?\s*version\s* =.*?(?:\r?\n)/m
395
+ /tool\.poetry\.#{T.must(old_req.groups).first}\.#{escape(dep)}\](?:\r?\n).*?\s*version\s* =.*?(?:\r?\n)/m
396
396
  end
397
397
 
398
398
  sig { params(dep: Dependency).returns(String) }
@@ -410,7 +410,7 @@ module Dependabot
410
410
  changed_requirements =
411
411
  dependency.requirements - T.must(dependency.previous_requirements)
412
412
 
413
- changed_requirements.any? { |f| f[:file] == file.name }
413
+ changed_requirements.any? { |f| f.file == file.name }
414
414
  end
415
415
 
416
416
  sig { params(file: Dependabot::DependencyFile, content: String).returns(Dependabot::DependencyFile) }
@@ -18,10 +18,7 @@ module Dependabot
18
18
 
19
19
  # Fixed regex for extracting the name+extras prefix from a PEP 508 entry.
20
20
  # Does not interpolate library input, avoiding polynomial backtracking.
21
- PEP508_PREFIX = T.let(
22
- /\A(?<prefix>(?<name>[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?)(?:\[[^\]]*\])?)/i,
23
- Regexp
24
- )
21
+ PEP508_PREFIX = /\A(?<prefix>(?<name>[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?)(?:\[[^\]]*\])?)/i
25
22
 
26
23
  # Pins a single PEP 508 dependency entry string to a specific version,
27
24
  # preserving extras and environment markers.
@@ -142,7 +139,7 @@ module Dependabot
142
139
  .gsub('#{', "{")
143
140
  end
144
141
 
145
- UNSUPPORTED_SOURCE_TYPES = T.let(%w(directory file url).freeze, T::Array[String])
142
+ UNSUPPORTED_SOURCE_TYPES = %w(directory file url).freeze
146
143
 
147
144
  sig { params(dependencies: T::Array[Dependabot::Dependency]).returns(String) }
148
145
  def freeze_top_level_dependencies_except(dependencies)
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -13,6 +13,10 @@ module Dependabot
13
13
  class RequirementFileUpdater
14
14
  extend T::Sig
15
15
 
16
+ RequirementChange = T.type_alias do
17
+ [Dependabot::DependencyRequirement, T.nilable(Dependabot::DependencyRequirement)]
18
+ end
19
+
16
20
  require_relative "requirement_replacer"
17
21
 
18
22
  sig { returns(T::Array[Dependabot::Dependency]) }
@@ -33,10 +37,10 @@ module Dependabot
33
37
  ).void
34
38
  end
35
39
  def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
36
- @dependencies = T.let(dependencies, T::Array[Dependabot::Dependency])
37
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
38
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
39
- @index_urls = T.let(index_urls, T.nilable(T::Array[T.nilable(String)]))
40
+ @dependencies = dependencies
41
+ @dependency_files = dependency_files
42
+ @credentials = credentials
43
+ @index_urls = index_urls
40
44
  @updated_dependency_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
41
45
  end
42
46
 
@@ -58,9 +62,9 @@ module Dependabot
58
62
  updated_contents = T.let({}, T::Hash[String, String])
59
63
 
60
64
  unique_requirement_changes.each do |pair|
61
- new_req = T.must(pair[0])
65
+ new_req = pair[0]
62
66
  old_req = pair[1]
63
- filename = new_req.fetch(:file)
67
+ filename = T.must(new_req.file)
64
68
  content = updated_contents[filename] || T.must(T.must(get_original_file(filename)).content)
65
69
  updated_contents[filename] = updated_requirement_or_setup_file_content(content, new_req, old_req)
66
70
  end
@@ -77,37 +81,37 @@ module Dependabot
77
81
  # Deduplicates requirements that share the same file and requirement strings.
78
82
  # The replacer's regex matches all extras variants at once, so one call per
79
83
  # unique (file, old_requirement, new_requirement) is sufficient.
80
- sig { returns(T::Array[T::Array[T.nilable(T::Hash[Symbol, T.untyped])]]) }
84
+ sig { returns(T::Array[RequirementChange]) }
81
85
  def unique_requirement_changes
82
86
  previous_reqs = dependency.previous_requirements || []
83
87
 
84
88
  changes = dependency.requirements.filter_map do |new_req|
85
- old_req = previous_reqs.find { |r| r[:file] == new_req[:file] && r[:groups] == new_req[:groups] }
89
+ old_req = previous_reqs.find { |r| r.file == new_req.file && r.groups == new_req.groups }
86
90
  next if new_req == old_req
87
91
 
88
- [new_req, old_req]
92
+ T.let([new_req, old_req], RequirementChange)
89
93
  end
90
94
 
91
95
  changes.uniq do |pair|
92
96
  new_req = pair[0]
93
97
  old_req = pair[1]
94
- [new_req[:file], old_req&.fetch(:requirement), new_req.fetch(:requirement)]
98
+ [new_req.file, old_req&.requirement, new_req.requirement]
95
99
  end
96
100
  end
97
101
 
98
102
  sig do
99
103
  params(
100
104
  content: String,
101
- new_req: T::Hash[Symbol, T.untyped],
102
- old_req: T.nilable(T::Hash[Symbol, T.untyped])
105
+ new_req: Dependabot::DependencyRequirement,
106
+ old_req: T.nilable(Dependabot::DependencyRequirement)
103
107
  ).returns(String)
104
108
  end
105
109
  def updated_requirement_or_setup_file_content(content, new_req, old_req)
106
110
  RequirementReplacer.new(
107
111
  content: content,
108
112
  dependency_name: dependency.name,
109
- old_requirement: old_req&.fetch(:requirement),
110
- new_requirement: new_req.fetch(:requirement),
113
+ old_requirement: old_req&.requirement_string,
114
+ new_requirement: T.must(new_req.requirement_string),
111
115
  new_hash_version: dependency.version,
112
116
  index_urls: @index_urls
113
117
  ).updated_content
@@ -37,12 +37,12 @@ module Dependabot
37
37
  new_hash_version: nil,
38
38
  index_urls: nil
39
39
  )
40
- @content = T.let(content, String)
40
+ @content = content
41
41
  @dependency_name = T.let(normalise(dependency_name), String)
42
- @old_requirement = T.let(old_requirement, T.nilable(String))
43
- @new_requirement = T.let(new_requirement, T.nilable(String))
44
- @new_hash_version = T.let(new_hash_version, T.nilable(String))
45
- @index_urls = T.let(index_urls, T.nilable(T::Array[T.nilable(String)]))
42
+ @old_requirement = old_requirement
43
+ @new_requirement = new_requirement
44
+ @new_hash_version = new_hash_version
45
+ @index_urls = index_urls
46
46
  end
47
47
 
48
48
  sig { returns(String) }
@@ -20,8 +20,8 @@ module Dependabot
20
20
  ).void
21
21
  end
22
22
  def initialize(setup_file:, setup_cfg:)
23
- @setup_file = T.let(setup_file, T.nilable(Dependabot::DependencyFile))
24
- @setup_cfg = T.let(setup_cfg, T.nilable(Dependabot::DependencyFile))
23
+ @setup_file = setup_file
24
+ @setup_cfg = setup_cfg
25
25
  @install_requires_array = T.let(nil, T.nilable(T::Array[String]))
26
26
  @setup_requires_array = T.let(nil, T.nilable(T::Array[String]))
27
27
  @extras_require_hash = T.let(nil, T.nilable(T::Hash[String, T::Array[String]]))
@@ -61,10 +61,9 @@ module Dependabot
61
61
  @install_requires_array ||=
62
62
  parsed_setup_file.dependencies.filter_map do |dep|
63
63
  first = T.must(dep.requirements.first)
64
- next unless first[:groups]
65
- .include?("install_requires")
64
+ next unless first.groups&.include?("install_requires")
66
65
 
67
- name_with_extras(dep) + first[:requirement].to_s
66
+ name_with_extras(dep) + first.requirement.to_s
68
67
  end
69
68
  end
70
69
 
@@ -73,10 +72,9 @@ module Dependabot
73
72
  @setup_requires_array ||=
74
73
  parsed_setup_file.dependencies.filter_map do |dep|
75
74
  first = T.must(dep.requirements.first)
76
- next unless first[:groups]
77
- .include?("setup_requires")
75
+ next unless first.groups&.include?("setup_requires")
78
76
 
79
- name_with_extras(dep) + first[:requirement].to_s
77
+ name_with_extras(dep) + first.requirement.to_s
80
78
  end
81
79
  end
82
80
 
@@ -87,12 +85,13 @@ module Dependabot
87
85
  hash = {}
88
86
  parsed_setup_file.dependencies.each do |dep|
89
87
  first = T.must(dep.requirements.first)
90
- first[:groups].each do |group|
88
+ T.must(first.groups).each do |group|
91
89
  next unless group.start_with?("extras_require:")
92
90
 
93
- hash[group.split(":").last] ||= []
94
- hash[group.split(":").last] <<
95
- (name_with_extras(dep) + first[:requirement].to_s)
91
+ group_name = group.to_s
92
+ hash[group_name.split(":").last] ||= []
93
+ hash[group_name.split(":").last] <<
94
+ (name_with_extras(dep) + first.requirement.to_s)
96
95
  end
97
96
  end
98
97
 
@@ -46,7 +46,7 @@ module Dependabot
46
46
  changed_reqs = reqs.zip(dependencies.flat_map(&:previous_requirements))
47
47
  .reject { |(new_req, old_req)| new_req == old_req }
48
48
  .map(&:first)
49
- changed_req_files = changed_reqs.map { |r| r.fetch(:file) }
49
+ changed_req_files = changed_reqs.filter_map(&:file)
50
50
 
51
51
  # If there are no requirements then this is a sub-dependency. It
52
52
  # must come from one of Pipenv, Poetry or pip-tools, and can't come
@@ -25,9 +25,9 @@ module Dependabot
25
25
  ).void
26
26
  end
27
27
  def initialize(dependency_files:, credentials:, dependency:)
28
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
29
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
30
- @dependency = T.let(dependency, Dependabot::Dependency)
28
+ @dependency_files = dependency_files
29
+ @credentials = credentials
30
+ @dependency = dependency
31
31
  end
32
32
 
33
33
  sig { returns(T::Array[String]) }
@@ -143,7 +143,7 @@ module Dependabot
143
143
  sig { returns(T.nilable(String)) }
144
144
  def lockfile_section
145
145
  if current_dependency.requirements.any?
146
- T.must(current_dependency.requirements.first)[:groups].first
146
+ T.must(T.must(current_dependency.requirements.first).groups).first&.to_s
147
147
  else
148
148
  parsed_lockfile = JSON.parse(T.must(T.must(lockfile).content))
149
149
  Python::FileParser::DEPENDENCY_GROUP_KEYS.each do |keys|
@@ -27,7 +27,7 @@ module Dependabot
27
27
 
28
28
  sig { params(pyproject_content: T.nilable(String)).void }
29
29
  def initialize(pyproject_content:)
30
- @pyproject_content = T.let(pyproject_content, T.nilable(String))
30
+ @pyproject_content = pyproject_content
31
31
  @plugins_installed = T.let(false, T::Boolean)
32
32
  end
33
33
 
@@ -12,7 +12,7 @@ module Dependabot
12
12
  class Requirement < Dependabot::Requirement
13
13
  extend T::Sig
14
14
 
15
- OR_SEPARATOR = T.let(/(?<=[a-zA-Z0-9)*])\s*\|+/, Regexp)
15
+ OR_SEPARATOR = /(?<=[a-zA-Z0-9)*])\s*\|+/
16
16
 
17
17
  # Add equality and arbitrary-equality matchers
18
18
  OPS = T.let(
@@ -28,8 +28,8 @@ module Dependabot
28
28
  version_pattern = Python::Version::VERSION_PATTERN
29
29
 
30
30
  PATTERN_RAW = T.let("\\s*(?<op>#{quoted})?\\s*(?<version>#{version_pattern})\\s*".freeze, String)
31
- PATTERN = T.let(/\A#{PATTERN_RAW}\z/, Regexp)
32
- PARENS_PATTERN = T.let(/\A\(([^)]+)\)\z/, Regexp)
31
+ PATTERN = /\A#{PATTERN_RAW}\z/
32
+ PARENS_PATTERN = /\A\(([^)]+)\)\z/
33
33
 
34
34
  sig { params(obj: T.any(Gem::Version, String)).returns([String, Gem::Version]) }
35
35
  def self.parse(obj)
@@ -107,11 +107,14 @@ module Dependabot
107
107
  req_string = req_string.gsub("~=", "~>")
108
108
  req_string = req_string.gsub(/(?<=\d)[<=>].*\Z/, "")
109
109
 
110
- if req_string.match?(/~[^>]/) then convert_tilde_req(req_string)
111
- elsif req_string.start_with?("^") then convert_caret_req(req_string)
110
+ if req_string.match?(/~[^>]/)
111
+ convert_tilde_req(req_string)
112
+ elsif req_string.start_with?("^")
113
+ convert_caret_req(req_string)
112
114
  elsif req_string.match?(/^=?={0,2}\s*\d+\.\d+(\.\d+)?(-[a-z0-9.-]+)?(\.\*)?$/i)
113
115
  convert_exact(req_string)
114
- elsif req_string.include?(".*") then convert_wildcard(req_string)
116
+ elsif req_string.include?(".*")
117
+ convert_wildcard(req_string)
115
118
  else
116
119
  req_string
117
120
  end
@@ -21,10 +21,10 @@ module Dependabot
21
21
 
22
22
  abstract!
23
23
 
24
- CHILD_REQUIREMENT_REGEX = T.let(/^-r\s?(?<path>.*\.(?:txt|in))/, Regexp)
25
- CONSTRAINT_REGEX = T.let(/^-c\s?(?<path>.*\.(?:txt|in))/, Regexp)
26
- DEPENDENCY_TYPES = T.let(%w(packages dev-packages).freeze, T::Array[String])
27
- MAX_FILE_SIZE = T.let(500_000, Integer)
24
+ CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/
25
+ CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/
26
+ DEPENDENCY_TYPES = %w(packages dev-packages).freeze
27
+ MAX_FILE_SIZE = 500_000
28
28
 
29
29
  sig { abstract.returns(T::Array[String]) }
30
30
  def self.ecosystem_specific_required_files; end
@@ -34,7 +34,7 @@ module Dependabot
34
34
  return true if filenames.any? { |name| name.end_with?(".txt", ".in") }
35
35
  return true if filenames.include?("requirements")
36
36
  return true if filenames.include?("pyproject.toml")
37
- return true if filenames.any? { |name| ecosystem_specific_required_files.include?(name) }
37
+ return true if filenames.intersect?(ecosystem_specific_required_files)
38
38
 
39
39
  false
40
40
  end
@@ -27,16 +27,14 @@ module Dependabot
27
27
  class PipCompileVersionResolver # rubocop:disable Metrics/ClassLength
28
28
  extend T::Sig
29
29
 
30
- GIT_DEPENDENCY_UNREACHABLE_REGEX = T.let(/git clone --filter=blob:none --quiet (?<url>[^\s]+).* /, Regexp)
31
- GIT_REFERENCE_NOT_FOUND_REGEX = T.let(/Did not find branch or tag '(?<tag>[^\n"]+)'/m, Regexp)
32
- NATIVE_COMPILATION_ERROR = T.let(
33
- "pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1",
34
- String
35
- )
30
+ GIT_DEPENDENCY_UNREACHABLE_REGEX = /git clone --filter=blob:none --quiet (?<url>[^\s]+).* /
31
+ GIT_REFERENCE_NOT_FOUND_REGEX = /Did not find branch or tag '(?<tag>[^\n"]+)'/m
32
+ NATIVE_COMPILATION_ERROR =
33
+ "pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1"
36
34
  # See https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata
37
- PYTHON_PACKAGE_NAME_REGEX = T.let(/[A-Za-z0-9_\-]+/, Regexp)
38
- RESOLUTION_IMPOSSIBLE_ERROR = T.let("ResolutionImpossible", String)
39
- ERROR_REGEX = T.let(/(?<=ERROR\:\W).*$/, Regexp)
35
+ PYTHON_PACKAGE_NAME_REGEX = /[A-Za-z0-9_\-]+/
36
+ RESOLUTION_IMPOSSIBLE_ERROR = "ResolutionImpossible"
37
+ ERROR_REGEX = /(?<=ERROR\:\W).*$/
40
38
 
41
39
  sig { returns(Dependabot::Dependency) }
42
40
  attr_reader :dependency
@@ -62,10 +60,10 @@ module Dependabot
62
60
  ).void
63
61
  end
64
62
  def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
65
- @dependency = T.let(dependency, Dependabot::Dependency)
66
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
67
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
68
- @repo_contents_path = T.let(repo_contents_path, T.nilable(String))
63
+ @dependency = dependency
64
+ @dependency_files = dependency_files
65
+ @credentials = credentials
66
+ @repo_contents_path = repo_contents_path
69
67
  @build_isolation = T.let(true, T::Boolean)
70
68
  @error_handler = T.let(PipCompileErrorHandler.new, PipCompileErrorHandler)
71
69
  end
@@ -402,14 +400,14 @@ module Dependabot
402
400
  def update_req_file(file, updated_req)
403
401
  return T.must(file.content) unless file.name.end_with?(".in")
404
402
 
405
- req = dependency.requirements.find { |r| r[:file] == file.name }
403
+ req = dependency.requirements.find { |r| r.file == file.name }
406
404
 
407
- return T.must(file.content) + "\n#{dependency.name} #{updated_req}" unless req&.fetch(:requirement)
405
+ return T.must(file.content) + "\n#{dependency.name} #{updated_req}" unless req&.requirement_string
408
406
 
409
407
  Python::FileUpdater::RequirementReplacer.new(
410
408
  content: T.must(file.content),
411
409
  dependency_name: dependency.name,
412
- old_requirement: req[:requirement],
410
+ old_requirement: req.requirement_string,
413
411
  new_requirement: updated_req
414
412
  ).updated_content
415
413
  end
@@ -428,7 +426,7 @@ module Dependabot
428
426
  def filenames_to_compile
429
427
  files_from_reqs =
430
428
  dependency.requirements
431
- .map { |r| r[:file] }
429
+ .filter_map(&:file)
432
430
  .select { |fn| fn.end_with?(".in") }
433
431
 
434
432
  files_from_compiled_files =
@@ -585,13 +583,13 @@ module Dependabot
585
583
  class PipCompileErrorHandler
586
584
  extend T::Sig
587
585
 
588
- SUBPROCESS_ERROR = T.let(/subprocess-exited-with-error/, Regexp)
586
+ SUBPROCESS_ERROR = /subprocess-exited-with-error/
589
587
 
590
- INSTALLATION_ERROR = T.let(/InstallationError/, Regexp)
588
+ INSTALLATION_ERROR = /InstallationError/
591
589
 
592
- INSTALLATION_SUBPROCESS_ERROR = T.let(/InstallationSubprocessError/, Regexp)
590
+ INSTALLATION_SUBPROCESS_ERROR = /InstallationSubprocessError/
593
591
 
594
- HASH_MISMATCH = T.let(/HashMismatch/, Regexp)
592
+ HASH_MISMATCH = /HashMismatch/
595
593
 
596
594
  sig { params(error: String).void }
597
595
  def handle_pipcompile_error(error)
@@ -182,7 +182,9 @@ module Dependabot
182
182
  sig { returns(T::Array[[String, String]]) }
183
183
  def normalized_requirement_files
184
184
  dependency.requirements.filter_map do |req|
185
- raw_file = T.cast(req.fetch(:file), String)
185
+ raw_file = req.file
186
+ next unless raw_file
187
+
186
188
  [raw_file, normalize_path(raw_file)]
187
189
  end
188
190
  end
@@ -56,10 +56,10 @@ module Dependabot
56
56
  ).void
57
57
  end
58
58
  def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
59
- @dependency = T.let(dependency, Dependabot::Dependency)
60
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
61
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
62
- @repo_contents_path = T.let(repo_contents_path, T.nilable(String))
59
+ @dependency = dependency
60
+ @dependency_files = dependency_files
61
+ @credentials = credentials
62
+ @repo_contents_path = repo_contents_path
63
63
  end
64
64
 
65
65
  sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Python::Version)) }
@@ -78,10 +78,10 @@ module Dependabot
78
78
  ).void
79
79
  end
80
80
  def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
81
- @dependency = T.let(dependency, Dependabot::Dependency)
82
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
83
- @credentials = T.let(credentials, T::Array[Dependabot::Credential])
84
- @repo_contents_path = T.let(repo_contents_path, T.nilable(String))
81
+ @dependency = dependency
82
+ @dependency_files = dependency_files
83
+ @credentials = credentials
84
+ @repo_contents_path = repo_contents_path
85
85
  @error_handler = T.let(
86
86
  PoetryErrorHandler.new(dependencies: dependency, dependency_files: dependency_files),
87
87
  Dependabot::Python::PoetryErrorHandler
@@ -333,7 +333,7 @@ module Dependabot
333
333
  end
334
334
 
335
335
  # If this is a sub-dependency, add the new requirement
336
- unless dependency.requirements.find { |r| r[:file] == T.must(pyproject).name }
336
+ unless dependency.requirements.find { |r| r.file == T.must(pyproject).name }
337
337
  poetry_object[subdep_type] ||= {}
338
338
  poetry_object[subdep_type][dependency.name] = updated_requirement
339
339
  end
@@ -490,8 +490,8 @@ module Dependabot
490
490
  ).void
491
491
  end
492
492
  def initialize(dependencies:, dependency_files:)
493
- @dependencies = T.let(dependencies, Dependabot::Dependency)
494
- @dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
493
+ @dependencies = dependencies
494
+ @dependency_files = dependency_files
495
495
  end
496
496
 
497
497
  private
@@ -16,9 +16,9 @@ module Dependabot
16
16
  class RequirementsUpdater
17
17
  extend T::Sig
18
18
 
19
- PYPROJECT_OR_SEPARATOR = T.let(/(?<=[a-zA-Z0-9*])\s*\|+/, Regexp)
20
- PYPROJECT_SEPARATOR = T.let(/#{PYPROJECT_OR_SEPARATOR}|,/, Regexp)
21
- LOWER_BOUND_OPS = T.let(%w(> >=).freeze, T::Array[String])
19
+ PYPROJECT_OR_SEPARATOR = /(?<=[a-zA-Z0-9*])\s*\|+/
20
+ PYPROJECT_SEPARATOR = /#{PYPROJECT_OR_SEPARATOR}|,/
21
+ LOWER_BOUND_OPS = %w(> >=).freeze
22
22
 
23
23
  class UnfixableRequirement < StandardError; end
24
24
 
@@ -52,8 +52,8 @@ module Dependabot
52
52
  requirements.map { |req| Dependabot::DependencyRequirement.create(req) },
53
53
  T::Array[Dependabot::DependencyRequirement]
54
54
  )
55
- @update_strategy = T.let(update_strategy, Dependabot::RequirementsUpdateStrategy)
56
- @has_lockfile = T.let(has_lockfile, T::Boolean)
55
+ @update_strategy = update_strategy
56
+ @has_lockfile = has_lockfile
57
57
  @latest_resolvable_version = T.let(nil, T.nilable(Dependabot::Python::Version))
58
58
 
59
59
  return unless latest_resolvable_version
@@ -66,45 +66,49 @@ module Dependabot
66
66
  return requirements if update_strategy.lockfile_only?
67
67
 
68
68
  requirements.map do |req|
69
- case req[:file]
69
+ case req.file
70
70
  when /setup\.(?:py|cfg)$/ then updated_setup_requirement(req)
71
71
  when ->(file) { file.end_with?("pyproject.toml") } then updated_pyproject_requirement(req)
72
72
  when "Pipfile" then updated_pipfile_requirement(req)
73
73
  when /\.txt$|\.in$/ then updated_requirement(req)
74
- else raise "Unexpected filename: #{req[:file]}"
74
+ else raise "Unexpected filename: #{req.file}"
75
75
  end
76
76
  end
77
77
  end
78
78
 
79
79
  private
80
80
 
81
- # rubocop:disable Metrics/PerceivedComplexity
82
81
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
83
82
  def updated_setup_requirement(req)
84
83
  return req unless latest_resolvable_version
85
- return req unless req.fetch(:requirement)
86
- return req if new_version_satisfies?(req)
87
84
 
88
- req_strings = req[:requirement].split(",").map(&:strip)
89
-
90
- new_requirement =
91
- if req_strings.any? { |r| requirement_class.new(r).exact? }
92
- find_and_update_equality_match(req_strings)
93
- elsif req_strings.any? { |r| r.start_with?("~=") }
94
- tw_req = req_strings.find { |r| r.start_with?("~=") }
95
- bump_version(tw_req, latest_resolvable_version.to_s)
96
- elsif req_strings.any? { |r| r.start_with?("==") }
97
- tw_req = req_strings.find { |r| r.start_with?("==") }
98
- convert_to_range(tw_req, T.must(latest_resolvable_version))
99
- else
100
- update_requirements_range(req_strings)
101
- end
85
+ requirement = req.requirement_string
86
+ return req unless requirement
87
+ return req if new_version_satisfies?(req)
102
88
 
89
+ new_requirement = updated_setup_requirement_string(requirement)
103
90
  Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
104
91
  rescue UnfixableRequirement
105
92
  Dependabot::DependencyRequirement.create(req.merge(requirement: :unfixable))
106
93
  end
107
- # rubocop:enable Metrics/PerceivedComplexity
94
+
95
+ sig { params(requirement: String).returns(String) }
96
+ def updated_setup_requirement_string(requirement)
97
+ req_strings = requirement.split(",").map(&:strip)
98
+ return find_and_update_equality_match(req_strings) if req_strings.any? { |r| requirement_class.new(r).exact? }
99
+
100
+ if req_strings.any? { |r| r.start_with?("~=") }
101
+ tw_req = req_strings.find { |r| r.start_with?("~=") }
102
+ return bump_version(T.must(tw_req), latest_resolvable_version.to_s)
103
+ end
104
+
105
+ if req_strings.any? { |r| r.start_with?("==") }
106
+ tw_req = req_strings.find { |r| r.start_with?("==") }
107
+ return convert_to_range(T.must(tw_req), T.must(latest_resolvable_version))
108
+ end
109
+
110
+ update_requirements_range(req_strings)
111
+ end
108
112
 
109
113
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
110
114
  def updated_pipfile_requirement(req)
@@ -116,7 +120,7 @@ module Dependabot
116
120
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
117
121
  def updated_pyproject_requirement(req)
118
122
  return req unless latest_resolvable_version
119
- return req unless req.fetch(:requirement)
123
+ return req unless req.requirement_string
120
124
  return req if skip_pyproject_update?(req)
121
125
 
122
126
  pyproject_update_for_strategy(req)
@@ -132,11 +136,13 @@ module Dependabot
132
136
 
133
137
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
134
138
  def pyproject_update_for_strategy(req)
139
+ requirement = T.must(req.requirement_string)
140
+
135
141
  # If the requirement uses || syntax then we always want to widen it
136
- return widen_pyproject_requirement(req) if req.fetch(:requirement).match?(PYPROJECT_OR_SEPARATOR)
142
+ return widen_pyproject_requirement(req) if requirement.match?(PYPROJECT_OR_SEPARATOR)
137
143
 
138
144
  # If the requirement is a development dependency we always want to bump it
139
- return update_pyproject_version(req) if req.fetch(:groups).include?("dev-dependencies")
145
+ return update_pyproject_version(req) if req.groups&.include?("dev-dependencies")
140
146
 
141
147
  case update_strategy
142
148
  when RequirementsUpdateStrategy::WidenRanges then widen_pyproject_requirement(req)
@@ -155,7 +161,7 @@ module Dependabot
155
161
 
156
162
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
157
163
  def update_pyproject_version(req)
158
- return req if req[:requirement] == "*"
164
+ return req if req.requirement == "*"
159
165
 
160
166
  update_pyproject_version_core(req, bump_lower_bound: true)
161
167
  end
@@ -167,14 +173,14 @@ module Dependabot
167
173
  ).returns(Dependabot::DependencyRequirement)
168
174
  end
169
175
  def update_pyproject_version_core(req, bump_lower_bound:)
170
- requirement_strings = req[:requirement].split(",").map(&:strip)
176
+ requirement_strings = T.must(req.requirement_string).split(",").map(&:strip)
171
177
 
172
178
  new_requirement =
173
179
  if requirement_strings.any? { |r| r.match?(/^=|^\d/) }
174
180
  find_and_update_equality_match(requirement_strings)
175
181
  elsif requirement_strings.any? { |r| r.start_with?("~", "^") }
176
182
  v_req = requirement_strings.find { |r| r.start_with?("~", "^") }
177
- bump_version(v_req, latest_resolvable_version.to_s)
183
+ bump_version(T.must(v_req), latest_resolvable_version.to_s)
178
184
  elsif bump_lower_bound
179
185
  bump_requirements_range(requirement_strings)
180
186
  else
@@ -188,11 +194,12 @@ module Dependabot
188
194
  def widen_pyproject_requirement(req)
189
195
  return req if new_version_satisfies?(req)
190
196
 
197
+ requirement = T.must(req.requirement_string)
191
198
  new_requirement =
192
- if req[:requirement].match?(PYPROJECT_OR_SEPARATOR)
193
- add_new_requirement_option(req[:requirement])
199
+ if requirement.match?(PYPROJECT_OR_SEPARATOR)
200
+ add_new_requirement_option(requirement)
194
201
  else
195
- widen_requirement_range(req[:requirement])
202
+ widen_requirement_range(requirement)
196
203
  end
197
204
 
198
205
  Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
@@ -248,7 +255,7 @@ module Dependabot
248
255
  sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
249
256
  def updated_requirement(req)
250
257
  return req unless latest_resolvable_version
251
- return req unless req.fetch(:requirement)
258
+ return req unless req.requirement_string
252
259
 
253
260
  case update_strategy
254
261
  when RequirementsUpdateStrategy::WidenRanges
@@ -279,17 +286,18 @@ module Dependabot
279
286
 
280
287
  sig { params(req: Dependabot::DependencyRequirement).returns(T.any(String, Symbol)) }
281
288
  def updated_requirement_string(req)
282
- requirement_strings = req[:requirement].split(",").map(&:strip)
289
+ requirement = T.must(req.requirement_string)
290
+ requirement_strings = requirement.split(",").map(&:strip)
283
291
 
284
292
  if requirement_strings.any? { |r| r.match?(/^[=\d]/) }
285
293
  find_and_update_equality_match(requirement_strings)
286
294
  elsif requirement_strings.any? { |r| r.start_with?("~=") }
287
295
  tw_req = requirement_strings.find { |r| r.start_with?("~=") }
288
- bump_version(tw_req, latest_resolvable_version.to_s)
296
+ bump_version(T.must(tw_req), latest_resolvable_version.to_s)
289
297
  elsif bump_lower_bound?(requirement_strings)
290
298
  bump_requirements_range(requirement_strings)
291
299
  elsif new_version_satisfies?(req)
292
- req.fetch(:requirement)
300
+ requirement
293
301
  else
294
302
  update_requirements_range(requirement_strings)
295
303
  end
@@ -305,7 +313,7 @@ module Dependabot
305
313
  def widen_requirement(req)
306
314
  return req if new_version_satisfies?(req)
307
315
 
308
- new_requirement = widen_requirement_range(req[:requirement])
316
+ new_requirement = widen_requirement_range(T.must(req.requirement_string))
309
317
 
310
318
  Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
311
319
  end
@@ -313,7 +321,7 @@ module Dependabot
313
321
  sig { params(req: Dependabot::DependencyRequirement).returns(T::Boolean) }
314
322
  def new_version_satisfies?(req)
315
323
  requirement_class
316
- .requirements_array(req.fetch(:requirement))
324
+ .requirements_array(req.requirement_string)
317
325
  .any? { |r| r.satisfied_by?(T.must(latest_resolvable_version)) }
318
326
  end
319
327
 
@@ -253,10 +253,9 @@ module Dependabot
253
253
  :requirements
254
254
  end
255
255
 
256
- sig { params(reqs: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Boolean) }
256
+ sig { params(reqs: T::Array[Dependabot::DependencyRequirement]).returns(T::Boolean) }
257
257
  def exact_requirement?(reqs)
258
- reqs = reqs.map { |r| r.fetch(:requirement) }
259
- reqs = reqs.compact
258
+ reqs = reqs.filter_map(&:requirement_string)
260
259
  reqs = reqs.flat_map { |r| r.split(",").map(&:strip) }
261
260
  reqs.any? { |r| Python::Requirement.new(r).exact? }
262
261
  end
@@ -332,12 +331,13 @@ module Dependabot
332
331
  return if reqs.none?
333
332
 
334
333
  requirement = reqs.find do |r|
335
- file = r[:file]
334
+ file = r.file
335
+ next false unless file
336
336
 
337
337
  file == "Pipfile" || file == "pyproject.toml" || file.end_with?(".in") || file.end_with?(".txt")
338
338
  end
339
339
 
340
- requirement&.fetch(:requirement)
340
+ requirement&.requirement_string
341
341
  end
342
342
 
343
343
  sig { returns(String) }
@@ -361,13 +361,13 @@ module Dependabot
361
361
  def updated_version_req_lower_bound
362
362
  return ">=#{dependency.version}" if dependency.version
363
363
 
364
- version_for_requirement =
365
- requirements.filter_map { |r| r[:requirement] }
366
- .reject { |req_string| req_string.start_with?("<") }
367
- .select { |req_string| req_string.match?(VERSION_REGEX) }
368
- .map { |req_string| req_string.match(VERSION_REGEX).to_s }
369
- .select { |version| Python::Version.correct?(version) }
370
- .max_by { |version| Python::Version.new(version) }
364
+ version_for_requirement = requirements
365
+ .filter_map(&:requirement_string)
366
+ .reject { |req_string| req_string.start_with?("<") }
367
+ .select { |req_string| req_string.match?(VERSION_REGEX) }
368
+ .map { |req_string| req_string.match(VERSION_REGEX).to_s }
369
+ .select { |version| Python::Version.correct?(version) }
370
+ .max_by { |version| Python::Version.new(version) }
371
371
 
372
372
  ">=#{version_for_requirement || 0}"
373
373
  end
@@ -450,7 +450,7 @@ module Dependabot
450
450
 
451
451
  sig { returns(T::Array[String]) }
452
452
  def requirement_files
453
- requirements.map { |r| r.fetch(:file) }
453
+ requirements.filter_map(&:file)
454
454
  end
455
455
 
456
456
  sig { returns(T::Array[Dependabot::DependencyRequirement]) }
@@ -30,7 +30,7 @@ module Dependabot
30
30
  sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
31
31
  attr_reader :local
32
32
 
33
- INFINITY = T.let(1000, Integer)
33
+ INFINITY = 1000
34
34
  NEGATIVE_INFINITY = T.let(-INFINITY, Integer)
35
35
 
36
36
  # See https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-python
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.390.0
4
+ version: 0.392.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.390.0
18
+ version: 0.392.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.390.0
25
+ version: 0.392.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -323,7 +323,7 @@ licenses:
323
323
  - MIT
324
324
  metadata:
325
325
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
326
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.390.0
326
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.392.0
327
327
  rdoc_options: []
328
328
  require_paths:
329
329
  - lib