dependabot-python 0.215.0 → 0.216.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/helpers/build +5 -5
- data/helpers/build_for_version +21 -0
- data/helpers/requirements.txt +4 -5
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +25 -15
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +16 -43
- data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +19 -59
- data/lib/dependabot/python/file_updater/pipfile_preparer.rb +17 -1
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +39 -34
- data/lib/dependabot/python/language_version_manager.rb +115 -0
- data/lib/dependabot/python/python_versions.rb +6 -6
- data/lib/dependabot/python/requirement_parser.rb +1 -1
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +16 -44
- data/lib/dependabot/python/update_checker/pip_version_resolver.rb +14 -40
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +23 -58
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +46 -44
- data/lib/dependabot/python/update_checker/requirements_updater.rb +25 -6
- data/lib/dependabot/python/update_checker.rb +21 -48
- data/lib/dependabot/python/version.rb +2 -2
- metadata +37 -33
- data/lib/dependabot/python/helpers.rb +0 -37
@@ -4,7 +4,7 @@ module Dependabot
|
|
4
4
|
module Python
|
5
5
|
module PythonVersions
|
6
6
|
PRE_INSTALLED_PYTHON_VERSIONS = %w(
|
7
|
-
3.11.
|
7
|
+
3.11.3
|
8
8
|
).freeze
|
9
9
|
|
10
10
|
# Due to an OpenSSL issue we can only install the following versions in
|
@@ -13,11 +13,11 @@ module Dependabot
|
|
13
13
|
#
|
14
14
|
# WARNING: 3.9.3 is purposefully omitted as it was recalled: https://www.python.org/downloads/release/python-393/
|
15
15
|
SUPPORTED_VERSIONS = %w(
|
16
|
-
3.11.0
|
17
|
-
3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
18
|
-
3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.2 3.9.1 3.9.0
|
19
|
-
3.8.15 3.8.14 3.8.13 3.8.12 3.8.11 3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 3.8.2 3.8.1 3.8.0
|
20
|
-
3.7.15 3.7.14 3.7.13 3.7.12 3.7.11 3.7.10 3.7.9 3.7.8 3.7.7 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0
|
16
|
+
3.11.3 3.11.2 3.11.1 3.11.0
|
17
|
+
3.10.11 3.10.10 3.10.9 3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
18
|
+
3.9.16 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.2 3.9.1 3.9.0
|
19
|
+
3.8.16 3.8.15 3.8.14 3.8.13 3.8.12 3.8.11 3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 3.8.2 3.8.1 3.8.0
|
20
|
+
3.7.16 3.7.15 3.7.14 3.7.13 3.7.12 3.7.11 3.7.10 3.7.9 3.7.8 3.7.7 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0
|
21
21
|
3.6.15 3.6.14 3.6.13 3.6.12 3.6.11 3.6.10 3.6.9 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.6.0
|
22
22
|
3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
|
23
23
|
).freeze
|
@@ -9,7 +9,7 @@ module Dependabot
|
|
9
9
|
VERSION = /([1-9][0-9]*!)?[0-9]+[a-zA-Z0-9\-_.*]*(\+[0-9a-zA-Z]+(\.[0-9a-zA-Z]+)*)?/
|
10
10
|
|
11
11
|
REQUIREMENT = /(?<comparison>#{COMPARISON})\s*\\?\s*(?<version>#{VERSION})/
|
12
|
-
HASH = /--hash=(?<algorithm>.*?):(?<hash>.*?)(?=\s
|
12
|
+
HASH = /--hash=(?<algorithm>.*?):(?<hash>.*?)(?=\s|\\|$)/
|
13
13
|
REQUIREMENTS = /#{REQUIREMENT}(\s*,\s*\\?\s*#{REQUIREMENT})*/
|
14
14
|
HASHES = /#{HASH}(\s*\\?\s*#{HASH})*/
|
15
15
|
MARKER_OP = /\s*(#{COMPARISON}|(\s*in)|(\s*not\s*in))/
|
@@ -11,7 +11,7 @@ require "dependabot/python/file_updater/requirement_replacer"
|
|
11
11
|
require "dependabot/python/file_updater/setup_file_sanitizer"
|
12
12
|
require "dependabot/python/version"
|
13
13
|
require "dependabot/shared_helpers"
|
14
|
-
require "dependabot/python/
|
14
|
+
require "dependabot/python/language_version_manager"
|
15
15
|
require "dependabot/python/native_helpers"
|
16
16
|
require "dependabot/python/python_versions"
|
17
17
|
require "dependabot/python/name_normaliser"
|
@@ -71,7 +71,7 @@ module Dependabot
|
|
71
71
|
SharedHelpers.in_a_temporary_directory do
|
72
72
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
73
73
|
write_temporary_dependency_files(updated_req: requirement)
|
74
|
-
|
74
|
+
language_version_manager.install_required_python
|
75
75
|
|
76
76
|
filenames_to_compile.each do |filename|
|
77
77
|
# Shell out to pip-compile.
|
@@ -173,6 +173,10 @@ module Dependabot
|
|
173
173
|
raise GitDependenciesNotReachable, url
|
174
174
|
end
|
175
175
|
|
176
|
+
raise Dependabot::OutOfDisk if error.message.end_with?("[Errno 28] No space left on device")
|
177
|
+
|
178
|
+
raise Dependabot::OutOfMemory if error.message.end_with?("MemoryError")
|
179
|
+
|
176
180
|
raise
|
177
181
|
end
|
178
182
|
# rubocop:enable Metrics/AbcSize
|
@@ -233,7 +237,7 @@ module Dependabot
|
|
233
237
|
end
|
234
238
|
|
235
239
|
def new_resolver_supported?
|
236
|
-
python_version >= Python::Version.new("3.7")
|
240
|
+
language_version_manager.python_version >= Python::Version.new("3.7")
|
237
241
|
end
|
238
242
|
|
239
243
|
def pip_compile_options_fingerprint(options)
|
@@ -275,7 +279,7 @@ module Dependabot
|
|
275
279
|
|
276
280
|
def run_pip_compile_command(command, fingerprint:)
|
277
281
|
run_command(
|
278
|
-
"pyenv local #{
|
282
|
+
"pyenv local #{language_version_manager.python_major_minor}",
|
279
283
|
fingerprint: "pyenv local <python_major_minor>"
|
280
284
|
)
|
281
285
|
|
@@ -322,7 +326,7 @@ module Dependabot
|
|
322
326
|
end
|
323
327
|
|
324
328
|
# Overwrite the .python-version with updated content
|
325
|
-
File.write(".python-version",
|
329
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
326
330
|
|
327
331
|
setup_files.each do |file|
|
328
332
|
path = file.name
|
@@ -434,9 +438,9 @@ module Dependabot
|
|
434
438
|
while (remaining_filenames = filenames - ordered_filenames).any?
|
435
439
|
ordered_filenames +=
|
436
440
|
remaining_filenames.
|
437
|
-
|
441
|
+
reject do |fn|
|
438
442
|
unupdated_reqs = requirement_map[fn] - ordered_filenames
|
439
|
-
(
|
443
|
+
unupdated_reqs.intersect?(filenames)
|
440
444
|
end
|
441
445
|
end
|
442
446
|
|
@@ -479,41 +483,6 @@ module Dependabot
|
|
479
483
|
).parse.find { |d| d.name == dependency.name }&.version
|
480
484
|
end
|
481
485
|
|
482
|
-
def python_version
|
483
|
-
@python_version ||=
|
484
|
-
user_specified_python_version ||
|
485
|
-
python_version_matching_imputed_requirements ||
|
486
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
487
|
-
end
|
488
|
-
|
489
|
-
def user_specified_python_version
|
490
|
-
return unless python_requirement_parser.user_specified_requirements.any?
|
491
|
-
|
492
|
-
user_specified_requirements =
|
493
|
-
python_requirement_parser.user_specified_requirements.
|
494
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
495
|
-
python_version_matching(user_specified_requirements)
|
496
|
-
end
|
497
|
-
|
498
|
-
def python_version_matching_imputed_requirements
|
499
|
-
compiled_file_python_requirement_markers =
|
500
|
-
python_requirement_parser.imputed_requirements.map do |r|
|
501
|
-
Dependabot::Python::Requirement.new(r)
|
502
|
-
end
|
503
|
-
python_version_matching(compiled_file_python_requirement_markers)
|
504
|
-
end
|
505
|
-
|
506
|
-
def python_version_matching(requirements)
|
507
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
508
|
-
version = Python::Version.new(version_string)
|
509
|
-
requirements.all? do |req|
|
510
|
-
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
511
|
-
|
512
|
-
req.satisfied_by?(version)
|
513
|
-
end
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
486
|
def python_requirement_parser
|
518
487
|
@python_requirement_parser ||=
|
519
488
|
FileParser::PythonRequirementParser.new(
|
@@ -521,8 +490,11 @@ module Dependabot
|
|
521
490
|
)
|
522
491
|
end
|
523
492
|
|
524
|
-
def
|
525
|
-
|
493
|
+
def language_version_manager
|
494
|
+
@language_version_manager ||=
|
495
|
+
LanguageVersionManager.new(
|
496
|
+
python_requirement_parser: python_requirement_parser
|
497
|
+
)
|
526
498
|
end
|
527
499
|
|
528
500
|
def setup_files
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "dependabot/python/language_version_manager"
|
3
4
|
require "dependabot/python/update_checker"
|
4
5
|
require "dependabot/python/update_checker/latest_version_finder"
|
5
6
|
require "dependabot/python/file_parser/python_requirement_parser"
|
@@ -20,17 +21,17 @@ module Dependabot
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def latest_resolvable_version
|
23
|
-
latest_version_finder.latest_version(python_version: python_version)
|
24
|
+
latest_version_finder.latest_version(python_version: language_version_manager.python_version)
|
24
25
|
end
|
25
26
|
|
26
27
|
def latest_resolvable_version_with_no_unlock
|
27
28
|
latest_version_finder.
|
28
|
-
latest_version_with_no_unlock(python_version: python_version)
|
29
|
+
latest_version_with_no_unlock(python_version: language_version_manager.python_version)
|
29
30
|
end
|
30
31
|
|
31
32
|
def lowest_resolvable_security_fix_version
|
32
33
|
latest_version_finder.
|
33
|
-
lowest_security_fix_version(python_version: python_version)
|
34
|
+
lowest_security_fix_version(python_version: language_version_manager.python_version)
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
@@ -49,45 +50,18 @@ module Dependabot
|
|
49
50
|
)
|
50
51
|
end
|
51
52
|
|
52
|
-
def python_version
|
53
|
-
@python_version ||=
|
54
|
-
user_specified_python_version ||
|
55
|
-
python_version_matching_imputed_requirements ||
|
56
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
57
|
-
end
|
58
|
-
|
59
|
-
def user_specified_python_version
|
60
|
-
return unless python_requirement_parser.user_specified_requirements.any?
|
61
|
-
|
62
|
-
user_specified_requirements =
|
63
|
-
python_requirement_parser.user_specified_requirements.
|
64
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
65
|
-
python_version_matching(user_specified_requirements)
|
66
|
-
end
|
67
|
-
|
68
|
-
def python_version_matching_imputed_requirements
|
69
|
-
compiled_file_python_requirement_markers =
|
70
|
-
python_requirement_parser.imputed_requirements.map do |r|
|
71
|
-
Dependabot::Python::Requirement.new(r)
|
72
|
-
end
|
73
|
-
python_version_matching(compiled_file_python_requirement_markers)
|
74
|
-
end
|
75
|
-
|
76
|
-
def python_version_matching(requirements)
|
77
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
78
|
-
version = Python::Version.new(version_string)
|
79
|
-
requirements.all? do |req|
|
80
|
-
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
81
|
-
|
82
|
-
req.satisfied_by?(version)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
53
|
def python_requirement_parser
|
88
54
|
@python_requirement_parser ||=
|
89
|
-
FileParser::PythonRequirementParser.
|
90
|
-
|
55
|
+
FileParser::PythonRequirementParser.new(
|
56
|
+
dependency_files: dependency_files
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def language_version_manager
|
61
|
+
@language_version_manager ||=
|
62
|
+
LanguageVersionManager.new(
|
63
|
+
python_requirement_parser: python_requirement_parser
|
64
|
+
)
|
91
65
|
end
|
92
66
|
end
|
93
67
|
end
|
@@ -175,7 +175,7 @@ module Dependabot
|
|
175
175
|
end
|
176
176
|
|
177
177
|
if error.message.include?("UnsupportedPythonVersion") &&
|
178
|
-
|
178
|
+
language_version_manager.user_specified_python_version
|
179
179
|
check_original_requirements_resolvable
|
180
180
|
|
181
181
|
# The latest version of the dependency we're updating to needs a
|
@@ -231,7 +231,7 @@ module Dependabot
|
|
231
231
|
end
|
232
232
|
|
233
233
|
if error.message.include?("UnsupportedPythonVersion") &&
|
234
|
-
|
234
|
+
language_version_manager.user_specified_python_version
|
235
235
|
msg = clean_error_message(error.message).
|
236
236
|
lines.take_while { |l| !l.start_with?("File") }.join.strip
|
237
237
|
raise if msg.empty?
|
@@ -239,8 +239,10 @@ module Dependabot
|
|
239
239
|
raise DependencyFileNotResolvable, msg
|
240
240
|
end
|
241
241
|
|
242
|
-
# NOTE: Pipenv masks the
|
242
|
+
# NOTE: Pipenv masks the actual error, see this issue for updates:
|
243
243
|
# https://github.com/pypa/pipenv/issues/2791
|
244
|
+
# TODO: This may no longer be reproducible on latest pipenv, see linked issue,
|
245
|
+
# so investigate when we next bump to newer pipenv...
|
244
246
|
handle_pipenv_installation_error(error.message) if error.message.match?(PIPENV_INSTALLATION_ERROR_REGEX)
|
245
247
|
|
246
248
|
# Raise an unhandled error, as this could be a problem with
|
@@ -290,7 +292,7 @@ module Dependabot
|
|
290
292
|
end
|
291
293
|
|
292
294
|
# Overwrite the .python-version with updated content
|
293
|
-
File.write(".python-version",
|
295
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
294
296
|
|
295
297
|
setup_files.each do |file|
|
296
298
|
path = file.name
|
@@ -320,7 +322,7 @@ module Dependabot
|
|
320
322
|
nil
|
321
323
|
end
|
322
324
|
|
323
|
-
|
325
|
+
language_version_manager.install_required_python
|
324
326
|
end
|
325
327
|
|
326
328
|
def sanitized_setup_file_content(file)
|
@@ -354,7 +356,7 @@ module Dependabot
|
|
354
356
|
def update_python_requirement(pipfile_content)
|
355
357
|
Python::FileUpdater::PipfilePreparer.
|
356
358
|
new(pipfile_content: pipfile_content).
|
357
|
-
update_python_requirement(
|
359
|
+
update_python_requirement(language_version_manager.python_major_minor)
|
358
360
|
end
|
359
361
|
|
360
362
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -398,57 +400,6 @@ module Dependabot
|
|
398
400
|
replace_sources(credentials)
|
399
401
|
end
|
400
402
|
|
401
|
-
def python_version
|
402
|
-
@python_version ||= python_version_from_supported_versions
|
403
|
-
end
|
404
|
-
|
405
|
-
def python_version_from_supported_versions
|
406
|
-
requirement_string =
|
407
|
-
if @using_python_two then "2.7.*"
|
408
|
-
elsif user_specified_python_requirement
|
409
|
-
parts = user_specified_python_requirement.split(".")
|
410
|
-
parts.fill("*", (parts.length)..2).join(".")
|
411
|
-
else
|
412
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
413
|
-
end
|
414
|
-
|
415
|
-
# Ideally, the requirement is satisfied by a Python version we support
|
416
|
-
requirement =
|
417
|
-
Python::Requirement.requirements_array(requirement_string).first
|
418
|
-
version =
|
419
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
420
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
421
|
-
return version if version
|
422
|
-
|
423
|
-
# If not, and changing the patch version would fix things, we do that
|
424
|
-
# as the patch version is unlikely to affect resolution
|
425
|
-
requirement =
|
426
|
-
Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
|
427
|
-
version =
|
428
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
429
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
430
|
-
return version if version
|
431
|
-
|
432
|
-
# Otherwise we have to raise, giving details of the Python versions
|
433
|
-
# that Dependabot supports
|
434
|
-
msg = "Dependabot detected the following Python requirement " \
|
435
|
-
"for your project: '#{requirement_string}'.\n\nCurrently, the " \
|
436
|
-
"following Python versions are supported in Dependabot: " \
|
437
|
-
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
438
|
-
raise DependencyFileNotResolvable, msg
|
439
|
-
end
|
440
|
-
|
441
|
-
def user_specified_python_requirement
|
442
|
-
python_requirement_parser.user_specified_requirements.first
|
443
|
-
end
|
444
|
-
|
445
|
-
def python_requirement_parser
|
446
|
-
@python_requirement_parser ||=
|
447
|
-
FileParser::PythonRequirementParser.new(
|
448
|
-
dependency_files: dependency_files
|
449
|
-
)
|
450
|
-
end
|
451
|
-
|
452
403
|
def run_command(command, env: {})
|
453
404
|
start = Time.now
|
454
405
|
command = SharedHelpers.escape_command(command)
|
@@ -468,7 +419,7 @@ module Dependabot
|
|
468
419
|
end
|
469
420
|
|
470
421
|
def run_pipenv_command(command, env: pipenv_env_variables)
|
471
|
-
run_command("pyenv local #{
|
422
|
+
run_command("pyenv local #{language_version_manager.python_major_minor}")
|
472
423
|
run_command(command, env: env)
|
473
424
|
end
|
474
425
|
|
@@ -486,6 +437,20 @@ module Dependabot
|
|
486
437
|
NameNormaliser.normalise(name)
|
487
438
|
end
|
488
439
|
|
440
|
+
def python_requirement_parser
|
441
|
+
@python_requirement_parser ||=
|
442
|
+
FileParser::PythonRequirementParser.new(
|
443
|
+
dependency_files: dependency_files
|
444
|
+
)
|
445
|
+
end
|
446
|
+
|
447
|
+
def language_version_manager
|
448
|
+
@language_version_manager ||=
|
449
|
+
LanguageVersionManager.new(
|
450
|
+
python_requirement_parser: python_requirement_parser
|
451
|
+
)
|
452
|
+
end
|
453
|
+
|
489
454
|
def pipfile
|
490
455
|
dependency_files.find { |f| f.name == "Pipfile" }
|
491
456
|
end
|
@@ -92,10 +92,10 @@ module Dependabot
|
|
92
92
|
write_temporary_dependency_files(updated_req: requirement)
|
93
93
|
add_auth_env_vars
|
94
94
|
|
95
|
-
|
95
|
+
language_version_manager.install_required_python
|
96
96
|
|
97
97
|
# use system git instead of the pure Python dulwich
|
98
|
-
unless python_version&.start_with?("3.6")
|
98
|
+
unless language_version_manager.python_version&.start_with?("3.6")
|
99
99
|
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
100
100
|
end
|
101
101
|
|
@@ -205,7 +205,7 @@ module Dependabot
|
|
205
205
|
end
|
206
206
|
|
207
207
|
# Overwrite the .python-version with updated content
|
208
|
-
File.write(".python-version",
|
208
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
209
209
|
|
210
210
|
# Overwrite the pyproject with updated content
|
211
211
|
if update_pyproject
|
@@ -224,39 +224,10 @@ module Dependabot
|
|
224
224
|
add_auth_env_vars(credentials)
|
225
225
|
end
|
226
226
|
|
227
|
-
def python_version
|
228
|
-
requirements = python_requirement_parser.user_specified_requirements
|
229
|
-
requirements = requirements.
|
230
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
231
|
-
|
232
|
-
version = PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |v|
|
233
|
-
requirements.all? do |reqs|
|
234
|
-
reqs.any? { |r| r.satisfied_by?(Python::Version.new(v)) }
|
235
|
-
end
|
236
|
-
end
|
237
|
-
return version if version
|
238
|
-
|
239
|
-
msg = "Dependabot detected the following Python requirements " \
|
240
|
-
"for your project: '#{requirements}'.\n\nCurrently, the " \
|
241
|
-
"following Python versions are supported in Dependabot: " \
|
242
|
-
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
243
|
-
raise DependencyFileNotResolvable, msg
|
244
|
-
end
|
245
|
-
|
246
|
-
def python_requirement_parser
|
247
|
-
@python_requirement_parser ||=
|
248
|
-
FileParser::PythonRequirementParser.new(
|
249
|
-
dependency_files: dependency_files
|
250
|
-
)
|
251
|
-
end
|
252
|
-
|
253
|
-
def pre_installed_python?(version)
|
254
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.include?(version)
|
255
|
-
end
|
256
|
-
|
257
227
|
def updated_pyproject_content(updated_requirement:)
|
258
228
|
content = pyproject.content
|
259
229
|
content = sanitize_pyproject_content(content)
|
230
|
+
content = update_python_requirement(content)
|
260
231
|
content = freeze_other_dependencies(content)
|
261
232
|
content = set_target_dependency_req(content, updated_requirement)
|
262
233
|
content
|
@@ -265,6 +236,7 @@ module Dependabot
|
|
265
236
|
def sanitized_pyproject_content
|
266
237
|
content = pyproject.content
|
267
238
|
content = sanitize_pyproject_content(content)
|
239
|
+
content = update_python_requirement(content)
|
268
240
|
content
|
269
241
|
end
|
270
242
|
|
@@ -274,13 +246,18 @@ module Dependabot
|
|
274
246
|
sanitize
|
275
247
|
end
|
276
248
|
|
249
|
+
def update_python_requirement(pyproject_content)
|
250
|
+
Python::FileUpdater::PyprojectPreparer.
|
251
|
+
new(pyproject_content: pyproject_content).
|
252
|
+
update_python_requirement(language_version_manager.python_major_minor)
|
253
|
+
end
|
254
|
+
|
277
255
|
def freeze_other_dependencies(pyproject_content)
|
278
256
|
Python::FileUpdater::PyprojectPreparer.
|
279
257
|
new(pyproject_content: pyproject_content, lockfile: lockfile).
|
280
258
|
freeze_top_level_dependencies_except([dependency])
|
281
259
|
end
|
282
260
|
|
283
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
284
261
|
def set_target_dependency_req(pyproject_content, updated_requirement)
|
285
262
|
return pyproject_content unless updated_requirement
|
286
263
|
|
@@ -288,15 +265,15 @@ module Dependabot
|
|
288
265
|
poetry_object = pyproject_object.dig("tool", "poetry")
|
289
266
|
|
290
267
|
Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |type|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
268
|
+
dependencies = poetry_object[type]
|
269
|
+
next unless dependencies
|
270
|
+
|
271
|
+
update_dependency_requirement(dependencies, updated_requirement)
|
272
|
+
end
|
273
|
+
|
274
|
+
groups = poetry_object["group"]&.values || []
|
275
|
+
groups.each do |group_spec|
|
276
|
+
update_dependency_requirement(group_spec["dependencies"], updated_requirement)
|
300
277
|
end
|
301
278
|
|
302
279
|
# If this is a sub-dependency, add the new requirement
|
@@ -307,7 +284,18 @@ module Dependabot
|
|
307
284
|
|
308
285
|
TomlRB.dump(pyproject_object)
|
309
286
|
end
|
310
|
-
|
287
|
+
|
288
|
+
def update_dependency_requirement(toml_node, requirement)
|
289
|
+
names = toml_node.keys
|
290
|
+
pkg_name = names.find { |nm| normalise(nm) == dependency.name }
|
291
|
+
return unless pkg_name
|
292
|
+
|
293
|
+
if toml_node[pkg_name].is_a?(Hash)
|
294
|
+
toml_node[pkg_name]["version"] = requirement
|
295
|
+
else
|
296
|
+
toml_node[pkg_name] = requirement
|
297
|
+
end
|
298
|
+
end
|
311
299
|
|
312
300
|
def subdep_type
|
313
301
|
category =
|
@@ -318,6 +306,20 @@ module Dependabot
|
|
318
306
|
category == "dev" ? "dev-dependencies" : "dependencies"
|
319
307
|
end
|
320
308
|
|
309
|
+
def python_requirement_parser
|
310
|
+
@python_requirement_parser ||=
|
311
|
+
FileParser::PythonRequirementParser.new(
|
312
|
+
dependency_files: dependency_files
|
313
|
+
)
|
314
|
+
end
|
315
|
+
|
316
|
+
def language_version_manager
|
317
|
+
@language_version_manager ||=
|
318
|
+
LanguageVersionManager.new(
|
319
|
+
python_requirement_parser: python_requirement_parser
|
320
|
+
)
|
321
|
+
end
|
322
|
+
|
321
323
|
def pyproject
|
322
324
|
dependency_files.find { |f| f.name == "pyproject.toml" }
|
323
325
|
end
|
@@ -88,12 +88,19 @@ module Dependabot
|
|
88
88
|
case update_strategy
|
89
89
|
when :widen_ranges then widen_pyproject_requirement(req)
|
90
90
|
when :bump_versions then update_pyproject_version(req)
|
91
|
+
when :bump_versions_if_necessary then update_pyproject_version_if_needed(req)
|
91
92
|
else raise "Unexpected update strategy: #{update_strategy}"
|
92
93
|
end
|
93
94
|
rescue UnfixableRequirement
|
94
95
|
req.merge(requirement: :unfixable)
|
95
96
|
end
|
96
97
|
|
98
|
+
def update_pyproject_version_if_needed(req)
|
99
|
+
return req if new_version_satisfies?(req)
|
100
|
+
|
101
|
+
update_pyproject_version(req)
|
102
|
+
end
|
103
|
+
|
97
104
|
def update_pyproject_version(req)
|
98
105
|
requirement_strings = req[:requirement].split(",").map(&:strip)
|
99
106
|
|
@@ -180,10 +187,14 @@ module Dependabot
|
|
180
187
|
return req unless req.fetch(:requirement)
|
181
188
|
|
182
189
|
case update_strategy
|
190
|
+
when :widen_ranges
|
191
|
+
widen_requirement(req)
|
183
192
|
when :bump_versions
|
184
193
|
update_requirement(req)
|
185
194
|
when :bump_versions_if_necessary
|
186
195
|
update_requirement_if_needed(req)
|
196
|
+
else
|
197
|
+
raise "Unexpected update strategy: #{update_strategy}"
|
187
198
|
end
|
188
199
|
end
|
189
200
|
|
@@ -212,6 +223,14 @@ module Dependabot
|
|
212
223
|
req.merge(requirement: :unfixable)
|
213
224
|
end
|
214
225
|
|
226
|
+
def widen_requirement(req)
|
227
|
+
return req if new_version_satisfies?(req)
|
228
|
+
|
229
|
+
new_requirement = widen_requirement_range(req[:requirement])
|
230
|
+
|
231
|
+
req.merge(requirement: new_requirement)
|
232
|
+
end
|
233
|
+
|
215
234
|
def new_version_satisfies?(req)
|
216
235
|
requirement_class.
|
217
236
|
requirements_array(req.fetch(:requirement)).
|
@@ -256,8 +275,10 @@ module Dependabot
|
|
256
275
|
next r.to_s if r.satisfied_by?(latest_resolvable_version)
|
257
276
|
|
258
277
|
case op = r.requirements.first.first
|
259
|
-
when "<"
|
260
|
-
"<" + update_greatest_version(r.
|
278
|
+
when "<"
|
279
|
+
"<" + update_greatest_version(r.requirements.first.last, latest_resolvable_version)
|
280
|
+
when "<="
|
281
|
+
"<=" + latest_resolvable_version.to_s
|
261
282
|
when "!=", ">", ">="
|
262
283
|
raise UnfixableRequirement
|
263
284
|
else
|
@@ -329,14 +350,12 @@ module Dependabot
|
|
329
350
|
end
|
330
351
|
end
|
331
352
|
|
332
|
-
# Updates the version in a "<"
|
333
|
-
|
334
|
-
def update_greatest_version(req_string, version_to_be_permitted)
|
353
|
+
# Updates the version in a "<" constraint to allow the given version
|
354
|
+
def update_greatest_version(version, version_to_be_permitted)
|
335
355
|
if version_to_be_permitted.is_a?(String)
|
336
356
|
version_to_be_permitted =
|
337
357
|
Python::Version.new(version_to_be_permitted)
|
338
358
|
end
|
339
|
-
version = Python::Version.new(req_string.gsub(/<=?/, ""))
|
340
359
|
version = version.release if version.prerelease?
|
341
360
|
|
342
361
|
index_to_update = [
|