dependabot-python 0.226.0 → 0.228.0

Sign up to get free protection for your applications and to get access to all the features.
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