1"""Implementation of magic functions that control various automatic behaviors.
2"""
3from __future__ import annotations
4#-----------------------------------------------------------------------------
5# Copyright (c) 2012 The IPython Development Team.
6#
7# Distributed under the terms of the Modified BSD License.
8#
9# The full license is in the file COPYING.txt, distributed with this software.
10#-----------------------------------------------------------------------------
11
12#-----------------------------------------------------------------------------
13# Imports
14#-----------------------------------------------------------------------------
15
16# Our own packages
17from IPython.core.magic import Bunch, Magics, magics_class, line_magic
18from IPython.testing.skipdoctest import skip_doctest
19from logging import error
20
21#-----------------------------------------------------------------------------
22# Magic implementation classes
23#-----------------------------------------------------------------------------
24
25@magics_class
26class AutoMagics(Magics):
27 """Magics that control various autoX behaviors."""
28
29 def __init__(self, shell):
30 super().__init__(shell)
31 # namespace for holding state we may need
32 self._magic_state = Bunch()
33
34 @line_magic
35 def automagic(self, parameter_s=''):
36 """Make magic functions callable without having to type the initial %.
37
38 Without arguments toggles on/off (when off, you must call it as
39 %automagic, of course). With arguments it sets the value, and you can
40 use any of (case insensitive):
41
42 - on, 1, True: to activate
43
44 - off, 0, False: to deactivate.
45
46 Note that magic functions have lowest priority, so if there's a
47 variable whose name collides with that of a magic fn, automagic won't
48 work for that function (you get the variable instead). However, if you
49 delete the variable (del var), the previously shadowed magic function
50 becomes visible to automagic again."""
51
52 arg = parameter_s.lower()
53 mman = self.shell.magics_manager
54 if arg in ('on', '1', 'true'):
55 val = True
56 elif arg in ('off', '0', 'false'):
57 val = False
58 else:
59 val = not mman.auto_magic
60 mman.auto_magic = val
61 print('\n' + self.shell.magics_manager.auto_status())
62
63 @skip_doctest
64 @line_magic
65 def autocall(self, parameter_s=''):
66 """Make functions callable without having to type parentheses.
67
68 Usage:
69
70 %autocall [mode]
71
72 The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
73 value is toggled on and off (remembering the previous state).
74
75 In more detail, these values mean:
76
77 0 -> fully disabled
78
79 1 -> active, but do not apply if there are no arguments on the line.
80
81 In this mode, you get::
82
83 In [1]: callable
84 Out[1]: <built-in function callable>
85
86 In [2]: callable 'hello'
87 ------> callable('hello')
88 Out[2]: False
89
90 2 -> Active always. Even if no arguments are present, the callable
91 object is called::
92
93 In [2]: float
94 ------> float()
95 Out[2]: 0.0
96
97 Note that even with autocall off, you can still use '/' at the start of
98 a line to treat the first argument on the command line as a function
99 and add parentheses to it::
100
101 In [8]: /str 43
102 ------> str(43)
103 Out[8]: '43'
104
105 # all-random (note for auto-testing)
106 """
107
108 valid_modes = {
109 0: "Off",
110 1: "Smart",
111 2: "Full",
112 }
113
114 def errorMessage() -> str:
115 error = "Valid modes: "
116 for k, v in valid_modes.items():
117 error += str(k) + "->" + v + ", "
118 error = error[:-2] # remove tailing `, ` after last element
119 return error
120
121 if parameter_s:
122 if parameter_s not in map(str, valid_modes.keys()):
123 error(errorMessage())
124 return
125 arg = int(parameter_s)
126 else:
127 arg = 'toggle'
128
129 if arg not in (*list(valid_modes.keys()), "toggle"):
130 error(errorMessage())
131 return
132
133 if arg in (valid_modes.keys()):
134 self.shell.autocall = arg
135 else: # toggle
136 if self.shell.autocall:
137 self._magic_state.autocall_save = self.shell.autocall
138 self.shell.autocall = 0
139 else:
140 try:
141 self.shell.autocall = self._magic_state.autocall_save
142 except AttributeError:
143 self.shell.autocall = self._magic_state.autocall_save = 1
144
145 print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])