PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib_pypy/pyrepl/python_reader.py

https://bitbucket.org/pypy/pypy/
Python | 393 lines | 343 code | 17 blank | 33 comment | 47 complexity | fea4d94050b92867f009e4aa6b0f9a04 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. # Copyright 2000-2007 Michael Hudson-Doyle <micahel@gmail.com>
  2. # Bob Ippolito
  3. # Maciek Fijalkowski
  4. #
  5. # All Rights Reserved
  6. #
  7. #
  8. # Permission to use, copy, modify, and distribute this software and
  9. # its documentation for any purpose is hereby granted without fee,
  10. # provided that the above copyright notice appear in all copies and
  11. # that both that copyright notice and this permission notice appear in
  12. # supporting documentation.
  13. #
  14. # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
  15. # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  16. # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
  17. # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  18. # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  19. # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  20. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21. # one impressive collections of imports:
  22. from pyrepl.completing_reader import CompletingReader
  23. from pyrepl.historical_reader import HistoricalReader
  24. from pyrepl import completing_reader, reader
  25. from pyrepl import copy_code, commands, completer
  26. from pyrepl import module_lister
  27. import new, sys, os, re, code, traceback
  28. import atexit, warnings
  29. try:
  30. import cPickle as pickle
  31. except ImportError:
  32. import pickle
  33. try:
  34. import imp
  35. imp.find_module("twisted")
  36. from twisted.internet import reactor
  37. from twisted.internet.abstract import FileDescriptor
  38. except ImportError:
  39. default_interactmethod = "interact"
  40. else:
  41. default_interactmethod = "twistedinteract"
  42. CommandCompiler = code.CommandCompiler
  43. def eat_it(*args):
  44. """this function eats warnings, if you were wondering"""
  45. pass
  46. class maybe_accept(commands.Command):
  47. def do(self):
  48. r = self.reader
  49. text = r.get_unicode()
  50. try:
  51. # ooh, look at the hack:
  52. code = r.compiler("#coding:utf-8\n"+text.encode('utf-8'))
  53. except (OverflowError, SyntaxError, ValueError):
  54. self.finish = 1
  55. else:
  56. if code is None:
  57. r.insert("\n")
  58. else:
  59. self.finish = 1
  60. from_line_prog = re.compile(
  61. "^from\s+(?P<mod>[A-Za-z_.0-9]*)\s+import\s+(?P<name>[A-Za-z_.0-9]*)")
  62. import_line_prog = re.compile(
  63. "^(?:import|from)\s+(?P<mod>[A-Za-z_.0-9]*)\s*$")
  64. def mk_saver(reader):
  65. def saver(reader=reader):
  66. try:
  67. file = open(os.path.expanduser("~/.pythoni.hist"), "w")
  68. except IOError:
  69. pass
  70. else:
  71. pickle.dump(reader.history, file)
  72. file.close()
  73. return saver
  74. class PythonicReader(CompletingReader, HistoricalReader):
  75. def collect_keymap(self):
  76. return super(PythonicReader, self).collect_keymap() + (
  77. (r'\n', 'maybe-accept'),
  78. (r'\M-\n', 'insert-nl'))
  79. def __init__(self, console, locals,
  80. compiler=None):
  81. super(PythonicReader, self).__init__(console)
  82. self.completer = completer.Completer(locals)
  83. st = self.syntax_table
  84. for c in "._0123456789":
  85. st[c] = reader.SYNTAX_WORD
  86. self.locals = locals
  87. if compiler is None:
  88. self.compiler = CommandCompiler()
  89. else:
  90. self.compiler = compiler
  91. try:
  92. file = open(os.path.expanduser("~/.pythoni.hist"))
  93. except IOError:
  94. pass
  95. else:
  96. try:
  97. self.history = pickle.load(file)
  98. except:
  99. self.history = []
  100. self.historyi = len(self.history)
  101. file.close()
  102. atexit.register(mk_saver(self))
  103. for c in [maybe_accept]:
  104. self.commands[c.__name__] = c
  105. self.commands[c.__name__.replace('_', '-')] = c
  106. def get_completions(self, stem):
  107. b = self.get_unicode()
  108. m = import_line_prog.match(b)
  109. if m:
  110. if not self._module_list_ready:
  111. module_lister._make_module_list()
  112. self._module_list_ready = True
  113. mod = m.group("mod")
  114. try:
  115. return module_lister.find_modules(mod)
  116. except ImportError:
  117. pass
  118. m = from_line_prog.match(b)
  119. if m:
  120. mod, name = m.group("mod", "name")
  121. try:
  122. l = module_lister._packages[mod]
  123. except KeyError:
  124. try:
  125. mod = __import__(mod, self.locals, self.locals, [''])
  126. return [x for x in dir(mod) if x.startswith(name)]
  127. except ImportError:
  128. pass
  129. else:
  130. return [x[len(mod) + 1:]
  131. for x in l if x.startswith(mod + '.' + name)]
  132. try:
  133. l = sorted(set(self.completer.complete(stem)))
  134. return l
  135. except (NameError, AttributeError):
  136. return []
  137. class ReaderConsole(code.InteractiveInterpreter):
  138. II_init = code.InteractiveInterpreter.__init__
  139. def __init__(self, console, locals=None):
  140. if locals is None:
  141. locals = {}
  142. self.II_init(locals)
  143. self.compiler = CommandCompiler()
  144. self.compile = self.compiler.compiler
  145. self.reader = PythonicReader(console, locals, self.compiler)
  146. locals['Reader'] = self.reader
  147. def run_user_init_file(self):
  148. for key in "PYREPLSTARTUP", "PYTHONSTARTUP":
  149. initfile = os.environ.get(key)
  150. if initfile is not None and os.path.exists(initfile):
  151. break
  152. else:
  153. return
  154. try:
  155. execfile(initfile, self.locals, self.locals)
  156. except:
  157. etype, value, tb = sys.exc_info()
  158. traceback.print_exception(etype, value, tb.tb_next)
  159. def execute(self, text):
  160. try:
  161. # ooh, look at the hack:
  162. code = self.compile("# coding:utf8\n"+text.encode('utf-8'),
  163. '<stdin>', 'single')
  164. except (OverflowError, SyntaxError, ValueError):
  165. self.showsyntaxerror('<stdin>')
  166. else:
  167. self.runcode(code)
  168. if sys.stdout and not sys.stdout.closed:
  169. sys.stdout.flush()
  170. def interact(self):
  171. while 1:
  172. try: # catches EOFError's and KeyboardInterrupts during execution
  173. try: # catches KeyboardInterrupts during editing
  174. try: # warning saver
  175. # can't have warnings spewed onto terminal
  176. sv = warnings.showwarning
  177. warnings.showwarning = eat_it
  178. l = unicode(self.reader.readline(), 'utf-8')
  179. finally:
  180. warnings.showwarning = sv
  181. except KeyboardInterrupt:
  182. print "KeyboardInterrupt"
  183. else:
  184. if l:
  185. self.execute(l)
  186. except EOFError:
  187. break
  188. except KeyboardInterrupt:
  189. continue
  190. def prepare(self):
  191. self.sv_sw = warnings.showwarning
  192. warnings.showwarning = eat_it
  193. self.reader.prepare()
  194. self.reader.refresh() # we want :after methods...
  195. def restore(self):
  196. self.reader.restore()
  197. warnings.showwarning = self.sv_sw
  198. def handle1(self, block=1):
  199. try:
  200. r = 1
  201. r = self.reader.handle1(block)
  202. except KeyboardInterrupt:
  203. self.restore()
  204. print "KeyboardInterrupt"
  205. self.prepare()
  206. else:
  207. if self.reader.finished:
  208. text = self.reader.get_unicode()
  209. self.restore()
  210. if text:
  211. self.execute(text)
  212. self.prepare()
  213. return r
  214. def tkfilehandler(self, file, mask):
  215. try:
  216. self.handle1(block=0)
  217. except:
  218. self.exc_info = sys.exc_info()
  219. # how the <expletive> do you get this to work on Windows (without
  220. # createfilehandler)? threads, I guess
  221. def really_tkinteract(self):
  222. import _tkinter
  223. _tkinter.createfilehandler(
  224. self.reader.console.input_fd, _tkinter.READABLE,
  225. self.tkfilehandler)
  226. self.exc_info = None
  227. while 1:
  228. # dooneevent will return 0 without blocking if there are
  229. # no Tk windows, 1 after blocking until an event otherwise
  230. # so the following does what we want (this wasn't expected
  231. # to be obvious).
  232. if not _tkinter.dooneevent(_tkinter.ALL_EVENTS):
  233. self.handle1(block=1)
  234. if self.exc_info:
  235. type, value, tb = self.exc_info
  236. self.exc_info = None
  237. raise type, value, tb
  238. def tkinteract(self):
  239. """Run a Tk-aware Python interactive session.
  240. This function simulates the Python top-level in a way that
  241. allows Tk's mainloop to run."""
  242. # attempting to understand the control flow of this function
  243. # without help may cause internal injuries. so, some
  244. # explanation.
  245. # The outer while loop is there to restart the interaction if
  246. # the user types control-c when execution is deep in our
  247. # innards. I'm not sure this can't leave internals in an
  248. # inconsistent state, but it's a good start.
  249. # then the inside loop keeps calling self.handle1 until
  250. # _tkinter gets imported; then control shifts to
  251. # self.really_tkinteract, above.
  252. # this function can only return via an exception; we mask
  253. # EOFErrors (but they end the interaction) and
  254. # KeyboardInterrupts cause a restart. All other exceptions
  255. # are likely bugs in pyrepl (well, 'cept for SystemExit, of
  256. # course).
  257. while 1:
  258. try:
  259. try:
  260. self.prepare()
  261. try:
  262. while 1:
  263. if sys.modules.has_key("_tkinter"):
  264. self.really_tkinteract()
  265. # really_tkinteract is not expected to
  266. # return except via an exception, but:
  267. break
  268. self.handle1()
  269. except EOFError:
  270. pass
  271. finally:
  272. self.restore()
  273. except KeyboardInterrupt:
  274. continue
  275. else:
  276. break
  277. def twistedinteract(self):
  278. from twisted.internet import reactor
  279. from twisted.internet.abstract import FileDescriptor
  280. import signal
  281. outerself = self
  282. class Me(FileDescriptor):
  283. def fileno(self):
  284. """ We want to select on FD 0 """
  285. return 0
  286. def doRead(self):
  287. """called when input is ready"""
  288. try:
  289. outerself.handle1()
  290. except EOFError:
  291. reactor.stop()
  292. reactor.addReader(Me())
  293. reactor.callWhenRunning(signal.signal,
  294. signal.SIGINT,
  295. signal.default_int_handler)
  296. self.prepare()
  297. try:
  298. reactor.run()
  299. finally:
  300. self.restore()
  301. def cocoainteract(self, inputfilehandle=None, outputfilehandle=None):
  302. # only call this when there's a run loop already going!
  303. # note that unlike the other *interact methods, this returns immediately
  304. from cocoasupport import CocoaInteracter
  305. self.cocoainteracter = CocoaInteracter.alloc().init(self, inputfilehandle, outputfilehandle)
  306. def main(use_pygame_console=0, interactmethod=default_interactmethod, print_banner=True, clear_main=True):
  307. si, se, so = sys.stdin, sys.stderr, sys.stdout
  308. try:
  309. if 0 and use_pygame_console: # pygame currently borked
  310. from pyrepl.pygame_console import PyGameConsole, FakeStdin, FakeStdout
  311. con = PyGameConsole()
  312. sys.stderr = sys.stdout = FakeStdout(con)
  313. sys.stdin = FakeStdin(con)
  314. else:
  315. from pyrepl.unix_console import UnixConsole
  316. try:
  317. import locale
  318. except ImportError:
  319. encoding = None
  320. else:
  321. if hasattr(locale, 'nl_langinfo') \
  322. and hasattr(locale, 'CODESET'):
  323. encoding = locale.nl_langinfo(locale.CODESET)
  324. elif os.environ.get('TERM_PROGRAM') == 'Apple_Terminal':
  325. # /me whistles innocently...
  326. code = int(os.popen(
  327. "defaults read com.apple.Terminal StringEncoding"
  328. ).read())
  329. if code == 4:
  330. encoding = 'utf-8'
  331. # More could go here -- and what's here isn't
  332. # bulletproof. What would be? AppleScript?
  333. # Doesn't seem to be possible.
  334. else:
  335. encoding = None
  336. else:
  337. encoding = None # so you get ASCII...
  338. con = UnixConsole(os.dup(0), os.dup(1), None, encoding)
  339. if print_banner:
  340. print "Python", sys.version, "on", sys.platform
  341. print 'Type "help", "copyright", "credits" or "license" '\
  342. 'for more information.'
  343. sys.path.insert(0, os.getcwd())
  344. if clear_main and __name__ != '__main__':
  345. mainmod = new.module('__main__')
  346. sys.modules['__main__'] = mainmod
  347. else:
  348. mainmod = sys.modules['__main__']
  349. rc = ReaderConsole(con, mainmod.__dict__)
  350. rc.reader._module_list_ready = False
  351. rc.run_user_init_file()
  352. getattr(rc, interactmethod)()
  353. finally:
  354. sys.stdin, sys.stderr, sys.stdout = si, se, so
  355. if __name__ == '__main__':
  356. main()