dependabot-python 0.393.0 → 0.395.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: 242cdbd71bb6b0424ba7c88daf21d1839db3eb9d3f0beb2ad9e070f3d624cf77
4
- data.tar.gz: 40a2faa1353d5fd82480211fee5ac28840996cf483fdf3c884fb558702396f08
3
+ metadata.gz: 0a1dec50c1cd900eb433c984eb046d5a4b4e327c036d83c09e4d90ce1dd93572
4
+ data.tar.gz: 608eb3b97ebcc5ee85f66fda06bb4f1f2407e244f3f582c333ec9cf604edd90e
5
5
  SHA512:
6
- metadata.gz: 9a75d27db29ca5df37ea4e4962da3cbbfa0c05627044fd340d9b0b6f657108d44ff78bc40c206b2d0ac3a6d8387f3f0f30cd7dfeacafee122fd92b3e2d981954
7
- data.tar.gz: 7651c73fdab13d9f091cada4a7d7531842e90042825ef0052c67882e90958870a26fd3936ac213bcd69362d9ac3b9d64d422a34ea4f9646344468851c6969b7c
6
+ metadata.gz: 5b2de818a1e9b73a7b1af590c4f9bdf3c5ecf64d8bdd36e5043831e9d781f6fb829fe3282e0080e129595eb5adc49631c4d956bc1501dcd623fbeab8a8ba7b2a
7
+ data.tar.gz: 90ae8a95010a4a414c1fdffd2d9ad371c3ff3418852191297d03699abadb62b5d7aa4b7ed9dae5e288bd246c7475f7ee29b8d7ed11f84b822b9efb2cc30ab903
@@ -1,4 +1,4 @@
1
- pip==26.1.2
1
+ pip==26.2.1
2
2
  pip-tools==7.6.1
3
3
  flake8==7.3.0
4
4
  hashin==1.0.5
@@ -10,4 +10,4 @@ pytest==9.1.1
10
10
  tomli==2.4.1
11
11
 
12
12
  # Some dependencies will only install if Cython is present
13
- Cython==3.2.9
13
+ Cython==3.3.0
@@ -0,0 +1,53 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/python/file_parser"
7
+
8
+ module Dependabot
9
+ module Python
10
+ class FileParser < Dependabot::FileParsers::Base
11
+ class PepDependency < T::ImmutableStruct
12
+ extend T::Sig
13
+
14
+ const :name, String
15
+ const :version, T.nilable(String), default: nil
16
+ const :markers, T.nilable(String), default: nil
17
+ const :file, String
18
+ const :requirement, T.nilable(String), default: nil
19
+ const :source_requirement, T.nilable(String), default: nil
20
+ const :extras, T::Array[String]
21
+ const :requirement_type, T.nilable(String), default: nil
22
+
23
+ sig { params(result: Object).returns(T::Array[PepDependency]) }
24
+ def self.from_helper_result(result)
25
+ PyprojectValueParser.array(result, "PEP dependency result").map do |value|
26
+ from_object(value)
27
+ end
28
+ end
29
+
30
+ sig { params(value: Object).returns(PepDependency) }
31
+ def self.from_object(value)
32
+ hash = PyprojectValueParser.object_hash(value, "PEP dependency")
33
+ new(
34
+ name: PyprojectValueParser.string(hash["name"], "PEP dependency name"),
35
+ version: PyprojectValueParser.optional_string(hash["version"], "PEP dependency version"),
36
+ markers: PyprojectValueParser.optional_string(hash["markers"], "PEP dependency markers"),
37
+ file: PyprojectValueParser.string(hash["file"], "PEP dependency file"),
38
+ requirement: PyprojectValueParser.optional_string(hash["requirement"], "PEP dependency requirement"),
39
+ source_requirement: PyprojectValueParser.optional_string(
40
+ hash["source_requirement"],
41
+ "PEP dependency source_requirement"
42
+ ),
43
+ extras: PyprojectValueParser.string_array(hash["extras"], "PEP dependency extras"),
44
+ requirement_type: PyprojectValueParser.optional_string(
45
+ hash["requirement_type"],
46
+ "PEP dependency requirement_type"
47
+ )
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,95 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "toml-rb"
5
+ require "sorbet-runtime"
6
+
7
+ require "dependabot/dependency_file"
8
+ require "dependabot/errors"
9
+ require "dependabot/python/file_parser"
10
+
11
+ module Dependabot
12
+ module Python
13
+ class FileParser < Dependabot::FileParsers::Base
14
+ class PoetryLock
15
+ extend T::Sig
16
+
17
+ class Package < T::ImmutableStruct
18
+ extend T::Sig
19
+
20
+ const :name, String
21
+ const :version, String
22
+ const :source_type, T.nilable(String), default: nil
23
+
24
+ sig { params(value: Object).returns(Package) }
25
+ def self.from_object(value)
26
+ hash = PyprojectValueParser.object_hash(value, "Poetry lock package")
27
+ source = hash["source"]
28
+ source_hash =
29
+ if source.nil?
30
+ nil
31
+ else
32
+ PyprojectValueParser.object_hash(source, "Poetry lock package source")
33
+ end
34
+
35
+ new(
36
+ name: PyprojectValueParser.string(hash["name"], "Poetry lock package name"),
37
+ version: PyprojectValueParser.string(hash["version"], "Poetry lock package version"),
38
+ source_type: PyprojectValueParser.optional_string(
39
+ source_hash&.[]("type"),
40
+ "Poetry lock package source type"
41
+ )
42
+ )
43
+ end
44
+
45
+ sig { returns(T::Hash[Symbol, T.nilable(String)]) }
46
+ def to_h
47
+ {
48
+ name: name,
49
+ version: version,
50
+ source_type: source_type
51
+ }
52
+ end
53
+ end
54
+
55
+ sig { returns(T::Array[Package]) }
56
+ attr_reader :packages
57
+
58
+ sig { params(packages: T::Array[Package]).void }
59
+ def initialize(packages)
60
+ @packages = packages
61
+ end
62
+
63
+ sig { params(file: Dependabot::DependencyFile).returns(PoetryLock) }
64
+ def self.from_file(file)
65
+ parsed = T.cast(TomlRB.parse(T.must(file.content)), Object)
66
+ document = PyprojectValueParser.object_hash(parsed, "poetry.lock")
67
+ value = document["package"]
68
+ packages =
69
+ if value.nil?
70
+ []
71
+ else
72
+ PyprojectValueParser.array(value, "poetry.lock package").map do |package|
73
+ Package.from_object(package)
74
+ end
75
+ end
76
+ new(packages)
77
+ rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
78
+ raise Dependabot::DependencyFileNotParseable, file.path
79
+ end
80
+
81
+ sig do
82
+ params(
83
+ name: String,
84
+ _normalizer: T.proc.params(name: String).returns(String)
85
+ )
86
+ .returns(T.nilable(String))
87
+ end
88
+ def version_for(name, &_normalizer)
89
+ normalized_name = yield(name)
90
+ packages.find { |package| yield(package.name) == normalized_name }&.version
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,284 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "toml-rb"
5
+ require "sorbet-runtime"
6
+
7
+ require "dependabot/dependency_file"
8
+ require "dependabot/errors"
9
+ require "dependabot/python/file_parser"
10
+
11
+ module Dependabot
12
+ module Python
13
+ class FileParser < Dependabot::FileParsers::Base
14
+ module PyprojectValueParser
15
+ extend T::Sig
16
+
17
+ ObjectHash = T.type_alias { T::Hash[String, Object] }
18
+ PoetryRequirement = T.type_alias { T.any(String, ObjectHash) }
19
+ PoetryDependencyMap = T.type_alias { T::Hash[String, T::Array[PoetryRequirement]] }
20
+
21
+ sig { params(value: Object, context: String).returns(ObjectHash) }
22
+ def self.object_hash(value, context)
23
+ raise TypeError, "#{context} must be an object" unless value.is_a?(Hash)
24
+
25
+ result = T.let({}, ObjectHash)
26
+ value.each do |raw_key, raw_value|
27
+ key = T.cast(raw_key, Object)
28
+ raise TypeError, "#{context} keys must be strings" unless key.is_a?(String)
29
+
30
+ result[key] = T.cast(raw_value, Object)
31
+ end
32
+ result
33
+ end
34
+
35
+ sig { params(value: Object, context: String).returns(T::Array[Object]) }
36
+ def self.array(value, context)
37
+ raise TypeError, "#{context} must be an array" unless value.is_a?(Array)
38
+
39
+ value.map { |item| T.cast(item, Object) }
40
+ end
41
+
42
+ sig { params(value: Object, context: String).returns(String) }
43
+ def self.string(value, context)
44
+ return value if value.is_a?(String)
45
+
46
+ raise TypeError, "#{context} must be a string"
47
+ end
48
+
49
+ sig { params(value: T.nilable(Object), context: String).returns(T.nilable(String)) }
50
+ def self.optional_string(value, context)
51
+ return if value.nil?
52
+
53
+ string(value, context)
54
+ end
55
+
56
+ sig { params(value: Object, context: String).returns(T::Array[String]) }
57
+ def self.string_array(value, context)
58
+ array(value, context).map do |item|
59
+ raise TypeError, "#{context} must contain only strings" unless item.is_a?(String)
60
+
61
+ item
62
+ end
63
+ end
64
+
65
+ sig { params(value: Object, name: String).returns(T::Array[PoetryRequirement]) }
66
+ def self.poetry_requirements(value, name)
67
+ flattened = value.is_a?(Array) ? value.flatten : [value]
68
+ flattened.compact.map do |item|
69
+ item = T.cast(item, Object)
70
+ case item
71
+ when String
72
+ item
73
+ when Hash
74
+ object_hash(item, "Poetry dependency #{name}")
75
+ else
76
+ raise TypeError, "Poetry dependency #{name} must be a string, object, or array"
77
+ end
78
+ end
79
+ end
80
+
81
+ sig { params(value: Object, context: String).returns(PoetryDependencyMap) }
82
+ def self.poetry_dependency_map(value, context)
83
+ object_hash(value, context).to_h do |name, requirement|
84
+ [name, poetry_requirements(requirement, name)]
85
+ end
86
+ end
87
+ end
88
+ private_constant :PyprojectValueParser
89
+
90
+ class PyprojectDocument
91
+ extend T::Sig
92
+
93
+ PoetryRequirement = T.type_alias { PyprojectValueParser::PoetryRequirement }
94
+ PoetryDependencyMap = T.type_alias { PyprojectValueParser::PoetryDependencyMap }
95
+
96
+ class PoetrySource < T::ImmutableStruct
97
+ const :name, String
98
+ const :url, T.nilable(String), default: nil
99
+ end
100
+
101
+ class ProjectMetadata < T::ImmutableStruct
102
+ const :name, T.nilable(String), default: nil
103
+ const :description, T.nilable(String), default: nil
104
+ end
105
+
106
+ sig { params(data: PyprojectValueParser::ObjectHash).void }
107
+ def initialize(data)
108
+ @data = data
109
+ end
110
+
111
+ sig { params(file: Dependabot::DependencyFile).returns(PyprojectDocument) }
112
+ def self.from_file(file)
113
+ from_content(T.must(file.content))
114
+ rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
115
+ raise Dependabot::DependencyFileNotParseable, file.path
116
+ end
117
+
118
+ sig { params(content: String).returns(PyprojectDocument) }
119
+ def self.from_content(content)
120
+ parsed = T.cast(TomlRB.parse(content), Object)
121
+ new(PyprojectValueParser.object_hash(parsed, "pyproject.toml"))
122
+ end
123
+
124
+ sig { returns(T::Boolean) }
125
+ def poetry?
126
+ !poetry_root.nil?
127
+ end
128
+
129
+ sig { returns(T::Boolean) }
130
+ def project?
131
+ !section(@data, "project", "project").nil?
132
+ end
133
+
134
+ sig { returns(T.nilable(ProjectMetadata)) }
135
+ def poetry_metadata
136
+ metadata_from(poetry_root, "tool.poetry")
137
+ end
138
+
139
+ sig { returns(T.nilable(ProjectMetadata)) }
140
+ def project_metadata
141
+ metadata_from(section(@data, "project", "project"), "project")
142
+ end
143
+
144
+ sig { returns(T.nilable(ProjectMetadata)) }
145
+ def build_system_metadata
146
+ metadata_from(section(@data, "build-system", "build-system"), "build-system")
147
+ end
148
+
149
+ sig { returns(T::Boolean) }
150
+ def pep621?
151
+ project = section(@data, "project", "project")
152
+ build_system = section(@data, "build-system", "build-system")
153
+
154
+ !project&.[]("dependencies").nil? ||
155
+ !project&.[]("optional-dependencies").nil? ||
156
+ !build_system&.[]("requires").nil?
157
+ end
158
+
159
+ sig { returns(T::Boolean) }
160
+ def pep735?
161
+ @data.key?("dependency-groups")
162
+ end
163
+
164
+ sig { params(type: String).returns(PoetryDependencyMap) }
165
+ def poetry_dependencies(type)
166
+ root = poetry_root
167
+ return {} unless root
168
+
169
+ value = root[type]
170
+ return {} if value.nil?
171
+
172
+ PyprojectValueParser.poetry_dependency_map(value, "tool.poetry.#{type}")
173
+ end
174
+
175
+ sig { returns(T::Hash[String, PoetryDependencyMap]) }
176
+ def poetry_groups
177
+ root = poetry_root
178
+ return {} unless root
179
+
180
+ raw_groups = root["group"]
181
+ return {} if raw_groups.nil?
182
+
183
+ parsed_groups = PyprojectValueParser.object_hash(raw_groups, "tool.poetry.group")
184
+ parsed_groups.each_with_object({}) do |(name, value), groups|
185
+ group = PyprojectValueParser.object_hash(value, "tool.poetry.group.#{name}")
186
+ dependencies = group["dependencies"]
187
+ next if dependencies.nil?
188
+
189
+ groups[name] = PyprojectValueParser.poetry_dependency_map(
190
+ dependencies,
191
+ "tool.poetry.group.#{name}.dependencies"
192
+ )
193
+ end
194
+ end
195
+
196
+ sig { returns(T::Array[String]) }
197
+ def dynamic_fields
198
+ project = section(@data, "project", "project")
199
+ value = project&.[]("dynamic")
200
+ return [] if value.nil?
201
+
202
+ PyprojectValueParser.string_array(value, "project.dynamic")
203
+ end
204
+
205
+ sig { params(name: String).returns(T::Boolean) }
206
+ def optional_dependency_group?(name)
207
+ project = section(@data, "project", "project")
208
+ value = project&.[]("optional-dependencies")
209
+ return false if value.nil?
210
+
211
+ PyprojectValueParser.object_hash(value, "project.optional-dependencies").key?(name)
212
+ end
213
+
214
+ sig { params(name: String).returns(T.nilable(PoetrySource)) }
215
+ def poetry_source(name)
216
+ poetry_sources.find { |source| source.name == name }
217
+ end
218
+
219
+ sig { params(key: String).returns(T::Array[String]) }
220
+ def workspace_globs(key)
221
+ tool = section(@data, "tool", "tool")
222
+ uv = tool && section(tool, "uv", "tool.uv")
223
+ workspace = uv && section(uv, "workspace", "tool.uv.workspace")
224
+ value = workspace&.[](key)
225
+ return [] if value.nil?
226
+
227
+ PyprojectValueParser.string_array(value, "tool.uv.workspace.#{key}")
228
+ end
229
+
230
+ private
231
+
232
+ sig do
233
+ params(data: T.nilable(PyprojectValueParser::ObjectHash), context: String)
234
+ .returns(T.nilable(ProjectMetadata))
235
+ end
236
+ def metadata_from(data, context)
237
+ return unless data
238
+
239
+ ProjectMetadata.new(
240
+ name: PyprojectValueParser.optional_string(data["name"], "#{context}.name"),
241
+ description: PyprojectValueParser.optional_string(data["description"], "#{context}.description")
242
+ )
243
+ end
244
+
245
+ sig { returns(T.nilable(PyprojectValueParser::ObjectHash)) }
246
+ def poetry_root
247
+ tool = section(@data, "tool", "tool")
248
+ tool && section(tool, "poetry", "tool.poetry")
249
+ end
250
+
251
+ sig { returns(T::Array[PoetrySource]) }
252
+ def poetry_sources
253
+ root = poetry_root
254
+ return [] unless root
255
+
256
+ value = root["source"]
257
+ return [] if value.nil?
258
+
259
+ PyprojectValueParser.array(value, "tool.poetry.source").map do |source|
260
+ source = PyprojectValueParser.object_hash(source, "tool.poetry.source entry")
261
+ PoetrySource.new(
262
+ name: PyprojectValueParser.string(source["name"], "Poetry source name"),
263
+ url: PyprojectValueParser.optional_string(source["url"], "Poetry source url")
264
+ )
265
+ end
266
+ end
267
+
268
+ sig do
269
+ params(
270
+ hash: PyprojectValueParser::ObjectHash,
271
+ key: String,
272
+ context: String
273
+ ).returns(T.nilable(PyprojectValueParser::ObjectHash))
274
+ end
275
+ def section(hash, key, context)
276
+ value = hash[key]
277
+ return if value.nil?
278
+
279
+ PyprojectValueParser.object_hash(value, context)
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end