PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib_pypy/pyrepl/python_reader.py

https://bitbucket.org/bwesterb/pypy
Python | 392 lines | 342 code | 17 blank | 33 comment | 47 complexity | 2daf67c02df8603e899a096b698fc614 MD5 | raw file
  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 = completing_reader.uniqify(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. '<input>', 'single')
  164. except (OverflowError, SyntaxError, ValueError):
  165. self.showsyntaxerror("<input>")
  166. else:
  167. self.runcode(code)
  168. sys.stdout.flush()
  169. def interact(self):
  170. while 1:
  171. try: # catches EOFError's and KeyboardInterrupts during execution
  172. try: # catches KeyboardInterrupts during editing
  173. try: # warning saver
  174. # can't have warnings spewed onto terminal
  175. sv = warnings.showwarning
  176. warnings.showwarning = eat_it
  177. l = unicode(self.reader.readline(), 'utf-8')
  178. finally:
  179. warnings.showwarning = sv
  180. except KeyboardInterrupt:
  181. print "KeyboardInterrupt"
  182. else:
  183. if l:
  184. self.execute(l)
  185. except EOFError:
  186. break
  187. except KeyboardInterrupt:
  188. continue
  189. def prepare(self):
  190. self.sv_sw = warnings.showwarning
  191. warnings.showwarning = eat_it
  192. self.reader.prepare()
  193. self.reader.refresh() # we want :after methods...
  194. def restore(self):
  195. self.reader.restore()
  196. warnings.showwarning = self.sv_sw
  197. def handle1(self, block=1):
  198. try:
  199. r = 1
  200. r = self.reader.handle1(block)
  201. except KeyboardInterrupt:
  202. self.restore()
  203. print "KeyboardInterrupt"
  204. self.prepare()
  205. else:
  206. if self.reader.finished:
  207. text = self.reader.get_unicode()
  208. self.restore()
  209. if text:
  210. self.execute(text)
  211. self.prepare()
  212. return r
  213. def tkfilehandler(self, file, mask):
  214. try:
  215. self.handle1(block=0)
  216. except:
  217. self.exc_info = sys.exc_info()
  218. # how the <expletive> do you get this to work on Windows (without
  219. # createfilehandler)? threads, I guess
  220. def really_tkinteract(self):
  221. import _tkinter
  222. _tkinter.createfilehandler(
  223. self.reader.console.input_fd, _tkinter.READABLE,
  224. self.tkfilehandler)
  225. self.exc_info = None
  226. while 1:
  227. # dooneevent will return 0 without blocking if there are
  228. # no Tk windows, 1 after blocking until an event otherwise
  229. # so the following does what we want (this wasn't expected
  230. # to be obvious).
  231. if not _tkinter.dooneevent(_tkinter.ALL_EVENTS):
  232. self.handle1(block=1)
  233. if self.exc_info:
  234. type, value, tb = self.exc_info
  235. self.exc_info = None
  236. raise type, value, tb
  237. def tkinteract(self):
  238. """Run a Tk-aware Python interactive session.
  239. This function simulates the Python top-level in a way that
  240. allows Tk's mainloop to run."""
  241. # attempting to understand the control flow of this function
  242. # without help may cause internal injuries. so, some
  243. # explanation.
  244. # The outer while loop is there to restart the interaction if
  245. # the user types control-c when execution is deep in our
  246. # innards. I'm not sure this can't leave internals in an
  247. # inconsistent state, but it's a good start.
  248. # then the inside loop keeps calling self.handle1 until
  249. # _tkinter gets imported; then control shifts to
  250. # self.really_tkinteract, above.
  251. # this function can only return via an exception; we mask
  252. # EOFErrors (but they end the interaction) and
  253. # KeyboardInterrupts cause a restart. All other exceptions
  254. # are likely bugs in pyrepl (well, 'cept for SystemExit, of
  255. # course).
  256. while 1:
  257. try:
  258. try:
  259. self.prepare()
  260. try:
  261. while 1:
  262. if sys.modules.has_key("_tkinter"):
  263. self.really_tkinteract()
  264. # really_tkinteract is not expected to
  265. # return except via an exception, but:
  266. break
  267. self.handle1()
  268. except EOFError:
  269. pass
  270. finally:
  271. self.restore()
  272. except KeyboardInterrupt:
  273. continue
  274. else:
  275. break
  276. def twistedinteract(self):
  277. from twisted.internet import reactor
  278. from twisted.internet.abstract import FileDescriptor
  279. import signal
  280. outerself = self
  281. class Me(FileDescriptor):
  282. def fileno(self):
  283. """ We want to select on FD 0 """
  284. return 0
  285. def doRead(self):
  286. """called when input is ready"""
  287. try:
  288. outerself.handle1()
  289. except EOFError:
  290. reactor.stop()
  291. reactor.addReader(Me())
  292. reactor.callWhenRunning(signal.signal,
  293. signal.SIGINT,
  294. signal.default_int_handler)
  295. self.prepare()
  296. try:
  297. reactor.run()
  298. finally:
  299. self.restore()
  300. def cocoainteract(self, inputfilehandle=None, outputfilehandle=None):
  301. # only call this when there's a run loop already going!
  302. # note that unlike the other *interact methods, this returns immediately
  303. from cocoasupport import CocoaInteracter
  304. self.cocoainteracter = CocoaInteracter.alloc().init(self, inputfilehandle, outputfilehandle)
  305. def main(use_pygame_console=0, interactmethod=default_interactmethod, print_banner=True, clear_main=True):
  306. si, se, so = sys.stdin, sys.stderr, sys.stdout
  307. try:
  308. if 0 and use_pygame_console: # pygame currently borked
  309. from pyrepl.pygame_console import PyGameConsole, FakeStdin, FakeStdout
  310. con = PyGameConsole()
  311. sys.stderr = sys.stdout = FakeStdout(con)
  312. sys.stdin = FakeStdin(con)
  313. else:
  314. from pyrepl.unix_console import UnixConsole
  315. try:
  316. import locale
  317. except ImportError:
  318. encoding = None
  319. else:
  320. if hasattr(locale, 'nl_langinfo') \
  321. and hasattr(locale, 'CODESET'):
  322. encoding = locale.nl_langinfo(locale.CODESET)
  323. elif os.environ.get('TERM_PROGRAM') == 'Apple_Terminal':
  324. # /me whistles innocently...
  325. code = int(os.popen(
  326. "defaults read com.apple.Terminal StringEncoding"
  327. ).read())
  328. if code == 4:
  329. encoding = 'utf-8'
  330. # More could go here -- and what's here isn't
  331. # bulletproof. What would be? AppleScript?
  332. # Doesn't seem to be possible.
  333. else:
  334. encoding = None
  335. else:
  336. encoding = None # so you get ASCII...
  337. con = UnixConsole(0, 1, None, encoding)
  338. if print_banner:
  339. print "Python", sys.version, "on", sys.platform
  340. print 'Type "help", "copyright", "credits" or "license" '\
  341. 'for more information.'
  342. sys.path.insert(0, os.getcwd())
  343. if clear_main and __name__ != '__main__':
  344. mainmod = new.module('__main__')
  345. sys.modules['__main__'] = mainmod
  346. else:
  347. mainmod = sys.modules['__main__']
  348. rc = ReaderConsole(con, mainmod.__dict__)
  349. rc.reader._module_list_ready = False
  350. rc.run_user_init_file()
  351. getattr(rc, interactmethod)()
  352. finally:
  353. sys.stdin, sys.stderr, sys.stdout = si, se, so
  354. if __name__ == '__main__':
  355. main()