dependabot-python 0.288.0 → 0.289.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: 2a48e0851bec2770472370c41f5bc8c2f51252f14d0df9895b354eb0ed0cd26b
4
- data.tar.gz: f105f8d5deffbb70dc2c0a3cfb9e00a4b591c01e6ededcacec376f52ae926738
3
+ metadata.gz: 53fcf514cdb25a0a0ce7ee91ee7c7a709bed7a0b0b12e96c1b75ee0670c9a776
4
+ data.tar.gz: ad1d6c5111311f7c22da1b9632747a03a419d329a2047f147fc93aba580aedd1
5
5
  SHA512:
6
- metadata.gz: 0d407719216601023ff1d397072e158e3a4ab2fcf0113702655d83176accdfbdb3fb532a72e71fdaab76c07985203dbf12de20b69be78ed93d5bd37241b99db1
7
- data.tar.gz: 75ad08b140727494fbb29ea3a564680b2366c9104f19e08d16896483cb594a3fc66c1bf51836c8ab063fedc64d4448bbaa1777868efb883e13587e63cfe70c95
6
+ metadata.gz: ada2669aa9b1e58cc9ed8e8f3001d7d47b9ecaf496666753247a8e4b9e00db288aecae9a30061dfe4880bfe5569eeab7faf873187d93d132330097104fd1b5a3
7
+ data.tar.gz: 04c164ca91f954361f394fba2a2f4fe3ee4685b392526d6e8ad8d14148da95ea9f1ca4d104c84d8af626d6462cb545b73d7e60f52ead0f8fe228596a82322093
@@ -8,9 +8,12 @@ require "dependabot/file_parsers/base/dependency_set"
8
8
  require "dependabot/shared_helpers"
9
9
  require "dependabot/python/requirement"
10
10
  require "dependabot/errors"
11
+ require "dependabot/python/language"
11
12
  require "dependabot/python/native_helpers"
12
13
  require "dependabot/python/name_normaliser"
13
14
  require "dependabot/python/pip_compile_file_matcher"
15
+ require "dependabot/python/language_version_manager"
16
+ require "dependabot/python/package_manager"
14
17
 
15
18
  module Dependabot
16
19
  module Python
@@ -34,6 +37,11 @@ module Dependabot
34
37
  InvalidRequirement ValueError RecursionError
35
38
  ).freeze
36
39
 
40
+ # we use this placeholder version in case we are not able to detect any
41
+ # PIP version from shell, we are ensuring that the actual update is not blocked
42
+ # in any way if any metric collection exception start happening
43
+ UNDETECTED_PACKAGE_MANAGER_VERSION = "0.0"
44
+
37
45
  def parse
38
46
  # TODO: setup.py from external dependencies is evaluated. Provide guards before removing this.
39
47
  raise Dependabot::UnexpectedExternalCode if @reject_external_code
@@ -48,8 +56,172 @@ module Dependabot
48
56
  dependency_set.dependencies
49
57
  end
50
58
 
59
+ sig { returns(Ecosystem) }
60
+ def ecosystem
61
+ @ecosystem ||= T.let(
62
+ Ecosystem.new(
63
+ name: ECOSYSTEM,
64
+ package_manager: package_manager,
65
+ language: language
66
+ ),
67
+ T.nilable(Ecosystem)
68
+ )
69
+ end
70
+
51
71
  private
52
72
 
73
+ def language_version_manager
74
+ @language_version_manager ||=
75
+ LanguageVersionManager.new(
76
+ python_requirement_parser: python_requirement_parser
77
+ )
78
+ end
79
+
80
+ def python_requirement_parser
81
+ @python_requirement_parser ||=
82
+ FileParser::PythonRequirementParser.new(
83
+ dependency_files: dependency_files
84
+ )
85
+ end
86
+
87
+ sig { returns(Ecosystem::VersionManager) }
88
+ def package_manager
89
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
90
+ Dependabot.logger.info("Detected package manager : #{detected_package_manager.name}")
91
+ end
92
+
93
+ @package_manager ||= detected_package_manager
94
+ end
95
+
96
+ sig { returns(Ecosystem::VersionManager) }
97
+ def detected_package_manager
98
+ setup_python_environment if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
99
+
100
+ return PipenvPackageManager.new(T.must(detect_pipenv_version)) if detect_pipenv_version
101
+
102
+ return PoetryPackageManager.new(T.must(detect_poetry_version)) if detect_poetry_version
103
+
104
+ return PipCompilePackageManager.new(T.must(detect_pipcompile_version)) if detect_pipcompile_version
105
+
106
+ PipPackageManager.new(detect_pip_version)
107
+ end
108
+
109
+ # Detects the version of poetry. If the version cannot be detected, it returns nil
110
+ sig { returns(T.nilable(String)) }
111
+ def detect_poetry_version
112
+ if poetry_files
113
+ package_manager = PoetryPackageManager::NAME
114
+
115
+ version = package_manager_version(package_manager)
116
+ .to_s.split("version ").last&.split(")")&.first
117
+
118
+ log_if_version_malformed(package_manager, version)
119
+
120
+ # makes sure we have correct version format returned
121
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
122
+ end
123
+ rescue StandardError
124
+ nil
125
+ end
126
+
127
+ # Detects the version of pip-compile. If the version cannot be detected, it returns nil
128
+ sig { returns(T.nilable(String)) }
129
+ def detect_pipcompile_version
130
+ if pipcompile_in_file
131
+ package_manager = PipCompilePackageManager::NAME
132
+
133
+ version = package_manager_version(package_manager)
134
+ .to_s.split("version ").last&.split(")")&.first
135
+
136
+ log_if_version_malformed(package_manager, version)
137
+
138
+ # makes sure we have correct version format returned
139
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
140
+ end
141
+ rescue StandardError
142
+ nil
143
+ end
144
+
145
+ # Detects the version of pipenv. If the version cannot be detected, it returns nil
146
+ sig { returns(T.nilable(String)) }
147
+ def detect_pipenv_version
148
+ if pipenv_files
149
+ package_manager = PipenvPackageManager::NAME
150
+
151
+ version = package_manager_version(package_manager)
152
+ .to_s.split("version ").last&.strip
153
+
154
+ log_if_version_malformed(package_manager, version)
155
+
156
+ # makes sure we have correct version format returned
157
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
158
+ end
159
+ rescue StandardError
160
+ nil
161
+ end
162
+
163
+ # Detects the version of pip. If the version cannot be detected, it returns 0.0
164
+ sig { returns(String) }
165
+ def detect_pip_version
166
+ package_manager = PipPackageManager::NAME
167
+
168
+ version = package_manager_version(package_manager)
169
+ .split("from").first&.split("pip")&.last&.strip
170
+
171
+ log_if_version_malformed(package_manager, version)
172
+
173
+ version&.match?(/^\d+(?:\.\d+)*$/) ? version : UNDETECTED_PACKAGE_MANAGER_VERSION
174
+ rescue StandardError
175
+ nil
176
+ end
177
+
178
+ sig { params(package_manager: String).returns(T.any(String, T.untyped)) }
179
+ def package_manager_version(package_manager)
180
+ version_info = SharedHelpers.run_shell_command("pyenv exec #{package_manager} --version")
181
+ Dependabot.logger.info("Package manager #{package_manager}, Info : #{version_info}")
182
+
183
+ version_info
184
+ rescue StandardError => e
185
+ Dependabot.logger.error(e.message)
186
+ nil
187
+ end
188
+
189
+ # setup python local setup on file parser stage
190
+ sig { void }
191
+ def setup_python_environment
192
+ language_version_manager.install_required_python
193
+
194
+ SharedHelpers.run_shell_command("pyenv local #{language_version_manager.python_major_minor}")
195
+ rescue StandardError => e
196
+ Dependabot.logger.error(e.message)
197
+ nil
198
+ end
199
+
200
+ sig { params(package_manager: String, version: String).void }
201
+ def log_if_version_malformed(package_manager, version)
202
+ # logs warning if malformed version is found
203
+ return true if version.match?(/^\d+(?:\.\d+)*$/)
204
+
205
+ Dependabot.logger.warn(
206
+ "Detected #{package_manager} with malformed version #{version}"
207
+ )
208
+ end
209
+
210
+ sig { returns(String) }
211
+ def python_raw_version
212
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
213
+ Dependabot.logger.info("Detected python version: #{language_version_manager.python_version}")
214
+ Dependabot.logger.info("Detected python major minor version: #{language_version_manager.python_major_minor}")
215
+ end
216
+
217
+ language_version_manager.python_version
218
+ end
219
+
220
+ sig { returns(T.nilable(Ecosystem::VersionManager)) }
221
+ def language
222
+ Language.new(python_raw_version)
223
+ end
224
+
53
225
  def requirement_files
54
226
  dependency_files.select { |f| f.name.end_with?(".txt", ".in") }
55
227
  end
@@ -164,6 +336,18 @@ module Dependabot
164
336
  end
165
337
  end
166
338
 
339
+ def pipcompile_in_file
340
+ requirement_files.any? { |f| f.end_with?(".in") }
341
+ end
342
+
343
+ def pipenv_files
344
+ dependency_files.any? { |f| f.name == PipenvPackageManager::LOCKFILE_FILENAME }
345
+ end
346
+
347
+ def poetry_files
348
+ true if get_original_file(PoetryPackageManager::LOCKFILE_NAME)
349
+ end
350
+
167
351
  def write_temporary_dependency_files
168
352
  dependency_files
169
353
  .reject { |f| f.name == ".python-version" }
@@ -0,0 +1,21 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/python/version"
6
+ require "dependabot/ecosystem"
7
+
8
+ module Dependabot
9
+ module Python
10
+ LANGUAGE = "python"
11
+
12
+ class Language < Dependabot::Ecosystem::VersionManager
13
+ extend T::Sig
14
+
15
+ sig { params(raw_version: String, requirement: T.nilable(Requirement)).void }
16
+ def initialize(raw_version, requirement = nil)
17
+ super(LANGUAGE, Version.new(raw_version), [], [], requirement)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,166 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/python/version"
6
+ require "dependabot/ecosystem"
7
+ require "dependabot/python/requirement"
8
+
9
+ module Dependabot
10
+ module Python
11
+ ECOSYSTEM = "Python"
12
+
13
+ SUPPORTED_PYTHON_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
14
+
15
+ DEPRECATED_PYTHON_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
16
+
17
+ class PipPackageManager < Dependabot::Ecosystem::VersionManager
18
+ extend T::Sig
19
+
20
+ NAME = "pip"
21
+
22
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
23
+
24
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
25
+
26
+ sig do
27
+ params(
28
+ raw_version: String,
29
+ requirement: T.nilable(Requirement)
30
+ ).void
31
+ end
32
+ def initialize(raw_version, requirement = nil)
33
+ super(
34
+ NAME,
35
+ Version.new(raw_version),
36
+ SUPPORTED_VERSIONS,
37
+ DEPRECATED_VERSIONS,
38
+ requirement,
39
+ )
40
+ end
41
+
42
+ sig { override.returns(T::Boolean) }
43
+ def deprecated?
44
+ false
45
+ end
46
+
47
+ sig { override.returns(T::Boolean) }
48
+ def unsupported?
49
+ false
50
+ end
51
+ end
52
+
53
+ class PoetryPackageManager < Dependabot::Ecosystem::VersionManager
54
+ extend T::Sig
55
+
56
+ NAME = "poetry"
57
+
58
+ LOCKFILE_NAME = "poetry.lock"
59
+
60
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
61
+
62
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
63
+
64
+ sig do
65
+ params(
66
+ raw_version: String,
67
+ requirement: T.nilable(Requirement)
68
+ ).void
69
+ end
70
+ def initialize(raw_version, requirement = nil)
71
+ super(
72
+ NAME,
73
+ Version.new(raw_version),
74
+ SUPPORTED_VERSIONS,
75
+ DEPRECATED_VERSIONS,
76
+ requirement,
77
+ )
78
+ end
79
+
80
+ sig { override.returns(T::Boolean) }
81
+ def deprecated?
82
+ false
83
+ end
84
+
85
+ sig { override.returns(T::Boolean) }
86
+ def unsupported?
87
+ false
88
+ end
89
+ end
90
+
91
+ class PipCompilePackageManager < Dependabot::Ecosystem::VersionManager
92
+ extend T::Sig
93
+
94
+ NAME = "pip-compile"
95
+
96
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
97
+
98
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
99
+
100
+ sig do
101
+ params(
102
+ raw_version: String,
103
+ requirement: T.nilable(Requirement)
104
+ ).void
105
+ end
106
+ def initialize(raw_version, requirement = nil)
107
+ super(
108
+ NAME,
109
+ Version.new(raw_version),
110
+ SUPPORTED_VERSIONS,
111
+ DEPRECATED_VERSIONS,
112
+ requirement,
113
+ )
114
+ end
115
+
116
+ sig { override.returns(T::Boolean) }
117
+ def deprecated?
118
+ false
119
+ end
120
+
121
+ sig { override.returns(T::Boolean) }
122
+ def unsupported?
123
+ false
124
+ end
125
+ end
126
+
127
+ class PipenvPackageManager < Dependabot::Ecosystem::VersionManager
128
+ extend T::Sig
129
+
130
+ NAME = "pipenv"
131
+
132
+ MANIFEST_FILENAME = "Pipfile"
133
+ LOCKFILE_FILENAME = "Pipfile.lock"
134
+
135
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
136
+
137
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
138
+
139
+ sig do
140
+ params(
141
+ raw_version: String,
142
+ requirement: T.nilable(Requirement)
143
+ ).void
144
+ end
145
+ def initialize(raw_version, requirement = nil)
146
+ super(
147
+ NAME,
148
+ Version.new(raw_version),
149
+ SUPPORTED_VERSIONS,
150
+ DEPRECATED_VERSIONS,
151
+ requirement,
152
+ )
153
+ end
154
+
155
+ sig { override.returns(T::Boolean) }
156
+ def deprecated?
157
+ false
158
+ end
159
+
160
+ sig { override.returns(T::Boolean) }
161
+ def unsupported?
162
+ false
163
+ end
164
+ end
165
+ end
166
+ end
@@ -113,6 +113,10 @@ module Dependabot
113
113
  end
114
114
 
115
115
  def resolver
116
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
117
+ Dependabot.logger.info("Python package resolver : #{resolver_type}")
118
+ end
119
+
116
120
  case resolver_type
117
121
  when :pip_compile then pip_compile_version_resolver
118
122
  when :pipenv then pipenv_version_resolver
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.288.0
4
+ version: 0.289.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2024-12-05 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.288.0
19
+ version: 0.289.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.288.0
26
+ version: 0.289.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -266,10 +266,12 @@ files:
266
266
  - lib/dependabot/python/file_updater/requirement_file_updater.rb
267
267
  - lib/dependabot/python/file_updater/requirement_replacer.rb
268
268
  - lib/dependabot/python/file_updater/setup_file_sanitizer.rb
269
+ - lib/dependabot/python/language.rb
269
270
  - lib/dependabot/python/language_version_manager.rb
270
271
  - lib/dependabot/python/metadata_finder.rb
271
272
  - lib/dependabot/python/name_normaliser.rb
272
273
  - lib/dependabot/python/native_helpers.rb
274
+ - lib/dependabot/python/package_manager.rb
273
275
  - lib/dependabot/python/pip_compile_file_matcher.rb
274
276
  - lib/dependabot/python/pipenv_runner.rb
275
277
  - lib/dependabot/python/requirement.rb
@@ -288,7 +290,7 @@ licenses:
288
290
  - MIT
289
291
  metadata:
290
292
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
291
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.288.0
293
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.289.0
292
294
  post_install_message:
293
295
  rdoc_options: []
294
296
  require_paths: