splitinput.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. """
  2. Simple utility for splitting user input. This is used by both inputsplitter and
  3. prefilter.
  4. """
  5. # -----------------------------------------------------------------------------
  6. # Imports
  7. # -----------------------------------------------------------------------------
  8. import re
  9. import sys
  10. import warnings
  11. from IPython.core.oinspect import OInfo
  12. # -----------------------------------------------------------------------------
  13. # Main function
  14. # -----------------------------------------------------------------------------
  15. # RegExp for splitting line contents into pre-char//first word-method//rest.
  16. # For clarity, each group in on one line.
  17. # WARNING: update the regexp if the escapes in interactiveshell are changed, as
  18. # they are hardwired in.
  19. # Although it's not solely driven by the regex, note that:
  20. # ,;/% only trigger if they are the first character on the line
  21. # ! and !! trigger if they are first char(s) *or* follow an indent
  22. # ? triggers as first or last char.
  23. line_split = re.compile(
  24. r"""
  25. ^(\s*) # any leading space
  26. ([,;/%]|!!?|\?\??)? # escape character or characters
  27. \s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading %
  28. # to correctly treat things like '?%magic'
  29. (.*?$|$) # rest of line
  30. """,
  31. re.VERBOSE,
  32. )
  33. def split_user_input(
  34. line: str, pattern: re.Pattern[str] | None = None
  35. ) -> tuple[str, str, str, str]:
  36. """Split user input into initial whitespace, escape character, function part
  37. and the rest.
  38. """
  39. assert isinstance(line, str)
  40. if pattern is None:
  41. pattern = line_split
  42. match = pattern.match(line)
  43. if not match:
  44. # print("match failed for line '%s'" % line)
  45. try:
  46. ifun, the_rest = line.split(None, 1)
  47. except ValueError:
  48. # print("split failed for line '%s'" % line)
  49. ifun, the_rest = line, ""
  50. pre = re.match(r"^(\s*)(.*)", line).groups()[0]
  51. esc = ""
  52. else:
  53. pre, esc, ifun, the_rest = match.groups()
  54. # print('line:<%s>' % line) # dbg
  55. # print('pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest)) # dbg
  56. return pre, esc or "", ifun.strip(), the_rest
  57. class LineInfo:
  58. """A single line of input and associated info.
  59. Includes the following as properties:
  60. line
  61. The original, raw line
  62. continue_prompt
  63. Is this line a continuation in a sequence of multiline input?
  64. pre
  65. Any leading whitespace.
  66. esc
  67. The escape character(s) in pre or the empty string if there isn't one.
  68. Note that '!!' and '??' are possible values for esc. Otherwise it will
  69. always be a single character.
  70. ifun
  71. The 'function part', which is basically the maximal initial sequence
  72. of valid python identifiers and the '.' character. This is what is
  73. checked for alias and magic transformations, used for auto-calling,
  74. etc. In contrast to Python identifiers, it may start with "%" and contain
  75. "*".
  76. the_rest
  77. Everything else on the line.
  78. raw_the_rest
  79. the_rest without whitespace stripped.
  80. """
  81. line: str
  82. continue_prompt: bool
  83. pre: str
  84. esc: str
  85. ifun: str
  86. raw_the_rest: str
  87. the_rest: str
  88. pre_char: str
  89. pre_whitespace: str
  90. def __init__(self, line: str, continue_prompt: bool = False) -> None:
  91. assert isinstance(line, str)
  92. self.line = line
  93. self.continue_prompt = continue_prompt
  94. self.pre, self.esc, self.ifun, self.raw_the_rest = split_user_input(line)
  95. self.the_rest = self.raw_the_rest.lstrip()
  96. self.pre_char = self.pre.strip()
  97. if self.pre_char:
  98. self.pre_whitespace = "" # No whitespace allowed before esc chars
  99. else:
  100. self.pre_whitespace = self.pre
  101. def ofind(self, ip) -> OInfo:
  102. """Do a full, attribute-walking lookup of the ifun in the various
  103. namespaces for the given IPython InteractiveShell instance.
  104. Return a dict with keys: {found, obj, ospace, ismagic}
  105. Note: can cause state changes because of calling getattr, but should
  106. only be run if autocall is on and if the line hasn't matched any
  107. other, less dangerous handlers.
  108. Does cache the results of the call, so can be called multiple times
  109. without worrying about *further* damaging state.
  110. .. deprecated:: 9.8
  111. Use ``shell._ofind(line_info.ifun)`` directly instead.
  112. """
  113. warnings.warn(
  114. "LineInfo.ofind() is deprecated since IPython 9.9. "
  115. "Use shell._ofind(line_info.ifun) directly instead.",
  116. DeprecationWarning,
  117. stacklevel=2,
  118. )
  119. return ip._ofind(self.ifun)
  120. def __str__(self) -> str:
  121. return "LineInfo [%s|%s|%s|%s]" % (self.pre, self.esc, self.ifun, self.the_rest)
  122. def __repr__(self) -> str:
  123. return "<" + str(self) + ">"