dependabot-python 0.395.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: 0a1dec50c1cd900eb433c984eb046d5a4b4e327c036d83c09e4d90ce1dd93572
4
- data.tar.gz: 608eb3b97ebcc5ee85f66fda06bb4f1f2407e244f3f582c333ec9cf604edd90e
3
+ metadata.gz: 888f4700108c651abbfd1604d6e2d87a13a836c1939d32617ee9be72a53c3967
4
+ data.tar.gz: afe0da2c49e3d9f141c14a2e513322ffd4629691c05ebaed078642d00d1f0b17
5
5
  SHA512:
6
- metadata.gz: 5b2de818a1e9b73a7b1af590c4f9bdf3c5ecf64d8bdd36e5043831e9d781f6fb829fe3282e0080e129595eb5adc49631c4d956bc1501dcd623fbeab8a8ba7b2a
7
- data.tar.gz: 90ae8a95010a4a414c1fdffd2d9ad371c3ff3418852191297d03699abadb62b5d7aa4b7ed9dae5e288bd246c7475f7ee29b8d7ed11f84b822b9efb2cc30ab903
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")
@@ -216,6 +216,37 @@ module Dependabot
216
216
  poetry_sources.find { |source| source.name == name }
217
217
  end
218
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
+
219
250
  sig { params(key: String).returns(T::Array[String]) }
220
251
  def workspace_globs(key)
221
252
  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
@@ -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
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.395.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.395.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.395.0
25
+ version: 0.396.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  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.395.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