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

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

48 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, TypeVar 

19from collections.abc import Callable, Iterable 

20 

21if TYPE_CHECKING: 

22 from IPython.core.interactiveshell import ( 

23 ExecutionInfo, 

24 ExecutionResult, 

25 InteractiveShell, 

26 ) 

27 

28 

29class EventManager: 

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

31 

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

33 instances as an ``events`` attribute. 

34 

35 .. note:: 

36 

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

38 """ 

39 

40 def __init__( 

41 self, 

42 shell: InteractiveShell, 

43 available_events: Iterable[str], 

44 print_on_error: bool = True, 

45 ) -> None: 

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

47 

48 Parameters 

49 ---------- 

50 shell 

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

52 available_events 

53 An iterable of names for callback events. 

54 print_on_error: 

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

56 """ 

57 self.shell = shell 

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

59 n: [] for n in available_events 

60 } 

61 self.print_on_error = print_on_error 

62 

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

64 """Register a new event callback. 

65 

66 Parameters 

67 ---------- 

68 event : str 

69 The event for which to register this callback. 

70 function : callable 

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

72 parameters as the appropriate callback prototype. 

73 

74 Raises 

75 ------ 

76 TypeError 

77 If ``function`` is not callable. 

78 KeyError 

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

80 """ 

81 if not callable(function): 

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

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

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

85 

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

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

88 if function in self.callbacks[event]: 

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

90 

91 raise ValueError(f'Function {function!r} is not registered as a {event} callback') 

92 

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

94 """Call callbacks for ``event``. 

95 

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

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

98 """ 

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

100 try: 

101 func(*args, **kwargs) 

102 except (Exception, KeyboardInterrupt): 

103 if self.print_on_error: 

104 print( 

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

106 func, event, args, kwargs 

107 ) 

108 ) 

109 self.shell.showtraceback() 

110 

111# event_name -> prototype mapping 

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

113 

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

115 

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

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

118 available_events[callback_function.__name__] = callback_function 

119 return callback_function 

120 

121# ------------------------------------------------------------------------------ 

122# Callback prototypes 

123# 

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

125# signatures of callbacks for those events. 

126# ------------------------------------------------------------------------------ 

127 

128@_define_event 

129def pre_execute() -> None: 

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

131 

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

133 code cells. 

134 """ 

135 pass 

136 

137@_define_event 

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

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

140 

141 Parameters 

142 ---------- 

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

144 An object containing information used for the code execution. 

145 """ 

146 pass 

147 

148@_define_event 

149def post_execute() -> None: 

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

151 

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

153 code cells. 

154 """ 

155 pass 

156 

157@_define_event 

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

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

160 

161 Parameters 

162 ---------- 

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

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

165 """ 

166 pass 

167 

168@_define_event 

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

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

171 

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

173 set by subclassing. 

174 

175 Parameters 

176 ---------- 

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

178 The newly initialised shell. 

179 """ 

180 pass