Decorator factory for standalone functions.
(
magic_kind: _MagicSpec,
)
| 227 | |
| 228 | |
| 229 | def _function_magic_marker( |
| 230 | magic_kind: _MagicSpec, |
| 231 | ) -> Callable[[_F | str], _F | Callable[[_F], _F]]: |
| 232 | """Decorator factory for standalone functions.""" |
| 233 | validate_type(magic_kind) |
| 234 | |
| 235 | # This is a closure to capture the magic_kind. We could also use a class, |
| 236 | # but it's overkill for just that one bit of state. |
| 237 | def magic_deco(arg: _F | str) -> _F | Callable[[_F], _F]: |
| 238 | # Find get_ipython() in the caller's namespace |
| 239 | caller: FrameType = sys._getframe(1) |
| 240 | get_ipython: Callable[[], InteractiveShell] | None = None |
| 241 | for ns in ["f_locals", "f_globals", "f_builtins"]: |
| 242 | get_ipython = getattr(caller, ns).get("get_ipython") |
| 243 | if get_ipython is not None: |
| 244 | break |
| 245 | else: |
| 246 | raise NameError( |
| 247 | "Decorator can only run in context where `get_ipython` exists" |
| 248 | ) |
| 249 | |
| 250 | ip: InteractiveShell = get_ipython() |
| 251 | |
| 252 | retval: _F | Callable[[_F], _F] |
| 253 | if callable(arg): |
| 254 | # "Naked" decorator call (just @foo, no args) |
| 255 | func = arg |
| 256 | name = func.__name__ |
| 257 | ip.register_magic_function(func, magic_kind, name) # type: ignore[arg-type] |
| 258 | retval = arg |
| 259 | elif isinstance(arg, str): |
| 260 | # Decorator called with arguments (@foo('bar')) |
| 261 | name = arg |
| 262 | |
| 263 | def mark(func: _F, *a: Any, **kw: Any) -> _F: |
| 264 | ip.register_magic_function(func, magic_kind, name) # type: ignore[arg-type] |
| 265 | return func |
| 266 | |
| 267 | retval = mark |
| 268 | else: |
| 269 | raise TypeError("Decorator can only be called with string or function") |
| 270 | return retval |
| 271 | |
| 272 | # Ensure the resulting decorator has a usable docstring |
| 273 | ds = _docstring_template.format("function", magic_kind) |
| 274 | |
| 275 | ds += dedent( |
| 276 | """ |
| 277 | Note: this decorator can only be used in a context where IPython is already |
| 278 | active, so that the `get_ipython()` call succeeds. You can therefore use |
| 279 | it in your startup files loaded after IPython initializes, but *not* in the |
| 280 | IPython configuration file itself, which is executed before IPython is |
| 281 | fully up and running. Any file located in the `startup` subdirectory of |
| 282 | your configuration profile will be OK in this sense. |
| 283 | """ |
| 284 | ) |
| 285 | |
| 286 | magic_deco.__doc__ = ds |
no test coverage detected
searching dependent graphs…