dependabot-python 0.211.0 → 0.212.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: 48410b5617f95831c3ed5aba2c8e6cd9d48d7d9fc812c65e44eb853a9c46b336
4
- data.tar.gz: 24c798b98475ad41a3600f7b168921f04c63d02029c87b96410585d9ad88af66
3
+ metadata.gz: 4862b59513a97a33d51ff8ad57b6d9815842769c87f612426ffbcd8e75a9655c
4
+ data.tar.gz: 9543935b3ab8027344757b41aa8ff265d823beac956a06d20d4917e75962698d
5
5
  SHA512:
6
- metadata.gz: 3adfdad038c43c09ec2ce7cb3c04fa4606b4e538ffc418100bbe3bf3a6a4344e243f141a8c13b7215bd5e669cfc52e31b99b888791cbdf8ce9d75bc2d52cd013
7
- data.tar.gz: 2b4972ad44a0f39a9a3355630baf7f088b1d988224b66d782c65779ed3f9e4f98956190d1ddb3ec4889796edbebb983b281dad9f79e12a0574bc7da3a71bd17a
6
+ metadata.gz: fd9e547d19f01addfdc2fcc4eeb7095bf8e886eded086772f81b9bfbd6acfb2fc6076c354c970ae5fad0691a25679d99db8eb0884121e986c1bcf39b17c041ba
7
+ data.tar.gz: be587fe031f132dd20d4fc023668e31d81c37608d915a9f586ca159b675302993a208b6e93209cfaedad83d08eaae1ca06f6af7eec8933bcc2c44e8a61293ccf
@@ -4,7 +4,7 @@ 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
7
+ poetry>=1.1.15,<=1.2.0
8
8
  wheel==0.37.1
9
9
 
10
10
  # Some dependencies will only install if Cython is present
@@ -13,6 +13,7 @@ module Dependabot
13
13
  class FileFetcher < Dependabot::FileFetchers::Base
14
14
  CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/.freeze
15
15
  CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/.freeze
16
+ DEPENDENCY_TYPES = %w(packages dev-packages).freeze
16
17
 
17
18
  def self.required_files_in?(filenames)
18
19
  return true if filenames.any? { |name| name.end_with?(".txt", ".in") }
@@ -32,8 +33,8 @@ module Dependabot
32
33
  end
33
34
 
34
35
  def self.required_files_message
35
- "Repo must contain a requirements.txt, setup.py, setup.cfg, pyproject.toml, "\
36
- "or a Pipfile."
36
+ "Repo must contain a requirements.txt, setup.py, setup.cfg, pyproject.toml, " \
37
+ "or a Pipfile."
37
38
  end
38
39
 
39
40
  private
@@ -372,7 +373,7 @@ module Dependabot
372
373
  return [] unless pipfile
373
374
 
374
375
  paths = []
375
- %w(packages dev-packages).each do |dep_type|
376
+ DEPENDENCY_TYPES.each do |dep_type|
376
377
  next unless parsed_pipfile[dep_type]
377
378
 
378
379
  parsed_pipfile[dep_type].each do |_, req|
@@ -61,7 +61,7 @@ module Dependabot
61
61
 
62
62
  # @param req can be an Array, Hash or String that represents the constraints for a dependency
63
63
  def parse_requirements_from(req, type)
64
- [req].flatten.compact.map do |requirement|
64
+ [req].flatten.compact.filter_map do |requirement|
65
65
  next if requirement.is_a?(Hash) && (UNSUPPORTED_DEPENDENCY_TYPES & requirement.keys).any?
66
66
 
67
67
  check_requirements(requirement)
@@ -72,7 +72,7 @@ module Dependabot
72
72
  source: nil,
73
73
  groups: [type]
74
74
  }
75
- end.compact
75
+ end
76
76
  end
77
77
 
78
78
  # Create a DependencySet where each element has no requirement. Any
@@ -81,8 +81,9 @@ module Dependabot
81
81
  def lockfile_dependencies
82
82
  dependencies = Dependabot::FileParsers::Base::DependencySet.new
83
83
 
84
+ source_types = %w(directory git url)
84
85
  parsed_lockfile.fetch("package", []).each do |details|
85
- next if %w(directory git url).include?(details.dig("source", "type"))
86
+ next if source_types.include?(details.dig("source", "type"))
86
87
 
87
88
  dependencies <<
88
89
  Dependency.new(
@@ -33,8 +33,7 @@ module Dependabot
33
33
  requirement_files.flat_map do |file|
34
34
  file.content.lines.
35
35
  select { |l| l.include?(";") && l.include?("python") }.
36
- map { |l| l.match(/python_version(?<req>.*?["'].*?['"])/) }.
37
- compact.
36
+ filter_map { |l| l.match(/python_version(?<req>.*?["'].*?['"])/) }.
38
37
  map { |re| re.named_captures.fetch("req").gsub(/['"]/, "") }.
39
38
  select { |r| valid_requirement?(r) }
40
39
  end
@@ -128,7 +128,7 @@ module Dependabot
128
128
  tests_require = get_regexed_req_array(TESTS_REQUIRE_REGEX)
129
129
  extras_require = get_regexed_req_dict(EXTRAS_REQUIRE_REGEX)
130
130
 
131
- tmp = "from setuptools import setup\n\n"\
131
+ tmp = "from setuptools import setup\n\n" \
132
132
  "setup(name=\"sanitized-package\",version=\"0.0.1\","
133
133
 
134
134
  tmp += "install_requires=#{install_requires}," if install_requires
@@ -71,20 +71,20 @@ module Dependabot
71
71
  filenames_to_compile.each do |filename|
72
72
  # Shell out to pip-compile, generate a new set of requirements.
73
73
  # This is slow, as pip-compile needs to do installs.
74
- name_part = "pyenv exec pip-compile "\
75
- "#{pip_compile_options(filename)} -P "\
74
+ name_part = "pyenv exec pip-compile " \
75
+ "#{pip_compile_options(filename)} -P " \
76
76
  "#{dependency.name}"
77
77
  version_part = "#{dependency.version} #{filename}"
78
78
  # Don't escape pyenv `dep-name==version` syntax
79
79
  run_pip_compile_command(
80
- "#{SharedHelpers.escape_command(name_part)}=="\
80
+ "#{SharedHelpers.escape_command(name_part)}==" \
81
81
  "#{SharedHelpers.escape_command(version_part)}",
82
82
  allow_unsafe_shell_command: true
83
83
  )
84
84
  # Run pip-compile a second time, without an update argument, to
85
85
  # ensure it resets the right comments.
86
86
  run_pip_compile_command(
87
- "pyenv exec pip-compile #{pip_compile_options(filename)} "\
87
+ "pyenv exec pip-compile #{pip_compile_options(filename)} " \
88
88
  "#{filename}"
89
89
  )
90
90
  end
@@ -92,7 +92,7 @@ module Dependabot
92
92
  # Remove any .python-version file before parsing the reqs
93
93
  FileUtils.remove_entry(".python-version", true)
94
94
 
95
- dependency_files.map do |file|
95
+ dependency_files.filter_map do |file|
96
96
  next unless file.name.end_with?(".txt")
97
97
 
98
98
  updated_content = File.read(file.name)
@@ -102,12 +102,12 @@ module Dependabot
102
102
  next if updated_content == file.content
103
103
 
104
104
  file.dup.tap { |f| f.content = updated_content }
105
- end.compact
105
+ end
106
106
  end
107
107
  end
108
108
 
109
109
  def update_manifest_files
110
- dependency_files.map do |file|
110
+ dependency_files.filter_map do |file|
111
111
  next unless file.name.end_with?(".in")
112
112
 
113
113
  file = file.dup
@@ -116,7 +116,7 @@ module Dependabot
116
116
 
117
117
  file.content = updated_content
118
118
  file
119
- end.compact
119
+ end
120
120
  end
121
121
 
122
122
  def update_uncompiled_files(updated_files)
@@ -132,7 +132,7 @@ module Dependabot
132
132
  reject { |file| updated_filenames.include?(file.name) }
133
133
 
134
134
  args = dependency.to_h
135
- args = args.keys.map { |k| [k.to_sym, args[k]] }.to_h
135
+ args = args.keys.to_h { |k| [k.to_sym, args[k]] }
136
136
  args[:requirements] = new_reqs
137
137
  args[:previous_requirements] = old_reqs
138
138
 
@@ -224,7 +224,7 @@ module Dependabot
224
224
 
225
225
  run_command("pyenv install -s #{python_version}")
226
226
  run_command("pyenv exec pip install --upgrade pip")
227
- run_command("pyenv exec pip install -r "\
227
+ run_command("pyenv exec pip install -r " \
228
228
  "#{NativeHelpers.python_requirements_path}")
229
229
  end
230
230
 
@@ -352,7 +352,7 @@ module Dependabot
352
352
  end
353
353
 
354
354
  def deps_to_augment_hashes_for(updated_content, original_content)
355
- regex = /^#{RequirementParser::INSTALL_REQ_WITH_REQUIREMENT}/
355
+ regex = /^#{RequirementParser::INSTALL_REQ_WITH_REQUIREMENT}/o
356
356
 
357
357
  new_matches = []
358
358
  updated_content.scan(regex) { new_matches << Regexp.last_match }
@@ -18,6 +18,8 @@ module Dependabot
18
18
  require_relative "pipfile_manifest_updater"
19
19
  require_relative "setup_file_sanitizer"
20
20
 
21
+ DEPENDENCY_TYPES = %w(packages dev-packages).freeze
22
+
21
23
  attr_reader :dependencies, :dependency_files, :credentials
22
24
 
23
25
  def initialize(dependencies:, dependency_files:, credentials:)
@@ -145,7 +147,7 @@ module Dependabot
145
147
  pipfile_object = TomlRB.parse(pipfile_content)
146
148
 
147
149
  dependencies.each do |dep|
148
- %w(packages dev-packages).each do |type|
150
+ DEPENDENCY_TYPES.each do |type|
149
151
  names = pipfile_object[type]&.keys || []
150
152
  pkg_name = names.find { |nm| normalise(nm) == dep.name }
151
153
  next unless pkg_name || subdep_type?(type)
@@ -350,9 +352,9 @@ module Dependabot
350
352
 
351
353
  # Otherwise we have to raise, giving details of the Python versions
352
354
  # that Dependabot supports
353
- msg = "Dependabot detected the following Python requirement "\
354
- "for your project: '#{requirement_string}'.\n\nCurrently, the "\
355
- "following Python versions are supported in Dependabot: "\
355
+ msg = "Dependabot detected the following Python requirement " \
356
+ "for your project: '#{requirement_string}'.\n\nCurrently, the " \
357
+ "following Python versions are supported in Dependabot: " \
356
358
  "#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
357
359
  raise DependencyFileNotResolvable, msg
358
360
  end
@@ -173,7 +173,7 @@ module Dependabot
173
173
  if python_version && !pre_installed_python?(python_version)
174
174
  run_poetry_command("pyenv install -s #{python_version}")
175
175
  run_poetry_command("pyenv exec pip install --upgrade pip")
176
- run_poetry_command("pyenv exec pip install -r"\
176
+ run_poetry_command("pyenv exec pip install -r" \
177
177
  "#{NativeHelpers.python_requirements_path}")
178
178
  end
179
179
 
@@ -55,6 +55,7 @@ module Dependabot
55
55
  Dependabot::Python::FileParser::PoetryFilesParser::POETRY_DEPENDENCY_TYPES.each do |key|
56
56
  next unless poetry_object[key]
57
57
 
58
+ source_types = %w(directory file url)
58
59
  poetry_object.fetch(key).each do |dep_name, _|
59
60
  next if excluded_names.include?(normalise(dep_name))
60
61
 
@@ -62,7 +63,7 @@ module Dependabot
62
63
 
63
64
  next unless (locked_version = locked_details&.fetch("version"))
64
65
 
65
- next if %w(directory file url).include?(locked_details&.dig("source", "type"))
66
+ next if source_types.include?(locked_details&.dig("source", "type"))
66
67
 
67
68
  if locked_details&.dig("source", "type") == "git"
68
69
  poetry_object[key][dep_name] = {
@@ -36,7 +36,7 @@ module Dependabot
36
36
  def fetch_updated_dependency_files
37
37
  reqs = dependency.requirements.zip(dependency.previous_requirements)
38
38
 
39
- reqs.map do |(new_req, old_req)|
39
+ reqs.filter_map do |(new_req, old_req)|
40
40
  next if new_req == old_req
41
41
 
42
42
  file = get_original_file(new_req.fetch(:file)).dup
@@ -46,7 +46,7 @@ module Dependabot
46
46
 
47
47
  file.content = updated_content
48
48
  file
49
- end.compact
49
+ end
50
50
  end
51
51
 
52
52
  def updated_requirement_or_setup_file_content(new_req, old_req)
@@ -52,7 +52,7 @@ module Dependabot
52
52
  if add_space_after_operators?
53
53
  new_req_string =
54
54
  new_req_string.
55
- gsub(/(#{RequirementParser::COMPARISON})\s*(?=\d)/, '\1 ')
55
+ gsub(/(#{RequirementParser::COMPARISON})\s*(?=\d)/o, '\1 ')
56
56
  end
57
57
 
58
58
  new_req_string
@@ -92,7 +92,7 @@ module Dependabot
92
92
  def add_space_after_operators?
93
93
  original_dependency_declaration_string(old_requirement).
94
94
  match(RequirementParser::REQUIREMENTS).
95
- to_s.match?(/#{RequirementParser::COMPARISON}\s+\d/)
95
+ to_s.match?(/#{RequirementParser::COMPARISON}\s+\d/o)
96
96
  end
97
97
 
98
98
  def original_declaration_replacement_regex
@@ -19,9 +19,9 @@ module Dependabot
19
19
  # install_requires. A name and version are required by don't end up
20
20
  # in the lockfile.
21
21
  content =
22
- "from setuptools import setup\n\n"\
23
- "setup(name=\"sanitized-package\",version=\"0.0.1\","\
24
- "install_requires=#{install_requires_array.to_json},"\
22
+ "from setuptools import setup\n\n" \
23
+ "setup(name=\"sanitized-package\",version=\"0.0.1\"," \
24
+ "install_requires=#{install_requires_array.to_json}," \
25
25
  "extras_require=#{extras_require_hash.to_json}"
26
26
 
27
27
  content += ',setup_requires=["pbr"],pbr=True' if include_pbr?
@@ -38,22 +38,22 @@ module Dependabot
38
38
 
39
39
  def install_requires_array
40
40
  @install_requires_array ||=
41
- parsed_setup_file.dependencies.map do |dep|
41
+ parsed_setup_file.dependencies.filter_map do |dep|
42
42
  next unless dep.requirements.first[:groups].
43
43
  include?("install_requires")
44
44
 
45
45
  dep.name + dep.requirements.first[:requirement].to_s
46
- end.compact
46
+ end
47
47
  end
48
48
 
49
49
  def setup_requires_array
50
50
  @setup_requires_array ||=
51
- parsed_setup_file.dependencies.map do |dep|
51
+ parsed_setup_file.dependencies.filter_map do |dep|
52
52
  next unless dep.requirements.first[:groups].
53
53
  include?("setup_requires")
54
54
 
55
55
  dep.name + dep.requirements.first[:requirement].to_s
56
- end.compact
56
+ end
57
57
  end
58
58
 
59
59
  def extras_require_hash
@@ -66,7 +66,7 @@ module Dependabot
66
66
 
67
67
  hash[group.split(":").last] ||= []
68
68
  hash[group.split(":").last] <<
69
- dep.name + dep.requirements.first[:requirement].to_s
69
+ (dep.name + dep.requirements.first[:requirement].to_s)
70
70
  end
71
71
  end
72
72
 
@@ -60,8 +60,8 @@ module Dependabot
60
60
 
61
61
  # Otherwise, this is a top-level dependency, and we can figure out
62
62
  # which resolver to use based on the filename of its requirements
63
- return :pipfile if changed_req_files.any? { |f| f == "Pipfile" }
64
- return :poetry if changed_req_files.any? { |f| f == "pyproject.toml" }
63
+ return :pipfile if changed_req_files.any?("Pipfile")
64
+ return :poetry if changed_req_files.any?("pyproject.toml")
65
65
  return :pip_compile if changed_req_files.any? { |f| f.end_with?(".in") }
66
66
 
67
67
  :requirements
@@ -12,7 +12,7 @@ module Dependabot
12
12
  end
13
13
 
14
14
  def self.python_helpers_dir
15
- File.join(native_helpers_root, "python/helpers")
15
+ File.join(native_helpers_root, "python")
16
16
  end
17
17
 
18
18
  def self.native_helpers_root
@@ -171,7 +171,7 @@ module Dependabot
171
171
  authed_url = config_variable_urls.find { |u| u.match?(regexp) }
172
172
  return authed_url if authed_url
173
173
 
174
- cleaned_url = url.gsub(%r{#{ENVIRONMENT_VARIABLE_REGEX}/?}, "")
174
+ cleaned_url = url.gsub(%r{#{ENVIRONMENT_VARIABLE_REGEX}/?}o, "")
175
175
  authed_url = authed_base_url(cleaned_url)
176
176
  return authed_url if credential_for(cleaned_url)
177
177
 
@@ -85,14 +85,14 @@ module Dependabot
85
85
  end
86
86
 
87
87
  def filter_unsupported_versions(versions_array, python_version)
88
- versions_array.map do |details|
88
+ versions_array.filter_map do |details|
89
89
  python_requirement = details.fetch(:python_requirement)
90
90
  next details.fetch(:version) unless python_version
91
91
  next details.fetch(:version) unless python_requirement
92
92
  next unless python_requirement.satisfied_by?(python_version)
93
93
 
94
94
  details.fetch(:version)
95
- end.compact
95
+ end
96
96
  end
97
97
 
98
98
  def filter_prerelease_versions(versions_array)
@@ -118,9 +118,9 @@ module Dependabot
118
118
  end
119
119
 
120
120
  def filter_out_of_range_versions(versions_array)
121
- reqs = dependency.requirements.map do |r|
121
+ reqs = dependency.requirements.filter_map do |r|
122
122
  requirement_class.requirements_array(r.fetch(:requirement))
123
- end.compact
123
+ end
124
124
 
125
125
  versions_array.
126
126
  select { |v| reqs.all? { |r| r.any? { |o| o.satisfied_by?(v) } } }
@@ -144,11 +144,14 @@ module Dependabot
144
144
  @available_versions ||=
145
145
  index_urls.flat_map do |index_url|
146
146
  sanitized_url = index_url.gsub(%r{(?<=//).*(?=@)}, "redacted")
147
+
147
148
  index_response = registry_response_for_dependency(index_url)
149
+ if index_response.status == 401 || index_response.status == 403
150
+ registry_index_response = registry_index_response(index_url)
148
151
 
149
- if [401, 403].include?(index_response.status) &&
150
- [401, 403].include?(registry_index_response(index_url).status)
151
- raise PrivateSourceAuthenticationFailure, sanitized_url
152
+ if registry_index_response.status == 401 || registry_index_response.status == 403
153
+ raise PrivateSourceAuthenticationFailure, sanitized_url
154
+ end
152
155
  end
153
156
 
154
157
  version_links = []
@@ -318,7 +318,7 @@ module Dependabot
318
318
 
319
319
  run_command("pyenv install -s #{python_version}")
320
320
  run_command("pyenv exec pip install --upgrade pip")
321
- run_command("pyenv exec pip install -r"\
321
+ run_command("pyenv exec pip install -r" \
322
322
  "#{NativeHelpers.python_requirements_path}")
323
323
  end
324
324
 
@@ -29,12 +29,13 @@ module Dependabot
29
29
  # just raise if the latest version can't be resolved. Knowing that is
30
30
  # still better than nothing, though.
31
31
  class PipenvVersionResolver
32
+ # rubocop:disable Layout/LineLength
32
33
  GIT_DEPENDENCY_UNREACHABLE_REGEX =
33
34
  /git clone -q (?<url>[^\s]+).* /.freeze
34
35
  GIT_REFERENCE_NOT_FOUND_REGEX =
35
36
  %r{git checkout -q (?<tag>[^\n"]+)\n?[^\n]*/(?<name>.*?)(\\n'\]|$)}m.
36
37
  freeze
37
- PIPENV_INSTALLATION_ERROR = "pipenv.patched.notpip._internal.exceptions.InstallationError: Command errored out"\
38
+ PIPENV_INSTALLATION_ERROR = "pipenv.patched.notpip._internal.exceptions.InstallationError: Command errored out" \
38
39
  " with exit status 1: python setup.py egg_info"
39
40
  TRACEBACK = "Traceback (most recent call last):"
40
41
  PIPENV_INSTALLATION_ERROR_REGEX =
@@ -44,6 +45,9 @@ module Dependabot
44
45
  UNSUPPORTED_DEP_REGEX =
45
46
  /Could not find a version that satisfies the requirement.*(?:#{UNSUPPORTED_DEPS.join("|")})/.freeze
46
47
  PIPENV_RANGE_WARNING = /Warning:\sPython\s[<>].* was not found/.freeze
48
+ # rubocop:enable Layout/LineLength
49
+
50
+ DEPENDENCY_TYPES = %w(packages dev-packages).freeze
47
51
 
48
52
  attr_reader :dependency, :dependency_files, :credentials
49
53
 
@@ -136,20 +140,20 @@ module Dependabot
136
140
  end
137
141
 
138
142
  if error.message.match?(UNSUPPORTED_DEP_REGEX)
139
- msg = "Dependabot detected a dependency that can't be built on "\
140
- "linux. Currently, all Dependabot builds happen on linux "\
141
- "boxes, so there is no way for Dependabot to resolve your "\
142
- "dependency files.\n\n"\
143
- "Unless you think Dependabot has made a mistake (please "\
144
- "tag us if so) you may wish to disable Dependabot on this "\
143
+ msg = "Dependabot detected a dependency that can't be built on " \
144
+ "linux. Currently, all Dependabot builds happen on linux " \
145
+ "boxes, so there is no way for Dependabot to resolve your " \
146
+ "dependency files.\n\n" \
147
+ "Unless you think Dependabot has made a mistake (please " \
148
+ "tag us if so) you may wish to disable Dependabot on this " \
145
149
  "repo."
146
150
  raise DependencyFileNotResolvable, msg
147
151
  end
148
152
 
149
153
  if error.message.match?(PIPENV_RANGE_WARNING)
150
- msg = "Pipenv does not support specifying Python ranges "\
151
- "(see https://github.com/pypa/pipenv/issues/1050 for more "\
152
- "details)."
154
+ msg = "Pipenv does not support specifying Python ranges " \
155
+ "(see https://github.com/pypa/pipenv/issues/1050 for more " \
156
+ "details)."
153
157
  raise DependencyFileNotResolvable, msg
154
158
  end
155
159
 
@@ -159,7 +163,7 @@ module Dependabot
159
163
 
160
164
  if error.message.include?("SyntaxError: invalid syntax")
161
165
  raise DependencyFileNotResolvable,
162
- "SyntaxError while installing dependencies. Is one of the dependencies not Python 3 compatible? "\
166
+ "SyntaxError while installing dependencies. Is one of the dependencies not Python 3 compatible? " \
163
167
  "Pip v21 no longer supports Python 2."
164
168
  end
165
169
 
@@ -272,9 +276,9 @@ module Dependabot
272
276
  dependency_name = error_message.match(PIPENV_INSTALLATION_ERROR_REGEX).named_captures["name"]
273
277
  raise unless dependency_name
274
278
 
275
- msg = "Pipenv failed to install \"#{dependency_name}\". This could be caused by missing system "\
276
- "dependencies that can't be installed by Dependabot or required installation flags.\n\n"\
277
- "Error output from running \"pipenv lock\":\n"\
279
+ msg = "Pipenv failed to install \"#{dependency_name}\". This could be caused by missing system " \
280
+ "dependencies that can't be installed by Dependabot or required installation flags.\n\n" \
281
+ "Error output from running \"pipenv lock\":\n" \
278
282
  "#{clean_error_message(error_message)}"
279
283
 
280
284
  raise DependencyFileNotResolvable, msg
@@ -324,7 +328,7 @@ module Dependabot
324
328
  requirements_path = NativeHelpers.python_requirements_path
325
329
  run_command("pyenv install -s #{python_version}")
326
330
  run_command("pyenv exec pip install --upgrade pip")
327
- run_command("pyenv exec pip install -r "\
331
+ run_command("pyenv exec pip install -r " \
328
332
  "#{requirements_path}")
329
333
  end
330
334
 
@@ -361,7 +365,7 @@ module Dependabot
361
365
 
362
366
  pipfile_object = TomlRB.parse(pipfile_content)
363
367
 
364
- %w(packages dev-packages).each do |type|
368
+ DEPENDENCY_TYPES.each do |type|
365
369
  names = pipfile_object[type]&.keys || []
366
370
  pkg_name = names.find { |nm| normalise(nm) == dependency.name }
367
371
  next unless pkg_name || subdep_type?(type)
@@ -429,9 +433,9 @@ module Dependabot
429
433
 
430
434
  # Otherwise we have to raise, giving details of the Python versions
431
435
  # that Dependabot supports
432
- msg = "Dependabot detected the following Python requirement "\
433
- "for your project: '#{requirement_string}'.\n\nCurrently, the "\
434
- "following Python versions are supported in Dependabot: "\
436
+ msg = "Dependabot detected the following Python requirement " \
437
+ "for your project: '#{requirement_string}'.\n\nCurrently, the " \
438
+ "following Python versions are supported in Dependabot: " \
435
439
  "#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
436
440
  raise DependencyFileNotResolvable, msg
437
441
  end
@@ -3,6 +3,7 @@
3
3
  require "excon"
4
4
  require "toml-rb"
5
5
  require "open3"
6
+ require "uri"
6
7
  require "dependabot/dependency"
7
8
  require "dependabot/errors"
8
9
  require "dependabot/shared_helpers"
@@ -23,18 +24,26 @@ module Dependabot
23
24
  # This class does version resolution for pyproject.toml files.
24
25
  class PoetryVersionResolver
25
26
  GIT_REFERENCE_NOT_FOUND_REGEX = /
26
- 'git'.*pypoetry-git-(?<name>.+?).{8}',
27
+ (?:'git'.*pypoetry-git-(?<name>.+?).{8}',
27
28
  'checkout',
28
29
  '(?<tag>.+?)'
29
- /x.freeze
30
+ |
31
+ ...Failedtoclone
32
+ (?<url>.+?).gitat'(?<tag>.+?)',
33
+ verifyrefexistsonremote)
34
+ /x.freeze # TODO: remove the first clause and | when py3.6 support is EoL
30
35
  GIT_DEPENDENCY_UNREACHABLE_REGEX = /
31
- '\['git',
32
- \s+'clone',
33
- \s+'--recurse-submodules',
34
- \s+'(--)?',
35
- \s+'(?<url>.+?)'.*
36
- \s+exit\s+status\s+128
37
- /mx.freeze
36
+ (?:'\['git',
37
+ \s+'clone',
38
+ \s+'--recurse-submodules',
39
+ \s+'(--)?',
40
+ \s+'(?<url>.+?)'.*
41
+ \s+exit\s+status\s+128
42
+ |
43
+ \s+Failed\sto\sclone
44
+ \s+(?<url>.+?),
45
+ \s+check\syour\sgit\sconfiguration)
46
+ /mx.freeze # TODO: remove the first clause and | when py3.6 support is EoL
38
47
 
39
48
  attr_reader :dependency, :dependency_files, :credentials
40
49
 
@@ -61,7 +70,8 @@ module Dependabot
61
70
  false
62
71
  end
63
72
  rescue SharedHelpers::HelperSubprocessFailed => e
64
- raise unless e.message.include?("SolverProblemError")
73
+ raise unless e.message.include?("SolverProblemError") || # TODO: Remove once py3.6 is EoL
74
+ e.message.include?("version solving failed.")
65
75
 
66
76
  @resolvable[version] = false
67
77
  end
@@ -82,7 +92,7 @@ module Dependabot
82
92
  run_poetry_command("pyenv install -s #{python_version}")
83
93
  run_poetry_command("pyenv exec pip install --upgrade pip")
84
94
  run_poetry_command(
85
- "pyenv exec pip install -r "\
95
+ "pyenv exec pip install -r " \
86
96
  "#{NativeHelpers.python_requirements_path}"
87
97
  )
88
98
  end
@@ -118,8 +128,13 @@ module Dependabot
118
128
  def handle_poetry_errors(error)
119
129
  if error.message.gsub(/\s/, "").match?(GIT_REFERENCE_NOT_FOUND_REGEX)
120
130
  message = error.message.gsub(/\s/, "")
121
- name = message.match(GIT_REFERENCE_NOT_FOUND_REGEX).
122
- named_captures.fetch("name")
131
+ match = message.match(GIT_REFERENCE_NOT_FOUND_REGEX)
132
+ name = if (url = match.named_captures.fetch("url"))
133
+ File.basename(URI.parse(url).path)
134
+ else
135
+ message.match(GIT_REFERENCE_NOT_FOUND_REGEX).
136
+ named_captures.fetch("name")
137
+ end
123
138
  raise GitDependencyReferenceNotFound, name
124
139
  end
125
140
 
@@ -130,7 +145,8 @@ module Dependabot
130
145
  end
131
146
 
132
147
  raise unless error.message.include?("SolverProblemError") ||
133
- error.message.include?("PackageNotFound")
148
+ error.message.include?("PackageNotFound") ||
149
+ error.message.include?("version solving failed.")
134
150
 
135
151
  check_original_requirements_resolvable
136
152
 
@@ -161,7 +177,8 @@ module Dependabot
161
177
  @original_reqs_resolvable = true
162
178
  rescue SharedHelpers::HelperSubprocessFailed => e
163
179
  raise unless e.message.include?("SolverProblemError") ||
164
- e.message.include?("PackageNotFound")
180
+ e.message.include?("PackageNotFound") ||
181
+ e.message.include?("version solving failed.")
165
182
 
166
183
  msg = clean_error_message(e.message)
167
184
  raise DependencyFileNotResolvable, msg
@@ -214,9 +231,9 @@ module Dependabot
214
231
  end
215
232
  return version if version
216
233
 
217
- msg = "Dependabot detected the following Python requirements "\
218
- "for your project: '#{requirements}'.\n\nCurrently, the "\
219
- "following Python versions are supported in Dependabot: "\
234
+ msg = "Dependabot detected the following Python requirements " \
235
+ "for your project: '#{requirements}'.\n\nCurrently, the " \
236
+ "following Python versions are supported in Dependabot: " \
220
237
  "#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
221
238
  raise DependencyFileNotResolvable, msg
222
239
  end
@@ -260,7 +260,7 @@ module Dependabot
260
260
  # Updates the version in a constraint to be the given version
261
261
  def bump_version(req_string, version_to_be_permitted)
262
262
  old_version = req_string.
263
- match(/(#{RequirementParser::VERSION})/).
263
+ match(/(#{RequirementParser::VERSION})/o).
264
264
  captures.first
265
265
 
266
266
  req_string.sub(
@@ -132,7 +132,6 @@ module Dependabot
132
132
  resolver.resolvable?(version: fix_version) ? fix_version : nil
133
133
  end
134
134
 
135
- # rubocop:disable Metrics/PerceivedComplexity
136
135
  def resolver_type
137
136
  reqs = dependency.requirements
138
137
  req_files = reqs.map { |r| r.fetch(:file) }
@@ -144,8 +143,8 @@ module Dependabot
144
143
 
145
144
  # Otherwise, this is a top-level dependency, and we can figure out
146
145
  # which resolver to use based on the filename of its requirements
147
- return :pipenv if req_files.any? { |f| f == "Pipfile" }
148
- return :poetry if req_files.any? { |f| f == "pyproject.toml" }
146
+ return :pipenv if req_files.any?("Pipfile")
147
+ return :poetry if req_files.any?("pyproject.toml")
149
148
  return :pip_compile if req_files.any? { |f| f.end_with?(".in") }
150
149
 
151
150
  if dependency.version && !exact_requirement?(reqs)
@@ -154,7 +153,6 @@ module Dependabot
154
153
  :requirements
155
154
  end
156
155
  end
157
- # rubocop:enable Metrics/PerceivedComplexity
158
156
 
159
157
  def subdependency_resolver
160
158
  return :pipenv if pipfile_lock
@@ -238,7 +236,7 @@ module Dependabot
238
236
  return ">= #{dependency.version}" if dependency.version
239
237
 
240
238
  version_for_requirement =
241
- dependency.requirements.map { |r| r[:requirement] }.compact.
239
+ dependency.requirements.filter_map { |r| r[:requirement] }.
242
240
  reject { |req_string| req_string.start_with?("<") }.
243
241
  select { |req_string| req_string.match?(VERSION_REGEX) }.
244
242
  map { |req_string| req_string.match(VERSION_REGEX) }.
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.211.0
4
+ version: 0.212.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-23 00:00:00.000000000 Z
11
+ date: 2022-09-06 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.211.0
19
+ version: 0.212.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.211.0
26
+ version: 0.212.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debase
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 3.11.1
89
+ version: 3.12.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 3.11.1
96
+ version: 3.12.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,28 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 1.35.1
145
+ version: 1.36.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 1.35.1
152
+ version: 1.36.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-performance
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 1.14.2
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 1.14.2
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: ruby-debug-ide
155
169
  requirement: !ruby/object:Gem::Requirement