dependabot-python 0.368.0 → 0.370.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 +4 -0
- data/helpers/lib/parser.py +26 -0
- data/helpers/requirements.txt +1 -0
- data/helpers/test/fixtures/no_dependencies.toml +3 -0
- data/helpers/test/fixtures/pep621_arbitrary_equality.toml +7 -0
- data/helpers/test/fixtures/pep621_dependencies.toml +21 -0
- data/helpers/test/fixtures/pep621_empty_deps.toml +8 -0
- data/helpers/test/fixtures/pep621_extras.toml +8 -0
- data/helpers/test/fixtures/pep621_markers.toml +7 -0
- data/helpers/test/fixtures/pep621_multiple_extras.toml +7 -0
- data/helpers/test/fixtures/pep621_no_version.toml +8 -0
- data/helpers/test/fixtures/pep621_only_build_system.toml +3 -0
- data/helpers/test/fixtures/pep621_spaced_specifiers.toml +10 -0
- data/helpers/test/fixtures/pep735_cycle.toml +13 -0
- data/helpers/test/fixtures/pep735_dependency_groups.toml +18 -0
- data/helpers/test/fixtures/requirements/constraints.txt +1 -0
- data/helpers/test/fixtures/requirements/markers.txt +1 -0
- data/helpers/test/fixtures/requirements/requirements-dev.txt +2 -0
- data/helpers/test/fixtures/requirements/requirements.txt +5 -0
- data/helpers/test/fixtures/requirements/with_constraints.txt +2 -0
- data/helpers/test/fixtures/requirements_empty/.gitkeep +0 -0
- data/helpers/test/fixtures/setup_cfg/setup.cfg +16 -0
- data/helpers/test/fixtures/setup_py/setup.py +20 -0
- data/helpers/test/fixtures/setup_py_comments/setup.py +9 -0
- data/helpers/test/test_hasher.py +114 -0
- data/helpers/test/test_parse_requirements.py +103 -0
- data/helpers/test/test_parse_setup.py +127 -0
- data/helpers/test/test_parser.py +265 -0
- data/helpers/test/test_run.py +49 -0
- data/lib/dependabot/python/dependency_grapher/lockfile_generator.rb +13 -0
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +42 -11
- data/lib/dependabot/python/file_parser.rb +21 -1
- data/lib/dependabot/python/file_updater/poetry_file_updater/pep621_updater.rb +162 -0
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +60 -77
- data/lib/dependabot/python/file_updater/pyproject_preparer.rb +139 -27
- data/lib/dependabot/python/package_manager.rb +16 -0
- data/lib/dependabot/python/poetry_plugin_installer.rb +95 -0
- data/lib/dependabot/python/update_checker/latest_version_finder.rb +4 -2
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +13 -0
- data/lib/dependabot/python/update_checker/requirements_updater.rb +86 -15
- data/lib/dependabot/python/update_checker.rb +6 -2
- metadata +32 -4
|
@@ -11,11 +11,13 @@ require "dependabot/requirements_update_strategy"
|
|
|
11
11
|
module Dependabot
|
|
12
12
|
module Python
|
|
13
13
|
class UpdateChecker
|
|
14
|
+
# rubocop:disable Metrics/ClassLength
|
|
14
15
|
class RequirementsUpdater
|
|
15
16
|
extend T::Sig
|
|
16
17
|
|
|
17
18
|
PYPROJECT_OR_SEPARATOR = T.let(/(?<=[a-zA-Z0-9*])\s*\|+/, Regexp)
|
|
18
19
|
PYPROJECT_SEPARATOR = T.let(/#{PYPROJECT_OR_SEPARATOR}|,/, Regexp)
|
|
20
|
+
LOWER_BOUND_OPS = T.let(%w(> >=).freeze, T::Array[String])
|
|
19
21
|
|
|
20
22
|
class UnfixableRequirement < StandardError; end
|
|
21
23
|
|
|
@@ -111,13 +113,25 @@ module Dependabot
|
|
|
111
113
|
def updated_pyproject_requirement(req)
|
|
112
114
|
return req unless latest_resolvable_version
|
|
113
115
|
return req unless req.fetch(:requirement)
|
|
114
|
-
return req if
|
|
116
|
+
return req if skip_pyproject_update?(req)
|
|
115
117
|
|
|
118
|
+
pyproject_update_for_strategy(req)
|
|
119
|
+
rescue UnfixableRequirement
|
|
120
|
+
req.merge(requirement: :unfixable)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
|
|
124
|
+
def skip_pyproject_update?(req)
|
|
125
|
+
new_version_satisfies?(req) && !has_lockfile &&
|
|
126
|
+
update_strategy != RequirementsUpdateStrategy::BumpVersions
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
|
130
|
+
def pyproject_update_for_strategy(req)
|
|
116
131
|
# If the requirement uses || syntax then we always want to widen it
|
|
117
132
|
return widen_pyproject_requirement(req) if req.fetch(:requirement).match?(PYPROJECT_OR_SEPARATOR)
|
|
118
133
|
|
|
119
|
-
# If the requirement is a development dependency we always want to
|
|
120
|
-
# bump it
|
|
134
|
+
# If the requirement is a development dependency we always want to bump it
|
|
121
135
|
return update_pyproject_version(req) if req.fetch(:groups).include?("dev-dependencies")
|
|
122
136
|
|
|
123
137
|
case update_strategy
|
|
@@ -126,37 +140,40 @@ module Dependabot
|
|
|
126
140
|
when RequirementsUpdateStrategy::BumpVersionsIfNecessary then update_pyproject_version_if_needed(req)
|
|
127
141
|
else raise "Unexpected update strategy: #{update_strategy}"
|
|
128
142
|
end
|
|
129
|
-
rescue UnfixableRequirement
|
|
130
|
-
req.merge(requirement: :unfixable)
|
|
131
143
|
end
|
|
132
144
|
|
|
133
145
|
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
|
134
146
|
def update_pyproject_version_if_needed(req)
|
|
135
147
|
return req if new_version_satisfies?(req)
|
|
136
148
|
|
|
137
|
-
|
|
149
|
+
update_pyproject_version_core(req, bump_lower_bound: false)
|
|
138
150
|
end
|
|
139
151
|
|
|
140
152
|
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
|
141
153
|
def update_pyproject_version(req)
|
|
154
|
+
return req if req[:requirement] == "*"
|
|
155
|
+
|
|
156
|
+
update_pyproject_version_core(req, bump_lower_bound: true)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
sig do
|
|
160
|
+
params(
|
|
161
|
+
req: T::Hash[Symbol, T.untyped],
|
|
162
|
+
bump_lower_bound: T::Boolean
|
|
163
|
+
).returns(T::Hash[Symbol, T.untyped])
|
|
164
|
+
end
|
|
165
|
+
def update_pyproject_version_core(req, bump_lower_bound:)
|
|
142
166
|
requirement_strings = req[:requirement].split(",").map(&:strip)
|
|
143
167
|
|
|
144
168
|
new_requirement =
|
|
145
169
|
if requirement_strings.any? { |r| r.match?(/^=|^\d/) }
|
|
146
|
-
# If there is an equality operator, just update that. It must
|
|
147
|
-
# be binding and any other requirements will be being ignored
|
|
148
170
|
find_and_update_equality_match(requirement_strings)
|
|
149
171
|
elsif requirement_strings.any? { |r| r.start_with?("~", "^") }
|
|
150
|
-
# If a compatibility operator is being used, just bump its
|
|
151
|
-
# version (and remove any other requirements)
|
|
152
172
|
v_req = requirement_strings.find { |r| r.start_with?("~", "^") }
|
|
153
173
|
bump_version(v_req, latest_resolvable_version.to_s)
|
|
154
|
-
elsif
|
|
155
|
-
|
|
156
|
-
# required if it's already satisfied
|
|
157
|
-
req.fetch(:requirement)
|
|
174
|
+
elsif bump_lower_bound
|
|
175
|
+
bump_requirements_range(requirement_strings)
|
|
158
176
|
else
|
|
159
|
-
# But if it's not, update it
|
|
160
177
|
update_requirements_range(requirement_strings)
|
|
161
178
|
end
|
|
162
179
|
|
|
@@ -344,6 +361,59 @@ module Dependabot
|
|
|
344
361
|
.sort_by { |r| requirement_class.new(r).requirements.first.last }.join(",").delete(" ")
|
|
345
362
|
end
|
|
346
363
|
|
|
364
|
+
# Bumps the lower bound of a range requirement to the latest version
|
|
365
|
+
# Used by BumpVersions strategy to increase the minimum version
|
|
366
|
+
sig { params(requirement_strings: T::Array[String]).returns(String) }
|
|
367
|
+
def bump_requirements_range(requirement_strings)
|
|
368
|
+
ruby_requirements = requirement_strings.map { |r| requirement_class.new(r) }
|
|
369
|
+
|
|
370
|
+
validate_lower_bounds_not_too_high(ruby_requirements)
|
|
371
|
+
|
|
372
|
+
updated_requirement_strings = ruby_requirements.map { |r| bump_single_requirement(r) }
|
|
373
|
+
|
|
374
|
+
updated_requirement_strings
|
|
375
|
+
.sort_by { |r| requirement_class.new(r).requirements.first.last }.join(",").delete(" ")
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
sig { params(ruby_requirements: T::Array[Dependabot::Python::Requirement]).void }
|
|
379
|
+
def validate_lower_bounds_not_too_high(ruby_requirements)
|
|
380
|
+
ruby_requirements.each do |r|
|
|
381
|
+
op, version = r.requirements.first
|
|
382
|
+
raise UnfixableRequirement if LOWER_BOUND_OPS.include?(op) && version > T.must(latest_resolvable_version)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
sig { params(req: Dependabot::Python::Requirement).returns(String) }
|
|
387
|
+
def bump_single_requirement(req)
|
|
388
|
+
op, version = req.requirements.first
|
|
389
|
+
|
|
390
|
+
case op
|
|
391
|
+
when ">=" then ">=" + T.must(latest_resolvable_version).to_s
|
|
392
|
+
# Strict lower bound becomes inclusive because the resolved version
|
|
393
|
+
# is the exact target — using ">" would exclude it.
|
|
394
|
+
when ">" then ">=" + T.must(latest_resolvable_version).to_s
|
|
395
|
+
when "<" then bump_upper_bound_less_than(req, version)
|
|
396
|
+
when "<=" then bump_upper_bound_less_or_equal(req)
|
|
397
|
+
when "~>", "~=" then bump_version(req.to_s, T.must(latest_resolvable_version).to_s)
|
|
398
|
+
when "!=" then req.to_s
|
|
399
|
+
else req.to_s
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
sig { params(req: Dependabot::Python::Requirement, version: Gem::Version).returns(String) }
|
|
404
|
+
def bump_upper_bound_less_than(req, version)
|
|
405
|
+
return req.to_s if req.satisfied_by?(T.must(latest_resolvable_version))
|
|
406
|
+
|
|
407
|
+
"<" + update_greatest_version(version, T.must(latest_resolvable_version))
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
sig { params(req: Dependabot::Python::Requirement).returns(String) }
|
|
411
|
+
def bump_upper_bound_less_or_equal(req)
|
|
412
|
+
return req.to_s if req.satisfied_by?(T.must(latest_resolvable_version))
|
|
413
|
+
|
|
414
|
+
"<=" + T.must(latest_resolvable_version).to_s
|
|
415
|
+
end
|
|
416
|
+
|
|
347
417
|
# Updates the version in a constraint to be the given version
|
|
348
418
|
sig { params(req_string: String, version_to_be_permitted: String).returns(String) }
|
|
349
419
|
def bump_version(req_string, version_to_be_permitted)
|
|
@@ -448,6 +518,7 @@ module Dependabot
|
|
|
448
518
|
Python::Requirement
|
|
449
519
|
end
|
|
450
520
|
end
|
|
521
|
+
# rubocop:enable Metrics/ClassLength
|
|
451
522
|
end
|
|
452
523
|
end
|
|
453
524
|
end
|
|
@@ -409,14 +409,18 @@ module Dependabot
|
|
|
409
409
|
def check_pypi_for_library_match
|
|
410
410
|
return false unless updating_pyproject? && library_details && !T.must(library_details)["name"].nil?
|
|
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?
|
|
415
|
+
|
|
412
416
|
response = Dependabot::RegistryClient.get(
|
|
413
417
|
url: "https://pypi.org/pypi/#{normalised_name(T.must(library_details)['name'])}/json/"
|
|
414
418
|
)
|
|
415
|
-
return
|
|
419
|
+
return has_library_metadata unless response.status == 200
|
|
416
420
|
|
|
417
421
|
(JSON.parse(response.body)["info"] || {})["summary"] == T.must(library_details)["description"]
|
|
418
422
|
rescue Excon::Error::Timeout, Excon::Error::Socket, URI::InvalidURIError
|
|
419
|
-
|
|
423
|
+
has_library_metadata
|
|
420
424
|
end
|
|
421
425
|
|
|
422
426
|
sig { returns(T::Boolean) }
|
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.370.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.370.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.370.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -247,6 +247,32 @@ files:
|
|
|
247
247
|
- helpers/lib/parser.py
|
|
248
248
|
- helpers/requirements.txt
|
|
249
249
|
- helpers/run.py
|
|
250
|
+
- helpers/test/fixtures/no_dependencies.toml
|
|
251
|
+
- helpers/test/fixtures/pep621_arbitrary_equality.toml
|
|
252
|
+
- helpers/test/fixtures/pep621_dependencies.toml
|
|
253
|
+
- helpers/test/fixtures/pep621_empty_deps.toml
|
|
254
|
+
- helpers/test/fixtures/pep621_extras.toml
|
|
255
|
+
- helpers/test/fixtures/pep621_markers.toml
|
|
256
|
+
- helpers/test/fixtures/pep621_multiple_extras.toml
|
|
257
|
+
- helpers/test/fixtures/pep621_no_version.toml
|
|
258
|
+
- helpers/test/fixtures/pep621_only_build_system.toml
|
|
259
|
+
- helpers/test/fixtures/pep621_spaced_specifiers.toml
|
|
260
|
+
- helpers/test/fixtures/pep735_cycle.toml
|
|
261
|
+
- helpers/test/fixtures/pep735_dependency_groups.toml
|
|
262
|
+
- helpers/test/fixtures/requirements/constraints.txt
|
|
263
|
+
- helpers/test/fixtures/requirements/markers.txt
|
|
264
|
+
- helpers/test/fixtures/requirements/requirements-dev.txt
|
|
265
|
+
- helpers/test/fixtures/requirements/requirements.txt
|
|
266
|
+
- helpers/test/fixtures/requirements/with_constraints.txt
|
|
267
|
+
- helpers/test/fixtures/requirements_empty/.gitkeep
|
|
268
|
+
- helpers/test/fixtures/setup_cfg/setup.cfg
|
|
269
|
+
- helpers/test/fixtures/setup_py/setup.py
|
|
270
|
+
- helpers/test/fixtures/setup_py_comments/setup.py
|
|
271
|
+
- helpers/test/test_hasher.py
|
|
272
|
+
- helpers/test/test_parse_requirements.py
|
|
273
|
+
- helpers/test/test_parse_setup.py
|
|
274
|
+
- helpers/test/test_parser.py
|
|
275
|
+
- helpers/test/test_run.py
|
|
250
276
|
- lib/dependabot/python.rb
|
|
251
277
|
- lib/dependabot/python/authed_url_builder.rb
|
|
252
278
|
- lib/dependabot/python/dependency_grapher.rb
|
|
@@ -263,6 +289,7 @@ files:
|
|
|
263
289
|
- lib/dependabot/python/file_updater/pipfile_manifest_updater.rb
|
|
264
290
|
- lib/dependabot/python/file_updater/pipfile_preparer.rb
|
|
265
291
|
- lib/dependabot/python/file_updater/poetry_file_updater.rb
|
|
292
|
+
- lib/dependabot/python/file_updater/poetry_file_updater/pep621_updater.rb
|
|
266
293
|
- lib/dependabot/python/file_updater/pyproject_preparer.rb
|
|
267
294
|
- lib/dependabot/python/file_updater/requirement_file_updater.rb
|
|
268
295
|
- lib/dependabot/python/file_updater/requirement_replacer.rb
|
|
@@ -277,6 +304,7 @@ files:
|
|
|
277
304
|
- lib/dependabot/python/package_manager.rb
|
|
278
305
|
- lib/dependabot/python/pip_compile_file_matcher.rb
|
|
279
306
|
- lib/dependabot/python/pipenv_runner.rb
|
|
307
|
+
- lib/dependabot/python/poetry_plugin_installer.rb
|
|
280
308
|
- lib/dependabot/python/requirement.rb
|
|
281
309
|
- lib/dependabot/python/requirement_parser.rb
|
|
282
310
|
- lib/dependabot/python/shared_file_fetcher.rb
|
|
@@ -294,7 +322,7 @@ licenses:
|
|
|
294
322
|
- MIT
|
|
295
323
|
metadata:
|
|
296
324
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
297
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
325
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.370.0
|
|
298
326
|
rdoc_options: []
|
|
299
327
|
require_paths:
|
|
300
328
|
- lib
|