dependabot-python 0.394.0 → 0.396.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: 0d1b1deb24d07d3b15f0c1cb2a434bc4014459ff9e52173a6b1aa1608bed9bef
4
- data.tar.gz: c2a82f5e34e3f06ecfd16ad0516aa925d7cea4d564b9436befaf50ea5eaeb05f
3
+ metadata.gz: 888f4700108c651abbfd1604d6e2d87a13a836c1939d32617ee9be72a53c3967
4
+ data.tar.gz: afe0da2c49e3d9f141c14a2e513322ffd4629691c05ebaed078642d00d1f0b17
5
5
  SHA512:
6
- metadata.gz: c6f557bb606f5cdd0105035e2569dfb80410716ae0b6eb514c46d92837f4677107e2f22c309dd90fcd983c0b4a0d23a8ef596036f242560670de569b90a01b43
7
- data.tar.gz: 7426a6a6748ef14ed637e82fa5757e5a11fc2c56fadb9e549b559a35e0bd831985978be092f6908068ae5cdd787d330ff95bc7e9b54dc0add588523a4a194d6d
6
+ metadata.gz: fe09edfd56b3d1ccc79bf494528e322bbfcff4bc9d2335265e01af41c5b23a925c22ac0f8fd915c8a73ba355ac9226752f438c63deb0ef6a79d977573169990f
7
+ data.tar.gz: 6cd05d5203c68ccc9a0e0230a1acf097425fe0ff451c8f43adecf887148bd7c06c20cdd8a350aa281cccd162ed1caa588078645a316c47d953f88fd75ce3e71b
@@ -393,7 +393,8 @@ module Dependabot
393
393
  dependency: nil,
394
394
  lockfile: pipfile_lock,
395
395
  language_version_manager: language_version_manager,
396
- dependency_files: dependency_files
396
+ dependency_files: dependency_files,
397
+ repo_contents_path: file_parser.repo_contents_path
397
398
  ),
398
399
  T.nilable(PipenvRunner)
399
400
  )
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "sorbet-runtime"
5
5
 
6
+ require "dependabot/errors"
6
7
  require "dependabot/python/file_parser"
7
8
 
8
9
  module Dependabot
@@ -27,6 +28,17 @@ module Dependabot
27
28
  end
28
29
  end
29
30
 
31
+ sig { params(result: Object).returns(T::Array[PepDependency]) }
32
+ def self.from_requirements_helper_result(result)
33
+ PyprojectValueParser.array(result, "parse_requirements result").each_with_index.map do |value, index|
34
+ from_object(value)
35
+ rescue TypeError => e
36
+ raise Dependabot::DependencyFileNotEvaluatable, "parse_requirements result[#{index}]: #{e.message}"
37
+ end
38
+ rescue TypeError => e
39
+ raise Dependabot::DependencyFileNotEvaluatable, e.message
40
+ end
41
+
30
42
  sig { params(value: Object).returns(PepDependency) }
31
43
  def self.from_object(value)
32
44
  hash = PyprojectValueParser.object_hash(value, "PEP dependency")
@@ -98,6 +98,11 @@ module Dependabot
98
98
  const :url, T.nilable(String), default: nil
99
99
  end
100
100
 
101
+ class ProjectMetadata < T::ImmutableStruct
102
+ const :name, T.nilable(String), default: nil
103
+ const :description, T.nilable(String), default: nil
104
+ end
105
+
101
106
  sig { params(data: PyprojectValueParser::ObjectHash).void }
102
107
  def initialize(data)
103
108
  @data = data
@@ -105,18 +110,42 @@ module Dependabot
105
110
 
106
111
  sig { params(file: Dependabot::DependencyFile).returns(PyprojectDocument) }
107
112
  def self.from_file(file)
108
- content = T.must(file.content)
109
- parsed = T.cast(TomlRB.parse(content), Object)
110
- new(PyprojectValueParser.object_hash(parsed, "pyproject.toml"))
113
+ from_content(T.must(file.content))
111
114
  rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
112
115
  raise Dependabot::DependencyFileNotParseable, file.path
113
116
  end
114
117
 
118
+ sig { params(content: String).returns(PyprojectDocument) }
119
+ def self.from_content(content)
120
+ parsed = T.cast(TomlRB.parse(content), Object)
121
+ new(PyprojectValueParser.object_hash(parsed, "pyproject.toml"))
122
+ end
123
+
115
124
  sig { returns(T::Boolean) }
116
125
  def poetry?
117
126
  !poetry_root.nil?
118
127
  end
119
128
 
129
+ sig { returns(T::Boolean) }
130
+ def project?
131
+ !section(@data, "project", "project").nil?
132
+ end
133
+
134
+ sig { returns(T.nilable(ProjectMetadata)) }
135
+ def poetry_metadata
136
+ metadata_from(poetry_root, "tool.poetry")
137
+ end
138
+
139
+ sig { returns(T.nilable(ProjectMetadata)) }
140
+ def project_metadata
141
+ metadata_from(section(@data, "project", "project"), "project")
142
+ end
143
+
144
+ sig { returns(T.nilable(ProjectMetadata)) }
145
+ def build_system_metadata
146
+ metadata_from(section(@data, "build-system", "build-system"), "build-system")
147
+ end
148
+
120
149
  sig { returns(T::Boolean) }
121
150
  def pep621?
122
151
  project = section(@data, "project", "project")
@@ -187,6 +216,37 @@ module Dependabot
187
216
  poetry_sources.find { |source| source.name == name }
188
217
  end
189
218
 
219
+ # A name pinned to one of these says nothing about what a package index holds. A git source
220
+ # carrying a tag is left alone: the tag gives an ordering, so such a pin can be updated from
221
+ # the remote instead of being skipped.
222
+ UNRESOLVABLE_UV_SOURCE_KEYS = %w(git url).freeze
223
+
224
+ sig { returns(T::Array[String]) }
225
+ def unresolvable_uv_source_names
226
+ tool = section(@data, "tool", "tool")
227
+ uv = tool && section(tool, "uv", "tool.uv")
228
+ sources = uv && section(uv, "sources", "tool.uv.sources")
229
+ return [] unless sources
230
+
231
+ sources.filter_map do |name, config|
232
+ # uv accepts either a single source or a list of them, each with its own markers.
233
+ entries = T.let(config.is_a?(Array) ? config : [config], T::Array[Object])
234
+ next unless entries.any? { |entry| unresolvable_uv_source_entry?(entry) }
235
+
236
+ name
237
+ end
238
+ end
239
+
240
+ sig { params(entry: Object).returns(T::Boolean) }
241
+ def unresolvable_uv_source_entry?(entry)
242
+ return false unless entry.is_a?(Hash)
243
+
244
+ keys = entry.keys
245
+ return false unless keys.intersect?(UNRESOLVABLE_UV_SOURCE_KEYS)
246
+
247
+ !(keys.include?("git") && keys.include?("tag"))
248
+ end
249
+
190
250
  sig { params(key: String).returns(T::Array[String]) }
191
251
  def workspace_globs(key)
192
252
  tool = section(@data, "tool", "tool")
@@ -200,6 +260,19 @@ module Dependabot
200
260
 
201
261
  private
202
262
 
263
+ sig do
264
+ params(data: T.nilable(PyprojectValueParser::ObjectHash), context: String)
265
+ .returns(T.nilable(ProjectMetadata))
266
+ end
267
+ def metadata_from(data, context)
268
+ return unless data
269
+
270
+ ProjectMetadata.new(
271
+ name: PyprojectValueParser.optional_string(data["name"], "#{context}.name"),
272
+ description: PyprojectValueParser.optional_string(data["description"], "#{context}.description")
273
+ )
274
+ end
275
+
203
276
  sig { returns(T.nilable(PyprojectValueParser::ObjectHash)) }
204
277
  def poetry_root
205
278
  tool = section(@data, "tool", "tool")
@@ -295,16 +295,16 @@ module Dependabot
295
295
  # probably blocked. Ignore it.
296
296
  next if blocking_marker?(dep)
297
297
 
298
- name = dep["name"]
299
- file = dep["file"]
300
- version = dep["version"]
298
+ name = dep.name
299
+ file = dep.file
300
+ version = dep.version
301
301
  original_file = get_original_file(file)
302
302
 
303
303
  requirements =
304
304
  if original_file && pip_compile_file_matcher.lockfile_for_pip_compile_file?(original_file) then []
305
305
  else
306
306
  [{
307
- requirement: dep["requirement"],
307
+ requirement: dep.requirement,
308
308
  file: Pathname.new(file).cleanpath.to_path,
309
309
  source: nil,
310
310
  groups: group_from_filename(file)
@@ -320,7 +320,7 @@ module Dependabot
320
320
  version: version&.include?("*") ? nil : version,
321
321
  requirements: requirements,
322
322
  package_manager: "pip",
323
- metadata: extras_metadata(dep["extras"])
323
+ metadata: extras_metadata(dep.extras)
324
324
  )
325
325
  end
326
326
  dependencies
@@ -342,36 +342,33 @@ module Dependabot
342
342
  end
343
343
  end
344
344
 
345
- sig { params(dep: T.untyped).returns(T::Boolean) }
345
+ sig { params(dep: PepDependency).returns(T::Boolean) }
346
346
  def blocking_marker?(dep)
347
- return false if dep["markers"] == "None"
347
+ marker = dep.markers
348
+ return false if marker.nil? || marker == "None"
348
349
 
349
- marker = dep["markers"]
350
350
  version = python_raw_version
351
351
 
352
352
  if marker.include?("python_version")
353
353
  !marker_satisfied?(marker, version)
354
354
  else
355
- return true if dep["markers"].include?("<")
356
- return false if dep["markers"].include?(">")
357
- return false if dep["requirement"].nil?
355
+ return true if marker.include?("<")
356
+ return false if marker.include?(">")
358
357
 
359
- dep["requirement"].include?("<")
358
+ dep.requirement&.include?("<") || false
360
359
  end
361
360
  end
362
361
 
363
- sig do
364
- params(marker: T.untyped, python_version: T.any(String, Integer, Gem::Version)).returns(T::Boolean)
365
- end
362
+ sig { params(marker: String, python_version: T.any(String, Integer, Gem::Version)).returns(T::Boolean) }
366
363
  def marker_satisfied?(marker, python_version)
367
364
  conditions = marker.split(/\s+(and|or)\s+/)
368
365
 
369
366
  # Explicitly define the type of result as T::Boolean
370
- result = T.let(evaluate_condition(conditions.shift, python_version), T::Boolean)
367
+ result = T.let(evaluate_condition(T.must(conditions.shift), python_version), T::Boolean)
371
368
 
372
369
  until conditions.empty?
373
370
  operator = conditions.shift
374
- next_condition = conditions.shift
371
+ next_condition = T.must(conditions.shift)
375
372
  next_result = evaluate_condition(next_condition, python_version)
376
373
 
377
374
  result = if operator == "and"
@@ -386,12 +383,13 @@ module Dependabot
386
383
 
387
384
  sig do
388
385
  params(
389
- condition: T.untyped,
386
+ condition: String,
390
387
  python_version: T.any(String, Integer, Gem::Version)
391
388
  ).returns(T::Boolean)
392
389
  end
393
390
  def evaluate_condition(condition, python_version)
394
391
  operator, version = condition.match(/([<>=!]=?)\s*"?([\d.]+)"?/)&.captures
392
+ return false unless version
395
393
 
396
394
  case operator
397
395
  when "<"
@@ -418,17 +416,18 @@ module Dependabot
418
416
  )
419
417
  end
420
418
 
421
- sig { returns(T.untyped) }
419
+ sig { returns(T::Array[PepDependency]) }
422
420
  def parsed_requirement_files
423
421
  SharedHelpers.in_a_temporary_directory do
424
422
  write_temporary_dependency_files
425
423
 
426
- requirements = SharedHelpers.run_helper_subprocess(
424
+ result = SharedHelpers.run_helper_subprocess(
427
425
  command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
428
426
  function: "parse_requirements",
429
427
  args: [Dir.pwd]
430
428
  )
431
429
 
430
+ requirements = PepDependency.from_requirements_helper_result(result)
432
431
  check_requirements(requirements)
433
432
  requirements
434
433
  end
@@ -439,12 +438,13 @@ module Dependabot
439
438
  raise Dependabot::DependencyFileNotEvaluatable, e.message
440
439
  end
441
440
 
442
- sig { params(requirements: T.untyped).returns(T.untyped) }
441
+ sig { params(requirements: T::Array[PepDependency]).void }
443
442
  def check_requirements(requirements)
444
443
  requirements.each do |dep|
445
- next unless dep["requirement"]
444
+ requirement = dep.requirement
445
+ next unless requirement
446
446
 
447
- Python::Requirement.new(dep["requirement"].split(","))
447
+ Python::Requirement.new(requirement.split(","))
448
448
  rescue Gem::Requirement::BadRequirementError => e
449
449
  raise Dependabot::DependencyFileNotEvaluatable, e.message
450
450
  end
@@ -17,7 +17,7 @@ require "dependabot/python/authed_url_builder"
17
17
  module Dependabot
18
18
  module Python
19
19
  class FileUpdater
20
- # rubocop:disable Metrics/ClassLength
20
+ # rubocop:disable-next Metrics/ClassLength
21
21
  class PipCompileFileUpdater
22
22
  extend T::Sig
23
23
 
@@ -466,6 +466,7 @@ module Dependabot
466
466
  end
467
467
 
468
468
  sig { params(name: String, version: String, algorithm: String).returns(T::Array[String]) }
469
+ # rubocop:disable-next Metrics/PerceivedComplexity
469
470
  def package_hashes_for(name:, version:, algorithm:)
470
471
  index_urls = @index_urls || [nil]
471
472
  hashes = []
@@ -477,12 +478,17 @@ module Dependabot
477
478
  args << index_url if index_url
478
479
 
479
480
  begin
481
+ helper_result = SharedHelpers.run_helper_subprocess(
482
+ command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
483
+ function: "get_dependency_hash",
484
+ args: args
485
+ )
486
+
487
+ # Skip this index if helper returned nil (can happen with unavailable registries)
488
+ next if helper_result.nil?
489
+
480
490
  native_helper_hashes = T.cast(
481
- SharedHelpers.run_helper_subprocess(
482
- command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
483
- function: "get_dependency_hash",
484
- args: args
485
- ),
491
+ helper_result,
486
492
  T::Array[T::Hash[String, String]]
487
493
  ).map { |h| "--hash=#{algorithm}:#{h['hash']}" }
488
494
 
@@ -494,9 +500,10 @@ module Dependabot
494
500
  end
495
501
  end
496
502
 
503
+ raise DependencyFileNotResolvable, "Unable to find hashes for package #{name}" if hashes.empty?
504
+
497
505
  hashes
498
506
  end
499
-
500
507
  sig { params(requirement_string: String).returns(T.nilable(String)) }
501
508
  def hash_separator(requirement_string)
502
509
  hash_regex = RequirementParser::HASH
@@ -807,7 +814,6 @@ module Dependabot
807
814
  dependency_files.select { |f| f.name.end_with?("setup.cfg") }
808
815
  end
809
816
  end
810
- # rubocop:enable Metrics/ClassLength
811
817
  end
812
818
  end
813
819
  end
@@ -16,15 +16,17 @@ module Dependabot
16
16
  dependency: T.nilable(Dependabot::Dependency),
17
17
  lockfile: T.nilable(Dependabot::DependencyFile),
18
18
  language_version_manager: LanguageVersionManager,
19
- dependency_files: T.nilable(T::Array[Dependabot::DependencyFile])
19
+ dependency_files: T.nilable(T::Array[Dependabot::DependencyFile]),
20
+ repo_contents_path: T.nilable(String)
20
21
  )
21
22
  .void
22
23
  end
23
- def initialize(dependency:, lockfile:, language_version_manager:, dependency_files: nil)
24
+ def initialize(dependency:, lockfile:, language_version_manager:, dependency_files: nil, repo_contents_path: nil)
24
25
  @dependency = dependency
25
26
  @lockfile = lockfile
26
27
  @language_version_manager = language_version_manager
27
28
  @dependency_files = dependency_files
29
+ @repo_contents_path = repo_contents_path
28
30
  end
29
31
 
30
32
  sig { params(constraint: T.nilable(String)).returns(String) }
@@ -53,7 +55,8 @@ module Dependabot
53
55
  # Called by Python::DependencyGrapher.
54
56
  sig { returns(String) }
55
57
  def run_pipenv_graph
56
- SharedHelpers.in_a_temporary_directory do
58
+ SharedHelpers.in_a_temporary_repo_directory(base_directory, repo_contents_path) do
59
+ File.write(".python-version", language_version_manager.python_major_minor)
57
60
  write_temporary_dependency_files
58
61
  language_version_manager.install_required_python
59
62
  run_command("pyenv exec pipenv sync --dev", fingerprint: "pyenv exec pipenv sync --dev")
@@ -85,6 +88,9 @@ module Dependabot
85
88
  sig { returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
86
89
  attr_reader :dependency_files
87
90
 
91
+ sig { returns(T.nilable(String)) }
92
+ attr_reader :repo_contents_path
93
+
88
94
  sig { returns(Dependabot::Dependency) }
89
95
  def current_dependency
90
96
  T.must(dependency)
@@ -101,6 +107,11 @@ module Dependabot
101
107
  end
102
108
  end
103
109
 
110
+ sig { returns(String) }
111
+ def base_directory
112
+ dependency_files&.first&.directory || "/"
113
+ end
114
+
104
115
  sig { returns(String) }
105
116
  def extras_specification
106
117
  extras = dependency_extras
@@ -19,7 +19,7 @@ module Dependabot
19
19
  class UpdateChecker
20
20
  # This resolver intentionally co-locates resolution, marker handling, and
21
21
  # constraints matching to keep compatibility decisions in one place.
22
- # rubocop:disable Metrics/ClassLength
22
+ # rubocop:disable-next Metrics/ClassLength
23
23
  class PipVersionResolver
24
24
  extend T::Sig
25
25
 
@@ -575,7 +575,6 @@ module Dependabot
575
575
  T.must(@pyproject_content_cache[pyproject.name])
576
576
  end
577
577
  end
578
- # rubocop:enable Metrics/ClassLength
579
578
  end
580
579
  end
581
580
  end
@@ -12,7 +12,7 @@ require "dependabot/requirements_update_strategy"
12
12
  module Dependabot
13
13
  module Python
14
14
  class UpdateChecker
15
- # rubocop:disable Metrics/ClassLength
15
+ # rubocop:disable-next Metrics/ClassLength
16
16
  class RequirementsUpdater
17
17
  extend T::Sig
18
18
 
@@ -358,7 +358,7 @@ module Dependabot
358
358
  new_segments
359
359
  .first(count)
360
360
  .map.with_index { |s, i| i < precision ? s : "*" }
361
- .join(".")
361
+ .join(".")
362
362
  end
363
363
 
364
364
  sig { params(requirement_strings: T::Array[String]).returns(String) }
@@ -542,7 +542,6 @@ module Dependabot
542
542
  Python::Requirement
543
543
  end
544
544
  end
545
- # rubocop:enable Metrics/ClassLength
546
545
  end
547
546
  end
548
547
  end
@@ -2,12 +2,13 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
- require "toml-rb"
5
+ require "json"
6
6
  require "sorbet-runtime"
7
7
 
8
8
  require "dependabot/dependency"
9
9
  require "dependabot/dependency_requirement"
10
10
  require "dependabot/errors"
11
+ require "dependabot/python/file_parser"
11
12
  require "dependabot/python/name_normaliser"
12
13
  require "dependabot/python/requirement_parser"
13
14
  require "dependabot/python/requirement"
@@ -18,7 +19,7 @@ require "dependabot/update_checkers/base"
18
19
 
19
20
  module Dependabot
20
21
  module Python
21
- # rubocop:disable Metrics/ClassLength
22
+ # rubocop:disable-next Metrics/ClassLength
22
23
  class UpdateChecker < Dependabot::UpdateCheckers::Base
23
24
  extend T::Sig
24
25
 
@@ -29,6 +30,8 @@ module Dependabot
29
30
  require_relative "update_checker/requirements_updater"
30
31
  require_relative "update_checker/latest_version_finder"
31
32
 
33
+ PyprojectDocument = FileParser::PyprojectDocument
34
+
32
35
  MAIN_PYPI_INDEXES = %w(
33
36
  https://pypi.python.org/simple/
34
37
  https://pypi.org/simple/
@@ -248,7 +251,7 @@ module Dependabot
248
251
  # For hybrid projects with both [tool.poetry] and [project] sections but no lockfile,
249
252
  # use the requirements resolver to handle PEP 621 dependencies
250
253
  # For pure Poetry projects, use Poetry resolver even without lockfile
251
- return :poetry if poetry_based? && (poetry_lock || !standard_details)
254
+ return :poetry if poetry_based? && (poetry_lock || !pyproject_document.project?)
252
255
 
253
256
  :requirements
254
257
  end
@@ -395,7 +398,7 @@ module Dependabot
395
398
 
396
399
  sig { returns(T::Boolean) }
397
400
  def poetry_based?
398
- updating_pyproject? && !poetry_details.nil?
401
+ updating_pyproject? && pyproject_document.poetry?
399
402
  end
400
403
 
401
404
  sig { returns(T::Boolean) }
@@ -410,22 +413,41 @@ module Dependabot
410
413
  def check_pypi_for_library_match
411
414
  return false unless updating_pyproject?
412
415
 
413
- library_details_temp = library_details
414
- return false unless library_details_temp && !library_details_temp["name"].nil?
416
+ metadata = library_details
417
+ name = metadata&.name
418
+ return false unless name
415
419
 
416
- has_library_metadata = !library_details_temp["description"].nil?
420
+ local_description = metadata.description
421
+ has_library_metadata = !local_description.nil?
417
422
 
418
- response = Dependabot::RegistryClient.get(
419
- url: "https://pypi.org/pypi/#{normalised_name(library_details_temp['name'])}/json/"
420
- )
421
- return has_library_metadata unless response.status == 200
423
+ begin
424
+ response = Dependabot::RegistryClient.get(
425
+ url: "https://pypi.org/pypi/#{normalised_name(name)}/json/"
426
+ )
427
+ return has_library_metadata unless response.status == 200
422
428
 
423
- local_description = library_details_temp["description"]
424
- return true if local_description.nil?
429
+ return true if local_description.nil?
425
430
 
426
- (JSON.parse(response.body)["info"] || {})["summary"] == local_description
427
- rescue Excon::Error::Timeout, Excon::Error::Socket, URI::InvalidURIError
428
- has_library_metadata
431
+ pypi_summary(response.body) == local_description
432
+ rescue Excon::Error::Timeout, Excon::Error::Socket, URI::InvalidURIError
433
+ has_library_metadata
434
+ end
435
+ end
436
+
437
+ sig { params(body: String).returns(T.nilable(String)) }
438
+ def pypi_summary(body)
439
+ metadata = T.cast(JSON.parse(body), Object)
440
+ raise TypeError, "PyPI metadata must be an object" unless metadata.is_a?(Hash)
441
+
442
+ info = T.cast(metadata["info"], Object)
443
+ return if info.nil?
444
+ raise TypeError, "PyPI info must be an object" unless info.is_a?(Hash)
445
+
446
+ summary = T.cast(info["summary"], Object)
447
+ return if summary.nil?
448
+ return summary if summary.is_a?(String)
449
+
450
+ raise TypeError, "PyPI info.summary must be a string"
429
451
  end
430
452
 
431
453
  sig { returns(T::Boolean) }
@@ -483,43 +505,21 @@ module Dependabot
483
505
  dependency_files.find { |f| f.name == "poetry.lock" }
484
506
  end
485
507
 
486
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
508
+ sig { returns(T.nilable(PyprojectDocument::ProjectMetadata)) }
487
509
  def library_details
488
510
  @library_details ||= T.let(
489
- poetry_details || standard_details || build_system_details,
490
- T.nilable(T::Hash[String, T.untyped])
491
- )
492
- end
493
-
494
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
495
- def poetry_details
496
- @poetry_details ||= T.let(
497
- toml_content.dig("tool", "poetry"),
498
- T.nilable(T::Hash[String, T.untyped])
499
- )
500
- end
501
-
502
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
503
- def standard_details
504
- @standard_details ||= T.let(
505
- toml_content["project"],
506
- T.nilable(T::Hash[String, T.untyped])
507
- )
508
- end
509
-
510
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
511
- def build_system_details
512
- @build_system_details ||= T.let(
513
- toml_content["build-system"],
514
- T.nilable(T::Hash[String, T.untyped])
511
+ pyproject_document.poetry_metadata ||
512
+ pyproject_document.project_metadata ||
513
+ pyproject_document.build_system_metadata,
514
+ T.nilable(PyprojectDocument::ProjectMetadata)
515
515
  )
516
516
  end
517
517
 
518
- sig { returns(T::Hash[String, T.untyped]) }
519
- def toml_content
520
- @toml_content ||= T.let(
521
- TomlRB.parse(T.must(pyproject).content),
522
- T.nilable(T::Hash[String, T.untyped])
518
+ sig { returns(PyprojectDocument) }
519
+ def pyproject_document
520
+ @pyproject_document ||= T.let(
521
+ PyprojectDocument.from_content(T.must(T.must(pyproject).content)),
522
+ T.nilable(PyprojectDocument)
523
523
  )
524
524
  end
525
525
 
@@ -528,7 +528,6 @@ module Dependabot
528
528
  dependency_files.select { |f| f.name.end_with?(".in") }
529
529
  end
530
530
  end
531
- # rubocop:enable Metrics/ClassLength
532
531
  end
533
532
  end
534
533
 
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.394.0
4
+ version: 0.396.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.394.0
18
+ version: 0.396.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.394.0
25
+ version: 0.396.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -178,19 +178,19 @@ dependencies:
178
178
  - !ruby/object:Gem::Version
179
179
  version: '1.1'
180
180
  - !ruby/object:Gem::Dependency
181
- name: turbo_tests
181
+ name: turbo_tests2
182
182
  requirement: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: 2.2.5
186
+ version: 3.2.7
187
187
  type: :development
188
188
  prerelease: false
189
189
  version_requirements: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: 2.2.5
193
+ version: 3.2.7
194
194
  - !ruby/object:Gem::Dependency
195
195
  name: vcr
196
196
  requirement: !ruby/object:Gem::Requirement
@@ -327,7 +327,7 @@ licenses:
327
327
  - MIT
328
328
  metadata:
329
329
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
330
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.394.0
330
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.396.0
331
331
  rdoc_options: []
332
332
  require_paths:
333
333
  - lib