#!/usr/bin/python # Copyright (c) 2012-2013, Itzik Kotler # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the author nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import readline import code import codeop import argparse import logging import os import atexit import runpy try: import _preamble except ImportError: sys.exc_clear() import pythonect # Pythonect Console class PythonectCompile(codeop.Compile): def __init__(self): codeop.Compile.__init__(self) def __call__(self, source, filename, symbol): if source[-1] == '\\': return None return source.replace('\\\n', '') class PythonectCommandCompiler(codeop.CommandCompiler): def __init__(self): codeop.CommandCompiler.__init__(self) self.compiler = PythonectCompile() class PythonectInteractiveConsole(code.InteractiveConsole): def __init__(self, locals=None, histfile=os.path.expanduser("~/.pythonect_history")): code.InteractiveConsole.__init__(self, locals) self.compile = PythonectCommandCompiler() self.init_history(histfile) def init_history(self, histfile): try: readline.read_history_file(histfile) except IOError: pass atexit.register(self.save_history, histfile) def save_history(self, histfile): readline.write_history_file(histfile) # This is a cut & paste from /usr/lib/python2.7/code.py # Except we're not calling `exec` statement def runcode(self, code_): try: return_value = pythonect.eval(code_, {}, self.locals) # Meaningful Return Value? if return_value is not None: # String? if isinstance(return_value, basestring): # Enclose in single quotes return_value = "'" + return_value + "'" self.write(str(return_value) + '\n') # Keep return_value for further reference or reset to None? if return_value is False or return_value is True: # Reset locals to None self.locals['_'] = None except SystemExit: raise except: self.showtraceback() else: if code.softspace(sys.stdout, 0): print def main(): locals = {} verbose_levels = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] # Pythonect's Banner (for -V, --version purposes) banner = "Pythonect %s" % pythonect.__version__ # Parse command-line arguments parser = argparse.ArgumentParser(sys.argv) parser.add_argument('script', metavar='file', nargs='?', type=argparse.FileType('rt'), help='program read from script file') parser.add_argument('arg', metavar='arg', nargs='*', help='arguments passed to program in sys.argv[1:]') parser.add_argument('--verbose', '-v', action='count', default=0) parser.add_argument('--version', '-V', action='version', version=banner) parser.add_argument('--interactive', '-i', action='store_true', default=False, help='inspect interactively after running script') parser.add_argument('--command', '-c', metavar='cmd', nargs='*', help='program passed in as string') parser.add_argument('--module', '-m', metavar='mod', action='store', help='run library module as a script') args = parser.parse_args() # Setup logging level logging.basicConfig(level=verbose_levels[args.verbose % 4], format="%(filename)10s:%(lineno)4d:%(message)s") # Adjust sys.argv, make sys.argv[1] as sys.argv[0], sys.argv[2] as sys.argv[1] and etc. sys.argv = sys.argv[1:] if not sys.argv: sys.argv = [''] # Module as script mode (i.e. python -m 'os') if args.module: locals = runpy.run_module(args.module) # Command line mode (i.e. ./pythonect -c "'Hello world' -> print") if args.command: pythonect.eval(args.command[0], globals(), locals) # Script-mode (i.e. ./pythonect script or #!/usr/bin/env pythonect) if args.script: pythonect.eval(args.script.read().replace('\\\n', ''), globals_, locals_) args.script.close() if not args.module and not args.command and not args.script: args.interactive = True else: banner = '' # Interactive-mode (i.e. ./pythonect) if args.interactive: # Add current working directory to sys.path sys.path.insert(0, os.getcwd()) # Pythonect's Banner (for -V, --version purposes) banner = """Python %s\n[Pythonect %s] on %s\nType "help", "copyright", "credits" or "license" for more information.""" % (sys.version.split('\n')[0], pythonect.__version__, sys.platform) PythonectInteractiveConsole(locals).interact(banner) return 0 # Entry Point if __name__ == "__main__": try: sys.exit(main()) except ValueError as e: pass