dependabot-python 0.226.0 → 0.228.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: 62fa8493503751dac8cc47e22819a502a292e5de2523c22a5dbd9edcb44e8051
4
- data.tar.gz: 37ea1a41eb2064d2eb28149f86bc6e0c6aee4e9f6b40c64e044fa8b0d69ac8af
3
+ metadata.gz: 67fcdac9ca728ef251cf259a11a3d1efec3f037715f9587bc30896baf3abcad9
4
+ data.tar.gz: 00cf4ecfceeba160a6ccb95c84853f782df01f571ea17b320609205a6138e76e
5
5
  SHA512:
6
- metadata.gz: '08074756f750b4cae957e60277544eac7c23ec2f958a78d44d8c258921fbba181d783c1a1cf0ca11813969ad1cf0446493367893a797493ab9febae8668ddf75'
7
- data.tar.gz: 5416cb34a8d3a2aeaf66da9a8bbe90e44d00ff950ed1444c1558131af7863ba7fc1b7b8944c153647686a129539d01b62d9cc2e6b9796927c43f9e0011909a76
6
+ metadata.gz: e320bfeef5f545705df3daf17edf15cf9633b3ed2a6438bc1cd12ec3fc66d8abd1248d20898b0a8aca1d3aaa86f1b512f951179c4708706af36d64a93b0a5933
7
+ data.tar.gz: 9bc806e1d363784ed23ed71d694154e8d37f967bb1d559348852fffdde381889b2f235658b5dc424c9400589483d76c08b5f1f608eb15e43e59e70bc773a266a
@@ -1,9 +1,10 @@
1
- pip>=21.3.1,<23.2.0 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
2
- pip-tools>=6.4.0,<=6.14.0 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
1
+ pip==23.2.1
2
+ pip-tools==7.3.0
3
+ flake8==6.1.0
3
4
  hashin==0.17.0
4
5
  pipenv==2022.4.8
5
6
  pipfile==0.0.2
6
- poetry>=1.1.15,<1.6.0
7
+ poetry==1.6.1
7
8
 
8
9
  # Some dependencies will only install if Cython is present
9
10
  Cython==3.0.0
@@ -4,8 +4,10 @@ require "toml-rb"
4
4
 
5
5
  require "dependabot/file_fetchers"
6
6
  require "dependabot/file_fetchers/base"
7
+ require "dependabot/python/language_version_manager"
7
8
  require "dependabot/python/requirement_parser"
8
9
  require "dependabot/python/file_parser/pyproject_files_parser"
10
+ require "dependabot/python/file_parser/python_requirement_parser"
9
11
  require "dependabot/errors"
10
12
 
11
13
  module Dependabot
@@ -91,7 +93,7 @@ module Dependabot
91
93
  end
92
94
 
93
95
  def pyproject_files
94
- [pyproject, pyproject_lock, poetry_lock, pdm_lock].compact
96
+ [pyproject, poetry_lock, pdm_lock].compact
95
97
  end
96
98
 
97
99
  def requirement_files
@@ -166,12 +168,6 @@ module Dependabot
166
168
  @pyproject = fetch_file_if_present("pyproject.toml")
167
169
  end
168
170
 
169
- def pyproject_lock
170
- return @pyproject_lock if defined?(@pyproject_lock)
171
-
172
- @pyproject_lock = fetch_file_if_present("pyproject.lock")
173
- end
174
-
175
171
  def poetry_lock
176
172
  return @poetry_lock if defined?(@poetry_lock)
177
173
 
@@ -7,6 +7,7 @@ require "dependabot/file_parsers/base/dependency_set"
7
7
  require "dependabot/python/file_parser"
8
8
  require "dependabot/python/requirement"
9
9
  require "dependabot/errors"
10
+ require "dependabot/python/helpers"
10
11
  require "dependabot/python/name_normaliser"
11
12
 
12
13
  module Dependabot
@@ -44,16 +45,20 @@ module Dependabot
44
45
  end
45
46
 
46
47
  def poetry_dependencies
48
+ @poetry_dependencies ||= parse_poetry_dependencies
49
+ end
50
+
51
+ def parse_poetry_dependencies
47
52
  dependencies = Dependabot::FileParsers::Base::DependencySet.new
48
53
 
49
54
  POETRY_DEPENDENCY_TYPES.each do |type|
50
55
  deps_hash = parsed_pyproject.dig("tool", "poetry", type) || {}
51
- dependencies += parse_poetry_dependencies(type, deps_hash)
56
+ dependencies += parse_poetry_dependency_group(type, deps_hash)
52
57
  end
53
58
 
54
59
  groups = parsed_pyproject.dig("tool", "poetry", "group") || {}
55
60
  groups.each do |group, group_spec|
56
- dependencies += parse_poetry_dependencies(group, group_spec["dependencies"])
61
+ dependencies += parse_poetry_dependency_group(group, group_spec["dependencies"])
57
62
  end
58
63
  dependencies
59
64
  end
@@ -92,7 +97,7 @@ module Dependabot
92
97
  dependencies
93
98
  end
94
99
 
95
- def parse_poetry_dependencies(type, deps_hash)
100
+ def parse_poetry_dependency_group(type, deps_hash)
96
101
  dependencies = Dependabot::FileParsers::Base::DependencySet.new
97
102
 
98
103
  deps_hash.each do |name, req|
@@ -154,14 +159,16 @@ module Dependabot
154
159
  parsed_lockfile.fetch("package", []).each do |details|
155
160
  next if source_types.include?(details.dig("source", "type"))
156
161
 
162
+ name = normalise(details.fetch("name"))
163
+
157
164
  dependencies <<
158
165
  Dependency.new(
159
- name: normalise(details.fetch("name")),
166
+ name: name,
160
167
  version: details.fetch("version"),
161
168
  requirements: [],
162
169
  package_manager: "pip",
163
170
  subdependency_metadata: [{
164
- production: details["category"] != "dev"
171
+ production: production_dependency_names.include?(name)
165
172
  }]
166
173
  )
167
174
  end
@@ -169,6 +176,32 @@ module Dependabot
169
176
  dependencies
170
177
  end
171
178
 
179
+ def production_dependency_names
180
+ @production_dependency_names ||= parse_production_dependency_names
181
+ end
182
+
183
+ def parse_production_dependency_names
184
+ SharedHelpers.in_a_temporary_directory do
185
+ File.write(pyproject.name, pyproject.content)
186
+ File.write(lockfile.name, lockfile.content)
187
+
188
+ begin
189
+ output = Helpers.run_poetry_command("pyenv exec poetry show --only main")
190
+
191
+ output.split("\n").map { |line| line.split.first }
192
+ rescue SharedHelpers::HelperSubprocessFailed
193
+ # Sometimes, we may be dealing with an old lockfile that our
194
+ # poetry version can't show dependency information for. Other
195
+ # commands we use like `poetry update` are more resilient and
196
+ # automatically heal the lockfile. So we rescue the error and make
197
+ # a best effort approach to this.
198
+ poetry_dependencies.dependencies.filter_map do |dep|
199
+ dep.name if dep.production?
200
+ end
201
+ end
202
+ end
203
+ end
204
+
172
205
  def version_from_lockfile(dep_name)
173
206
  return unless parsed_lockfile
174
207
 
@@ -194,12 +227,6 @@ module Dependabot
194
227
  raise Dependabot::DependencyFileNotParseable, pyproject.path
195
228
  end
196
229
 
197
- def parsed_pyproject_lock
198
- @parsed_pyproject_lock ||= TomlRB.parse(pyproject_lock.content)
199
- rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
200
- raise Dependabot::DependencyFileNotParseable, pyproject_lock.path
201
- end
202
-
203
230
  def parsed_poetry_lock
204
231
  @parsed_poetry_lock ||= TomlRB.parse(poetry_lock.content)
205
232
  rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
@@ -212,7 +239,7 @@ module Dependabot
212
239
  end
213
240
 
214
241
  def lockfile
215
- poetry_lock || pyproject_lock
242
+ poetry_lock
216
243
  end
217
244
 
218
245
  def parsed_pep621_dependencies
@@ -234,13 +261,7 @@ module Dependabot
234
261
  end
235
262
 
236
263
  def parsed_lockfile
237
- return parsed_poetry_lock if poetry_lock
238
- return parsed_pyproject_lock if pyproject_lock
239
- end
240
-
241
- def pyproject_lock
242
- @pyproject_lock ||=
243
- dependency_files.find { |f| f.name == "pyproject.lock" }
264
+ parsed_poetry_lock if poetry_lock
244
265
  end
245
266
 
246
267
  def poetry_lock
@@ -208,10 +208,6 @@ module Dependabot
208
208
  @pyproject ||= get_original_file("pyproject.toml")
209
209
  end
210
210
 
211
- def pyproject_lock
212
- @pyproject_lock ||= get_original_file("pyproject.lock")
213
- end
214
-
215
211
  def poetry_lock
216
212
  @poetry_lock ||= get_original_file("poetry.lock")
217
213
  end
@@ -9,7 +9,6 @@ require "dependabot/python/file_updater"
9
9
  require "dependabot/shared_helpers"
10
10
  require "dependabot/python/language_version_manager"
11
11
  require "dependabot/python/native_helpers"
12
- require "dependabot/python/python_versions"
13
12
  require "dependabot/python/name_normaliser"
14
13
  require "dependabot/python/authed_url_builder"
15
14
 
@@ -7,9 +7,9 @@ require "dependabot/shared_helpers"
7
7
  require "dependabot/python/language_version_manager"
8
8
  require "dependabot/python/version"
9
9
  require "dependabot/python/requirement"
10
- require "dependabot/python/python_versions"
11
10
  require "dependabot/python/file_parser/python_requirement_parser"
12
11
  require "dependabot/python/file_updater"
12
+ require "dependabot/python/helpers"
13
13
  require "dependabot/python/native_helpers"
14
14
  require "dependabot/python/name_normaliser"
15
15
 
@@ -95,6 +95,12 @@ module Dependabot
95
95
  begin
96
96
  new_lockfile = updated_lockfile_content_for(prepared_pyproject)
97
97
 
98
+ original_locked_python = TomlRB.parse(lockfile.content)["metadata"]["python-versions"]
99
+
100
+ new_lockfile.gsub!(/\[metadata\]\n.*python-versions[^\n]+\n/m) do |match|
101
+ match.gsub(/(["']).*(['"])\n\Z/, '\1' + original_locked_python + '\1' + "\n")
102
+ end
103
+
98
104
  tmp_hash =
99
105
  TomlRB.parse(new_lockfile)["metadata"]["content-hash"]
100
106
  correct_hash = pyproject_hash_for(updated_pyproject_content)
@@ -139,7 +145,7 @@ module Dependabot
139
145
  def update_python_requirement(pyproject_content)
140
146
  PyprojectPreparer.
141
147
  new(pyproject_content: pyproject_content).
142
- update_python_requirement(language_version_manager.python_major_minor)
148
+ update_python_requirement(language_version_manager.python_version)
143
149
  end
144
150
 
145
151
  def lock_declaration_to_new_version!(poetry_object, dep)
@@ -157,17 +163,10 @@ module Dependabot
157
163
  end
158
164
 
159
165
  def create_declaration_at_new_version!(poetry_object, dep)
160
- poetry_object[subdep_type] ||= {}
161
- poetry_object[subdep_type][dependency.name] = dep.version
162
- end
163
-
164
- def subdep_type
165
- category =
166
- TomlRB.parse(lockfile.content).fetch("package", []).
167
- find { |dets| normalise(dets.fetch("name")) == dependency.name }.
168
- fetch("category")
166
+ subdep_type = dep.production? ? "dependencies" : "dev-dependencies"
169
167
 
170
- category == "dev" ? "dev-dependencies" : "dependencies"
168
+ poetry_object[subdep_type] ||= {}
169
+ poetry_object[subdep_type][dep.name] = dep.version
171
170
  end
172
171
 
173
172
  def sanitize(pyproject_content)
@@ -185,15 +184,11 @@ module Dependabot
185
184
  language_version_manager.install_required_python
186
185
 
187
186
  # use system git instead of the pure Python dulwich
188
- unless language_version_manager.python_version&.start_with?("3.6")
189
- run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
190
- end
187
+ run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
191
188
 
192
189
  run_poetry_update_command
193
190
 
194
- return File.read("poetry.lock") if File.exist?("poetry.lock")
195
-
196
- File.read("pyproject.lock")
191
+ File.read("poetry.lock")
197
192
  end
198
193
  end
199
194
  end
@@ -208,24 +203,7 @@ module Dependabot
208
203
  end
209
204
 
210
205
  def run_poetry_command(command, fingerprint: nil)
211
- start = Time.now
212
- command = SharedHelpers.escape_command(command)
213
- stdout, process = Open3.capture2e(command)
214
- time_taken = Time.now - start
215
-
216
- # Raise an error with the output from the shell session if Pipenv
217
- # returns a non-zero status
218
- return if process.success?
219
-
220
- raise SharedHelpers::HelperSubprocessFailed.new(
221
- message: stdout,
222
- error_context: {
223
- command: command,
224
- fingerprint: fingerprint,
225
- time_taken: time_taken,
226
- process_exit_value: process.to_s
227
- }
228
- )
206
+ Helpers.run_poetry_command(command, fingerprint: fingerprint)
229
207
  end
230
208
 
231
209
  def write_temporary_dependency_files(pyproject_content)
@@ -315,17 +293,13 @@ module Dependabot
315
293
  end
316
294
 
317
295
  def lockfile
318
- @lockfile ||= pyproject_lock || poetry_lock
296
+ @lockfile ||= poetry_lock
319
297
  end
320
298
 
321
299
  def python_helper_path
322
300
  NativeHelpers.python_helper_path
323
301
  end
324
302
 
325
- def pyproject_lock
326
- dependency_files.find { |f| f.name == "pyproject.lock" }
327
- end
328
-
329
303
  def poetry_lock
330
304
  dependency_files.find { |f| f.name == "poetry.lock" }
331
305
  end
@@ -77,7 +77,7 @@ module Dependabot
77
77
 
78
78
  def subdependency_resolver
79
79
  return :pipfile if pipfile_lock
80
- return :poetry if poetry_lock || pyproject_lock
80
+ return :poetry if poetry_lock
81
81
  return :pip_compile if pip_compile_files.any?
82
82
 
83
83
  raise "Claimed to be a sub-dependency, but no lockfile exists!"
@@ -144,10 +144,6 @@ module Dependabot
144
144
  @pyproject ||= get_original_file("pyproject.toml")
145
145
  end
146
146
 
147
- def pyproject_lock
148
- @pyproject_lock ||= get_original_file("pyproject.lock")
149
- end
150
-
151
147
  def poetry_lock
152
148
  @poetry_lock ||= get_original_file("poetry.lock")
153
149
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+ require "open3"
5
+
6
+ require "dependabot/errors"
7
+ require "dependabot/shared_helpers"
8
+
9
+ module Dependabot
10
+ module Python
11
+ module Helpers
12
+ def self.run_poetry_command(command, fingerprint: nil)
13
+ start = Time.now
14
+ command = SharedHelpers.escape_command(command)
15
+ stdout, stderr, process = Open3.capture3(command)
16
+ time_taken = Time.now - start
17
+
18
+ # Raise an error with the output from the shell session if Poetry
19
+ # returns a non-zero status
20
+ return stdout if process.success?
21
+
22
+ raise SharedHelpers::HelperSubprocessFailed.new(
23
+ message: stderr,
24
+ error_context: {
25
+ command: command,
26
+ fingerprint: fingerprint,
27
+ time_taken: time_taken,
28
+ process_exit_value: process.to_s
29
+ }
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,6 +6,14 @@ require "dependabot/python/version"
6
6
  module Dependabot
7
7
  module Python
8
8
  class LanguageVersionManager
9
+ # This list must match the versions specified at the top of `python/Dockerfile`
10
+ PRE_INSTALLED_PYTHON_VERSIONS = %w(
11
+ 3.11.4
12
+ 3.10.12
13
+ 3.9.17
14
+ 3.8.17
15
+ ).freeze
16
+
9
17
  def initialize(python_requirement_parser:)
10
18
  @python_requirement_parser = python_requirement_parser
11
19
  end
@@ -14,22 +22,9 @@ module Dependabot
14
22
  # The leading space is important in the version check
15
23
  return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_major_minor}.")
16
24
 
17
- if File.exist?("/usr/local/.pyenv/#{python_major_minor}.tar.gz")
18
- SharedHelpers.run_shell_command(
19
- "tar xzf /usr/local/.pyenv/#{python_major_minor}.tar.gz -C /usr/local/.pyenv/"
20
- )
21
- return if SharedHelpers.run_shell_command("pyenv versions").
22
- include?(" #{python_major_minor}.")
23
- end
24
-
25
- Dependabot.logger.info("Installing required Python #{python_version}.")
26
- start = Time.now
27
- SharedHelpers.run_shell_command("pyenv install -s #{python_version}")
28
- SharedHelpers.run_shell_command("pyenv exec pip install --upgrade pip")
29
- SharedHelpers.run_shell_command("pyenv exec pip install -r" \
30
- "#{NativeHelpers.python_requirements_path}")
31
- time_taken = Time.now - start
32
- Dependabot.logger.info("Installing Python #{python_version} took #{time_taken}s.")
25
+ SharedHelpers.run_shell_command(
26
+ "tar xzf /usr/local/.pyenv/#{python_major_minor}.tar.gz -C /usr/local/.pyenv/"
27
+ )
33
28
  end
34
29
 
35
30
  def python_major_minor
@@ -48,42 +43,27 @@ module Dependabot
48
43
  else
49
44
  user_specified_python_version
50
45
  end
51
- elsif python_version_matching_imputed_requirements
52
- python_version_matching_imputed_requirements
53
46
  else
54
- PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
47
+ python_version_matching_imputed_requirements || PRE_INSTALLED_PYTHON_VERSIONS.first
55
48
  end
56
49
  end
57
50
 
58
51
  def python_version_from_supported_versions
59
52
  requirement_string = python_requirement_string
60
53
 
61
- # Ideally, the requirement is satisfied by a Python version we support
62
- requirement =
63
- Python::Requirement.requirements_array(requirement_string).first
64
- version =
65
- PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
66
- find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
67
- return version if version
54
+ # If the requirement string isn't already a range (eg ">3.10"), coerce it to "major.minor.*".
55
+ # The patch version is ignored because a non-matching patch version is unlikely to affect resolution.
56
+ requirement_string = requirement_string.gsub(/\.\d+$/, ".*") if requirement_string.start_with?(/\d/)
68
57
 
69
- # If not, and we're dealing with a simple version string
70
- # and changing the patch version would fix things, we do that
71
- # as the patch version is unlikely to affect resolution
72
- if requirement_string.start_with?(/\d/)
73
- requirement =
74
- Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
75
- version =
76
- PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
77
- find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
78
- return version if version
79
- end
58
+ # Try to match one of our pre-installed Python versions
59
+ requirement = Python::Requirement.requirements_array(requirement_string).first
60
+ version = PRE_INSTALLED_PYTHON_VERSIONS.find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
61
+ return version if version
80
62
 
81
- # Otherwise we have to raise, giving details of the Python versions
82
- # that Dependabot supports
83
- msg = "Dependabot detected the following Python requirement " \
84
- "for your project: '#{requirement_string}'.\n\nCurrently, the " \
85
- "following Python versions are supported in Dependabot: " \
86
- "#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
63
+ # Otherwise we have to raise
64
+ msg = "Dependabot detected the following Python requirement for your project: '#{python_requirement_string}'." \
65
+ "\n\nCurrently, the following Python versions are supported in Dependabot: " \
66
+ "#{PRE_INSTALLED_PYTHON_VERSIONS.map { |x| x.gsub(/\.\d+$/, '.*') }.join(', ')}."
87
67
  raise DependencyFileNotResolvable, msg
88
68
  end
89
69
 
@@ -100,7 +80,7 @@ module Dependabot
100
80
  end
101
81
 
102
82
  def python_version_matching(requirements)
103
- PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
83
+ PRE_INSTALLED_PYTHON_VERSIONS.find do |version_string|
104
84
  version = Python::Version.new(version_string)
105
85
  requirements.all? do |req|
106
86
  next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
@@ -118,6 +118,9 @@ module Dependabot
118
118
  []
119
119
 
120
120
  sources.each do |source|
121
+ # If source is PyPI, skip it, and let it pick the default URI
122
+ next if source["name"].casecmp?("PyPI")
123
+
121
124
  if source["default"]
122
125
  urls[:main] = source["url"]
123
126
  else
@@ -13,7 +13,6 @@ require "dependabot/python/version"
13
13
  require "dependabot/shared_helpers"
14
14
  require "dependabot/python/language_version_manager"
15
15
  require "dependabot/python/native_helpers"
16
- require "dependabot/python/python_versions"
17
16
  require "dependabot/python/name_normaliser"
18
17
  require "dependabot/python/authed_url_builder"
19
18
 
@@ -23,7 +22,6 @@ module Dependabot
23
22
  # This class does version resolution for pip-compile. Its approach is:
24
23
  # - Unlock the dependency we're checking in the requirements.in file
25
24
  # - Run `pip-compile` and see what the result is
26
- # rubocop:disable Metrics/ClassLength
27
25
  class PipCompileVersionResolver
28
26
  GIT_DEPENDENCY_UNREACHABLE_REGEX = /git clone --filter=blob:none --quiet (?<url>[^\s]+).* /
29
27
  GIT_REFERENCE_NOT_FOUND_REGEX = /Did not find branch or tag '(?<tag>[^\n"]+)'/m
@@ -236,10 +234,6 @@ module Dependabot
236
234
  )
237
235
  end
238
236
 
239
- def new_resolver_supported?
240
- language_version_manager.python_version >= Python::Version.new("3.7")
241
- end
242
-
243
237
  def pip_compile_options_fingerprint(options)
244
238
  options.sub(
245
239
  /--output-file=\S+/, "--output-file=<output_file>"
@@ -253,8 +247,9 @@ module Dependabot
253
247
  def pip_compile_options(filename)
254
248
  options = @build_isolation ? ["--build-isolation"] : ["--no-build-isolation"]
255
249
  options += pip_compile_index_options
250
+ # TODO: Stop explicitly specifying `allow-unsafe` once it becomes the default:
251
+ # https://github.com/jazzband/pip-tools/issues/989#issuecomment-1661254701
256
252
  options += ["--allow-unsafe"]
257
- options += ["--resolver backtracking"] if new_resolver_supported?
258
253
 
259
254
  if (requirements_file = compiled_file_for_filename(filename))
260
255
  options << "--output-file=#{requirements_file.name}"
@@ -502,7 +497,6 @@ module Dependabot
502
497
  dependency_files.select { |f| f.name.end_with?("setup.cfg") }
503
498
  end
504
499
  end
505
- # rubocop:enable Metrics/ClassLength
506
500
  end
507
501
  end
508
502
  end
@@ -11,7 +11,6 @@ require "dependabot/python/file_parser/python_requirement_parser"
11
11
  require "dependabot/python/file_updater/pipfile_preparer"
12
12
  require "dependabot/python/file_updater/setup_file_sanitizer"
13
13
  require "dependabot/python/update_checker"
14
- require "dependabot/python/python_versions"
15
14
  require "dependabot/python/native_helpers"
16
15
  require "dependabot/python/name_normaliser"
17
16
  require "dependabot/python/version"
@@ -40,7 +39,7 @@ module Dependabot
40
39
 
41
40
  UNSUPPORTED_DEPS = %w(pyobjc).freeze
42
41
  UNSUPPORTED_DEP_REGEX =
43
- /Could not find a version that satisfies the requirement.*(?:#{UNSUPPORTED_DEPS.join("|")})/
42
+ /Could not find a version that satisfies the requirement.*(?:#{UNSUPPORTED_DEPS.join('|')})/
44
43
  PIPENV_RANGE_WARNING = /Warning:\sPython\s[<>].* was not found/
45
44
  # rubocop:enable Layout/LineLength
46
45
 
@@ -208,15 +207,13 @@ module Dependabot
208
207
  # errors when failing to update
209
208
  def check_original_requirements_resolvable
210
209
  SharedHelpers.in_a_temporary_directory do
211
- SharedHelpers.with_git_configured(credentials: credentials) do
212
- write_temporary_dependency_files(update_pipfile: false)
210
+ write_temporary_dependency_files(update_pipfile: false)
213
211
 
214
- run_pipenv_command("pyenv exec pipenv lock")
212
+ run_pipenv_command("pyenv exec pipenv lock")
215
213
 
216
- true
217
- rescue SharedHelpers::HelperSubprocessFailed => e
218
- handle_pipenv_errors_resolving_original_reqs(e)
219
- end
214
+ true
215
+ rescue SharedHelpers::HelperSubprocessFailed => e
216
+ handle_pipenv_errors_resolving_original_reqs(e)
220
217
  end
221
218
  end
222
219
 
@@ -13,8 +13,8 @@ require "dependabot/python/file_updater/pyproject_preparer"
13
13
  require "dependabot/python/update_checker"
14
14
  require "dependabot/python/version"
15
15
  require "dependabot/python/requirement"
16
+ require "dependabot/python/helpers"
16
17
  require "dependabot/python/native_helpers"
17
- require "dependabot/python/python_versions"
18
18
  require "dependabot/python/authed_url_builder"
19
19
  require "dependabot/python/name_normaliser"
20
20
 
@@ -24,30 +24,19 @@ module Dependabot
24
24
  # This class does version resolution for pyproject.toml files.
25
25
  class PoetryVersionResolver
26
26
  GIT_REFERENCE_NOT_FOUND_REGEX = /
27
- (?:'git'.*pypoetry-git-(?<name>.+?).{8}',
28
- 'checkout',
29
- '(?<tag>.+?)'
30
- |
31
- Failed to checkout
27
+ (Failed to checkout
32
28
  (?<tag>.+?)
33
29
  (?<url>.+?).git at '(?<tag>.+?)'
34
30
  |
35
31
  ...Failedtoclone
36
32
  (?<url>.+?).gitat'(?<tag>.+?)',
37
33
  verifyrefexistsonremote)
38
- /x # TODO: remove the first clause and | when py3.6 support is EoL
34
+ /x
39
35
  GIT_DEPENDENCY_UNREACHABLE_REGEX = /
40
- (?:'\['git',
41
- \s+'clone',
42
- \s+'--recurse-submodules',
43
- \s+'(--)?',
44
- \s+'(?<url>.+?)'.*
45
- \s+exit\s+status\s+128
46
- |
47
36
  \s+Failed\sto\sclone
48
37
  \s+(?<url>.+?),
49
- \s+check\syour\sgit\sconfiguration)
50
- /mx # TODO: remove the first clause and | when py3.6 support is EoL
38
+ \s+check\syour\sgit\sconfiguration
39
+ /mx
51
40
 
52
41
  attr_reader :dependency, :dependency_files, :credentials
53
42
 
@@ -74,8 +63,7 @@ module Dependabot
74
63
  false
75
64
  end
76
65
  rescue SharedHelpers::HelperSubprocessFailed => e
77
- raise unless e.message.include?("SolverProblemError") || # TODO: Remove once py3.6 is EoL
78
- e.message.include?("version solving failed.")
66
+ raise unless e.message.include?("version solving failed.")
79
67
 
80
68
  @resolvable[version] = false
81
69
  end
@@ -95,18 +83,12 @@ module Dependabot
95
83
  language_version_manager.install_required_python
96
84
 
97
85
  # use system git instead of the pure Python dulwich
98
- unless language_version_manager.python_version&.start_with?("3.6")
99
- run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
100
- end
86
+ run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
101
87
 
102
88
  # Shell out to Poetry, which handles everything for us.
103
89
  run_poetry_update_command
104
90
 
105
- updated_lockfile =
106
- if File.exist?("poetry.lock") then File.read("poetry.lock")
107
- else
108
- File.read("pyproject.lock")
109
- end
91
+ updated_lockfile = File.read("poetry.lock")
110
92
  updated_lockfile = TomlRB.parse(updated_lockfile)
111
93
 
112
94
  fetch_version_from_parsed_lockfile(updated_lockfile)
@@ -147,7 +129,7 @@ module Dependabot
147
129
  end
148
130
 
149
131
  raise unless error.message.include?("SolverProblemError") ||
150
- error.message.include?("PackageNotFound") ||
132
+ error.message.include?("not found") ||
151
133
  error.message.include?("version solving failed.")
152
134
 
153
135
  check_original_requirements_resolvable
@@ -174,20 +156,18 @@ module Dependabot
174
156
  return @original_reqs_resolvable if @original_reqs_resolvable
175
157
 
176
158
  SharedHelpers.in_a_temporary_directory do
177
- SharedHelpers.with_git_configured(credentials: credentials) do
178
- write_temporary_dependency_files(update_pyproject: false)
159
+ write_temporary_dependency_files(update_pyproject: false)
179
160
 
180
- run_poetry_update_command
161
+ run_poetry_update_command
181
162
 
182
- @original_reqs_resolvable = true
183
- rescue SharedHelpers::HelperSubprocessFailed => e
184
- raise unless e.message.include?("SolverProblemError") ||
185
- e.message.include?("PackageNotFound") ||
186
- e.message.include?("version solving failed.")
163
+ @original_reqs_resolvable = true
164
+ rescue SharedHelpers::HelperSubprocessFailed => e
165
+ raise unless e.message.include?("SolverProblemError") ||
166
+ e.message.include?("not found") ||
167
+ e.message.include?("version solving failed.")
187
168
 
188
- msg = clean_error_message(e.message)
189
- raise DependencyFileNotResolvable, msg
190
- end
169
+ msg = clean_error_message(e.message)
170
+ raise DependencyFileNotResolvable, msg
191
171
  end
192
172
  end
193
173
 
@@ -249,7 +229,7 @@ module Dependabot
249
229
  def update_python_requirement(pyproject_content)
250
230
  Python::FileUpdater::PyprojectPreparer.
251
231
  new(pyproject_content: pyproject_content).
252
- update_python_requirement(language_version_manager.python_major_minor)
232
+ update_python_requirement(language_version_manager.python_version)
253
233
  end
254
234
 
255
235
  def freeze_other_dependencies(pyproject_content)
@@ -298,12 +278,7 @@ module Dependabot
298
278
  end
299
279
 
300
280
  def subdep_type
301
- category =
302
- TomlRB.parse(lockfile.content).fetch("package", []).
303
- find { |dets| normalise(dets.fetch("name")) == dependency.name }.
304
- fetch("category")
305
-
306
- category == "dev" ? "dev-dependencies" : "dependencies"
281
+ dependency.production? ? "dependencies" : "dev-dependencies"
307
282
  end
308
283
 
309
284
  def python_requirement_parser
@@ -324,37 +299,16 @@ module Dependabot
324
299
  dependency_files.find { |f| f.name == "pyproject.toml" }
325
300
  end
326
301
 
327
- def pyproject_lock
328
- dependency_files.find { |f| f.name == "pyproject.lock" }
329
- end
330
-
331
302
  def poetry_lock
332
303
  dependency_files.find { |f| f.name == "poetry.lock" }
333
304
  end
334
305
 
335
306
  def lockfile
336
- poetry_lock || pyproject_lock
307
+ poetry_lock
337
308
  end
338
309
 
339
310
  def run_poetry_command(command, fingerprint: nil)
340
- start = Time.now
341
- command = SharedHelpers.escape_command(command)
342
- stdout, process = Open3.capture2e(command)
343
- time_taken = Time.now - start
344
-
345
- # Raise an error with the output from the shell session if poetry
346
- # returns a non-zero status
347
- return if process.success?
348
-
349
- raise SharedHelpers::HelperSubprocessFailed.new(
350
- message: stdout,
351
- error_context: {
352
- command: command,
353
- fingerprint: fingerprint,
354
- time_taken: time_taken,
355
- process_exit_value: process.to_s
356
- }
357
- )
311
+ Helpers.run_poetry_command(command, fingerprint: fingerprint)
358
312
  end
359
313
 
360
314
  def normalise(name)
@@ -74,7 +74,7 @@ module Dependabot
74
74
  requirements: requirements,
75
75
  latest_resolvable_version: preferred_resolvable_version&.to_s,
76
76
  update_strategy: requirements_update_strategy,
77
- has_lockfile: !(pipfile_lock || poetry_lock || pyproject_lock).nil?
77
+ has_lockfile: !(pipfile_lock || poetry_lock).nil?
78
78
  ).updated_requirements
79
79
  end
80
80
 
@@ -143,7 +143,7 @@ module Dependabot
143
143
 
144
144
  def subdependency_resolver
145
145
  return :pipenv if pipfile_lock
146
- return :poetry if poetry_lock || pyproject_lock
146
+ return :poetry if poetry_lock
147
147
  return :pip_compile if pip_compile_files.any?
148
148
 
149
149
  raise "Claimed to be a sub-dependency, but no lockfile exists!"
@@ -257,7 +257,7 @@ module Dependabot
257
257
  end
258
258
 
259
259
  def library?
260
- return unless updating_pyproject?
260
+ return false unless updating_pyproject?
261
261
 
262
262
  # Hit PyPi and check whether there are details for a library with a
263
263
  # matching name and description
@@ -315,10 +315,6 @@ module Dependabot
315
315
  dependency_files.find { |f| f.name == "pyproject.toml" }
316
316
  end
317
317
 
318
- def pyproject_lock
319
- dependency_files.find { |f| f.name == "pyproject.lock" }
320
- end
321
-
322
318
  def poetry_lock
323
319
  dependency_files.find { |f| f.name == "poetry.lock" }
324
320
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-python
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.226.0
4
+ version: 0.228.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-11 00:00:00.000000000 Z
11
+ date: 2023-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.226.0
19
+ version: 0.228.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.226.0
26
+ version: 0.228.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -114,28 +114,28 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.50.0
117
+ version: 1.56.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.50.0
124
+ version: 1.56.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-performance
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.18.0
131
+ version: 1.19.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.18.0
138
+ version: 1.19.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: stackprof
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -210,11 +210,11 @@ files:
210
210
  - lib/dependabot/python/file_updater/requirement_file_updater.rb
211
211
  - lib/dependabot/python/file_updater/requirement_replacer.rb
212
212
  - lib/dependabot/python/file_updater/setup_file_sanitizer.rb
213
+ - lib/dependabot/python/helpers.rb
213
214
  - lib/dependabot/python/language_version_manager.rb
214
215
  - lib/dependabot/python/metadata_finder.rb
215
216
  - lib/dependabot/python/name_normaliser.rb
216
217
  - lib/dependabot/python/native_helpers.rb
217
- - lib/dependabot/python/python_versions.rb
218
218
  - lib/dependabot/python/requirement.rb
219
219
  - lib/dependabot/python/requirement_parser.rb
220
220
  - lib/dependabot/python/update_checker.rb
@@ -231,7 +231,7 @@ licenses:
231
231
  - Nonstandard
232
232
  metadata:
233
233
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
234
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.226.0
234
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.228.0
235
235
  post_install_message:
236
236
  rdoc_options: []
237
237
  require_paths:
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dependabot
4
- module Python
5
- module PythonVersions
6
- PRE_INSTALLED_PYTHON_VERSIONS = %w(
7
- 3.11.4
8
- ).freeze
9
-
10
- # Due to an OpenSSL issue we can only install the following versions in
11
- # the Dependabot container.
12
- # NOTE: When adding one version, always doublecheck for additional releases: https://www.python.org/downloads/
13
- #
14
- # WARNING: 3.9.3 is purposefully omitted as it was recalled: https://www.python.org/downloads/release/python-393/
15
- SUPPORTED_VERSIONS = %w(
16
- 3.11.4 3.11.3 3.11.2 3.11.1 3.11.0
17
- 3.10.12 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.17 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.17 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.17 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
- 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
- 3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
23
- ).freeze
24
-
25
- # This list gets iterated through to find a valid version, so we have
26
- # the pre-installed versions listed first.
27
- SUPPORTED_VERSIONS_TO_ITERATE =
28
- [
29
- *PRE_INSTALLED_PYTHON_VERSIONS,
30
- *SUPPORTED_VERSIONS
31
- ].freeze
32
- end
33
- end
34
- end