dependabot-python 0.280.0 → 0.282.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 769029ca498ad0bf57b8e8a3f7470dded08b67253371747cdc2cd14f19733660
4
- data.tar.gz: '05984613c4a3eb2298b755c4e96287c4d1b15a94553a378ab31b8992d20151b7'
3
+ metadata.gz: cb78159e578c1979c167b0539aef17d508c9a07b17b257c05a7d177a3c543d56
4
+ data.tar.gz: 31e6e4a5c352927c54cca8ef0a9b69265737d1739e9d85622aab8fba4b9e5ac3
5
5
  SHA512:
6
- metadata.gz: c3de2cf52a0326efb5e91b045001bfca0f25574394425f70ab59b7c6fe15f9618f690cfd847e8736c81b29d3e8fd28e5524931db4f9bad90171f8daffeeafad3
7
- data.tar.gz: d47f611d5f940b9c420f727d2f44d19308a7317a6ca799e86a29369401c64c6e833020f4279a991515ecfe3dcf6c3522d5b0d9aea8a282cbcc181b3a2d3c303a
6
+ metadata.gz: 4a15a3f16e2e68aa7c35d2fc3c011e88210a483cc13b7676e6412a035b8dac2abc831f395074185ca21e4bc020aa0cc775bb8d4b8efb3dda2be0332612bdf3f7
7
+ data.tar.gz: a241cbe9a4b2bab87b9daa50ad2e3ff357b2890f4ecb3f540a97350d44e7a24bd39dcfa660f9d2777d950834ab114ff54183255e35e8edfb22b1daeea92c74ae
@@ -11,9 +11,9 @@ module Dependabot
11
11
  PRE_INSTALLED_PYTHON_VERSIONS = %w(
12
12
  3.12.5
13
13
  3.11.9
14
- 3.10.13
14
+ 3.10.15
15
15
  3.9.18
16
- 3.8.18
16
+ 3.8.20
17
17
  ).freeze
18
18
 
19
19
  def initialize(python_requirement_parser:)
@@ -24,7 +24,7 @@ module Dependabot
24
24
  .map { |k| Regexp.quote(k) }.join("|")
25
25
  version_pattern = Python::Version::VERSION_PATTERN
26
26
 
27
- PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{version_pattern})\\s*".freeze
27
+ PATTERN_RAW = "\\s*(?<op>#{quoted})?\\s*(?<version>#{version_pattern})\\s*".freeze
28
28
  PATTERN = /\A#{PATTERN_RAW}\z/
29
29
  PARENS_PATTERN = /\A\(([^)]+)\)\z/
30
30
 
@@ -41,9 +41,9 @@ module Dependabot
41
41
  raise BadRequirementError, msg
42
42
  end
43
43
 
44
- return DefaultRequirement if matches[1] == ">=" && matches[2] == "0"
44
+ return DefaultRequirement if matches[:op] == ">=" && matches[:version] == "0"
45
45
 
46
- [matches[1] || "=", Python::Version.new(T.must(matches[2]))]
46
+ [matches[:op] || "=", Python::Version.new(T.must(matches[:version]))]
47
47
  end
48
48
 
49
49
  # Returns an array of requirements. At least one requirement from the
@@ -128,7 +128,8 @@ module Dependabot
128
128
  upper_bound = parts.map.with_index do |part, i|
129
129
  if i < first_non_zero_index then part
130
130
  elsif i == first_non_zero_index then (part.to_i + 1).to_s
131
- elsif i > first_non_zero_index && i == 2 then "0.a"
131
+ # .dev has lowest precedence: https://packaging.python.org/en/latest/specifications/version-specifiers/#summary-of-permitted-suffixes-and-relative-ordering
132
+ elsif i > first_non_zero_index && i == 2 then "0.dev"
132
133
  else
133
134
  0
134
135
  end
@@ -151,7 +152,7 @@ module Dependabot
151
152
  .first(req_string.split(".").index { |s| s.include?("*") } + 1)
152
153
  .join(".")
153
154
  .gsub(/\*(?!$)/, "0")
154
- .gsub(/\*$/, "0.a")
155
+ .gsub(/\*$/, "0.dev")
155
156
  .tap { |s| exact_op ? s.gsub!(/^(?<!!)=*/, "~>") : s }
156
157
  end
157
158
  end
@@ -159,10 +159,7 @@ module Dependabot
159
159
  end
160
160
 
161
161
  def wants_prerelease?
162
- if dependency.version
163
- version = version_class.new(dependency.version.tr("+", "."))
164
- return version.prerelease?
165
- end
162
+ return version_class.new(dependency.version).prerelease? if dependency.version
166
163
 
167
164
  dependency.requirements.any? do |req|
168
165
  reqs = (req.fetch(:requirement) || "").split(",").map(&:strip)
@@ -4,119 +4,282 @@
4
4
  require "dependabot/version"
5
5
  require "dependabot/utils"
6
6
 
7
- # Python versions can include a local version identifier, which Ruby can't
8
- # parse. This class augments Gem::Version with local version identifier info.
9
- # See https://www.python.org/dev/peps/pep-0440 for details.
7
+ # See https://packaging.python.org/en/latest/specifications/version-specifiers for spec details.
10
8
 
11
9
  module Dependabot
12
10
  module Python
13
11
  class Version < Dependabot::Version
12
+ sig { returns(Integer) }
14
13
  attr_reader :epoch
15
- attr_reader :local_version
16
- attr_reader :post_release_version
14
+
15
+ sig { returns(T::Array[Integer]) }
16
+ attr_reader :release_segment
17
+
18
+ sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
19
+ attr_reader :dev
20
+
21
+ sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
22
+ attr_reader :pre
23
+
24
+ sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
25
+ attr_reader :post
26
+
27
+ sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
28
+ attr_reader :local
29
+
30
+ INFINITY = 1000
31
+ NEGATIVE_INFINITY = -INFINITY
17
32
 
18
33
  # See https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
19
- VERSION_PATTERN = 'v?([1-9][0-9]*!)?[0-9]+[0-9a-zA-Z]*(?>\.[0-9a-zA-Z]+)*' \
20
- '(-[0-9A-Za-z]+(\.[0-9a-zA-Z]+)*)?' \
21
- '(\+[0-9a-zA-Z]+(\.[0-9a-zA-Z]+)*)?'
22
- ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/
34
+ VERSION_PATTERN = /
35
+ v?
36
+ (?:
37
+ (?:(?<epoch>[0-9]+)!)? # epoch
38
+ (?<release>[0-9]+(?:\.[0-9]+)*) # release
39
+ (?<pre> # prerelease
40
+ [-_\.]?
41
+ (?<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
42
+ [-_\.]?
43
+ (?<pre_n>[0-9]+)?
44
+ )?
45
+ (?<post> # post release
46
+ (?:-(?<post_n1>[0-9]+))
47
+ |
48
+ (?:
49
+ [-_\.]?
50
+ (?<post_l>post|rev|r)
51
+ [-_\.]?
52
+ (?<post_n2>[0-9]+)?
53
+ )
54
+ )?
55
+ (?<dev> # dev release
56
+ [-_\.]?
57
+ (?<dev_l>dev)
58
+ [-_\.]?
59
+ (?<dev_n>[0-9]+)?
60
+ )?
61
+ )
62
+ (?:\+(?<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
63
+ /ix
64
+
65
+ ANCHORED_VERSION_PATTERN = /\A\s*#{VERSION_PATTERN}\s*\z/
23
66
 
67
+ sig { override.params(version: VersionParameter).returns(T::Boolean) }
24
68
  def self.correct?(version)
25
69
  return false if version.nil?
26
70
 
27
71
  version.to_s.match?(ANCHORED_VERSION_PATTERN)
28
72
  end
29
73
 
74
+ sig { override.params(version: VersionParameter).void }
30
75
  def initialize(version)
76
+ raise Dependabot::BadRequirementError, "Malformed version string - string is nil" if version.nil?
77
+
31
78
  @version_string = version.to_s
32
- version, @local_version = @version_string.split("+")
33
- version ||= ""
34
- version = version.gsub(/^v/, "")
35
- if version.include?("!")
36
- @epoch, version = version.split("!")
37
- else
38
- @epoch = "0"
79
+
80
+ raise Dependabot::BadRequirementError, "Malformed version string - string is empty" if @version_string.empty?
81
+
82
+ matches = ANCHORED_VERSION_PATTERN.match(@version_string.downcase)
83
+
84
+ unless matches
85
+ raise Dependabot::BadRequirementError,
86
+ "Malformed version string - #{@version_string} does not match regex"
39
87
  end
40
- version = normalise_prerelease(version)
41
- version, @post_release_version = version.split(/\.r(?=\d)/)
42
- version ||= ""
43
- @local_version = normalise_prerelease(@local_version) if @local_version
44
- super
88
+
89
+ @epoch = matches["epoch"].to_i
90
+ @release_segment = matches["release"]&.split(".")&.map(&:to_i) || []
91
+ @pre = parse_letter_version(matches["pre_l"], matches["pre_n"])
92
+ @post = parse_letter_version(matches["post_l"], matches["post_n1"] || matches["post_n2"])
93
+ @dev = parse_letter_version(matches["dev_l"], matches["dev_n"])
94
+ @local = parse_local_version(matches["local"])
95
+ super(matches["release"] || "")
45
96
  end
46
97
 
98
+ sig { override.params(version: VersionParameter).returns(Dependabot::Python::Version) }
99
+ def self.new(version)
100
+ T.cast(super, Dependabot::Python::Version)
101
+ end
102
+
103
+ sig { returns(String) }
47
104
  def to_s
48
105
  @version_string
49
106
  end
50
107
 
108
+ sig { returns(String) }
51
109
  def inspect # :nodoc:
52
110
  "#<#{self.class} #{@version_string}>"
53
111
  end
54
112
 
113
+ sig { returns(T::Boolean) }
114
+ def prerelease?
115
+ !!(pre || dev)
116
+ end
117
+
118
+ sig { returns(Dependabot::Python::Version) }
119
+ def release
120
+ Dependabot::Python::Version.new(release_segment.join("."))
121
+ end
122
+
123
+ sig { params(other: VersionParameter).returns(Integer) }
55
124
  def <=>(other)
56
- other = Version.new(other.to_s) unless other.is_a?(Python::Version)
125
+ other = Dependabot::Python::Version.new(other.to_s) unless other.is_a?(Dependabot::Python::Version)
126
+ other = T.cast(other, Dependabot::Python::Version)
57
127
 
58
- epoch_comparison = epoch_comparison(other)
128
+ epoch_comparison = epoch <=> other.epoch
59
129
  return epoch_comparison unless epoch_comparison.zero?
60
130
 
61
- version_comparison = super
62
- return version_comparison unless version_comparison&.zero?
131
+ release_comparison = release_version_comparison(other)
132
+ return release_comparison unless release_comparison.zero?
63
133
 
64
- post_version_comparison = post_version_comparison(other)
65
- return post_version_comparison unless post_version_comparison.zero?
134
+ pre_comparison = compare_keys(pre_cmp_key, other.pre_cmp_key)
135
+ return pre_comparison unless pre_comparison.zero?
66
136
 
67
- local_version_comparison(other)
137
+ post_comparison = compare_keys(post_cmp_key, other.post_cmp_key)
138
+ return post_comparison unless post_comparison.zero?
139
+
140
+ dev_comparison = compare_keys(dev_cmp_key, other.dev_cmp_key)
141
+ return dev_comparison unless dev_comparison.zero?
142
+
143
+ compare_keys(local_cmp_key, other.local_cmp_key)
68
144
  end
69
145
 
70
- private
146
+ sig do
147
+ params(
148
+ key: T.any(Integer, T::Array[T.any(String, Integer)]),
149
+ other_key: T.any(Integer, T::Array[T.any(String, Integer)])
150
+ ).returns(Integer)
151
+ end
152
+ def compare_keys(key, other_key)
153
+ if key.is_a?(Integer) && other_key.is_a?(Integer)
154
+ key <=> other_key
155
+ elsif key.is_a?(Array) && other_key.is_a?(Array)
156
+ key <=> other_key
157
+ elsif key.is_a?(Integer)
158
+ key == NEGATIVE_INFINITY ? -1 : 1
159
+ elsif other_key.is_a?(Integer)
160
+ other_key == NEGATIVE_INFINITY ? 1 : -1
161
+ end
162
+ end
71
163
 
72
- def epoch_comparison(other)
73
- epoch.to_i <=> other.epoch.to_i
164
+ sig { returns(T.any(Integer, T::Array[T.any(String, Integer)])) }
165
+ def pre_cmp_key
166
+ if pre.nil? && post.nil? && dev # sort 1.0.dev0 before 1.0a0
167
+ NEGATIVE_INFINITY
168
+ elsif pre.nil?
169
+ INFINITY # versions without a pre-release should sort after those with one.
170
+ else
171
+ T.must(pre)
172
+ end
74
173
  end
75
174
 
76
- def post_version_comparison(other)
77
- unless other.post_release_version
78
- return post_release_version.nil? ? 0 : 1
175
+ sig { returns(T.any(Integer, T::Array[T.any(String, Integer)])) }
176
+ def local_cmp_key
177
+ if local.nil?
178
+ # Versions without a local segment should sort before those with one.
179
+ NEGATIVE_INFINITY
180
+ else
181
+ # According to PEP440.
182
+ # - Alphanumeric segments sort before numeric segments
183
+ # - Alphanumeric segments sort lexicographically
184
+ # - Numeric segments sort numerically
185
+ # - Shorter versions sort before longer versions when the prefixes match exactly
186
+ local&.map do |token|
187
+ if token.is_a?(Integer)
188
+ [token, ""]
189
+ else
190
+ [NEGATIVE_INFINITY, token]
191
+ end
192
+ end
79
193
  end
194
+ end
195
+
196
+ sig { returns(T.any(Integer, T::Array[T.any(String, Integer)])) }
197
+ def post_cmp_key
198
+ # Versions without a post segment should sort before those with one.
199
+ return NEGATIVE_INFINITY if post.nil?
200
+
201
+ T.must(post)
202
+ end
203
+
204
+ sig { returns(T.any(Integer, T::Array[T.any(String, Integer)])) }
205
+ def dev_cmp_key
206
+ # Versions without a dev segment should sort after those with one.
207
+ return INFINITY if dev.nil?
208
+
209
+ T.must(dev)
210
+ end
211
+
212
+ sig { returns(String) }
213
+ def lowest_prerelease_suffix
214
+ "dev0"
215
+ end
80
216
 
81
- return -1 if post_release_version.nil?
217
+ private
218
+
219
+ sig { params(other: Dependabot::Python::Version).returns(Integer) }
220
+ def release_version_comparison(other)
221
+ tokens, other_tokens = pad_for_comparison(release_segment, other.release_segment)
222
+ tokens <=> other_tokens
223
+ end
82
224
 
83
- post_release_version.to_i <=> other.post_release_version.to_i
225
+ sig do
226
+ params(
227
+ tokens: T::Array[Integer],
228
+ other_tokens: T::Array[Integer]
229
+ ).returns(T::Array[T::Array[Integer]])
84
230
  end
231
+ def pad_for_comparison(tokens, other_tokens)
232
+ tokens = tokens.dup
233
+ other_tokens = other_tokens.dup
85
234
 
86
- def local_version_comparison(other)
87
- # Local version comparison works differently in Python: `1.0.beta`
88
- # compares as greater than `1.0`. To accommodate, we make the
89
- # strings the same length before comparing.
90
- lhsegments = local_version.to_s.split(".").map(&:downcase)
91
- rhsegments = other.local_version.to_s.split(".").map(&:downcase)
92
- limit = [lhsegments.count, rhsegments.count].min
235
+ longer = [tokens, other_tokens].max_by(&:count)
236
+ shorter = [tokens, other_tokens].min_by(&:count)
93
237
 
94
- lhs = ["1", *lhsegments.first(limit)].join(".")
95
- rhs = ["1", *rhsegments.first(limit)].join(".")
238
+ difference = T.must(longer).length - T.must(shorter).length
239
+
240
+ difference.times { T.must(shorter) << 0 }
241
+
242
+ [tokens, other_tokens]
243
+ end
96
244
 
97
- local_comparison = Gem::Version.new(lhs) <=> Gem::Version.new(rhs)
245
+ sig { params(local: T.nilable(String)).returns(T.nilable(T::Array[T.any(String, Integer)])) }
246
+ def parse_local_version(local)
247
+ return if local.nil?
98
248
 
99
- return local_comparison unless local_comparison&.zero?
249
+ # Takes a string like abc.1.twelve and turns it into ["abc", 1, "twelve"]
250
+ local.split(/[\._-]/).map { |s| /^\d+$/.match?(s) ? s.to_i : s }
251
+ end
100
252
 
101
- lhsegments.count <=> rhsegments.count
253
+ sig do
254
+ params(
255
+ letter: T.nilable(String), number: T.nilable(String)
256
+ ).returns(T.nilable(T::Array[T.any(String, Integer)]))
102
257
  end
258
+ def parse_letter_version(letter = nil, number = nil)
259
+ return if letter.nil? && number.nil?
260
+
261
+ if letter
262
+ # Implicit 0 for cases where prerelease has no numeral
263
+ number ||= 0
264
+
265
+ # Normalize alternate spellings
266
+ if letter == "alpha"
267
+ letter = "a"
268
+ elsif letter == "beta"
269
+ letter = "b"
270
+ elsif %w(c pre preview).include? letter
271
+ letter = "rc"
272
+ elsif %w(rev r).include? letter
273
+ letter = "post"
274
+ end
275
+
276
+ return letter, number.to_i
277
+ end
278
+
279
+ # Number but no letter i.e. implicit post release syntax (e.g. 1.0-1)
280
+ letter = "post"
103
281
 
104
- def normalise_prerelease(version)
105
- # Python has reserved words for release states, which are treated
106
- # as equal (e.g., preview, pre and rc).
107
- # Further, Python treats dashes as a separator between version
108
- # parts and treats the alphabetical characters in strings as the
109
- # start of a new version part (so 1.1a2 == 1.1.alpha.2).
110
- version
111
- .gsub("alpha", "a")
112
- .gsub("beta", "b")
113
- .gsub("preview", "c")
114
- .gsub("pre", "c")
115
- .gsub("post", "r")
116
- .gsub("rev", "r")
117
- .gsub(/([\d.\-_])rc([\d.\-_])?/, '\1c\2')
118
- .tr("-", ".")
119
- .gsub(/(\d)([a-z])/i, '\1.\2')
282
+ [letter, number.to_i]
120
283
  end
121
284
  end
122
285
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-python
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.280.0
4
+ version: 0.282.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-10 00:00:00.000000000 Z
11
+ date: 2024-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.280.0
19
+ version: 0.282.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.280.0
26
+ version: 0.282.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -114,28 +114,28 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.65.0
117
+ version: 1.67.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.65.0
124
+ version: 1.67.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-performance
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.21.0
131
+ version: 1.22.1
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.21.0
138
+ version: 1.22.1
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop-rspec
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -288,8 +288,8 @@ licenses:
288
288
  - MIT
289
289
  metadata:
290
290
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
291
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.280.0
292
- post_install_message:
291
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.282.0
292
+ post_install_message:
293
293
  rdoc_options: []
294
294
  require_paths:
295
295
  - lib
@@ -305,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
305
305
  version: 3.1.0
306
306
  requirements: []
307
307
  rubygems_version: 3.5.9
308
- signing_key:
308
+ signing_key:
309
309
  specification_version: 4
310
310
  summary: Provides Dependabot support for Python
311
311
  test_files: []