Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/IPython/core/events.py: 51%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

47 statements  

1"""Infrastructure for registering and firing callbacks on application events. 

2 

3Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to 

4be called at specific times, or a collection of alternative methods to try, 

5callbacks are designed to be used by extension authors. A number of callbacks 

6can be registered for the same event without needing to be aware of one another. 

7 

8The functions defined in this module are no-ops indicating the names of available 

9events and the arguments which will be passed to them. 

10 

11.. note:: 

12 

13 This API is experimental in IPython 2.0, and may be revised in future versions. 

14""" 

15 

16from __future__ import annotations 

17 

18from typing import TYPE_CHECKING, Any, Callable, Iterable, TypeVar 

19 

20if TYPE_CHECKING: 

21 from IPython.core.interactiveshell import ( 

22 ExecutionInfo, 

23 ExecutionResult, 

24 InteractiveShell, 

25 ) 

26 

27 

28class EventManager: 

29 """Manage a collection of events and a sequence of callbacks for each. 

30  

31 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell` 

32 instances as an ``events`` attribute. 

33  

34 .. note:: 

35 

36 This API is experimental in IPython 2.0, and may be revised in future versions. 

37 """ 

38 

39 def __init__( 

40 self, 

41 shell: InteractiveShell, 

42 available_events: Iterable[str], 

43 print_on_error: bool = True, 

44 ) -> None: 

45 """Initialise the :class:`CallbackManager`. 

46 

47 Parameters 

48 ---------- 

49 shell 

50 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance 

51 available_events 

52 An iterable of names for callback events. 

53 print_on_error: 

54 A boolean flag to set whether the EventManager will print a warning which a event errors. 

55 """ 

56 self.shell = shell 

57 self.callbacks: dict[str, list[Callable[..., Any]]] = { 

58 n: [] for n in available_events 

59 } 

60 self.print_on_error = print_on_error 

61 

62 def register(self, event: str, function: Callable[..., Any]) -> None: 

63 """Register a new event callback. 

64 

65 Parameters 

66 ---------- 

67 event : str 

68 The event for which to register this callback. 

69 function : callable 

70 A function to be called on the given event. It should take the same 

71 parameters as the appropriate callback prototype. 

72 

73 Raises 

74 ------ 

75 TypeError 

76 If ``function`` is not callable. 

77 KeyError 

78 If ``event`` is not one of the known events. 

79 """ 

80 if not callable(function): 

81 raise TypeError('Need a callable, got %r' % function) 

82 if function not in self.callbacks[event]: 

83 self.callbacks[event].append(function) 

84 

85 def unregister(self, event: str, function: Callable[..., Any]) -> None: 

86 """Remove a callback from the given event.""" 

87 if function in self.callbacks[event]: 

88 return self.callbacks[event].remove(function) 

89 

90 raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event)) 

91 

92 def trigger(self, event: str, *args: Any, **kwargs: Any) -> None: 

93 """Call callbacks for ``event``. 

94 

95 Any additional arguments are passed to all callbacks registered for this 

96 event. Exceptions raised by callbacks are caught, and a message printed. 

97 """ 

98 for func in self.callbacks[event][:]: 

99 try: 

100 func(*args, **kwargs) 

101 except (Exception, KeyboardInterrupt): 

102 if self.print_on_error: 

103 print( 

104 "Error in callback {} (for {}), with arguments args {},kwargs {}:".format( 

105 func, event, args, kwargs 

106 ) 

107 ) 

108 self.shell.showtraceback() 

109 

110# event_name -> prototype mapping 

111available_events: dict[str, Callable[..., Any]] = {} 

112 

113_CallbackT = TypeVar("_CallbackT", bound=Callable[..., Any]) 

114 

115def _define_event(callback_function: _CallbackT) -> _CallbackT: 

116 """Decorator to register a function as an available event prototype.""" 

117 available_events[callback_function.__name__] = callback_function 

118 return callback_function 

119 

120# ------------------------------------------------------------------------------ 

121# Callback prototypes 

122# 

123# No-op functions which describe the names of available events and the 

124# signatures of callbacks for those events. 

125# ------------------------------------------------------------------------------ 

126 

127@_define_event 

128def pre_execute() -> None: 

129 """Fires before code is executed in response to user/frontend action. 

130 

131 This includes comm and widget messages and silent execution, as well as user 

132 code cells. 

133 """ 

134 pass 

135 

136@_define_event 

137def pre_run_cell(info: ExecutionInfo) -> None: 

138 """Fires before user-entered code runs. 

139 

140 Parameters 

141 ---------- 

142 info : :class:`~IPython.core.interactiveshell.ExecutionInfo` 

143 An object containing information used for the code execution. 

144 """ 

145 pass 

146 

147@_define_event 

148def post_execute() -> None: 

149 """Fires after code is executed in response to user/frontend action. 

150 

151 This includes comm and widget messages and silent execution, as well as user 

152 code cells. 

153 """ 

154 pass 

155 

156@_define_event 

157def post_run_cell(result: ExecutionResult) -> None: 

158 """Fires after user-entered code runs. 

159 

160 Parameters 

161 ---------- 

162 result : :class:`~IPython.core.interactiveshell.ExecutionResult` 

163 The object which will be returned as the execution result. 

164 """ 

165 pass 

166 

167@_define_event 

168def shell_initialized(ip: InteractiveShell) -> None: 

169 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`. 

170 

171 This is before extensions and startup scripts are loaded, so it can only be 

172 set by subclassing. 

173 

174 Parameters 

175 ---------- 

176 ip : :class:`~IPython.core.interactiveshell.InteractiveShell` 

177 The newly initialised shell. 

178 """ 

179 pass