Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/IPython/core/magic.py: 43%
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
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
1from __future__ import annotations
3"""Magic functions for InteractiveShell."""
5# -----------------------------------------------------------------------------
6# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7# Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8# Copyright (C) 2008 The IPython Development Team
10# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.
12# -----------------------------------------------------------------------------
14import os
15import re
16import sys
17from getopt import getopt, GetoptError
19from traitlets.config.configurable import Configurable
20from . import oinspect
21from .error import UsageError
22from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
23from ..utils.ipstruct import Struct
24from ..utils.process import arg_split
25from ..utils.text import dedent
26from traitlets import Bool, Dict, Instance, observe
27from logging import error
29import typing as t
30from typing import Any, Literal, TypeVar, overload
31from collections.abc import Callable
33if t.TYPE_CHECKING:
34 from types import FrameType
36 from IPython.core.interactiveshell import InteractiveShell
38_F = TypeVar("_F", bound=Callable[..., Any])
39_MagicKind = Literal["line", "cell"]
40_MagicSpec = Literal["line", "cell", "line_cell"]
43# -----------------------------------------------------------------------------
44# Globals
45# -----------------------------------------------------------------------------
47# A dict we'll use for each class that has magics, used as temporary storage to
48# pass information between the @line/cell_magic method decorators and the
49# @magics_class class decorator, because the method decorators have no
50# access to the class when they run. See for more details:
51# http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
53magics: dict[str, dict[str, str]] = dict(line={}, cell={})
55magic_kinds: tuple[_MagicKind, ...] = ("line", "cell")
56magic_spec: tuple[_MagicSpec, ...] = ("line", "cell", "line_cell")
57magic_escapes: dict[_MagicKind, str] = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
59# Regexes used by Magics.format_latex, compiled once at import time.
60# Characters that need to be escaped for latex:
61_LATEX_ESCAPE_RE = re.compile(r"(%|_|\$|#|&)", re.MULTILINE)
62# Magic command names as headers:
63_LATEX_CMD_NAME_RE = re.compile(r"^(%s.*?):" % ESC_MAGIC, re.MULTILINE)
64# Magic commands
65_LATEX_CMD_RE = re.compile(r"(?P<cmd>%s.+?\b)(?!\}\}:)" % ESC_MAGIC, re.MULTILINE)
66# Paragraph continue
67_LATEX_PAR_RE = re.compile(r"\\$", re.MULTILINE)
68# The "\n" symbol
69_LATEX_NEWLINE_RE = re.compile(r"\\n")
71# -----------------------------------------------------------------------------
72# Utility classes and functions
73# -----------------------------------------------------------------------------
76class Bunch:
77 pass
80def compress_dhist(dh: list[str]) -> list[str]:
81 """Compress a directory history into a new one with at most 20 entries.
83 Return a new list made from the first and last 10 elements of dhist after
84 removal of duplicates.
85 """
86 head, tail = dh[:-10], dh[-10:]
88 newhead: list[str] = []
89 done: set[str] = set()
90 for h in head:
91 if h in done:
92 continue
93 newhead.append(h)
94 done.add(h)
96 return newhead + tail
99def needs_local_scope(func: _F) -> _F:
100 """Decorator to mark magic functions which need to local scope to run."""
101 func.needs_local_scope = True # type: ignore[attr-defined]
102 return func
105# -----------------------------------------------------------------------------
106# Class and method decorators for registering magics
107# -----------------------------------------------------------------------------
110_T = TypeVar("_T", bound=type["Magics"])
113def magics_class(cls: _T) -> _T:
114 """Class decorator for all subclasses of the main Magics class.
116 Any class that subclasses Magics *must* also apply this decorator, to
117 ensure that all the methods that have been decorated as line/cell magics
118 get correctly registered in the class instance. This is necessary because
119 when method decorators run, the class does not exist yet, so they
120 temporarily store their information into a module global. Application of
121 this class decorator copies that global data to the class instance and
122 clears the global.
124 Obviously, this mechanism is not thread-safe, which means that the
125 *creation* of subclasses of Magic should only be done in a single-thread
126 context. Instantiation of the classes has no restrictions. Given that
127 these classes are typically created at IPython startup time and before user
128 application code becomes active, in practice this should not pose any
129 problems.
130 """
131 cls.registered = True
132 cls.magics = dict(line=magics["line"], cell=magics["cell"])
133 magics["line"] = {}
134 magics["cell"] = {}
135 return cls
138def record_magic(
139 dct: dict[str, dict[str, Any]],
140 magic_kind: _MagicSpec,
141 magic_name: str,
142 func: Any,
143) -> None:
144 """Utility function to store a function as a magic of a specific kind.
146 Parameters
147 ----------
148 dct : dict
149 A dictionary with 'line' and 'cell' subdicts.
150 magic_kind : str
151 Kind of magic to be stored.
152 magic_name : str
153 Key to store the magic as.
154 func : function
155 Callable object to store.
156 """
157 if magic_kind == "line_cell":
158 dct["line"][magic_name] = dct["cell"][magic_name] = func
159 else:
160 dct[magic_kind][magic_name] = func
163def validate_type(magic_kind: str) -> None:
164 """Ensure that the given magic_kind is valid.
166 Check that the given magic_kind is one of the accepted spec types (stored
167 in the global `magic_spec`), raise ValueError otherwise.
168 """
169 if magic_kind not in magic_spec:
170 raise ValueError(
171 "magic_kind must be one of %s, %s given" % magic_kinds, magic_kind
172 )
175# The docstrings for the decorator below will be fairly similar for the two
176# types (method and function), so we generate them here once and reuse the
177# templates below.
178_docstring_template = """Decorate the given {0} as {1} magic.
180The decorator can be used with or without arguments, as follows.
182i) without arguments: it will create a {1} magic named as the {0} being
183decorated::
185 @deco
186 def foo(...)
188will create a {1} magic named `foo`.
190ii) with one string argument: which will be used as the actual name of the
191resulting magic::
193 @deco('bar')
194 def foo(...)
196will create a {1} magic named `bar`.
198To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
199"""
201# These two are decorator factories. While they are conceptually very similar,
202# there are enough differences in the details that it's simpler to have them
203# written as completely standalone functions rather than trying to share code
204# and make a single one with convoluted logic.
207def _method_magic_marker(
208 magic_kind: _MagicSpec,
209) -> Callable[[_F | str], _F | Callable[[_F], _F]]:
210 """Decorator factory for methods in Magics subclasses."""
212 validate_type(magic_kind)
214 # This is a closure to capture the magic_kind. We could also use a class,
215 # but it's overkill for just that one bit of state.
216 def magic_deco(arg: _F | str) -> _F | Callable[[_F], _F]:
217 retval: _F | Callable[[_F], _F]
218 if callable(arg):
219 # "Naked" decorator call (just @foo, no args)
220 func = arg
221 name = func.__name__
222 retval = arg
223 record_magic(magics, magic_kind, name, name)
224 elif isinstance(arg, str):
225 # Decorator called with arguments (@foo('bar'))
226 name = arg
228 def mark(func: _F, *a: Any, **kw: Any) -> _F:
229 record_magic(magics, magic_kind, name, func.__name__)
230 return func
232 retval = mark
233 else:
234 raise TypeError("Decorator can only be called with string or function")
235 return retval
237 # Ensure the resulting decorator has a usable docstring
238 magic_deco.__doc__ = _docstring_template.format("method", magic_kind)
239 return magic_deco
242def _function_magic_marker(
243 magic_kind: _MagicSpec,
244) -> Callable[[_F | str], _F | Callable[[_F], _F]]:
245 """Decorator factory for standalone functions."""
246 validate_type(magic_kind)
248 # This is a closure to capture the magic_kind. We could also use a class,
249 # but it's overkill for just that one bit of state.
250 def magic_deco(arg: _F | str) -> _F | Callable[[_F], _F]:
251 # Find get_ipython() in the caller's namespace
252 caller: FrameType = sys._getframe(1)
253 get_ipython: Callable[[], InteractiveShell] | None = None
254 for ns in ["f_locals", "f_globals", "f_builtins"]:
255 get_ipython = getattr(caller, ns).get("get_ipython")
256 if get_ipython is not None:
257 break
258 else:
259 raise NameError(
260 "Decorator can only run in context where `get_ipython` exists"
261 )
263 ip: InteractiveShell = get_ipython()
265 retval: _F | Callable[[_F], _F]
266 if callable(arg):
267 # "Naked" decorator call (just @foo, no args)
268 func = arg
269 name = func.__name__
270 ip.register_magic_function(func, magic_kind, name) # type: ignore[arg-type]
271 retval = arg
272 elif isinstance(arg, str):
273 # Decorator called with arguments (@foo('bar'))
274 name = arg
276 def mark(func: _F, *a: Any, **kw: Any) -> _F:
277 ip.register_magic_function(func, magic_kind, name) # type: ignore[arg-type]
278 return func
280 retval = mark
281 else:
282 raise TypeError("Decorator can only be called with string or function")
283 return retval
285 # Ensure the resulting decorator has a usable docstring
286 ds = _docstring_template.format("function", magic_kind)
288 ds += dedent(
289 """
290 Note: this decorator can only be used in a context where IPython is already
291 active, so that the `get_ipython()` call succeeds. You can therefore use
292 it in your startup files loaded after IPython initializes, but *not* in the
293 IPython configuration file itself, which is executed before IPython is
294 fully up and running. Any file located in the `startup` subdirectory of
295 your configuration profile will be OK in this sense.
296 """
297 )
299 magic_deco.__doc__ = ds
300 return magic_deco
303MAGIC_NO_VAR_EXPAND_ATTR = "_ipython_magic_no_var_expand"
304MAGIC_OUTPUT_CAN_BE_SILENCED = "_ipython_magic_output_can_be_silenced"
307def no_var_expand(magic_func: _F) -> _F:
308 """Mark a magic function as not needing variable expansion
310 By default, IPython interprets `{a}` or `$a` in the line passed to magics
311 as variables that should be interpolated from the interactive namespace
312 before passing the line to the magic function.
313 This is not always desirable, e.g. when the magic executes Python code
314 (%timeit, %time, etc.).
315 Decorate magics with `@no_var_expand` to opt-out of variable expansion.
317 .. versionadded:: 7.3
318 """
319 setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
320 return magic_func
323def output_can_be_silenced(magic_func: _F) -> _F:
324 """Mark a magic function so its output may be silenced.
326 The output is silenced if the Python code used as a parameter of
327 the magic ends in a semicolon, not counting a Python comment that can
328 follow it.
329 """
330 setattr(magic_func, MAGIC_OUTPUT_CAN_BE_SILENCED, True)
331 return magic_func
334# Create the actual decorators for public use
336# These three are used to decorate methods in class definitions
337line_magic = _method_magic_marker("line")
338cell_magic = _method_magic_marker("cell")
339line_cell_magic = _method_magic_marker("line_cell")
341# These three decorate standalone functions and perform the decoration
342# immediately. They can only run where get_ipython() works
343register_line_magic = _function_magic_marker("line")
344register_cell_magic = _function_magic_marker("cell")
345register_line_cell_magic = _function_magic_marker("line_cell")
347# -----------------------------------------------------------------------------
348# Core Magic classes
349# -----------------------------------------------------------------------------
352class MagicsManager(Configurable):
353 """Object that handles all magic-related functionality for IPython."""
355 # Non-configurable class attributes
357 # A two-level dict, first keyed by magic type, then by magic function, and
358 # holding the actual callable object as value. This is the dict used for
359 # magic function dispatch
360 magics = Dict()
361 lazy_magics = Dict(
362 help="""
363 Mapping from magic names to modules to load.
365 This can be used in IPython/IPykernel configuration to declare lazy magics
366 that will only be imported/registered on first use.
368 For example::
370 c.MagicsManager.lazy_magics = {
371 "my_magic": "slow.to.import",
372 "my_other_magic": "also.slow",
373 }
375 On first invocation of `%my_magic`, `%%my_magic`, `%%my_other_magic` or
376 `%%my_other_magic`, the corresponding module will be loaded as an ipython
377 extensions as if you had previously done `%load_ext ipython`.
379 Magics names should be without percent(s) as magics can be both cell
380 and line magics.
382 Lazy loading happen relatively late in execution process, and
383 complex extensions that manipulate Python/IPython internal state or global state
384 might not support lazy loading.
385 """
386 ).tag(
387 config=True,
388 )
390 # A registry of the original objects that we've been given holding magics.
391 registry = Dict()
393 shell = Instance(
394 "IPython.core.interactiveshell.InteractiveShellABC", allow_none=True
395 )
397 auto_magic = Bool(
398 True, help="Automatically call line magics without requiring explicit % prefix"
399 ).tag(config=True)
401 @observe("auto_magic")
402 def _auto_magic_changed(self, change: dict[str, Any]) -> None:
403 assert self.shell is not None
404 self.shell.automagic = change["new"]
406 _auto_status = [
407 "Automagic is OFF, % prefix IS needed for line magics.",
408 "Automagic is ON, % prefix IS NOT needed for line magics.",
409 ]
411 user_magics = Instance("IPython.core.magics.UserMagics", allow_none=True)
413 def __init__(
414 self,
415 shell: InteractiveShell | None = None,
416 config: Any = None,
417 user_magics: Magics | None = None,
418 **traits: Any,
419 ) -> None:
420 super().__init__(
421 shell=shell, config=config, user_magics=user_magics, **traits
422 )
423 self.magics = dict(line={}, cell={})
424 # Let's add the user_magics to the registry for uniformity, so *all*
425 # registered magic containers can be found there.
426 if user_magics is not None:
427 self.registry[user_magics.__class__.__name__] = user_magics
429 def auto_status(self) -> str:
430 """Return descriptive string with automagic status."""
431 return self._auto_status[self.auto_magic]
433 def lsmagic(self) -> dict[str, dict[str, Any]]:
434 """Return a dict of currently available magic functions.
436 The return dict has the keys 'line' and 'cell', corresponding to the
437 two types of magics we support. Each value is a list of names.
438 """
439 return self.magics
441 def lsmagic_docs(
442 self, brief: bool = False, missing: str = ""
443 ) -> dict[str, dict[str, str]]:
444 """Return dict of documentation of magic functions.
446 The return dict has the keys 'line' and 'cell', corresponding to the
447 two types of magics we support. Each value is a dict keyed by magic
448 name whose value is the function docstring. If a docstring is
449 unavailable, the value of `missing` is used instead.
451 If brief is True, only the first line of each docstring will be returned.
452 """
453 docs: dict[str, dict[str, str]] = {}
454 for m_type in self.magics:
455 m_docs: dict[str, str] = {}
456 for m_name, m_func in self.magics[m_type].items():
457 if m_func.__doc__:
458 if brief:
459 m_docs[m_name] = m_func.__doc__.split("\n", 1)[0]
460 else:
461 m_docs[m_name] = m_func.__doc__.rstrip()
462 else:
463 m_docs[m_name] = missing
464 docs[m_type] = m_docs
465 return docs
467 def register_lazy(self, name: str, fully_qualified_name: str) -> None:
468 """
469 Lazily register a magic via an extension.
472 Parameters
473 ----------
474 name : str
475 Name of the magic you wish to register.
476 fully_qualified_name :
477 Fully qualified name of the module/submodule that should be loaded
478 as an extensions when the magic is first called.
479 It is assumed that loading this extensions will register the given
480 magic.
481 """
483 self.lazy_magics[name] = fully_qualified_name
485 def register(self, *magic_objects: type[Magics] | Magics) -> None:
486 """Register one or more instances of Magics.
488 Take one or more classes or instances of classes that subclass the main
489 `core.Magic` class, and register them with IPython to use the magic
490 functions they provide. The registration process will then ensure that
491 any methods that have decorated to provide line and/or cell magics will
492 be recognized with the `%x`/`%%x` syntax as a line/cell magic
493 respectively.
495 If classes are given, they will be instantiated with the default
496 constructor. If your classes need a custom constructor, you should
497 instanitate them first and pass the instance.
499 The provided arguments can be an arbitrary mix of classes and instances.
501 Parameters
502 ----------
503 *magic_objects : one or more classes or instances
504 """
505 # Start by validating them to ensure they have all had their magic
506 # methods registered at the instance level
507 for m in magic_objects:
508 if not m.registered:
509 raise ValueError(
510 "Class of magics %r was constructed without "
511 "the @register_magics class decorator"
512 )
513 if isinstance(m, type):
514 # If we're given an uninstantiated class
515 m = m(shell=self.shell)
517 # Now that we have an instance, we can register it and update the
518 # table of callables
519 self.registry[m.__class__.__name__] = m
520 for mtype in magic_kinds:
521 self.magics[mtype].update(m.magics[mtype])
523 def register_function(
524 self,
525 func: Callable[..., Any],
526 magic_kind: _MagicSpec = "line",
527 magic_name: str | None = None,
528 ) -> None:
529 """Expose a standalone function as magic function for IPython.
531 This will create an IPython magic (line, cell or both) from a
532 standalone function. The functions should have the following
533 signatures:
535 * For line magics: `def f(line)`
536 * For cell magics: `def f(line, cell)`
537 * For a function that does both: `def f(line, cell=None)`
539 In the latter case, the function will be called with `cell==None` when
540 invoked as `%f`, and with cell as a string when invoked as `%%f`.
542 Parameters
543 ----------
544 func : callable
545 Function to be registered as a magic.
546 magic_kind : str
547 Kind of magic, one of 'line', 'cell' or 'line_cell'
548 magic_name : optional str
549 If given, the name the magic will have in the IPython namespace. By
550 default, the name of the function itself is used.
551 """
553 # Create the new method in the user_magics and register it in the
554 # global table
555 validate_type(magic_kind)
556 magic_name = func.__name__ if magic_name is None else magic_name
557 assert self.user_magics is not None
558 setattr(self.user_magics, magic_name, func)
559 record_magic(self.magics, magic_kind, magic_name, func)
561 def register_alias(
562 self,
563 alias_name: str,
564 magic_name: str,
565 magic_kind: _MagicKind = "line",
566 magic_params: str | None = None,
567 ) -> None:
568 """Register an alias to a magic function.
570 The alias is an instance of :class:`MagicAlias`, which holds the
571 name and kind of the magic it should call. Binding is done at
572 call time, so if the underlying magic function is changed the alias
573 will call the new function.
575 Parameters
576 ----------
577 alias_name : str
578 The name of the magic to be registered.
579 magic_name : str
580 The name of an existing magic.
581 magic_kind : str
582 Kind of magic, one of 'line' or 'cell'
583 """
585 # `validate_type` is too permissive, as it allows 'line_cell'
586 # which we do not handle.
587 if magic_kind not in magic_kinds:
588 raise ValueError(
589 "magic_kind must be one of %s, %s given" % magic_kinds, magic_kind
590 )
592 assert self.shell is not None
593 assert self.user_magics is not None
594 alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
595 setattr(self.user_magics, alias_name, alias)
596 record_magic(self.magics, magic_kind, alias_name, alias)
599# Key base class that provides the central functionality for magics.
602class Magics(Configurable):
603 """Base class for implementing magic functions.
605 Shell functions which can be reached as %function_name. All magic
606 functions should accept a string, which they can parse for their own
607 needs. This can make some functions easier to type, eg `%cd ../`
608 vs. `%cd("../")`
610 Classes providing magic functions need to subclass this class, and they
611 MUST:
613 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
614 individual methods as magic functions, AND
616 - Use the class decorator `@magics_class` to ensure that the magic
617 methods are properly registered at the instance level upon instance
618 initialization.
620 See :mod:`magic_functions` for examples of actual implementation classes.
621 """
623 # Dict holding all command-line options for each magic.
624 options_table: dict[str, t.Any] = {}
625 # Dict for the mapping of magic names to methods, set by class decorator
626 magics: dict[str, t.Any] = {}
627 # Flag to check that the class decorator was properly applied
628 registered: bool = False
629 # Instance of IPython shell
630 shell: None | InteractiveShell = None
632 def __init__(
633 self, shell: InteractiveShell | None = None, **kwargs: Any
634 ) -> None:
635 if not (self.__class__.registered):
636 raise ValueError(
637 "Magics subclass without registration - "
638 "did you forget to apply @magics_class?"
639 )
640 if shell is not None:
641 if hasattr(shell, "configurables"):
642 shell.configurables.append(self) # type: ignore[arg-type]
643 if hasattr(shell, "config"):
644 kwargs.setdefault("parent", shell)
646 self.shell = shell
647 self.options_table = {}
648 # The method decorators are run when the instance doesn't exist yet, so
649 # they can only record the names of the methods they are supposed to
650 # grab. Only now, that the instance exists, can we create the proper
651 # mapping to bound methods. So we read the info off the original names
652 # table and replace each method name by the actual bound method.
653 # But we mustn't clobber the *class* mapping, in case of multiple instances.
654 class_magics = self.magics
655 self.magics = {}
656 for mtype in magic_kinds:
657 self.magics[mtype] = {}
658 tab: dict[str, Any] = self.magics[mtype]
659 cls_tab: dict[str, Any] = class_magics[mtype]
660 for magic_name, meth_name in cls_tab.items():
661 if isinstance(meth_name, str):
662 # it's a method name, grab it
663 tab[magic_name] = getattr(self, meth_name)
664 else:
665 # it's the real thing
666 tab[magic_name] = meth_name
667 # Configurable **needs** to be initiated at the end or the config
668 # magics get screwed up.
669 super().__init__(**kwargs)
671 def arg_err(self, func: Callable[..., Any]) -> None:
672 """Print docstring if incorrect arguments were passed"""
673 print("Error in arguments:")
674 print(oinspect.getdoc(func))
676 def format_latex(self, strng: str) -> str:
677 """Format a string for latex inclusion."""
679 # Now build the string for output:
680 # strng = _LATEX_CMD_NAME_RE.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
681 strng = _LATEX_CMD_NAME_RE.sub(r"\n\\bigskip\n\\texttt{\\textbf{ \1}}:", strng)
682 strng = _LATEX_CMD_RE.sub(r"\\texttt{\g<cmd>}", strng)
683 strng = _LATEX_PAR_RE.sub(r"\\\\", strng)
684 strng = _LATEX_ESCAPE_RE.sub(r"\\\1", strng)
685 strng = _LATEX_NEWLINE_RE.sub(r"\\textbackslash{}n", strng)
686 return strng
688 def parse_options(
689 self, arg_str: str, opt_str: str, *long_opts: str, **kw: Any
690 ) -> tuple[Any, Any]:
691 """Parse options passed to an argument string.
693 The interface is similar to that of :func:`getopt.getopt`, but it
694 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
695 and the stripped argument string still as a string.
697 arg_str is quoted as a true sys.argv vector by using shlex.split.
698 This allows us to easily expand variables, glob files, quote
699 arguments, etc.
701 Parameters
702 ----------
703 arg_str : str
704 The arguments to parse.
705 opt_str : str
706 The options specification.
707 mode : str, default 'string'
708 If given as 'list', the argument string is returned as a list (split
709 on whitespace) instead of a string.
710 list_all : bool, default False
711 Put all option values in lists. Normally only options
712 appearing more than once are put in a list.
713 posix : bool, default True
714 Whether to split the input line in POSIX mode or not, as per the
715 conventions outlined in the :mod:`shlex` module from the standard
716 library.
717 """
719 # inject default options at the beginning of the input line
720 caller = sys._getframe(1).f_code.co_name
721 arg_str = "{} {}".format(self.options_table.get(caller, ""), arg_str)
723 mode = kw.get("mode", "string")
724 if mode not in ["string", "list"]:
725 raise ValueError("incorrect mode given: %s" % mode)
726 # Get options
727 list_all = kw.get("list_all", 0)
728 posix = kw.get("posix", os.name == "posix")
729 strict = kw.get("strict", True)
731 preserve_non_opts = kw.get("preserve_non_opts", False)
732 remainder_arg_str = arg_str
734 # Check if we have more than one argument to warrant extra processing:
735 odict: dict[str, t.Any] = {} # Dictionary with options
736 args = arg_str.split()
737 if len(args) >= 1:
738 # If the list of inputs only has 0 or 1 thing in it, there's no
739 # need to look for options
740 argv = arg_split(arg_str, posix, strict)
741 # Do regular option processing
742 try:
743 opts, args = getopt(argv, opt_str, long_opts)
744 except GetoptError as e:
745 raise UsageError(
746 '%s (allowed: "%s"%s)'
747 % (e.msg, opt_str, " ".join(("",) + long_opts) if long_opts else "")
748 ) from e
749 for o, a in opts:
750 if mode == "string" and preserve_non_opts:
751 # remove option-parts from the original args-string and preserve remaining-part.
752 # This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
753 # returned in the original order.
754 remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
755 a, "", 1
756 )
757 if o.startswith("--"):
758 o = o[2:]
759 else:
760 o = o[1:]
761 try:
762 odict[o].append(a)
763 except AttributeError:
764 odict[o] = [odict[o], a]
765 except KeyError:
766 if list_all:
767 odict[o] = [a]
768 else:
769 odict[o] = a
771 # Prepare opts,args for return
772 opts = Struct(odict) # type: ignore[assignment, no-untyped-call]
773 if mode == "string":
774 if preserve_non_opts:
775 args = remainder_arg_str.lstrip() # type: ignore[assignment]
776 else:
777 args = " ".join(args) # type: ignore[assignment]
779 return opts, args
781class MagicAlias:
782 """An alias to another magic function.
784 An alias is determined by its magic name and magic kind. Lookup
785 is done at call time, so if the underlying magic changes the alias
786 will call the new function.
788 Use the :meth:`MagicsManager.register_alias` method or the
789 `%alias_magic` magic function to create and register a new alias.
790 """
792 def __init__(
793 self,
794 shell: InteractiveShell,
795 magic_name: str,
796 magic_kind: _MagicKind,
797 magic_params: str | None = None,
798 ) -> None:
799 self.shell = shell
800 self.magic_name = magic_name
801 self.magic_params = magic_params
802 self.magic_kind = magic_kind
804 self.pretty_target = "{}{}".format(magic_escapes[self.magic_kind], self.magic_name)
805 self.__doc__ = "Alias for `%s`." % self.pretty_target
807 self._in_call = False
809 def __call__(self, *args: Any, **kwargs: Any) -> Any:
810 """Call the magic alias."""
811 fn = self.shell.find_magic(self.magic_name, self.magic_kind) # type: ignore[no-untyped-call]
812 if fn is None:
813 raise UsageError("Magic `%s` not found." % self.pretty_target)
815 # Protect against infinite recursion.
816 if self._in_call:
817 raise UsageError(
818 "Infinite recursion detected; magic aliases cannot call themselves."
819 )
820 self._in_call = True
821 try:
822 if self.magic_params:
823 args_list = list(args)
824 args_list[0] = self.magic_params + " " + args[0]
825 args = tuple(args_list)
826 return fn(*args, **kwargs)
827 finally:
828 self._in_call = False