Coverage for src/_griffe/agents/nodes/exports.py: 92.98%

51 statements  

« prev     ^ index     » next       coverage.py v7.6.2, created at 2024-10-12 01:34 +0200

1# This module contains utilities for extracting exports from `__all__` assignments. 

2 

3from __future__ import annotations 

4 

5import ast 

6from contextlib import suppress 

7from dataclasses import dataclass 

8from typing import TYPE_CHECKING, Any, Callable 

9 

10from _griffe.agents.nodes.values import get_value 

11from _griffe.enumerations import LogLevel 

12from _griffe.expressions import ExprName 

13from _griffe.logger import logger 

14 

15if TYPE_CHECKING: 

16 from _griffe.models import Module 

17 

18 

19# YORE: Bump 2: Remove block. 

20@dataclass 

21class ExportedName: 

22 """Deprecated. An intermediate class to store names. 

23 

24 The [`get__all__`][griffe.get__all__] function now returns instances of [`ExprName`][griffe.ExprName] instead. 

25 """ 

26 

27 name: str 

28 """The exported name.""" 

29 parent: Module 

30 """The parent module.""" 

31 

32 

33def _extract_attribute(node: ast.Attribute, parent: Module) -> list[str | ExprName]: 

34 return [ExprName(name=node.attr, parent=_extract(node.value, parent)[0])] 

35 

36 

37def _extract_binop(node: ast.BinOp, parent: Module) -> list[str | ExprName]: 

38 left = _extract(node.left, parent) 

39 right = _extract(node.right, parent) 

40 return left + right 

41 

42 

43def _extract_constant(node: ast.Constant, parent: Module) -> list[str | ExprName]: 

44 return [node.value] 

45 

46 

47def _extract_name(node: ast.Name, parent: Module) -> list[str | ExprName]: 

48 return [ExprName(node.id, parent)] 

49 

50 

51def _extract_sequence(node: ast.List | ast.Set | ast.Tuple, parent: Module) -> list[str | ExprName]: 

52 sequence = [] 

53 for elt in node.elts: 

54 sequence.extend(_extract(elt, parent)) 

55 return sequence 

56 

57 

58def _extract_starred(node: ast.Starred, parent: Module) -> list[str | ExprName]: 

59 return _extract(node.value, parent) 

60 

61 

62_node_map: dict[type, Callable[[Any, Module], list[str | ExprName]]] = { 

63 ast.Attribute: _extract_attribute, 

64 ast.BinOp: _extract_binop, 

65 ast.Constant: _extract_constant, 

66 ast.List: _extract_sequence, 

67 ast.Name: _extract_name, 

68 ast.Set: _extract_sequence, 

69 ast.Starred: _extract_starred, 

70 ast.Tuple: _extract_sequence, 

71} 

72 

73 

74def _extract(node: ast.AST, parent: Module) -> list[str | ExprName]: 

75 return _node_map[type(node)](node, parent) 

76 

77 

78def get__all__(node: ast.Assign | ast.AnnAssign | ast.AugAssign, parent: Module) -> list[str | ExprName]: 

79 """Get the values declared in `__all__`. 

80 

81 Parameters: 

82 node: The assignment node. 

83 parent: The parent module. 

84 

85 Returns: 

86 A set of names. 

87 """ 

88 if node.value is None: 88 ↛ 89line 88 didn't jump to line 89 because the condition on line 88 was never true

89 return [] 

90 return _extract(node.value, parent) 

91 

92 

93def safe_get__all__( 

94 node: ast.Assign | ast.AnnAssign | ast.AugAssign, 

95 parent: Module, 

96 log_level: LogLevel = LogLevel.debug, # TODO: set to error when we handle more things 

97) -> list[str | ExprName]: 

98 """Safely (no exception) extract values in `__all__`. 

99 

100 Parameters: 

101 node: The `__all__` assignment node. 

102 parent: The parent used to resolve the names. 

103 log_level: Log level to use to log a message. 

104 

105 Returns: 

106 A list of strings or resovable names. 

107 """ 

108 try: 

109 return get__all__(node, parent) 

110 except Exception as error: # noqa: BLE001 

111 message = f"Failed to extract `__all__` value: {get_value(node.value)}" 

112 with suppress(Exception): 

113 message += f" at {parent.relative_filepath}:{node.lineno}" 

114 if isinstance(error, KeyError): 114 ↛ 117line 114 didn't jump to line 117 because the condition on line 114 was always true

115 message += f": unsupported node {error}" 

116 else: 

117 message += f": {error}" 

118 getattr(logger, log_level.value)(message) 

119 return []