|
14 | 14 | from pathlib import Path
|
15 | 15 |
|
16 | 16 |
|
| 17 | +class SetupReaderError(Exception): |
| 18 | + pass |
| 19 | + |
| 20 | + |
17 | 21 | class SetupReader:
|
18 | 22 | """
|
19 | 23 | Class that reads a setup.py file without executing it.
|
@@ -192,113 +196,95 @@ def _find_sub_setup_call(
|
192 | 196 | return None
|
193 | 197 |
|
194 | 198 | def _find_install_requires(self, call: ast.Call, body: list[ast.stmt]) -> list[str]:
|
195 |
| - install_requires: list[str] = [] |
196 | 199 | value = self._find_in_call(call, "install_requires")
|
197 | 200 | if value is None:
|
198 | 201 | # Trying to find in kwargs
|
199 | 202 | kwargs = self._find_call_kwargs(call)
|
200 | 203 |
|
201 | 204 | if kwargs is None or not isinstance(kwargs, ast.Name):
|
202 |
| - return install_requires |
| 205 | + return [] |
203 | 206 |
|
204 | 207 | variable = self._find_variable_in_body(body, kwargs.id)
|
205 |
| - if not isinstance(variable, (ast.Dict, ast.Call)): |
206 |
| - return install_requires |
207 |
| - |
208 |
| - if isinstance(variable, ast.Call): |
209 |
| - if not isinstance(variable.func, ast.Name): |
210 |
| - return install_requires |
211 | 208 |
|
212 |
| - if variable.func.id != "dict": |
213 |
| - return install_requires |
| 209 | + if isinstance(variable, ast.Dict): |
| 210 | + value = self._find_in_dict(variable, "install_requires") |
214 | 211 |
|
| 212 | + elif ( |
| 213 | + isinstance(variable, ast.Call) |
| 214 | + and isinstance(variable.func, ast.Name) |
| 215 | + and variable.func.id == "dict" |
| 216 | + ): |
215 | 217 | value = self._find_in_call(variable, "install_requires")
|
| 218 | + |
216 | 219 | else:
|
217 |
| - value = self._find_in_dict(variable, "install_requires") |
| 220 | + raise SetupReaderError(f"Cannot handle variable {variable}") |
218 | 221 |
|
219 | 222 | if value is None:
|
220 |
| - return install_requires |
| 223 | + return [] |
221 | 224 |
|
222 |
| - if isinstance(value, ast.List): |
223 |
| - for el in value.elts: |
224 |
| - if isinstance(el, ast.Constant) and isinstance(el.value, str): |
225 |
| - install_requires.append(el.value) |
226 |
| - elif isinstance(value, ast.Name): |
227 |
| - variable = self._find_variable_in_body(body, value.id) |
| 225 | + if isinstance(value, ast.Name): |
| 226 | + value = self._find_variable_in_body(body, value.id) |
228 | 227 |
|
229 |
| - if variable is not None and isinstance(variable, ast.List): |
230 |
| - for el in variable.elts: |
231 |
| - if isinstance(el, ast.Constant) and isinstance(el.value, str): |
232 |
| - install_requires.append(el.value) |
| 228 | + if isinstance(value, ast.Constant) and value.value is None: |
| 229 | + return [] |
233 | 230 |
|
234 |
| - return install_requires |
| 231 | + if isinstance(value, ast.List): |
| 232 | + return string_list_values(value) |
| 233 | + |
| 234 | + raise SetupReaderError(f"Cannot handle value of type {type(value)}") |
235 | 235 |
|
236 | 236 | def _find_extras_require(
|
237 | 237 | self, call: ast.Call, body: list[ast.stmt]
|
238 | 238 | ) -> dict[str, list[str]]:
|
239 |
| - extras_require: dict[str, list[str]] = {} |
240 | 239 | value = self._find_in_call(call, "extras_require")
|
241 | 240 | if value is None:
|
242 | 241 | # Trying to find in kwargs
|
243 | 242 | kwargs = self._find_call_kwargs(call)
|
244 | 243 |
|
245 | 244 | if kwargs is None or not isinstance(kwargs, ast.Name):
|
246 |
| - return extras_require |
| 245 | + return {} |
247 | 246 |
|
248 | 247 | variable = self._find_variable_in_body(body, kwargs.id)
|
249 |
| - if not isinstance(variable, (ast.Dict, ast.Call)): |
250 |
| - return extras_require |
251 |
| - |
252 |
| - if isinstance(variable, ast.Call): |
253 |
| - if not isinstance(variable.func, ast.Name): |
254 |
| - return extras_require |
255 |
| - |
256 |
| - if variable.func.id != "dict": |
257 |
| - return extras_require |
| 248 | + if isinstance(variable, ast.Dict): |
| 249 | + value = self._find_in_dict(variable, "extras_require") |
258 | 250 |
|
| 251 | + elif ( |
| 252 | + isinstance(variable, ast.Call) |
| 253 | + and isinstance(variable.func, ast.Name) |
| 254 | + and variable.func.id == "dict" |
| 255 | + ): |
259 | 256 | value = self._find_in_call(variable, "extras_require")
|
| 257 | + |
260 | 258 | else:
|
261 |
| - value = self._find_in_dict(variable, "extras_require") |
| 259 | + raise SetupReaderError(f"Cannot handle variable {variable}") |
262 | 260 |
|
263 | 261 | if value is None:
|
264 |
| - return extras_require |
| 262 | + return {} |
| 263 | + |
| 264 | + if isinstance(value, ast.Name): |
| 265 | + value = self._find_variable_in_body(body, value.id) |
| 266 | + |
| 267 | + if isinstance(value, ast.Constant) and value.value is None: |
| 268 | + return {} |
265 | 269 |
|
266 | 270 | if isinstance(value, ast.Dict):
|
| 271 | + extras_require: dict[str, list[str]] = {} |
267 | 272 | val: ast.expr | None
|
268 | 273 | for key, val in zip(value.keys, value.values):
|
269 | 274 | if not isinstance(key, ast.Constant) or not isinstance(key.value, str):
|
270 |
| - continue |
| 275 | + raise SetupReaderError(f"Cannot handle key {key}") |
271 | 276 |
|
272 | 277 | if isinstance(val, ast.Name):
|
273 | 278 | val = self._find_variable_in_body(body, val.id)
|
274 | 279 |
|
275 |
| - if isinstance(val, ast.List): |
276 |
| - extras_require[key.value] = [ |
277 |
| - e.value |
278 |
| - for e in val.elts |
279 |
| - if isinstance(e, ast.Constant) and isinstance(e.value, str) |
280 |
| - ] |
281 |
| - elif isinstance(value, ast.Name): |
282 |
| - variable = self._find_variable_in_body(body, value.id) |
283 |
| - |
284 |
| - if variable is None or not isinstance(variable, ast.Dict): |
285 |
| - return extras_require |
286 |
| - |
287 |
| - for key, val in zip(variable.keys, variable.values): |
288 |
| - if not isinstance(key, ast.Constant) or not isinstance(key.value, str): |
289 |
| - continue |
| 280 | + if not isinstance(val, ast.List): |
| 281 | + raise SetupReaderError(f"Cannot handle value of type {type(val)}") |
290 | 282 |
|
291 |
| - if isinstance(val, ast.Name): |
292 |
| - val = self._find_variable_in_body(body, val.id) |
| 283 | + extras_require[key.value] = string_list_values(val) |
293 | 284 |
|
294 |
| - if isinstance(val, ast.List): |
295 |
| - extras_require[key.value] = [ |
296 |
| - e.value |
297 |
| - for e in val.elts |
298 |
| - if isinstance(e, ast.Constant) and isinstance(e.value, str) |
299 |
| - ] |
| 285 | + return extras_require |
300 | 286 |
|
301 |
| - return extras_require |
| 287 | + raise SetupReaderError(f"Cannot handle value of type {type(value)}") |
302 | 288 |
|
303 | 289 | def _find_single_string(
|
304 | 290 | self, call: ast.Call, body: list[ast.stmt], name: str
|
@@ -383,3 +369,15 @@ def _find_in_dict(self, dict_: ast.Dict, name: str) -> ast.expr | None:
|
383 | 369 | return val
|
384 | 370 |
|
385 | 371 | return None
|
| 372 | + |
| 373 | + |
| 374 | +def string_list_values(value: ast.List) -> list[str]: |
| 375 | + strings = [] |
| 376 | + for element in value.elts: |
| 377 | + if isinstance(element, ast.Constant) and isinstance(element.value, str): |
| 378 | + strings.append(element.value) |
| 379 | + |
| 380 | + else: |
| 381 | + raise SetupReaderError("Found non-string element in list") |
| 382 | + |
| 383 | + return strings |
0 commit comments