input.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. """
  2. Abstraction of CLI Input.
  3. """
  4. from __future__ import unicode_literals
  5. from .utils import DummyContext, is_windows
  6. from abc import ABCMeta, abstractmethod
  7. from six import with_metaclass
  8. import io
  9. import os
  10. import sys
  11. if is_windows():
  12. from .terminal.win32_input import raw_mode, cooked_mode
  13. else:
  14. from .terminal.vt100_input import raw_mode, cooked_mode
  15. __all__ = (
  16. 'Input',
  17. 'StdinInput',
  18. 'PipeInput',
  19. )
  20. class Input(with_metaclass(ABCMeta, object)):
  21. """
  22. Abstraction for any input.
  23. An instance of this class can be given to the constructor of a
  24. :class:`~prompt_toolkit.interface.CommandLineInterface` and will also be
  25. passed to the :class:`~prompt_toolkit.eventloop.base.EventLoop`.
  26. """
  27. @abstractmethod
  28. def fileno(self):
  29. """
  30. Fileno for putting this in an event loop.
  31. """
  32. @abstractmethod
  33. def read(self):
  34. """
  35. Return text from the input.
  36. """
  37. @abstractmethod
  38. def raw_mode(self):
  39. """
  40. Context manager that turns the input into raw mode.
  41. """
  42. @abstractmethod
  43. def cooked_mode(self):
  44. """
  45. Context manager that turns the input into cooked mode.
  46. """
  47. class StdinInput(Input):
  48. """
  49. Simple wrapper around stdin.
  50. """
  51. def __init__(self, stdin=None):
  52. self.stdin = stdin or sys.stdin
  53. # The input object should be a TTY.
  54. assert self.stdin.isatty()
  55. # Test whether the given input object has a file descriptor.
  56. # (Idle reports stdin to be a TTY, but fileno() is not implemented.)
  57. try:
  58. # This should not raise, but can return 0.
  59. self.stdin.fileno()
  60. except io.UnsupportedOperation:
  61. if 'idlelib.run' in sys.modules:
  62. raise io.UnsupportedOperation(
  63. 'Stdin is not a terminal. Running from Idle is not supported.')
  64. else:
  65. raise io.UnsupportedOperation('Stdin is not a terminal.')
  66. def __repr__(self):
  67. return 'StdinInput(stdin=%r)' % (self.stdin,)
  68. def raw_mode(self):
  69. return raw_mode(self.stdin.fileno())
  70. def cooked_mode(self):
  71. return cooked_mode(self.stdin.fileno())
  72. def fileno(self):
  73. return self.stdin.fileno()
  74. def read(self):
  75. return self.stdin.read()
  76. class PipeInput(Input):
  77. """
  78. Input that is send through a pipe.
  79. This is useful if we want to send the input programatically into the
  80. interface, but still use the eventloop.
  81. Usage::
  82. input = PipeInput()
  83. input.send('inputdata')
  84. """
  85. def __init__(self):
  86. self._r, self._w = os.pipe()
  87. def fileno(self):
  88. return self._r
  89. def read(self):
  90. return os.read(self._r)
  91. def send_text(self, data):
  92. " Send text to the input. "
  93. os.write(self._w, data.encode('utf-8'))
  94. # Deprecated alias for `send_text`.
  95. send = send_text
  96. def raw_mode(self):
  97. return DummyContext()
  98. def cooked_mode(self):
  99. return DummyContext()
  100. def close(self):
  101. " Close pipe fds. "
  102. os.close(self._r)
  103. os.close(self._w)
  104. self._r = None
  105. self._w = None