Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/IPython/core/events.py: 42%

50 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:05 +0000

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 backcall import callback_prototype 

17 

18 

19class EventManager(object): 

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

21  

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

23 instances as an ``events`` attribute. 

24  

25 .. note:: 

26 

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

28 """ 

29 

30 def __init__(self, shell, available_events, print_on_error=True): 

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

32 

33 Parameters 

34 ---------- 

35 shell 

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

37 available_events 

38 An iterable of names for callback events. 

39 print_on_error: 

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

41 """ 

42 self.shell = shell 

43 self.callbacks = {n:[] for n in available_events} 

44 self.print_on_error = print_on_error 

45 

46 def register(self, event, function): 

47 """Register a new event callback. 

48 

49 Parameters 

50 ---------- 

51 event : str 

52 The event for which to register this callback. 

53 function : callable 

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

55 parameters as the appropriate callback prototype. 

56 

57 Raises 

58 ------ 

59 TypeError 

60 If ``function`` is not callable. 

61 KeyError 

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

63 """ 

64 if not callable(function): 

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

66 callback_proto = available_events.get(event) 

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

68 self.callbacks[event].append(callback_proto.adapt(function)) 

69 

70 def unregister(self, event, function): 

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

72 if function in self.callbacks[event]: 

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

74 

75 # Remove callback in case ``function`` was adapted by `backcall`. 

76 for callback in self.callbacks[event]: 

77 try: 

78 if callback.__wrapped__ is function: 

79 return self.callbacks[event].remove(callback) 

80 except AttributeError: 

81 pass 

82 

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

84 

85 def trigger(self, event, *args, **kwargs): 

86 """Call callbacks for ``event``. 

87 

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

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

90 """ 

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

92 try: 

93 func(*args, **kwargs) 

94 except (Exception, KeyboardInterrupt): 

95 if self.print_on_error: 

96 print("Error in callback {} (for {}):".format(func, event)) 

97 self.shell.showtraceback() 

98 

99# event_name -> prototype mapping 

100available_events = {} 

101 

102def _define_event(callback_function): 

103 callback_proto = callback_prototype(callback_function) 

104 available_events[callback_function.__name__] = callback_proto 

105 return callback_proto 

106 

107# ------------------------------------------------------------------------------ 

108# Callback prototypes 

109# 

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

111# signatures of callbacks for those events. 

112# ------------------------------------------------------------------------------ 

113 

114@_define_event 

115def pre_execute(): 

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

117 

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

119 code cells. 

120 """ 

121 pass 

122 

123@_define_event 

124def pre_run_cell(info): 

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

126 

127 Parameters 

128 ---------- 

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

130 An object containing information used for the code execution. 

131 """ 

132 pass 

133 

134@_define_event 

135def post_execute(): 

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

137 

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

139 code cells. 

140 """ 

141 pass 

142 

143@_define_event 

144def post_run_cell(result): 

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

146 

147 Parameters 

148 ---------- 

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

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

151 """ 

152 pass 

153 

154@_define_event 

155def shell_initialized(ip): 

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

157 

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

159 set by subclassing. 

160 

161 Parameters 

162 ---------- 

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

164 The newly initialised shell. 

165 """ 

166 pass