dependabot-python 0.370.0 → 0.371.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: 67c1d482dda68f38a7bbc7ea74f0d4cc206debd5c3f0704905911b05f04e4b2f
4
- data.tar.gz: bb39f9c0055c2ab9a86d8a2138676c69fbac55e52c45a7a261b7af5b94c28042
3
+ metadata.gz: e5c59beb6b677e51deac37d95023e448ad921265030b47910e4477249a07d1b4
4
+ data.tar.gz: 4c91924b433ac4f54c2f4f1bfd649e1124864b789cc459e4ab0aca281c02b603
5
5
  SHA512:
6
- metadata.gz: 9d0def98050153cafb8f4ce61c39495fd8b24f82f4ca8a4d62f158b86bfa9a695016520b92c4b54025d1df9a5c98be6eb5bba723e54846e3c449feee86d7fa28
7
- data.tar.gz: 715ae0908b35409adb0a67afb7aa5c6ca1cbb6036ae596719a8ef5afbe3b326571850a4b026820541e56c1ad70afd9a960cf7a796cf4a1b1986f2e4bb26531b6
6
+ metadata.gz: ec8aa99e69214eec367ee3dff6e9e4b6f2031f75cca5e7b674eaa41369c8f40e5af4b8ba86dce39420e7affc0316301bacfc0cf2c832902d3d3da22558971d19
7
+ data.tar.gz: 586dea07cef16ec324974e7983dfbe42314e4782bfb388194bb524dc78ccb8a3448de97b52867e20be55b5304f674ce3eec26ec6f5e6be30632e4b3e1ffdff34
@@ -69,7 +69,10 @@ module Dependabot
69
69
 
70
70
  groups = T.must(poetry_root)["group"] || {}
71
71
  groups.each do |group, group_spec|
72
- dependencies += parse_poetry_dependency_group(group, group_spec["dependencies"])
72
+ deps = group_spec["dependencies"]
73
+ next unless deps
74
+
75
+ dependencies += parse_poetry_dependency_group(group, deps)
73
76
  end
74
77
  dependencies
75
78
  end
@@ -33,6 +33,9 @@ module Dependabot
33
33
  prefix = T.must(prefix_match[:prefix])
34
34
  rest = T.must(entry[prefix.length..])
35
35
 
36
+ # Skip direct references (e.g. "pkg @ git+https://...") — already pinned to a URL
37
+ return entry if rest.match?(/\A\s*@\s/)
38
+
36
39
  # Extract the environment marker ("; ..." suffix) if present
37
40
  marker_match = rest.match(/(\s*;.*)/)
38
41
  marker = marker_match ? marker_match[1] : ""
@@ -57,9 +57,19 @@ module Dependabot
57
57
 
58
58
  LOCKFILE_NAME = "poetry.lock"
59
59
 
60
- SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
60
+ POETRY_V1 = "1"
61
+ POETRY_V2 = "2"
61
62
 
62
- DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
63
+ # Keep versions in ascending order
64
+ SUPPORTED_VERSIONS = T.let(
65
+ [
66
+ Version.new(POETRY_V1),
67
+ Version.new(POETRY_V2)
68
+ ].freeze,
69
+ T::Array[Dependabot::Version]
70
+ )
71
+
72
+ DEPRECATED_VERSIONS = T.let([Version.new(POETRY_V1)].freeze, T::Array[Dependabot::Version])
63
73
 
64
74
  sig do
65
75
  params(
@@ -68,25 +78,17 @@ module Dependabot
68
78
  ).void
69
79
  end
70
80
  def initialize(raw_version, requirement = nil)
81
+ version = Version.new(raw_version)
71
82
  super(
72
83
  name: NAME,
73
- version: Version.new(raw_version),
84
+ detected_version: Version.new(T.must(version.segments.first).to_s),
85
+ version: version,
74
86
  deprecated_versions: DEPRECATED_VERSIONS,
75
87
  supported_versions: SUPPORTED_VERSIONS,
76
88
  requirement: requirement,
77
89
  )
78
90
  end
79
91
 
80
- sig { override.returns(T::Boolean) }
81
- def deprecated?
82
- false
83
- end
84
-
85
- sig { override.returns(T::Boolean) }
86
- def unsupported?
87
- false
88
- end
89
-
90
92
  # Poetry supports requires-poetry constraints in pyproject.toml;
91
93
  # other Python package managers don't have an equivalent mechanism.
92
94
  sig { override.void }
@@ -26,6 +26,19 @@ module Dependabot
26
26
  DEPENDENCY_TYPES = T.let(%w(packages dev-packages).freeze, T::Array[String])
27
27
  MAX_FILE_SIZE = T.let(500_000, Integer)
28
28
 
29
+ # Regex patterns for detecting Python requirements.txt manifest variants.
30
+ # Ported from github/dependency-snapshots-api.
31
+ #
32
+ # Matches "requirements" preceded by a hyphen, period, underscore, start-of-string, or slash,
33
+ # followed by non-whitespace chars and ".txt".
34
+ # Examples: requirements.txt, requirements.prod.txt, requirements/production.txt
35
+ REQUIREMENTS_TXT_REGEX = T.let(%r{(?:[-._]|^|/)requirements[^\s]*\.txt$}i, Regexp)
36
+
37
+ # More lenient: matches "require" with optional prefix (no dots/whitespace)
38
+ # and optional hyphen/underscore/slash suffix. Does not match "require" as a substring.
39
+ # Examples: require.txt, require-test.txt, py3-require.txt, pyenv_require_e2e.txt
40
+ REQUIRE_TXT_REGEX = T.let(%r{[^\s|.]*require(?:[-_/][^\s|.]*)?\.txt$}i, Regexp)
41
+
29
42
  sig { abstract.returns(T::Array[String]) }
30
43
  def self.ecosystem_specific_required_files; end
31
44
 
@@ -169,7 +182,7 @@ module Dependabot
169
182
 
170
183
  repo_contents
171
184
  .select { |f| f.type == "file" }
172
- .select { |f| f.name.end_with?(".txt", ".in") }
185
+ .select { |f| potential_requirements_file?(f.name) }
173
186
  .reject { |f| f.size > MAX_FILE_SIZE }
174
187
  .map { |f| fetch_file_from_host(f.name) }
175
188
  .select { |f| requirements_file?(f) }
@@ -193,7 +206,7 @@ module Dependabot
193
206
 
194
207
  repo_contents(dir: relative_reqs_dir)
195
208
  .select { |f| f.type == "file" }
196
- .select { |f| f.name.end_with?(".txt", ".in") }
209
+ .select { |f| potential_requirements_file?(File.join(relative_reqs_dir, f.name)) }
197
210
  .reject { |f| f.size > MAX_FILE_SIZE }
198
211
  .map { |f| fetch_file_from_host("#{relative_reqs_dir}/#{f.name}") }
199
212
  .select { |f| requirements_file?(f) }
@@ -379,6 +392,24 @@ module Dependabot
379
392
  uneditable_reqs + editable_reqs
380
393
  end
381
394
 
395
+ # Checks if a filename matches known Python requirements.txt naming patterns.
396
+ sig { params(path: String).returns(T::Boolean) }
397
+ def requirements_txt_filename?(path)
398
+ path.match?(REQUIREMENTS_TXT_REGEX) || path.match?(REQUIRE_TXT_REGEX)
399
+ end
400
+
401
+ # When the feature flag is enabled, only considers .txt files whose names match
402
+ # requirements patterns (plus all .in files). When disabled, falls back to the
403
+ # original behavior of accepting any .txt or .in file.
404
+ sig { params(path: String).returns(T::Boolean) }
405
+ def potential_requirements_file?(path)
406
+ unless Dependabot::Experiments.enabled?(:python_requirements_file_name_filtering)
407
+ return path.end_with?(".txt", ".in")
408
+ end
409
+
410
+ path.end_with?(".in") || requirements_txt_filename?(path)
411
+ end
412
+
382
413
  sig { params(path: String).returns(String) }
383
414
  def clean_path(path)
384
415
  Pathname.new(path).cleanpath.to_path
@@ -267,24 +267,36 @@ module Dependabot
267
267
 
268
268
  sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
269
269
  def update_requirement(req)
270
- requirement_strings = req[:requirement].split(",").map(&:strip)
271
-
272
- new_requirement =
273
- if requirement_strings.any? { |r| r.match?(/^[=\d]/) }
274
- find_and_update_equality_match(requirement_strings)
275
- elsif requirement_strings.any? { |r| r.start_with?("~=") }
276
- tw_req = requirement_strings.find { |r| r.start_with?("~=") }
277
- bump_version(tw_req, latest_resolvable_version.to_s)
278
- elsif new_version_satisfies?(req)
279
- req.fetch(:requirement)
280
- else
281
- update_requirements_range(requirement_strings)
282
- end
270
+ new_requirement = updated_requirement_string(req)
283
271
  req.merge(requirement: new_requirement)
284
272
  rescue UnfixableRequirement
285
273
  req.merge(requirement: :unfixable)
286
274
  end
287
275
 
276
+ sig { params(req: T::Hash[Symbol, T.untyped]).returns(T.any(String, Symbol)) }
277
+ def updated_requirement_string(req)
278
+ requirement_strings = req[:requirement].split(",").map(&:strip)
279
+
280
+ if requirement_strings.any? { |r| r.match?(/^[=\d]/) }
281
+ find_and_update_equality_match(requirement_strings)
282
+ elsif requirement_strings.any? { |r| r.start_with?("~=") }
283
+ tw_req = requirement_strings.find { |r| r.start_with?("~=") }
284
+ bump_version(tw_req, latest_resolvable_version.to_s)
285
+ elsif bump_lower_bound?(requirement_strings)
286
+ bump_requirements_range(requirement_strings)
287
+ elsif new_version_satisfies?(req)
288
+ req.fetch(:requirement)
289
+ else
290
+ update_requirements_range(requirement_strings)
291
+ end
292
+ end
293
+
294
+ sig { params(requirement_strings: T::Array[String]).returns(T::Boolean) }
295
+ def bump_lower_bound?(requirement_strings)
296
+ update_strategy == RequirementsUpdateStrategy::BumpVersions &&
297
+ requirement_strings.any? { |r| r.strip.start_with?(">") }
298
+ end
299
+
288
300
  sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
289
301
  def widen_requirement(req)
290
302
  return req if new_version_satisfies?(req)
@@ -407,18 +407,22 @@ module Dependabot
407
407
 
408
408
  sig { returns(T::Boolean) }
409
409
  def check_pypi_for_library_match
410
- return false unless updating_pyproject? && library_details && !T.must(library_details)["name"].nil?
410
+ return false unless updating_pyproject?
411
411
 
412
- # If the project has a description in its pyproject.toml metadata, treat it as a
413
- # library when PyPI is unavailable or the package isn't published there yet.
414
- has_library_metadata = !T.must(library_details)["description"].nil?
412
+ library_details_temp = library_details
413
+ return false unless library_details_temp && !library_details_temp["name"].nil?
414
+
415
+ has_library_metadata = !library_details_temp["description"].nil?
415
416
 
416
417
  response = Dependabot::RegistryClient.get(
417
- url: "https://pypi.org/pypi/#{normalised_name(T.must(library_details)['name'])}/json/"
418
+ url: "https://pypi.org/pypi/#{normalised_name(library_details_temp['name'])}/json/"
418
419
  )
419
420
  return has_library_metadata unless response.status == 200
420
421
 
421
- (JSON.parse(response.body)["info"] || {})["summary"] == T.must(library_details)["description"]
422
+ local_description = library_details_temp["description"]
423
+ return true if local_description.nil?
424
+
425
+ (JSON.parse(response.body)["info"] || {})["summary"] == local_description
422
426
  rescue Excon::Error::Timeout, Excon::Error::Socket, URI::InvalidURIError
423
427
  has_library_metadata
424
428
  end
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.370.0
4
+ version: 0.371.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.370.0
18
+ version: 0.371.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.370.0
25
+ version: 0.371.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -322,7 +322,7 @@ licenses:
322
322
  - MIT
323
323
  metadata:
324
324
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
325
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.370.0
325
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.371.0
326
326
  rdoc_options: []
327
327
  require_paths:
328
328
  - lib