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 +4 -4
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +4 -1
- data/lib/dependabot/python/file_updater/pyproject_preparer.rb +3 -0
- data/lib/dependabot/python/package_manager.rb +15 -13
- data/lib/dependabot/python/shared_file_fetcher.rb +33 -2
- data/lib/dependabot/python/update_checker/requirements_updater.rb +25 -13
- data/lib/dependabot/python/update_checker.rb +10 -6
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5c59beb6b677e51deac37d95023e448ad921265030b47910e4477249a07d1b4
|
|
4
|
+
data.tar.gz: 4c91924b433ac4f54c2f4f1bfd649e1124864b789cc459e4ab0aca281c02b603
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
60
|
+
POETRY_V1 = "1"
|
|
61
|
+
POETRY_V2 = "2"
|
|
61
62
|
|
|
62
|
-
|
|
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
|
-
|
|
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
|
|
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|
|
|
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
|
-
|
|
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?
|
|
410
|
+
return false unless updating_pyproject?
|
|
411
411
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|