dependabot-python 0.366.0 → 0.367.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 +4 -4
- data/lib/dependabot/python/dependency_grapher/lockfile_generator.rb +131 -0
- data/lib/dependabot/python/dependency_grapher.rb +77 -1
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +13 -6
- data/lib/dependabot/python/file_parser/setup_file_parser.rb +15 -2
- data/lib/dependabot/python/file_parser.rb +10 -2
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +11 -8
- data/lib/dependabot/python/file_updater/setup_file_sanitizer.rb +12 -3
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e54cc0660ba9d6007661da639e66151ac7cdab9dafb2ea460ee544b825e7790
|
|
4
|
+
data.tar.gz: eaaec236cd949ffa2a446b5056a56378a2bcf954eb32da78e0ec0cb9f7b0bb4c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88f0d4fc4032adab9165c2d0187ef56660ebc219472723ad97c61c128e764cfeac49d4a49abfa4999f05ac85f9ccee3189dec442fc5701bf1afd41d18d706fba
|
|
7
|
+
data.tar.gz: 931b2880cdfda0184098b61416963e02542a13993752f83e8682f3c25b7de3e2f6c45affe5a80e231a331fc6bcd4b62b0eec3bab33aae065a92d70932e31c844
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
|
|
6
|
+
require "dependabot/dependency_file"
|
|
7
|
+
require "dependabot/shared_helpers"
|
|
8
|
+
require "dependabot/python/file_parser/python_requirement_parser"
|
|
9
|
+
require "dependabot/python/language_version_manager"
|
|
10
|
+
|
|
11
|
+
module Dependabot
|
|
12
|
+
module Python
|
|
13
|
+
class DependencyGrapher < Dependabot::DependencyGraphers::Base
|
|
14
|
+
class LockfileGenerator
|
|
15
|
+
extend T::Sig
|
|
16
|
+
|
|
17
|
+
LOCKFILE_NAME = "poetry.lock"
|
|
18
|
+
|
|
19
|
+
sig do
|
|
20
|
+
params(
|
|
21
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
|
22
|
+
credentials: T::Array[Dependabot::Credential]
|
|
23
|
+
).void
|
|
24
|
+
end
|
|
25
|
+
def initialize(dependency_files:, credentials:)
|
|
26
|
+
@dependency_files = dependency_files
|
|
27
|
+
@credentials = credentials
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
31
|
+
def generate
|
|
32
|
+
SharedHelpers.in_a_temporary_directory do
|
|
33
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
|
34
|
+
write_temporary_files
|
|
35
|
+
language_version_manager.install_required_python
|
|
36
|
+
run_poetry_lock
|
|
37
|
+
read_generated_lockfile
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
41
|
+
handle_generation_error(e)
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
48
|
+
attr_reader :dependency_files
|
|
49
|
+
|
|
50
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
|
51
|
+
attr_reader :credentials
|
|
52
|
+
|
|
53
|
+
sig { void }
|
|
54
|
+
def write_temporary_files
|
|
55
|
+
dependency_files.each do |file|
|
|
56
|
+
path = file.name
|
|
57
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
58
|
+
File.write(path, file.content)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
sig { void }
|
|
65
|
+
def run_poetry_lock
|
|
66
|
+
Dependabot.logger.info("Generating poetry.lock for dependency graphing")
|
|
67
|
+
|
|
68
|
+
# Use system git instead of the pure Python dulwich
|
|
69
|
+
run_poetry_command("pyenv exec poetry config system-git-client true")
|
|
70
|
+
|
|
71
|
+
# --no-interaction avoids password prompts
|
|
72
|
+
run_poetry_command("pyenv exec poetry lock --no-interaction")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
76
|
+
def read_generated_lockfile
|
|
77
|
+
unless File.exist?(LOCKFILE_NAME)
|
|
78
|
+
Dependabot.logger.warn("#{LOCKFILE_NAME} was not generated")
|
|
79
|
+
return nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
content = File.read(LOCKFILE_NAME)
|
|
83
|
+
|
|
84
|
+
Dependabot::DependencyFile.new(
|
|
85
|
+
name: LOCKFILE_NAME,
|
|
86
|
+
content: content,
|
|
87
|
+
directory: pyproject_directory
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
sig { returns(String) }
|
|
92
|
+
def pyproject_directory
|
|
93
|
+
pyproject = dependency_files.find { |f| f.name == "pyproject.toml" }
|
|
94
|
+
pyproject&.directory || "/"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
sig { params(command: String).returns(String) }
|
|
98
|
+
def run_poetry_command(command)
|
|
99
|
+
SharedHelpers.run_shell_command(command, fingerprint: command)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
sig { returns(LanguageVersionManager) }
|
|
103
|
+
def language_version_manager
|
|
104
|
+
@language_version_manager ||= T.let(
|
|
105
|
+
LanguageVersionManager.new(
|
|
106
|
+
python_requirement_parser: python_requirement_parser
|
|
107
|
+
),
|
|
108
|
+
T.nilable(LanguageVersionManager)
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
sig { returns(FileParser::PythonRequirementParser) }
|
|
113
|
+
def python_requirement_parser
|
|
114
|
+
@python_requirement_parser ||= T.let(
|
|
115
|
+
FileParser::PythonRequirementParser.new(
|
|
116
|
+
dependency_files: dependency_files
|
|
117
|
+
),
|
|
118
|
+
T.nilable(FileParser::PythonRequirementParser)
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).void }
|
|
123
|
+
def handle_generation_error(error)
|
|
124
|
+
Dependabot.logger.error(
|
|
125
|
+
"Failed to generate #{LOCKFILE_NAME}: #{error.message}"
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -16,12 +16,14 @@ require "toml-rb"
|
|
|
16
16
|
module Dependabot
|
|
17
17
|
module Python
|
|
18
18
|
class DependencyGrapher < Dependabot::DependencyGraphers::Base
|
|
19
|
+
require_relative "dependency_grapher/lockfile_generator"
|
|
20
|
+
|
|
19
21
|
sig { override.returns(Dependabot::DependencyFile) }
|
|
20
22
|
def relevant_dependency_file
|
|
21
23
|
dependency_files_by_package_manager = T.let(
|
|
22
24
|
{
|
|
23
25
|
PipenvPackageManager::NAME => [pipfile_lock, pipfile],
|
|
24
|
-
PoetryPackageManager::NAME => [
|
|
26
|
+
PoetryPackageManager::NAME => [committed_poetry_lock, pyproject_toml],
|
|
25
27
|
PipCompilePackageManager::NAME => [pip_compile_lockfile, pip_compile_manifest, pyproject_toml],
|
|
26
28
|
PipPackageManager::NAME => [pip_requirements_file, pyproject_toml, pipfile_lock, pipfile, setup_file,
|
|
27
29
|
setup_cfg_file]
|
|
@@ -36,13 +38,87 @@ module Dependabot
|
|
|
36
38
|
raise DependabotError, "No supported dependency file present."
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
sig { override.void }
|
|
42
|
+
def prepare!
|
|
43
|
+
if poetry_project_without_lockfile?
|
|
44
|
+
Dependabot.logger.info("No poetry.lock found, generating ephemeral lockfile for dependency graphing")
|
|
45
|
+
generate_ephemeral_lockfile!
|
|
46
|
+
emit_missing_lockfile_warning! if @ephemeral_lockfile_generated
|
|
47
|
+
end
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
39
51
|
private
|
|
40
52
|
|
|
53
|
+
# Returns the poetry.lock only if it was committed to the repo,
|
|
54
|
+
# not if it was generated ephemerally. This ensures that
|
|
55
|
+
# relevant_dependency_file reports the real manifest (pyproject.toml).
|
|
56
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
57
|
+
def committed_poetry_lock
|
|
58
|
+
return nil if @ephemeral_lockfile_generated
|
|
59
|
+
|
|
60
|
+
poetry_lock
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# The file parser only identifies Poetry when poetry.lock is present,
|
|
64
|
+
# so we detect it independently by checking for [tool.poetry] in pyproject.toml.
|
|
65
|
+
# Within the python image, no other package manager uses this section
|
|
66
|
+
# (uv runs in a separate image).
|
|
67
|
+
sig { returns(T::Boolean) }
|
|
68
|
+
def poetry_project_without_lockfile?
|
|
69
|
+
return false if poetry_lock
|
|
70
|
+
return false unless pyproject_toml
|
|
71
|
+
|
|
72
|
+
parsed = TomlRB.parse(T.must(pyproject_toml&.content))
|
|
73
|
+
!parsed.dig("tool", "poetry").nil?
|
|
74
|
+
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
|
|
41
78
|
sig { returns(String) }
|
|
42
79
|
def python_package_manager
|
|
43
80
|
T.must(file_parser.ecosystem).package_manager.name
|
|
44
81
|
end
|
|
45
82
|
|
|
83
|
+
sig { void }
|
|
84
|
+
def generate_ephemeral_lockfile!
|
|
85
|
+
generator = LockfileGenerator.new(
|
|
86
|
+
dependency_files: dependency_files,
|
|
87
|
+
credentials: file_parser.credentials
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
ephemeral_lockfile = generator.generate
|
|
91
|
+
return unless ephemeral_lockfile
|
|
92
|
+
|
|
93
|
+
inject_ephemeral_lockfile(ephemeral_lockfile)
|
|
94
|
+
@ephemeral_lockfile_generated = T.let(true, T.nilable(T::Boolean))
|
|
95
|
+
|
|
96
|
+
Dependabot.logger.info(
|
|
97
|
+
"Successfully generated ephemeral #{ephemeral_lockfile.name} for dependency graphing"
|
|
98
|
+
)
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
Dependabot.logger.warn(
|
|
101
|
+
"Failed to generate ephemeral lockfile: #{e.message}. " \
|
|
102
|
+
"Dependency versions may not be resolved."
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sig { params(ephemeral_lockfile: Dependabot::DependencyFile).void }
|
|
107
|
+
def inject_ephemeral_lockfile(ephemeral_lockfile)
|
|
108
|
+
dependency_files << ephemeral_lockfile
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
sig { void }
|
|
112
|
+
def emit_missing_lockfile_warning!
|
|
113
|
+
Dependabot.logger.warn(
|
|
114
|
+
"No poetry.lock was found in this repository. " \
|
|
115
|
+
"Dependabot generated a temporary lockfile to determine exact dependency versions.\n\n" \
|
|
116
|
+
"To ensure consistent builds and security scanning, we recommend committing your poetry.lock file. " \
|
|
117
|
+
"Without a committed lockfile, resolved dependency versions may change between scans " \
|
|
118
|
+
"due to new package releases."
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
46
122
|
sig { override.params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
|
|
47
123
|
def fetch_subdependencies(dependency)
|
|
48
124
|
package_relationships.fetch(dependency.name, []).select { |child| dependency_name_set.include?(child) }
|
|
@@ -46,11 +46,7 @@ module Dependabot
|
|
|
46
46
|
def pyproject_dependencies
|
|
47
47
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
48
48
|
|
|
49
|
-
# Parse Poetry dependencies if [tool.poetry] section exists
|
|
50
49
|
dependencies += poetry_dependencies if using_poetry?
|
|
51
|
-
|
|
52
|
-
# Parse PEP 621/735 dependencies if those sections exist
|
|
53
|
-
# This handles hybrid projects that have both Poetry and PEP 621 sections
|
|
54
50
|
dependencies += pep621_pep735_dependencies if using_pep621? || using_pep735?
|
|
55
51
|
|
|
56
52
|
dependencies
|
|
@@ -101,7 +97,7 @@ module Dependabot
|
|
|
101
97
|
|
|
102
98
|
dependencies <<
|
|
103
99
|
Dependency.new(
|
|
104
|
-
name:
|
|
100
|
+
name: normalise(dep["name"]),
|
|
105
101
|
version: dep["version"]&.include?("*") ? nil : dep["version"],
|
|
106
102
|
requirements: [{
|
|
107
103
|
requirement: dep["requirement"],
|
|
@@ -109,7 +105,8 @@ module Dependabot
|
|
|
109
105
|
source: nil,
|
|
110
106
|
groups: [dep["requirement_type"]].compact
|
|
111
107
|
}],
|
|
112
|
-
package_manager: "pip"
|
|
108
|
+
package_manager: "pip",
|
|
109
|
+
metadata: extras_metadata(dep["extras"])
|
|
113
110
|
)
|
|
114
111
|
end
|
|
115
112
|
|
|
@@ -147,6 +144,16 @@ module Dependabot
|
|
|
147
144
|
NameNormaliser.normalise_including_extras(name, extras)
|
|
148
145
|
end
|
|
149
146
|
|
|
147
|
+
# Build metadata hash storing extras as a comma-separated string.
|
|
148
|
+
# Stored in metadata so the file updater can reconstruct the full
|
|
149
|
+
# PEP 621 declaration (e.g. "cachecontrol[filecache]>=0.14.0").
|
|
150
|
+
sig { params(extras: T::Array[String]).returns(T::Hash[Symbol, String]) }
|
|
151
|
+
def extras_metadata(extras)
|
|
152
|
+
return {} if extras.empty?
|
|
153
|
+
|
|
154
|
+
{ extras: extras.join(",") }
|
|
155
|
+
end
|
|
156
|
+
|
|
150
157
|
# @param req can be an Array, Hash or String that represents the constraints for a dependency
|
|
151
158
|
sig { params(req: T.untyped, type: String).returns(T::Array[T::Hash[Symbol, T.nilable(String)]]) }
|
|
152
159
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
@@ -43,7 +43,7 @@ module Dependabot
|
|
|
43
43
|
|
|
44
44
|
dependencies <<
|
|
45
45
|
Dependency.new(
|
|
46
|
-
name:
|
|
46
|
+
name: normalise(dep["name"]),
|
|
47
47
|
version: dep["version"]&.include?("*") ? nil : dep["version"],
|
|
48
48
|
requirements: [{
|
|
49
49
|
requirement: dep["requirement"],
|
|
@@ -51,7 +51,8 @@ module Dependabot
|
|
|
51
51
|
source: nil,
|
|
52
52
|
groups: [dep["requirement_type"]]
|
|
53
53
|
}],
|
|
54
|
-
package_manager: "pip"
|
|
54
|
+
package_manager: "pip",
|
|
55
|
+
metadata: extras_metadata(dep["extras"])
|
|
55
56
|
)
|
|
56
57
|
end
|
|
57
58
|
dependencies
|
|
@@ -184,6 +185,18 @@ module Dependabot
|
|
|
184
185
|
NameNormaliser.normalise_including_extras(name, extras)
|
|
185
186
|
end
|
|
186
187
|
|
|
188
|
+
sig { params(name: String).returns(String) }
|
|
189
|
+
def normalise(name)
|
|
190
|
+
NameNormaliser.normalise(name)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
sig { params(extras: T::Array[String]).returns(T::Hash[Symbol, String]) }
|
|
194
|
+
def extras_metadata(extras)
|
|
195
|
+
return {} if extras.empty?
|
|
196
|
+
|
|
197
|
+
{ extras: extras.join(",") }
|
|
198
|
+
end
|
|
199
|
+
|
|
187
200
|
sig { returns(T.untyped) }
|
|
188
201
|
def setup_file
|
|
189
202
|
dependency_files.find { |f| f.name == "setup.py" }
|
|
@@ -293,10 +293,11 @@ module Dependabot
|
|
|
293
293
|
|
|
294
294
|
dependencies <<
|
|
295
295
|
Dependency.new(
|
|
296
|
-
name:
|
|
296
|
+
name: NameNormaliser.normalise(name),
|
|
297
297
|
version: version&.include?("*") ? nil : version,
|
|
298
298
|
requirements: requirements,
|
|
299
|
-
package_manager: "pip"
|
|
299
|
+
package_manager: "pip",
|
|
300
|
+
metadata: extras_metadata(dep["extras"])
|
|
300
301
|
)
|
|
301
302
|
end
|
|
302
303
|
dependencies
|
|
@@ -467,6 +468,13 @@ module Dependabot
|
|
|
467
468
|
NameNormaliser.normalise_including_extras(name, extras)
|
|
468
469
|
end
|
|
469
470
|
|
|
471
|
+
sig { params(extras: T::Array[String]).returns(T::Hash[Symbol, String]) }
|
|
472
|
+
def extras_metadata(extras)
|
|
473
|
+
return {} if extras.empty?
|
|
474
|
+
|
|
475
|
+
{ extras: extras.join(",") }
|
|
476
|
+
end
|
|
477
|
+
|
|
470
478
|
sig { override.returns(T.untyped) }
|
|
471
479
|
def check_required_files
|
|
472
480
|
filenames = dependency_files.map(&:name)
|
|
@@ -49,7 +49,6 @@ module Dependabot
|
|
|
49
49
|
@language_version_manager = T.let(nil, T.nilable(LanguageVersionManager))
|
|
50
50
|
@python_requirement_parser = T.let(nil, T.nilable(FileParser::PythonRequirementParser))
|
|
51
51
|
@updated_pyproject_content = T.let(nil, T.nilable(String))
|
|
52
|
-
@python_helper_path = T.let(nil, T.nilable(String))
|
|
53
52
|
@poetry_lock = T.let(nil, T.nilable(Dependabot::DependencyFile))
|
|
54
53
|
end
|
|
55
54
|
|
|
@@ -363,7 +362,7 @@ module Dependabot
|
|
|
363
362
|
write_temporary_dependency_files(pyproject_content)
|
|
364
363
|
|
|
365
364
|
SharedHelpers.run_helper_subprocess(
|
|
366
|
-
command: "pyenv exec python3 #{python_helper_path}",
|
|
365
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
367
366
|
function: "get_pyproject_hash",
|
|
368
367
|
args: [T.cast(dir, Pathname).to_s]
|
|
369
368
|
)
|
|
@@ -386,7 +385,16 @@ module Dependabot
|
|
|
386
385
|
|
|
387
386
|
sig { params(dep: Dependabot::Dependency, old_req: String).returns(Regexp) }
|
|
388
387
|
def pep621_declaration_regex(dep, old_req)
|
|
389
|
-
/(?<declaration>["']#{escape(dep)}#{Regexp.escape(old_req)}["'])/mi
|
|
388
|
+
/(?<declaration>["']#{escape(dep)}#{extras_pattern(dep)}#{Regexp.escape(old_req)}["'])/mi
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Reconstructs extras from metadata for PEP 621 regex matching.
|
|
392
|
+
sig { params(dep: Dependabot::Dependency).returns(String) }
|
|
393
|
+
def extras_pattern(dep)
|
|
394
|
+
extras_str = dep.metadata[:extras]
|
|
395
|
+
return "" unless extras_str.is_a?(String) && !extras_str.empty?
|
|
396
|
+
|
|
397
|
+
"\\[" + extras_str.split(",").map { |e| Regexp.escape(e.strip) }.join(",\\s*") + "\\]"
|
|
390
398
|
end
|
|
391
399
|
|
|
392
400
|
sig { params(dep: Dependency).returns(String) }
|
|
@@ -446,11 +454,6 @@ module Dependabot
|
|
|
446
454
|
@lockfile ||= poetry_lock
|
|
447
455
|
end
|
|
448
456
|
|
|
449
|
-
sig { returns(String) }
|
|
450
|
-
def python_helper_path
|
|
451
|
-
NativeHelpers.python_helper_path
|
|
452
|
-
end
|
|
453
|
-
|
|
454
457
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
455
458
|
def poetry_lock
|
|
456
459
|
dependency_files.find { |f| f.name == "poetry.lock" }
|
|
@@ -64,7 +64,7 @@ module Dependabot
|
|
|
64
64
|
next unless first[:groups]
|
|
65
65
|
.include?("install_requires")
|
|
66
66
|
|
|
67
|
-
dep
|
|
67
|
+
name_with_extras(dep) + first[:requirement].to_s
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ module Dependabot
|
|
|
76
76
|
next unless first[:groups]
|
|
77
77
|
.include?("setup_requires")
|
|
78
78
|
|
|
79
|
-
dep
|
|
79
|
+
name_with_extras(dep) + first[:requirement].to_s
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
|
|
@@ -92,7 +92,7 @@ module Dependabot
|
|
|
92
92
|
|
|
93
93
|
hash[group.split(":").last] ||= []
|
|
94
94
|
hash[group.split(":").last] <<
|
|
95
|
-
(dep
|
|
95
|
+
(name_with_extras(dep) + first[:requirement].to_s)
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -100,6 +100,15 @@ module Dependabot
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
# Reconstruct dependency name with extras from metadata.
|
|
104
|
+
sig { params(dep: Dependabot::Dependency).returns(String) }
|
|
105
|
+
def name_with_extras(dep)
|
|
106
|
+
extras_str = dep.metadata[:extras]
|
|
107
|
+
return dep.name unless extras_str.is_a?(String) && !extras_str.empty?
|
|
108
|
+
|
|
109
|
+
"#{dep.name}[#{extras_str}]"
|
|
110
|
+
end
|
|
111
|
+
|
|
103
112
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
|
104
113
|
def parsed_setup_file
|
|
105
114
|
@parsed_setup_file ||=
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-python
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.367.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.367.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.367.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -250,6 +250,7 @@ files:
|
|
|
250
250
|
- lib/dependabot/python.rb
|
|
251
251
|
- lib/dependabot/python/authed_url_builder.rb
|
|
252
252
|
- lib/dependabot/python/dependency_grapher.rb
|
|
253
|
+
- lib/dependabot/python/dependency_grapher/lockfile_generator.rb
|
|
253
254
|
- lib/dependabot/python/file_fetcher.rb
|
|
254
255
|
- lib/dependabot/python/file_parser.rb
|
|
255
256
|
- lib/dependabot/python/file_parser/pipfile_files_parser.rb
|
|
@@ -293,7 +294,7 @@ licenses:
|
|
|
293
294
|
- MIT
|
|
294
295
|
metadata:
|
|
295
296
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
296
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
297
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.367.0
|
|
297
298
|
rdoc_options: []
|
|
298
299
|
require_paths:
|
|
299
300
|
- lib
|