dependabot-python 0.212.0 → 0.213.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/build +1 -6
  3. data/helpers/lib/parser.py +52 -0
  4. data/helpers/requirements.txt +3 -3
  5. data/helpers/run.py +2 -0
  6. data/lib/dependabot/python/file_fetcher.rb +21 -12
  7. data/lib/dependabot/python/file_parser/{poetry_files_parser.rb → pyproject_files_parser.rb} +83 -2
  8. data/lib/dependabot/python/file_parser/setup_file_parser.rb +4 -4
  9. data/lib/dependabot/python/file_parser.rb +5 -29
  10. data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +5 -20
  11. data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +1 -5
  12. data/lib/dependabot/python/file_updater/poetry_file_updater.rb +7 -6
  13. data/lib/dependabot/python/file_updater/pyproject_preparer.rb +1 -1
  14. data/lib/dependabot/python/file_updater.rb +14 -1
  15. data/lib/dependabot/python/helpers.rb +20 -0
  16. data/lib/dependabot/python/metadata_finder.rb +2 -0
  17. data/lib/dependabot/python/python_versions.rb +5 -5
  18. data/lib/dependabot/python/requirement.rb +7 -4
  19. data/lib/dependabot/python/requirement_parser.rb +20 -23
  20. data/lib/dependabot/python/update_checker/index_finder.rb +1 -1
  21. data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +17 -19
  22. data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +7 -16
  23. data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +13 -11
  24. data/lib/dependabot/python/update_checker/requirements_updater.rb +17 -4
  25. data/lib/dependabot/python/update_checker.rb +82 -25
  26. data/lib/dependabot/python/version.rb +2 -2
  27. metadata +15 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4862b59513a97a33d51ff8ad57b6d9815842769c87f612426ffbcd8e75a9655c
4
- data.tar.gz: 9543935b3ab8027344757b41aa8ff265d823beac956a06d20d4917e75962698d
3
+ metadata.gz: 6cb23890c79504e40e7e4962485003c76c07179574ac89b210b6529d15d2c216
4
+ data.tar.gz: b96523f9cf991cbffc38fc2831221c43450c74ef560e8e80ff2d2bbf73c889c4
5
5
  SHA512:
6
- metadata.gz: fd9e547d19f01addfdc2fcc4eeb7095bf8e886eded086772f81b9bfbd6acfb2fc6076c354c970ae5fad0691a25679d99db8eb0884121e986c1bcf39b17c041ba
7
- data.tar.gz: be587fe031f132dd20d4fc023668e31d81c37608d915a9f586ca159b675302993a208b6e93209cfaedad83d08eaae1ca06f6af7eec8933bcc2c44e8a61293ccf
6
+ metadata.gz: 5beeac4ec63193ce095e6a5d7223c11e4e9c2ace55b3ef5c94f0011d8cb0c70fc7b364108b68cd68f656a5ed79d712b64eecbb75998714325a0f3b101169592c
7
+ data.tar.gz: 17ec5483c750fe4bc35490feebf418a8bd7eaf0eb2d14e2bcfc811e06f94c02f69eca71bafb589cb2d51b8a73155d3d358b97fcc6125a8fb7229b54f06a42fbe
data/helpers/build CHANGED
@@ -18,9 +18,4 @@ cp -r \
18
18
  "$install_dir"
19
19
 
20
20
  cd "$install_dir"
21
- PYENV_VERSION=3.10.5 pyenv exec pip --disable-pip-version-check install -r "requirements.txt"
22
-
23
- # Workaround of https://github.com/python-poetry/poetry/issues/3010
24
- # By default poetry config file is stored under ~/.config/pypoetry
25
- # and is not bound to any specific Python version
26
- PYENV_VERSION=3.10.5 pyenv exec poetry config experimental.new-installer false
21
+ PYENV_VERSION=3.10.7 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
@@ -11,11 +11,63 @@ from pip._internal.req.constructors import (
11
11
  install_req_from_line,
12
12
  install_req_from_parsed_requirement,
13
13
  )
14
+
15
+ from packaging.requirements import InvalidRequirement, Requirement
16
+ import toml
17
+
14
18
  # Inspired by pips internal check:
15
19
  # https://github.com/pypa/pip/blob/0bb3ac87f5bb149bd75cceac000844128b574385/src/pip/_internal/req/req_file.py#L35
16
20
  COMMENT_RE = re.compile(r'(^|\s+)#.*$')
17
21
 
18
22
 
23
+ def parse_pep621_dependencies(pyproject_path):
24
+ project_toml = toml.load(pyproject_path)['project']
25
+
26
+ def parse_toml_section_pep621_dependencies(pyproject_path, dependencies):
27
+ requirement_packages = []
28
+
29
+ def version_from_req(specifier_set):
30
+ if (len(specifier_set) == 1 and
31
+ next(iter(specifier_set)).operator in {"==", "==="}):
32
+ return next(iter(specifier_set)).version
33
+
34
+ for dependency in dependencies:
35
+ try:
36
+ req = Requirement(dependency)
37
+ except InvalidRequirement as e:
38
+ print(json.dumps({"error": repr(e)}))
39
+ exit(1)
40
+ else:
41
+ requirement_packages.append({
42
+ "name": req.name,
43
+ "version": version_from_req(req.specifier),
44
+ "markers": str(req.marker) or None,
45
+ "file": pyproject_path,
46
+ "requirement": str(req.specifier),
47
+ "extras": sorted(list(req.extras))
48
+ })
49
+
50
+ return requirement_packages
51
+
52
+ dependencies = parse_toml_section_pep621_dependencies(
53
+ pyproject_path,
54
+ project_toml['dependencies']
55
+ )
56
+
57
+ if 'optional-dependencies' in project_toml:
58
+ optional_dependencies_toml = project_toml['optional-dependencies']
59
+
60
+ for group in optional_dependencies_toml:
61
+ group_dependencies = parse_toml_section_pep621_dependencies(
62
+ pyproject_path,
63
+ optional_dependencies_toml[group]
64
+ )
65
+
66
+ dependencies.extend(group_dependencies)
67
+
68
+ return json.dumps({"result": dependencies})
69
+
70
+
19
71
  def parse_requirements(directory):
20
72
  # Parse the requirements.txt
21
73
  requirement_packages = []
@@ -1,10 +1,10 @@
1
- pip>=21.3.1,<22.2.3 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
2
- pip-tools>=6.4.0,<6.8.1 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
1
+ pip>=21.3.1,<22.4.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.9.1 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
3
3
  flake8==5.0.4
4
4
  hashin==0.17.0
5
5
  pipenv==2022.4.8
6
6
  pipfile==0.0.2
7
- poetry>=1.1.15,<=1.2.0
7
+ poetry>=1.1.15,<1.3.0
8
8
  wheel==0.37.1
9
9
 
10
10
  # Some dependencies will only install if Cython is present
data/helpers/run.py CHANGED
@@ -10,6 +10,8 @@ if __name__ == "__main__":
10
10
  print(parser.parse_requirements(args["args"][0]))
11
11
  elif args["function"] == "parse_setup":
12
12
  print(parser.parse_setup(args["args"][0]))
13
+ elif args["function"] == "parse_pep621_dependencies":
14
+ print(parser.parse_pep621_dependencies(args["args"][0]))
13
15
  elif args["function"] == "get_dependency_hash":
14
16
  print(hasher.get_dependency_hash(*args["args"]))
15
17
  elif args["function"] == "get_pipfile_hash":
@@ -5,15 +5,15 @@ require "toml-rb"
5
5
  require "dependabot/file_fetchers"
6
6
  require "dependabot/file_fetchers/base"
7
7
  require "dependabot/python/requirement_parser"
8
- require "dependabot/python/file_parser/poetry_files_parser"
8
+ require "dependabot/python/file_parser/pyproject_files_parser"
9
9
  require "dependabot/errors"
10
10
 
11
11
  module Dependabot
12
12
  module Python
13
13
  class FileFetcher < Dependabot::FileFetchers::Base
14
- CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/.freeze
15
- CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/.freeze
16
- DEPENDENCY_TYPES = %w(packages dev-packages).freeze
14
+ CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/
15
+ CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/
16
+ DEPENDENCY_TYPES = %w(packages dev-packages)
17
17
 
18
18
  def self.required_files_in?(filenames)
19
19
  return true if filenames.any? { |name| name.end_with?(".txt", ".in") }
@@ -24,7 +24,7 @@ module Dependabot
24
24
  # If this repo is using a Pipfile return true
25
25
  return true if filenames.include?("Pipfile")
26
26
 
27
- # If this repo is using Poetry return true
27
+ # If this repo is using pyproject.toml return true
28
28
  return true if filenames.include?("pyproject.toml")
29
29
 
30
30
  return true if filenames.include?("setup.py")
@@ -69,7 +69,7 @@ module Dependabot
69
69
  end
70
70
 
71
71
  def pyproject_files
72
- [pyproject, pyproject_lock, poetry_lock].compact
72
+ [pyproject, pyproject_lock, poetry_lock, pdm_lock].compact
73
73
  end
74
74
 
75
75
  def requirement_files
@@ -81,7 +81,12 @@ module Dependabot
81
81
  end
82
82
 
83
83
  def check_required_files_present
84
- return if requirements_txt_files.any? || setup_file || setup_cfg_file || pipfile || pyproject
84
+ return if requirements_txt_files.any? ||
85
+ requirements_in_files.any? ||
86
+ setup_file ||
87
+ setup_cfg_file ||
88
+ pipfile ||
89
+ pyproject
85
90
 
86
91
  path = Pathname.new(File.join(directory, "requirements.txt")).
87
92
  cleanpath.to_path
@@ -136,6 +141,10 @@ module Dependabot
136
141
  @poetry_lock ||= fetch_file_if_present("poetry.lock")
137
142
  end
138
143
 
144
+ def pdm_lock
145
+ @pdm_lock ||= fetch_file_if_present("pdm.lock")
146
+ end
147
+
139
148
  def requirements_txt_files
140
149
  req_txt_and_in_files.select { |f| f.name.end_with?(".txt") }
141
150
  end
@@ -169,7 +178,7 @@ module Dependabot
169
178
  repo_contents.
170
179
  select { |f| f.type == "file" }.
171
180
  select { |f| f.name.end_with?(".txt", ".in") }.
172
- reject { |f| f.size > 200_000 }.
181
+ reject { |f| f.size > 500_000 }.
173
182
  map { |f| fetch_file_from_host(f.name) }.
174
183
  select { |f| requirements_file?(f) }.
175
184
  each { |f| @req_txt_and_in_files << f }
@@ -189,7 +198,7 @@ module Dependabot
189
198
  repo_contents(dir: relative_reqs_dir).
190
199
  select { |f| f.type == "file" }.
191
200
  select { |f| f.name.end_with?(".txt", ".in") }.
192
- reject { |f| f.size > 200_000 }.
201
+ reject { |f| f.size > 500_000 }.
193
202
  map { |f| fetch_file_from_host("#{relative_reqs_dir}/#{f.name}") }.
194
203
  select { |f| requirements_file?(f) }
195
204
  end
@@ -291,8 +300,8 @@ module Dependabot
291
300
  fetch_submodules: true
292
301
  ).tap { |f| f.support_file = true }
293
302
  rescue Dependabot::DependencyFileNotFound
294
- # For Poetry projects attempt to fetch a pyproject.toml at the
295
- # given path instead of a setup.py. We do not require a
303
+ # For projects with pyproject.toml attempt to fetch a pyproject.toml
304
+ # at the given path instead of a setup.py. We do not require a
296
305
  # setup.py to be present, so if none can be found, simply return
297
306
  return [] unless allow_pyproject
298
307
 
@@ -390,7 +399,7 @@ module Dependabot
390
399
  return [] unless pyproject
391
400
 
392
401
  paths = []
393
- Dependabot::Python::FileParser::PoetryFilesParser::POETRY_DEPENDENCY_TYPES.each do |dep_type|
402
+ Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |dep_type|
394
403
  next unless parsed_pyproject.dig("tool", "poetry", dep_type)
395
404
 
396
405
  parsed_pyproject.dig("tool", "poetry", dep_type).each do |_, req|
@@ -12,7 +12,7 @@ require "dependabot/python/name_normaliser"
12
12
  module Dependabot
13
13
  module Python
14
14
  class FileParser
15
- class PoetryFilesParser
15
+ class PyprojectFilesParser
16
16
  POETRY_DEPENDENCY_TYPES = %w(dependencies dev-dependencies).freeze
17
17
 
18
18
  # https://python-poetry.org/docs/dependency-specification/
@@ -25,7 +25,7 @@ module Dependabot
25
25
  def dependency_set
26
26
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new
27
27
 
28
- dependency_set += pyproject_dependencies
28
+ dependency_set += pyproject_dependencies if using_poetry? || using_pep621?
29
29
  dependency_set += lockfile_dependencies if lockfile
30
30
 
31
31
  dependency_set
@@ -36,6 +36,14 @@ module Dependabot
36
36
  attr_reader :dependency_files
37
37
 
38
38
  def pyproject_dependencies
39
+ if using_poetry?
40
+ poetry_dependencies
41
+ else
42
+ pep621_dependencies
43
+ end
44
+ end
45
+
46
+ def poetry_dependencies
39
47
  dependencies = Dependabot::FileParsers::Base::DependencySet.new
40
48
 
41
49
  POETRY_DEPENDENCY_TYPES.each do |type|
@@ -59,6 +67,44 @@ module Dependabot
59
67
  dependencies
60
68
  end
61
69
 
70
+ def pep621_dependencies
71
+ dependencies = Dependabot::FileParsers::Base::DependencySet.new
72
+
73
+ # PDM is not yet supported, so we want to ignore it for now because in
74
+ # the current state of things, going on would result in updating
75
+ # pyproject.toml but leaving pdm.lock out of sync, which is
76
+ # undesirable. Leave PDM alone until properly supported
77
+ return dependencies if using_pdm?
78
+
79
+ parsed_pep621_dependencies.each do |dep|
80
+ # If a requirement has a `<` or `<=` marker then updating it is
81
+ # probably blocked. Ignore it.
82
+ next if dep["markers"].include?("<")
83
+
84
+ # If no requirement, don't add it
85
+ next if dep["requirement"].empty?
86
+
87
+ dependencies <<
88
+ Dependency.new(
89
+ name: normalised_name(dep["name"], dep["extras"]),
90
+ version: dep["version"]&.include?("*") ? nil : dep["version"],
91
+ requirements: [{
92
+ requirement: dep["requirement"],
93
+ file: Pathname.new(dep["file"]).cleanpath.to_path,
94
+ source: nil,
95
+ groups: [dep["requirement_type"]]
96
+ }],
97
+ package_manager: "pip"
98
+ )
99
+ end
100
+
101
+ dependencies
102
+ end
103
+
104
+ def normalised_name(name, extras)
105
+ NameNormaliser.normalise_including_extras(name, extras)
106
+ end
107
+
62
108
  # @param req can be an Array, Hash or String that represents the constraints for a dependency
63
109
  def parse_requirements_from(req, type)
64
110
  [req].flatten.compact.filter_map do |requirement|
@@ -75,6 +121,18 @@ module Dependabot
75
121
  end
76
122
  end
77
123
 
124
+ def using_poetry?
125
+ !parsed_pyproject.dig("tool", "poetry").nil?
126
+ end
127
+
128
+ def using_pep621?
129
+ !parsed_pyproject.dig("project", "dependencies").nil?
130
+ end
131
+
132
+ def using_pdm?
133
+ using_pep621? && pdm_lock
134
+ end
135
+
78
136
  # Create a DependencySet where each element has no requirement. Any
79
137
  # requirements will be added when combining the DependencySet with
80
138
  # other DependencySets.
@@ -146,6 +204,24 @@ module Dependabot
146
204
  poetry_lock || pyproject_lock
147
205
  end
148
206
 
207
+ def parsed_pep621_dependencies
208
+ SharedHelpers.in_a_temporary_directory do
209
+ write_temporary_pyproject
210
+
211
+ SharedHelpers.run_helper_subprocess(
212
+ command: "pyenv exec python #{NativeHelpers.python_helper_path}",
213
+ function: "parse_pep621_dependencies",
214
+ args: [pyproject.name]
215
+ )
216
+ end
217
+ end
218
+
219
+ def write_temporary_pyproject
220
+ path = pyproject.name
221
+ FileUtils.mkdir_p(Pathname.new(path).dirname)
222
+ File.write(path, pyproject.content)
223
+ end
224
+
149
225
  def parsed_lockfile
150
226
  return parsed_poetry_lock if poetry_lock
151
227
  return parsed_pyproject_lock if pyproject_lock
@@ -160,6 +236,11 @@ module Dependabot
160
236
  @poetry_lock ||=
161
237
  dependency_files.find { |f| f.name == "poetry.lock" }
162
238
  end
239
+
240
+ def pdm_lock
241
+ @pdm_lock ||=
242
+ dependency_files.find { |f| f.name == "pdm.lock" }
243
+ end
163
244
  end
164
245
  end
165
246
  end
@@ -12,10 +12,10 @@ module Dependabot
12
12
  module Python
13
13
  class FileParser
14
14
  class SetupFileParser
15
- INSTALL_REQUIRES_REGEX = /install_requires\s*=\s*\[/m.freeze
16
- SETUP_REQUIRES_REGEX = /setup_requires\s*=\s*\[/m.freeze
17
- TESTS_REQUIRE_REGEX = /tests_require\s*=\s*\[/m.freeze
18
- EXTRAS_REQUIRE_REGEX = /extras_require\s*=\s*\{/m.freeze
15
+ INSTALL_REQUIRES_REGEX = /install_requires\s*=\s*\[/m
16
+ SETUP_REQUIRES_REGEX = /setup_requires\s*=\s*\[/m
17
+ TESTS_REQUIRE_REGEX = /tests_require\s*=\s*\[/m
18
+ EXTRAS_REQUIRE_REGEX = /extras_require\s*=\s*\{/m
19
19
 
20
20
  CLOSING_BRACKET = { "[" => "]", "{" => "}" }.freeze
21
21
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "toml-rb"
4
3
  require "dependabot/dependency"
5
4
  require "dependabot/file_parsers"
6
5
  require "dependabot/file_parsers/base"
@@ -15,11 +14,9 @@ module Dependabot
15
14
  module Python
16
15
  class FileParser < Dependabot::FileParsers::Base
17
16
  require_relative "file_parser/pipfile_files_parser"
18
- require_relative "file_parser/poetry_files_parser"
17
+ require_relative "file_parser/pyproject_files_parser"
19
18
  require_relative "file_parser/setup_file_parser"
20
19
 
21
- POETRY_DEPENDENCY_TYPES =
22
- %w(tool.poetry.dependencies tool.poetry.dev-dependencies).freeze
23
20
  DEPENDENCY_GROUP_KEYS = [
24
21
  {
25
22
  pipfile: "packages",
@@ -42,7 +39,7 @@ module Dependabot
42
39
  dependency_set = DependencySet.new
43
40
 
44
41
  dependency_set += pipenv_dependencies if pipfile
45
- dependency_set += poetry_dependencies if using_poetry?
42
+ dependency_set += pyproject_file_dependencies if pyproject
46
43
  dependency_set += requirement_dependencies if requirement_files.any?
47
44
  dependency_set += setup_file_dependencies if setup_file || setup_cfg_file
48
45
 
@@ -62,9 +59,9 @@ module Dependabot
62
59
  dependency_set
63
60
  end
64
61
 
65
- def poetry_dependencies
66
- @poetry_dependencies ||=
67
- PoetryFilesParser.
62
+ def pyproject_file_dependencies
63
+ @pyproject_file_dependencies ||=
64
+ PyprojectFilesParser.
68
65
  new(dependency_files: dependency_files).
69
66
  dependency_set
70
67
  end
@@ -105,18 +102,6 @@ module Dependabot
105
102
  end
106
103
  end
107
104
 
108
- def included_in_pipenv_deps?(dep_name)
109
- return false unless pipfile
110
-
111
- pipenv_dependencies.dependencies.map(&:name).include?(dep_name)
112
- end
113
-
114
- def included_in_poetry_deps?(dep_name)
115
- return false unless using_poetry?
116
-
117
- poetry_dependencies.dependencies.map(&:name).include?(dep_name)
118
- end
119
-
120
105
  def blocking_marker?(dep)
121
106
  return false if dep["markers"] == "None"
122
107
  return true if dep["markers"].include?("<")
@@ -215,15 +200,6 @@ module Dependabot
215
200
  @pipfile_lock ||= get_original_file("Pipfile.lock")
216
201
  end
217
202
 
218
- def using_poetry?
219
- return false unless pyproject
220
- return true if poetry_lock || pyproject_lock
221
-
222
- !TomlRB.parse(pyproject.content).dig("tool", "poetry").nil?
223
- rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
224
- raise Dependabot::DependencyFileNotParseable, pyproject.path
225
- end
226
-
227
203
  def output_file_regex(filename)
228
204
  "--output-file[=\s]+#{Regexp.escape(filename)}(?:\s|$)"
229
205
  end
@@ -7,6 +7,7 @@ require "dependabot/python/file_fetcher"
7
7
  require "dependabot/python/file_parser/python_requirement_parser"
8
8
  require "dependabot/python/file_updater"
9
9
  require "dependabot/shared_helpers"
10
+ require "dependabot/python/helpers"
10
11
  require "dependabot/python/native_helpers"
11
12
  require "dependabot/python/python_versions"
12
13
  require "dependabot/python/name_normaliser"
@@ -22,10 +23,9 @@ module Dependabot
22
23
  require_relative "setup_file_sanitizer"
23
24
 
24
25
  UNSAFE_PACKAGES = %w(setuptools distribute pip).freeze
25
- INCOMPATIBLE_VERSIONS_REGEX = /There are incompatible versions in the resolved dependencies:.*\z/m.freeze
26
- WARNINGS = /\s*# WARNING:.*\Z/m.freeze
27
- UNSAFE_NOTE =
28
- /\s*# The following packages are considered to be unsafe.*\Z/m.freeze
26
+ INCOMPATIBLE_VERSIONS_REGEX = /There are incompatible versions in the resolved dependencies:.*\z/m
27
+ WARNINGS = /\s*# WARNING:.*\Z/m
28
+ UNSAFE_NOTE = /\s*# The following packages are considered to be unsafe.*\Z/m
29
29
 
30
30
  attr_reader :dependencies, :dependency_files, :credentials
31
31
 
@@ -66,7 +66,7 @@ module Dependabot
66
66
  def compile_new_requirement_files
67
67
  SharedHelpers.in_a_temporary_directory do
68
68
  write_updated_dependency_files
69
- install_required_python
69
+ Helpers.install_required_python(python_version)
70
70
 
71
71
  filenames_to_compile.each do |filename|
72
72
  # Shell out to pip-compile, generate a new set of requirements.
@@ -81,12 +81,6 @@ module Dependabot
81
81
  "#{SharedHelpers.escape_command(version_part)}",
82
82
  allow_unsafe_shell_command: true
83
83
  )
84
- # Run pip-compile a second time, without an update argument, to
85
- # ensure it resets the right comments.
86
- run_pip_compile_command(
87
- "pyenv exec pip-compile #{pip_compile_options(filename)} " \
88
- "#{filename}"
89
- )
90
84
  end
91
85
 
92
86
  # Remove any .python-version file before parsing the reqs
@@ -219,15 +213,6 @@ module Dependabot
219
213
  end
220
214
  end
221
215
 
222
- def install_required_python
223
- return if run_command("pyenv versions").include?("#{python_version}\n")
224
-
225
- run_command("pyenv install -s #{python_version}")
226
- run_command("pyenv exec pip install --upgrade pip")
227
- run_command("pyenv exec pip install -r " \
228
- "#{NativeHelpers.python_requirements_path}")
229
- end
230
-
231
216
  def sanitized_setup_file_content(file)
232
217
  @sanitized_setup_file_content ||= {}
233
218
  return @sanitized_setup_file_content[file.name] if @sanitized_setup_file_content[file.name]
@@ -302,11 +302,7 @@ module Dependabot
302
302
  nil
303
303
  end
304
304
 
305
- return if run_command("pyenv versions").include?("#{python_version}\n")
306
-
307
- requirements_path = NativeHelpers.python_requirements_path
308
- run_command("pyenv install -s #{python_version}")
309
- run_command("pyenv exec pip install -r #{requirements_path}")
305
+ Helpers.install_required_python(python_version)
310
306
  end
311
307
 
312
308
  def sanitized_setup_file_content(file)
@@ -4,6 +4,7 @@ require "toml-rb"
4
4
  require "open3"
5
5
  require "dependabot/dependency"
6
6
  require "dependabot/shared_helpers"
7
+ require "dependabot/python/helpers"
7
8
  require "dependabot/python/version"
8
9
  require "dependabot/python/requirement"
9
10
  require "dependabot/python/python_versions"
@@ -131,7 +132,7 @@ module Dependabot
131
132
  end
132
133
 
133
134
  def lock_declaration_to_new_version!(poetry_object, dep)
134
- Dependabot::Python::FileParser::PoetryFilesParser::POETRY_DEPENDENCY_TYPES.each do |type|
135
+ Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |type|
135
136
  names = poetry_object[type]&.keys || []
136
137
  pkg_name = names.find { |nm| normalise(nm) == dep.name }
137
138
  next unless pkg_name
@@ -170,11 +171,11 @@ module Dependabot
170
171
  write_temporary_dependency_files(pyproject_content)
171
172
  add_auth_env_vars
172
173
 
173
- if python_version && !pre_installed_python?(python_version)
174
- run_poetry_command("pyenv install -s #{python_version}")
175
- run_poetry_command("pyenv exec pip install --upgrade pip")
176
- run_poetry_command("pyenv exec pip install -r" \
177
- "#{NativeHelpers.python_requirements_path}")
174
+ Helpers.install_required_python(python_version)
175
+
176
+ # use system git instead of the pure Python dulwich
177
+ unless python_version&.start_with?("3.6")
178
+ run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
178
179
  end
179
180
 
180
181
  run_poetry_command(poetry_update_command)
@@ -52,7 +52,7 @@ module Dependabot
52
52
  poetry_object = pyproject_object["tool"]["poetry"]
53
53
  excluded_names = dependencies.map(&:name) + ["python"]
54
54
 
55
- Dependabot::Python::FileParser::PoetryFilesParser::POETRY_DEPENDENCY_TYPES.each do |key|
55
+ Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |key|
56
56
  next unless poetry_object[key]
57
57
 
58
58
  source_types = %w(directory file url)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "toml-rb"
3
4
  require "dependabot/file_updaters"
4
5
  require "dependabot/file_updaters/base"
5
6
  require "dependabot/shared_helpers"
@@ -61,7 +62,13 @@ module Dependabot
61
62
  # Otherwise, this is a top-level dependency, and we can figure out
62
63
  # which resolver to use based on the filename of its requirements
63
64
  return :pipfile if changed_req_files.any?("Pipfile")
64
- return :poetry if changed_req_files.any?("pyproject.toml")
65
+
66
+ if changed_req_files.any?("pyproject.toml")
67
+ return :poetry if poetry_based?
68
+
69
+ return :requirements
70
+ end
71
+
65
72
  return :pip_compile if changed_req_files.any? { |f| f.end_with?(".in") }
66
73
 
67
74
  :requirements
@@ -119,6 +126,12 @@ module Dependabot
119
126
  raise "Missing required files!"
120
127
  end
121
128
 
129
+ def poetry_based?
130
+ return false unless pyproject
131
+
132
+ !TomlRB.parse(pyproject.content).dig("tool", "poetry").nil?
133
+ end
134
+
122
135
  def pipfile
123
136
  @pipfile ||= get_original_file("Pipfile")
124
137
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/logger"
4
+
5
+ module Dependabot
6
+ module Python
7
+ module Helpers
8
+ def self.install_required_python(python_version)
9
+ # The leading space is important in the version check
10
+ return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_version}")
11
+
12
+ Dependabot.logger.info("Installing required Python #{python_version}.")
13
+ SharedHelpers.run_shell_command("pyenv install -s #{python_version}")
14
+ SharedHelpers.run_shell_command("pyenv exec pip install --upgrade pip")
15
+ SharedHelpers.run_shell_command("pyenv exec pip install -r" \
16
+ "#{NativeHelpers.python_requirements_path}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -131,6 +131,8 @@ module Dependabot
131
131
  return @pypi_listing
132
132
  rescue JSON::ParserError
133
133
  next
134
+ rescue Excon::Error::Timeout
135
+ next
134
136
  end
135
137
 
136
138
  @pypi_listing = {} # No listing found
@@ -4,16 +4,16 @@ module Dependabot
4
4
  module Python
5
5
  module PythonVersions
6
6
  PRE_INSTALLED_PYTHON_VERSIONS = %w(
7
- 3.10.5
7
+ 3.10.7
8
8
  ).freeze
9
9
 
10
10
  # Due to an OpenSSL issue we can only install the following versions in
11
11
  # the Dependabot container.
12
12
  SUPPORTED_VERSIONS = %w(
13
- 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
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
15
- 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
16
- 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
13
+ 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
14
+ 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
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
16
+ 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
17
17
  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
18
18
  3.6.2 3.6.1 3.6.0 3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
19
19
  ).freeze