def paste(self, s): """Call out to helper program for pastebin upload.""" try: helper = subprocess.Popen('', executable=self.executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError as e: if e.errno == errno.ENOENT: raise PasteFailed(_('Helper program not found.')) else: raise PasteFailed(_('Helper program could not be run.')) if helper.returncode != 0: raise PasteFailed(_('Helper program returned non-zero exit ' 'status %d.' % (helper.returncode, ))) if not paste_url: raise PasteFailed(_('No output from helper program.')) else: parsed_url = urlparse(paste_url) if (not parsed_url.scheme or any(unicodedata.category(c) == 'Cc' for c in paste_url)): raise PasteFailed(_('Failed to recognize the helper ' 'program\'s output as an URL.')) return paste_url,
def do_pastebin_xmlrpc(self, s): """Upload to pastebin via XML-RPC.""" try: pasteservice = ServerProxy(self.config.pastebin_url) except IOError as e: self.interact.notify( _("Pastebin error for URL '%s': %s") % (self.config.pastebin_url, str(e))) return self.interact.notify(_('Posting data to pastebin...')) try: paste_id = pasteservice.pastes.newPaste( 'pycon', s, '', '', '', self.config.pastebin_private) except (SocketError, XMLRPCError) as e: self.interact.notify(_('Upload failed: %s') % (str(e), )) return self.prev_pastebin_content = s paste_url_template = Template(self.config.pastebin_show_url) paste_id = urlquote(paste_id) paste_url = paste_url_template.safe_substitute(paste_id=paste_id) self.prev_pastebin_url = paste_url self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) return paste_url
def do_pastebin(self, s): """Actually perform the upload.""" if s == self.prev_pastebin_content: self.interact.notify(_('Duplicate pastebin. Previous URL: %s. ' 'Removal URL: %s') % (self.prev_pastebin_url, self.prev_removal_url), 10) return self.prev_pastebin_url self.interact.notify(_('Posting data to pastebin...')) try: paste_url, removal_url = self.paster.paste(s) except PasteFailed as e: self.interact.notify(_('Upload failed: %s') % e) return self.prev_pastebin_content = s self.prev_pastebin_url = paste_url self.prev_removal_url = removal_url if removal_url is not None: self.interact.notify(_('Pastebin URL: %s - Removal URL: %s') % (paste_url, removal_url), 10) else: self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) return paste_url
def do_pastebin_json(self, s): """Upload to pastebin via json interface.""" url = urljoin(self.config.pastebin_url, '/json/new') payload = { 'code': s, 'lexer': 'pycon', 'expiry': self.config.pastebin_expiry } self.interact.notify(_('Posting data to pastebin...')) try: response = requests.post(url, data=payload, verify=True) response.raise_for_status() except requests.exceptions.RequestException as exc: self.interact.notify(_('Upload failed: %s') % (str(exc), )) return self.prev_pastebin_content = s data = response.json() paste_url_template = Template(self.config.pastebin_show_url) paste_id = urlquote(data['paste_id']) paste_url = paste_url_template.safe_substitute(paste_id=paste_id) removal_url_template = Template(self.config.pastebin_removal_url) removal_id = urlquote(data['removal_id']) removal_url = removal_url_template.safe_substitute(removal_id=removal_id) self.prev_pastebin_url = paste_url self.interact.notify(_('Pastebin URL: %s - Removal URL: %s') % (paste_url, removal_url)) return paste_url
def file_prompt(self, s): chooser = gtk.FileChooserDialog(title=_("File to save to"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) chooser.set_default_response(gtk.RESPONSE_OK) chooser.set_current_name('test.py') chooser.set_current_folder(os.path.expanduser('~')) pyfilter = gtk.FileFilter() pyfilter.set_name(_("Python files")) pyfilter.add_pattern("*.py") chooser.add_filter(pyfilter) allfilter = gtk.FileFilter() allfilter.set_name(_("All files")) allfilter.add_pattern("*") chooser.add_filter(allfilter) response = chooser.run() if response == gtk.RESPONSE_OK: fn = chooser.get_filename() else: fn = False chooser.destroy() return fn
def prompt_undo(self): """Returns how many lines to undo, 0 means don't undo""" if (self.config.single_undo_time < 0 or self.interp.timer.estimate() < self.config.single_undo_time): return 1 est = self.interp.timer.estimate() n = self.interact.file_prompt( _("Undo how many lines? (Undo will take up to ~%.1f seconds) [1]") % (est,)) try: if n == '': n = '1' n = int(n) except ValueError: self.interact.notify(_('Undo canceled'), .1) return 0 else: if n == 0: self.interact.notify(_('Undo canceled'), .1) return 0 else: message = ngettext('Undoing %d line... (est. %.1f seconds)', 'Undoing %d lines... (est. %.1f seconds)', n) self.interact.notify(message % (n, est), .1) return n
def do_pastebin_xmlrpc(self, s): """Upload to pastebin via XML-RPC.""" try: pasteservice = ServerProxy(self.config.pastebin_url) except IOError as e: self.interact.notify(_("Pastebin error for URL '%s': %s") % (self.config.pastebin_url, str(e))) return self.interact.notify(_('Posting data to pastebin...')) try: paste_id = pasteservice.pastes.newPaste('pycon', s, '', '', '', self.config.pastebin_private) except (SocketError, XMLRPCError) as e: self.interact.notify(_('Upload failed: %s') % (str(e), )) return self.prev_pastebin_content = s paste_url_template = Template(self.config.pastebin_show_url) paste_id = urlquote(paste_id) paste_url = paste_url_template.safe_substitute(paste_id=paste_id) self.prev_pastebin_url = paste_url self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) return paste_url
def file_prompt(self, s): chooser = gtk.FileChooserDialog( title=_("File to save to"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) chooser.set_default_response(gtk.RESPONSE_OK) chooser.set_current_name('test.py') chooser.set_current_folder(os.path.expanduser('~')) pyfilter = gtk.FileFilter() pyfilter.set_name(_("Python files")) pyfilter.add_pattern("*.py") chooser.add_filter(pyfilter) allfilter = gtk.FileFilter() allfilter.set_name(_("All files")) allfilter.add_pattern("*") chooser.add_filter(allfilter) response = chooser.run() if response == gtk.RESPONSE_OK: fn = chooser.get_filename() else: fn = False chooser.destroy() return fn
def edit_config(self): if not (os.path.isfile(self.config.config_path)): if self.interact.confirm(_("Config file does not exist - create " "new from default? (y/N)")): try: default_config = pkgutil.get_data('bpython', 'sample-config') if py3: # py3 files need unicode default_config = default_config.decode('ascii') bpython_dir, script_name = os.path.split(__file__) containing_dir = os.path.dirname( os.path.abspath(self.config.config_path)) if not os.path.exists(containing_dir): os.makedirs(containing_dir) with open(self.config.config_path, 'w') as f: f.write(default_config) except (IOError, OSError) as e: self.interact.notify(_("Error writing file '%s': %s") % (self.config.config.path, e)) return False else: return False try: if self.open_in_external_editor(self.config.config_path): self.interact.notify(_('bpython config file edited. Restart ' 'bpython for changes to take effect.')) except OSError as e: self.interact.notify(_('Error editing config file: %s') % e)
def paste(self, s): """Call out to helper program for pastebin upload.""" try: helper = subprocess.Popen('', executable=self.executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError as e: if e.errno == errno.ENOENT: raise PasteFailed(_('Helper program not found.')) else: raise PasteFailed(_('Helper program could not be run.')) if helper.returncode != 0: raise PasteFailed( _('Helper program returned non-zero exit ' 'status %d.' % (helper.returncode, ))) if not paste_url: raise PasteFailed(_('No output from helper program.')) else: parsed_url = urlparse(paste_url) if (not parsed_url.scheme or any(unicodedata.category(c) == 'Cc' for c in paste_url)): raise PasteFailed( _('Failed to recognize the helper ' 'program\'s output as an URL.')) return paste_url,
def main(args=None, locals_=None, banner=None): config, options, exec_args = bpargs.parse(args, ( 'scroll options', None, [ Option('--log', '-L', action='store_true', help=_("log debug messages to bpython-curtsies.log")), Option('--type', '-t', action='store_true', help=_("enter lines of file as though interactively typed")), ])) if options.log: import logging logging.basicConfig(filename='scroll.log', level=logging.DEBUG) interp = None paste = None if exec_args: assert options, "don't pass in exec_args without options" exit_value = 0 if options.type: paste = curtsies.events.PasteEvent() sourcecode = open(exec_args[0]).read() paste.events.extend(sourcecode) else: try: interp = code.InteractiveInterpreter(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit, e: exit_value = e.args if not options.interactive: raise SystemExit(exit_value)
def do_pastebin_json(self, s): """Upload to pastebin via json interface.""" url = urljoin(self.config.pastebin_url, '/json/new') payload = { 'code': s, 'lexer': 'pycon', 'expiry': self.config.pastebin_expiry } self.interact.notify(_('Posting data to pastebin...')) try: response = requests.post(url, data=payload, verify=True) response.raise_for_status() except requests.exceptions.RequestException as exc: self.interact.notify(_('Upload failed: %s') % (str(exc), )) return self.prev_pastebin_content = s data = response.json() paste_url_template = Template(self.config.pastebin_show_url) paste_id = urlquote(data['paste_id']) paste_url = paste_url_template.safe_substitute(paste_id=paste_id) removal_url_template = Template(self.config.pastebin_removal_url) removal_id = urlquote(data['removal_id']) removal_url = removal_url_template.safe_substitute( removal_id=removal_id) self.prev_pastebin_url = paste_url self.interact.notify( _('Pastebin URL: %s - Removal URL: %s') % (paste_url, removal_url)) return paste_url
def edit_config(self): if not (os.path.isfile(self.config.config_path)): if self.interact.confirm(_("Config file does not exist - create " "new from default? (y/N)")): try: default_config = pkgutil.get_data('bpython', 'sample-config') if py3: # py3 files need unicode default_config = default_config.decode('ascii') bpython_dir, script_name = os.path.split(__file__) containing_dir = os.path.dirname( os.path.abspath(self.config.config_path)) if not os.path.exists(containing_dir): os.makedirs(containing_dir) with open(self.config.config_path, 'w') as f: f.write(default_config) except (IOError, OSError) as e: self.interact.notify(_("Error writing file '%s': %s") % (self.config.config.path, e)) return False else: return False if self.open_in_external_editor(self.config.config_path): self.interact.notify(_('bpython config file edited. Restart ' 'bpython for changes to take effect.')) else: self.interact.notify(_('Error editing config file.'))
def confirm(self, q): """Ask for yes or no and return boolean""" try: reply = self.statusbar.prompt(q) except ValueError: return False return reply.lower() in (_('y'), _('yes'))
def main(args=None, locals_=None, banner=None): translations.init() config, options, exec_args = bpargs.parse( args, ('curtsies options', None, [ Option('--log', '-L', action='count', help=_("log debug messages to bpython.log")), Option('--paste', '-p', action='store_true', help=_("start by pasting lines of a file into session")), ])) if options.log is None: options.log = 0 logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG] level = logging_levels[min(len(logging_levels) - 1, options.log)] logging.getLogger('curtsies').setLevel(level) logging.getLogger('bpython').setLevel(level) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False interp = None paste = None if exec_args: if not options: raise ValueError("don't pass in exec_args without options") exit_value = 0 if options.paste: paste = curtsies.events.PasteEvent() encoding = inspection.get_encoding_file(exec_args[0]) with io.open(exec_args[0], encoding=encoding) as f: sourcecode = f.read() paste.events.extend(sourcecode) else: try: interp = code.InteractiveInterpreter(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit as e: exit_value = e.args if not options.interactive: raise SystemExit(exit_value) else: # expected for interactive sessions (vanilla python does it) sys.path.insert(0, '') print(bpargs.version_banner()) mainloop(config, locals_, banner, interp, paste, interactive=(not exec_args))
def pastebin(self, s=None): """Upload to a pastebin and display the URL in the status bar.""" if s is None: s = self.getstdout() if (self.config.pastebin_confirm and not self.interact.confirm(_("Pastebin buffer? (y/N) "))): self.interact.notify(_("Pastebin aborted")) return return self.do_pastebin(s)
def copy2clipboard(self): """Copy current content to clipboard.""" if self.clipboard is None: self.interact.notify(_('No clipboard available.')) return content = self.formatforfile(self.getstdout()) try: self.clipboard.copy(content) except CopyFailed: self.interact.notify(_('Could not copy to clipboard.')) else: self.interact.notify(_('Copied content to clipboard.'))
def append_reload_and_write(self, s, filename, encoding): if not self.hist_size: return self.append(s) try: with codecs.open(filename, 'a+', encoding, 'ignore') as hfile: with FileLock(hfile): # read entries hfile.seek(0, os.SEEK_SET) entries = self.load_from(hfile) self.append_to(entries, s) # write new entries hfile.seek(0, os.SEEK_SET) hfile.truncate() self.save_to(hfile, entries, self.hist_size) self.entries = entries except EnvironmentError as err: raise RuntimeError( _('Error occurred while writing to file %s (%s)') % (filename, err.strerror)) else: if len(self.entries) == 0: # Make sure that entries contains at least one element. If the # file and s are empty, this can occur. self.entries = ['']
def do_expose_event(self, event): """Draw a flat box around the popup window on expose event.""" width, height = self.get_size() self.style.paint_flat_box(self.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT, None, self, _('tooltip'), 0, 0, width, height) gtk.Window.do_expose_event(self, event)
def append_reload_and_write(self, s, filename, encoding): if not self.hist_size: return self.append(s) try: fd = os.open(filename, os.O_APPEND | os.O_RDWR | os.O_CREAT, stat.S_IRUSR | stat.S_IWUSR) with io.open(fd, 'a+', encoding=encoding, errors='ignore') as hfile: with FileLock(hfile): # read entries hfile.seek(0, os.SEEK_SET) entries = self.load_from(hfile) self.append_to(entries, s) # write new entries hfile.seek(0, os.SEEK_SET) hfile.truncate() self.save_to(hfile, entries, self.hist_size) self.entries = entries except EnvironmentError as err: raise RuntimeError( _('Error occurred while writing to file %s (%s)') % (filename, err.strerror)) else: if len(self.entries) == 0: # Make sure that entries contains at least one element. If the # file and s are empty, this can occur. self.entries = ['']
def edit_config(self): if not (os.path.isfile(self.config.config_path)): if self.interact.confirm( _("Config file does not exist - create new from default? (y/N)" )): try: bpython_dir, script_name = os.path.split(__file__) with open(os.path.join(bpython_dir, "sample-config")) as f: default_config = f.read() containing_dir = os.path.dirname( os.path.abspath(self.config.config_path)) if not os.path.exists(containing_dir): os.makedirs(containing_dir) with open(self.config.config_path, 'w') as f: f.write(default_config) except (IOError, OSError) as e: self.interact.notify('error creating file: %r' % e) return False else: return False if self.open_in_external_editor(self.config.config_path): self.interact.notify( 'bpython config file edited. Restart bpython for changes to take effect.' ) else: self.interact.notify('error editing config file')
def do_pastebin_xmlrpc(self, s): """Upload to pastebin via XML-RPC.""" try: pasteservice = ServerProxy(self.config.pastebin_url) except IOError, e: self.interact.notify(_("Pastebin error for URL '%s': %s") % (self.config.pastebin_url, str(e))) return
def __init__(self, exc_type, exc_value, tb, text=None): if text is None: text = _('An error occurred.') gtk.MessageDialog.__init__(self, buttons=gtk.BUTTONS_CLOSE, type=gtk.MESSAGE_ERROR, message_format=text) self.set_resizable(True) import cgitb text = cgitb.text((exc_type, exc_value, tb), 5) expander = gtk.Expander(_('Exception details')) self.vbox.pack_start(expander) textview = gtk.TextView() textview.get_buffer().set_text(text) scrolled_window = gtk.ScrolledWindow() scrolled_window.add(textview) expander.add(scrolled_window) self.show_all()
def do_show_source(dispatcher): from bpython.translations import _ from plugins.introspection import show_source obj = dispatcher.owner.current_object if obj is not None: show_source(obj) else: dispatcher.owner.interact.notify(_('Cannot show source.')) return ''
def do_pastebin(self, s): """Actually perform the upload.""" if s == self.prev_pastebin_content: self.interact.notify(_('Duplicate pastebin. Previous URL: %s') % (self.prev_pastebin_url, )) return self.prev_pastebin_url if self.config.pastebin_helper: return self.do_pastebin_helper(s) else: return self.do_pastebin_json(s)
def do_pastebin_helper(self, s): """Call out to helper program for pastebin upload.""" self.interact.notify(_('Posting data to pastebin...')) try: helper = subprocess.Popen('', executable=self.config.pastebin_helper, stdin=subprocess.PIPE, stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError, e: if e.errno == errno.ENOENT: self.interact.notify(_('Upload failed: ' 'Helper program not found.')) else: self.interact.notify(_('Upload failed: ' 'Helper program could not be run.')) return
def do_pastebin(self, s): """Actually perform the upload.""" if s == self.prev_pastebin_content: self.interact.notify(_('Duplicate pastebin. Previous URL: %s') % (self.prev_pastebin_url, )) return self.prev_pastebin_url if self.config.pastebin_helper: return self.do_pastebin_helper(s) else: return self.do_pastebin_xmlrpc(s)
def main(args=None, locals_=None, banner=None): config, options, exec_args = bpargs.parse(args, ( 'scroll options', None, [ Option('--log', '-L', action='store_true', help=_("log debug messages to bpython.log")), Option('--type', '-t', action='store_true', help=_("enter lines of file as though interactively typed")), ])) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').setLevel(logging.DEBUG) logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').setLevel(logging.DEBUG) logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False else: logging.getLogger('bpython').setLevel(logging.WARNING) interp = hy.cmdline.HyREPL() paste = None if exec_args: assert options, "don't pass in exec_args without options" exit_value = 0 if options.type: paste = curtsies.events.PasteEvent() sourcecode = open(exec_args[0]).read() paste.events.extend(sourcecode) else: try: interp = code.InteractiveInterpreter(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit as e: exit_value = e.args if not options.interactive: raise SystemExit(exit_value) else: sys.path.insert(0, '') # expected for interactive sessions (vanilla python does it) mainloop(config, locals_, banner, interp, paste, interactive=(not exec_args))
def main(args=None, locals_=None, banner=None): config, options, exec_args = bpargs.parse(args, ('scroll options', None, [ Option('--log', '-L', action='store_true', help=_("log debug messages to bpython.log")), Option('--type', '-t', action='store_true', help=_("enter lines of file as though interactively typed")), ])) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').setLevel(logging.DEBUG) logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').setLevel(logging.DEBUG) logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False else: logging.getLogger('bpython').setLevel(logging.WARNING) interp = None paste = None if exec_args: if not options: raise ValueError("don't pass in exec_args without options") exit_value = 0 if options.type: paste = curtsies.events.PasteEvent() sourcecode = open(exec_args[0]).read() paste.events.extend(sourcecode) else: try: interp = code.InteractiveInterpreter(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit, e: exit_value = e.args if not options.interactive: raise SystemExit(exit_value)
def main(args=None, locals_=None, banner=None): config, options, exec_args = bpargs.parse(args, ( 'curtsies options', None, [ Option('--log', '-L', action='store_true', help=_("log debug messages to bpython.log")), Option('--type', '-t', action='store_true', help=_("enter lines of file as though interactively typed")), ])) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').setLevel(logging.WARNING) logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').setLevel(logging.WARNING) logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False else: logging.getLogger('bpython').setLevel(logging.ERROR) logging.getLogger('curtsies').setLevel(logging.ERROR) interp = None paste = None if exec_args: if not options: raise ValueError("don't pass in exec_args without options") exit_value = 0 if options.type: paste = curtsies.events.PasteEvent() sourcecode = open(exec_args[0]).read() paste.events.extend(sourcecode) else: try: interp = code.InteractiveInterpreter(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit, e: exit_value = e.args if not options.interactive: raise SystemExit(exit_value)
def write2file(self): """Prompt for a filename and write the current contents of the stdout buffer to disk.""" try: fn = self.interact.file_prompt(_('Save to file (Esc to cancel): ')) if not fn: self.interact.notify(_('Save cancelled.')) return except ValueError: self.interact.notify(_('Save cancelled.')) return if fn.startswith('~'): fn = os.path.expanduser(fn) if not fn.endswith('.py') and self.config.save_append_py: fn = fn + '.py' mode = 'w' if os.path.exists(fn): mode = self.interact.file_prompt( _('%s already exists. Do you ' 'want to (c)ancel, ' ' (o)verwrite or ' '(a)ppend? ') % (fn, )) if mode in ('o', 'overwrite', _('overwrite')): mode = 'w' elif mode in ('a', 'append', _('append')): mode = 'a' else: self.interact.notify(_('Save cancelled.')) return s = self.formatforfile(self.getstdout()) try: with open(fn, mode) as f: f.write(s) except IOError as e: self.interact.notify( _("Error writing file '%s': %s") % (fn, str(e))) else: self.interact.notify(_('Saved to %s.') % (fn, ))
def get_source_of_current_name(self): """Return the source code of the object which is bound to the current name in the current input line. Throw `SourceNotFound` if the source cannot be found. Returns bytestring in py2, unicode in py3.""" obj = self.current_func try: if obj is None: line = self.current_line if not line.strip(): raise SourceNotFound(_("Nothing to get source of")) if inspection.is_eval_safe_name(line): obj = self.get_object(line) return inspect.getsource(obj) except (AttributeError, NameError) as e: msg = _("Cannot get source: %s") % (str(e), ) except IOError as e: msg = str(e) except TypeError as e: if "built-in" in str(e): msg = _("Cannot access source of %r") % (obj, ) else: msg = _("No source code found for %s") % (self.current_line, ) raise SourceNotFound(msg)
def write2file(self): """Prompt for a filename and write the current contents of the stdout buffer to disk.""" try: fn = self.interact.file_prompt(_('Save to file (Esc to cancel): ')) if not fn: self.interact.notify(_('Save cancelled.')) return except ValueError: self.interact.notify(_('Save cancelled.')) return if fn.startswith('~'): fn = os.path.expanduser(fn) if not fn.endswith('.py') and self.config.save_append_py: fn = fn + '.py' mode = 'w' if os.path.exists(fn): mode = self.interact.file_prompt(_('%s already exists. Do you ' 'want to (c)ancel, ' ' (o)verwrite or ' '(a)ppend? ') % (fn, )) if mode in ('o', 'overwrite', _('overwrite')): mode = 'w' elif mode in ('a', 'append', _('append')): mode = 'a' else: self.interact.notify(_('Save cancelled.')) return s = self.formatforfile(self.getstdout()) try: with open(fn, mode) as f: f.write(s) except IOError as e: self.interact.notify(_("Error writing file '%s': %s") % (fn, str(e))) else: self.interact.notify(_('Saved to %s.') % (fn, ))
def __init__(self, event_loop, palette, interpreter, config): repl.Repl.__init__(self, interpreter, config) self._redraw_handle = None self._redraw_pending = False self._redraw_time = 0 self.listbox = BPythonListBox(urwid.SimpleListWalker([])) self.tooltip = urwid.ListBox(urwid.SimpleListWalker([])) self.tooltip.grid = None self.overlay = Tooltip(self.listbox, self.tooltip) self.stdout_hist = '' self.frame = urwid.Frame(self.overlay) if urwid.get_encoding_mode() == 'narrow': input_filter = decoding_input_filter else: input_filter = None # This constructs a raw_display.Screen, which nabs sys.stdin/out. self.main_loop = urwid.MainLoop(self.frame, palette, event_loop=event_loop, unhandled_input=self.handle_input, input_filter=input_filter, handle_mouse=False) # String is straight from bpython.cli self.statusbar = Statusbar( config, _(" <%s> Rewind <%s> Save <%s> Pastebin " " <%s> Pager <%s> Show Source ") % (config.undo_key, config.save_key, config.pastebin_key, config.last_output_key, config.show_source_key), self.main_loop) self.frame.set_footer(self.statusbar.widget) self.interact = URWIDInteraction(self.config, self.statusbar, self.frame) self.edits = [] self.edit = None self.current_output = None self._completion_update_suppressed = False # Bulletproof: this is a value extract_exit_value accepts. self.exit_value = () load_urwid_command_map(config)
def get_source_of_current_name(self): """Return the unicode source code of the object which is bound to the current name in the current input line. Throw `SourceNotFound` if the source cannot be found.""" obj = self.current_func try: if obj is None: line = self.current_line if not line.strip(): raise SourceNotFound(_("Nothing to get source of")) if inspection.is_eval_safe_name(line): obj = self.get_object(line) return inspection.get_source_unicode(obj) except (AttributeError, NameError) as e: msg = _(u"Cannot get source: %s") % (e, ) except IOError as e: msg = u"%s" % (e, ) except TypeError as e: if "built-in" in u"%s" % (e, ): msg = _("Cannot access source of %r") % (obj, ) else: msg = _("No source code found for %s") % (self.current_line, ) raise SourceNotFound(msg)
def __init__(self, event_loop, palette, interpreter, config): repl.Repl.__init__(self, interpreter, config) self._redraw_handle = None self._redraw_pending = False self._redraw_time = 0 self.listbox = BPythonListBox(urwid.SimpleListWalker([])) self.tooltip = urwid.ListBox(urwid.SimpleListWalker([])) self.tooltip.grid = None self.overlay = Tooltip(self.listbox, self.tooltip) self.stdout_hist = "" self.frame = urwid.Frame(self.overlay) if urwid.get_encoding_mode() == "narrow": input_filter = decoding_input_filter else: input_filter = None # This constructs a raw_display.Screen, which nabs sys.stdin/out. self.main_loop = urwid.MainLoop( self.frame, palette, event_loop=event_loop, unhandled_input=self.handle_input, input_filter=input_filter, handle_mouse=False, ) # String is straight from bpython.cli self.statusbar = Statusbar( config, _(" <%s> Rewind <%s> Save <%s> Pastebin " " <%s> Pager <%s> Show Source ") % (config.undo_key, config.save_key, config.pastebin_key, config.last_output_key, config.show_source_key), self.main_loop, ) self.frame.set_footer(self.statusbar.widget) self.interact = URWIDInteraction(self.config, self.statusbar, self.frame) self.edits = [] self.edit = None self.current_output = None self._completion_update_suppressed = False load_urwid_command_map(config)
def do_pastebin_helper(self, s): """Call out to helper program for pastebin upload.""" self.interact.notify(_('Posting data to pastebin...')) try: helper = subprocess.Popen('', executable=self.config.pastebin_helper, stdin=subprocess.PIPE, stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError as e: if e.errno == errno.ENOENT: self.interact.notify( _('Upload failed: ' 'Helper program not found.')) else: self.interact.notify( _('Upload failed: ' 'Helper program could not be run.')) return if helper.returncode != 0: self.interact.notify( _('Upload failed: ' 'Helper program returned non-zero exit ' 'status %s.' % (helper.returncode, ))) return if not paste_url: self.interact.notify( _('Upload failed: ' 'No output from helper program.')) return else: parsed_url = urlparse(paste_url) if (not parsed_url.scheme or any(unicodedata.category(c) == 'Cc' for c in paste_url)): self.interact.notify( _("Upload failed: " "Failed to recognize the helper " "program's output as an URL.")) return self.prev_pastebin_content = s self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) return paste_url
def __init__(self): logging.debug("starting init") interp = code.InteractiveInterpreter() config = Struct() loadini(config, default_config_path()) config.autocomplete_mode = SIMPLE # only one implemented currently #TODO determine if this is supposed to use this, or if it should be # frontend specific. if config.cli_suggestion_width <= 0 or config.cli_suggestion_width > 1: config.cli_suggestion_width = 1 self.status_bar = StatusBar(_('welcome to bpython')) self.rl_char_sequences = get_updated_char_sequences(key_dispatch, config) logging.debug("starting parent init") super(Repl, self).__init__(interp, config) self.formatter = BPythonFormatter(config.color_scheme) self.interact = self.status_bar # overwriting what bpython.Repl put there # interact is called to interact with the status bar, # so we're just using the same object self._current_line = '' # line currently being edited, without '>>> ' self.current_formatted_line = fmtstr('') # needs to be updated before each draw # by calling set_formatted_line self.display_lines = [] # lines separated whenever logical line # length goes over what the terminal width # was at the time of original output self.history = [] # this is every line that's been executed; # it gets smaller on rewind self.display_buffer = [] # formatted version of lines in the buffer # kept around so we can unhighlight parens # using self.reprint_line as called by # bpython.Repl self.scroll_offset = 0 self.cursor_offset_in_line = 0 # from the left, 0 means first char self.done = True self.paste_mode = False self.width = None self.height = None self.start_background_tasks()
def do_pastebin_helper(self, s): """Call out to helper program for pastebin upload.""" self.interact.notify(_('Posting data to pastebin...')) try: helper = subprocess.Popen('', executable=self.config.pastebin_helper, stdin=subprocess.PIPE, stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError as e: if e.errno == errno.ENOENT: self.interact.notify(_('Upload failed: ' 'Helper program not found.')) else: self.interact.notify(_('Upload failed: ' 'Helper program could not be run.')) return if helper.returncode != 0: self.interact.notify(_('Upload failed: ' 'Helper program returned non-zero exit ' 'status %d.' % (helper.returncode, ))) return if not paste_url: self.interact.notify(_('Upload failed: ' 'No output from helper program.')) return else: parsed_url = urlparse(paste_url) if (not parsed_url.scheme or any(unicodedata.category(c) == 'Cc' for c in paste_url)): self.interact.notify(_("Upload failed: " "Failed to recognize the helper " "program's output as an URL.")) return self.prev_pastebin_content = s self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) return paste_url
def edit_config(self): if not (os.path.isfile(self.config.config_path)): if self.interact.confirm(_("Config file does not exist - create new from default? (y/N)")): try: bpython_dir, script_name = os.path.split(__file__) with open(os.path.join(bpython_dir, "sample-config")) as f: default_config = f.read() containing_dir = os.path.dirname(os.path.abspath(self.config.config_path)) if not os.path.exists(containing_dir): os.makedirs(containing_dir) with open(self.config.config_path, 'w') as f: f.write(default_config) except (IOError, OSError) as e: self.interact.notify('error creating file: %r' % e) return False else: return False if self.open_in_external_editor(self.config.config_path): self.interact.notify('bpython config file edited. Restart bpython for changes to take effect.') else: self.interact.notify('error editing config file')
def main(args=None, locals_=None, banner=None, welcome_message=None): """ banner is displayed directly after the version information. welcome_message is passed on to Repl and displayed in the statusbar. """ translations.init() config, options, exec_args = bpargs.parse( args, ('curtsies options', None, [ Option('--log', '-L', action='count', help=_("log debug messages to bpython.log")), Option('--paste', '-p', action='store_true', help=_("start by pasting lines of a file into session")), ])) if options.log is None: options.log = 0 logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG] level = logging_levels[min(len(logging_levels) - 1, options.log)] logging.getLogger('curtsies').setLevel(level) logging.getLogger('bpython').setLevel(level) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False interp = None paste = None if exec_args: if not options: raise ValueError("don't pass in exec_args without options") exit_value = () if options.paste: paste = curtsies.events.PasteEvent() encoding = inspection.get_encoding_file(exec_args[0]) with io.open(exec_args[0], encoding=encoding) as f: sourcecode = f.read() paste.events.extend(sourcecode) else: try: interp = Interp(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit as e: exit_value = e.args if not options.interactive: return extract_exit_value(exit_value) else: # expected for interactive sessions (vanilla python does it) sys.path.insert(0, '') if not options.quiet: print(bpargs.version_banner()) if banner is not None: print(banner) global repl repl = FullCurtsiesRepl(config, locals_, welcome_message, interp, paste) try: with repl.input_generator: with repl.window as win: with repl: repl.height, repl.width = win.t.height, win.t.width exit_value = repl.mainloop() except (SystemExitFromCodeGreenlet, SystemExit) as e: exit_value = e.args return extract_exit_value(exit_value)
def main(args=None, locals_=None, banner=None): translations.init() # TODO: maybe support displays other than raw_display? config, options, exec_args = bpargs.parse(args, ('Urwid options', None, [ Option('--twisted', '-T', action='store_true', help=_('Run twisted reactor.')), Option('--reactor', '-r', help=_('Select specific reactor (see --help-reactors). ' 'Implies --twisted.')), Option('--help-reactors', action='store_true', help=_('List available reactors for -r.')), Option('--plugin', '-p', help=_('twistd plugin to run (use twistd for a list). ' 'Use "--" to pass further options to the plugin.')), Option('--server', '-s', type='int', help=_('Port to run an eval server on (forces Twisted).')), ])) if options.help_reactors: try: from twisted.application import reactors # Stolen from twisted.application.app (twistd). for r in reactors.getReactorTypes(): print(' %-4s\t%s' % (r.shortName, r.description)) except ImportError: sys.stderr.write('No reactors are available. Please install ' 'twisted for reactor support.\n') return palette = [(name, COLORMAP[color.lower()], 'default', 'bold' if color.isupper() else 'default') for name, color in config.color_scheme.items()] palette.extend([('bold ' + name, color + ',bold', background, monochrome) for name, color, background, monochrome in palette]) if options.server or options.plugin: options.twisted = True if options.reactor: try: from twisted.application import reactors except ImportError: sys.stderr.write('No reactors are available. Please install ' 'twisted for reactor support.\n') return try: # XXX why does this not just return the reactor it installed? reactor = reactors.installReactor(options.reactor) if reactor is None: from twisted.internet import reactor except reactors.NoSuchReactor: sys.stderr.write('Reactor %s does not exist\n' % (options.reactor, )) return event_loop = TwistedEventLoop(reactor) elif options.twisted: try: from twisted.internet import reactor except ImportError: sys.stderr.write('No reactors are available. Please install ' 'twisted for reactor support.\n') return event_loop = TwistedEventLoop(reactor) else: # None, not urwid.SelectEventLoop(), to work with # screens that do not support external event loops. event_loop = None # TODO: there is also a glib event loop. Do we want that one? # __main__ construction from bpython.cli if locals_ is None: main_mod = sys.modules['__main__'] = ModuleType('__main__') locals_ = main_mod.__dict__ if options.plugin: try: from twisted import plugin from twisted.application import service except ImportError: sys.stderr.write( 'No twisted plugins are available. Please install ' 'twisted for twisted plugin support.\n') return for plug in plugin.getPlugins(service.IServiceMaker): if plug.tapname == options.plugin: break else: sys.stderr.write('Plugin %s does not exist\n' % (options.plugin, )) return plugopts = plug.options() plugopts.parseOptions(exec_args) serv = plug.makeService(plugopts) locals_['service'] = serv reactor.callWhenRunning(serv.startService) exec_args = [] interpreter = repl.Interpreter(locals_, locale.getpreferredencoding()) # This nabs sys.stdin/out via urwid.MainLoop myrepl = URWIDRepl(event_loop, palette, interpreter, config) if options.server: factory = EvalFactory(myrepl) reactor.listenTCP(options.server, factory, interface='127.0.0.1') if options.reactor: # Twisted sets a sigInt handler that stops the reactor unless # it sees a different custom signal handler. def sigint(*args): reactor.callFromThread(myrepl.keyboard_interrupt) signal.signal(signal.SIGINT, sigint) # Save stdin, stdout and stderr for later restoration orig_stdin = sys.stdin orig_stdout = sys.stdout orig_stderr = sys.stderr # urwid's screen start() and stop() calls currently hit sys.stdin # directly (via RealTerminal.tty_signal_keys), so start the screen # before swapping sys.std*, and swap them back before restoring # the screen. This also avoids crashes if our redirected sys.std* # are called before we get around to starting the mainloop # (urwid raises an exception if we try to draw to the screen # before starting it). def run_with_screen_before_mainloop(): try: # Currently we just set this to None because I do not # expect code hitting stdin to work. For example: exit() # (not sys.exit, site.py's exit) tries to close sys.stdin, # which breaks urwid's shutdown. bpython.cli sets this to # a fake object that reads input through curses and # returns it. When using twisted I do not think we can do # that because sys.stdin.read and friends block, and we # cannot re-enter the reactor. If using urwid's own # mainloop we *might* be able to do something similar and # re-enter its mainloop. sys.stdin = None #FakeStdin(myrepl) sys.stdout = myrepl sys.stderr = myrepl myrepl.main_loop.set_alarm_in(0, start) while True: try: myrepl.main_loop.run() except KeyboardInterrupt: # HACK: if we run under a twisted mainloop this should # never happen: we have a SIGINT handler set. # If we use the urwid select-based loop we just restart # that loop if interrupted, instead of trying to cook # up an equivalent to reactor.callFromThread (which # is what our Twisted sigint handler does) myrepl.main_loop.set_alarm_in( 0, lambda *args: myrepl.keyboard_interrupt()) continue break finally: sys.stdin = orig_stdin sys.stderr = orig_stderr sys.stdout = orig_stdout # This needs more thought. What needs to happen inside the mainloop? def start(main_loop, user_data): if exec_args: bpargs.exec_code(interpreter, exec_args) if not options.interactive: raise urwid.ExitMainLoop() if not exec_args: sys.path.insert(0, '') # this is CLIRepl.startup inlined. filename = os.environ.get('PYTHONSTARTUP') if filename and os.path.isfile(filename): with open(filename, 'r') as f: if py3: interpreter.runsource(f.read(), filename, 'exec') else: interpreter.runsource(f.read(), filename, 'exec', encode=False) if banner is not None: repl.write(banner) repl.write('\n') myrepl.start() # This bypasses main_loop.set_alarm_in because we must *not* # hit the draw_screen call (it's unnecessary and slow). def run_find_coroutine(): if find_coroutine(): main_loop.event_loop.alarm(0, run_find_coroutine) run_find_coroutine() myrepl.main_loop.screen.run_wrapper(run_with_screen_before_mainloop) if config.flush_output and not options.quiet: sys.stdout.write(myrepl.getstdout()) if hasattr(sys.stdout, "flush"): sys.stdout.flush() return repl.extract_exit_value(myrepl.exit_value)
def main(args=None, locals_=None, banner=None, welcome_message=None): """ banner is displayed directly after the version information. welcome_message is passed on to Repl and displayed in the statusbar. """ translations.init() config, options, exec_args = bpargs.parse(args, ( 'curtsies options', None, [ Option('--log', '-L', action='count', help=_("log debug messages to bpython.log")), Option('--paste', '-p', action='store_true', help=_("start by pasting lines of a file into session")), ])) if options.log is None: options.log = 0 logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG] level = logging_levels[min(len(logging_levels) - 1, options.log)] logging.getLogger('curtsies').setLevel(level) logging.getLogger('bpython').setLevel(level) if options.log: handler = logging.FileHandler(filename='bpython.log') logging.getLogger('curtsies').addHandler(handler) logging.getLogger('curtsies').propagate = False logging.getLogger('bpython').addHandler(handler) logging.getLogger('bpython').propagate = False interp = None paste = None if exec_args: if not options: raise ValueError("don't pass in exec_args without options") exit_value = () if options.paste: paste = curtsies.events.PasteEvent() encoding = inspection.get_encoding_file(exec_args[0]) with io.open(exec_args[0], encoding=encoding) as f: sourcecode = f.read() paste.events.extend(sourcecode) else: try: interp = Interp(locals=locals_) bpargs.exec_code(interp, exec_args) except SystemExit as e: exit_value = e.args if not options.interactive: return extract_exit_value(exit_value) else: # expected for interactive sessions (vanilla python does it) sys.path.insert(0, '') if not options.quiet: print(bpargs.version_banner()) if banner is not None: print(banner) global repl repl = FullCurtsiesRepl(config, locals_, welcome_message, interp, paste) try: with repl.input_generator: with repl.window as win: with repl: repl.height, repl.width = win.t.height, win.t.width exit_value = repl.mainloop() except (SystemExitFromCodeGreenlet, SystemExit) as e: exit_value = e.args return extract_exit_value(exit_value)
def callback_wrapper(result): callback(result.lower() in (_('y'), _('yes')))
def __init__(self, locals_=None, config=None, request_refresh=lambda: None, banner=None, interp=None): """ locals_ is a mapping of locals to pass into the interpreter config is a bpython config.Struct with config attributes request_refresh is a function that will be called when the Repl wants to refresh the display, but wants control returned to it afterwards banner is a string to display briefly in the status bar interp is an interpreter to use """ logging.debug("starting init") if config is None: config = Struct() loadini(config, default_config_path()) self.weak_rewind = bool(locals_ or interp) # If creating a new interpreter on undo # would be unsafe because initial # state was passed in if interp is None: interp = code.InteractiveInterpreter(locals=locals_) if banner is None: banner = _('welcome to bpython') config.autocomplete_mode = SIMPLE # only one implemented currently if config.cli_suggestion_width <= 0 or config.cli_suggestion_width > 1: config.cli_suggestion_width = 1 self.reevaluating = False self.fake_refresh_requested = False def smarter_request_refresh(): if self.reevaluating or self.paste_mode: self.fake_refresh_requested = True else: request_refresh() self.request_refresh = smarter_request_refresh self.status_bar = StatusBar(banner if config.curtsies_fill_terminal else '', _( " <%s> Rewind <%s> Save <%s> Pastebin <%s> Editor" ) % (config.undo_key, config.save_key, config.pastebin_key, config.external_editor_key), refresh_request=self.request_refresh ) self.rl_char_sequences = get_updated_char_sequences(key_dispatch, config) logging.debug("starting parent init") super(Repl, self).__init__(interp, config) self.formatter = BPythonFormatter(config.color_scheme) self.interact = self.status_bar # overwriting what bpython.Repl put there # interact is called to interact with the status bar, # so we're just using the same object self._current_line = '' # line currently being edited, without '>>> ' self.current_stdouterr_line = '' # current line of output - stdout and stdin go here self.display_lines = [] # lines separated whenever logical line # length goes over what the terminal width # was at the time of original output self.history = [] # this is every line that's been executed; # it gets smaller on rewind self.display_buffer = [] # formatted version of lines in the buffer # kept around so we can unhighlight parens # using self.reprint_line as called by # bpython.Repl self.scroll_offset = 0 # how many times display has been scrolled down # because there wasn't room to display everything self.cursor_offset_in_line = 0 # from the left, 0 means first char self.coderunner = CodeRunner(self.interp, self.request_refresh) self.stdout = FakeOutput(self.coderunner, self.send_to_stdout) self.stderr = FakeOutput(self.coderunner, self.send_to_stderr) self.stdin = FakeStdin(self.coderunner, self) self.request_paint_to_clear_screen = False # next paint should clear screen self.last_events = [None] * 50 self.presentation_mode = False self.paste_mode = False self.width = None # will both be set by a window resize event self.height = None
def parse(args, extras=None, ignore_stdin=False): """Receive an argument list - if None, use sys.argv - parse all args and take appropriate action. Also receive optional extra options: this should be a tuple of (title, description, options) title: The title for the option group description: A full description of the option group options: A list of optparse.Option objects to be added to the group e.g.: parse( ['-i', '-m', 'foo.py'], ('Front end-specific options', 'A full description of what these options are for', [optparse.Option('-f', action='store_true', dest='f', help='Explode'), optparse.Option('-l', action='store_true', dest='l', help='Love')])) Return a tuple of (config, options, exec_args) wherein "config" is the config object either parsed from a default/specified config file or default config options, "options" is the parsed options from OptionParser.parse_args, and "exec_args" are the args (if any) to be parsed to the executed file (if any). """ if args is None: args = sys.argv[1:] parser = RaisingOptionParser( usage=_('Usage: %prog [options] [file [args]]\n' 'NOTE: If bpython sees an argument it does ' 'not know, execution falls back to the ' 'regular Python interpreter.')) # This is not sufficient if bpython gains its own -m support # (instead of falling back to Python itself for that). # That's probably fixable though, for example by having that # option swallow all remaining arguments in a callback. parser.disable_interspersed_args() parser.add_option('--config', default=default_config_path(), help=_('Use CONFIG instead of default config file.')) parser.add_option('--interactive', '-i', action='store_true', help=_('Drop to bpython shell after running file ' 'instead of exiting.')) parser.add_option('--quiet', '-q', action='store_true', help=_("Don't flush the output to stdout.")) parser.add_option('--version', '-V', action='store_true', help=_('Print version and exit.')) if extras is not None: extras_group = OptionGroup(parser, extras[0], extras[1]) for option in extras[2]: extras_group.add_option(option) parser.add_option_group(extras_group) try: options, args = parser.parse_args(args) except OptionParserFailed: # Just let Python handle this os.execv(sys.executable, [sys.executable] + args) if options.version: print('bpython version', __version__, end=" ") print('on top of Python', sys.version.split()[0]) print('(C) 2008-2015 Bob Farrell, Andreas Stuehrk et al. ' 'See AUTHORS for detail.') raise SystemExit if not ignore_stdin and not (sys.stdin.isatty() and sys.stdout.isatty()): interpreter = code.InteractiveInterpreter() interpreter.runsource(sys.stdin.read()) raise SystemExit config = Struct() loadini(config, options.config) return config, options, args
stdout=subprocess.PIPE) helper.stdin.write(s.encode(getpreferredencoding())) output = helper.communicate()[0].decode(getpreferredencoding()) paste_url = output.split()[0] except OSError, e: if e.errno == errno.ENOENT: self.interact.notify(_('Upload failed: ' 'Helper program not found.')) else: self.interact.notify(_('Upload failed: ' 'Helper program could not be run.')) return if helper.returncode != 0: self.interact.notify(_('Upload failed: ' 'Helper program returned non-zero exit ' 'status %s.' % (helper.returncode, ))) return if not paste_url: self.interact.notify(_('Upload failed: ' 'No output from helper program.')) return else: parsed_url = urlparse(paste_url) if (not parsed_url.scheme or any(unicodedata.category(c) == 'Cc' for c in paste_url)): self.interact.notify(_("Upload failed: " "Failed to recognize the helper " "program's output as an URL.")) return
def main(args=None): translations.init() gtk_options = (_('gtk-specific options'), _("Options specific to bpython's Gtk+ front end"), [ optparse.Option('--socket-id', dest='socket_id', type='int', help=_('Embed bpython')) ]) config, options, exec_args = bpython.args.parse(args, gtk_options, True) interpreter = repl.Interpreter(None, getpreferredencoding()) repl_widget = ReplWidget(interpreter, config) repl_widget.connect('exit-event', gtk.main_quit) gobject.idle_add(init_import_completion) if not exec_args: sys.path.insert(0, '') gobject.idle_add(repl_widget.startup) else: if options.interactive: gobject.idle_add(bpython.args.exec_code, interpreter, exec_args) else: bpython.args.exec_code(interpreter, exec_args) return 0 sys.stderr = repl_widget sys.stdout = repl_widget if not options.socket_id: parent = gtk.Window() parent.connect('delete-event', lambda widget, event: gtk.main_quit()) # branding # fix icon to be distributed and loaded from the correct path icon = gtk.gdk.pixbuf_new_from_file( os.path.join(os.path.dirname(__file__), 'logo.png')) parent.set_title('bpython') parent.set_icon(icon) parent.resize(600, 300) else: parent = gtk.Plug(options.socket_id) parent.connect('destroy', gtk.main_quit) container = gtk.VBox() parent.add(container) mb = gtk.MenuBar() filemenu = gtk.Menu() filem = gtk.MenuItem("File") filem.set_submenu(filemenu) save = gtk.ImageMenuItem(gtk.STOCK_SAVE) save.connect("activate", repl_widget.do_write2file) filemenu.append(save) pastebin = gtk.MenuItem("Pastebin") pastebin.connect("activate", repl_widget.do_paste) filemenu.append(pastebin) pastebin_partial = gtk.MenuItem(_("Pastebin selection")) pastebin_partial.connect("activate", repl_widget.do_partial_paste) filemenu.append(pastebin_partial) exit = gtk.ImageMenuItem(gtk.STOCK_QUIT) exit.connect("activate", gtk.main_quit) filemenu.append(exit) mb.append(filem) vbox = gtk.VBox(False, 2) vbox.pack_start(mb, False, False, 0) container.pack_start(vbox, expand=False) # read from config sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) sw.add(repl_widget) container.add(sw) sb = repl_widget.interact.statusbar container.pack_end(sb, expand=False) parent.set_focus(repl_widget) parent.show_all() parent.connect('delete-event', lambda widget, event: gtk.main_quit()) try: gtk.main() except KeyboardInterrupt: pass return 0
def do_key_press_event(self, event): state = event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK | gtk.gdk.MOD4_MASK | gtk.gdk.SHIFT_MASK) if not state: if event.keyval == gtk.keysyms.F2: source = self.get_source_of_current_name() if source is not None: show_source_in_new_window(source, self.config.color_gtk_scheme, self.config.syntax) else: self.interact.notify(_('Cannot show source.')) elif event.keyval == gtk.keysyms.Return: if self.list_win_visible: self.list_win_visible = False self.list_win.hide() self.rl_history.reset() line = self.current_line() more = self.push_line() self.prompt(more) if self.reset_indent: self.reset_indent = False else: indentation = self.next_indentation() if indentation: with self.editing: self.text_buffer.insert(self.get_cursor_iter(), '\t' * indentation) self.move_cursor(indentation) return True elif event.keyval == gtk.keysyms.Tab and self.list_win_visible: self.list_win.forward() return True elif event.keyval == gtk.keysyms.Up: if self.list_win_visible: self.list_win.back() else: if not self.rl_history.is_at_end: self.rl_history.enter(self.current_line()) self.change_line(self.rl_history.back()) self.text_buffer.place_cursor(self.get_line_end_iter()) return True elif event.keyval == gtk.keysyms.Down: if self.list_win_visible: self.list_win.forward() else: if not self.rl_history.is_at_start: self.rl_history.enter(self.current_line()) self.change_line(self.rl_history.forward()) self.text_buffer.place_cursor(self.get_line_end_iter()) return True elif state & gtk.gdk.SHIFT_MASK: if (event.keyval == gtk.keysyms.ISO_Left_Tab and self.list_win_visible): self.list_win.back() return True elif state & gtk.gdk.CONTROL_MASK: if event.string == chr(4) and not self.current_line(): self.emit('exit-event') return True return gtk.TextView.do_key_press_event(self, event)
def parse(args, extras=None, ignore_stdin=False): """Receive an argument list - if None, use sys.argv - parse all args and take appropriate action. Also receive optional extra options: this should be a tuple of (title, description, options) title: The title for the option group description: A full description of the option group options: A list of optparse.Option objects to be added to the group e.g.: parse(['-i', '-m', 'foo.py'], ('Front end-specific options', 'A full description of what these options are for', [optparse.Option('-f', action='store_true', dest='f', help='Explode'), optparse.Option('-l', action='store_true', dest='l', help='Love')])) Return a tuple of (config, options, exec_args) wherein "config" is the config object either parsed from a default/specified config file or default config options, "options" is the parsed options from OptionParser.parse_args, and "exec_args" are the args (if any) to be parsed to the executed file (if any). """ if args is None: args = sys.argv[1:] parser = RaisingOptionParser( usage=_('Usage: %prog [options] [file [args]]\n' 'NOTE: If bpython sees an argument it does ' 'not know, execution falls back to the ' 'regular Python interpreter.')) # This is not sufficient if bpython gains its own -m support # (instead of falling back to Python itself for that). # That's probably fixable though, for example by having that # option swallow all remaining arguments in a callback. parser.disable_interspersed_args() parser.add_option('--config', default=default_config_path(), help=_('Use CONFIG instead of default config file.')) parser.add_option('--interactive', '-i', action='store_true', help=_('Drop to bpython shell after running file ' 'instead of exiting.')) parser.add_option('--quiet', '-q', action='store_true', help=_("Don't flush the output to stdout.")) parser.add_option('--version', '-V', action='store_true', help=_('Print version and exit.')) if extras is not None: extras_group = OptionGroup(parser, extras[0], extras[1]) for option in extras[2]: extras_group.add_option(option) parser.add_option_group(extras_group) try: options, args = parser.parse_args(args) except OptionParserFailed: # Just let Python handle this os.execv(sys.executable, [sys.executable] + args) if options.version: print('bpython version', __version__, end=' ') print('on top of Python', sys.version.split()[0]) print('(C) 2008-2012 Bob Farrell, Andreas Stuehrk et al. ' 'See AUTHORS for detail.') raise SystemExit if not ignore_stdin and not (sys.stdin.isatty() and sys.stdout.isatty()): interpreter = code.InteractiveInterpreter() interpreter.runsource(sys.stdin.read()) raise SystemExit config = Struct() loadini(config, options.config) return config, options, args
def __init__(self): gtk.Statusbar.__init__(self) self.context_id = self.get_context_id(_('Statusbar'))
def __init__(self, DialogType, text=None): self.DialogType = DialogType self.text = text or _('An error occurred.')