dependabot-python 0.399.0 → 0.400.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: e243e407de697945437e9818b4a451ab39ecb274ea6281b9ddcd2270d1bd16e7
4
- data.tar.gz: 2ff42e6c9c205775d467942431d3c8aa51e2c4db9557b7bfbea733e2b201cfae
3
+ metadata.gz: ddc78c3d36f56fa3124806151a71bb16e46ccbd4fb002a814974c6d4b8fd2fad
4
+ data.tar.gz: b08192e8bc0a5b8c0125266571bd034029ed17e2c0f77a9d01350b7a9d30fca6
5
5
  SHA512:
6
- metadata.gz: '0297caeec2ee5d809878d232089fabb5015966cb703bf59f3fcbdd295ca87908be3bffbe447d9c32b79b2945796f4c7d2a985574643496fe45e69116fb77a7fc'
7
- data.tar.gz: 9f2c74c8fca0e487014943a033c030c67907c0f9135ae802bf4bd8d38dab8c876f18e0f05f98f7cae033906555ce0981c54b48671dd5d4d345e9b892576dda96
6
+ metadata.gz: 5062ffec97c3b221246787027d1afb91fc0da8aeba188cbf7be0f834448ec3ddf0d8ed25a5c7e18803bf986c8c0f6fea96cd4164ae6ecd81215fb4ffb0f75628
7
+ data.tar.gz: 932c74e3ca269747bcbd005fa0ac624d38a26bc60269953b7a8af99c03abf157b999b1d6ec5e30a64b7791a3c970aca267f964bb62dab880a083fb4021a8cbc9
@@ -129,7 +129,9 @@ module Dependabot
129
129
  end
130
130
 
131
131
  # When the primary is a compiled `.txt`, the `-r`/`-c` directives live in the paired `.in` files.
132
- referenced = referenced_requirement_files([primary] + paired)
132
+ # Constraints files join every layer below, so they are seeded here too: a constraints file
133
+ # that references siblings needs those siblings on disk for the layer to parse.
134
+ referenced = referenced_requirement_files([primary] + paired + constraints_files)
133
135
 
134
136
  support = (paired + referenced + constraints_files).uniq.map do |f|
135
137
  as_support_file(f)
@@ -0,0 +1,180 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "time"
6
+ require "uri"
7
+ require "cgi/escape"
8
+ require "nokogiri"
9
+ require "sorbet-runtime"
10
+ require "dependabot/errors"
11
+
12
+ module Dependabot
13
+ module Python
14
+ module Package
15
+ class Distribution < T::ImmutableStruct
16
+ extend T::Sig
17
+
18
+ ObjectHash = T.type_alias { T::Hash[String, Object] }
19
+
20
+ const :version_string, String
21
+ const :released_at, T.nilable(Time), default: nil
22
+ const :requires_python, T.nilable(String), default: nil
23
+ const :python_version, T.nilable(String), default: nil
24
+ const :yanked, T::Boolean, default: false
25
+ const :yanked_reason, T.nilable(String), default: nil
26
+ const :downloads, Integer, default: -1
27
+ const :url, T.nilable(String), default: nil
28
+ const :package_type, T.nilable(String), default: nil
29
+
30
+ sig { params(value: Object, version_string: String, context: String).returns(Distribution) }
31
+ def self.from_pypi(value, version_string:, context:)
32
+ fields = object(value, context)
33
+ new(
34
+ version_string: version_string,
35
+ released_at: timestamp(fields["upload_time"], "#{context}.upload_time"),
36
+ requires_python: optional_string(fields["requires_python"], "#{context}.requires_python"),
37
+ python_version: optional_string(fields["python_version"], "#{context}.python_version"),
38
+ yanked: boolean(fields["yanked"], "#{context}.yanked"),
39
+ yanked_reason: optional_string(fields["yanked_reason"], "#{context}.yanked_reason"),
40
+ downloads: downloads(fields["downloads"], "#{context}.downloads"),
41
+ url: optional_string(fields["url"], "#{context}.url"),
42
+ package_type: optional_string(fields["packagetype"], "#{context}.packagetype")
43
+ )
44
+ end
45
+
46
+ sig do
47
+ params(value: Object, version_string: String, context: String, project_url: String).returns(Distribution)
48
+ end
49
+ def self.from_simple(value, version_string:, context:, project_url:)
50
+ fields = object(value, context)
51
+ withdrawn = fields["yanked"]
52
+ yanked = withdrawn.is_a?(String) || boolean(withdrawn, "#{context}.yanked")
53
+ new(
54
+ version_string: version_string,
55
+ released_at: timestamp(fields["upload-time"], "#{context}.upload-time"),
56
+ requires_python: optional_string(fields["requires-python"], "#{context}.requires-python"),
57
+ yanked: yanked,
58
+ yanked_reason: withdrawn.is_a?(String) ? withdrawn : nil,
59
+ url: resolve_url(optional_string(fields["url"], "#{context}.url"), project_url, "#{context}.url")
60
+ )
61
+ end
62
+
63
+ sig do
64
+ params(
65
+ link: Nokogiri::XML::Node, version_string: String, context: String, project_url: String
66
+ ).returns(Distribution)
67
+ end
68
+ def self.from_html(link, version_string:, context:, project_url:)
69
+ requirement = optional_string(T.cast(link["data-requires-python"], Object), "#{context}.data-requires-python")
70
+ reason = optional_string(T.cast(link["data-yanked"], Object), "#{context}.data-yanked")
71
+ withdrawn = !T.cast(link.attribute("data-yanked"), Object).nil?
72
+ new(
73
+ version_string: version_string,
74
+ requires_python: requirement ? CGI.unescapeHTML(requirement) : nil,
75
+ yanked: withdrawn,
76
+ yanked_reason: reason,
77
+ url: resolve_url(
78
+ optional_string(T.cast(link["href"], Object), "#{context}.href"),
79
+ project_url,
80
+ "#{context}.href"
81
+ )
82
+ )
83
+ end
84
+
85
+ sig { params(format: String, source_url: String).returns(String) }
86
+ def self.context(format, source_url)
87
+ uri = URI.parse(source_url)
88
+ uri.userinfo = nil
89
+ uri.query = nil
90
+ uri.fragment = nil
91
+ "#{format} registry #{String(uri)}"
92
+ rescue URI::InvalidURIError
93
+ invalid(format, "registry URL is invalid")
94
+ end
95
+
96
+ sig { params(content: String, context: String).returns(Object) }
97
+ def self.parse_json(content, context)
98
+ T.cast(JSON.parse(content), Object)
99
+ rescue JSON::ParserError
100
+ invalid(context, "must contain valid JSON")
101
+ end
102
+
103
+ sig { params(value: Object, context: String).returns(ObjectHash) }
104
+ def self.object(value, context)
105
+ invalid(context, "must be an object") unless value.is_a?(Hash)
106
+
107
+ value.to_h do |raw_key, raw_value|
108
+ key = T.cast(raw_key, Object)
109
+ invalid(context, "keys must be strings") unless key.is_a?(String)
110
+
111
+ [key, T.cast(raw_value, Object)]
112
+ end
113
+ end
114
+
115
+ sig { params(value: Object, context: String).returns(T::Array[Object]) }
116
+ def self.array(value, context)
117
+ invalid(context, "must be an array") unless value.is_a?(Array)
118
+
119
+ value.map { |entry| T.cast(entry, Object) }
120
+ end
121
+
122
+ sig { params(value: Object, context: String).returns(T.nilable(String)) }
123
+ def self.optional_string(value, context)
124
+ return if value.nil?
125
+ return value if value.is_a?(String)
126
+
127
+ invalid(context, "must be a string or nil")
128
+ end
129
+
130
+ sig { params(context: String, message: String).returns(T.noreturn) }
131
+ def self.invalid(context, message)
132
+ raise DependencyFileNotResolvable.new("#{context} #{message}"), cause: nil
133
+ end
134
+
135
+ sig { params(value: Object, context: String).returns(T.nilable(Time)) }
136
+ def self.timestamp(value, context)
137
+ text = optional_string(value, context)
138
+ return if text.nil?
139
+
140
+ Time.parse(text)
141
+ rescue ArgumentError
142
+ invalid(context, "must be a valid timestamp")
143
+ end
144
+ private_class_method :timestamp
145
+
146
+ sig { params(value: Object, context: String).returns(T::Boolean) }
147
+ def self.boolean(value, context)
148
+ case value
149
+ when nil, false then false
150
+ when true then true
151
+ else invalid(context, "must be a boolean or nil")
152
+ end
153
+ end
154
+ private_class_method :boolean
155
+
156
+ sig { params(value: Object, context: String).returns(Integer) }
157
+ def self.downloads(value, context)
158
+ return -1 if value.nil?
159
+ return value if value.is_a?(Integer)
160
+
161
+ invalid(context, "must be an integer or nil")
162
+ end
163
+ private_class_method :downloads
164
+
165
+ sig { params(url: T.nilable(String), project_url: String, context: String).returns(T.nilable(String)) }
166
+ def self.resolve_url(url, project_url, context)
167
+ return if url.nil?
168
+
169
+ resolved = URI.join(project_url, url)
170
+ resolved.user = nil
171
+ resolved.password = nil
172
+ String(resolved)
173
+ rescue URI::InvalidURIError
174
+ invalid(context, "must be a valid URL")
175
+ end
176
+ private_class_method :resolve_url
177
+ end
178
+ end
179
+ end
180
+ end
@@ -1,8 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "json"
5
- require "time"
6
4
  require "cgi/escape"
7
5
  require "excon"
8
6
  require "nokogiri"
@@ -13,6 +11,8 @@ require "dependabot/package/package_release"
13
11
  require "dependabot/package/package_details"
14
12
  require "dependabot/python/package/package_registry_finder"
15
13
  require "dependabot/python/package/simple_api_parser"
14
+ require "dependabot/python/package/distribution"
15
+ require "dependabot/python/package/pypi_json_parser"
16
16
 
17
17
  # Stores metadata for a package, including all its available versions
18
18
  module Dependabot
@@ -111,7 +111,7 @@ module Dependabot
111
111
  "Fetching release information from simple registry at #{sanitized_url(index_url)} for #{dependency.name}"
112
112
  )
113
113
  response = registry_response_for_dependency(index_url, accept: simple_api_accept)
114
- project_url = response.path ? Excon::Utils.request_uri(response.data) : index_url + normalised_name + "/"
114
+ project_url = project_url_for(response, index_url)
115
115
  check_authentication_response(response, index_url)
116
116
 
117
117
  version_releases = if simple_json_response?(response)
@@ -120,14 +120,11 @@ module Dependabot
120
120
  project_url: project_url
121
121
  ).parse(response.body)
122
122
  else
123
- extract_release_details_json_from_html(response.body)
123
+ distributions_from_html(response.body, project_url: project_url)
124
124
  end
125
125
 
126
126
  format_version_releases(version_releases, preserve_distributions: simple_json_response?(response))
127
127
  .sort_by(&:version).reverse
128
- rescue JSON::ParserError
129
- Dependabot.logger.warn("JSON parsing error for #{sanitized_url(index_url)}.")
130
- []
131
128
  end
132
129
 
133
130
  # Example JSON Response Format:
@@ -190,16 +187,13 @@ module Dependabot
190
187
  return nil unless response.status == 200
191
188
 
192
189
  begin
193
- data = JSON.parse(response.body)
194
-
195
- version_releases = data["releases"]
190
+ version_releases = PypiJsonParser.new(source_url: json_url).parse(response.body)
196
191
 
197
192
  releases = format_version_releases(version_releases)
198
193
 
199
194
  releases.sort_by(&:version).reverse
200
- rescue JSON::ParserError
201
- Dependabot.logger.warn("JSON parsing error for #{json_url}. Falling back to HTML.")
202
- nil
195
+ rescue Dependabot::DependencyFileNotResolvable
196
+ raise
203
197
  rescue StandardError => e
204
198
  Dependabot.logger.warn("Unexpected error while fetching JSON data: #{e.message}.")
205
199
  nil
@@ -235,7 +229,9 @@ module Dependabot
235
229
  index_response = registry_response_for_dependency(index_url, accept: APPLICATION_TEXT)
236
230
  check_authentication_response(index_response, index_url)
237
231
 
238
- version_releases = extract_release_details_json_from_html(index_response.body)
232
+ version_releases = distributions_from_html(
233
+ index_response.body, project_url: project_url_for(index_response, index_url)
234
+ )
239
235
  releases = format_version_releases(version_releases)
240
236
 
241
237
  releases.sort_by(&:version).reverse
@@ -262,102 +258,64 @@ module Dependabot
262
258
  raise PrivateSourceAuthenticationFailure, sanitized_url(index_url)
263
259
  end
264
260
 
265
- sig do
266
- params(html_body: String)
267
- .returns(T::Hash[String, T::Array[T::Hash[String, T.untyped]]]) # Returns JSON-like format
261
+ sig { params(response: Excon::Response, index_url: String).returns(String) }
262
+ def project_url_for(response, index_url)
263
+ response.path ? Excon::Utils.request_uri(response.data) : index_url + normalised_name + "/"
268
264
  end
269
- def extract_release_details_json_from_html(html_body)
270
- doc = Nokogiri::HTML(html_body)
271
-
272
- releases = {}
273
265
 
274
- doc.css("a").each do |a_tag|
275
- details = version_details_from_link(a_tag.to_s)
276
- if details && details["version"]
277
- releases[details["version"]] ||= []
278
- releases[details["version"]] << details
279
- end
266
+ sig { params(html_body: String, project_url: String).returns(T::Hash[String, T::Array[Distribution]]) }
267
+ def distributions_from_html(html_body, project_url:)
268
+ doc = Nokogiri::HTML(html_body)
269
+ context = Distribution.context("HTML index", project_url)
270
+ releases = T.let({}, T::Hash[String, T::Array[Distribution]])
271
+
272
+ doc.css("a").each_with_index do |link, index|
273
+ filename = link.content
274
+ url = link["href"]
275
+ next unless filename.match?(name_regex) || url&.match?(name_regex)
276
+
277
+ version = get_version_from_filename(filename)
278
+ next unless version && version_class.correct?(version)
279
+
280
+ distribution = Distribution.from_html(
281
+ link, version_string: version, context: "#{context}.links[#{index}]", project_url: project_url
282
+ )
283
+ releases[version] ||= []
284
+ T.must(releases[version]) << distribution
280
285
  end
281
286
 
282
287
  releases
283
288
  end
284
289
 
285
- # rubocop:disable Metrics/PerceivedComplexity
286
- sig do
287
- params(link: T.nilable(String))
288
- .returns(T.nilable(T::Hash[String, T.untyped]))
289
- end
290
- def version_details_from_link(link)
291
- return unless link
292
-
293
- doc = Nokogiri::XML(link)
294
- filename = doc.at_css("a")&.content
295
- url = doc.at_css("a")&.attributes&.fetch("href", nil)&.value
296
-
297
- return unless filename&.match?(name_regex) || url&.match?(name_regex)
298
-
299
- version = get_version_from_filename(filename)
300
- return unless version_class.correct?(version)
301
-
302
- {
303
- "version" => version,
304
- "requires_python" => requires_python_from_link(link),
305
- "yanked" => link.include?("data-yanked"),
306
- "url" => link
307
- }
308
- end
309
- # rubocop:enable Metrics/PerceivedComplexity
310
-
311
290
  sig do
312
291
  params(
313
- releases_json: T.nilable(T::Hash[String, T::Array[T::Hash[String, T.untyped]]]),
292
+ distributions: T::Hash[String, T::Array[Distribution]],
314
293
  preserve_distributions: T::Boolean
315
294
  )
316
295
  .returns(T::Array[Dependabot::Package::PackageRelease])
317
296
  end
318
- def format_version_releases(releases_json, preserve_distributions: false)
319
- return [] unless releases_json
320
-
321
- releases_json.each_with_object([]) do |(version, release_data_array), versions|
322
- release_data_array = [release_data_array.last].compact unless preserve_distributions
323
- versions.concat(release_data_array.filter_map { |data| format_version_release(version, data) })
297
+ def format_version_releases(distributions, preserve_distributions: false)
298
+ distributions.each_value.flat_map do |files|
299
+ selected = preserve_distributions ? files : files.last(1)
300
+ selected.map { |distribution| format_version_release(distribution) }
324
301
  end
325
302
  end
326
303
 
327
- sig do
328
- params(
329
- version: String,
330
- release_data: T::Hash[String, T.untyped]
331
- )
332
- .returns(T.nilable(Dependabot::Package::PackageRelease))
333
- end
334
- def format_version_release(version, release_data)
335
- # Skip versions that don't conform to PEP 440
336
- unless Dependabot::Python::Version.correct?(version)
337
- Dependabot.logger.warn("Skipping invalid version #{version}: does not match PEP 440")
338
- return nil
339
- end
340
-
341
- upload_time = release_data["upload_time"]
342
- released_at = Time.parse(upload_time) if upload_time
343
- yanked = release_data["yanked"] || false
344
- yanked_reason = release_data["yanked_reason"]
345
- downloads = release_data["downloads"] || -1
346
- url = release_data["url"]
347
- package_type = release_data["packagetype"]
304
+ sig { params(distribution: Distribution).returns(Dependabot::Package::PackageRelease) }
305
+ def format_version_release(distribution)
348
306
  language = package_language(
349
- python_version: release_data["python_version"],
350
- requires_python: release_data["requires_python"]
307
+ python_version: distribution.python_version,
308
+ requires_python: distribution.requires_python
351
309
  )
352
310
 
353
311
  Dependabot::Package::PackageRelease.new(
354
- version: Dependabot::Python::Version.new(version),
355
- released_at: released_at,
356
- yanked: yanked,
357
- yanked_reason: yanked_reason,
358
- downloads: downloads,
359
- url: url,
360
- package_type: package_type,
312
+ version: Dependabot::Python::Version.new(distribution.version_string),
313
+ released_at: distribution.released_at,
314
+ yanked: distribution.yanked,
315
+ yanked_reason: distribution.yanked_reason,
316
+ downloads: distribution.downloads,
317
+ url: distribution.url,
318
+ package_type: distribution.package_type,
361
319
  language: language
362
320
  )
363
321
  end
@@ -472,18 +430,6 @@ module Dependabot
472
430
  nil
473
431
  end
474
432
 
475
- sig { params(link: String).returns(T.nilable(String)) }
476
- def requires_python_from_link(link)
477
- raw_value = Nokogiri::XML(link)
478
- .at_css("a")
479
- &.attribute("data-requires-python")
480
- &.content
481
-
482
- return nil unless raw_value
483
-
484
- CGI.unescapeHTML(raw_value) # Decodes HTML entities like &gt;=3 → >=3
485
- end
486
-
487
433
  sig { returns(T.class_of(Dependabot::Version)) }
488
434
  def version_class
489
435
  dependency.version_class
@@ -0,0 +1,48 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/python/version"
6
+ require "dependabot/python/package/distribution"
7
+
8
+ module Dependabot
9
+ module Python
10
+ module Package
11
+ class PypiJsonParser
12
+ extend T::Sig
13
+
14
+ sig { params(source_url: String).void }
15
+ def initialize(source_url:)
16
+ @context = T.let(Distribution.context("PyPI JSON", source_url), String)
17
+ end
18
+
19
+ sig { params(content: String).returns(T::Hash[String, T::Array[Distribution]]) }
20
+ def parse(content)
21
+ fields = Distribution.object(Distribution.parse_json(content, @context), @context)
22
+ raw_releases = fields["releases"]
23
+ return {} if raw_releases.nil?
24
+
25
+ releases = Distribution.object(raw_releases, "#{@context}.releases")
26
+ parsed = T.let({}, T::Hash[String, T::Array[Distribution]])
27
+ releases.each_with_index do |(version, value), release_index|
28
+ location = "#{@context}.releases[#{release_index}]"
29
+ entries = Distribution.array(value, location)
30
+ next if entries.empty?
31
+
32
+ unless Python::Version.correct?(version)
33
+ Dependabot.logger.warn("Skipping invalid version #{version}: does not match PEP 440")
34
+ next
35
+ end
36
+
37
+ parsed[version] = entries.each_with_index.map do |entry, index|
38
+ Distribution.from_pypi(
39
+ entry, version_string: version, context: "#{location}[#{index}]"
40
+ )
41
+ end
42
+ end
43
+ parsed
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,11 +1,10 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
- require "json"
5
- require "uri"
6
4
  require "sorbet-runtime"
7
5
  require "dependabot/errors"
8
6
  require "dependabot/python/name_normaliser"
7
+ require "dependabot/python/package/distribution"
9
8
 
10
9
  module Dependabot
11
10
  module Python
@@ -13,8 +12,6 @@ module Dependabot
13
12
  class SimpleApiParser
14
13
  extend T::Sig
15
14
 
16
- ReleaseDetail = T.type_alias { T::Hash[String, T.nilable(T.any(String, T::Boolean))] }
17
-
18
15
  sig { params(dependency: Dependabot::Dependency, project_url: String).void }
19
16
  def initialize(dependency:, project_url:)
20
17
  @dependency = dependency
@@ -23,31 +20,32 @@ module Dependabot
23
20
 
24
21
  sig do
25
22
  params(json_body: String)
26
- .returns(T::Hash[String, T::Array[ReleaseDetail]])
23
+ .returns(T::Hash[String, T::Array[Distribution]])
27
24
  end
28
25
  def parse(json_body)
29
- data = JSON.parse(json_body)
30
- validate_api_version!(data.dig("meta", "api-version").to_s)
31
-
32
- data.fetch("files", []).each_with_object({}) do |file, releases|
33
- filename = file["filename"]
26
+ context = Distribution.context("Simple API JSON", project_url)
27
+ data = Distribution.object(Distribution.parse_json(json_body, context), context)
28
+ meta = data["meta"]
29
+ metadata = meta.nil? ? {} : Distribution.object(meta, "#{context}.meta")
30
+ validate_api_version!(metadata.fetch("api-version", "1.0"), context)
31
+
32
+ releases = T.let({}, T::Hash[String, T::Array[Distribution]])
33
+ Distribution.array(data.fetch("files", []), "#{context}.files").each_with_index do |entry, index|
34
+ location = "#{context}.files[#{index}]"
35
+ file = Distribution.object(entry, location)
36
+ filename = Distribution.optional_string(file["filename"], "#{location}.filename")
34
37
  next unless filename&.match?(name_regex)
35
38
 
36
39
  version = version_from_filename(filename)
37
- next unless dependency.version_class.correct?(version)
40
+ next unless version && dependency.version_class.correct?(version)
38
41
 
39
- yanked = file["yanked"] || false
40
- details = {
41
- "version" => version,
42
- "requires_python" => file["requires-python"],
43
- "yanked" => yanked != false,
44
- "yanked_reason" => yanked.is_a?(String) ? yanked : nil,
45
- "upload_time" => file["upload-time"],
46
- "url" => resolve_url(file["url"])
47
- }
42
+ distribution = Distribution.from_simple(
43
+ file, version_string: version, context: location, project_url: project_url
44
+ )
48
45
  releases[version] ||= []
49
- releases[version] << details
46
+ T.must(releases[version]) << distribution
50
47
  end
48
+ releases
51
49
  end
52
50
 
53
51
  private
@@ -58,18 +56,11 @@ module Dependabot
58
56
  sig { returns(String) }
59
57
  attr_reader :project_url
60
58
 
61
- sig { params(url: T.nilable(String)).returns(T.nilable(String)) }
62
- def resolve_url(url)
63
- return unless url
64
-
65
- resolved_url = URI.join(project_url, url)
66
- resolved_url.user = nil
67
- resolved_url.password = nil
68
- resolved_url.to_s
69
- end
70
-
71
- sig { params(api_version: String).void }
72
- def validate_api_version!(api_version)
59
+ sig { params(api_version: Object, context: String).void }
60
+ def validate_api_version!(api_version, context)
61
+ unless api_version.is_a?(String) && api_version.match?(/\A[0-9]+\.[0-9]+\z/)
62
+ Distribution.invalid("#{context}.meta.api-version", "must be a Major.Minor string")
63
+ end
73
64
  return unless api_version.split(".").first.to_i > 1
74
65
 
75
66
  raise Dependabot::DependencyFileNotResolvable, "Unsupported PEP 691 API version: #{api_version}"
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.399.0
4
+ version: 0.400.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.399.0
18
+ version: 0.400.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.399.0
25
+ version: 0.400.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -305,8 +305,10 @@ files:
305
305
  - lib/dependabot/python/metadata_finder.rb
306
306
  - lib/dependabot/python/name_normaliser.rb
307
307
  - lib/dependabot/python/native_helpers.rb
308
+ - lib/dependabot/python/package/distribution.rb
308
309
  - lib/dependabot/python/package/package_details_fetcher.rb
309
310
  - lib/dependabot/python/package/package_registry_finder.rb
311
+ - lib/dependabot/python/package/pypi_json_parser.rb
310
312
  - lib/dependabot/python/package/simple_api_parser.rb
311
313
  - lib/dependabot/python/package_manager.rb
312
314
  - lib/dependabot/python/pip_compile_file_matcher.rb
@@ -329,7 +331,7 @@ licenses:
329
331
  - MIT
330
332
  metadata:
331
333
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
332
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.399.0
334
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.400.0
333
335
  rdoc_options: []
334
336
  require_paths:
335
337
  - lib