From 27a9b8825573493f9f1bbad706597b61f5d3af2d Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 21:52:54 +0100
Subject: [PATCH 001/864] Simply require Sphinx >= 1.1.3
---
.travis.install.sh | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.install.sh b/.travis.install.sh
index b73e9e5d6..8522aa261 100755
--- a/.travis.install.sh
+++ b/.travis.install.sh
@@ -32,5 +32,5 @@ if [[ $RUN == nosetests ]]; then
python setup.py install
elif [[ $RUN == build_sphinx ]]; then
# documentation specific dependencies
- pip install sphinx
+ pip install 'sphinx >=1.1.3'
fi
diff --git a/setup.py b/setup.py
index 94082134b..c282df7aa 100755
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
try:
import sphinx
from sphinx.setup_command import BuildDoc
- if sphinx.__version__ == '1.1.2':
+ if sphinx.__version__ >= '1.1.3':
# Sphinx 1.1.2 is buggy and building bpython with that version fails.
# See #241.
using_sphinx = False
From 1d23529095a41c213f50d983043f47e7c8ef8e0e Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 22:05:27 +0100
Subject: [PATCH 002/864] Fix typos
---
bpython/curtsiesfrontend/repl.py | 2 +-
bpython/formatter.py | 2 +-
bpython/lazyre.py | 4 ++--
bpython/urwid.py | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index e79d1298f..8d7f9fb7e 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -403,7 +403,7 @@ def __init__(self,
self.request_paint_to_pad_bottom = 0
- # offscreen command yields results different from scrollback bufffer
+ # offscreen command yields results different from scrollback buffer
self.inconsistent_history = False
# history error message has already been displayed
diff --git a/bpython/formatter.py b/bpython/formatter.py
index 6c0ab75ef..96ee6ed28 100644
--- a/bpython/formatter.py
+++ b/bpython/formatter.py
@@ -49,7 +49,7 @@
\x04 represents the end of the string; this is
necessary because the strings are all joined
together at the end so the parser needs them
- as delimeters
+ as delimiters
"""
diff --git a/bpython/lazyre.py b/bpython/lazyre.py
index e27b8de5f..54e8d565b 100644
--- a/bpython/lazyre.py
+++ b/bpython/lazyre.py
@@ -26,8 +26,8 @@
class LazyReCompile(object):
"""Compile regular expressions on first use
- This class allows to store regular expressions and compiles them on first
- use."""
+ This class allows one to store regular expressions and compiles them on
+ first use."""
def __init__(self, regex, flags=0):
self.regex = regex
diff --git a/bpython/urwid.py b/bpython/urwid.py
index d2c392d72..ceb8717b8 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -233,7 +233,7 @@ def _reset_timer(self):
def prompt(self, s=None, single=False):
"""Prompt the user for some input (with the optional prompt 's'). After
- the user hit enter the signal 'prompt_result' will be emited and the
+ the user hit enter the signal 'prompt_result' will be emitted and the
status bar will be reset. If single is True, the first keypress will be
returned."""
From f75870575127bd1be9afb5888279c4fcf9f0a275 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 22:14:03 +0100
Subject: [PATCH 003/864] Fix sphinx version check
---
setup.py | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/setup.py b/setup.py
index c282df7aa..44495534c 100755
--- a/setup.py
+++ b/setup.py
@@ -24,12 +24,9 @@
try:
import sphinx
from sphinx.setup_command import BuildDoc
- if sphinx.__version__ >= '1.1.3':
- # Sphinx 1.1.2 is buggy and building bpython with that version fails.
- # See #241.
- using_sphinx = False
- else:
- using_sphinx = True
+ # Sphinx 1.1.2 is buggy and building bpython with that version fails.
+ # See #241.
+ using_sphinx = sphinx.__version__ >= '1.1.3'
except ImportError:
using_sphinx = False
From 305773234fde003a00e115d6858de82dd93b76e9 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 22:14:14 +0100
Subject: [PATCH 004/864] Use implementation agnostic names
---
bpython/curtsies.py | 8 ++++----
bpython/curtsiesfrontend/coderunner.py | 20 ++++++++++----------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 3f0f4be45..9f7f6d57d 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -12,7 +12,7 @@
import curtsies.events
from bpython.curtsiesfrontend.repl import BaseRepl
-from bpython.curtsiesfrontend.coderunner import SystemExitFromCodeGreenlet
+from bpython.curtsiesfrontend.coderunner import SystemExitFromCodeRunner
from bpython.curtsiesfrontend.interpreter import Interp
from bpython import args as bpargs
from bpython import translations
@@ -87,11 +87,11 @@ def process_event_and_paint(self, e):
try:
if e is not None:
self.process_event(e)
- except (SystemExitFromCodeGreenlet, SystemExit) as err:
+ except (SystemExitFromCodeRunner, SystemExit) as err:
array, cursor_pos = self.paint(
about_to_exit=True,
user_quit=isinstance(err,
- SystemExitFromCodeGreenlet))
+ SystemExitFromCodeRunner))
scrolled = self.window.render_to_terminal(array, cursor_pos)
self.scroll_offset += scrolled
raise
@@ -188,7 +188,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
with repl:
repl.height, repl.width = win.t.height, win.t.width
exit_value = repl.mainloop()
- except (SystemExitFromCodeGreenlet, SystemExit) as e:
+ except (SystemExitFromCodeRunner, SystemExit) as e:
exit_value = e.args
return extract_exit_value(exit_value)
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index 79fb215ff..630caf9a0 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -25,32 +25,32 @@ class SigintHappened(object):
"""If this class is returned, a SIGINT happened while the main greenlet"""
-class SystemExitFromCodeGreenlet(SystemExit):
+class SystemExitFromCodeRunner(SystemExit):
"""If this class is returned, a SystemExit happened while in the code
greenlet"""
-class RequestFromCodeGreenlet(object):
- """Message from the code greenlet"""
+class RequestFromCodeRunner(object):
+ """Message from the code runner"""
-class Wait(RequestFromCodeGreenlet):
+class Wait(RequestFromCodeRunner):
"""Running code would like the main loop to run for a bit"""
-class Refresh(RequestFromCodeGreenlet):
+class Refresh(RequestFromCodeRunner):
"""Running code would like the main loop to refresh the display"""
-class Done(RequestFromCodeGreenlet):
+class Done(RequestFromCodeRunner):
"""Running code is done running"""
-class Unfinished(RequestFromCodeGreenlet):
+class Unfinished(RequestFromCodeRunner):
"""Source code wasn't executed because it wasn't fully formed"""
-class SystemExitRequest(RequestFromCodeGreenlet):
+class SystemExitRequest(RequestFromCodeRunner):
"""Running code raised a SystemExit"""
def __init__(self, args):
@@ -145,7 +145,7 @@ def run_code(self, for_code=None):
request = self.code_greenlet.switch(for_code)
logger.debug('request received from code was %r', request)
- if not isinstance(request, RequestFromCodeGreenlet):
+ if not isinstance(request, RequestFromCodeRunner):
raise ValueError("Not a valid value from code greenlet: %r" %
request)
if isinstance(request, (Wait, Refresh)):
@@ -160,7 +160,7 @@ def run_code(self, for_code=None):
return request
elif isinstance(request, SystemExitRequest):
self._unload_code()
- raise SystemExitFromCodeGreenlet(request.args)
+ raise SystemExitFromCodeRunner(request.args)
def sigint_handler(self, *args):
"""SIGINT handler to use while code is running or request being
From 2b8c30b94690941c00ae8d70a6fe11d5d43d8461 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 22:24:25 +0100
Subject: [PATCH 005/864] Rename {main,code,request}_greenlet to *_context
---
bpython/curtsiesfrontend/coderunner.py | 42 ++++++++++++-------------
bpython/curtsiesfrontend/interaction.py | 26 +++++++--------
bpython/curtsiesfrontend/repl.py | 4 +--
3 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index 630caf9a0..fc1e9dac6 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -61,13 +61,13 @@ class CodeRunner(object):
"""Runs user code in an interpreter.
Running code requests a refresh by calling
- request_from_main_greenlet(force_refresh=True), which
+ request_from_main_context(force_refresh=True), which
suspends execution of the code and switches back to the main greenlet
After load_code() is called with the source code to be run,
the run_code() method should be called to start running the code.
The running code may request screen refreshes and user input
- by calling request_from_main_greenlet.
+ by calling request_from_main_context.
When this are called, the running source code cedes
control, and the current run_code() method call returns.
@@ -93,32 +93,32 @@ def __init__(self, interp=None, request_refresh=lambda: None):
"""
self.interp = interp or code.InteractiveInterpreter()
self.source = None
- self.main_greenlet = greenlet.getcurrent()
- self.code_greenlet = None
+ self.main_context = greenlet.getcurrent()
+ self.code_context = None
self.request_refresh = request_refresh
# waiting for response from main thread
self.code_is_waiting = False
# sigint happened while in main thread
- self.sigint_happened_in_main_greenlet = False
+ self.sigint_happened_in_main_context = False
self.orig_sigint_handler = None
@property
def running(self):
"""Returns greenlet if code has been loaded greenlet has been
started"""
- return self.source and self.code_greenlet
+ return self.source and self.code_context
def load_code(self, source):
"""Prep code to be run"""
assert self.source is None, "you shouldn't load code when some is " \
"already running"
self.source = source
- self.code_greenlet = None
+ self.code_context = None
def _unload_code(self):
"""Called when done running code"""
self.source = None
- self.code_greenlet = None
+ self.code_context = None
self.code_is_waiting = False
def run_code(self, for_code=None):
@@ -128,21 +128,21 @@ def run_code(self, for_code=None):
if source code is complete, returns "done"
if source code is incomplete, returns "unfinished"
"""
- if self.code_greenlet is None:
+ if self.code_context is None:
assert self.source is not None
- self.code_greenlet = greenlet.greenlet(self._blocking_run_code)
+ self.code_context = greenlet.greenlet(self._blocking_run_code)
self.orig_sigint_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, self.sigint_handler)
- request = self.code_greenlet.switch()
+ request = self.code_context.switch()
else:
assert self.code_is_waiting
self.code_is_waiting = False
signal.signal(signal.SIGINT, self.sigint_handler)
- if self.sigint_happened_in_main_greenlet:
- self.sigint_happened_in_main_greenlet = False
- request = self.code_greenlet.switch(SigintHappened)
+ if self.sigint_happened_in_main_context:
+ self.sigint_happened_in_main_context = False
+ request = self.code_context.switch(SigintHappened)
else:
- request = self.code_greenlet.switch(for_code)
+ request = self.code_context.switch(for_code)
logger.debug('request received from code was %r', request)
if not isinstance(request, RequestFromCodeRunner):
@@ -165,13 +165,13 @@ def run_code(self, for_code=None):
def sigint_handler(self, *args):
"""SIGINT handler to use while code is running or request being
fulfilled"""
- if greenlet.getcurrent() is self.code_greenlet:
+ if greenlet.getcurrent() is self.code_context:
logger.debug('sigint while running user code!')
raise KeyboardInterrupt()
else:
logger.debug('sigint while fulfilling code request sigint handler '
'running!')
- self.sigint_happened_in_main_greenlet = True
+ self.sigint_happened_in_main_context = True
def _blocking_run_code(self):
try:
@@ -180,15 +180,15 @@ def _blocking_run_code(self):
return SystemExitRequest(e.args)
return Unfinished() if unfinished else Done()
- def request_from_main_greenlet(self, force_refresh=False):
+ def request_from_main_context(self, force_refresh=False):
"""Return the argument passed in to .run_code(for_code)
Nothing means calls to run_code must be... ???
"""
if force_refresh:
- value = self.main_greenlet.switch(Refresh())
+ value = self.main_context.switch(Refresh())
else:
- value = self.main_greenlet.switch(Wait())
+ value = self.main_context.switch(Wait())
if value is SigintHappened:
raise KeyboardInterrupt()
return value
@@ -211,7 +211,7 @@ def write(self, s, *args, **kwargs):
if not py3 and isinstance(s, str):
s = s.decode(getpreferredencoding(), 'ignore')
self.on_write(s, *args, **kwargs)
- return self.coderunner.request_from_main_greenlet(force_refresh=True)
+ return self.coderunner.request_from_main_context(force_refresh=True)
# Some applications which use curses require that sys.stdout
# have a method called fileno. One example is pwntools. This
diff --git a/bpython/curtsiesfrontend/interaction.py b/bpython/curtsiesfrontend/interaction.py
index 3022ba430..94ce6a3cf 100644
--- a/bpython/curtsiesfrontend/interaction.py
+++ b/bpython/curtsiesfrontend/interaction.py
@@ -40,8 +40,8 @@ def __init__(self,
self.permanent_stack = []
if permanent_text:
self.permanent_stack.append(permanent_text)
- self.main_greenlet = greenlet.getcurrent()
- self.request_greenlet = None
+ self.main_context = greenlet.getcurrent()
+ self.request_context = None
self.request_refresh = request_refresh
self.schedule_refresh = schedule_refresh
@@ -76,13 +76,13 @@ def process_event(self, e):
assert self.in_prompt or self.in_confirm or self.waiting_for_refresh
if isinstance(e, RefreshRequestEvent):
self.waiting_for_refresh = False
- self.request_greenlet.switch()
+ self.request_context.switch()
elif isinstance(e, events.PasteEvent):
for ee in e.events:
# strip control seq
self.add_normal_character(ee if len(ee) == 1 else ee[-1])
elif e in [''] or isinstance(e, events.SigIntEvent):
- self.request_greenlet.switch(False)
+ self.request_context.switch(False)
self.escape()
elif e in edit_keys:
self.cursor_offset_in_line, self._current_line = edit_keys[e](
@@ -94,12 +94,12 @@ def process_event(self, e):
elif self.in_prompt and e in ("\n", "\r", "", "Ctrl-m>"):
line = self._current_line
self.escape()
- self.request_greenlet.switch(line)
+ self.request_context.switch(line)
elif self.in_confirm:
if e in ('y', 'Y'):
- self.request_greenlet.switch(True)
+ self.request_context.switch(True)
else:
- self.request_greenlet.switch(False)
+ self.request_context.switch(False)
self.escape()
else: # add normal character
self.add_normal_character(e)
@@ -140,26 +140,26 @@ def should_show_message(self):
# interaction interface - should be called from other greenlets
def notify(self, msg, n=3, wait_for_keypress=False):
- self.request_greenlet = greenlet.getcurrent()
+ self.request_context = greenlet.getcurrent()
self.message_time = n
self.message(msg, schedule_refresh=wait_for_keypress)
self.waiting_for_refresh = True
self.request_refresh()
- self.main_greenlet.switch(msg)
+ self.main_context.switch(msg)
# below Really ought to be called from greenlets other than main because
# they block
def confirm(self, q):
"""Expected to return True or False, given question prompt q"""
- self.request_greenlet = greenlet.getcurrent()
+ self.request_context = greenlet.getcurrent()
self.prompt = q
self.in_confirm = True
- return self.main_greenlet.switch(q)
+ return self.main_context.switch(q)
def file_prompt(self, s):
"""Expected to return a file name, given """
- self.request_greenlet = greenlet.getcurrent()
+ self.request_context = greenlet.getcurrent()
self.prompt = s
self.in_prompt = True
- result = self.main_greenlet.switch(s)
+ result = self.main_context.switch(s)
return result
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 8d7f9fb7e..c45f0f2b7 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -128,7 +128,7 @@ def process_event(self, e):
self.cursor_offset, self.current_line = self.rl_char_sequences[e](
self.cursor_offset, self.current_line)
elif isinstance(e, events.SigIntEvent):
- self.coderunner.sigint_happened_in_main_greenlet = True
+ self.coderunner.sigint_happened_in_main_context = True
self.has_focus = False
self.current_line = ''
self.cursor_offset = 0
@@ -179,7 +179,7 @@ def add_input_character(self, e):
def readline(self):
self.has_focus = True
self.repl.send_to_stdin(self.current_line)
- value = self.coderunner.request_from_main_greenlet()
+ value = self.coderunner.request_from_main_context()
self.readline_results.append(value)
return value
From f35f8056e1e7dff19774734b0ef06439fb2298bb Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 23:01:05 +0100
Subject: [PATCH 006/864] Be consistent with history file expansion
---
bpython/repl.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index cd3dc9a5c..03c4debf7 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -899,8 +899,9 @@ def push(self, s, insert_into_history=True):
return more
def insert_into_history(self, s):
+ pythonhist = os.path.expanduser(self.config.hist_file)
try:
- self.rl_history.append_reload_and_write(s, self.config.hist_file,
+ self.rl_history.append_reload_and_write(s, pythonhist,
getpreferredencoding())
except RuntimeError as e:
self.interact.notify(u"%s" % (e, ))
From 205ca1be204c12ebac162b9fe95945b290f15a19 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 23:05:12 +0100
Subject: [PATCH 007/864] Disable history for tests
---
bpython/test/test.config | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/test/test.config b/bpython/test/test.config
index 334706bab..b7397d44f 100644
--- a/bpython/test/test.config
+++ b/bpython/test/test.config
@@ -1,3 +1,3 @@
[general]
-hist_file = /dev/null
-paste_time = 0
\ No newline at end of file
+hist_size = 0
+paste_time = 0
From 5d1c976585123710ea2e438655d24603fa5565ca Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 22:55:29 +0100
Subject: [PATCH 008/864] Move TEST_CONFIG to bpython.test
---
bpython/test/__init__.py | 4 ++++
bpython/test/test_crashers.py | 4 +---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/bpython/test/__init__.py b/bpython/test/__init__.py
index 7aa5d1a9d..39b5f5cb3 100644
--- a/bpython/test/__init__.py
+++ b/bpython/test/__init__.py
@@ -13,6 +13,7 @@
from bpython.translations import init
from bpython._py3compat import py3
from six.moves import builtins
+import os
class FixLanguageTestCase(unittest.TestCase):
@@ -33,3 +34,6 @@ class MagicIterMock(mock.MagicMock):
def builtin_target(obj):
"""Returns mock target string of a builtin"""
return '%s.%s' % (builtins.__name__, obj.__name__)
+
+
+TEST_CONFIG = os.path.join(os.path.dirname(__file__), "test.config")
diff --git a/bpython/test/test_crashers.py b/bpython/test/test_crashers.py
index e2f1ccabb..341f6b45f 100644
--- a/bpython/test/test_crashers.py
+++ b/bpython/test/test_crashers.py
@@ -6,7 +6,7 @@
import termios
import textwrap
-from bpython.test import unittest
+from bpython.test import unittest, TEST_CONFIG
try:
from twisted.internet import reactor
@@ -32,8 +32,6 @@ def identity(func):
return func
return identity
-TEST_CONFIG = os.path.join(os.path.dirname(__file__), "test.config")
-
def set_win_size(fd, rows, columns):
s = struct.pack('HHHH', rows, columns, 0, 0)
From a6fef36886fa8c02f0eaadbfb3a3979bea327e6a Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 19 Dec 2016 23:13:33 +0100
Subject: [PATCH 009/864] Use test config (fixes #654)
---
bpython/test/test_curtsies_painting.py | 4 ++--
bpython/test/test_curtsies_repl.py | 4 ++--
bpython/test/test_repl.py | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py
index ec0d102c2..80f29ab78 100644
--- a/bpython/test/test_curtsies_painting.py
+++ b/bpython/test/test_curtsies_painting.py
@@ -18,12 +18,12 @@
from bpython.repl import History
from bpython.curtsiesfrontend.repl import INCONSISTENT_HISTORY_MSG, \
CONTIGUITY_BROKEN_MSG
-from bpython.test import FixLanguageTestCase as TestCase
+from bpython.test import FixLanguageTestCase as TestCase, TEST_CONFIG
def setup_config():
config_struct = config.Struct()
- config.loadini(config_struct, os.devnull)
+ config.loadini(config_struct, TEST_CONFIG)
config_struct.cli_suggestion_width = 1
return config_struct
diff --git a/bpython/test/test_curtsies_repl.py b/bpython/test/test_curtsies_repl.py
index 03a7b8ae3..3cf25da85 100644
--- a/bpython/test/test_curtsies_repl.py
+++ b/bpython/test/test_curtsies_repl.py
@@ -18,7 +18,7 @@
from bpython import args
from bpython._py3compat import py3
from bpython.test import (FixLanguageTestCase as TestCase, MagicIterMock, mock,
- unittest)
+ unittest, TEST_CONFIG)
from curtsies import events
@@ -31,7 +31,7 @@ def invalidate_caches():
def setup_config(conf):
config_struct = config.Struct()
- config.loadini(config_struct, os.devnull)
+ config.loadini(config_struct, TEST_CONFIG)
for key, value in conf.items():
if not hasattr(config_struct, key):
raise ValueError("%r is not a valid config attribute" % (key, ))
diff --git a/bpython/test/test_repl.py b/bpython/test/test_repl.py
index a27de674d..34d7f774a 100644
--- a/bpython/test/test_repl.py
+++ b/bpython/test/test_repl.py
@@ -11,7 +11,7 @@
from bpython._py3compat import py3
from bpython import config, repl, cli, autocomplete
from bpython.test import MagicIterMock, mock, FixLanguageTestCase as TestCase
-from bpython.test import unittest
+from bpython.test import unittest, TEST_CONFIG
pypy = 'PyPy' in sys.version
@@ -19,7 +19,7 @@
def setup_config(conf):
config_struct = config.Struct()
- config.loadini(config_struct, os.devnull)
+ config.loadini(config_struct, TEST_CONFIG)
if 'autocomplete_mode' in conf:
config_struct.autocomplete_mode = conf['autocomplete_mode']
return config_struct
From 3e99cc5f09da031d35467529fa0958722f819e51 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 00:12:40 +0100
Subject: [PATCH 010/864] Port FileLock to Windows
Signed-off-by: Sebastian Ramacher
---
bpython/filelock.py | 89 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 71 insertions(+), 18 deletions(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 9c98b2acd..958e8220d 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -2,7 +2,7 @@
# The MIT License
#
-# Copyright (c) 2015 Sebastian Ramacher
+# Copyright (c) 2015-2016 Sebastian Ramacher
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -30,33 +30,86 @@
except ImportError:
has_fcntl = False
+try:
+ import msvcrt
+ has_msvcrt = True
+except ImportError:
+ has_msvcrt = False
+
+
+class BaseLock(object):
+ """Base class for file locking
+ """
+
+ def __init__(self, fd):
+ self.fd = fd
+ self.locked = False
-class FileLock(object):
- """Simple file locking
+ def acquire(self):
+ pass
- On platforms without fcntl, all operations in this class are no-ops.
+ def release(self):
+ pass
+
+ def __enter__(self):
+ self.acquire()
+
+ def __exit__(self, *args):
+ if self.locked:
+ self.release()
+
+ def __del__(self):
+ if self.locked:
+ self.release()
+
+
+class UnixFileLock(BaseLock):
+ """Simple file locking for Unix using fcntl
"""
def __init__(self, fd, mode=None):
- if has_fcntl and mode is None:
- mode = fcntl.LOCK_EX
+ super(UnixFileLock, self).__init__(fd)
- self.fd = fd
+ if mode is None:
+ mode = fcntl.LOCK_EX
self.mode = mode
+
+ def acquire(self):
+ try:
+ fcntl.flock(self.fd, self.mode)
+ self.locked = True
+ except IOError as e:
+ if e.errno != errno.ENOLCK:
+ raise e
+ return self
+
+ def release(self):
+ fcntl.flock(self.fd, fcntl.LOCK_UN)
self.locked = False
- def __enter__(self):
- if has_fcntl:
- try:
- fcntl.flock(self.fd, self.mode)
- self.locked = True
- except IOError as e:
- if e.errno != errno.ENOLCK:
- raise e
+
+class WindowsFileLock(BaseLock):
+ """Simple file locking for Windows using msvcrt
+ """
+
+ def __init__(self, fd, mode=None):
+ super(WindowsFileLock, self).__init__(fd)
+
+ def acquire(self):
+ msvcrt.locking(self.fd, msvcrt.LK_NBLCK, 1)
+ self.locked = True
return self
- def __exit__(self, *args):
- if has_fcntl and self.locked:
- fcntl.flock(self.fd, fcntl.LOCK_UN)
+ def release(self):
+ msvcrt.locking(self.fd, msvcrt.LK_UNLCK, 1)
+ self.locked = False
+
+
+if has_fcntl:
+ FileLock = UnixFileLock
+elif has_msvcrt:
+ FileLock = WindowsFileLock
+else:
+ FileLock = BaseLock
# vim: sw=4 ts=4 sts=4 ai et
From 4e611563e7bd2e4aee37b8f2afbc5c66ffe7ee9b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 00:17:33 +0100
Subject: [PATCH 011/864] Fix __enter__
Signed-off-by: Sebastian Ramacher
---
bpython/filelock.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 958e8220d..724cb4498 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -53,6 +53,7 @@ def release(self):
def __enter__(self):
self.acquire()
+ return self
def __exit__(self, *args):
if self.locked:
@@ -81,7 +82,6 @@ def acquire(self):
except IOError as e:
if e.errno != errno.ENOLCK:
raise e
- return self
def release(self):
fcntl.flock(self.fd, fcntl.LOCK_UN)
@@ -98,7 +98,6 @@ def __init__(self, fd, mode=None):
def acquire(self):
msvcrt.locking(self.fd, msvcrt.LK_NBLCK, 1)
self.locked = True
- return self
def release(self):
msvcrt.locking(self.fd, msvcrt.LK_UNLCK, 1)
From 8df76efd1f6258b743c32e1e4e82e76e4e1c2ad5 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 00:50:13 +0100
Subject: [PATCH 012/864] Fix name of config variable
---
bpython/test/test.config | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/test/test.config b/bpython/test/test.config
index b7397d44f..21f55c121 100644
--- a/bpython/test/test.config
+++ b/bpython/test/test.config
@@ -1,3 +1,3 @@
[general]
-hist_size = 0
+hist_length = 0
paste_time = 0
From b51df1cf369a49990282326de7067d7f4228fc5c Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 01:15:58 +0100
Subject: [PATCH 013/864] Remove History workaround
We already have a clean history.
---
bpython/test/test_curtsies_painting.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py
index 80f29ab78..3f7414b9e 100644
--- a/bpython/test/test_curtsies_painting.py
+++ b/bpython/test/test_curtsies_painting.py
@@ -15,7 +15,6 @@
from bpython import config, inspection
from bpython.curtsiesfrontend.repl import BaseRepl
from bpython.curtsiesfrontend import replpainter
-from bpython.repl import History
from bpython.curtsiesfrontend.repl import INCONSISTENT_HISTORY_MSG, \
CONTIGUITY_BROKEN_MSG
from bpython.test import FixLanguageTestCase as TestCase, TEST_CONFIG
@@ -48,8 +47,6 @@ class TestRepl(BaseRepl):
def _request_refresh(inner_self):
pass
self.repl = TestRepl(config=setup_config())
- # clear history
- self.repl.rl_history = History()
self.repl.height, self.repl.width = (5, 10)
@property
@@ -236,8 +233,6 @@ class TestRepl(BaseRepl):
def _request_refresh(inner_self):
self.refresh()
self.repl = TestRepl(banner='', config=setup_config())
- # clear history
- self.repl.rl_history = History()
self.repl.height, self.repl.width = (5, 32)
def send_key(self, key):
From ee6afe1728f71e21a7d3c8bf46d72f0320471329 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 01:33:37 +0100
Subject: [PATCH 014/864] entries must always have at least one element
Signed-off-by: Sebastian Ramacher
---
bpython/history.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/history.py b/bpython/history.py
index 4e63bf776..8093aca7a 100644
--- a/bpython/history.py
+++ b/bpython/history.py
@@ -185,7 +185,7 @@ def load_from(self, fd):
entries = []
for line in fd:
self.append_to(entries, line)
- return entries
+ return entries if len(entries) else ['']
def save(self, filename, encoding, lines=0):
fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.TRUNC,
From 27322d88d837c41db5ac443a04722ed928d32cd4 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 21 Dec 2016 01:33:44 +0100
Subject: [PATCH 015/864] Also specify hist_file (really fixes #654)
---
bpython/test/test.config | 1 +
1 file changed, 1 insertion(+)
diff --git a/bpython/test/test.config b/bpython/test/test.config
index 21f55c121..38a233624 100644
--- a/bpython/test/test.config
+++ b/bpython/test/test.config
@@ -1,3 +1,4 @@
[general]
hist_length = 0
+hist_file = /dev/null
paste_time = 0
From 36457741e9d5fcdef518a5fd76a6a691387a5b88 Mon Sep 17 00:00:00 2001
From: Atri Bhattacharya
Date: Sun, 25 Dec 2016 21:54:14 +0530
Subject: [PATCH 016/864] Close node in description correctly.
This trivial markup fix ensures that the
node is closed
in the right place, so that when software centers like
gnome-software show the appdata, the description section does
not get curtailed at the place where the
+
+ In-line syntax highlighting.
+ Readline-like autocomplete with suggestion displayed as you type.
+ Expected parameter list for any Python function.
+ "Rewind" function to pop the last line of code from memory and re-evaluate.
+ Send the code you've entered off to a pastebin.
+ Save the code you've entered to a file.
+ Auto-indentation.
+
http://www.bpython-interpreter.org/
https://github.com/bpython/bpython/issues
From 237a493b2c99cefe6c28ad752cdbe633781a732d Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 28 Dec 2016 15:06:41 +0100
Subject: [PATCH 017/864] Test with Python 3.6
To be replaced with 3.6 once available.
Signed-off-by: Sebastian Ramacher
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 6383194d8..3d761f016 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ python:
- "3.3"
- "3.4"
- "3.5"
+ - "3.6-dev"
- "pypy"
- "pypy3"
From 2480377a5ffcc0aca24c49ccf07ec5c44f26ed16 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 21:10:51 +0100
Subject: [PATCH 018/864] Remove unused member variable
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/interpreter.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 410a9f3fa..d157b71b4 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -79,7 +79,6 @@ def __init__(self, locals=None, encoding=None):
encoding = getpreferredencoding()
ReplInterpreter.__init__(self, locals, encoding)
- self.locals = locals
self.compile = CommandCompiler()
# typically changed after being instantiated
From cb6eb39dbbf53efa14169c3cfca0364fc8c812ed Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 21:12:04 +0100
Subject: [PATCH 019/864] Default locals is set-up in super().__init__
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/interpreter.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index d157b71b4..9da08744d 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -73,8 +73,6 @@ def __init__(self, locals=None, encoding=None):
We include an argument for the outfile to pass to the formatter for it
to write to.
"""
- if locals is None:
- locals = {"__name__": "__console__", "__doc__": None}
if encoding is None:
encoding = getpreferredencoding()
ReplInterpreter.__init__(self, locals, encoding)
From 4a36757b10f7a3b304c37a5eb3b7e50505a7c383 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 21:17:04 +0100
Subject: [PATCH 020/864] Remove code duplication
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/interpreter.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 9da08744d..22da121a1 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -73,8 +73,6 @@ def __init__(self, locals=None, encoding=None):
We include an argument for the outfile to pass to the formatter for it
to write to.
"""
- if encoding is None:
- encoding = getpreferredencoding()
ReplInterpreter.__init__(self, locals, encoding)
self.compile = CommandCompiler()
From 70477ef89e7857c869a374f04642115eceb8fd28 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 21:32:32 +0100
Subject: [PATCH 021/864] Remove more duplicated code
---
bpython/curtsiesfrontend/interpreter.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 22da121a1..223fe9618 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -1,5 +1,4 @@
import sys
-from codeop import CommandCompiler
from six import iteritems, text_type
from pygments.token import Generic, Token, Keyword, Name, Comment, String
@@ -75,8 +74,6 @@ def __init__(self, locals=None, encoding=None):
"""
ReplInterpreter.__init__(self, locals, encoding)
- self.compile = CommandCompiler()
-
# typically changed after being instantiated
# but used when interpreter used corresponding REPL
def write(err_line):
From f189da1789211d267ee8d9ac345dcb3fa90cd338 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 22:00:38 +0100
Subject: [PATCH 022/864] Consolidate common locals setup (fixes #665)
Signed-off-by: Sebastian Ramacher
---
bpython/cli.py | 4 ----
bpython/curtsiesfrontend/interpreter.py | 5 -----
bpython/repl.py | 17 ++++++++++++++++-
bpython/urwid.py | 11 ++++-------
4 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index f4334b702..4c71957bc 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -58,7 +58,6 @@
import unicodedata
import errno
-from types import ModuleType
from six.moves import range
# These are used for syntax highlighting
@@ -1891,9 +1890,6 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
curses.raw(True)
main_win, statusbar = init_wins(scr, config)
- if locals_ is None:
- sys.modules['__main__'] = ModuleType('__main__')
- locals_ = sys.modules['__main__'].__dict__
interpreter = repl.Interpreter(locals_, getpreferredencoding())
clirepl = CLIRepl(main_win, interpreter, statusbar, config, idle)
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 223fe9618..37edf40e7 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -64,11 +64,6 @@ class Interp(ReplInterpreter):
def __init__(self, locals=None, encoding=None):
"""Constructor.
- The optional 'locals' argument specifies the dictionary in
- which code will be executed; it defaults to a newly created
- dictionary with key "__name__" set to "__console__" and key
- "__doc__" set to None.
-
We include an argument for the outfile to pass to the formatter for it
to write to.
"""
diff --git a/bpython/repl.py b/bpython/repl.py
index 03c4debf7..9d73d3847 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -39,6 +39,7 @@
import traceback
from itertools import takewhile
from six import itervalues
+from types import ModuleType
from pygments.token import Token
@@ -77,9 +78,16 @@ def estimate(self):
class Interpreter(code.InteractiveInterpreter):
+ """Source code interpreter for use in bpython."""
def __init__(self, locals=None, encoding=None):
- """The syntaxerror callback can be set at any time and will be called
+ """Constructor.
+
+ The optional 'locals' argument specifies the dictionary in which code
+ will be executed; it defaults to a newly created dictionary with key
+ "__name__" set to "__main__".
+
+ The syntaxerror callback can be set at any time and will be called
on a caught syntax error. The purpose for this in bpython is so that
the repl can be instantiated after the interpreter (which it
necessarily must be with the current factoring) and then an exception
@@ -95,6 +103,13 @@ def __init__(self, locals=None, encoding=None):
self.encoding = encoding or sys.getdefaultencoding()
self.syntaxerror_callback = None
+
+ if locals is None:
+ # instead of messing with sys.modules, we should modify sys.modules
+ # in the interpreter instance
+ sys.modules['__main__'] = main_mod = ModuleType('__main__')
+ locals = main_mod.__dict__
+
# Unfortunately code.InteractiveInterpreter is a classic class, so no
# super()
code.InteractiveInterpreter.__init__(self, locals)
diff --git a/bpython/urwid.py b/bpython/urwid.py
index ceb8717b8..dcea20be0 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -40,7 +40,6 @@
import time
import locale
import signal
-from types import ModuleType
from optparse import Option
from six.moves import range
from six import iteritems, string_types
@@ -1192,11 +1191,7 @@ def main(args=None, locals_=None, banner=None):
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__
-
+ extend_locals = {}
if options.plugin:
try:
from twisted import plugin
@@ -1215,10 +1210,12 @@ def main(args=None, locals_=None, banner=None):
plugopts = plug.options()
plugopts.parseOptions(exec_args)
serv = plug.makeService(plugopts)
- locals_['service'] = serv
+ extend_locals['service'] = serv
reactor.callWhenRunning(serv.startService)
exec_args = []
interpreter = repl.Interpreter(locals_, locale.getpreferredencoding())
+ # TODO: replace with something less hack-ish
+ interpreter.locals.update(extend_locals)
# This nabs sys.stdin/out via urwid.MainLoop
myrepl = URWIDRepl(event_loop, palette, interpreter, config)
From a64fb8ebb9e6c3b572b395fb5b3560abb508ff6f Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 22:38:43 +0100
Subject: [PATCH 023/864] Fix typo
Signed-off-by: Sebastian Ramacher
---
CHANGELOG | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index f7385b257..5d023875e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -418,7 +418,7 @@ A quick bugfix release (this should not become a habit).
A bugfix/feature release (and a start at gtk). Happy Christmas everyone!
* #67: Make pastebin URL really configurable.
-* #68: Set a__main__ module and set interpreter's namespace to that module.
+* #68: Set a __main__ module and set interpreter's namespace to that module.
* #70: Implement backward completion on backward tab.
* #62: Hide matches starting with a _ unless explicitly typed.
* #72: Auto dedentation
From 015356b0e142b1e0a95de35d6f6ceaf8871218ab Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 8 Jan 2017 22:41:55 +0100
Subject: [PATCH 024/864] Update changelog
---
CHANGELOG | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 5d023875e..3833a971c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,10 @@ Changelog
New features:
Fixes:
+* #648: Fix paste helper.
+ Thanks to Jakob Bowyer.
+* #653: Handle docstrings more carefully.
+* #654: Do not modify history file during tests.
0.16
----
From a4aea3d8334c7e77226f5f7faba2d42cd4ce1054 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 9 Jan 2017 00:14:42 +0100
Subject: [PATCH 025/864] Re-use version_banner
---
bpython/args.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/bpython/args.py b/bpython/args.py
index db5569d25..fbba65827 100644
--- a/bpython/args.py
+++ b/bpython/args.py
@@ -89,8 +89,7 @@ def parse(args, extras=None, ignore_stdin=False):
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(version_banner())
print('(C) 2008-2016 Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. '
'See AUTHORS for detail.')
raise SystemExit
From 508082a8f607b4454625ebf662e6ff47795ced93 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 9 Jan 2017 00:16:18 +0100
Subject: [PATCH 026/864] Import consistency
---
bpython/config.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/bpython/config.py b/bpython/config.py
index bd78c399b..3d02b236a 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -10,8 +10,7 @@
from six.moves.configparser import ConfigParser
from bpython.keys import cli_key_dispatch as key_dispatch
-from bpython.autocomplete import SIMPLE as default_completion
-import bpython.autocomplete
+from bpython.autocomplete import SIMPLE as default_completion, ALL_MODES
class Struct(object):
@@ -273,7 +272,7 @@ def get_key_no_doublebind(command):
struct.hist_file = os.path.expanduser(struct.hist_file)
# verify completion mode
- if struct.autocomplete_mode not in bpython.autocomplete.ALL_MODES:
+ if struct.autocomplete_mode not in ALL_MODES:
struct.autocomplete_mode = default_completion
# set box drawing characters
From 4029ab26ebf9a70612f20eefce9e8d7edfe2156a Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 9 Jan 2017 00:40:16 +0100
Subject: [PATCH 027/864] Use consistent encoding
Signed-off-by: Sebastian Ramacher
---
bpdb/__init__.py | 2 ++
bpdb/__main__.py | 2 ++
bpdb/debugger.py | 2 ++
bpython/_internal.py | 2 ++
bpython/args.py | 2 ++
bpython/clipboard.py | 2 ++
bpython/curtsies.py | 2 ++
bpython/curtsiesfrontend/_internal.py | 2 ++
bpython/curtsiesfrontend/coderunner.py | 2 ++
bpython/curtsiesfrontend/events.py | 2 ++
bpython/curtsiesfrontend/filewatch.py | 2 ++
bpython/curtsiesfrontend/interaction.py | 2 ++
bpython/curtsiesfrontend/interpreter.py | 2 ++
bpython/curtsiesfrontend/manual_readline.py | 2 ++
bpython/curtsiesfrontend/preprocess.py | 2 ++
bpython/curtsiesfrontend/sitefix.py | 2 ++
bpython/formatter.py | 2 ++
bpython/importcompletion.py | 2 ++
bpython/keys.py | 2 ++
bpython/lazyre.py | 2 ++
bpython/line.py | 2 ++
bpython/pager.py | 2 ++
bpython/patch_linecache.py | 2 ++
bpython/test/test_bpython.py | 0
bpython/test/test_config.py | 2 ++
bpython/test/test_crashers.py | 2 ++
bpython/test/test_curtsies_coderunner.py | 2 ++
bpython/test/test_curtsies_painting.py | 1 +
bpython/test/test_curtsies_parser.py | 2 ++
bpython/test/test_filewatch.py | 2 ++
bpython/test/test_history.py | 2 ++
bpython/test/test_importcompletion.py | 2 ++
bpython/test/test_keys.py | 2 ++
bpython/test/test_line_properties.py | 2 ++
bpython/test/test_manual_readline.py | 2 ++
bpython/test/test_pager.py | 0
bpython/test/test_preprocess.py | 2 ++
bpython/test/test_repl.py | 2 ++
bpython/urwid.py | 1 +
39 files changed, 72 insertions(+)
delete mode 100644 bpython/test/test_bpython.py
delete mode 100644 bpython/test/test_pager.py
diff --git a/bpdb/__init__.py b/bpdb/__init__.py
index 9f1c57d06..db2daba21 100644
--- a/bpdb/__init__.py
+++ b/bpdb/__init__.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2008 Bob Farrell
diff --git a/bpdb/__main__.py b/bpdb/__main__.py
index b85accb45..c339c9c36 100644
--- a/bpdb/__main__.py
+++ b/bpdb/__main__.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2013 Sebastian Ramacher
diff --git a/bpdb/debugger.py b/bpdb/debugger.py
index 373389146..73e1c560b 100644
--- a/bpdb/debugger.py
+++ b/bpdb/debugger.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2008 Bob Farrell
diff --git a/bpython/_internal.py b/bpython/_internal.py
index 225133ead..ea8fb9b33 100644
--- a/bpython/_internal.py
+++ b/bpython/_internal.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import pydoc
import sys
diff --git a/bpython/args.py b/bpython/args.py
index fbba65827..857c42618 100644
--- a/bpython/args.py
+++ b/bpython/args.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""
Module to handle command line argument parsing, for all front-ends.
"""
diff --git a/bpython/clipboard.py b/bpython/clipboard.py
index 252f1a225..5e426e381 100644
--- a/bpython/clipboard.py
+++ b/bpython/clipboard.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2015 Sebastian Ramacher
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 9f7f6d57d..ef38005f0 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from __future__ import absolute_import
import collections
diff --git a/bpython/curtsiesfrontend/_internal.py b/bpython/curtsiesfrontend/_internal.py
index 187427824..7d458e646 100644
--- a/bpython/curtsiesfrontend/_internal.py
+++ b/bpython/curtsiesfrontend/_internal.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2015 the bpython authors.
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index fc1e9dac6..7255a99cd 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""For running Python code that could interrupt itself at any time in order to,
for example, ask for a read on stdin, or a write on stdout
diff --git a/bpython/curtsiesfrontend/events.py b/bpython/curtsiesfrontend/events.py
index 982c96655..065a8dc41 100644
--- a/bpython/curtsiesfrontend/events.py
+++ b/bpython/curtsiesfrontend/events.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""Non-keyboard events used in bpython curtsies REPL"""
import time
diff --git a/bpython/curtsiesfrontend/filewatch.py b/bpython/curtsiesfrontend/filewatch.py
index 301de9ac0..576852c03 100644
--- a/bpython/curtsiesfrontend/filewatch.py
+++ b/bpython/curtsiesfrontend/filewatch.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import os
from collections import defaultdict
diff --git a/bpython/curtsiesfrontend/interaction.py b/bpython/curtsiesfrontend/interaction.py
index 94ce6a3cf..5505e367f 100644
--- a/bpython/curtsiesfrontend/interaction.py
+++ b/bpython/curtsiesfrontend/interaction.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from __future__ import unicode_literals
import greenlet
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 37edf40e7..e1a484802 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import sys
from six import iteritems, text_type
diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py
index 3849a95b8..953471e22 100644
--- a/bpython/curtsiesfrontend/manual_readline.py
+++ b/bpython/curtsiesfrontend/manual_readline.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""implementations of simple readline edit operations
just the ones that fit the model of transforming the current line
diff --git a/bpython/curtsiesfrontend/preprocess.py b/bpython/curtsiesfrontend/preprocess.py
index 473a0c346..279d25d9e 100644
--- a/bpython/curtsiesfrontend/preprocess.py
+++ b/bpython/curtsiesfrontend/preprocess.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""Tools for preparing code to be run in the REPL (removing blank lines,
etc)"""
diff --git a/bpython/curtsiesfrontend/sitefix.py b/bpython/curtsiesfrontend/sitefix.py
index a8cf8a38b..fa3016617 100644
--- a/bpython/curtsiesfrontend/sitefix.py
+++ b/bpython/curtsiesfrontend/sitefix.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import sys
from six.moves import builtins
diff --git a/bpython/formatter.py b/bpython/formatter.py
index 96ee6ed28..12885087a 100644
--- a/bpython/formatter.py
+++ b/bpython/formatter.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2008 Bob Farrell
diff --git a/bpython/importcompletion.py b/bpython/importcompletion.py
index b23994908..4a283c527 100644
--- a/bpython/importcompletion.py
+++ b/bpython/importcompletion.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2009-2011 Andreas Stuehrk
diff --git a/bpython/keys.py b/bpython/keys.py
index 619116a19..f8119b931 100644
--- a/bpython/keys.py
+++ b/bpython/keys.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2008 Simon de Vlieger
diff --git a/bpython/lazyre.py b/bpython/lazyre.py
index 54e8d565b..2729c8eb3 100644
--- a/bpython/lazyre.py
+++ b/bpython/lazyre.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2015 Sebastian Ramacher
diff --git a/bpython/line.py b/bpython/line.py
index fecdfcec5..078059a4f 100644
--- a/bpython/line.py
+++ b/bpython/line.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
"""Extracting and changing portions of the current line
All functions take cursor offset from the beginning of the line and the line of
diff --git a/bpython/pager.py b/bpython/pager.py
index 70448672f..cf8944205 100644
--- a/bpython/pager.py
+++ b/bpython/pager.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
# The MIT License
#
# Copyright (c) 2009-2011 Andreas Stuehrk
diff --git a/bpython/patch_linecache.py b/bpython/patch_linecache.py
index 7dc321e7a..c335f05a4 100644
--- a/bpython/patch_linecache.py
+++ b/bpython/patch_linecache.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import linecache
diff --git a/bpython/test/test_bpython.py b/bpython/test/test_bpython.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/bpython/test/test_config.py b/bpython/test/test_config.py
index 6b8c5dea4..fc5b841ed 100644
--- a/bpython/test/test_config.py
+++ b/bpython/test/test_config.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import os
import tempfile
import textwrap
diff --git a/bpython/test/test_crashers.py b/bpython/test/test_crashers.py
index 341f6b45f..2e1ff4fda 100644
--- a/bpython/test/test_crashers.py
+++ b/bpython/test/test_crashers.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import fcntl
import os
import pty
diff --git a/bpython/test/test_curtsies_coderunner.py b/bpython/test/test_curtsies_coderunner.py
index 80af72760..b58806509 100644
--- a/bpython/test/test_curtsies_coderunner.py
+++ b/bpython/test/test_curtsies_coderunner.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import sys
from bpython.test import mock, unittest
diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py
index 3f7414b9e..422d14cce 100644
--- a/bpython/test/test_curtsies_painting.py
+++ b/bpython/test/test_curtsies_painting.py
@@ -1,4 +1,5 @@
# coding: utf8
+
from __future__ import unicode_literals
import itertools
import os
diff --git a/bpython/test/test_curtsies_parser.py b/bpython/test/test_curtsies_parser.py
index 0d765bab2..58d3b5424 100644
--- a/bpython/test/test_curtsies_parser.py
+++ b/bpython/test/test_curtsies_parser.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from __future__ import unicode_literals
from bpython.test import unittest
diff --git a/bpython/test/test_filewatch.py b/bpython/test/test_filewatch.py
index 061e18b2b..9fe56b02d 100644
--- a/bpython/test/test_filewatch.py
+++ b/bpython/test/test_filewatch.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import os
try:
diff --git a/bpython/test/test_history.py b/bpython/test/test_history.py
index abbe99d1f..49450e1b2 100644
--- a/bpython/test/test_history.py
+++ b/bpython/test/test_history.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from six.moves import range
from bpython.history import History
diff --git a/bpython/test/test_importcompletion.py b/bpython/test/test_importcompletion.py
index 4df736b54..4b0c0fca3 100644
--- a/bpython/test/test_importcompletion.py
+++ b/bpython/test/test_importcompletion.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from __future__ import unicode_literals
from bpython import importcompletion
diff --git a/bpython/test/test_keys.py b/bpython/test/test_keys.py
index bf15542dd..1e19f8e5f 100644
--- a/bpython/test/test_keys.py
+++ b/bpython/test/test_keys.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from bpython import keys
from bpython.test import unittest
diff --git a/bpython/test/test_line_properties.py b/bpython/test/test_line_properties.py
index 4638084c2..cffd57241 100644
--- a/bpython/test/test_line_properties.py
+++ b/bpython/test/test_line_properties.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import re
from bpython.test import unittest
diff --git a/bpython/test/test_manual_readline.py b/bpython/test/test_manual_readline.py
index 8b87be651..4141292d2 100644
--- a/bpython/test/test_manual_readline.py
+++ b/bpython/test/test_manual_readline.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from bpython.curtsiesfrontend.manual_readline import \
left_arrow, right_arrow, beginning_of_line, forward_word, back_word, \
end_of_line, delete, last_word_pos, backspace, delete_from_cursor_back, \
diff --git a/bpython/test/test_pager.py b/bpython/test/test_pager.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/bpython/test/test_preprocess.py b/bpython/test/test_preprocess.py
index f94366565..0ef21f098 100644
--- a/bpython/test/test_preprocess.py
+++ b/bpython/test/test_preprocess.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from code import compile_command as compiler
from functools import partial
import difflib
diff --git a/bpython/test/test_repl.py b/bpython/test/test_repl.py
index 34d7f774a..67a7d37a2 100644
--- a/bpython/test/test_repl.py
+++ b/bpython/test/test_repl.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
from itertools import islice
from six.moves import range
import collections
diff --git a/bpython/urwid.py b/bpython/urwid.py
index dcea20be0..7695c95e0 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -1,3 +1,4 @@
+# encoding: utf-8
#
# The MIT License
From 5bd6bd070a5152bf1aba8eb5bfc541b4ec946589 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 21:55:23 +0100
Subject: [PATCH 028/864] Define encoding
---
bpython/translations/__init__.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/bpython/translations/__init__.py b/bpython/translations/__init__.py
index 26c504075..84d75d808 100644
--- a/bpython/translations/__init__.py
+++ b/bpython/translations/__init__.py
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
import gettext
import locale
import os.path
From af6bcae6c8bb5ab05a3e3634b6b815cdd1d41273 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 22:03:38 +0100
Subject: [PATCH 029/864] Change to [] for consistency
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 44495534c..6c6612bbc 100755
--- a/setup.py
+++ b/setup.py
@@ -255,7 +255,7 @@ def initialize_options(self):
tests_require.append('mock')
# translations
-mo_files = list()
+mo_files = []
for language in os.listdir(translations_dir):
mo_subpath = os.path.join(language, 'LC_MESSAGES', 'bpython.mo')
if os.path.exists(os.path.join(translations_dir, mo_subpath)):
From 69c41088558ef2b5f6bc682c44d3f550765f915b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 22:05:37 +0100
Subject: [PATCH 030/864] Only check for 2.x since we only support >= 3.3 for
3.x
---
setup.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/setup.py b/setup.py
index 6c6612bbc..5505f5ddd 100755
--- a/setup.py
+++ b/setup.py
@@ -250,8 +250,7 @@ def initialize_options(self):
}
tests_require = []
-if (sys.version_info[0] == 2 or
- (sys.version_info[0] == 3 and sys.version_info[0] < 3)):
+if sys.version_info[0] == 2:
tests_require.append('mock')
# translations
From e8ed9dbd6200a990f07b69ef296c6aa7ce71f9e9 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 22:20:23 +0100
Subject: [PATCH 031/864] Update requirements
---
requirements.txt | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index 7fd8f8ae4..78619ff24 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
Pygments
-curtsies >=0.1.15, <0.2.0
+curtsies >=0.1.18
greenlet
-setuptools
requests
+setuptools
+six >=1.5
From 8543e3c0e053c57e008143089dce7e4d84a5a90e Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 22:20:31 +0100
Subject: [PATCH 032/864] Avoid duplication
---
.travis.install.sh | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/.travis.install.sh b/.travis.install.sh
index 8522aa261..dc568c48b 100755
--- a/.travis.install.sh
+++ b/.travis.install.sh
@@ -6,11 +6,7 @@ pip install setuptools
if [[ $RUN == nosetests ]]; then
# core dependencies
- pip install pygments
- pip install requests
- pip install 'curtsies >=0.1.17'
- pip install greenlet
- pip install 'six >=1.5'
+ pop install -r requirements.txt
# filewatch specific dependencies
pip install watchdog
# jedi specific dependencies
From 7c8cef6fa6c2c66e37f497fdcccbf918a046b8c4 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 10 Jan 2017 22:21:23 +0100
Subject: [PATCH 033/864] Fix typo
---
.travis.install.sh | 2 +-
bpython/__init__.py | 6 ++++--
bpython/_py3compat.py | 2 ++
bpython/args.py | 9 +++++----
bpython/autocomplete.py | 18 +++++++++---------
bpython/cli.py | 26 +++++++++++++-------------
bpython/clipboard.py | 2 ++
bpython/config.py | 6 +++---
bpython/curtsies.py | 20 ++++++++++----------
bpython/filelock.py | 1 +
bpython/formatter.py | 2 ++
bpython/history.py | 6 +++---
bpython/importcompletion.py | 8 +++++---
bpython/inspection.py | 7 ++++---
bpython/keys.py | 3 ++-
bpython/lazyre.py | 2 ++
bpython/line.py | 4 ++--
bpython/pager.py | 1 +
bpython/paste.py | 4 +++-
bpython/patch_linecache.py | 2 ++
bpython/repl.py | 26 ++++++++++++++------------
bpython/simpleeval.py | 8 +++++---
bpython/simplerepl.py | 8 ++++----
bpython/translations/__init__.py | 6 ++++--
bpython/urwid.py | 17 +++++++----------
25 files changed, 110 insertions(+), 86 deletions(-)
diff --git a/.travis.install.sh b/.travis.install.sh
index dc568c48b..deaf5714a 100755
--- a/.travis.install.sh
+++ b/.travis.install.sh
@@ -6,7 +6,7 @@ pip install setuptools
if [[ $RUN == nosetests ]]; then
# core dependencies
- pop install -r requirements.txt
+ pip install -r requirements.txt
# filewatch specific dependencies
pip install watchdog
# jedi specific dependencies
diff --git a/bpython/__init__.py b/bpython/__init__.py
index 0fd94818f..a4f3bcc37 100644
--- a/bpython/__init__.py
+++ b/bpython/__init__.py
@@ -20,10 +20,12 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import os.path
try:
- from bpython._version import __version__ as version
+ from ._version import __version__ as version
except ImportError:
version = 'unknown'
@@ -32,5 +34,5 @@
def embed(locals_=None, args=['-i', '-q'], banner=None):
- from bpython.curtsies import main
+ from .curtsies import main
return main(args, locals_, banner)
diff --git a/bpython/_py3compat.py b/bpython/_py3compat.py
index 8082b8367..41acc5ce1 100644
--- a/bpython/_py3compat.py
+++ b/bpython/_py3compat.py
@@ -34,6 +34,8 @@
- py3: True if the hosting Python runtime is of Python version 3 or later
"""
+from __future__ import absolute_import
+
import sys
py3 = (sys.version_info[0] == 3)
diff --git a/bpython/args.py b/bpython/args.py
index 857c42618..1dfe010df 100644
--- a/bpython/args.py
+++ b/bpython/args.py
@@ -4,16 +4,17 @@
Module to handle command line argument parsing, for all front-ends.
"""
-from __future__ import print_function
+from __future__ import print_function, absolute_import
+
import code
import imp
import os
import sys
from optparse import OptionParser, OptionGroup
-from bpython import __version__
-from bpython.config import default_config_path, loadini, Struct
-from bpython.translations import _
+from . import __version__
+from .config import default_config_path, loadini, Struct
+from .translations import _
class OptionParserFailed(ValueError):
diff --git a/bpython/autocomplete.py b/bpython/autocomplete.py
index fd4c2facb..d2ea220f1 100644
--- a/bpython/autocomplete.py
+++ b/bpython/autocomplete.py
@@ -23,7 +23,7 @@
# THE SOFTWARE.
#
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
import __main__
import abc
@@ -37,14 +37,14 @@
from six.moves import range, builtins
from six import string_types, iteritems
-from bpython import inspection
-from bpython import importcompletion
-from bpython import line as lineparts
-from bpython.line import LinePart
-from bpython._py3compat import py3, try_decode
-from bpython.lazyre import LazyReCompile
-from bpython.simpleeval import (safe_eval, evaluate_current_expression,
- EvaluationError)
+from . import inspection
+from . import importcompletion
+from . import line as lineparts
+from .line import LinePart
+from ._py3compat import py3, try_decode
+from .lazyre import LazyReCompile
+from .simpleeval import (safe_eval, evaluate_current_expression,
+ EvaluationError)
if not py3:
from types import InstanceType, ClassType
diff --git a/bpython/cli.py b/bpython/cli.py
index 4c71957bc..c7a540283 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -39,7 +39,7 @@
# - Instead the suspend key exits the program
# - View source doesn't work on windows unless you install the less program (From GnuUtils or Cygwin)
-from __future__ import division
+from __future__ import division, absolute_import
import platform
import os
@@ -63,27 +63,27 @@
# These are used for syntax highlighting
from pygments import format
from pygments.formatters import TerminalFormatter
-from bpython._py3compat import PythonLexer
+from ._py3compat import PythonLexer
from pygments.token import Token
-from bpython.formatter import BPythonFormatter
+from .formatter import BPythonFormatter
# This for completion
-from bpython import importcompletion
+from . import importcompletion
# This for config
-from bpython.config import Struct, getpreferredencoding
+from .config import Struct, getpreferredencoding
# This for keys
-from bpython.keys import cli_key_dispatch as key_dispatch
+from .keys import cli_key_dispatch as key_dispatch
# This for i18n
-from bpython import translations
-from bpython.translations import _
+from . import translations
+from .translations import _
-from bpython import repl
-from bpython._py3compat import py3
-from bpython.pager import page
-import bpython.args
+from . import repl
+from ._py3compat import py3
+from .pager import page
+from .args import parse as argsparse
if not py3:
import inspect
@@ -1946,7 +1946,7 @@ def main(args=None, locals_=None, banner=None):
translations.init()
- config, options, exec_args = bpython.args.parse(args)
+ config, options, exec_args = argsparse(args)
# Save stdin, stdout and stderr for later restoration
orig_stdin = sys.stdin
diff --git a/bpython/clipboard.py b/bpython/clipboard.py
index 5e426e381..89a419f32 100644
--- a/bpython/clipboard.py
+++ b/bpython/clipboard.py
@@ -22,6 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import subprocess
import os
import platform
diff --git a/bpython/config.py b/bpython/config.py
index 3d02b236a..a45afba7b 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -1,6 +1,6 @@
# encoding: utf-8
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
import os
import sys
@@ -9,8 +9,8 @@
from six import iterkeys, iteritems
from six.moves.configparser import ConfigParser
-from bpython.keys import cli_key_dispatch as key_dispatch
-from bpython.autocomplete import SIMPLE as default_completion, ALL_MODES
+from .autocomplete import SIMPLE as default_completion, ALL_MODES
+from .keys import cli_key_dispatch as cli_key_dispatch
class Struct(object):
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index ef38005f0..f4520ecfa 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -13,16 +13,16 @@
import curtsies.input
import curtsies.events
-from bpython.curtsiesfrontend.repl import BaseRepl
-from bpython.curtsiesfrontend.coderunner import SystemExitFromCodeRunner
-from bpython.curtsiesfrontend.interpreter import Interp
-from bpython import args as bpargs
-from bpython import translations
-from bpython.translations import _
-from bpython.importcompletion import find_iterator
-from bpython.curtsiesfrontend import events as bpythonevents
-from bpython import inspection
-from bpython.repl import extract_exit_value
+from .curtsiesfrontend.repl import BaseRepl
+from .curtsiesfrontend.coderunner import SystemExitFromCodeRunner
+from .curtsiesfrontend.interpreter import Interp
+from . import args as bpargs
+from . import translations
+from .translations import _
+from .importcompletion import find_iterator
+from .curtsiesfrontend import events as bpythonevents
+from . import inspection
+from .repl import extract_exit_value
logger = logging.getLogger(__name__)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 724cb4498..9ce5ee153 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -22,6 +22,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
try:
import fcntl
diff --git a/bpython/formatter.py b/bpython/formatter.py
index 12885087a..4d916c626 100644
--- a/bpython/formatter.py
+++ b/bpython/formatter.py
@@ -26,6 +26,8 @@
# Pygments really kicks ass, it made it really easy to
# get the exact behaviour I wanted, thanks Pygments.:)
+from __future__ import absolute_import
+
from pygments.formatter import Formatter
from pygments.token import Keyword, Name, Comment, String, Error, \
Number, Operator, Token, Whitespace, Literal, Punctuation
diff --git a/bpython/history.py b/bpython/history.py
index 8093aca7a..bd9301b03 100644
--- a/bpython/history.py
+++ b/bpython/history.py
@@ -23,15 +23,15 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
import io
import os
import stat
from itertools import islice
from six.moves import range
-from bpython.translations import _
-from bpython.filelock import FileLock
+from .translations import _
+from .filelock import FileLock
class History(object):
diff --git a/bpython/importcompletion.py b/bpython/importcompletion.py
index 4a283c527..5d5977b55 100644
--- a/bpython/importcompletion.py
+++ b/bpython/importcompletion.py
@@ -22,9 +22,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-from bpython._py3compat import py3, try_decode
-from bpython.line import current_word, current_import, \
- current_from_import_from, current_from_import_import
+from __future__ import absolute_import
+
+from ._py3compat import py3, try_decode
+from .line import (current_word, current_import, current_from_import_from,
+ current_from_import_import)
import imp
import os
diff --git a/bpython/inspection.py b/bpython/inspection.py
index 8ebb9496c..10b7db761 100644
--- a/bpython/inspection.py
+++ b/bpython/inspection.py
@@ -22,7 +22,8 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-#
+
+from __future__ import absolute_import
import inspect
import io
@@ -33,8 +34,8 @@
from pygments.token import Token
-from bpython._py3compat import PythonLexer, py3
-from bpython.lazyre import LazyReCompile
+from ._py3compat import PythonLexer, py3
+from .lazyre import LazyReCompile
if not py3:
import types
diff --git a/bpython/keys.py b/bpython/keys.py
index f8119b931..00c25b792 100644
--- a/bpython/keys.py
+++ b/bpython/keys.py
@@ -21,7 +21,8 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-#
+
+from __future__ import absolute_import
import string
from six.moves import range
diff --git a/bpython/lazyre.py b/bpython/lazyre.py
index 2729c8eb3..fa1cbd6ef 100644
--- a/bpython/lazyre.py
+++ b/bpython/lazyre.py
@@ -22,6 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import re
diff --git a/bpython/line.py b/bpython/line.py
index 078059a4f..3a6806647 100644
--- a/bpython/line.py
+++ b/bpython/line.py
@@ -5,12 +5,12 @@
All functions take cursor offset from the beginning of the line and the line of
Python code, and return None, or a tuple of the start index, end index, and the
word."""
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
from itertools import chain
from collections import namedtuple
-from bpython.lazyre import LazyReCompile
+from .lazyre import LazyReCompile
LinePart = namedtuple('LinePart', ['start', 'stop', 'word'])
diff --git a/bpython/pager.py b/bpython/pager.py
index cf8944205..13e904a6b 100644
--- a/bpython/pager.py
+++ b/bpython/pager.py
@@ -22,6 +22,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
import curses
import errno
diff --git a/bpython/paste.py b/bpython/paste.py
index 035812dcd..b76ab35c1 100644
--- a/bpython/paste.py
+++ b/bpython/paste.py
@@ -22,6 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
from locale import getpreferredencoding
from six.moves.urllib_parse import quote as urlquote, urljoin, urlparse
from string import Template
@@ -30,7 +32,7 @@
import subprocess
import unicodedata
-from bpython.translations import _
+from .translations import _
class PasteFailed(Exception):
diff --git a/bpython/patch_linecache.py b/bpython/patch_linecache.py
index c335f05a4..2b473bca2 100644
--- a/bpython/patch_linecache.py
+++ b/bpython/patch_linecache.py
@@ -1,5 +1,7 @@
# encoding: utf-8
+from __future__ import absolute_import
+
import linecache
diff --git a/bpython/repl.py b/bpython/repl.py
index 9d73d3847..02e91404f 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -23,6 +23,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import code
import inspect
import io
@@ -43,17 +45,17 @@
from pygments.token import Token
-from bpython import autocomplete
-from bpython import inspection
-from bpython._py3compat import PythonLexer, py3, prepare_for_exec
-from bpython.clipboard import get_clipboard, CopyFailed
-from bpython.config import getpreferredencoding
-from bpython.formatter import Parenthesis
-from bpython.history import History
-from bpython.paste import PasteHelper, PastePinnwand, PasteFailed
-from bpython.patch_linecache import filename_for_console_input
-from bpython.translations import _, ngettext
-from bpython import simpleeval
+from . import autocomplete
+from . import inspection
+from ._py3compat import PythonLexer, py3, prepare_for_exec
+from .clipboard import get_clipboard, CopyFailed
+from .config import getpreferredencoding
+from .formatter import Parenthesis
+from .history import History
+from .paste import PasteHelper, PastePinnwand, PasteFailed
+from .patch_linecache import filename_for_console_input
+from .translations import _, ngettext
+from . import simpleeval
class RuntimeTimer(object):
@@ -101,7 +103,7 @@ def __init__(self, locals=None, encoding=None):
into a bytestring source as part of an encoding comment.
"""
- self.encoding = encoding or sys.getdefaultencoding()
+ self.encoding = encoding or getpreferredencoding()
self.syntaxerror_callback = None
if locals is None:
diff --git a/bpython/simpleeval.py b/bpython/simpleeval.py
index b7b348187..b4934fb66 100644
--- a/bpython/simpleeval.py
+++ b/bpython/simpleeval.py
@@ -28,6 +28,8 @@
"""
+from __future__ import absolute_import
+
import ast
import inspect
from six import string_types
@@ -35,9 +37,9 @@
import sys
import types
-from bpython import line as line_properties
-from bpython._py3compat import py3
-from bpython.inspection import is_new_style, AttrCleaner
+from . import line as line_properties
+from ._py3compat import py3
+from .inspection import is_new_style, AttrCleaner
_string_type_nodes = (ast.Str, ast.Bytes) if py3 else (ast.Str,)
_numeric_types = (int, float, complex) + (() if py3 else (long,))
diff --git a/bpython/simplerepl.py b/bpython/simplerepl.py
index 4038cefdf..1355f270a 100644
--- a/bpython/simplerepl.py
+++ b/bpython/simplerepl.py
@@ -30,10 +30,10 @@
import time
import logging
-from bpython.curtsiesfrontend.repl import BaseRepl
-from bpython.curtsiesfrontend import events as bpythonevents
-from bpython import translations
-from bpython import importcompletion
+from .curtsiesfrontend.repl import BaseRepl
+from .curtsiesfrontend import events as bpythonevents
+from . import translations
+from . import importcompletion
from curtsies.configfile_keynames import keymap as key_dispatch
diff --git a/bpython/translations/__init__.py b/bpython/translations/__init__.py
index 84d75d808..4b3b2f956 100644
--- a/bpython/translations/__init__.py
+++ b/bpython/translations/__init__.py
@@ -1,12 +1,14 @@
# encoding: utf-8
+from __future__ import absolute_import
+
import gettext
import locale
import os.path
import sys
-from bpython import package_dir
-from bpython._py3compat import py3
+from .. import package_dir
+from .._py3compat import py3
translator = None
diff --git a/bpython/urwid.py b/bpython/urwid.py
index 7695c95e0..a23b7e406 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -47,13 +47,14 @@
from pygments.token import Token
-from bpython import args as bpargs, repl, translations
-from bpython._py3compat import py3
-from bpython.formatter import theme_map
-from bpython.importcompletion import find_coroutine
-from bpython.translations import _
+from . import args as bpargs, repl, translations
+from ._py3compat import py3
+from .config import getpreferredencoding
+from .formatter import theme_map
+from .importcompletion import find_coroutine
+from .translations import _
-from bpython.keys import urwid_key_dispatch as key_dispatch
+from .keys import urwid_key_dispatch as key_dispatch
import urwid
@@ -83,10 +84,6 @@
}
-def getpreferredencoding():
- return locale.getpreferredencoding() or "ascii"
-
-
try:
from twisted.internet import protocol
from twisted.protocols import basic
From 4c08efefea813aa58c1f1153de344d3f82bca396 Mon Sep 17 00:00:00 2001
From: shanahanjrs
Date: Sun, 11 Dec 2016 23:00:37 -0500
Subject: [PATCH 034/864] Modified repl.py to conform to follow more PEP
standards including 8 and 263
[Sebastian Ramacher]: Squashed 204bc17bc2005a0e3d040e5328601e36d7500508
and 9a0aedaed7ec89730714d495fd4b9806804ac242 and rebased on current
master.
---
bpython/repl.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index 02e91404f..61e214fcd 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -59,6 +59,7 @@
class RuntimeTimer(object):
+ """Calculate running time"""
def __init__(self):
self.reset_timer()
self.time = time.monotonic if hasattr(time, 'monotonic') else time.time
@@ -224,7 +225,7 @@ def showtraceback(self):
tblist[i] = (fname, lineno, module, something)
# Set the right lineno (encoding header adds an extra line)
if fname == ' ' and not py3:
- tblist[i] = (fname, lineno - 2, module, something)
+ tblist[i] = (fname, lineno - 2, module, something)
l = traceback.format_list(tblist)
if l:
@@ -787,13 +788,13 @@ def line_is_empty(line):
indentation = 0
return indentation
- def formatforfile(self, s):
+ def formatforfile(self, session_ouput):
"""Format the stdout buffer to something suitable for writing to disk,
i.e. without >>> and ... at input lines and with "# OUT: " prepended to
output lines."""
def process():
- for line in s.split('\n'):
+ for line in session_ouput.split('\n'):
if line.startswith(self.ps1):
yield line[len(self.ps1):]
elif line.startswith(self.ps2):
@@ -834,11 +835,11 @@ def write2file(self):
self.interact.notify(_('Save cancelled.'))
return
- s = self.formatforfile(self.getstdout())
+ session_test = self.formatforfile(self.getstdout())
try:
with open(fn, mode) as f:
- f.write(s)
+ f.write(stdout_text)
except IOError as e:
self.interact.notify(_("Error writing file '%s': %s") % (fn, e))
else:
@@ -876,8 +877,8 @@ def do_pastebin(self, s):
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)
+ (self.prev_pastebin_url,
+ self.prev_removal_url), 10)
return self.prev_pastebin_url
self.interact.notify(_('Posting data to pastebin...'))
@@ -1088,7 +1089,7 @@ def clear_current_line(self):
"""This is used as the exception callback for the Interpreter instance.
It prevents autoindentation from occurring after a traceback."""
- def send_to_external_editor(self, text, filename=None):
+ def send_to_external_editor(self, text):
"""Returns modified text from an editor, or the original text if editor
exited with non-zero"""
@@ -1117,7 +1118,7 @@ def open_in_external_editor(self, filename):
return subprocess.call(args) == 0
def edit_config(self):
- if not (os.path.isfile(self.config.config_path)):
+ 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:
@@ -1125,7 +1126,6 @@ def edit_config(self):
'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):
@@ -1159,10 +1159,10 @@ def next_indentation(line, tab_length):
return indentation
-def next_token_inside_string(s, inside_string):
+def next_token_inside_string(code_string, inside_string):
"""Given a code string s and an initial state inside_string, return
whether the next token will be inside a string or not."""
- for token, value in PythonLexer().get_tokens(s):
+ for token, value in PythonLexer().get_tokens(code_string):
if token is Token.String:
value = value.lstrip('bBrRuU')
if value in ['"""', "'''", '"', "'"]:
From fb47353bd6f11fbb4f001a726296a87a3c905b3b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 26 Jan 2017 20:04:29 +0100
Subject: [PATCH 035/864] Update to 3.6
Signed-off-by: Sebastian Ramacher
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 3d761f016..a81e507eb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ python:
- "3.3"
- "3.4"
- "3.5"
- - "3.6-dev"
+ - "3.6"
- "pypy"
- "pypy3"
From 8ac18df3a82ff7f1b28fce7340a3948c8c928559 Mon Sep 17 00:00:00 2001
From: Thomas Ballinger
Date: Thu, 30 Mar 2017 00:29:04 -0700
Subject: [PATCH 036/864] fix default values of keyword only arguments
---
bpython/urwid.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/urwid.py b/bpython/urwid.py
index a23b7e406..c81843d9f 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -808,7 +808,7 @@ def _populate_completion(self):
(color, arg)])
if arg in kwonly_defaults:
markup.extend([('punctuation', '='),
- ('token', kwonly_defaults[arg])])
+ ('token', repr(kwonly_defaults[arg]))])
if varkw:
if args or varargs or kwonly:
From da6150b911f9e7caad0b25188b002e1c6d4045e0 Mon Sep 17 00:00:00 2001
From: periklis
Date: Sat, 10 Dec 2016 17:51:26 +0200
Subject: [PATCH 037/864] Initial changes to implement ctrl+o functionality
---
bpython/curtsiesfrontend/repl.py | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index c45f0f2b7..3935741e1 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -483,13 +483,13 @@ def request_undo(self, n=1):
"""Like request_refresh, but for undo request events."""
raise NotImplementedError
- def on_suspend():
+ def on_suspend(self):
"""Will be called on sigtstp.
Do whatever cleanup would allow the user to use other programs."""
raise NotImplementedError
- def after_suspend():
+ def after_suspend(self):
"""Will be called when process foregrounded after suspend.
See to it that process_event is called with None to trigger a refresh
@@ -675,6 +675,8 @@ def process_key_event(self, e):
self.down_one_line()
elif e in ("",):
self.on_control_d()
+ elif e in ("",):
+ self.on_control_o()
elif e in ("",):
self.get_last_word()
elif e in key_dispatch[self.config.reverse_incremental_search_key]:
@@ -844,6 +846,13 @@ def on_control_d(self):
self.current_line = (self.current_line[:self.cursor_offset] +
self.current_line[(self.cursor_offset + 1):])
+ def on_control_o(self):
+ next_idx = -self.rl_history.index + 1
+ next = self.rl_history.entries[next_idx]
+ self.on_enter()
+ print("Next is : " + next)
+ self._set_current_line(next)
+
def cut_to_buffer(self):
self.cut_buffer = self.current_line[self.cursor_offset:]
self.current_line = self.current_line[:self.cursor_offset]
@@ -958,11 +967,15 @@ def toggle_file_watch(self):
# Handler Helpers
def add_normal_character(self, char):
+ print("Char is :" + str(char))
if len(char) > 1 or is_nop(char):
return
if self.incr_search_mode:
+ print("Incr search mode")
self.add_to_incremental_search(char)
else:
+ print("In here current line: " + self.current_line)
+
self._set_current_line((self.current_line[:self.cursor_offset] +
char +
self.current_line[self.cursor_offset:]),
@@ -970,6 +983,8 @@ def add_normal_character(self, char):
reset_rl_history=False,
clear_special_mode=False)
self.cursor_offset += 1
+
+ print("but here: " + self.current_line)
if (self.config.cli_trim_prompts and
self.current_line.startswith(self.ps1)):
self.current_line = self.current_line[4:]
@@ -1021,6 +1036,7 @@ def push(self, line, insert_into_history=True):
If the interpreter successfully runs the code, clear the buffer
"""
+
if self.paste_mode:
self.saved_indent = 0
else:
@@ -1187,6 +1203,7 @@ def current_line_formatted(self):
self.old_fs = fs
return fs
+
@property
def lines_for_display(self):
"""All display lines (wrapped, colored, with prompts)"""
From e04e0f2c40037cddcef3c0a051d9eb2956275b60 Mon Sep 17 00:00:00 2001
From: periklis
Date: Sat, 10 Dec 2016 17:55:48 +0200
Subject: [PATCH 038/864] Resetting debugging-oriented changes
---
bpython/curtsiesfrontend/repl.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 3935741e1..2cc03a594 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -967,15 +967,12 @@ def toggle_file_watch(self):
# Handler Helpers
def add_normal_character(self, char):
- print("Char is :" + str(char))
if len(char) > 1 or is_nop(char):
return
if self.incr_search_mode:
print("Incr search mode")
self.add_to_incremental_search(char)
else:
- print("In here current line: " + self.current_line)
-
self._set_current_line((self.current_line[:self.cursor_offset] +
char +
self.current_line[self.cursor_offset:]),
@@ -983,8 +980,6 @@ def add_normal_character(self, char):
reset_rl_history=False,
clear_special_mode=False)
self.cursor_offset += 1
-
- print("but here: " + self.current_line)
if (self.config.cli_trim_prompts and
self.current_line.startswith(self.ps1)):
self.current_line = self.current_line[4:]
@@ -1036,7 +1031,6 @@ def push(self, line, insert_into_history=True):
If the interpreter successfully runs the code, clear the buffer
"""
-
if self.paste_mode:
self.saved_indent = 0
else:
@@ -1203,7 +1197,6 @@ def current_line_formatted(self):
self.old_fs = fs
return fs
-
@property
def lines_for_display(self):
"""All display lines (wrapped, colored, with prompts)"""
From eb3b8f3277281e1131f6045fe54ae7e1eb3f9a17 Mon Sep 17 00:00:00 2001
From: periklis
Date: Wed, 14 Dec 2016 23:13:06 +0200
Subject: [PATCH 039/864] Implementing code review changes.
---
bpython/curtsiesfrontend/repl.py | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 2cc03a594..db3f602b1 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -676,7 +676,7 @@ def process_key_event(self, e):
elif e in ("",):
self.on_control_d()
elif e in ("",):
- self.on_control_o()
+ self.operate_and_get_next()
elif e in ("",):
self.get_last_word()
elif e in key_dispatch[self.config.reverse_incremental_search_key]:
@@ -846,13 +846,6 @@ def on_control_d(self):
self.current_line = (self.current_line[:self.cursor_offset] +
self.current_line[(self.cursor_offset + 1):])
- def on_control_o(self):
- next_idx = -self.rl_history.index + 1
- next = self.rl_history.entries[next_idx]
- self.on_enter()
- print("Next is : " + next)
- self._set_current_line(next)
-
def cut_to_buffer(self):
self.cut_buffer = self.current_line[self.cursor_offset:]
self.current_line = self.current_line[:self.cursor_offset]
@@ -860,6 +853,18 @@ def cut_to_buffer(self):
def yank_from_buffer(self):
pass
+ def operate_and_get_next(self):
+ # If we have not navigated back in history
+ # ctrl+o will have the same effect as enter
+ if self.rl_history.index == 0 or self.rl_history.index == 1:
+ self.on_enter()
+ return
+
+ index = self.rl_history.index
+ self.on_enter()
+ self.rl_history.index = index
+ self._set_current_line(self.rl_history.entries[-index], reset_rl_history=False)
+
def up_one_line(self):
self.rl_history.enter(self.current_line)
self._set_current_line(tabs_to_spaces(self.rl_history.back(
From f9ccb5c00115785a68651a987c6f873081f6eb0e Mon Sep 17 00:00:00 2001
From: Thomas Ballinger
Date: Sun, 12 Feb 2017 15:33:58 -0800
Subject: [PATCH 040/864] alternate impl for ctrl-o
---
bpython/curtsiesfrontend/repl.py | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index db3f602b1..d29722c43 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -788,9 +788,11 @@ def readline_kill(self, e):
else:
self.cut_buffer = cut
- def on_enter(self, insert_into_history=True):
+ def on_enter(self, insert_into_history=True, reset_rl_history=True):
# so the cursor isn't touching a paren TODO: necessary?
self._set_cursor_offset(-1, update_completion=False)
+ if reset_rl_history:
+ self.rl_history.reset()
self.history.append(self.current_line)
self.push(self.current_line, insert_into_history=insert_into_history)
@@ -856,14 +858,7 @@ def yank_from_buffer(self):
def operate_and_get_next(self):
# If we have not navigated back in history
# ctrl+o will have the same effect as enter
- if self.rl_history.index == 0 or self.rl_history.index == 1:
- self.on_enter()
- return
-
- index = self.rl_history.index
- self.on_enter()
- self.rl_history.index = index
- self._set_current_line(self.rl_history.entries[-index], reset_rl_history=False)
+ self.on_enter(reset_rl_history=False)
def up_one_line(self):
self.rl_history.enter(self.current_line)
@@ -1091,7 +1086,11 @@ def run_code_and_maybe_finish(self, for_code=None):
self.current_stdouterr_line, self.width))
self.current_stdouterr_line = ''
- self._set_current_line(' ' * indent, update_completion=True)
+ if self.rl_history.index == 0:
+ self._set_current_line(' ' * indent, update_completion=True)
+ else:
+ self._set_current_line(self.rl_history.entries[-self.rl_history.index],
+ reset_rl_history=False)
self.cursor_offset = len(self.current_line)
def keyboard_interrupt(self):
From 8e2723375fdb7403f6025cee1e4dc6009572affc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?=
Date: Thu, 6 Apr 2017 17:27:09 -0300
Subject: [PATCH 041/864] Correct "next" duplication in line 40
---
doc/sphinx/source/contributing.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/sphinx/source/contributing.rst b/doc/sphinx/source/contributing.rst
index e62b6b51c..a4f16f8da 100644
--- a/doc/sphinx/source/contributing.rst
+++ b/doc/sphinx/source/contributing.rst
@@ -37,7 +37,7 @@ Fork bpython in the GitHub web interface, then clone the repo:
$ git clone git@github.com:YOUR_GITHUB_USERNAME/bpython.git
# or "git clone https://github.com/YOUR_GITHUB_USERNAME/bpython.git"
-Next install the install your development copy of bpython and its dependencies:
+Next install your development copy of bpython and its dependencies:
.. code-block:: bash
From a743920e3fb2043a9610ed569dafc5b47932c559 Mon Sep 17 00:00:00 2001
From: Alwx
Date: Tue, 18 Apr 2017 12:01:24 +0300
Subject: [PATCH 042/864] remove deprecation warning in inspect module
method getargspec was deprecated in python3
and method getfullargspec was deprecated until python3.6 in favour
of signature method
---
bpython/curtsiesfrontend/manual_readline.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py
index 953471e22..752ba8de8 100644
--- a/bpython/curtsiesfrontend/manual_readline.py
+++ b/bpython/curtsiesfrontend/manual_readline.py
@@ -10,10 +10,15 @@
import inspect
from six import iteritems
+from bpython._py3compat import py3
INDENT = 4
# TODO Allow user config of keybindings for these actions
+if py3:
+ getargspec = lambda func: inspect.getargspec(func)[0]
+else:
+ getargspec = lambda func: inspect.signature(func).parameters
class AbstractEdits(object):
@@ -38,7 +43,7 @@ def add(self, key, func, overwrite=False):
del self[key]
else:
raise ValueError('key %r already has a mapping' % (key,))
- params = inspect.getargspec(func)[0]
+ params = getargspec(func)
args = dict((k, v) for k, v in iteritems(self.default_kwargs)
if k in params)
r = func(**args)
@@ -64,7 +69,7 @@ def add_config_attr(self, config_attr, func):
def call(self, key, **kwargs):
func = self[key]
- params = inspect.getargspec(func)[0]
+ params = getargspec(func)
args = dict((k, v) for k, v in kwargs.items() if k in params)
return func(**args)
From 951401a0ecaabda16aed5ce028c2329b17c2b088 Mon Sep 17 00:00:00 2001
From: Alwx
Date: Tue, 18 Apr 2017 12:13:14 +0300
Subject: [PATCH 043/864] fix logic mistake
---
bpython/curtsiesfrontend/manual_readline.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py
index 752ba8de8..35d28f541 100644
--- a/bpython/curtsiesfrontend/manual_readline.py
+++ b/bpython/curtsiesfrontend/manual_readline.py
@@ -15,7 +15,7 @@
INDENT = 4
# TODO Allow user config of keybindings for these actions
-if py3:
+if not py3:
getargspec = lambda func: inspect.getargspec(func)[0]
else:
getargspec = lambda func: inspect.signature(func).parameters
From e6214795e723a91e02ce7f56803f1b2efca8e4a6 Mon Sep 17 00:00:00 2001
From: Thomas Ballinger
Date: Sat, 22 Apr 2017 00:15:47 -0700
Subject: [PATCH 044/864] don't ignore rc flines by by overwriting rcLines
---
bpdb/debugger.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/bpdb/debugger.py b/bpdb/debugger.py
index 73e1c560b..ecd011194 100644
--- a/bpdb/debugger.py
+++ b/bpdb/debugger.py
@@ -33,7 +33,6 @@ class BPdb(pdb.Pdb):
def __init__(self, *args, **kwargs):
pdb.Pdb.__init__(self, *args, **kwargs)
- self.rcLines = []
self.prompt = '(BPdb) '
self.intro = 'Use "B" to enter bpython, Ctrl-d to exit it.'
From ef917412711fe55fe64325dbb2c61872914d4ee0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Attila=20Sz=C3=B6ll=C5=91si?=
Date: Wed, 10 May 2017 22:55:16 +0200
Subject: [PATCH 045/864] Use width aware slice
---
bpython/curtsiesfrontend/replpainter.py | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index 36c9c1324..a48d299fb 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -25,11 +25,14 @@ def display_linize(msg, columns, blank_line=False):
"""Returns lines obtained by splitting msg over multiple lines.
Warning: if msg is empty, returns an empty list of lines"""
- display_lines = ([msg[start:end]
- for start, end in zip(
- range(0, len(msg), columns),
- range(columns, len(msg) + columns, columns))]
- if msg else ([''] if blank_line else []))
+ msg = fmtstr(msg)
+ try:
+ display_lines = [msg.width_aware_slice(slice(start, end))
+ for start, end in zip(
+ range(0, msg.width, columns),
+ range(columns, msg.width + columns, columns))]
+ except ValueError:
+ display_lines = ([''] if blank_line else [])
return display_lines
From f0ca805b5e7a8ee6887cc5a25c078ffbf9bb6584 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Attila=20Sz=C3=B6ll=C5=91si?=
Date: Thu, 11 May 2017 14:00:33 +0200
Subject: [PATCH 046/864] Fix test failure
---
bpython/curtsiesfrontend/replpainter.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index a48d299fb..16babde9d 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -27,12 +27,13 @@ def display_linize(msg, columns, blank_line=False):
Warning: if msg is empty, returns an empty list of lines"""
msg = fmtstr(msg)
try:
- display_lines = [msg.width_aware_slice(slice(start, end))
+ display_lines = ([msg.width_aware_slice(slice(start, end))
for start, end in zip(
range(0, msg.width, columns),
range(columns, msg.width + columns, columns))]
+ if msg else ([''] if blank_line else []))
except ValueError:
- display_lines = ([''] if blank_line else [])
+ display_lines = ['']
return display_lines
From 724f3b9b561ce8b7397d8413a342c8b46262109d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Attila=20Sz=C3=B6ll=C5=91si?=
Date: Sat, 27 May 2017 00:14:36 +0200
Subject: [PATCH 047/864] Fix newline handling in stdout and stderr
---
bpython/curtsiesfrontend/repl.py | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index d29722c43..a24d38c7e 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -1079,13 +1079,6 @@ def run_code_and_maybe_finish(self, for_code=None):
if err:
indent = 0
- # TODO This should be printed ABOVE the error that just happened
- # instead or maybe just thrown away and not shown
- if self.current_stdouterr_line:
- self.display_lines.extend(paint.display_linize(
- self.current_stdouterr_line, self.width))
- self.current_stdouterr_line = ''
-
if self.rl_history.index == 0:
self._set_current_line(' ' * indent, update_completion=True)
else:
@@ -1137,11 +1130,26 @@ def clear_current_block(self, remove_from_history=True):
def get_current_block(self):
return '\n'.join(self.buffer + [self.current_line])
+ def move_current_stdouterr_line_up(self):
+ """Append self.current_stdouterr_line to self.display_lines
+ then clean it."""
+ self.display_lines.extend(paint.display_linize(
+ self.current_stdouterr_line, self.width))
+ self.current_stdouterr_line = ''
+
def send_to_stdout(self, output):
"""Send unicode string to Repl stdout"""
+ if not output: return
lines = output.split('\n')
+ if output == len(output) * '\n':
+ # If the string consist only of newline characters,
+ # str.split returns one more empty strings.
+ lines = lines[:-1]
logger.debug('display_lines: %r', self.display_lines)
- self.current_stdouterr_line += lines[0]
+ if lines[0]:
+ self.current_stdouterr_line += lines[0]
+ else:
+ self.move_current_stdouterr_line_up()
if len(lines) > 1:
self.display_lines.extend(paint.display_linize(
self.current_stdouterr_line, self.width, blank_line=True))
@@ -1157,9 +1165,16 @@ def send_to_stderr(self, error):
Must be able to handle FmtStrs because interpreter pass in
tracebacks already formatted."""
+ if not error: return
lines = error.split('\n')
+ if error == len(error) * '\n':
+ # If the string consist only of newline characters,
+ # str.split returns one more empty strings.
+ lines = lines[:-1]
if lines[-1]:
self.current_stdouterr_line += lines[-1]
+ else:
+ self.move_current_stdouterr_line_up()
self.display_lines.extend(sum((paint.display_linize(line, self.width,
blank_line=True)
for line in lines[:-1]), []))
From 997117a7bc09a9f4ba2df200a31c853ea94cf012 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Attila=20Sz=C3=B6ll=C5=91si?=
Date: Sun, 28 May 2017 12:53:17 +0200
Subject: [PATCH 048/864] Changes requested by sebastinas
---
bpython/curtsiesfrontend/repl.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index a24d38c7e..4f32abb93 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -1139,9 +1139,10 @@ def move_current_stdouterr_line_up(self):
def send_to_stdout(self, output):
"""Send unicode string to Repl stdout"""
- if not output: return
+ if not output:
+ return
lines = output.split('\n')
- if output == len(output) * '\n':
+ if all(not line for line in lines):
# If the string consist only of newline characters,
# str.split returns one more empty strings.
lines = lines[:-1]
@@ -1165,9 +1166,10 @@ def send_to_stderr(self, error):
Must be able to handle FmtStrs because interpreter pass in
tracebacks already formatted."""
- if not error: return
+ if not error:
+ return
lines = error.split('\n')
- if error == len(error) * '\n':
+ if all(not line for line in lines):
# If the string consist only of newline characters,
# str.split returns one more empty strings.
lines = lines[:-1]
From 3463e7ac2bc1599b10a06bfbd89a4bf4a3dee009 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 17:18:28 +0200
Subject: [PATCH 049/864] Update changelog
Signed-off-by: Sebastian Ramacher
---
CHANGELOG | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 3833a971c..66e350388 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,12 +5,16 @@ Changelog
----
New features:
+* #641: Implement Ctrol+O.
Fixes:
+* Fix deprecation warnings.
* #648: Fix paste helper.
Thanks to Jakob Bowyer.
* #653: Handle docstrings more carefully.
* #654: Do not modify history file during tests.
+* #658: Fix newline handling.
+* #670: Fix handlign of ANSI escape codes.
0.16
----
From 8f86cc2356f719ea9c71b55df06fc2f853cf4384 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 17:21:29 +0200
Subject: [PATCH 050/864] Fix typo
Signed-off-by: Sebastian Ramacher
---
CHANGELOG | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 66e350388..74007f217 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,7 +5,7 @@ Changelog
----
New features:
-* #641: Implement Ctrol+O.
+* #641: Implement Ctrl+O.
Fixes:
* Fix deprecation warnings.
From df00c79914c457433c2ddaf36da4354ea63d51af Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 17:27:28 +0200
Subject: [PATCH 051/864] Error out if not enough parameters are given
Signed-off-by: Sebastian Ramacher
---
bpdb/__init__.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/bpdb/__init__.py b/bpdb/__init__.py
index db2daba21..4e0aef920 100644
--- a/bpdb/__init__.py
+++ b/bpdb/__init__.py
@@ -78,6 +78,10 @@ def main():
'See AUTHORS for detail.')
return 0
+ if len(args) < 2:
+ print('usage: bpdb scriptfile [arg] ...')
+ return 2
+
# The following code is based on Python's pdb.py.
mainpyfile = args[1]
if not os.path.exists(mainpyfile):
From 670b5c9c38d4eaae635c6885f719fb9229b4ac39 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 17:29:01 +0200
Subject: [PATCH 052/864] Use absolute imports
---
bpdb/__init__.py | 4 ++--
bpdb/__main__.py | 4 +++-
bpython/__main__.py | 4 +++-
bpython/_internal.py | 4 +++-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/bpdb/__init__.py b/bpdb/__init__.py
index 4e0aef920..5806a5c37 100644
--- a/bpdb/__init__.py
+++ b/bpdb/__init__.py
@@ -23,14 +23,14 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-from __future__ import print_function
+from __future__ import print_function, absolute_import
import os
import sys
import traceback
import bpython
-from bpdb.debugger import BPdb
+from .debugger import BPdb
from optparse import OptionParser
from pdb import Restart
diff --git a/bpdb/__main__.py b/bpdb/__main__.py
index c339c9c36..758db27e7 100644
--- a/bpdb/__main__.py
+++ b/bpdb/__main__.py
@@ -22,8 +22,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import sys
if __name__ == '__main__':
- from bpdb import main
+ from . import main
sys.exit(main())
diff --git a/bpython/__main__.py b/bpython/__main__.py
index fe2651ebc..d81ec1efd 100644
--- a/bpython/__main__.py
+++ b/bpython/__main__.py
@@ -22,8 +22,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
+from __future__ import absolute_import
+
import sys
if __name__ == '__main__':
- from bpython.curtsies import main
+ from .curtsies import main
sys.exit(main())
diff --git a/bpython/_internal.py b/bpython/_internal.py
index ea8fb9b33..55da7e6d6 100644
--- a/bpython/_internal.py
+++ b/bpython/_internal.py
@@ -1,9 +1,11 @@
# encoding: utf-8
+from __future__ import absolute_import
+
import pydoc
import sys
-from bpython.pager import page
+from .pager import page
# Ugly monkeypatching
pydoc.pager = page
From 43c43dee3e341b941982f74f494e400d99efd47c Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 18:05:03 +0200
Subject: [PATCH 053/864] Avoid naming variables after global functions
Signed-off-by: Sebastian Ramacher
---
bpython/repl.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index 61e214fcd..16b7a07a7 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -184,10 +184,10 @@ def showsyntaxerror(self, filename=None):
if self.syntaxerror_callback is not None:
self.syntaxerror_callback()
- type, value, sys.last_traceback = sys.exc_info()
- sys.last_type = type
+ exc_type, value, sys.last_traceback = sys.exc_info()
+ sys.last_type = exc_type
sys.last_value = value
- if filename and type is SyntaxError:
+ if filename and exc_type is SyntaxError:
# Work hard to stuff the correct filename in the exception
try:
msg, (dummy_filename, lineno, offset, line) = value.args
@@ -203,8 +203,8 @@ def showsyntaxerror(self, filename=None):
lineno -= 2
value = SyntaxError(msg, (filename, lineno, offset, line))
sys.last_value = value
- list = traceback.format_exception_only(type, value)
- self.writetb(list)
+ exc_formatted = traceback.format_exception_only(exc_type, value)
+ self.writetb(exc_formatted)
def showtraceback(self):
"""This needs to override the default traceback thing
From 128e4b5d1fc06759c49cd85735f70ee8022f8a2a Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 28 May 2017 18:09:23 +0200
Subject: [PATCH 054/864] Compile regex
Signed-off-by: Sebastian Ramacher
---
bpython/repl.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index 16b7a07a7..fe3da2063 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -52,6 +52,7 @@
from .config import getpreferredencoding
from .formatter import Parenthesis
from .history import History
+from .lazyre import LazyReCompile
from .paste import PasteHelper, PastePinnwand, PasteFailed
from .patch_linecache import filename_for_console_input
from .translations import _, ngettext
@@ -83,6 +84,8 @@ def estimate(self):
class Interpreter(code.InteractiveInterpreter):
"""Source code interpreter for use in bpython."""
+ bpython_input_re = LazyReCompile(r'')
+
def __init__(self, locals=None, encoding=None):
"""Constructor.
@@ -197,7 +200,7 @@ def showsyntaxerror(self, filename=None):
else:
# Stuff in the right filename and right lineno
# strip linecache line number
- if re.match(r'', filename):
+ if self.bpython_input_re.match(filename):
filename = ' '
if filename == ' ' and not py3:
lineno -= 2
@@ -220,7 +223,7 @@ def showtraceback(self):
for i, (fname, lineno, module, something) in enumerate(tblist):
# strip linecache line number
- if re.match(r'', fname):
+ if self.bpython_input_re.match(fname):
fname = ' '
tblist[i] = (fname, lineno, module, something)
# Set the right lineno (encoding header adds an extra line)
From 6be4207a7da639581cd062b92de66618d0043fa9 Mon Sep 17 00:00:00 2001
From: Alex Frieder
Date: Fri, 7 Jul 2017 21:00:08 -0400
Subject: [PATCH 055/864] Add default_autoreload config option
---
bpython/config.py | 2 ++
bpython/curtsiesfrontend/repl.py | 5 ++++-
bpython/sample-config | 3 +++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/bpython/config.py b/bpython/config.py
index a45afba7b..d80ac7185 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -71,6 +71,7 @@ def loadini(struct, configfile):
'color_scheme': 'default',
'complete_magic_methods': True,
'dedent_after': 1,
+ 'default_autoreload': False,
'editor': os.environ.get('VISUAL', os.environ.get('EDITOR', 'vi')),
'flush_output': True,
'highlight_show_source': True,
@@ -176,6 +177,7 @@ def get_key_no_doublebind(command):
struct.hist_length = config.getint('general', 'hist_length')
struct.hist_duplicates = config.getboolean('general', 'hist_duplicates')
struct.flush_output = config.getboolean('general', 'flush_output')
+ struct.default_autoreload = config.getboolean('general', 'default_autoreload')
struct.pastebin_key = get_key_no_doublebind('pastebin')
struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard')
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 4f32abb93..9fd0745c8 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -420,7 +420,8 @@ def __init__(self,
self.paste_mode = False
self.current_match = None
self.list_win_visible = False
- self.watching_files = False # whether auto reloading active
+ # whether auto reloading active
+ self.watching_files = config.default_autoreload
# 'reverse_incremental_search', 'incremental_search' or None
self.incr_search_mode = None
@@ -435,6 +436,8 @@ def __init__(self,
self.status_bar.message(banner)
self.watcher = ModuleChangedEventHandler([], self.request_reload)
+ if self.watcher and config.default_autoreload:
+ self.watcher.activate()
# The methods below should be overridden, but the default implementations
# below can be used as well.
diff --git a/bpython/sample-config b/bpython/sample-config
index 7fdf96361..1f7c8dd65 100644
--- a/bpython/sample-config
+++ b/bpython/sample-config
@@ -53,6 +53,9 @@
# always prompt.
# single_undo_time = 1.0
+# Enable autoreload feature by default (default: False).
+# default_autoreload = False
+
[keyboard]
# All key bindings are shown commented out with their default binding
From 51d208e1bbd25b028698f57ed4d701d2797e0da2 Mon Sep 17 00:00:00 2001
From: Max Nordlund
Date: Tue, 18 Apr 2017 13:18:17 +0200
Subject: [PATCH 056/864] Allow bpython/bpdb outside main thread
Because [signal.signal][1] is only allowed to be called from the main
thread, if you use bpdb in another thread it will crash upon entering
the repl. By ignoring the resulting `ValueError` the show can go on.
[1]: https://docs.python.org/3/library/signal.html#signal.signal
---
bpython/curtsiesfrontend/repl.py | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 9fd0745c8..043b8ca51 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -531,8 +531,12 @@ def __enter__(self):
sys.stdin = self.stdin
self.orig_sigwinch_handler = signal.getsignal(signal.SIGWINCH)
self.orig_sigtstp_handler = signal.getsignal(signal.SIGTSTP)
- signal.signal(signal.SIGWINCH, self.sigwinch_handler)
- signal.signal(signal.SIGTSTP, self.sigtstp_handler)
+
+ try:
+ signal.signal(signal.SIGWINCH, self.sigwinch_handler)
+ signal.signal(signal.SIGTSTP, self.sigtstp_handler)
+ except ValueError:
+ pass # Ignore "signal only works in main thread"
self.orig_meta_path = sys.meta_path
if self.watcher:
@@ -545,8 +549,13 @@ def __exit__(self, *args):
sys.stdin = self.orig_stdin
sys.stdout = self.orig_stdout
sys.stderr = self.orig_stderr
- signal.signal(signal.SIGWINCH, self.orig_sigwinch_handler)
- signal.signal(signal.SIGTSTP, self.orig_sigtstp_handler)
+
+ try:
+ signal.signal(signal.SIGWINCH, self.orig_sigwinch_handler)
+ signal.signal(signal.SIGTSTP, self.orig_sigtstp_handler)
+ except ValueError:
+ pass # Ignore "signal only works in main thread"
+
sys.meta_path = self.orig_meta_path
def sigwinch_handler(self, signum, frame):
From 4ba61b279d4733f57a9b8af2bd5d01f81c806139 Mon Sep 17 00:00:00 2001
From: Max Nordlund
Date: Sun, 23 Apr 2017 11:32:28 +0200
Subject: [PATCH 057/864] Comment what is turned off
This adds an extra comment explaining what is turned off when the signal
handlers are ignored.
---
bpython/curtsiesfrontend/repl.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 043b8ca51..3f99ca18f 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -536,7 +536,8 @@ def __enter__(self):
signal.signal(signal.SIGWINCH, self.sigwinch_handler)
signal.signal(signal.SIGTSTP, self.sigtstp_handler)
except ValueError:
- pass # Ignore "signal only works in main thread"
+ pass # Ignore "signal only works in main thread"
+ # This turns off resize detection and ctrl-z suspension.
self.orig_meta_path = sys.meta_path
if self.watcher:
@@ -554,7 +555,8 @@ def __exit__(self, *args):
signal.signal(signal.SIGWINCH, self.orig_sigwinch_handler)
signal.signal(signal.SIGTSTP, self.orig_sigtstp_handler)
except ValueError:
- pass # Ignore "signal only works in main thread"
+ pass # Ignore "signal only works in main thread"
+ # This turns off resize detection and ctrl-z suspension.
sys.meta_path = self.orig_meta_path
From c58a933746df79af9daaa6fd8bd90180322ae1e7 Mon Sep 17 00:00:00 2001
From: Max Nordlund gmail
Date: Mon, 24 Apr 2017 10:49:58 +0200
Subject: [PATCH 058/864] Use an if instead of a try statement
---
bpython/curtsiesfrontend/repl.py | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 3f99ca18f..c5ac8c51d 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -11,6 +11,7 @@
import subprocess
import sys
import tempfile
+import threading
import time
import unicodedata
from six.moves import range
@@ -532,12 +533,10 @@ def __enter__(self):
self.orig_sigwinch_handler = signal.getsignal(signal.SIGWINCH)
self.orig_sigtstp_handler = signal.getsignal(signal.SIGTSTP)
- try:
+ if isinstance(threading.current_thread(), threading._MainThread):
+ # This turns off resize detection and ctrl-z suspension.
signal.signal(signal.SIGWINCH, self.sigwinch_handler)
signal.signal(signal.SIGTSTP, self.sigtstp_handler)
- except ValueError:
- pass # Ignore "signal only works in main thread"
- # This turns off resize detection and ctrl-z suspension.
self.orig_meta_path = sys.meta_path
if self.watcher:
@@ -551,12 +550,10 @@ def __exit__(self, *args):
sys.stdout = self.orig_stdout
sys.stderr = self.orig_stderr
- try:
+ if isinstance(threading.current_thread(), threading._MainThread):
+ # This turns off resize detection and ctrl-z suspension.
signal.signal(signal.SIGWINCH, self.orig_sigwinch_handler)
signal.signal(signal.SIGTSTP, self.orig_sigtstp_handler)
- except ValueError:
- pass # Ignore "signal only works in main thread"
- # This turns off resize detection and ctrl-z suspension.
sys.meta_path = self.orig_meta_path
From 307f855306ae8e0814458026b9fc47c1f25bf357 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 8 Jul 2017 10:47:47 +0200
Subject: [PATCH 059/864] Check if current thread is the main thread using
threading.main_thread()
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/repl.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index c5ac8c51d..197a136b1 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -99,6 +99,14 @@
unicode = str
+if sys.version_info >= (3, 4):
+ def is_main_thread():
+ return threading.main_thread() == threading.current_thread()
+else:
+ def is_main_thread():
+ return isinstance(threading.current_thread(), threading._MainThread)
+
+
class FakeStdin(object):
"""The stdin object user code will reference
@@ -533,7 +541,7 @@ def __enter__(self):
self.orig_sigwinch_handler = signal.getsignal(signal.SIGWINCH)
self.orig_sigtstp_handler = signal.getsignal(signal.SIGTSTP)
- if isinstance(threading.current_thread(), threading._MainThread):
+ if is_main_thread():
# This turns off resize detection and ctrl-z suspension.
signal.signal(signal.SIGWINCH, self.sigwinch_handler)
signal.signal(signal.SIGTSTP, self.sigtstp_handler)
@@ -550,7 +558,7 @@ def __exit__(self, *args):
sys.stdout = self.orig_stdout
sys.stderr = self.orig_stderr
- if isinstance(threading.current_thread(), threading._MainThread):
+ if is_main_thread():
# This turns off resize detection and ctrl-z suspension.
signal.signal(signal.SIGWINCH, self.orig_sigwinch_handler)
signal.signal(signal.SIGTSTP, self.orig_sigtstp_handler)
From 836bb87d2a4f084ebbfffe3596e61e7bae20c891 Mon Sep 17 00:00:00 2001
From: Alex Frieder
Date: Sat, 8 Jul 2017 10:29:04 -0400
Subject: [PATCH 060/864] Fix option-backspace behavior
---
bpython/curtsiesfrontend/manual_readline.py | 2 +-
bpython/test/test_manual_readline.py | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py
index 35d28f541..223ec9e71 100644
--- a/bpython/curtsiesfrontend/manual_readline.py
+++ b/bpython/curtsiesfrontend/manual_readline.py
@@ -323,7 +323,7 @@ def titlecase_next_word(cursor_offset, line):
return cursor_offset, line # TODO Not implemented
-delete_word_from_cursor_back_re = LazyReCompile(r'\b\w')
+delete_word_from_cursor_back_re = LazyReCompile(r'^|\b\w')
@edit_keys.on('')
diff --git a/bpython/test/test_manual_readline.py b/bpython/test/test_manual_readline.py
index 4141292d2..faf4b585f 100644
--- a/bpython/test/test_manual_readline.py
+++ b/bpython/test/test_manual_readline.py
@@ -240,6 +240,12 @@ def test_delete_word_from_cursor_back(self):
"|"],
delete_word_from_cursor_back)
+ self.try_stages_kill([
+ " (( asdf |",
+ " (( |",
+ "|"],
+ delete_word_from_cursor_back)
+
class TestEdits(unittest.TestCase):
From 08345670aea35e57b319483366f5a0a743dade20 Mon Sep 17 00:00:00 2001
From: Sorin Vatasoiu
Date: Tue, 11 Jul 2017 18:30:37 -0700
Subject: [PATCH 061/864] fixed pasting (-p flag)
---
bpython/curtsies.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index f4520ecfa..97fd7ebe1 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -32,8 +32,7 @@
class FullCurtsiesRepl(BaseRepl):
- def __init__(self, config, locals_, banner, interp=None,
- paste=None):
+ def __init__(self, config, locals_, banner, interp=None):
self.input_generator = curtsies.input.Input(
keynames='curtsies',
sigint_event=True,
@@ -189,7 +188,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
with repl.window as win:
with repl:
repl.height, repl.width = win.t.height, win.t.width
- exit_value = repl.mainloop()
+ exit_value = repl.mainloop(True, paste)
except (SystemExitFromCodeRunner, SystemExit) as e:
exit_value = e.args
return extract_exit_value(exit_value)
From 99dcc9dc594736c239de9de971ca3fd572a17860 Mon Sep 17 00:00:00 2001
From: Tom Ballinger
Date: Tue, 11 Jul 2017 22:23:21 -0700
Subject: [PATCH 062/864] fix paste fix
---
bpython/curtsies.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 97fd7ebe1..7af127d9f 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -182,7 +182,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
if banner is not None:
print(banner)
global repl
- repl = FullCurtsiesRepl(config, locals_, welcome_message, interp, paste)
+ repl = FullCurtsiesRepl(config, locals_, welcome_message, interp)
try:
with repl.input_generator:
with repl.window as win:
From 9ec89db987844f98a6bba85c5680bd67182ef017 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 13 Jul 2017 22:29:47 +0200
Subject: [PATCH 063/864] Fix call of update
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/repl.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 197a136b1..a4502fa58 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -1029,7 +1029,7 @@ def update_completion(self, tab=False):
# or disappear; whenever current line or cursor offset changes,
# unless this happened via selecting a match
self.current_match = None
- self.list_win_visible = BpythonRepl.complete(self, tab)
+ self.list_win_visible = self.complete(tab)
def predicted_indent(self, line):
# TODO get rid of this! It's repeated code! Combine with Repl.
From d067b9df7a54d3465a1199979c7fc2a608c8d43d Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 13 Jul 2017 22:54:40 +0200
Subject: [PATCH 064/864] Decode matches from jedi (fixes #687)
Signed-off-by: Sebastian Ramacher
---
bpython/autocomplete.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/autocomplete.py b/bpython/autocomplete.py
index d2ea220f1..f93d8b86d 100644
--- a/bpython/autocomplete.py
+++ b/bpython/autocomplete.py
@@ -519,7 +519,7 @@ def matches(self, cursor_offset, line, **kwargs):
first_letter = line[self._orig_start:self._orig_start + 1]
- matches = [c.name for c in completions]
+ matches = [try_decode(c.name, 'ascii') for c in completions]
if any(not m.lower().startswith(matches[0][0].lower())
for m in matches):
# Too general - giving completions starting with multiple
From f9a76fdc1ae14253f5025f3a888e4a3f1b292762 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 13 Jul 2017 23:28:08 +0200
Subject: [PATCH 065/864] Update changelog
---
CHANGELOG | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 74007f217..dfebfd864 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,15 +6,24 @@ Changelog
New features:
* #641: Implement Ctrl+O.
+* Add default_autoreload config option.
+ Thanks to Alex Frieder.
Fixes:
* Fix deprecation warnings.
+* Do not call signal outside of main thread.
+ Thanks to Max Nordlund.
+* Fix option-backspace behavior.
+ Thanks to Alex Frieder.
* #648: Fix paste helper.
Thanks to Jakob Bowyer.
* #653: Handle docstrings more carefully.
* #654: Do not modify history file during tests.
* #658: Fix newline handling.
+ Thanks to Attila Szöllősi.
* #670: Fix handlign of ANSI escape codes.
+ Thanks to Attila Szöllősi.
+* #687: Fix encoding of jedi completions.
0.16
----
From 01b192154206d19703d56084435f96956a455bd3 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 15 Jul 2017 11:48:09 +0200
Subject: [PATCH 066/864] Point Travis to 0.17-bugfix branch
---
README.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.rst b/README.rst
index ed68c8cbc..961e55c39 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
|ImageLink|_
-.. |ImageLink| image:: https://travis-ci.org/bpython/bpython.svg?branch=master
+.. |ImageLink| image:: https://travis-ci.org/bpython/bpython.svg?branch=bugfix-0.17
.. _ImageLink: https://travis-ci.org/bpython/bpython
***********************************************************************
From 14acea09f26e95dc02225ce9bbc45d70a763067f Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 15 Jul 2017 11:49:34 +0200
Subject: [PATCH 067/864] Start development of 0.18
---
CHANGELOG | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index dfebfd864..685707112 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,15 @@
Changelog
=========
+0.18
+----
+
+New features:
+
+
+Fixes:
+
+
0.17
----
From 0cdaf41acfcc2830b2fe8cf81f28125c2197fd4b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 15 Jul 2017 12:46:35 +0200
Subject: [PATCH 068/864] Drop support for Python 3.3
By the time of the 0.18 release, Python 3.3 is EOL.
Signed-off-by: Sebastian Ramacher
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index a81e507eb..8fb607d80 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,6 @@ notifications:
python:
- "2.7"
- - "3.3"
- "3.4"
- "3.5"
- "3.6"
From 97a4c9d79a306be15b76a2d56cca80c5c4fa6096 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 15 Jul 2017 12:47:19 +0200
Subject: [PATCH 069/864] Test with 3.7-dev
Signed-off-by: Sebastian Ramacher
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 8fb607d80..be708063a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ python:
- "3.4"
- "3.5"
- "3.6"
+ - "3.7-dev"
- "pypy"
- "pypy3"
@@ -18,6 +19,7 @@ env:
matrix:
allow_failures:
+ - python: "3.7-dev"
- python: "pypy"
- python: "pypy3"
From a0ef506012d829bcff34b254bdba6e54d7b8bbf9 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 15 Jul 2017 15:18:25 +0200
Subject: [PATCH 070/864] Simplify version checks
Signed-off-by: Sebastian Ramacher
---
bpython/autocomplete.py | 3 +--
bpython/curtsiesfrontend/repl.py | 2 +-
bpython/importcompletion.py | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/bpython/autocomplete.py b/bpython/autocomplete.py
index f93d8b86d..578a10bbb 100644
--- a/bpython/autocomplete.py
+++ b/bpython/autocomplete.py
@@ -33,7 +33,6 @@
import os
import re
import rlcompleter
-import sys
from six.moves import range, builtins
from six import string_types, iteritems
@@ -210,7 +209,7 @@ class FilenameCompletion(BaseCompletionType):
def __init__(self, mode=SIMPLE):
super(FilenameCompletion, self).__init__(False, mode)
- if sys.version_info[:2] >= (3, 4):
+ if py3:
def safe_glob(self, pathname):
return glob.iglob(glob.escape(pathname) + '*')
else:
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index a4502fa58..7497e7225 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -99,7 +99,7 @@
unicode = str
-if sys.version_info >= (3, 4):
+if py3:
def is_main_thread():
return threading.main_thread() == threading.current_thread()
else:
diff --git a/bpython/importcompletion.py b/bpython/importcompletion.py
index 5d5977b55..b8dc1964c 100644
--- a/bpython/importcompletion.py
+++ b/bpython/importcompletion.py
@@ -35,7 +35,7 @@
from warnings import catch_warnings
from six.moves import filter
-if sys.version_info[0] == 3 and sys.version_info[1] >= 3:
+if py3:
import importlib.machinery
SUFFIXES = importlib.machinery.all_suffixes()
else:
From 35beff8b687b051a84c0b252ad042e9e43c499d9 Mon Sep 17 00:00:00 2001
From: Tom Ballinger
Date: Tue, 25 Jul 2017 18:27:35 -0700
Subject: [PATCH 071/864] simple fix (ctrl-c handling probably doesn't work in
all cases)
---
bpython/curtsiesfrontend/coderunner.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index 7255a99cd..2fae023fb 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -13,6 +13,7 @@
"""
import code
+import threading
import signal
import greenlet
import logging
@@ -130,16 +131,19 @@ def run_code(self, for_code=None):
if source code is complete, returns "done"
if source code is incomplete, returns "unfinished"
"""
+ is_main_thread = isinstance(threading.current_thread(), threading._MainThread)
if self.code_context is None:
assert self.source is not None
self.code_context = greenlet.greenlet(self._blocking_run_code)
- self.orig_sigint_handler = signal.getsignal(signal.SIGINT)
- signal.signal(signal.SIGINT, self.sigint_handler)
+ if is_main_thread:
+ self.orig_sigint_handler = signal.getsignal(signal.SIGINT)
+ signal.signal(signal.SIGINT, self.sigint_handler)
request = self.code_context.switch()
else:
assert self.code_is_waiting
self.code_is_waiting = False
- signal.signal(signal.SIGINT, self.sigint_handler)
+ if is_main_thread:
+ signal.signal(signal.SIGINT, self.sigint_handler)
if self.sigint_happened_in_main_context:
self.sigint_happened_in_main_context = False
request = self.code_context.switch(SigintHappened)
@@ -157,7 +161,8 @@ def run_code(self, for_code=None):
return False
elif isinstance(request, (Done, Unfinished)):
self._unload_code()
- signal.signal(signal.SIGINT, self.orig_sigint_handler)
+ if is_main_thread:
+ signal.signal(signal.SIGINT, self.orig_sigint_handler)
self.orig_sigint_handler = None
return request
elif isinstance(request, SystemExitRequest):
From 55c26557de4f9303eec1ce97b0c1b8fd5f167d98 Mon Sep 17 00:00:00 2001
From: Tom Ballinger
Date: Sat, 19 Aug 2017 12:49:35 -0700
Subject: [PATCH 072/864] fix encoding issues in urwid and curses
---
bpython/cli.py | 12 +++++++++---
bpython/urwid.py | 14 +++++++-------
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index c7a540283..6fb0594ea 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -330,7 +330,7 @@ def __init__(self, scr, interp, statusbar, config, idle=None):
repl.Repl.__init__(self, interp, config)
self.interp.writetb = self.writetb
self.scr = scr
- self.stdout_hist = ''
+ self.stdout_hist = '' # str (bytes in Py2, unicode in Py3)
self.list_win = newwin(get_colpair(config, 'background'), 1, 1, 1, 1)
self.cpos = 0
self.do_exit = False
@@ -1066,13 +1066,19 @@ def prompt(self, more):
"""Show the appropriate Python prompt"""
if not more:
self.echo("\x01%s\x03%s" % (self.config.color_scheme['prompt'], self.ps1))
- self.stdout_hist += self.ps1
+ if py3:
+ self.stdout_hist += self.ps1
+ else:
+ self.stdout_hist += self.ps1.encode(getpreferredencoding())
self.s_hist.append('\x01%s\x03%s\x04' %
(self.config.color_scheme['prompt'], self.ps1))
else:
prompt_more_color = self.config.color_scheme['prompt_more']
self.echo("\x01%s\x03%s" % (prompt_more_color, self.ps2))
- self.stdout_hist += self.ps2
+ if py3:
+ self.stdout_hist += self.ps2
+ else:
+ self.stdout_hist += self.ps2.encode(getpreferredencoding())
self.s_hist.append('\x01%s\x03%s\x04' % (prompt_more_color, self.ps2))
def push(self, s, insert_into_history=True):
diff --git a/bpython/urwid.py b/bpython/urwid.py
index c81843d9f..bcaf53460 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -596,7 +596,7 @@ def __init__(self, event_loop, palette, interpreter, config):
self.tooltip = urwid.ListBox(urwid.SimpleListWalker([]))
self.tooltip.grid = None
self.overlay = Tooltip(self.listbox, self.tooltip)
- self.stdout_hist = ''
+ self.stdout_hist = '' # str (bytes in Py2, unicode in Py3)
self.frame = urwid.Frame(self.overlay)
@@ -976,17 +976,17 @@ def prompt(self, more):
# input to be the same type, using ascii as encoding. If the
# caption is bytes this breaks typing non-ascii into bpython.
if not more:
+ caption = ('prompt', self.ps1)
if py3:
- caption = ('prompt', self.ps1)
+ self.stdout_hist += self.ps1
else:
- caption = ('prompt', self.ps1.decode(getpreferredencoding()))
- self.stdout_hist += self.ps1
+ self.stdout_hist += self.ps1.encode(getpreferredencoding())
else:
+ caption = ('prompt_more', self.ps2)
if py3:
- caption = ('prompt_more', self.ps2)
+ self.stdout_hist += self.ps2
else:
- caption = ('prompt_more', self.ps2.decode(getpreferredencoding()))
- self.stdout_hist += self.ps2
+ self.stdout_hist += self.ps2.encode(getpreferredencoding())
self.edit = BPythonEdit(self.config, caption=caption)
urwid.connect_signal(self.edit, 'change', self.on_input_change)
From 143757c568bc016261cb5459586c9cb069697162 Mon Sep 17 00:00:00 2001
From: Tom Ballinger
Date: Sun, 20 Aug 2017 16:11:55 -0700
Subject: [PATCH 073/864] terminology change: native str
---
bpython/cli.py | 2 +-
bpython/urwid.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index 6fb0594ea..a8f9ba2f8 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -330,7 +330,7 @@ def __init__(self, scr, interp, statusbar, config, idle=None):
repl.Repl.__init__(self, interp, config)
self.interp.writetb = self.writetb
self.scr = scr
- self.stdout_hist = '' # str (bytes in Py2, unicode in Py3)
+ self.stdout_hist = '' # native str (bytes in Py2, unicode in Py3)
self.list_win = newwin(get_colpair(config, 'background'), 1, 1, 1, 1)
self.cpos = 0
self.do_exit = False
diff --git a/bpython/urwid.py b/bpython/urwid.py
index bcaf53460..acb153a27 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -596,7 +596,7 @@ def __init__(self, event_loop, palette, interpreter, config):
self.tooltip = urwid.ListBox(urwid.SimpleListWalker([]))
self.tooltip.grid = None
self.overlay = Tooltip(self.listbox, self.tooltip)
- self.stdout_hist = '' # str (bytes in Py2, unicode in Py3)
+ self.stdout_hist = '' # native str (bytes in Py2, unicode in Py3)
self.frame = urwid.Frame(self.overlay)
From a975340d8917d332e3ad3667c033d65f9b3d03b7 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 14 Sep 2017 00:30:59 +0200
Subject: [PATCH 074/864] Move is_main_thread to bpython._py3compat
Signed-off-by: Sebastian Ramacher
---
bpython/_py3compat.py | 12 ++++++++++++
bpython/curtsiesfrontend/repl.py | 10 +---------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/bpython/_py3compat.py b/bpython/_py3compat.py
index 41acc5ce1..c009ece5e 100644
--- a/bpython/_py3compat.py
+++ b/bpython/_py3compat.py
@@ -37,14 +37,17 @@
from __future__ import absolute_import
import sys
+import threading
py3 = (sys.version_info[0] == 3)
+
if py3:
from pygments.lexers import Python3Lexer as PythonLexer
else:
from pygments.lexers import PythonLexer
+
if py3 or sys.version_info[:3] >= (2, 7, 3):
def prepare_for_exec(arg, encoding=None):
return arg
@@ -65,3 +68,12 @@ def try_decode(s, encoding):
except UnicodeDecodeError:
return None
return s
+
+
+if py3:
+ def is_main_thread():
+ return threading.main_thread() == threading.current_thread()
+else:
+ def is_main_thread():
+ return isinstance(threading.current_thread(), threading._MainThread)
+
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 7497e7225..58ad1713e 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -34,7 +34,7 @@
from bpython.formatter import BPythonFormatter
from bpython import autocomplete
from bpython.translations import _
-from bpython._py3compat import py3
+from bpython._py3compat import py3, is_main_thread
from bpython.pager import get_pager_command
from bpython.curtsiesfrontend import replpainter as paint
@@ -99,14 +99,6 @@
unicode = str
-if py3:
- def is_main_thread():
- return threading.main_thread() == threading.current_thread()
-else:
- def is_main_thread():
- return isinstance(threading.current_thread(), threading._MainThread)
-
-
class FakeStdin(object):
"""The stdin object user code will reference
From 052b3a3620d90f3208f5593ddc63f7ce9f76e083 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 14 Sep 2017 00:31:31 +0200
Subject: [PATCH 075/864] Re-use is_main_thread
Signed-off-by: Sebastian Ramacher
---
bpython/curtsiesfrontend/coderunner.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index 2fae023fb..647a7dca1 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -18,7 +18,7 @@
import greenlet
import logging
-from bpython._py3compat import py3
+from bpython._py3compat import py3, is_main_thread
from bpython.config import getpreferredencoding
logger = logging.getLogger(__name__)
@@ -131,18 +131,17 @@ def run_code(self, for_code=None):
if source code is complete, returns "done"
if source code is incomplete, returns "unfinished"
"""
- is_main_thread = isinstance(threading.current_thread(), threading._MainThread)
if self.code_context is None:
assert self.source is not None
self.code_context = greenlet.greenlet(self._blocking_run_code)
- if is_main_thread:
+ if is_main_thread():
self.orig_sigint_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, self.sigint_handler)
request = self.code_context.switch()
else:
assert self.code_is_waiting
self.code_is_waiting = False
- if is_main_thread:
+ if is_main_thread():
signal.signal(signal.SIGINT, self.sigint_handler)
if self.sigint_happened_in_main_context:
self.sigint_happened_in_main_context = False
@@ -161,7 +160,7 @@ def run_code(self, for_code=None):
return False
elif isinstance(request, (Done, Unfinished)):
self._unload_code()
- if is_main_thread:
+ if is_main_thread():
signal.signal(signal.SIGINT, self.orig_sigint_handler)
self.orig_sigint_handler = None
return request
From 98a8269a8f38bcd473e0889097250d4733a46c2b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 9 Oct 2017 20:18:22 +0200
Subject: [PATCH 076/864] Fix appdata location
Signed-off-by: Sebastian Ramacher
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 5505f5ddd..a8ba03515 100755
--- a/setup.py
+++ b/setup.py
@@ -199,7 +199,7 @@ def initialize_options(self):
# desktop shortcut
(os.path.join('share', 'applications'), ['data/bpython.desktop']),
# AppData
- (os.path.join('share', 'appdata'), ['data/bpython.appdata.xml']),
+ (os.path.join('share', 'appinfo'), ['data/bpython.appdata.xml']),
# icon
(os.path.join('share', 'pixmaps'), ['data/bpython.png'])
]
From a9c88a1c8db42d6bc6068caa5228c0882169f685 Mon Sep 17 00:00:00 2001
From: "cody.j.b.scott@gmail.com"
Date: Tue, 10 Oct 2017 13:02:53 -0400
Subject: [PATCH 077/864] Add Python3 classifier
Motivated by caniusepython3[0] reporting bpython doesn't support Python3.
```shell
$ caniusepython3 --projects bpython
```
0: https://pypi.python.org/pypi/caniusepython3
---
setup.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/setup.py b/setup.py
index a8ba03515..38cdab0ba 100755
--- a/setup.py
+++ b/setup.py
@@ -205,6 +205,10 @@ def initialize_options(self):
]
data_files.extend(man_pages)
+classifiers = [
+ 'Programming Language :: Python :: 3',
+]
+
install_requires = [
'pygments',
'requests',
@@ -270,6 +274,7 @@ def initialize_options(self):
url="http://www.bpython-interpreter.org/",
long_description="""bpython is a fancy interface to the Python
interpreter for Unix-like operating systems.""",
+ classifiers=classifiers,
install_requires=install_requires,
extras_require=extras_require,
tests_require=tests_require,
From 2349722c9ce9b6f9d7ad5f411a1b5d2859a6b116 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=B5=D0=BD?=
=?UTF-8?q?=D1=8C=D0=BA=D0=BE=D0=B2=D1=81=D0=BA=D0=B8=D0=B9?=
Date: Thu, 19 Oct 2017 19:11:58 +0300
Subject: [PATCH 078/864] Fix NameError when saving to a file
---
bpython/repl.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index fe3da2063..88a9b6e19 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -838,7 +838,7 @@ def write2file(self):
self.interact.notify(_('Save cancelled.'))
return
- session_test = self.formatforfile(self.getstdout())
+ stdout_text = self.formatforfile(self.getstdout())
try:
with open(fn, mode) as f:
From 1c5484f82580ffb6fc531562f07cfe41a8189b1d Mon Sep 17 00:00:00 2001
From: Florian Klink
Date: Mon, 6 Nov 2017 15:58:01 +0100
Subject: [PATCH 079/864] use self.assertEqual instead of self.assertEquals
(deprecated) (#715)
---
bpython/test/test_args.py | 2 +-
bpython/test/test_config.py | 4 +-
bpython/test/test_curtsies_parser.py | 6 +--
bpython/test/test_curtsies_repl.py | 8 ++--
bpython/test/test_interpreter.py | 6 +--
bpython/test/test_manual_readline.py | 62 ++++++++++++++--------------
bpython/test/test_simpleeval.py | 16 +++----
7 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/bpython/test/test_args.py b/bpython/test/test_args.py
index 9c89f73c9..52c613267 100644
--- a/bpython/test/test_args.py
+++ b/bpython/test/test_args.py
@@ -35,7 +35,7 @@ def test_exec_dunder_file(self):
universal_newlines=True)
(_, stderr) = p.communicate()
- self.assertEquals(stderr.strip(), f.name)
+ self.assertEqual(stderr.strip(), f.name)
def test_exec_nonascii_file(self):
with tempfile.NamedTemporaryFile(mode="w") as f:
diff --git a/bpython/test/test_config.py b/bpython/test/test_config.py
index fc5b841ed..c4c3c8b83 100644
--- a/bpython/test/test_config.py
+++ b/bpython/test/test_config.py
@@ -30,13 +30,13 @@ def test_load_theme(self):
struct.color_scheme = dict()
config.load_theme(struct, TEST_THEME_PATH, struct.color_scheme, dict())
expected = {"keyword": "y"}
- self.assertEquals(struct.color_scheme, expected)
+ self.assertEqual(struct.color_scheme, expected)
defaults = {"name": "c"}
expected.update(defaults)
config.load_theme(struct, TEST_THEME_PATH, struct.color_scheme,
defaults)
- self.assertEquals(struct.color_scheme, expected)
+ self.assertEqual(struct.color_scheme, expected)
def test_keybindings_default_contains_no_duplicates(self):
struct = self.load_temp_config("")
diff --git a/bpython/test/test_curtsies_parser.py b/bpython/test/test_curtsies_parser.py
index 58d3b5424..019a7e0d4 100644
--- a/bpython/test/test_curtsies_parser.py
+++ b/bpython/test/test_curtsies_parser.py
@@ -10,15 +10,15 @@
class TestExecArgs(unittest.TestCase):
def test_parse(self):
- self.assertEquals(parse.parse('\x01y\x03print\x04'), yellow('print'))
+ self.assertEqual(parse.parse('\x01y\x03print\x04'), yellow('print'))
- self.assertEquals(
+ self.assertEqual(
parse.parse('\x01y\x03print\x04\x01c\x03 \x04\x01g\x031\x04\x01c'
'\x03 \x04\x01Y\x03+\x04\x01c\x03 \x04\x01g\x032\x04'),
yellow('print') + cyan(' ') + green('1') + cyan(' ') +
bold(yellow('+')) + cyan(' ') + green(u'2'))
def test_peal_off_string(self):
- self.assertEquals(parse.peel_off_string('\x01RI\x03]\x04asdf'),
+ self.assertEqual(parse.peel_off_string('\x01RI\x03]\x04asdf'),
({'bg': 'I', 'string': ']', 'fg': 'R', 'colormarker':
'\x01RI', 'bold': ''}, 'asdf'))
diff --git a/bpython/test/test_curtsies_repl.py b/bpython/test/test_curtsies_repl.py
index 3cf25da85..e91fff022 100644
--- a/bpython/test/test_curtsies_repl.py
+++ b/bpython/test/test_curtsies_repl.py
@@ -82,10 +82,10 @@ def test_get_last_word(self):
self.assertEqual(self.repl.current_line, 'abcde3')
def test_last_word(self):
- self.assertEquals(curtsiesrepl._last_word(''), '')
- self.assertEquals(curtsiesrepl._last_word(' '), '')
- self.assertEquals(curtsiesrepl._last_word('a'), 'a')
- self.assertEquals(curtsiesrepl._last_word('a b'), 'b')
+ self.assertEqual(curtsiesrepl._last_word(''), '')
+ self.assertEqual(curtsiesrepl._last_word(' '), '')
+ self.assertEqual(curtsiesrepl._last_word('a'), 'a')
+ self.assertEqual(curtsiesrepl._last_word('a b'), 'b')
# this is the behavior of bash - not currently implemented
@unittest.skip
diff --git a/bpython/test/test_interpreter.py b/bpython/test/test_interpreter.py
index 95feb8b51..48cb8ad55 100644
--- a/bpython/test/test_interpreter.py
+++ b/bpython/test/test_interpreter.py
@@ -54,7 +54,7 @@ def test_syntaxerror(self):
'\n')
self.assertMultiLineEqual(str(plain('').join(a)), str(expected))
- self.assertEquals(plain('').join(a), expected)
+ self.assertEqual(plain('').join(a), expected)
def test_traceback(self):
i, a = self.interp_errlog()
@@ -79,7 +79,7 @@ def gfunc():
bold(red('NameError')) + ': ' + cyan(global_not_found) + '\n')
self.assertMultiLineEqual(str(plain('').join(a)), str(expected))
- self.assertEquals(plain('').join(a), expected)
+ self.assertEqual(plain('').join(a), expected)
@unittest.skipIf(py3, "runsource() accepts only unicode in Python 3")
def test_runsource_bytes(self):
@@ -123,7 +123,7 @@ def test_getsource_works_on_interactively_defined_functions(self):
i.runsource(source)
import inspect
inspected_source = inspect.getsource(i.locals['foo'])
- self.assertEquals(inspected_source, source)
+ self.assertEqual(inspected_source, source)
@unittest.skipIf(py3, "encode only does anything in Python 2")
def test_runsource_unicode_autoencode_and_noencode(self):
diff --git a/bpython/test/test_manual_readline.py b/bpython/test/test_manual_readline.py
index faf4b585f..705558d9a 100644
--- a/bpython/test/test_manual_readline.py
+++ b/bpython/test/test_manual_readline.py
@@ -20,7 +20,7 @@ def test_left_arrow_at_zero(self):
pos = 0
expected = (pos, self._line)
result = left_arrow(pos, self._line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_left_arrow_at_non_zero(self):
for i in range(1, len(self._line)):
@@ -32,25 +32,25 @@ def test_right_arrow_at_end(self):
pos = len(self._line)
expected = (pos, self._line)
result = right_arrow(pos, self._line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_right_arrow_at_non_end(self):
for i in range(len(self._line) - 1):
expected = (i + 1, self._line)
result = right_arrow(i, self._line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_beginning_of_line(self):
expected = (0, self._line)
for i in range(len(self._line)):
result = beginning_of_line(i, self._line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_end_of_line(self):
expected = (len(self._line), self._line)
for i in range(len(self._line)):
result = end_of_line(i, self._line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_forward_word(self):
line = "going from here to_here"
@@ -58,12 +58,12 @@ def test_forward_word(self):
next_word_pos = 15
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
start_pos = 15
next_word_pos = 23
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_forward_word_tabs(self):
line = "going from here to_here"
@@ -71,12 +71,12 @@ def test_forward_word_tabs(self):
next_word_pos = 15
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
start_pos = 15
next_word_pos = 28
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_forward_word_end(self):
line = "going from here to_here"
@@ -84,17 +84,17 @@ def test_forward_word_end(self):
next_word_pos = 23
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
start_pos = 22
next_word_pos = 23
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
start_pos = 23
next_word_pos = 23
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_forward_word_empty(self):
line = ""
@@ -102,50 +102,50 @@ def test_forward_word_empty(self):
next_word_pos = 0
expected = (next_word_pos, line)
result = forward_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_back_word(self):
line = "going to here from_here"
start_pos = 14
prev_word_pos = 9
- self.assertEquals(line[start_pos], 'f')
- self.assertEquals(line[prev_word_pos], 'h')
+ self.assertEqual(line[start_pos], 'f')
+ self.assertEqual(line[prev_word_pos], 'h')
expected = (prev_word_pos, line)
result = back_word(start_pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_last_word_pos(self):
line = "a word"
expected = 2
result = last_word_pos(line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_last_word_pos_single_word(self):
line = "word"
expected = 0
result = last_word_pos(line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_delete(self):
line = "deletion line"
pos = 3
expected = (3, "deltion line")
result = delete(pos, line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_delete_from_cursor_back(self):
line = "everything before this will be deleted"
expected = (0, "this will be deleted")
result = delete_from_cursor_back(line.find("this"), line)
- self.assertEquals(expected, result)
+ self.assertEqual(expected, result)
def test_delete_from_cursor_forward(self):
line = "everything after this will be deleted"
pos = line.find("this")
expected = (pos, "everything after ")
result = delete_from_cursor_forward(line.find("this"), line)[:-1]
- self.assertEquals(expected, result)
- self.assertEquals(delete_from_cursor_forward(0, ''), (0, '', ''))
+ self.assertEqual(expected, result)
+ self.assertEqual(delete_from_cursor_forward(0, ''), (0, '', ''))
def test_delete_rest_of_word(self):
self.try_stages_kill([
@@ -184,7 +184,7 @@ def try_stages(self, strings, func):
stages = [(s.index('|'), s.replace('|', '')) for s in strings]
for (initial_pos, initial), (final_pos, final) in zip(stages[:-1],
stages[1:]):
- self.assertEquals(func(initial_pos, initial), (final_pos, final))
+ self.assertEqual(func(initial_pos, initial), (final_pos, final))
def try_stages_kill(self, strings, func):
if not all('|' in s for s in strings):
@@ -193,7 +193,7 @@ def try_stages_kill(self, strings, func):
stages = [(s.index('|'), s.replace('|', '')) for s in strings]
for (initial_pos, initial), (final_pos, final) in zip(stages[:-1],
stages[1:]):
- self.assertEquals(func(initial_pos, initial)[:-1],
+ self.assertEqual(func(initial_pos, initial)[:-1],
(final_pos, final))
def test_transpose_character_before_cursor(self):
@@ -204,27 +204,27 @@ def test_transpose_character_before_cursor(self):
"adf as|sdf"], transpose_character_before_cursor)
def test_transpose_empty_line(self):
- self.assertEquals(transpose_character_before_cursor(0, ''),
+ self.assertEqual(transpose_character_before_cursor(0, ''),
(0, ''))
def test_transpose_first_character(self):
- self.assertEquals(transpose_character_before_cursor(0, 'a'),
+ self.assertEqual(transpose_character_before_cursor(0, 'a'),
(0, 'a'))
- self.assertEquals(transpose_character_before_cursor(0, 'as'),
+ self.assertEqual(transpose_character_before_cursor(0, 'as'),
(0, 'as'))
def test_transpose_end_of_line(self):
- self.assertEquals(transpose_character_before_cursor(1, 'a'),
+ self.assertEqual(transpose_character_before_cursor(1, 'a'),
(1, 'a'))
- self.assertEquals(transpose_character_before_cursor(2, 'as'),
+ self.assertEqual(transpose_character_before_cursor(2, 'as'),
(2, 'sa'))
def test_transpose_word_before_cursor(self):
pass
def test_backspace(self):
- self.assertEquals(backspace(2, 'as'), (1, 'a'))
- self.assertEquals(backspace(3, 'as '), (2, 'as'))
+ self.assertEqual(backspace(2, 'as'), (1, 'a'))
+ self.assertEqual(backspace(3, 'as '), (2, 'as'))
def test_delete_word_from_cursor_back(self):
self.try_stages_kill([
diff --git a/bpython/test/test_simpleeval.py b/bpython/test/test_simpleeval.py
index 9db2fbf9b..92107c060 100644
--- a/bpython/test/test_simpleeval.py
+++ b/bpython/test/test_simpleeval.py
@@ -188,17 +188,17 @@ class TestSafeGetAttribute(unittest.TestCase):
def test_lookup_on_object(self):
a = A()
a.x = 1
- self.assertEquals(safe_get_attribute_new_style(a, 'x'), 1)
- self.assertEquals(safe_get_attribute_new_style(a, 'a'), 'a')
+ self.assertEqual(safe_get_attribute_new_style(a, 'x'), 1)
+ self.assertEqual(safe_get_attribute_new_style(a, 'a'), 'a')
b = B()
b.y = 2
- self.assertEquals(safe_get_attribute_new_style(b, 'y'), 2)
- self.assertEquals(safe_get_attribute_new_style(b, 'a'), 'a')
- self.assertEquals(safe_get_attribute_new_style(b, 'b'), 'b')
+ self.assertEqual(safe_get_attribute_new_style(b, 'y'), 2)
+ self.assertEqual(safe_get_attribute_new_style(b, 'a'), 'a')
+ self.assertEqual(safe_get_attribute_new_style(b, 'b'), 'b')
def test_avoid_running_properties(self):
p = Property()
- self.assertEquals(safe_get_attribute_new_style(p, 'prop'),
+ self.assertEqual(safe_get_attribute_new_style(p, 'prop'),
Property.prop)
@unittest.skipIf(py3, 'Old-style classes not in Python 3')
@@ -211,7 +211,7 @@ class Old:
def test_lookup_with_slots(self):
s = Slots()
s.s1 = 's1'
- self.assertEquals(safe_get_attribute(s, 's1'), 's1')
+ self.assertEqual(safe_get_attribute(s, 's1'), 's1')
self.assertIsInstance(safe_get_attribute_new_style(s, 's1'),
member_descriptor)
with self.assertRaises(AttributeError):
@@ -232,7 +232,7 @@ def test_lookup_with_property_and_slots(self):
sga = safe_get_attribute
s = SlotsSubclass()
self.assertIsInstance(sga(Slots, 's3'), property)
- self.assertEquals(safe_get_attribute(s, 's3'),
+ self.assertEqual(safe_get_attribute(s, 's3'),
Slots.__dict__['s3'])
self.assertIsInstance(sga(SlotsSubclass, 's3'), property)
From fd5d4829d222ed69f4a00e7afa240f3898f877db Mon Sep 17 00:00:00 2001
From: Florian Klink
Date: Mon, 6 Nov 2017 23:52:10 +0100
Subject: [PATCH 080/864] test.test_args: don't hardcode python2 (#716)
This will use python3 in a python3 env and python2 in a python2 one.
---
bpython/test/test_args.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/test/test_args.py b/bpython/test/test_args.py
index 52c613267..18e3abce4 100644
--- a/bpython/test/test_args.py
+++ b/bpython/test/test_args.py
@@ -40,7 +40,7 @@ def test_exec_dunder_file(self):
def test_exec_nonascii_file(self):
with tempfile.NamedTemporaryFile(mode="w") as f:
f.write(dedent('''\
- #!/usr/bin/env python2
+ #!/usr/bin/env python
# coding: utf-8
"你好 # nonascii"
'''))
@@ -55,7 +55,7 @@ def test_exec_nonascii_file(self):
def test_exec_nonascii_file_linenums(self):
with tempfile.NamedTemporaryFile(mode="w") as f:
f.write(dedent("""\
- #!/usr/bin/env python2
+ #!/usr/bin/env python
# coding: utf-8
1/0
"""))
From 0ddda1678c760c121e99ba6d4e55fac728e71d99 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 6 Nov 2017 23:53:04 +0100
Subject: [PATCH 081/864] Use sys.executable
Signed-off-by: Sebastian Ramacher
---
bpython/test/test_args.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/test/test_args.py b/bpython/test/test_args.py
index 18e3abce4..04d362406 100644
--- a/bpython/test/test_args.py
+++ b/bpython/test/test_args.py
@@ -47,7 +47,7 @@ def test_exec_nonascii_file(self):
f.flush()
try:
subprocess.check_call([
- 'python', '-m', 'bpython.curtsies',
+ sys.executable, '-m', 'bpython.curtsies',
f.name])
except subprocess.CalledProcessError:
self.fail('Error running module with nonascii characters')
From b6b518be4761d3a477db3de41f32a88f51e600f5 Mon Sep 17 00:00:00 2001
From: "cody.j.b.scott@gmail.com"
Date: Mon, 20 Nov 2017 17:21:57 -0500
Subject: [PATCH 082/864] Add Python2 classifier
---
setup.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/setup.py b/setup.py
index 38cdab0ba..709668165 100755
--- a/setup.py
+++ b/setup.py
@@ -206,6 +206,7 @@ def initialize_options(self):
data_files.extend(man_pages)
classifiers = [
+ 'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
]
From 1222d909f55570f5a6a34b887c9b0d045152f431 Mon Sep 17 00:00:00 2001
From: toejough
Date: Wed, 7 Feb 2018 17:32:23 -0500
Subject: [PATCH 083/864] expose global vars in debugger
resolves https://github.com/bpython/bpython/issues/713
---
bpdb/debugger.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/bpdb/debugger.py b/bpdb/debugger.py
index ecd011194..704af3f9e 100644
--- a/bpdb/debugger.py
+++ b/bpdb/debugger.py
@@ -44,7 +44,9 @@ def postloop(self):
# cmd.Cmd commands
def do_Bpython(self, arg):
- bpython.embed(self.curframe.f_locals, ['-i'])
+ locals_ = dict(**self.curframe.f_globals, **self.curframe.f_locals)
+ bpython.embed(locals_, ['-i'])
+
def help_Bpython(self):
print("B(python)")
From d5abcdc176817be1f7fa8762b7d6ed4a049ad738 Mon Sep 17 00:00:00 2001
From: Simon de Vlieger
Date: Mon, 12 Feb 2018 22:07:29 +0000
Subject: [PATCH 084/864] Revert "Use width aware slice"
Due to performance impact when outputting large strings this
commit has to be temporarily reverted.
This reverts commit ef917412711fe55fe64325dbb2c61872914d4ee0.
---
bpython/curtsiesfrontend/replpainter.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index 16babde9d..36c9c1324 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -25,15 +25,11 @@ def display_linize(msg, columns, blank_line=False):
"""Returns lines obtained by splitting msg over multiple lines.
Warning: if msg is empty, returns an empty list of lines"""
- msg = fmtstr(msg)
- try:
- display_lines = ([msg.width_aware_slice(slice(start, end))
- for start, end in zip(
- range(0, msg.width, columns),
- range(columns, msg.width + columns, columns))]
- if msg else ([''] if blank_line else []))
- except ValueError:
- display_lines = ['']
+ display_lines = ([msg[start:end]
+ for start, end in zip(
+ range(0, len(msg), columns),
+ range(columns, len(msg) + columns, columns))]
+ if msg else ([''] if blank_line else []))
return display_lines
From 60be9a1f98e0f0864980cd7402d671cc23f5871e Mon Sep 17 00:00:00 2001
From: Simon de Vlieger
Date: Mon, 12 Feb 2018 22:13:28 +0000
Subject: [PATCH 085/864] Revert "Use width aware slice"
Reverted due to performance impact when outputting large strings.
This reverts commit ef917412711fe55fe64325dbb2c61872914d4ee0.
---
bpython/curtsiesfrontend/replpainter.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index 16babde9d..36c9c1324 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -25,15 +25,11 @@ def display_linize(msg, columns, blank_line=False):
"""Returns lines obtained by splitting msg over multiple lines.
Warning: if msg is empty, returns an empty list of lines"""
- msg = fmtstr(msg)
- try:
- display_lines = ([msg.width_aware_slice(slice(start, end))
- for start, end in zip(
- range(0, msg.width, columns),
- range(columns, msg.width + columns, columns))]
- if msg else ([''] if blank_line else []))
- except ValueError:
- display_lines = ['']
+ display_lines = ([msg[start:end]
+ for start, end in zip(
+ range(0, len(msg), columns),
+ range(columns, len(msg) + columns, columns))]
+ if msg else ([''] if blank_line else []))
return display_lines
From 6288c7f9905019192f1d5b3ce20ebffb1309fa1b Mon Sep 17 00:00:00 2001
From: Simon de Vlieger
Date: Mon, 12 Feb 2018 22:15:23 +0000
Subject: [PATCH 086/864] Mark revert in CHANGELOG.
---
CHANGELOG | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index dfebfd864..9d9be8f53 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,13 @@
Changelog
=========
+0.17.1
+------
+
+Fixes:
+* Reverted #670 temporarily due to performance impact
+ on large strings being output.
+
0.17
----
From 7ec25ac96f1607463007a5654bff24515a80feb7 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 13 Feb 2018 22:38:40 +0100
Subject: [PATCH 087/864] Require >= 3.4 for Python 3.x
3.3 reached its EOL in September 2017.
Signed-off-by: Sebastian Ramacher
---
doc/sphinx/source/contributing.rst | 2 +-
doc/sphinx/source/releases.rst | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/sphinx/source/contributing.rst b/doc/sphinx/source/contributing.rst
index a4f16f8da..430aabc6e 100644
--- a/doc/sphinx/source/contributing.rst
+++ b/doc/sphinx/source/contributing.rst
@@ -17,7 +17,7 @@ the time of day.
Getting your development environment set up
-------------------------------------------
-bpython supports Python 2.7, 3.3 and newer. The code is compatible with all
+bpython supports Python 2.7, 3.4 and newer. The code is compatible with all
supported versions without the need to run post processing like `2to3`.
Using a virtual environment is probably a good idea. Create a virtual
diff --git a/doc/sphinx/source/releases.rst b/doc/sphinx/source/releases.rst
index 914360e7f..36a4a9bc8 100644
--- a/doc/sphinx/source/releases.rst
+++ b/doc/sphinx/source/releases.rst
@@ -45,7 +45,7 @@ A checklist to perform some manual tests before a release:
Check that all of the following work before a release:
-* Runs under Python 2.7, 3.3, 3.4 and 3.5.
+* Runs under Python 2.7, 3.4, 3.5 and 3.6.
* Save
* Rewind
* Pastebin
From ab6f17846e858e3f4e77a4fe00cba44275f37786 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 13 Feb 2018 22:52:33 +0100
Subject: [PATCH 088/864] Update changelog
---
CHANGELOG | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index a35d7f967..1aeb0098a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,10 @@ New features:
* #713 expose globals in bpdb debugging.
Thanks to toejough.
+Fixes:
+
+
+Support for Python 3.3 has been dropped.
Fixes:
From 23ee3c27e95f597ce1ad4ba4c58d7d534f9e2deb Mon Sep 17 00:00:00 2001
From: Tom Ballinger
Date: Thu, 1 Mar 2018 09:43:23 -0800
Subject: [PATCH 089/864] remove debugging print in rev incr search
---
bpython/curtsiesfrontend/repl.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 58ad1713e..c4614a580 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -981,7 +981,6 @@ def add_normal_character(self, char):
if len(char) > 1 or is_nop(char):
return
if self.incr_search_mode:
- print("Incr search mode")
self.add_to_incremental_search(char)
else:
self._set_current_line((self.current_line[:self.cursor_offset] +
From 5698a9e291654751d3d7437c4ee650c062daf1b0 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 5 Mar 2018 00:08:59 +0100
Subject: [PATCH 090/864] Fix compatibility with 2.7
Signed-off-by: Sebastian Ramacher
---
bpdb/debugger.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/bpdb/debugger.py b/bpdb/debugger.py
index 704af3f9e..ba802070b 100644
--- a/bpdb/debugger.py
+++ b/bpdb/debugger.py
@@ -44,7 +44,8 @@ def postloop(self):
# cmd.Cmd commands
def do_Bpython(self, arg):
- locals_ = dict(**self.curframe.f_globals, **self.curframe.f_locals)
+ locals_ = self.curframe.f_globals.copy()
+ locals_.update(self.curframe.f_locals)
bpython.embed(locals_, ['-i'])
From d4a28ef8f3a2a07454702e372c82bec14e599eed Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 5 Mar 2018 00:10:17 +0100
Subject: [PATCH 091/864] Exit gracefully if config file cannot be decoded (re
#735)
---
bpython/config.py | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/bpython/config.py b/bpython/config.py
index d80ac7185..a30e76c9b 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -137,13 +137,19 @@ def loadini(struct, configfile):
in iteritems(defaults['keyboard']))
fill_config_with_default_values(config, defaults)
- if not config.read(config_path):
- # No config file. If the user has it in the old place then complain
- if os.path.isfile(os.path.expanduser('~/.bpython.ini')):
- sys.stderr.write("Error: It seems that you have a config file at "
- "~/.bpython.ini. Please move your config file to "
- "%s\n" % default_config_path())
- sys.exit(1)
+ try:
+ if not config.read(config_path):
+ # No config file. If the user has it in the old place then complain
+ if os.path.isfile(os.path.expanduser('~/.bpython.ini')):
+ sys.stderr.write("Error: It seems that you have a config file at "
+ "~/.bpython.ini. Please move your config file to "
+ "%s\n" % default_config_path())
+ sys.exit(1)
+ except UnicodeDecodeError as e:
+ sys.stderr.write("Error: Unable to parse config file at '{}' due to an "
+ "encoding issue. Please make sure to fix the encoding "
+ "of the file or remove it and then try again.\n".format(config_path))
+ sys.exit(1)
def get_key_no_doublebind(command):
default_commands_to_keys = defaults['keyboard']
From 616792bcdaa516d135f8f2ca6360817fe55cf620 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 5 Mar 2018 00:47:57 +0100
Subject: [PATCH 092/864] Adapt desktop and appdata files to new spec
Signed-off-by: Sebastian Ramacher
---
...ta.xml => org.bpython-interpreter.bpython.appdata.xml} | 8 ++++----
...on.desktop => org.bpython-interpreter.bpython.desktop} | 0
setup.py | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
rename data/{bpython.appdata.xml => org.bpython-interpreter.bpython.appdata.xml} (89%)
rename data/{bpython.desktop => org.bpython-interpreter.bpython.desktop} (100%)
diff --git a/data/bpython.appdata.xml b/data/org.bpython-interpreter.bpython.appdata.xml
similarity index 89%
rename from data/bpython.appdata.xml
rename to data/org.bpython-interpreter.bpython.appdata.xml
index 8bcf0e163..e24a09069 100644
--- a/data/bpython.appdata.xml
+++ b/data/org.bpython-interpreter.bpython.appdata.xml
@@ -1,8 +1,7 @@
-
-
-
- bpython.desktop
+
+
+ org.bpython-interpreter.bpython
CC0-1.0
MIT
bpython interpreter
@@ -22,6 +21,7 @@
Auto-indentation.
+ org.bpython-interpreter.bpython.desktop
http://www.bpython-interpreter.org/
https://github.com/bpython/bpython/issues
diff --git a/data/bpython.desktop b/data/org.bpython-interpreter.bpython.desktop
similarity index 100%
rename from data/bpython.desktop
rename to data/org.bpython-interpreter.bpython.desktop
diff --git a/setup.py b/setup.py
index 709668165..f8f943339 100755
--- a/setup.py
+++ b/setup.py
@@ -197,9 +197,9 @@ def initialize_options(self):
data_files = [
# desktop shortcut
- (os.path.join('share', 'applications'), ['data/bpython.desktop']),
+ (os.path.join('share', 'applications'), ['data/org.bpython-interpreter.bpython.desktop']),
# AppData
- (os.path.join('share', 'appinfo'), ['data/bpython.appdata.xml']),
+ (os.path.join('share', 'appinfo'), ['data/org.bpython-interpreter.bpython.appdata.xml']),
# icon
(os.path.join('share', 'pixmaps'), ['data/bpython.png'])
]
From 997c2bc4fbb576e1f2c6ba9aaf7955fcba54a08f Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 5 Mar 2018 00:50:59 +0100
Subject: [PATCH 093/864] Fix paths
Signed-off-by: Sebastian Ramacher
---
MANIFEST.in | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index 66034b0cd..badb93f1e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,8 +3,8 @@ include AUTHORS
include CHANGELOG
include LICENSE
include data/bpython.png
-include data/bpython.desktop
-include data/bpython.appdata.xml
+include data/org.bpython-interpreter.bpython.desktop
+include data/org.bpython-interpreter.bpython.appdata.xml
include doc/sphinx/source/conf.py
include doc/sphinx/source/*.rst
include doc/sphinx/source/logo.png
From 1b2068903bd779ba59dc15e302d21faffb687a53 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 8 Mar 2018 21:25:30 +0100
Subject: [PATCH 094/864] Fix file locking on Windows
Also rename fd to fileobj.
Signed-off-by: Sebastian Ramacher
---
bpython/filelock.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 9ce5ee153..e956c5543 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -42,8 +42,8 @@ class BaseLock(object):
"""Base class for file locking
"""
- def __init__(self, fd):
- self.fd = fd
+ def __init__(self, fileobj):
+ self.fileobj = fileobj
self.locked = False
def acquire(self):
@@ -69,8 +69,8 @@ class UnixFileLock(BaseLock):
"""Simple file locking for Unix using fcntl
"""
- def __init__(self, fd, mode=None):
- super(UnixFileLock, self).__init__(fd)
+ def __init__(self, fileobj, mode=None):
+ super(UnixFileLock, self).__init__(fileobj)
if mode is None:
mode = fcntl.LOCK_EX
@@ -78,14 +78,14 @@ def __init__(self, fd, mode=None):
def acquire(self):
try:
- fcntl.flock(self.fd, self.mode)
+ fcntl.flock(self.fileobj, self.mode)
self.locked = True
except IOError as e:
if e.errno != errno.ENOLCK:
raise e
def release(self):
- fcntl.flock(self.fd, fcntl.LOCK_UN)
+ fcntl.flock(self.fileobj, fcntl.LOCK_UN)
self.locked = False
@@ -93,15 +93,15 @@ class WindowsFileLock(BaseLock):
"""Simple file locking for Windows using msvcrt
"""
- def __init__(self, fd, mode=None):
- super(WindowsFileLock, self).__init__(fd)
+ def __init__(self, fileobj, mode=None):
+ super(WindowsFileLock, self).__init__(fileobj)
def acquire(self):
- msvcrt.locking(self.fd, msvcrt.LK_NBLCK, 1)
+ msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_NBLCK, 1)
self.locked = True
def release(self):
- msvcrt.locking(self.fd, msvcrt.LK_UNLCK, 1)
+ msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_UNLCK, 1)
self.locked = False
From 0ff009e16f66b4807b33d11d9efe3790c52b51dc Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 8 Mar 2018 21:42:20 +0100
Subject: [PATCH 095/864] Update changelog
---
CHANGELOG | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 1aeb0098a..44db01884 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,7 +9,8 @@ New features:
Thanks to toejough.
Fixes:
-
+* Fix file locking on Windows.
+* Exit gracefully if config file fails to be loaded due to encoding errors.
Support for Python 3.3 has been dropped.
From c85c4e76af7808601ba260ff0d29b43e1c320b71 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 20 May 2018 23:24:24 +0200
Subject: [PATCH 096/864] Fix PEP8 issues
---
bpython/_internal.py | 1 +
bpython/_py3compat.py | 1 -
bpython/cli.py | 70 +++++++++++++------------
bpython/config.py | 3 +-
bpython/curtsies.py | 2 +-
bpython/importcompletion.py | 1 +
bpython/line.py | 6 +--
bpython/patch_linecache.py | 2 +-
bpython/repl.py | 6 ++-
bpython/simpleeval.py | 8 +--
bpython/urwid.py | 100 ++++++++++++++++++++----------------
11 files changed, 113 insertions(+), 87 deletions(-)
diff --git a/bpython/_internal.py b/bpython/_internal.py
index 55da7e6d6..e0e87ba3c 100644
--- a/bpython/_internal.py
+++ b/bpython/_internal.py
@@ -27,6 +27,7 @@ def __repr__(self):
def __call__(self, *args, **kwargs):
self.helper(*args, **kwargs)
+
_help = _Helper()
diff --git a/bpython/_py3compat.py b/bpython/_py3compat.py
index c009ece5e..5e6ff3aa8 100644
--- a/bpython/_py3compat.py
+++ b/bpython/_py3compat.py
@@ -76,4 +76,3 @@ def is_main_thread():
else:
def is_main_thread():
return isinstance(threading.current_thread(), threading._MainThread)
-
diff --git a/bpython/cli.py b/bpython/cli.py
index a8f9ba2f8..2a134d95b 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -52,9 +52,9 @@
import struct
if platform.system() != 'Windows':
- import signal #Windows does not have job control
- import termios #Windows uses curses
- import fcntl #Windows uses curses
+ import signal # Windows does not have job control
+ import termios # Windows uses curses
+ import fcntl # Windows uses curses
import unicodedata
import errno
@@ -112,6 +112,7 @@ def calculate_screen_lines(tokens, width, cursor=0):
pos %= width
return lines
+
def forward_if_not_current(func):
@functools.wraps(func)
def newfunc(self, *args, **kwargs):
@@ -202,7 +203,7 @@ def readline(self, size=-1):
# C-d
return ''
elif (key not in ('\n', '\r') and
- (len(key) > 1 or unicodedata.category(key) == 'Cc')):
+ (len(key) > 1 or unicodedata.category(key) == 'Cc')):
continue
sys.stdout.write(key)
# Include the \n in the buffer - raw_input() seems to deal with trailing
@@ -281,7 +282,7 @@ def make_colors(config):
if platform.system() == 'Windows':
c = dict(list(c.items()) +
- [
+ [
('K', 8),
('R', 9),
('G', 10),
@@ -290,8 +291,8 @@ def make_colors(config):
('M', 13),
('C', 14),
('W', 15),
- ]
- )
+ ]
+ )
for i in range(63):
if i > 7:
@@ -316,7 +317,6 @@ def confirm(self, q):
return reply.lower() in (_('y'), _('yes'))
-
def notify(self, s, n=10, wait_for_keypress=False):
return self.statusbar.message(s, n)
@@ -350,6 +350,7 @@ def __init__(self, scr, interp, statusbar, config, idle=None):
def _get_cursor_offset(self):
return len(self.s) - self.cpos
+
def _set_cursor_offset(self, offset):
self.cpos = len(self.s) - offset
cursor_offset = property(_get_cursor_offset, _set_cursor_offset, None,
@@ -427,7 +428,7 @@ def check(self):
it and force syntax highlighting."""
if (self.paste_mode
- and time.time() - self.last_key_press > self.config.paste_time):
+ and time.time() - self.last_key_press > self.config.paste_time):
self.paste_mode = False
self.print_line(self.s)
@@ -454,7 +455,7 @@ def complete(self, tab=False):
with tab
"""
if self.paste_mode:
- self.scr.touchwin() #TODO necessary?
+ self.scr.touchwin() # TODO necessary?
return
list_win_visible = repl.Repl.complete(self, tab)
@@ -489,6 +490,7 @@ def clrtobol(self):
def _get_current_line(self):
return self.s
+
def _set_current_line(self, line):
self.s = line
current_line = property(_get_current_line, _set_current_line, None,
@@ -716,7 +718,7 @@ def mkargspec(self, topline, in_arg, down):
self.list_win.addstr('\n ')
self.list_win.addstr(fn,
- get_colpair(self.config, 'name') | curses.A_BOLD)
+ get_colpair(self.config, 'name') | curses.A_BOLD)
self.list_win.addstr(': (', get_colpair(self.config, 'name'))
maxh = self.scr.getmaxyx()[0]
@@ -765,7 +767,7 @@ def mkargspec(self, topline, in_arg, down):
if kw is not None:
self.list_win.addstr('=', punctuation_colpair)
self.list_win.addstr(kw, get_colpair(self.config, 'token'))
- if k != len(args) -1:
+ if k != len(args) - 1:
self.list_win.addstr(', ', punctuation_colpair)
if _args:
@@ -854,7 +856,7 @@ def p_key(self, key):
key = '\n'
# Don't return; let it get handled
- if key == chr(27): #Escape Key
+ if key == chr(27): # Escape Key
return ''
if key in (BACKSP, 'KEY_BACKSPACE'):
@@ -894,7 +896,7 @@ def p_key(self, key):
self.fwd()
return ''
- elif key in ("KEY_LEFT",' ^B', chr(2)): # Cursor Left or ^B
+ elif key in ("KEY_LEFT", ' ^B', chr(2)): # Cursor Left or ^B
self.mvc(1)
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
@@ -914,11 +916,11 @@ def p_key(self, key):
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- elif key in ("KEY_NPAGE", '\T'): # page_down or \T
+ elif key in ("KEY_NPAGE", '\T'): # page_down or \T
self.hend()
self.print_line(self.s)
- elif key in ("KEY_PPAGE", '\S'): # page_up or \S
+ elif key in ("KEY_PPAGE", '\S'): # page_up or \S
self.hbegin()
self.print_line(self.s)
@@ -1065,7 +1067,8 @@ def print_line(self, s, clr=False, newline=False):
def prompt(self, more):
"""Show the appropriate Python prompt"""
if not more:
- self.echo("\x01%s\x03%s" % (self.config.color_scheme['prompt'], self.ps1))
+ self.echo("\x01%s\x03%s" %
+ (self.config.color_scheme['prompt'], self.ps1))
if py3:
self.stdout_hist += self.ps1
else:
@@ -1079,7 +1082,8 @@ def prompt(self, more):
self.stdout_hist += self.ps2
else:
self.stdout_hist += self.ps2.encode(getpreferredencoding())
- self.s_hist.append('\x01%s\x03%s\x04' % (prompt_more_color, self.ps2))
+ self.s_hist.append('\x01%s\x03%s\x04' %
+ (prompt_more_color, self.ps2))
def push(self, s, insert_into_history=True):
# curses.raw(True) prevents C-c from causing a SIGINT
@@ -1103,7 +1107,7 @@ def redraw(self):
self.iy, self.ix = self.scr.getyx()
for i in s.split('\x04'):
self.echo(i, redraw=False)
- if k < len(self.s_hist) -1:
+ if k < len(self.s_hist) - 1:
self.scr.addstr('\n')
self.iy, self.ix = self.scr.getyx()
self.print_line(self.s)
@@ -1186,14 +1190,12 @@ def resize(self):
self.statusbar.resize(refresh=False)
self.redraw()
-
def getstdout(self):
"""This method returns the 'spoofed' stdout buffer, for writing to a
file or sending to a pastebin or whatever."""
return self.stdout_hist + '\n'
-
def reevaluate(self):
"""Clear the buffer, redraw the screen and re-evaluate the history"""
@@ -1234,7 +1236,7 @@ def reevaluate(self):
self.evaluating = False
#map(self.push, self.history)
- #^-- That's how simple this method was at first :(
+ # ^-- That's how simple this method was at first :(
def write(self, s):
"""For overriding stdout defaults"""
@@ -1258,7 +1260,6 @@ def write(self, s):
self.echo(s)
self.s_hist.append(s.rstrip())
-
def show_list(self, items, arg_pos, topline=None, formatter=None, current_item=None):
shared = Struct()
@@ -1345,7 +1346,7 @@ def lsize():
self.list_win.resize(rows + 2, w)
else:
docstring = self.format_docstring(self.docstring, max_w - 2,
- max_h - height_offset)
+ max_h - height_offset)
docstring_string = ''.join(docstring)
rows += len(docstring)
self.list_win.resize(rows, max_w)
@@ -1445,7 +1446,7 @@ def tab(self, back=False):
# 3. check to see if we can expand the current word
if self.matches_iter.is_cseq():
- #TODO resolve this error-prone situation:
+ # TODO resolve this error-prone situation:
# can't assign at same time to self.s and self.cursor_offset
# because for cursor_offset
# property to work correctly, self.s must already be set
@@ -1458,7 +1459,7 @@ def tab(self, back=False):
# 4. swap current word for a match list item
elif self.matches_iter.matches:
current_match = back and self.matches_iter.previous() \
- or next(self.matches_iter)
+ or next(self.matches_iter)
try:
self.show_list(self.matches_iter.matches, self.arg_pos,
topline=self.funcprops,
@@ -1500,7 +1501,7 @@ def send_current_line_to_editor(self):
return ''
self.f_string = ''
- self.cpos = -1 # Set cursor position to -1 to prevent paren matching
+ self.cpos = -1 # Set cursor position to -1 to prevent paren matching
self.iy, self.ix = self.scr.getyx()
self.evaluating = True
@@ -1531,6 +1532,7 @@ def send_current_line_to_editor(self):
self.scr.redrawwin()
return ''
+
class Statusbar(object):
"""This class provides the status bar at the bottom of the screen.
It has message() and prompt() methods for user interactivity, as
@@ -1687,7 +1689,7 @@ def clear(self):
def init_wins(scr, config):
"""Initialise the two windows (the main repl interface and the little
status bar at the bottom with some stuff in it)"""
- #TODO: Document better what stuff is on the status bar.
+ # TODO: Document better what stuff is on the status bar.
background = get_colpair(config, 'background')
h, w = gethw()
@@ -1719,11 +1721,13 @@ def sigwinch(unused_scr):
global DO_RESIZE
DO_RESIZE = True
+
def sigcont(unused_scr):
sigwinch(unused_scr)
# Forces the redraw
curses.ungetch('\x00')
+
def gethw():
"""I found this code on a usenet post, and snipped out the bit I needed,
so thanks to whoever wrote that, sorry I forgot your name, I'm sure you're
@@ -1761,7 +1765,8 @@ def gethw():
sizex = right - left + 1
sizey = bottom - top + 1
else:
- sizex, sizey = stdscr.getmaxyx()# can't determine actual size - return default values
+ # can't determine actual size - return default values
+ sizex, sizey = stdscr.getmaxyx()
h, w = sizey, sizex
return h, w
@@ -1796,7 +1801,7 @@ def do_resize(caller):
global DO_RESIZE
h, w = gethw()
if not h:
- # Hopefully this shouldn't happen. :)
+ # Hopefully this shouldn't happen. :)
return
curses.endwin()
@@ -1878,7 +1883,8 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
old_sigwinch_handler = signal.signal(signal.SIGWINCH,
lambda *_: sigwinch(scr))
# redraw window after being suspended
- old_sigcont_handler = signal.signal(signal.SIGCONT, lambda *_: sigcont(scr))
+ old_sigcont_handler = signal.signal(
+ signal.SIGCONT, lambda *_: sigcont(scr))
stdscr = scr
try:
@@ -1951,7 +1957,6 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
def main(args=None, locals_=None, banner=None):
translations.init()
-
config, options, exec_args = argsparse(args)
# Save stdin, stdout and stderr for later restoration
@@ -1975,6 +1980,7 @@ def main(args=None, locals_=None, banner=None):
sys.stdout.flush()
return repl.extract_exit_value(exit_value)
+
if __name__ == '__main__':
sys.exit(main())
diff --git a/bpython/config.py b/bpython/config.py
index a30e76c9b..a3cca3bc1 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -183,7 +183,8 @@ def get_key_no_doublebind(command):
struct.hist_length = config.getint('general', 'hist_length')
struct.hist_duplicates = config.getboolean('general', 'hist_duplicates')
struct.flush_output = config.getboolean('general', 'flush_output')
- struct.default_autoreload = config.getboolean('general', 'default_autoreload')
+ struct.default_autoreload = config.getboolean(
+ 'general', 'default_autoreload')
struct.pastebin_key = get_key_no_doublebind('pastebin')
struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard')
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 7af127d9f..792f20b1c 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -139,7 +139,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
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]
diff --git a/bpython/importcompletion.py b/bpython/importcompletion.py
index b8dc1964c..5dbe76a6d 100644
--- a/bpython/importcompletion.py
+++ b/bpython/importcompletion.py
@@ -205,4 +205,5 @@ def reload():
for _ in find_all_modules():
pass
+
find_iterator = find_all_modules()
diff --git a/bpython/line.py b/bpython/line.py
index 3a6806647..6456073f0 100644
--- a/bpython/line.py
+++ b/bpython/line.py
@@ -15,8 +15,8 @@
LinePart = namedtuple('LinePart', ['start', 'stop', 'word'])
current_word_re = LazyReCompile(
- r'(?' % len(self.bpython_history)
self.bpython_history.append((len(source), None,
- source.splitlines(True), filename))
+ source.splitlines(True), filename))
return filename
def __getitem__(self, key):
diff --git a/bpython/repl.py b/bpython/repl.py
index 88a9b6e19..4439d71eb 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -61,6 +61,7 @@
class RuntimeTimer(object):
"""Calculate running time"""
+
def __init__(self):
self.reset_timer()
self.time = time.monotonic if hasattr(time, 'monotonic') else time.time
@@ -153,7 +154,8 @@ def runsource(self, source, filename=None, symbol='single',
if encode and filename is not None:
# files have encoding comments or implicit encoding of ASCII
if encode != 'auto':
- raise ValueError("shouldn't add encoding line to file contents")
+ raise ValueError(
+ "shouldn't add encoding line to file contents")
encode = False
if encode and not py3 and isinstance(source, str):
@@ -622,7 +624,7 @@ def get_args(self):
try:
fake_cursor = self.current_line.index(func) + len(func)
f = simpleeval.evaluate_current_attribute(
- fake_cursor, self.current_line, self.interp.locals)
+ fake_cursor, self.current_line, self.interp.locals)
except simpleeval.EvaluationError:
return False
except Exception:
diff --git a/bpython/simpleeval.py b/bpython/simpleeval.py
index b4934fb66..51b50e7ac 100644
--- a/bpython/simpleeval.py
+++ b/bpython/simpleeval.py
@@ -197,7 +197,7 @@ def evaluate_current_expression(cursor_offset, line, namespace=None):
temp_line = line[:cursor_offset] + 'xxx' + line[cursor_offset:]
temp_cursor = cursor_offset + 3
temp_attribute = line_properties.current_expression_attribute(
- temp_cursor, temp_line)
+ temp_cursor, temp_line)
if temp_attribute is None:
raise EvaluationError("No current attribute")
attr_before_cursor = temp_line[temp_attribute.start:temp_cursor]
@@ -218,7 +218,7 @@ def parse_trees(cursor_offset, line):
if largest_ast is None:
raise EvaluationError(
- "Corresponding ASTs to right of cursor are invalid")
+ "Corresponding ASTs to right of cursor are invalid")
try:
return simple_eval(largest_ast, namespace)
except ValueError:
@@ -238,7 +238,7 @@ def evaluate_current_attribute(cursor_offset, line, namespace=None):
return getattr(obj, attr.word)
except AttributeError:
raise EvaluationError(
- "can't lookup attribute %s on %r" % (attr.word, obj))
+ "can't lookup attribute %s on %r" % (attr.word, obj))
def safe_get_attribute(obj, attr):
@@ -255,6 +255,8 @@ def safe_get_attribute(obj, attr):
class _ClassWithSlots(object):
__slots__ = ['a']
+
+
member_descriptor = type(_ClassWithSlots.a)
diff --git a/bpython/urwid.py b/bpython/urwid.py
index acb153a27..f671dce7d 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -73,15 +73,15 @@
COLORMAP = {
'k': 'black',
- 'r': 'dark red', # or light red?
- 'g': 'dark green', # or light green?
+ 'r': 'dark red', # or light red?
+ 'g': 'dark green', # or light green?
'y': 'yellow',
- 'b': 'dark blue', # or light blue?
- 'm': 'dark magenta', # or light magenta?
- 'c': 'dark cyan', # or light cyan?
+ 'b': 'dark blue', # or light blue?
+ 'm': 'dark magenta', # or light magenta?
+ 'c': 'dark cyan', # or light cyan?
'w': 'white',
'd': 'default',
- }
+}
try:
@@ -104,7 +104,6 @@ def lineReceived(self, line):
self.repl.main_loop.process_input(line)
self.repl.main_loop.process_input(['enter'])
-
class EvalFactory(protocol.ServerFactory):
def __init__(self, myrepl):
@@ -171,8 +170,10 @@ def keypress(self, size, key):
else:
return urwid.Edit.keypress(self, size, key)
+
urwid.register_signal(StatusbarEdit, 'prompt_enter')
+
class Statusbar(object):
"""Statusbar object, ripped off from bpython.cli.
@@ -261,7 +262,7 @@ def settext(self, s, permanent=False):
self.text.set_text(('main', s))
if permanent:
- self.s = s
+ self.s = s
def clear(self):
"""Clear the status bar."""
@@ -273,6 +274,7 @@ def _on_prompt_enter(self, edit, new_text):
self.settext(self.s)
urwid.emit_signal(self, 'prompt_result', new_text)
+
urwid.register_signal(Statusbar, 'prompt_result')
@@ -288,6 +290,7 @@ def decoding_input_filter(keys, raw):
converted_keys.append(key)
return converted_keys
+
def format_tokens(tokensource):
for token, text in tokensource:
if text == '\n':
@@ -450,15 +453,18 @@ def mouse_event(self, *args):
finally:
self._bpy_may_move_cursor = False
+
class BPythonListBox(urwid.ListBox):
"""Like `urwid.ListBox`, except that it does not eat up and
down keys.
"""
+
def keypress(self, size, key):
if key not in ["up", "down"]:
return urwid.ListBox.keypress(self, size, key)
return key
+
class Tooltip(urwid.BoxWidget):
"""Container inspired by Overlay to position our tooltip.
@@ -540,6 +546,7 @@ def render(self, size, focus=False):
canvas.cursor = cursor
return canvas
+
class URWIDInteraction(repl.Interaction):
def __init__(self, config, statusbar, frame):
repl.Interaction.__init__(self, config, statusbar)
@@ -582,7 +589,7 @@ def _prompt_result(self, text):
class URWIDRepl(repl.Repl):
- _time_between_redraws = .05 # seconds
+ _time_between_redraws = .05 # seconds
def __init__(self, event_loop, palette, interpreter, config):
repl.Repl.__init__(self, interpreter, config)
@@ -613,12 +620,13 @@ def __init__(self, event_loop, palette, interpreter, config):
# 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)
+ _(" <%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.interact = URWIDInteraction(
+ self.config, self.statusbar, self.frame)
self.edits = []
self.edit = None
@@ -692,10 +700,11 @@ def _get_current_line(self):
if self.edit is None:
return ''
return self.edit.get_edit_text()
+
def _set_current_line(self, line):
self.edit.set_edit_text(line)
current_line = property(_get_current_line, _set_current_line, None,
- "Return the current line (the one the cursor is in).")
+ "Return the current line (the one the cursor is in).")
def cw(self):
"""Return the current word (incomplete word left of cursor)."""
@@ -710,7 +719,7 @@ def cw(self):
# Stolen from cli. TODO: clean up and split out.
if (not text or
- (not text[-1].isalnum() and text[-1] not in ('.', '_'))):
+ (not text[-1].isalnum() and text[-1] not in ('.', '_'))):
return
# Seek backwards in text for the first non-identifier char:
@@ -731,10 +740,11 @@ def cpos(self):
def _get_cursor_offset(self):
return self.edit.edit_pos
+
def _set_cursor_offset(self, offset):
self.edit.edit_pos = offset
cursor_offset = property(_get_cursor_offset, _set_cursor_offset, None,
- "The cursor offset from the beginning of the line")
+ "The cursor offset from the beginning of the line")
def _populate_completion(self):
widget_list = self.tooltip.body
@@ -877,7 +887,8 @@ def reevaluate(self):
if py3:
self.stdout_hist += line + '\n'
else:
- self.stdout_hist += line.encode(locale.getpreferredencoding()) + '\n'
+ self.stdout_hist += line.encode(
+ locale.getpreferredencoding()) + '\n'
self.print_line(line)
self.s_hist[-1] += self.f_string
# I decided it was easier to just do this manually
@@ -898,7 +909,7 @@ def reevaluate(self):
self.evaluating = False
#map(self.push, self.history)
- #^-- That's how simple this method was at first :(
+ # ^-- That's how simple this method was at first :(
def write(self, s):
"""For overriding stdout defaults"""
@@ -922,7 +933,6 @@ def write(self, s):
self.echo(s)
self.s_hist.append(s.rstrip())
-
def push(self, s, insert_into_history=True):
# Restore the original SIGINT handler. This is needed to be able
# to break out of infinite loops. If the interpreter itself
@@ -1061,7 +1071,7 @@ def handle_input(self, event):
self.tab()
elif urwid.command_map[event] == 'prev selectable':
self.tab(True)
- #else:
+ # else:
# self.echo(repr(event))
def tab(self, back=False):
@@ -1116,25 +1126,26 @@ def tab(self, back=False):
finally:
self._completion_update_suppressed = False
+
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).')),
- ]))
+ '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:
@@ -1144,7 +1155,7 @@ def main(args=None, locals_=None, banner=None):
print(' %-4s\t%s' % (r.shortName, r.description))
except ImportError:
sys.stderr.write('No reactors are available. Please install '
- 'twisted for reactor support.\n')
+ 'twisted for reactor support.\n')
return
palette = [
@@ -1152,8 +1163,8 @@ def main(args=None, locals_=None, banner=None):
'bold' if color.isupper() else 'default')
for name, color in iteritems(config.color_scheme)]
palette.extend([
- ('bold ' + name, color + ',bold', background, monochrome)
- for name, color, background, monochrome in palette])
+ ('bold ' + name, color + ',bold', background, monochrome)
+ for name, color, background, monochrome in palette])
if options.server or options.plugin:
options.twisted = True
@@ -1163,7 +1174,7 @@ def main(args=None, locals_=None, banner=None):
from twisted.application import reactors
except ImportError:
sys.stderr.write('No reactors are available. Please install '
- 'twisted for reactor support.\n')
+ 'twisted for reactor support.\n')
return
try:
# XXX why does this not just return the reactor it installed?
@@ -1172,7 +1183,7 @@ def main(args=None, locals_=None, banner=None):
from twisted.internet import reactor
except reactors.NoSuchReactor:
sys.stderr.write('Reactor %s does not exist\n' % (
- options.reactor,))
+ options.reactor,))
return
event_loop = TwistedEventLoop(reactor)
elif options.twisted:
@@ -1180,7 +1191,7 @@ def main(args=None, locals_=None, banner=None):
from twisted.internet import reactor
except ImportError:
sys.stderr.write('No reactors are available. Please install '
- 'twisted for reactor support.\n')
+ 'twisted for reactor support.\n')
return
event_loop = TwistedEventLoop(reactor)
else:
@@ -1196,7 +1207,7 @@ def main(args=None, locals_=None, banner=None):
from twisted.application import service
except ImportError:
sys.stderr.write('No twisted plugins are available. Please install '
- 'twisted for twisted plugin support.\n')
+ 'twisted for twisted plugin support.\n')
return
for plug in plugin.getPlugins(service.IServiceMaker):
@@ -1240,6 +1251,7 @@ def sigint(*args):
# 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
@@ -1252,7 +1264,7 @@ def run_with_screen_before_mainloop():
# 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.stdin = None # FakeStdin(myrepl)
sys.stdout = myrepl
sys.stderr = myrepl
@@ -1317,6 +1329,7 @@ def run_find_coroutine():
sys.stdout.flush()
return repl.extract_exit_value(myrepl.exit_value)
+
def load_urwid_command_map(config):
urwid.command_map[key_dispatch[config.up_one_line_key]] = 'cursor up'
urwid.command_map[key_dispatch[config.down_one_line_key]] = 'cursor down'
@@ -1329,6 +1342,7 @@ def load_urwid_command_map(config):
urwid.command_map[key_dispatch[config.clear_word_key]] = 'clear word'
urwid.command_map[key_dispatch[config.clear_line_key]] = 'clear line'
+
"""
'clear_screen': 'C-l',
'cut_to_buffer': 'C-k',
From ae4a502a443e024bd82ed1a7b88adf8be2068a2c Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 22 May 2018 17:18:23 +0200
Subject: [PATCH 097/864] Test with Python 3.8
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index be708063a..a7e0c7270 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,7 @@ python:
- "3.5"
- "3.6"
- "3.7-dev"
+ - "3.8-dev"
- "pypy"
- "pypy3"
@@ -20,6 +21,7 @@ env:
matrix:
allow_failures:
- python: "3.7-dev"
+ - python: "3.8-dev"
- python: "pypy"
- python: "pypy3"
From 4e3673cc90348ed9e9d9c51b5773e0c307c75472 Mon Sep 17 00:00:00 2001
From: Greg Burek
Date: Thu, 27 Sep 2018 10:41:03 -0700
Subject: [PATCH 098/864] Fix bpython-curses bug when passed an argument
Currently, running `bpython-curses -i file.py` results in:
```
...
File ".local/share/virtualenvs/flask-ex-03Wix3mp/lib/python3.6/site-packages/bpython/cli.py", line 1905, in main_curses
bpython.args.exec_code(interpreter, args)
NameError: name 'bpython' is not defined
```
This PR addresses this error by correctly importing args and using it,
like the curtsies implementation.
---
bpython/cli.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index 2a134d95b..5cd24261e 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -81,6 +81,7 @@
from .translations import _
from . import repl
+from . import args as bpargs
from ._py3compat import py3
from .pager import page
from .args import parse as argsparse
@@ -1914,7 +1915,7 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
if args:
exit_value = ()
try:
- bpython.args.exec_code(interpreter, args)
+ bpargs.exec_code(interpreter, args)
except SystemExit as e:
# The documentation of code.InteractiveInterpreter.runcode claims
# that it reraises SystemExit. However, I can't manage to trigger
From b214afaa44f3c7cffcc5da6b219fa1841963f152 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 27 Sep 2018 20:13:37 +0200
Subject: [PATCH 099/864] Switch to 3.7
---
.travis.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index a7e0c7270..2aad2fcce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ python:
- "3.4"
- "3.5"
- "3.6"
- - "3.7-dev"
+ - "3.7"
- "3.8-dev"
- "pypy"
- "pypy3"
@@ -20,7 +20,6 @@ env:
matrix:
allow_failures:
- - python: "3.7-dev"
- python: "3.8-dev"
- python: "pypy"
- python: "pypy3"
From 94cfb15f55144320ebae64c50dacee5512722f43 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 27 Sep 2018 21:44:41 +0200
Subject: [PATCH 100/864] Fix test with PyPy 3
---
bpython/test/test_interpreter.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/test/test_interpreter.py b/bpython/test/test_interpreter.py
index 48cb8ad55..d25d9d7d2 100644
--- a/bpython/test/test_interpreter.py
+++ b/bpython/test/test_interpreter.py
@@ -67,7 +67,7 @@ def gfunc():
i.runsource('gfunc()')
- if pypy:
+ if pypy and not py3:
global_not_found = "global name 'gfunc' is not defined"
else:
global_not_found = "name 'gfunc' is not defined"
From 725c9b78c3b41a72e75b8e22e10d51e74a59c15d Mon Sep 17 00:00:00 2001
From: Attila Szollosi
Date: Thu, 4 Oct 2018 13:37:58 +0200
Subject: [PATCH 101/864] Revert "Switch to 3.7"
This reverts commit b214afaa44f3c7cffcc5da6b219fa1841963f152.
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 2aad2fcce..a7e0c7270 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ python:
- "3.4"
- "3.5"
- "3.6"
- - "3.7"
+ - "3.7-dev"
- "3.8-dev"
- "pypy"
- "pypy3"
@@ -20,6 +20,7 @@ env:
matrix:
allow_failures:
+ - python: "3.7-dev"
- python: "3.8-dev"
- python: "pypy"
- python: "pypy3"
From 9747551e63250d84b52e4144348b265fc984bbe3 Mon Sep 17 00:00:00 2001
From: Attila Szollosi
Date: Thu, 4 Oct 2018 09:39:37 +0200
Subject: [PATCH 102/864] Merge send_to_stdout and send_to_stderr; fix newline
handling (#744)
---
bpython/curtsiesfrontend/repl.py | 51 ++++++------------------------
bpython/test/test_curtsies_repl.py | 28 ++++++++++++++++
2 files changed, 38 insertions(+), 41 deletions(-)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index c4614a580..d36997a22 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -229,7 +229,7 @@ def readline(self):
value = self.readline_results.pop(0)
else:
value = 'no saved input available'
- self.repl.send_to_stdout(value)
+ self.repl.send_to_stdouterr(value)
return value
@@ -333,7 +333,7 @@ def __init__(self,
if interp is None:
interp = Interp(locals=locals_)
- interp.write = self.send_to_stderr
+ interp.write = self.send_to_stdouterr
if banner is None:
if config.help_key:
banner = (_('Welcome to bpython!') + ' ' +
@@ -393,9 +393,9 @@ def __init__(self,
# filenos match the backing device for libs that expect it,
# but writing to them will do weird things to the display
- self.stdout = FakeOutput(self.coderunner, self.send_to_stdout,
+ self.stdout = FakeOutput(self.coderunner, self.send_to_stdouterr,
fileno=sys.__stdout__.fileno())
- self.stderr = FakeOutput(self.coderunner, self.send_to_stderr,
+ self.stderr = FakeOutput(self.coderunner, self.send_to_stdouterr,
fileno=sys.__stderr__.fileno())
self.stdin = FakeStdin(self.coderunner, self, self.edit_keys)
@@ -1140,27 +1140,16 @@ def clear_current_block(self, remove_from_history=True):
def get_current_block(self):
return '\n'.join(self.buffer + [self.current_line])
- def move_current_stdouterr_line_up(self):
- """Append self.current_stdouterr_line to self.display_lines
- then clean it."""
- self.display_lines.extend(paint.display_linize(
- self.current_stdouterr_line, self.width))
- self.current_stdouterr_line = ''
+ def send_to_stdouterr(self, output):
+ """Send unicode strings or FmtStr to Repl stdout or stderr
- def send_to_stdout(self, output):
- """Send unicode string to Repl stdout"""
+ Must be able to handle FmtStrs because interpreter pass in
+ tracebacks already formatted."""
if not output:
return
lines = output.split('\n')
- if all(not line for line in lines):
- # If the string consist only of newline characters,
- # str.split returns one more empty strings.
- lines = lines[:-1]
logger.debug('display_lines: %r', self.display_lines)
- if lines[0]:
- self.current_stdouterr_line += lines[0]
- else:
- self.move_current_stdouterr_line_up()
+ self.current_stdouterr_line += lines[0]
if len(lines) > 1:
self.display_lines.extend(paint.display_linize(
self.current_stdouterr_line, self.width, blank_line=True))
@@ -1171,26 +1160,6 @@ def send_to_stdout(self, output):
self.current_stdouterr_line = lines[-1]
logger.debug('display_lines: %r', self.display_lines)
- def send_to_stderr(self, error):
- """Send unicode strings or FmtStr to Repl stderr
-
- Must be able to handle FmtStrs because interpreter pass in
- tracebacks already formatted."""
- if not error:
- return
- lines = error.split('\n')
- if all(not line for line in lines):
- # If the string consist only of newline characters,
- # str.split returns one more empty strings.
- lines = lines[:-1]
- if lines[-1]:
- self.current_stdouterr_line += lines[-1]
- else:
- self.move_current_stdouterr_line_up()
- self.display_lines.extend(sum((paint.display_linize(line, self.width,
- blank_line=True)
- for line in lines[:-1]), []))
-
def send_to_stdin(self, line):
if line.endswith('\n'):
self.display_lines.extend(
@@ -1653,7 +1622,7 @@ def reevaluate(self, insert_into_history=False):
if not self.weak_rewind:
self.interp = self.interp.__class__()
- self.interp.write = self.send_to_stderr
+ self.interp.write = self.send_to_stdouterr
self.coderunner.interp = self.interp
self.initialize_interp()
diff --git a/bpython/test/test_curtsies_repl.py b/bpython/test/test_curtsies_repl.py
index e91fff022..330ed02d2 100644
--- a/bpython/test/test_curtsies_repl.py
+++ b/bpython/test/test_curtsies_repl.py
@@ -264,6 +264,34 @@ def test_interactive(self):
self.assertEqual(out.getvalue(), '0.5\n0.5\n')
+class TestStdOutErr(TestCase):
+ def setUp(self):
+ self.repl = create_repl()
+
+ def test_newline(self):
+ self.repl.send_to_stdouterr('\n\n')
+ self.assertEqual(self.repl.display_lines[-2], '')
+ self.assertEqual(self.repl.display_lines[-1], '')
+ self.assertEqual(self.repl.current_stdouterr_line, '')
+
+ def test_leading_newline(self):
+ self.repl.send_to_stdouterr('\nfoo\n')
+ self.assertEqual(self.repl.display_lines[-2], '')
+ self.assertEqual(self.repl.display_lines[-1], 'foo')
+ self.assertEqual(self.repl.current_stdouterr_line, '')
+
+ def test_no_trailing_newline(self):
+ self.repl.send_to_stdouterr('foo')
+ self.assertEqual(self.repl.current_stdouterr_line, 'foo')
+
+ def test_print_without_newline_then_print_with_leading_newline(self):
+ self.repl.send_to_stdouterr('foo')
+ self.repl.send_to_stdouterr('\nbar\n')
+ self.assertEqual(self.repl.display_lines[-2], 'foo')
+ self.assertEqual(self.repl.display_lines[-1], 'bar')
+ self.assertEqual(self.repl.current_stdouterr_line, '')
+
+
class TestPredictedIndent(TestCase):
def setUp(self):
self.repl = create_repl()
From f1acdc13550d2c569288e3a8444da587fbd7ac0e Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Fri, 5 Oct 2018 13:38:45 +0200
Subject: [PATCH 103/864] Update changelog
---
CHANGELOG | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 44db01884..cca433008 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,11 +11,11 @@ New features:
Fixes:
* Fix file locking on Windows.
* Exit gracefully if config file fails to be loaded due to encoding errors.
+* #744: Fix newline handling.
+ Thanks to Attila Szöllősi.
Support for Python 3.3 has been dropped.
-Fixes:
-
0.17.1
------
@@ -43,7 +43,7 @@ Fixes:
* #654: Do not modify history file during tests.
* #658: Fix newline handling.
Thanks to Attila Szöllősi.
-* #670: Fix handlign of ANSI escape codes.
+* #670: Fix handling of ANSI escape codes.
Thanks to Attila Szöllősi.
* #687: Fix encoding of jedi completions.
@@ -60,8 +60,8 @@ Fixes:
Thanks to Aditya Gupta.
* #614: Fix issues when view source.
Thanks to Daniel Hahler.
-* #625: Fix issues when runnings scripts with non-ASCII characters.
-* #639: Fix compatbility issues with pdb++.
+* #625: Fix issues when running scripts with non-ASCII characters.
+* #639: Fix compatibility issues with pdb++.
Thanks to Daniel Hahler.
Support for Python 2.6 has been dropped.
From f363204db91d793f7953aaf1ba728dfa7556f832 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 27 Nov 2018 20:26:27 +0100
Subject: [PATCH 104/864] Enable 3.7 again since it got released
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index a7e0c7270..a6e6bfbde 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ python:
- "3.4"
- "3.5"
- "3.6"
- - "3.7-dev"
+ - "3.7"
- "3.8-dev"
- "pypy"
- "pypy3"
@@ -20,7 +20,7 @@ env:
matrix:
allow_failures:
- - python: "3.7-dev"
+ - python: "3.7"
- python: "3.8-dev"
- python: "pypy"
- python: "pypy3"
From 167c5621b77033dd10d8c17ee40b8c34d4188d61 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 27 Nov 2018 20:50:34 +0100
Subject: [PATCH 105/864] travis: Use xenial
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index a6e6bfbde..d92366bea 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
language: python
sudo: false
+dist: xenial
notifications:
webhooks:
- secure: "QXcEHVnOi5mZpONkHSu1tydj8EK3G7xJ7Wv/WYhJ5soNUpEJgi6YwR1WcxSjo7qyi8hTL+4jc+ID0TpKDeS1lpXF41kG9xf5kdxw5OL0EnMkrP9okUN0Ip8taEhd8w+6+dGmfZrx2nXOg1kBU7W5cE90XYqEtNDVXXgNeilT+ik="
From 1d198efc01431e41618b056aa35c783e6f4f3693 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 27 Nov 2018 20:58:43 +0100
Subject: [PATCH 106/864] travis: remove 3.7 from allowed_failures
---
.travis.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index d92366bea..2ae9ef4a4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,6 @@ env:
matrix:
allow_failures:
- - python: "3.7"
- python: "3.8-dev"
- python: "pypy"
- python: "pypy3"
From ac473c3c9f15d04c897b82b480a2d1b78a97e916 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 00:47:43 +0100
Subject: [PATCH 107/864] Remove unnecessary import
---
bpython/urwid.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/bpython/urwid.py b/bpython/urwid.py
index f671dce7d..8d575dc61 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -141,7 +141,6 @@ def wrapper(*args, **kwargs):
except:
# This is the same as in urwid.
# We are obviously not supposed to ever hit this.
- import sys
print(sys.exc_info())
self._exc_info = sys.exc_info()
self.reactor.crash()
From 146be274410efa6fd3b8d1807d9dcea20befe309 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 00:49:36 +0100
Subject: [PATCH 108/864] Avoid unsafe default argument
---
bpython/test/test_repl.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/test/test_repl.py b/bpython/test/test_repl.py
index 67a7d37a2..532ee5865 100644
--- a/bpython/test/test_repl.py
+++ b/bpython/test/test_repl.py
@@ -22,7 +22,7 @@
def setup_config(conf):
config_struct = config.Struct()
config.loadini(config_struct, TEST_CONFIG)
- if 'autocomplete_mode' in conf:
+ if conf is not None and 'autocomplete_mode' in conf:
config_struct.autocomplete_mode = conf['autocomplete_mode']
return config_struct
@@ -37,7 +37,7 @@ def reset(self):
class FakeRepl(repl.Repl):
- def __init__(self, conf={}):
+ def __init__(self, conf=None):
repl.Repl.__init__(self, repl.Interpreter(), setup_config(conf))
self.current_line = ""
self.cursor_offset = 0
From d3a33e77d9197282542ea5462f27078f6c218c6b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 00:51:31 +0100
Subject: [PATCH 109/864] Avoid unsafe default argument
---
bpython/__init__.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/bpython/__init__.py b/bpython/__init__.py
index a4f3bcc37..779a1a682 100644
--- a/bpython/__init__.py
+++ b/bpython/__init__.py
@@ -33,6 +33,9 @@
package_dir = os.path.abspath(os.path.dirname(__file__))
-def embed(locals_=None, args=['-i', '-q'], banner=None):
+def embed(locals_=None, args=None, banner=None):
+ if args is None:
+ args = ['-i', '-q']
+
from .curtsies import main
return main(args, locals_, banner)
From 8e6f8f78e1840111f789cd8691bd45f9570a0358 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 00:52:05 +0100
Subject: [PATCH 110/864] Remove unused import
---
bpython/repl.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index 4439d71eb..cf87ad097 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -31,7 +31,6 @@
import os
import pkgutil
import pydoc
-import re
import shlex
import subprocess
import sys
From 1660fa5301f406c2c7c479c2332cf68b70dd763c Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 01:05:40 +0100
Subject: [PATCH 111/864] Update naming
---
bpython/curtsiesfrontend/replpainter.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index 36c9c1324..46c07458b 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -56,7 +56,7 @@ def paginate(rows, matches, current, words_wide):
return matches[per_page * current_page:per_page * (current_page + 1)]
-def matches_lines(rows, columns, matches, current, config, format):
+def matches_lines(rows, columns, matches, current, config, match_format):
highlight_color = func_for_letter(config.color_scheme['operator'].lower())
if not matches:
@@ -64,22 +64,22 @@ def matches_lines(rows, columns, matches, current, config, format):
color = func_for_letter(config.color_scheme['main'])
max_match_width = max(len(m) for m in matches)
words_wide = max(1, (columns - 1) // (max_match_width + 1))
- matches = [format(m) for m in matches]
+ matches = [match_format(m) for m in matches]
if current:
- current = format(current)
+ current = match_format(current)
matches = paginate(rows, matches, current, words_wide)
- matches_lines = [fmtstr(' ').join(color(m.ljust(max_match_width))
- if m != current
- else highlight_color(
- m.ljust(max_match_width))
- for m in matches[i:i + words_wide])
+ result = [fmtstr(' ').join(color(m.ljust(max_match_width))
+ if m != current
+ else highlight_color(
+ m.ljust(max_match_width))
+ for m in matches[i:i + words_wide])
for i in range(0, len(matches), words_wide)]
logger.debug('match: %r' % current)
- logger.debug('matches_lines: %r' % matches_lines)
- return matches_lines
+ logger.debug('matches_lines: %r' % result)
+ return result
def formatted_argspec(funcprops, arg_pos, columns, config):
@@ -175,7 +175,7 @@ def formatted_docstring(docstring, columns, config):
def paint_infobox(rows, columns, matches, funcprops, arg_pos, match, docstring,
- config, format):
+ config, match_format):
"""Returns painted completions, funcprops, match, docstring etc."""
if not (rows and columns):
return fsarray(0, 0)
@@ -185,7 +185,7 @@ def paint_infobox(rows, columns, matches, funcprops, arg_pos, match, docstring,
from_doc = (formatted_docstring(docstring, width, config)
if docstring else [])
from_matches = (matches_lines(max(1, rows - len(from_argspec) - 2),
- width, matches, match, config, format)
+ width, matches, match, config, match_format)
if matches else [])
lines = from_argspec + from_matches + from_doc
From 3bd1c256525775d469653c12ae3cdd0d6f6a600d Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 10 Dec 2018 01:07:05 +0100
Subject: [PATCH 112/864] Remove unused function
---
bpython/history.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/bpython/history.py b/bpython/history.py
index bd9301b03..ae9c31628 100644
--- a/bpython/history.py
+++ b/bpython/history.py
@@ -165,12 +165,6 @@ def enter(self, line):
if self.index == 0:
self.saved_line = line
- @classmethod
- def from_filename(cls, filename):
- history = cls()
- history.load(filename)
- return history
-
def reset(self):
self.index = 0
self.saved_line = ''
From 68df142edb1f9adb0b348374277211e1802de39c Mon Sep 17 00:00:00 2001
From: benkrig
Date: Wed, 9 Jan 2019 19:41:03 -0800
Subject: [PATCH 113/864] fix exit code issue
---
bpython/curtsiesfrontend/coderunner.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index 647a7dca1..f9cd19589 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -183,7 +183,7 @@ def _blocking_run_code(self):
try:
unfinished = self.interp.runsource(self.source)
except SystemExit as e:
- return SystemExitRequest(e.args)
+ return SystemExitRequest(*e.args)
return Unfinished() if unfinished else Done()
def request_from_main_context(self, force_refresh=False):
From 42ae73040ec6faa7b82d487f53d34132588ee6e7 Mon Sep 17 00:00:00 2001
From: Thomas Ballinger
Date: Sun, 3 Mar 2019 15:54:01 -0800
Subject: [PATCH 114/864] Fix 767 by using correct function
---
bpython/curtsiesfrontend/replpainter.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/curtsiesfrontend/replpainter.py b/bpython/curtsiesfrontend/replpainter.py
index 46c07458b..5dd7d92ea 100644
--- a/bpython/curtsiesfrontend/replpainter.py
+++ b/bpython/curtsiesfrontend/replpainter.py
@@ -5,7 +5,7 @@
import itertools
from six.moves import range
-from curtsies import fsarray, fmtstr
+from curtsies import fsarray, fmtstr, FSArray
from curtsies.formatstring import linesplit
from curtsies.fmtfuncs import bold
@@ -178,7 +178,7 @@ def paint_infobox(rows, columns, matches, funcprops, arg_pos, match, docstring,
config, match_format):
"""Returns painted completions, funcprops, match, docstring etc."""
if not (rows and columns):
- return fsarray(0, 0)
+ return FSArray(0, 0)
width = columns - 4
from_argspec = (formatted_argspec(funcprops, arg_pos, width, config)
if funcprops else [])
From 3f1caba7faf4efab7a4157b22f9b6ea632099564 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 2 Apr 2019 21:46:42 +0200
Subject: [PATCH 115/864] Update changelog
---
CHANGELOG | 3 +++
1 file changed, 3 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index cca433008..92e913568 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,9 @@ Fixes:
* Exit gracefully if config file fails to be loaded due to encoding errors.
* #744: Fix newline handling.
Thanks to Attila Szöllősi.
+* #731: Fix exit code.
+ Thanks to benkrig.
+* #767: Fix crash when matching certain lines in history.
Support for Python 3.3 has been dropped.
From bcf70785dd90a03b8db6eca26d789d7ed629752d Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 2 Apr 2019 21:53:14 +0200
Subject: [PATCH 116/864] Start development of 0.19
---
CHANGELOG | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 92e913568..6be4f3959 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,13 @@
Changelog
=========
+0.19
+----
+
+New features:
+
+Fixes:
+
0.18
----
From 286fd3612b1c6104ff24fa84ebb045684bf5c57b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 2 Apr 2019 21:53:32 +0200
Subject: [PATCH 117/864] Point back to master
---
README.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.rst b/README.rst
index 961e55c39..ed68c8cbc 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
|ImageLink|_
-.. |ImageLink| image:: https://travis-ci.org/bpython/bpython.svg?branch=bugfix-0.17
+.. |ImageLink| image:: https://travis-ci.org/bpython/bpython.svg?branch=master
.. _ImageLink: https://travis-ci.org/bpython/bpython
***********************************************************************
From a9407b643ceb4268611fd31cd83b2d0b57df0a28 Mon Sep 17 00:00:00 2001
From: Benedikt Rascher-Friesenhausen
Date: Sat, 16 Feb 2019 11:07:51 +0100
Subject: [PATCH 118/864] Display the correct signature for a decorated
function in Python 3
This patch changes it so that `inspect.signature` is used instead of
`inspect.getfullargspec` to get a function's signature, when using Python 3.
Python 3.3 introduced the `inspect.signature` function as a new way to get the
signature of a function (as an alternative to `inspect.getargspec` and
`inspect.getfullargspec`). `inspect.signature` has the advantage that it
preserves the signature of a decorated function if `functools.wraps` is used to
decorated the wrapper function. Having a function's signature available is very
hepful, especially when testing things out in a REPL.
---
bpython/inspection.py | 54 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 3 deletions(-)
diff --git a/bpython/inspection.py b/bpython/inspection.py
index 10b7db761..5817fac08 100644
--- a/bpython/inspection.py
+++ b/bpython/inspection.py
@@ -250,11 +250,10 @@ def getfuncprops(func, f):
return None
try:
if py3:
- argspec = inspect.getfullargspec(f)
+ argspec = get_argspec_from_signature(f)
else:
- argspec = inspect.getargspec(f)
+ argspec = list(inspect.getargspec(f))
- argspec = list(argspec)
fixlongargs(f, argspec)
if len(argspec) == 4:
argspec = argspec + [list(), dict(), None]
@@ -284,6 +283,55 @@ def is_callable(obj):
return callable(obj)
+def get_argspec_from_signature(f):
+ """Get callable signature from inspect.signature in argspec format.
+
+ inspect.signature is a Python 3 only function that returns the signature of
+ a function. Its advantage over inspect.getfullargspec is that it returns
+ the signature of a decorated function, if the wrapper function itself is
+ decorated with functools.wraps.
+
+ """
+ args = []
+ varargs = varkwargs = None
+ defaults = []
+ kwonly = []
+ kwonly_defaults = {}
+ annotations = {}
+
+ signature = inspect.signature(f)
+ for parameter in signature.parameters.values():
+ if parameter.annotation is not inspect._empty:
+ annotations[parameter.name] = parameter.annotation
+
+ if parameter.kind == inspect._ParameterKind.POSITIONAL_OR_KEYWORD:
+ args.append(parameter.name)
+ if parameter.default is not inspect._empty:
+ defaults.append(parameter.default)
+ elif parameter.kind == inspect._ParameterKind.POSITIONAL_ONLY:
+ args.append(parameter.name)
+ elif parameter.kind == inspect._ParameterKind.VAR_POSITIONAL:
+ varargs = parameter.name
+ elif parameter.kind == inspect._ParameterKind.KEYWORD_ONLY:
+ kwonly.append(parameter.name)
+ kwonly_defaults[parameter.name] = parameter.default
+ elif parameter.kind == inspect._ParameterKind.VAR_KEYWORD:
+ varkwargs = parameter.name
+
+ # inspect.getfullargspec returns None for 'defaults', 'kwonly_defaults' and
+ # 'annotations' if there are no values for them.
+ if not defaults:
+ defaults = None
+
+ if not kwonly_defaults:
+ kwonly_defaults = None
+
+ if not annotations:
+ annotations = None
+
+ return [args, varargs, varkwargs, defaults, kwonly, kwonly_defaults, annotations]
+
+
get_encoding_line_re = LazyReCompile(r'^.*coding[:=]\s*([-\w.]+).*$')
From 0a5bd6e84e10bb414db2ca23854432050a6f630b Mon Sep 17 00:00:00 2001
From: Benedikt Rascher-Friesenhausen
Date: Sat, 16 Feb 2019 11:45:37 +0100
Subject: [PATCH 119/864] Correctly reference inspect parameter kinds
Instead of referencing parameter kinds as class attributes on the private
`_ParameterKind` class we reference them on the public `Parameter` class. This
has two advantages:
1) We don't use a private interface.
2) The class attributes on `_ParameterKind` have only been added in Python 3.5,
but on `Parameter` they have existed since Python 3.3.
---
bpython/inspection.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/bpython/inspection.py b/bpython/inspection.py
index 5817fac08..410ac3173 100644
--- a/bpython/inspection.py
+++ b/bpython/inspection.py
@@ -304,18 +304,18 @@ def get_argspec_from_signature(f):
if parameter.annotation is not inspect._empty:
annotations[parameter.name] = parameter.annotation
- if parameter.kind == inspect._ParameterKind.POSITIONAL_OR_KEYWORD:
+ if parameter.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
args.append(parameter.name)
if parameter.default is not inspect._empty:
defaults.append(parameter.default)
- elif parameter.kind == inspect._ParameterKind.POSITIONAL_ONLY:
+ elif parameter.kind == inspect.Parameter.POSITIONAL_ONLY:
args.append(parameter.name)
- elif parameter.kind == inspect._ParameterKind.VAR_POSITIONAL:
+ elif parameter.kind == inspect.Parameter.VAR_POSITIONAL:
varargs = parameter.name
- elif parameter.kind == inspect._ParameterKind.KEYWORD_ONLY:
+ elif parameter.kind == inspect.Parameter.KEYWORD_ONLY:
kwonly.append(parameter.name)
kwonly_defaults[parameter.name] = parameter.default
- elif parameter.kind == inspect._ParameterKind.VAR_KEYWORD:
+ elif parameter.kind == inspect.Parameter.VAR_KEYWORD:
varkwargs = parameter.name
# inspect.getfullargspec returns None for 'defaults', 'kwonly_defaults' and
From cd6886a5b1ea8651bc9dee686fb82282a66c41d3 Mon Sep 17 00:00:00 2001
From: Benedikt Rascher-Friesenhausen
Date: Sat, 16 Feb 2019 11:50:02 +0100
Subject: [PATCH 120/864] Catch function signature inspection errors for
built-in types
Some built-in functions (e.g. `map`) can't be inspected with
`inspect.getargspec`, `inspect.getfullargspec` or `inspect.signature`. The
exceptions from `inspect.getargspec` and `inspect.getfullargspec` are all caught
in the code, but `inspect.signature` raises a `ValueError` instead of a
`TypeError`. This exception is now also caught.
---
bpython/inspection.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/inspection.py b/bpython/inspection.py
index 410ac3173..49423e45a 100644
--- a/bpython/inspection.py
+++ b/bpython/inspection.py
@@ -259,7 +259,7 @@ def getfuncprops(func, f):
argspec = argspec + [list(), dict(), None]
argspec = ArgSpec(*argspec)
fprops = FuncProps(func, argspec, is_bound_method)
- except (TypeError, KeyError):
+ except (TypeError, KeyError, ValueError):
with AttrCleaner(f):
argspec = getpydocspec(f, func)
if argspec is None:
From 06382d96c314a9fc8f02e9d7830a5b5c165ef8f1 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Tue, 2 Apr 2019 22:24:03 +0200
Subject: [PATCH 121/864] Update changelog
---
CHANGELOG | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 6be4f3959..5e529171e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,8 @@ Changelog
New features:
Fixes:
+* #765: Display correct signature for decorted functions.
+ Thanks to Bendeikt Rascher-Friesenhausen.
0.18
----
From ade9c77625e9ee0d438087ced8940b173a17f17e Mon Sep 17 00:00:00 2001
From: Wis <~@wis.am>
Date: Wed, 1 May 2019 01:48:01 +0300
Subject: [PATCH 122/864] 10x the too low hist_length default of 100 to 1000
I just lost a useful function I wrote that I hoped I could find in the history file.
a utf-8 encoded history file having 1000 lines of code less that 80 columns/characters long less than ~80 kilobytes in size.
or is the concern more about the look up time for autocomplete and the responsiveness of typing?
---
bpython/config.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/config.py b/bpython/config.py
index a3cca3bc1..aca3c2f5b 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -77,7 +77,7 @@ def loadini(struct, configfile):
'highlight_show_source': True,
'hist_duplicates': True,
'hist_file': '~/.pythonhist',
- 'hist_length': 100,
+ 'hist_length': 1000,
'paste_time': 0.02,
'pastebin_confirm': True,
'pastebin_expiry': '1week',
From c6adc1bde38242d867476f58b4bd0771ddfbbb3b Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 22 Sep 2019 22:18:23 +0200
Subject: [PATCH 123/864] Update translations
---
bpython/translations/bpython.pot | 147 +++++++-------
.../translations/de/LC_MESSAGES/bpython.po | 164 ++++++++--------
.../translations/es_ES/LC_MESSAGES/bpython.po | 145 +++++++-------
.../translations/fr_FR/LC_MESSAGES/bpython.po | 180 ++++++++++--------
.../translations/it_IT/LC_MESSAGES/bpython.po | 145 +++++++-------
.../translations/nl_NL/LC_MESSAGES/bpython.po | 145 +++++++-------
6 files changed, 508 insertions(+), 418 deletions(-)
diff --git a/bpython/translations/bpython.pot b/bpython/translations/bpython.pot
index 074e4a475..00f5329a0 100644
--- a/bpython/translations/bpython.pot
+++ b/bpython/translations/bpython.pot
@@ -1,289 +1,302 @@
# Translations template for bpython.
-# Copyright (C) 2015 ORGANIZATION
+# Copyright (C) 2019 ORGANIZATION
# This file is distributed under the same license as the bpython project.
-# FIRST AUTHOR , 2015.
+# FIRST AUTHOR , 2019.
#
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: bpython 0.15.dev98\n"
+"Project-Id-Version: bpython 0.19.dev6\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
"NOTE: If bpython sees an argument it does not know, execution falls back "
"to the regular Python interpreter."
msgstr ""
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr ""
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr ""
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr ""
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr ""
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr ""
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr ""
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr ""
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr ""
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr ""
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr ""
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr ""
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr ""
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
msgstr ""
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr ""
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr ""
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr ""
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr ""
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr ""
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr ""
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr ""
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
msgstr ""
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr ""
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr ""
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr ""
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr ""
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr ""
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr ""
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr ""
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr ""
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr ""
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr ""
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr ""
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr ""
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr ""
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr ""
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr ""
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-#: bpython/repl.py:1032
-msgid "Error editing config file."
+#: bpython/repl.py:1151
+#, python-format
+msgid "Error editing config file: %s"
msgstr ""
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr ""
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr ""
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
msgstr ""
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr ""
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
diff --git a/bpython/translations/de/LC_MESSAGES/bpython.po b/bpython/translations/de/LC_MESSAGES/bpython.po
index 094fab1e5..41a63bdab 100644
--- a/bpython/translations/de/LC_MESSAGES/bpython.po
+++ b/bpython/translations/de/LC_MESSAGES/bpython.po
@@ -7,289 +7,301 @@ msgid ""
msgstr ""
"Project-Id-Version: bpython mercurial\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
-"PO-Revision-Date: 2015-03-24 00:27+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
+"PO-Revision-Date: 2019-09-22 22:21+0200\n"
"Last-Translator: Sebastian Ramacher \n"
+"Language: de\n"
"Language-Team: de \n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
-"Language: de\n"
-"X-Generator: Poedit 1.6.10\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
-"NOTE: If bpython sees an argument it does not know, execution falls back to "
-"the regular Python interpreter."
+"NOTE: If bpython sees an argument it does not know, execution falls back "
+"to the regular Python interpreter."
msgstr ""
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr "Verwende CONFIG antatt der standardmäßigen Konfigurationsdatei."
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr "Verbleibe in bpython nach dem Ausführen der Datei."
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr "Gib Ausgabe beim Beenden nicht ernaut auf stdout aus."
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr "Zeige Versionsinformationen an und beende."
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr "j"
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr "ja"
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr "Rückgängig"
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr "Speichern"
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr "Quellcode anzeigen"
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr ""
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr "Fehler beim Schreiben in Datei %s aufgetreten (%s)"
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr "Hilfsprogramm konnte nicht gefunden werden."
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr "Hilfsprogramm konnte nicht ausgeführt werden."
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
msgstr "Hilfsprogramm beendete mit Status %d."
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr "Keine Ausgabe von Hilfsprogramm vorhanden."
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr "Konnte Ausgabe von Hilfsprogramm nicht verarbeiten."
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr "Kann Quellcode nicht finden: %s"
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr "Kann auf Quellcode nicht zugreifen: %r"
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr "Quellcode für %s nicht gefunden"
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr "In Datei speichern (Esc um abzubrechen): "
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr "Speichern abgebrochen."
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
-msgstr ""
-"%s existiert bereit. (C) abbrechen, (o) überschrieben oder (a) anhängen?"
+msgstr "%s existiert bereit. (C) abbrechen, (o) überschrieben oder (a) anhängen?"
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr "überschreiben"
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr "anhängen"
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr "Fehler beim Schreiben in Datei '%s': %s"
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr "Nach %s gespeichert."
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr "Zwischenablage ist nicht verfügbar."
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr "Konnte nicht in Zwischenablage kopieren."
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr "Inhalt wurde in Zwischenablage kopiert."
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr ""
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr ""
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr ""
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr "Lade Daten hoch..."
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr "Hochladen ist fehlgeschlagen: %s"
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr ""
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr ""
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr "Rückgängigmachen abgebrochen"
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-"Konfigurationsdatei existiert nicht. Soll eine neue Datei erstellt werden? "
-"(j/N)"
+"Konfigurationsdatei existiert nicht. Soll eine neue Datei erstellt "
+"werden? (j/N)"
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
"bpython Konfigurationsdatei bearbeitet. Starte bpython neu damit die "
"Änderungen übernommen werden."
-#: bpython/repl.py:1032
-msgid "Error editing config file."
-msgstr "Fehler beim Bearbeiten der Konfigurationsdatei."
+#: bpython/repl.py:1151
+#, python-format
+msgid "Error editing config file: %s"
+msgstr "Fehler beim Bearbeiten der Konfigurationsdatei: %s"
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr ""
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr ""
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
msgstr ""
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr ""
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr "Willkommen by bpython!"
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr "Drücke <%s> für Hilfe."
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr "Fehler beim Ausführen von PYTHONSTARTUP: %s"
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr "Die Sitzung wurde nicht neu ausgeführt, da sie nicht berabeitet wurde"
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr "Die Sitzung wurde nicht neu ausgeführt, da die gespeicherte Datei leer war"
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr "Sitzung bearbeitet und neu ausgeführt"
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
-msgstr ""
+msgstr "Bei %s vom Benutzer neu geladen."
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
+
diff --git a/bpython/translations/es_ES/LC_MESSAGES/bpython.po b/bpython/translations/es_ES/LC_MESSAGES/bpython.po
index d88ebcc9d..5ede109be 100644
--- a/bpython/translations/es_ES/LC_MESSAGES/bpython.po
+++ b/bpython/translations/es_ES/LC_MESSAGES/bpython.po
@@ -7,285 +7,302 @@ msgid ""
msgstr ""
"Project-Id-Version: bpython 0.9.7\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
"PO-Revision-Date: 2015-02-02 00:34+0100\n"
"Last-Translator: Sebastian Ramacher \n"
+"Language: es_ES\n"
"Language-Team: bpython developers\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
"NOTE: If bpython sees an argument it does not know, execution falls back "
"to the regular Python interpreter."
msgstr ""
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr ""
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr ""
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr ""
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr "s"
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr "si"
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr ""
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr ""
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr ""
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr ""
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr ""
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr ""
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr ""
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
msgstr ""
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr ""
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr ""
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr ""
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr ""
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr ""
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr ""
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr ""
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
msgstr ""
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr ""
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr ""
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr ""
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr ""
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr ""
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr ""
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr ""
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr ""
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr ""
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr ""
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr ""
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr ""
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr ""
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr ""
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr ""
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-#: bpython/repl.py:1032
-msgid "Error editing config file."
+#: bpython/repl.py:1151
+#, python-format
+msgid "Error editing config file: %s"
msgstr ""
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr ""
" <%s> Rewind <%s> Salva <%s> Pastebin <%s> Pager <%s> Mostra el "
"código fuente"
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr ""
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
msgstr ""
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr ""
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
+#~ msgid "Error editing config file."
+#~ msgstr ""
+
diff --git a/bpython/translations/fr_FR/LC_MESSAGES/bpython.po b/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
index cc326c2de..53dd059ba 100644
--- a/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
+++ b/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
@@ -6,295 +6,309 @@ msgid ""
msgstr ""
"Project-Id-Version: bpython 0.13-442\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
"PO-Revision-Date: 2015-03-24 00:29+0100\n"
"Last-Translator: Sebastian Ramacher \n"
+"Language: fr_FR\n"
"Language-Team: bpython developers\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
-"Language: fr_FR\n"
-"X-Generator: Poedit 1.6.10\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
-"NOTE: If bpython sees an argument it does not know, execution falls back to "
-"the regular Python interpreter."
+"NOTE: If bpython sees an argument it does not know, execution falls back "
+"to the regular Python interpreter."
msgstr ""
"Utilisation: %prog [options] [fichier [arguments]]\n"
-"NOTE: Si bpython ne reconnaît pas un des arguments fournis, l'interpréteur "
-"Python classique sera lancé"
+"NOTE: Si bpython ne reconnaît pas un des arguments fournis, "
+"l'interpréteur Python classique sera lancé"
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr "Utiliser CONFIG à la place du fichier de configuration par défaut."
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-"Aller dans le shell bpython après l'exécution du fichier au lieu de quitter."
+"Aller dans le shell bpython après l'exécution du fichier au lieu de "
+"quitter."
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr "Ne pas purger la sortie vers stdout."
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr "Afficher la version et quitter."
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr "o"
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr "oui"
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr "Rembobiner"
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr "Sauvegarder"
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr "Montrer le code source"
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr "logger les messages de debug dans bpython.log"
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr "Une erreur s'est produite pendant l'écriture du fichier %s (%s)"
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr "programme externe non trouvé."
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr "impossible de lancer le programme externe."
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
-msgstr ""
-"le programme externe a renvoyé un statut de sortie différent de zéro %d."
+msgstr "le programme externe a renvoyé un statut de sortie différent de zéro %d."
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr "pas de sortie du programme externe."
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr "la sortie du programme externe ne correspond pas à une URL."
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr "Impossible de récupérer le source: %s"
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr "Impossible d'accéder au source de %r"
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr "Pas de code source trouvé pour %s"
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr ""
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr ""
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
msgstr ""
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr ""
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr ""
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr "Une erreur s'est produite pendant l'écriture du fichier '%s': %s"
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr ""
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr "Pas de presse-papier disponible."
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr "Impossible de copier vers le presse-papier."
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr "Contenu copié vers le presse-papier."
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr "Tampon Pastebin ? (o/N) "
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr "Pastebin abandonné."
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr "Pastebin dupliqué. URL précédente: %s. URL de suppression: %s"
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr "Envoi des donnés à pastebin..."
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr "Echec du téléchargement: %s"
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr "URL Pastebin: %s - URL de suppression: %s"
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr "URL Pastebin: %s"
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr ""
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
-msgstr ""
-"Le fichier de configuration n'existe pas - en créér un par défaut? (o/N)"
+msgstr "Le fichier de configuration n'existe pas - en créér un par défaut? (o/N)"
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-#: bpython/repl.py:1032
-msgid "Error editing config file."
-msgstr ""
+#: bpython/repl.py:1151
+#, fuzzy, python-format
+msgid "Error editing config file: %s"
+msgstr "Une erreur s'est produite pendant l'écriture du fichier '%s': %s"
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr ""
-" <%s> Rebobiner <%s> Sauvegarder <%s> Pastebin <%s> Pager <%s> Montrer "
-"Source "
+" <%s> Rebobiner <%s> Sauvegarder <%s> Pastebin <%s> Pager <%s> "
+"Montrer Source "
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr "Lancer le reactor twisted."
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
-msgstr ""
-"Choisir un reactor spécifique (voir --help-reactors). Nécessite --twisted."
+msgstr "Choisir un reactor spécifique (voir --help-reactors). Nécessite --twisted."
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr "Lister les reactors disponibles pour -r."
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-"plugin twistd à lancer (utiliser twistd pour une list). Utiliser \"--\" pour "
-"donner plus d'options au plugin."
+"plugin twistd à lancer (utiliser twistd pour une list). Utiliser \"--\" "
+"pour donner plus d'options au plugin."
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr "Port pour lancer un server eval (force Twisted)."
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr "Bienvenue dans bpython!"
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr "Appuyer sur <%s> pour de l'aide."
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr "L'exécution de PYTHONSTARTUP a échoué: %s"
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
+
+#~ msgid "Error editing config file."
+#~ msgstr ""
+
diff --git a/bpython/translations/it_IT/LC_MESSAGES/bpython.po b/bpython/translations/it_IT/LC_MESSAGES/bpython.po
index 66cd0d5a5..aaa50c495 100644
--- a/bpython/translations/it_IT/LC_MESSAGES/bpython.po
+++ b/bpython/translations/it_IT/LC_MESSAGES/bpython.po
@@ -7,283 +7,300 @@ msgid ""
msgstr ""
"Project-Id-Version: bpython 0.9.7\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
"PO-Revision-Date: 2015-02-02 00:34+0100\n"
"Last-Translator: Sebastian Ramacher \n"
+"Language: it_IT\n"
"Language-Team: Michele Orrù\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
"NOTE: If bpython sees an argument it does not know, execution falls back "
"to the regular Python interpreter."
msgstr ""
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr ""
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr ""
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr ""
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr "s"
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr "si"
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr ""
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr ""
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr ""
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr ""
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr ""
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr ""
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr ""
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
msgstr ""
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr ""
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr ""
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr ""
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr ""
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr ""
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr ""
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr ""
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
msgstr ""
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr ""
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr ""
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr ""
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr ""
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr ""
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr ""
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr ""
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr ""
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr ""
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr ""
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr ""
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr ""
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr ""
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr ""
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr ""
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-#: bpython/repl.py:1032
-msgid "Error editing config file."
+#: bpython/repl.py:1151
+#, python-format
+msgid "Error editing config file: %s"
msgstr ""
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr " <%s> Rewind <%s> Salva <%s> Pastebin <%s> Pager <%s> Mostra Sorgente"
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr ""
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
msgstr ""
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr ""
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
+#~ msgid "Error editing config file."
+#~ msgstr ""
+
diff --git a/bpython/translations/nl_NL/LC_MESSAGES/bpython.po b/bpython/translations/nl_NL/LC_MESSAGES/bpython.po
index c82908ee7..bd4e52d52 100644
--- a/bpython/translations/nl_NL/LC_MESSAGES/bpython.po
+++ b/bpython/translations/nl_NL/LC_MESSAGES/bpython.po
@@ -7,283 +7,300 @@ msgid ""
msgstr ""
"Project-Id-Version: bpython 0.9.7.1\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
-"POT-Creation-Date: 2015-03-24 00:25+0100\n"
+"POT-Creation-Date: 2019-09-22 22:17+0200\n"
"PO-Revision-Date: 2015-02-02 00:34+0100\n"
"Last-Translator: Sebastian Ramacher \n"
+"Language: nl_NL\n"
"Language-Team: bpython developers\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 1.3\n"
+"Generated-By: Babel 2.6.0\n"
-#: bpython/args.py:59
+#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
"NOTE: If bpython sees an argument it does not know, execution falls back "
"to the regular Python interpreter."
msgstr ""
-#: bpython/args.py:69
+#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
msgstr ""
-#: bpython/args.py:71
+#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-#: bpython/args.py:74
+#: bpython/args.py:78
msgid "Don't flush the output to stdout."
msgstr ""
-#: bpython/args.py:76
+#: bpython/args.py:80
msgid "Print version and exit."
msgstr ""
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "y"
msgstr "j"
-#: bpython/cli.py:318 bpython/urwid.py:557
+#: bpython/cli.py:319 bpython/urwid.py:560
msgid "yes"
msgstr "ja"
-#: bpython/cli.py:1695
+#: bpython/cli.py:1705
msgid "Rewind"
msgstr ""
-#: bpython/cli.py:1696
+#: bpython/cli.py:1706
msgid "Save"
msgstr ""
-#: bpython/cli.py:1697
+#: bpython/cli.py:1707
msgid "Pastebin"
msgstr ""
-#: bpython/cli.py:1698
+#: bpython/cli.py:1708
msgid "Pager"
msgstr ""
-#: bpython/cli.py:1699
+#: bpython/cli.py:1709
msgid "Show Source"
msgstr ""
-#: bpython/curtsies.py:37
+#: bpython/curtsies.py:139
msgid "log debug messages to bpython.log"
msgstr ""
-#: bpython/curtsies.py:39
+#: bpython/curtsies.py:141
msgid "start by pasting lines of a file into session"
msgstr ""
-#: bpython/history.py:228
+#: bpython/history.py:222
#, python-format
msgid "Error occurred while writing to file %s (%s)"
msgstr ""
-#: bpython/paste.py:94
+#: bpython/paste.py:96
msgid "Helper program not found."
msgstr ""
-#: bpython/paste.py:96
+#: bpython/paste.py:98
msgid "Helper program could not be run."
msgstr ""
-#: bpython/paste.py:100
+#: bpython/paste.py:102
#, python-format
msgid "Helper program returned non-zero exit status %d."
msgstr ""
-#: bpython/paste.py:103
+#: bpython/paste.py:105
msgid "No output from helper program."
msgstr ""
-#: bpython/paste.py:109
+#: bpython/paste.py:111
msgid "Failed to recognize the helper program's output as an URL."
msgstr ""
-#: bpython/repl.py:549
+#: bpython/repl.py:672
msgid "Nothing to get source of"
msgstr ""
-#: bpython/repl.py:554
+#: bpython/repl.py:677
#, python-format
msgid "Cannot get source: %s"
msgstr ""
-#: bpython/repl.py:559
+#: bpython/repl.py:682
#, python-format
msgid "Cannot access source of %r"
msgstr ""
-#: bpython/repl.py:561
+#: bpython/repl.py:684
#, python-format
msgid "No source code found for %s"
msgstr ""
-#: bpython/repl.py:694
+#: bpython/repl.py:815
msgid "Save to file (Esc to cancel): "
msgstr ""
-#: bpython/repl.py:696 bpython/repl.py:699 bpython/repl.py:718
+#: bpython/repl.py:817 bpython/repl.py:820 bpython/repl.py:839
msgid "Save cancelled."
msgstr ""
-#: bpython/repl.py:709
+#: bpython/repl.py:830
#, python-format
msgid "%s already exists. Do you want to (c)ancel, (o)verwrite or (a)ppend? "
msgstr ""
-#: bpython/repl.py:713
+#: bpython/repl.py:834
msgid "overwrite"
msgstr ""
-#: bpython/repl.py:715
+#: bpython/repl.py:836
msgid "append"
msgstr ""
-#: bpython/repl.py:727 bpython/repl.py:1022
+#: bpython/repl.py:848 bpython/repl.py:1140
#, python-format
msgid "Error writing file '%s': %s"
msgstr ""
-#: bpython/repl.py:729
+#: bpython/repl.py:850
#, python-format
msgid "Saved to %s."
msgstr ""
-#: bpython/repl.py:735
+#: bpython/repl.py:856
msgid "No clipboard available."
msgstr ""
-#: bpython/repl.py:742
+#: bpython/repl.py:863
msgid "Could not copy to clipboard."
msgstr ""
-#: bpython/repl.py:744
+#: bpython/repl.py:865
msgid "Copied content to clipboard."
msgstr ""
-#: bpython/repl.py:753
+#: bpython/repl.py:874
msgid "Pastebin buffer? (y/N) "
msgstr ""
-#: bpython/repl.py:754
+#: bpython/repl.py:875
msgid "Pastebin aborted."
msgstr ""
-#: bpython/repl.py:761
+#: bpython/repl.py:882
#, python-format
msgid "Duplicate pastebin. Previous URL: %s. Removal URL: %s"
msgstr ""
-#: bpython/repl.py:768
+#: bpython/repl.py:888
msgid "Posting data to pastebin..."
msgstr ""
-#: bpython/repl.py:772
+#: bpython/repl.py:892
#, python-format
msgid "Upload failed: %s"
msgstr ""
-#: bpython/repl.py:780
+#: bpython/repl.py:900
#, python-format
msgid "Pastebin URL: %s - Removal URL: %s"
msgstr ""
-#: bpython/repl.py:783
+#: bpython/repl.py:903
#, python-format
msgid "Pastebin URL: %s"
msgstr ""
-#: bpython/repl.py:817
+#: bpython/repl.py:938
#, python-format
msgid "Undo how many lines? (Undo will take up to ~%.1f seconds) [1]"
msgstr ""
-#: bpython/repl.py:824 bpython/repl.py:828
+#: bpython/repl.py:945 bpython/repl.py:949
msgid "Undo canceled"
msgstr ""
-#: bpython/repl.py:831
+#: bpython/repl.py:952
#, python-format
msgid "Undoing %d line... (est. %.1f seconds)"
msgid_plural "Undoing %d lines... (est. %.1f seconds)"
msgstr[0] ""
msgstr[1] ""
-#: bpython/repl.py:1007
+#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-#: bpython/repl.py:1029
+#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-#: bpython/repl.py:1032
-msgid "Error editing config file."
+#: bpython/repl.py:1151
+#, python-format
+msgid "Error editing config file: %s"
msgstr ""
-#: bpython/urwid.py:619
+#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr " <%s> Rewind <%s> Opslaan <%s> Pastebin <%s> Pager <%s> Toon broncode"
-#: bpython/urwid.py:1128
+#: bpython/urwid.py:1136
msgid "Run twisted reactor."
msgstr ""
-#: bpython/urwid.py:1130
+#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
msgstr ""
-#: bpython/urwid.py:1133
+#: bpython/urwid.py:1141
msgid "List available reactors for -r."
msgstr ""
-#: bpython/urwid.py:1135
+#: bpython/urwid.py:1143
msgid ""
"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
"options to the plugin."
msgstr ""
-#: bpython/urwid.py:1138
+#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:344
+#: bpython/curtsiesfrontend/repl.py:339
msgid "Welcome to bpython!"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:345
+#: bpython/curtsiesfrontend/repl.py:340
#, python-format
msgid "Press <%s> for help."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:565
+#: bpython/curtsiesfrontend/repl.py:643
#, python-format
msgid "Executing PYTHONSTARTUP failed: %s"
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:582
+#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:855
+#: bpython/curtsiesfrontend/repl.py:929
+msgid "Session not reevaluated because it was not edited"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:941
+msgid "Session not reevaluated because saved file was blank"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:950
+msgid "Session edited and reevaluated"
+msgstr ""
+
+#: bpython/curtsiesfrontend/repl.py:960
#, python-format
msgid "Reloaded at %s by user."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:861
+#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:866
+#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
msgstr ""
-#: bpython/curtsiesfrontend/repl.py:871
+#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
+#~ msgid "Error editing config file."
+#~ msgstr ""
+
From a67c2d37ebd941037d1e6cb4e26b8ac4fb1db267 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 22 Sep 2019 22:54:34 +0200
Subject: [PATCH 124/864] Update translations
---
.../translations/de/LC_MESSAGES/bpython.po | 39 +++++++++++--------
.../translations/fr_FR/LC_MESSAGES/bpython.po | 36 ++++++++---------
2 files changed, 38 insertions(+), 37 deletions(-)
diff --git a/bpython/translations/de/LC_MESSAGES/bpython.po b/bpython/translations/de/LC_MESSAGES/bpython.po
index 41a63bdab..fdb8d8bc3 100644
--- a/bpython/translations/de/LC_MESSAGES/bpython.po
+++ b/bpython/translations/de/LC_MESSAGES/bpython.po
@@ -8,22 +8,26 @@ msgstr ""
"Project-Id-Version: bpython mercurial\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
"POT-Creation-Date: 2019-09-22 22:17+0200\n"
-"PO-Revision-Date: 2019-09-22 22:21+0200\n"
+"PO-Revision-Date: 2019-09-22 22:54+0200\n"
"Last-Translator: Sebastian Ramacher \n"
"Language: de\n"
"Language-Team: de \n"
-"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
+"X-Generator: Poedit 2.2.3\n"
#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
-"NOTE: If bpython sees an argument it does not know, execution falls back "
-"to the regular Python interpreter."
+"NOTE: If bpython sees an argument it does not know, execution falls back to the "
+"regular Python interpreter."
msgstr ""
+"Verwendung: %prog [Optionen] [Datei [Argumente]]\n"
+"Hinweis: Wenn bpython Argumente übergeben bekommt, die nicht verstanden werden, "
+"wird der normale Python Interpreter ausgeführt."
#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
@@ -216,14 +220,13 @@ msgstr[1] ""
#: bpython/repl.py:1126
msgid "Config file does not exist - create new from default? (y/N)"
msgstr ""
-"Konfigurationsdatei existiert nicht. Soll eine neue Datei erstellt "
-"werden? (j/N)"
+"Konfigurationsdatei existiert nicht. Soll eine neue Datei erstellt werden? (j/N)"
#: bpython/repl.py:1148
msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
-"bpython Konfigurationsdatei bearbeitet. Starte bpython neu damit die "
-"Änderungen übernommen werden."
+"bpython Konfigurationsdatei bearbeitet. Starte bpython neu damit die Änderungen "
+"übernommen werden."
#: bpython/repl.py:1151
#, python-format
@@ -237,21 +240,23 @@ msgstr ""
#: bpython/urwid.py:1136
msgid "Run twisted reactor."
-msgstr ""
+msgstr "Führe twisted reactor aus."
#: bpython/urwid.py:1138
msgid "Select specific reactor (see --help-reactors). Implies --twisted."
-msgstr ""
+msgstr "Wähle reactor aus (siehe --help-reactors). Impliziert --twisted."
#: bpython/urwid.py:1141
msgid "List available reactors for -r."
-msgstr ""
+msgstr "Liste verfügbare reactors für -r auf."
#: bpython/urwid.py:1143
msgid ""
-"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
-"options to the plugin."
+"twistd plugin to run (use twistd for a list). Use \"--\" to pass further options "
+"to the plugin."
msgstr ""
+"Auszuführendes twistd Plugin (starte twistd für eine Liste). Verwende \"--\" um "
+"Optionen an das Plugin zu übergeben."
#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
@@ -274,7 +279,7 @@ msgstr "Fehler beim Ausführen von PYTHONSTARTUP: %s"
#: bpython/curtsiesfrontend/repl.py:660
#, python-format
msgid "Reloaded at %s because %s modified."
-msgstr ""
+msgstr "Bei %s neugeladen, da %s modifiziert wurde."
#: bpython/curtsiesfrontend/repl.py:929
msgid "Session not reevaluated because it was not edited"
@@ -295,13 +300,13 @@ msgstr "Bei %s vom Benutzer neu geladen."
#: bpython/curtsiesfrontend/repl.py:966
msgid "Auto-reloading deactivated."
-msgstr ""
+msgstr "Automatisches Neuladen deaktiviert."
#: bpython/curtsiesfrontend/repl.py:971
msgid "Auto-reloading active, watching for file changes..."
-msgstr ""
+msgstr "Automatisches Neuladen ist aktiv; beobachte Dateiänderungen..."
#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
-
+"Automatisches Neuladen ist nicht verfügbar da watchdog nicht installiert ist."
diff --git a/bpython/translations/fr_FR/LC_MESSAGES/bpython.po b/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
index 53dd059ba..d16700c75 100644
--- a/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
+++ b/bpython/translations/fr_FR/LC_MESSAGES/bpython.po
@@ -7,25 +7,26 @@ msgstr ""
"Project-Id-Version: bpython 0.13-442\n"
"Report-Msgid-Bugs-To: http://github.com/bpython/bpython/issues\n"
"POT-Creation-Date: 2019-09-22 22:17+0200\n"
-"PO-Revision-Date: 2015-03-24 00:29+0100\n"
+"PO-Revision-Date: 2019-09-22 22:58+0200\n"
"Last-Translator: Sebastian Ramacher \n"
"Language: fr_FR\n"
"Language-Team: bpython developers\n"
-"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
+"X-Generator: Poedit 2.2.3\n"
#: bpython/args.py:63
msgid ""
"Usage: %prog [options] [file [args]]\n"
-"NOTE: If bpython sees an argument it does not know, execution falls back "
-"to the regular Python interpreter."
+"NOTE: If bpython sees an argument it does not know, execution falls back to the "
+"regular Python interpreter."
msgstr ""
"Utilisation: %prog [options] [fichier [arguments]]\n"
-"NOTE: Si bpython ne reconnaît pas un des arguments fournis, "
-"l'interpréteur Python classique sera lancé"
+"NOTE: Si bpython ne reconnaît pas un des arguments fournis, l'interpréteur "
+"Python classique sera lancé"
#: bpython/args.py:73
msgid "Use CONFIG instead of default config file."
@@ -34,8 +35,7 @@ msgstr "Utiliser CONFIG à la place du fichier de configuration par défaut."
#: bpython/args.py:75
msgid "Drop to bpython shell after running file instead of exiting."
msgstr ""
-"Aller dans le shell bpython après l'exécution du fichier au lieu de "
-"quitter."
+"Aller dans le shell bpython après l'exécution du fichier au lieu de quitter."
#: bpython/args.py:78
msgid "Don't flush the output to stdout."
@@ -226,16 +226,16 @@ msgid "bpython config file edited. Restart bpython for changes to take effect."
msgstr ""
#: bpython/repl.py:1151
-#, fuzzy, python-format
+#, python-format
msgid "Error editing config file: %s"
-msgstr "Une erreur s'est produite pendant l'écriture du fichier '%s': %s"
+msgstr ""
#: bpython/urwid.py:622
#, python-format
msgid " <%s> Rewind <%s> Save <%s> Pastebin <%s> Pager <%s> Show Source "
msgstr ""
-" <%s> Rebobiner <%s> Sauvegarder <%s> Pastebin <%s> Pager <%s> "
-"Montrer Source "
+" <%s> Rebobiner <%s> Sauvegarder <%s> Pastebin <%s> Pager <%s> Montrer "
+"Source "
#: bpython/urwid.py:1136
msgid "Run twisted reactor."
@@ -251,11 +251,11 @@ msgstr "Lister les reactors disponibles pour -r."
#: bpython/urwid.py:1143
msgid ""
-"twistd plugin to run (use twistd for a list). Use \"--\" to pass further "
-"options to the plugin."
+"twistd plugin to run (use twistd for a list). Use \"--\" to pass further options "
+"to the plugin."
msgstr ""
-"plugin twistd à lancer (utiliser twistd pour une list). Utiliser \"--\" "
-"pour donner plus d'options au plugin."
+"plugin twistd à lancer (utiliser twistd pour une list). Utiliser \"--\" pour "
+"donner plus d'options au plugin."
#: bpython/urwid.py:1146
msgid "Port to run an eval server on (forces Twisted)."
@@ -308,7 +308,3 @@ msgstr ""
#: bpython/curtsiesfrontend/repl.py:976
msgid "Auto-reloading not available because watchdog not installed."
msgstr ""
-
-#~ msgid "Error editing config file."
-#~ msgstr ""
-
From 54e83c82e55f3c5f8e9336d30db304660fcbb64f Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 3 Oct 2019 18:24:14 +0200
Subject: [PATCH 125/864] Remove assignments to local variables which are never
used
---
bpython/cli.py | 1 -
bpython/repl.py | 2 +-
bpython/urwid.py | 2 --
3 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index 5cd24261e..6c17a2999 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -1298,7 +1298,6 @@ def lsize():
rows += 1
if rows + 2 >= max_h:
- rows = max_h - 2
return False
shared.rows = rows
diff --git a/bpython/repl.py b/bpython/repl.py
index cf87ad097..f86a2366f 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -236,7 +236,7 @@ def showtraceback(self):
l.insert(0, "Traceback (most recent call last):\n")
l[len(l):] = traceback.format_exception_only(t, v)
finally:
- tblist = tb = None
+ pass
self.writetb(l)
diff --git a/bpython/urwid.py b/bpython/urwid.py
index 8d575dc61..a4e215219 100644
--- a/bpython/urwid.py
+++ b/bpython/urwid.py
@@ -1103,8 +1103,6 @@ def tab(self, back=False):
cw = self.current_string() or self.cw()
if not cw:
return True
- else:
- cw = self.matches_iter.current_word
if self.matches_iter.is_cseq():
cursor, text = self.matches_iter.substitute_cseq()
From d7117359858bd312594c935e2efc6571a0097e82 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Thu, 3 Oct 2019 18:29:15 +0200
Subject: [PATCH 126/864] Remove unused imports
---
bpython/config.py | 1 -
bpython/curtsiesfrontend/interpreter.py | 1 -
bpython/importcompletion.py | 3 +--
bpython/simpleeval.py | 2 --
4 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/bpython/config.py b/bpython/config.py
index aca3c2f5b..d9a2147cd 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -10,7 +10,6 @@
from six.moves.configparser import ConfigParser
from .autocomplete import SIMPLE as default_completion, ALL_MODES
-from .keys import cli_key_dispatch as cli_key_dispatch
class Struct(object):
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index e1a484802..c002cc797 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -11,7 +11,6 @@
from bpython.curtsiesfrontend.parse import parse
from bpython.repl import Interpreter as ReplInterpreter
-from bpython.config import getpreferredencoding
default_colors = {
diff --git a/bpython/importcompletion.py b/bpython/importcompletion.py
index 5dbe76a6d..0a243ec98 100644
--- a/bpython/importcompletion.py
+++ b/bpython/importcompletion.py
@@ -32,7 +32,6 @@
import os
import sys
import warnings
-from warnings import catch_warnings
from six.moves import filter
if py3:
@@ -146,7 +145,7 @@ def find_modules(path):
# Workaround for issue #166
continue
try:
- with catch_warnings():
+ with warnings.catch_warnings():
warnings.simplefilter("ignore", ImportWarning)
fo, pathname, _ = imp.find_module(name, [path])
except (ImportError, IOError, SyntaxError):
diff --git a/bpython/simpleeval.py b/bpython/simpleeval.py
index 51b50e7ac..986fcad31 100644
--- a/bpython/simpleeval.py
+++ b/bpython/simpleeval.py
@@ -34,8 +34,6 @@
import inspect
from six import string_types
from six.moves import builtins
-import sys
-import types
from . import line as line_properties
from ._py3compat import py3
From d9402cdc69c91f9f194077afbe29f4639a317259 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Fri, 4 Oct 2019 23:34:28 +0200
Subject: [PATCH 127/864] Call base's __init__
---
bpython/cli.py | 4 ++--
bpython/curtsiesfrontend/events.py | 2 +-
bpython/curtsiesfrontend/interaction.py | 3 +++
bpython/curtsiesfrontend/repl.py | 2 +-
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/bpython/cli.py b/bpython/cli.py
index 6c17a2999..14415a3a6 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -307,7 +307,7 @@ def make_colors(config):
class CLIInteraction(repl.Interaction):
def __init__(self, config, statusbar=None):
- repl.Interaction.__init__(self, config, statusbar)
+ super(CLIInteraction, self).__init__(config, statusbar)
def confirm(self, q):
"""Ask for yes or no and return boolean"""
@@ -328,7 +328,7 @@ def file_prompt(self, s):
class CLIRepl(repl.Repl):
def __init__(self, scr, interp, statusbar, config, idle=None):
- repl.Repl.__init__(self, interp, config)
+ super(CLIRepl, self).__init__(interp, config)
self.interp.writetb = self.writetb
self.scr = scr
self.stdout_hist = '' # native str (bytes in Py2, unicode in Py3)
diff --git a/bpython/curtsiesfrontend/events.py b/bpython/curtsiesfrontend/events.py
index 065a8dc41..b7766fbe0 100644
--- a/bpython/curtsiesfrontend/events.py
+++ b/bpython/curtsiesfrontend/events.py
@@ -27,7 +27,7 @@ class ScheduledRefreshRequestEvent(curtsies.events.ScheduledEvent):
Used to schedule the disappearance of status bar message that only shows
for a few seconds"""
def __init__(self, when):
- self.when = when # time.time() + how long
+ super(ScheduledRefreshRequestEvent, self).__init__(when)
def __repr__(self):
return ("" %
diff --git a/bpython/curtsiesfrontend/interaction.py b/bpython/curtsiesfrontend/interaction.py
index 5505e367f..80d1f45a1 100644
--- a/bpython/curtsiesfrontend/interaction.py
+++ b/bpython/curtsiesfrontend/interaction.py
@@ -27,6 +27,7 @@ class StatusBar(BpythonInteraction):
bpython.Repl code.
"""
def __init__(self,
+ config,
permanent_text="",
request_refresh=lambda: None,
schedule_refresh=lambda when: None):
@@ -47,6 +48,8 @@ def __init__(self,
self.request_refresh = request_refresh
self.schedule_refresh = schedule_refresh
+ super(StatusBar, self).__init__(config)
+
def push_permanent_message(self, msg):
self._message = ''
self.permanent_stack.append(msg)
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index d36997a22..6b415fabd 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -348,7 +348,7 @@ def __init__(self,
self.reevaluating = False
self.fake_refresh_requested = False
- self.status_bar = StatusBar('',
+ self.status_bar = StatusBar(config, '',
request_refresh=self.request_refresh,
schedule_refresh=self.schedule_refresh)
self.edit_keys = edit_keys.mapping_with_config(config, key_dispatch)
From 072576a7a83e7f47458aa994f507cad3a593e402 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Fri, 4 Oct 2019 23:42:40 +0200
Subject: [PATCH 128/864] Use super where possible
---
bpython/curtsies.py | 12 ++++++------
bpython/curtsiesfrontend/interpreter.py | 4 ++--
bpython/formatter.py | 2 +-
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 792f20b1c..92e4c8452 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -58,12 +58,12 @@ def __init__(self, config, locals_, banner, interp=None):
with self.input_generator:
pass # temp hack to get .original_stty
- BaseRepl.__init__(self,
- locals_=locals_,
- config=config,
- banner=banner,
- interp=interp,
- orig_tcattrs=self.input_generator.original_stty)
+ super(FullCurtsiesRepl, self).__init__(
+ locals_=locals_,
+ config=config,
+ banner=banner,
+ interp=interp,
+ orig_tcattrs=self.input_generator.original_stty)
def get_term_hw(self):
return self.window.get_term_hw()
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index c002cc797..139039f5b 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -49,7 +49,7 @@ def __init__(self, color_scheme, **options):
self.f_strings = {}
for k, v in iteritems(color_scheme):
self.f_strings[k] = '\x01%s' % (v,)
- Formatter.__init__(self, **options)
+ super(BPythonFormatter, self).__init__(**options)
def format(self, tokensource, outfile):
o = ''
@@ -68,7 +68,7 @@ def __init__(self, locals=None, encoding=None):
We include an argument for the outfile to pass to the formatter for it
to write to.
"""
- ReplInterpreter.__init__(self, locals, encoding)
+ super(Interp, self).__init__(locals, encoding)
# typically changed after being instantiated
# but used when interpreter used corresponding REPL
diff --git a/bpython/formatter.py b/bpython/formatter.py
index 4d916c626..23bf0ccbd 100644
--- a/bpython/formatter.py
+++ b/bpython/formatter.py
@@ -96,7 +96,7 @@ def __init__(self, color_scheme, **options):
# FIXME: Find a way to make this the inverse of the current
# background colour
self.f_strings[k] += 'I'
- Formatter.__init__(self, **options)
+ super(BPythonFormatter, self).__init__(**options)
def format(self, tokensource, outfile):
o = ''
From 14c17c10ea668b86ff291e51567bd1fbb8d5d921 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sat, 5 Oct 2019 09:45:21 +0200
Subject: [PATCH 129/864] Turn Interpreter into a new-style class
---
bpython/repl.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index f86a2366f..8387f2f22 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -81,7 +81,7 @@ def estimate(self):
return self.running_time - self.last_command
-class Interpreter(code.InteractiveInterpreter):
+class Interpreter(code.InteractiveInterpreter, object):
"""Source code interpreter for use in bpython."""
bpython_input_re = LazyReCompile(r'')
From 57aa616d0a61276f6b87cbb7b96fcd253b7c5bc7 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Sun, 13 Oct 2019 15:39:33 +0200
Subject: [PATCH 130/864] Also protect remaining part of get_args from user
code exceptions (fixes #776)
---
bpython/repl.py | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/bpython/repl.py b/bpython/repl.py
index 8387f2f22..d7f48a7b8 100644
--- a/bpython/repl.py
+++ b/bpython/repl.py
@@ -626,6 +626,24 @@ def get_args(self):
fake_cursor, self.current_line, self.interp.locals)
except simpleeval.EvaluationError:
return False
+
+ if inspect.isclass(f):
+ class_f = None
+
+ if (hasattr(f, '__init__') and
+ f.__init__ is not object.__init__):
+ class_f = f.__init__
+ if ((not class_f or
+ not inspection.getfuncprops(func, class_f)) and
+ hasattr(f, '__new__') and
+ f.__new__ is not object.__new__ and
+ # py3
+ f.__new__.__class__ is not object.__new__.__class__):
+
+ class_f = f.__new__
+
+ if class_f:
+ f = class_f
except Exception:
# another case of needing to catch every kind of error
# since user code is run in the case of descriptors
@@ -633,24 +651,6 @@ def get_args(self):
# stuff !
return False
- if inspect.isclass(f):
- class_f = None
-
- if (hasattr(f, '__init__') and
- f.__init__ is not object.__init__):
- class_f = f.__init__
- if ((not class_f or
- not inspection.getfuncprops(func, class_f)) and
- hasattr(f, '__new__') and
- f.__new__ is not object.__new__ and
- # py3
- f.__new__.__class__ is not object.__new__.__class__):
-
- class_f = f.__new__
-
- if class_f:
- f = class_f
-
self.current_func = f
self.funcprops = inspection.getfuncprops(func, f)
if self.funcprops:
From 0a6e34c99432b82bda2d027636e2260af54e16c2 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 21 Oct 2019 10:41:40 +0200
Subject: [PATCH 131/864] Use os.O_TRUNC
---
bpython/history.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/history.py b/bpython/history.py
index ae9c31628..de518439a 100644
--- a/bpython/history.py
+++ b/bpython/history.py
@@ -182,7 +182,7 @@ def load_from(self, fd):
return entries if len(entries) else ['']
def save(self, filename, encoding, lines=0):
- fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.TRUNC,
+ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
stat.S_IRUSR | stat.S_IWUSR)
with io.open(fd, 'w', encoding=encoding,
errors='ignore') as hfile:
From afc0eb325eeb54497c0f7db527ff6540b25b91b7 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Mon, 21 Oct 2019 10:47:20 +0200
Subject: [PATCH 132/864] Mark as not locked before releasing the lock
---
bpython/filelock.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index e956c5543..32044fcd3 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -85,8 +85,8 @@ def acquire(self):
raise e
def release(self):
- fcntl.flock(self.fileobj, fcntl.LOCK_UN)
self.locked = False
+ fcntl.flock(self.fileobj, fcntl.LOCK_UN)
class WindowsFileLock(BaseLock):
@@ -101,8 +101,8 @@ def acquire(self):
self.locked = True
def release(self):
- msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_UNLCK, 1)
self.locked = False
+ msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_UNLCK, 1)
if has_fcntl:
From 52580b49d65587ff2fb799b400153091248716b5 Mon Sep 17 00:00:00 2001
From: Sebastian Ramacher
Date: Wed, 23 Oct 2019 20:28:19 +0200
Subject: [PATCH 133/864] Create a lock file on Windows
---
bpython/filelock.py | 28 +++++++++++++++++++++-------
bpython/history.py | 6 +++---
2 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 32044fcd3..9a646f03f 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -2,7 +2,7 @@
# The MIT License
#
-# Copyright (c) 2015-2016 Sebastian Ramacher
+# Copyright (c) 2015-2019 Sebastian Ramacher
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@
try:
import msvcrt
+ import os
has_msvcrt = True
except ImportError:
has_msvcrt = False
@@ -42,7 +43,7 @@ class BaseLock(object):
"""Base class for file locking
"""
- def __init__(self, fileobj):
+ def __init__(self, fileobj, mode=None, filename=None):
self.fileobj = fileobj
self.locked = False
@@ -69,7 +70,7 @@ class UnixFileLock(BaseLock):
"""Simple file locking for Unix using fcntl
"""
- def __init__(self, fileobj, mode=None):
+ def __init__(self, fileobj, mode=None, filename=None):
super(UnixFileLock, self).__init__(fileobj)
if mode is None:
@@ -93,16 +94,29 @@ class WindowsFileLock(BaseLock):
"""Simple file locking for Windows using msvcrt
"""
- def __init__(self, fileobj, mode=None):
- super(WindowsFileLock, self).__init__(fileobj)
+ def __init__(self, fileobj, mode=None, filename=None):
+ super(WindowsFileLock, self).__init__(None)
+ self.filename = "{}.lock".format(filename)
def acquire(self):
- msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_NBLCK, 1)
+ # create a lock file and lock it
+ self.fileobj = os.open(self.filename, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
+ msvcrt.locking(self.fileobj, msvcrt.LK_NBLCK, 1)
+
self.locked = True
def release(self):
self.locked = False
- msvcrt.locking(self.fileobj.fileno(), msvcrt.LK_UNLCK, 1)
+
+ # unlock lock file and remove it
+ msvcrt.locking(self.fileobj, msvcrt.LK_UNLCK, 1)
+ self.fileobj.close()
+ self.fileobj = None
+
+ try:
+ os.remove(self.filename)
+ except OSError:
+ pass
if has_fcntl:
diff --git a/bpython/history.py b/bpython/history.py
index de518439a..edcf8b500 100644
--- a/bpython/history.py
+++ b/bpython/history.py
@@ -172,7 +172,7 @@ def reset(self):
def load(self, filename, encoding):
with io.open(filename, 'r', encoding=encoding,
errors='ignore') as hfile:
- with FileLock(hfile):
+ with FileLock(hfile, filename=filename):
self.entries = self.load_from(hfile)
def load_from(self, fd):
@@ -186,7 +186,7 @@ def save(self, filename, encoding, lines=0):
stat.S_IRUSR | stat.S_IWUSR)
with io.open(fd, 'w', encoding=encoding,
errors='ignore') as hfile:
- with FileLock(hfile):
+ with FileLock(hfile, filename=filename):
self.save_to(hfile, self.entries, lines)
def save_to(self, fd, entries=None, lines=0):
@@ -205,7 +205,7 @@ def append_reload_and_write(self, s, filename, encoding):
stat.S_IRUSR | stat.S_IWUSR)
with io.open(fd, 'a+', encoding=encoding,
errors='ignore') as hfile:
- with FileLock(hfile):
+ with FileLock(hfile, filename=filename):
# read entries
hfile.seek(0, os.SEEK_SET)
entries = self.load_from(hfile)
From 22db98ca55793da866ef2ada11adaddc44973ff7 Mon Sep 17 00:00:00 2001
From: myrmica-habilis
Date: Fri, 25 Oct 2019 10:14:41 +0200
Subject: [PATCH 134/864] Close lock file using os close()
---
bpython/filelock.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/filelock.py b/bpython/filelock.py
index 9a646f03f..703538738 100644
--- a/bpython/filelock.py
+++ b/bpython/filelock.py
@@ -110,7 +110,7 @@ def release(self):
# unlock lock file and remove it
msvcrt.locking(self.fileobj, msvcrt.LK_UNLCK, 1)
- self.fileobj.close()
+ os.close(self.fileobj)
self.fileobj = None
try:
From 13dabf88131fcf5ae447fd6b4e47c5f81118df47 Mon Sep 17 00:00:00 2001
From: myrmica-habilis
Date: Fri, 25 Oct 2019 10:04:29 +0200
Subject: [PATCH 135/864] Add test case for accessing the history file
---
bpython/test/test_history.py | 47 ++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/bpython/test/test_history.py b/bpython/test/test_history.py
index 49450e1b2..ac2b9b4d2 100644
--- a/bpython/test/test_history.py
+++ b/bpython/test/test_history.py
@@ -1,7 +1,11 @@
# encoding: utf-8
+import io
+import os
+
from six.moves import range
+from bpython.config import getpreferredencoding
from bpython.history import History
from bpython.test import unittest
@@ -81,3 +85,46 @@ def test_reset(self):
self.assertEqual(self.history.back(), '#999')
self.assertEqual(self.history.forward(), '')
+
+
+class TestHistoryFileAccess(unittest.TestCase):
+ def setUp(self):
+ self.filename = 'history_temp_file'
+ self.encoding = getpreferredencoding()
+
+ with io.open(self.filename, 'w', encoding=self.encoding,
+ errors='ignore') as f:
+ f.write('#1\n#2\n')
+
+ def test_load(self):
+ history = History()
+
+ history.load(self.filename, self.encoding)
+ self.assertEqual(history.entries, ['#1', '#2'])
+
+ def test_append_reload_and_write(self):
+ history = History()
+
+ history.append_reload_and_write('#3', self.filename, self.encoding)
+ self.assertEqual(history.entries, ['#1', '#2', '#3'])
+
+ history.append_reload_and_write('#4', self.filename, self.encoding)
+ self.assertEqual(history.entries, ['#1', '#2', '#3', '#4'])
+
+ def test_save(self):
+ history = History(['#1', '#2', '#3', '#4'])
+
+ # save only last 2 lines
+ history.save(self.filename, self.encoding, lines=2)
+
+ # empty the list of entries and load again from the file
+ history.entries = ['']
+ history.load(self.filename, self.encoding)
+
+ self.assertEqual(history.entries, ['#3', '#4'])
+
+ def tearDown(self):
+ try:
+ os.remove(self.filename)
+ except OSError:
+ pass
From 9d17172a03220cad27a5a46ee074a6aa7cd573d1 Mon Sep 17 00:00:00 2001
From: myrmica-habilis
Date: Fri, 25 Oct 2019 10:52:20 +0200
Subject: [PATCH 136/864] Fix Python 2.7 TypeError
---
bpython/test/test_history.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bpython/test/test_history.py b/bpython/test/test_history.py
index ac2b9b4d2..eb3b2d22f 100644
--- a/bpython/test/test_history.py
+++ b/bpython/test/test_history.py
@@ -94,7 +94,7 @@ def setUp(self):
with io.open(self.filename, 'w', encoding=self.encoding,
errors='ignore') as f:
- f.write('#1\n#2\n')
+ f.write(b'#1\n#2\n'.decode())
def test_load(self):
history = History()
From fabd54870e914244e45d2c097892ebc52c75c74a Mon Sep 17 00:00:00 2001
From: myrmica-habilis
Date: Fri, 25 Oct 2019 12:44:01 +0200
Subject: [PATCH 137/864] Fix Python 2.7 TypeError in test_save
---
bpython/test/test_history.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/bpython/test/test_history.py b/bpython/test/test_history.py
index eb3b2d22f..01574bd29 100644
--- a/bpython/test/test_history.py
+++ b/bpython/test/test_history.py
@@ -112,7 +112,10 @@ def test_append_reload_and_write(self):
self.assertEqual(history.entries, ['#1', '#2', '#3', '#4'])
def test_save(self):
- history = History(['#1', '#2', '#3', '#4'])
+ history = History()
+ history.entries = []
+ for line in ['#1', '#2', '#3', '#4']:
+ history.append_to(history.entries, line)
# save only last 2 lines
history.save(self.filename, self.encoding, lines=2)
From cde2aadff63b29dc33b0f498e129aa9161778430 Mon Sep 17 00:00:00 2001
From: Simon de Vlieger
Date: Fri, 22 Nov 2019 12:53:35 +0000
Subject: [PATCH 138/864] Blacken the source code and add `black`
configuration.
- Add configuration file for black's settings.
- Add a shield for black's codestyle.
- Run black over the entire codebase.
---
README.rst | 3 +
bpython/__init__.py | 5 +-
bpython/__main__.py | 3 +-
bpython/_internal.py | 7 +-
bpython/_py3compat.py | 14 +-
bpython/args.py | 68 +-
bpython/autocomplete.py | 270 +++--
bpython/cli.py | 582 +++++-----
bpython/clipboard.py | 24 +-
bpython/config.py | 407 +++----
bpython/curtsies.py | 80 +-
bpython/curtsiesfrontend/_internal.py | 2 +-
bpython/curtsiesfrontend/coderunner.py | 23 +-
bpython/curtsiesfrontend/events.py | 13 +-
bpython/curtsiesfrontend/filewatch.py | 8 +-
bpython/curtsiesfrontend/interaction.py | 54 +-
bpython/curtsiesfrontend/interpreter.py | 51 +-
bpython/curtsiesfrontend/manual_readline.py | 197 ++--
bpython/curtsiesfrontend/parse.py | 61 +-
bpython/curtsiesfrontend/preprocess.py | 18 +-
bpython/curtsiesfrontend/repl.py | 1052 +++++++++++--------
bpython/curtsiesfrontend/replpainter.py | 211 ++--
bpython/curtsiesfrontend/sitefix.py | 6 +-
bpython/filelock.py | 6 +-
bpython/formatter.py | 53 +-
bpython/history.py | 64 +-
bpython/importcompletion.py | 72 +-
bpython/inspection.py | 116 +-
bpython/keys.py | 35 +-
bpython/lazyre.py | 1 +
bpython/line.py | 70 +-
bpython/pager.py | 9 +-
bpython/paste.py | 53 +-
bpython/patch_linecache.py | 13 +-
bpython/repl.py | 417 ++++----
bpython/simpleeval.py | 62 +-
bpython/simplerepl.py | 46 +-
bpython/test/__init__.py | 5 +-
bpython/test/fodder/original.py | 23 +-
bpython/test/fodder/processed.py | 35 +-
bpython/test/test_args.py | 60 +-
bpython/test/test_autocomplete.py | 358 ++++---
bpython/test/test_config.py | 66 +-
bpython/test/test_crashers.py | 34 +-
bpython/test/test_curtsies.py | 36 +-
bpython/test/test_curtsies_coderunner.py | 22 +-
bpython/test/test_curtsies_painting.py | 775 +++++++-------
bpython/test/test_curtsies_parser.py | 35 +-
bpython/test/test_curtsies_repl.py | 301 +++---
bpython/test/test_filewatch.py | 10 +-
bpython/test/test_history.py | 65 +-
bpython/test/test_importcompletion.py | 40 +-
bpython/test/test_inspection.py | 66 +-
bpython/test/test_interpreter.py | 198 ++--
bpython/test/test_keys.py | 46 +-
bpython/test/test_line_properties.py | 333 +++---
bpython/test/test_manual_readline.py | 236 +++--
bpython/test/test_preprocess.py | 63 +-
bpython/test/test_repl.py | 197 ++--
bpython/test/test_simpleeval.py | 181 ++--
bpython/translations/__init__.py | 21 +-
bpython/urwid.py | 484 +++++----
pyproject.toml | 18 +
63 files changed, 4513 insertions(+), 3371 deletions(-)
create mode 100644 pyproject.toml
diff --git a/README.rst b/README.rst
index ed68c8cbc..8264667c5 100644
--- a/README.rst
+++ b/README.rst
@@ -3,6 +3,9 @@
.. |ImageLink| image:: https://travis-ci.org/bpython/bpython.svg?branch=master
.. _ImageLink: https://travis-ci.org/bpython/bpython
+.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
+ :target: https://github.com/ambv/black
+
***********************************************************************
bpython: A fancy curses interface to the Python interactive interpreter
***********************************************************************
diff --git a/bpython/__init__.py b/bpython/__init__.py
index 779a1a682..6d4a9aaa0 100644
--- a/bpython/__init__.py
+++ b/bpython/__init__.py
@@ -27,7 +27,7 @@
try:
from ._version import __version__ as version
except ImportError:
- version = 'unknown'
+ version = "unknown"
__version__ = version
package_dir = os.path.abspath(os.path.dirname(__file__))
@@ -35,7 +35,8 @@
def embed(locals_=None, args=None, banner=None):
if args is None:
- args = ['-i', '-q']
+ args = ["-i", "-q"]
from .curtsies import main
+
return main(args, locals_, banner)
diff --git a/bpython/__main__.py b/bpython/__main__.py
index d81ec1efd..28c488702 100644
--- a/bpython/__main__.py
+++ b/bpython/__main__.py
@@ -26,6 +26,7 @@
import sys
-if __name__ == '__main__':
+if __name__ == "__main__":
from .curtsies import main
+
sys.exit(main())
diff --git a/bpython/_internal.py b/bpython/_internal.py
index e0e87ba3c..e3907c7b1 100644
--- a/bpython/_internal.py
+++ b/bpython/_internal.py
@@ -12,7 +12,6 @@
class _Helper(object):
-
def __init__(self):
if hasattr(pydoc.Helper, "output"):
# See issue #228
@@ -21,8 +20,10 @@ def __init__(self):
self.helper = pydoc.Helper(sys.stdin, sys.stdout)
def __repr__(self):
- return ("Type help() for interactive help, "
- "or help(object) for help about object.")
+ return (
+ "Type help() for interactive help, "
+ "or help(object) for help about object."
+ )
def __call__(self, *args, **kwargs):
self.helper(*args, **kwargs)
diff --git a/bpython/_py3compat.py b/bpython/_py3compat.py
index 5e6ff3aa8..bebf4efd4 100644
--- a/bpython/_py3compat.py
+++ b/bpython/_py3compat.py
@@ -39,7 +39,7 @@
import sys
import threading
-py3 = (sys.version_info[0] == 3)
+py3 = sys.version_info[0] == 3
if py3:
@@ -49,17 +49,25 @@
if py3 or sys.version_info[:3] >= (2, 7, 3):
+
def prepare_for_exec(arg, encoding=None):
return arg
+
+
else:
+
def prepare_for_exec(arg, encoding=None):
return arg.encode(encoding)
if py3:
+
def try_decode(s, encoding):
return s
+
+
else:
+
def try_decode(s, encoding):
"""Try to decode s which is str names. Return None if not decodable"""
if not isinstance(s, unicode):
@@ -71,8 +79,12 @@ def try_decode(s, encoding):
if py3:
+
def is_main_thread():
return threading.main_thread() == threading.current_thread()
+
+
else:
+
def is_main_thread():
return isinstance(threading.current_thread(), threading._MainThread)
diff --git a/bpython/args.py b/bpython/args.py
index 1dfe010df..6aea8a197 100644
--- a/bpython/args.py
+++ b/bpython/args.py
@@ -27,8 +27,11 @@ def error(self, msg):
def version_banner():
- return 'bpython version %s on top of Python %s %s' % (
- __version__, sys.version.split()[0], sys.executable)
+ return "bpython version %s on top of Python %s %s" % (
+ __version__,
+ sys.version.split()[0],
+ sys.executable,
+ )
def parse(args, extras=None, ignore_stdin=False):
@@ -60,24 +63,43 @@ def parse(args, extras=None, ignore_stdin=False):
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.'))
+ 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.'))
+ 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])
@@ -93,8 +115,10 @@ def parse(args, extras=None, ignore_stdin=False):
if options.version:
print(version_banner())
- print('(C) 2008-2016 Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. '
- 'See AUTHORS for detail.')
+ print(
+ "(C) 2008-2016 Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. "
+ "See AUTHORS for detail."
+ )
raise SystemExit
if not ignore_stdin and not (sys.stdin.isatty() and sys.stdout.isatty()):
@@ -113,13 +137,13 @@ def exec_code(interpreter, args):
Helper to execute code in a given interpreter. args should be a [faked]
sys.argv
"""
- with open(args[0], 'r') as sourcefile:
+ with open(args[0], "r") as sourcefile:
source = sourcefile.read()
old_argv, sys.argv = sys.argv, args
sys.path.insert(0, os.path.abspath(os.path.dirname(args[0])))
- mod = imp.new_module('__console__')
- sys.modules['__console__'] = mod
+ mod = imp.new_module("__console__")
+ sys.modules["__console__"] = mod
interpreter.locals = mod.__dict__
- interpreter.locals['__file__'] = args[0]
- interpreter.runsource(source, args[0], 'exec')
+ interpreter.locals["__file__"] = args[0]
+ interpreter.runsource(source, args[0], "exec")
sys.argv = old_argv
diff --git a/bpython/autocomplete.py b/bpython/autocomplete.py
index 578a10bbb..53e1ea0f9 100644
--- a/bpython/autocomplete.py
+++ b/bpython/autocomplete.py
@@ -42,36 +42,84 @@
from .line import LinePart
from ._py3compat import py3, try_decode
from .lazyre import LazyReCompile
-from .simpleeval import (safe_eval, evaluate_current_expression,
- EvaluationError)
+from .simpleeval import safe_eval, evaluate_current_expression, EvaluationError
if not py3:
from types import InstanceType, ClassType
# Autocomplete modes
-SIMPLE = 'simple'
-SUBSTRING = 'substring'
-FUZZY = 'fuzzy'
+SIMPLE = "simple"
+SUBSTRING = "substring"
+FUZZY = "fuzzy"
ALL_MODES = (SIMPLE, SUBSTRING, FUZZY)
-MAGIC_METHODS = tuple("__%s__" % s for s in (
- "init", "repr", "str", "lt", "le", "eq", "ne", "gt", "ge", "cmp", "hash",
- "nonzero", "unicode", "getattr", "setattr", "get", "set", "call", "len",
- "getitem", "setitem", "iter", "reversed", "contains", "add", "sub", "mul",
- "floordiv", "mod", "divmod", "pow", "lshift", "rshift", "and", "xor", "or",
- "div", "truediv", "neg", "pos", "abs", "invert", "complex", "int", "float",
- "oct", "hex", "index", "coerce", "enter", "exit"))
+MAGIC_METHODS = tuple(
+ "__%s__" % s
+ for s in (
+ "init",
+ "repr",
+ "str",
+ "lt",
+ "le",
+ "eq",
+ "ne",
+ "gt",
+ "ge",
+ "cmp",
+ "hash",
+ "nonzero",
+ "unicode",
+ "getattr",
+ "setattr",
+ "get",
+ "set",
+ "call",
+ "len",
+ "getitem",
+ "setitem",
+ "iter",
+ "reversed",
+ "contains",
+ "add",
+ "sub",
+ "mul",
+ "floordiv",
+ "mod",
+ "divmod",
+ "pow",
+ "lshift",
+ "rshift",
+ "and",
+ "xor",
+ "or",
+ "div",
+ "truediv",
+ "neg",
+ "pos",
+ "abs",
+ "invert",
+ "complex",
+ "int",
+ "float",
+ "oct",
+ "hex",
+ "index",
+ "coerce",
+ "enter",
+ "exit",
+ )
+)
if py3:
KEYWORDS = frozenset(keyword.kwlist)
else:
- KEYWORDS = frozenset(name.decode('ascii') for name in keyword.kwlist)
+ KEYWORDS = frozenset(name.decode("ascii") for name in keyword.kwlist)
def after_last_dot(name):
- return name.rstrip('.').rsplit('.')[-1]
+ return name.rstrip(".").rsplit(".")[-1]
def few_enough_underscores(current, match):
@@ -81,11 +129,11 @@ def few_enough_underscores(current, match):
if current is __, True regardless of match
otherwise True if match does not start with any underscore
"""
- if current.startswith('__'):
+ if current.startswith("__"):
return True
- elif current.startswith('_') and not match.startswith('__'):
+ elif current.startswith("_") and not match.startswith("__"):
return True
- elif match.startswith('_'):
+ elif match.startswith("_"):
return False
else:
return True
@@ -100,14 +148,14 @@ def method_match_substring(word, size, text):
def method_match_fuzzy(word, size, text):
- s = r'.*%s.*' % '.*'.join(list(text))
+ s = r".*%s.*" % ".*".join(list(text))
return re.search(s, word)
MODES_MAP = {
SIMPLE: method_match_simple,
SUBSTRING: method_match_substring,
- FUZZY: method_match_fuzzy
+ FUZZY: method_match_fuzzy,
}
@@ -151,7 +199,7 @@ def substitute(self, cursor_offset, line, match):
"""Returns a cursor offset and line with match swapped in"""
lpart = self.locate(cursor_offset, line)
offset = lpart.start + len(match)
- changed_line = line[:lpart.start] + match + line[lpart.end:]
+ changed_line = line[: lpart.start] + match + line[lpart.end :]
return offset, changed_line
@property
@@ -167,7 +215,8 @@ class CumulativeCompleter(BaseCompletionType):
def __init__(self, completers, mode=SIMPLE):
if not completers:
raise ValueError(
- "CumulativeCompleter requires at least one completer")
+ "CumulativeCompleter requires at least one completer"
+ )
self._completers = completers
super(CumulativeCompleter, self).__init__(True, mode)
@@ -182,9 +231,9 @@ def matches(self, cursor_offset, line, **kwargs):
return_value = None
all_matches = set()
for completer in self._completers:
- matches = completer.matches(cursor_offset=cursor_offset,
- line=line,
- **kwargs)
+ matches = completer.matches(
+ cursor_offset=cursor_offset, line=line, **kwargs
+ )
if matches is not None:
all_matches.update(matches)
return_value = all_matches
@@ -193,7 +242,6 @@ def matches(self, cursor_offset, line, **kwargs):
class ImportCompletion(BaseCompletionType):
-
def matches(self, cursor_offset, line, **kwargs):
return importcompletion.complete(cursor_offset, line)
@@ -205,17 +253,19 @@ def format(self, word):
class FilenameCompletion(BaseCompletionType):
-
def __init__(self, mode=SIMPLE):
super(FilenameCompletion, self).__init__(False, mode)
if py3:
+
def safe_glob(self, pathname):
- return glob.iglob(glob.escape(pathname) + '*')
+ return glob.iglob(glob.escape(pathname) + "*")
+
else:
+
def safe_glob(self, pathname):
try:
- return glob.glob(pathname + '*')
+ return glob.glob(pathname + "*")
except re.error:
# see #491
return tuple()
@@ -230,8 +280,8 @@ def matches(self, cursor_offset, line, **kwargs):
for filename in self.safe_glob(os.path.expanduser(cs.word)):
if os.path.isdir(filename):
filename += os.path.sep
- if cs.word.startswith('~'):
- filename = username + filename[len(user_dir):]
+ if cs.word.startswith("~"):
+ filename = username + filename[len(user_dir) :]
matches.add(filename)
return matches
@@ -241,7 +291,7 @@ def locate(self, current_offset, line):
def format(self, filename):
filename.rstrip(os.sep).rsplit(os.sep)[-1]
if os.sep in filename[:-1]:
- return filename[filename.rindex(os.sep, 0, -1) + 1:]
+ return filename[filename.rindex(os.sep, 0, -1) + 1 :]
else:
return filename
@@ -251,9 +301,9 @@ class AttrCompletion(BaseCompletionType):
attr_matches_re = LazyReCompile(r"(\w+(\.\w+)*)\.(\w*)")
def matches(self, cursor_offset, line, **kwargs):
- if 'locals_' not in kwargs:
+ if "locals_" not in kwargs:
return None
- locals_ = kwargs['locals_']
+ locals_ = kwargs["locals_"]
r = self.locate(cursor_offset, line)
if r is None:
@@ -262,19 +312,23 @@ def matches(self, cursor_offset, line, **kwargs):
if locals_ is None: # TODO add a note about why
locals_ = __main__.__dict__
- assert '.' in r.word
+ assert "." in r.word
for i in range(1, len(r.word) + 1):
- if r.word[-i] == '[':
+ if r.word[-i] == "[":
i -= 1
break
methodtext = r.word[-i:]
- matches = set(''.join([r.word[:-i], m])
- for m in self.attr_matches(methodtext, locals_))
+ matches = set(
+ "".join([r.word[:-i], m])
+ for m in self.attr_matches(methodtext, locals_)
+ )
- return set(m for m in matches
- if few_enough_underscores(r.word.split('.')[-1],
- m.split('.')[-1]))
+ return set(
+ m
+ for m in matches
+ if few_enough_underscores(r.word.split(".")[-1], m.split(".")[-1])
+ )
def locate(self, current_offset, line):
return lineparts.current_dotted_attribute(current_offset, line)
@@ -311,18 +365,18 @@ def attr_lookup(self, obj, expr, attr):
be wrapped in a safe try/finally block in case anything bad happens to
restore the original __getattribute__ method."""
words = self.list_attributes(obj)
- if hasattr(obj, '__class__'):
- words.append('__class__')
+ if hasattr(obj, "__class__"):
+ words.append("__class__")
words = words + rlcompleter.get_class_members(obj.__class__)
if not isinstance(obj.__class__, abc.ABCMeta):
try:
- words.remove('__abstractmethods__')
+ words.remove("__abstractmethods__")
except ValueError:
pass
if not py3 and isinstance(obj, (InstanceType, ClassType)):
# Account for the __dict__ in an old-style class.
- words.append('__dict__')
+ words.append("__dict__")
matches = []
n = len(attr)
@@ -332,9 +386,12 @@ def attr_lookup(self, obj, expr, attr):
return matches
if py3:
+
def list_attributes(self, obj):
return dir(obj)
+
else:
+
def list_attributes(self, obj):
if isinstance(obj, InstanceType):
try:
@@ -343,17 +400,16 @@ def list_attributes(self, obj):
# This is a case where we can not prevent user code from
# running. We return a default list attributes on error
# instead. (#536)
- return ['__doc__', '__module__']
+ return ["__doc__", "__module__"]
else:
return dir(obj)
class DictKeyCompletion(BaseCompletionType):
-
def matches(self, cursor_offset, line, **kwargs):
- if 'locals_' not in kwargs:
+ if "locals_" not in kwargs:
return None
- locals_ = kwargs['locals_']
+ locals_ = kwargs["locals_"]
r = self.locate(cursor_offset, line)
if r is None:
@@ -364,8 +420,11 @@ def matches(self, cursor_offset, line, **kwargs):
except EvaluationError:
return None
if isinstance(obj, dict) and obj.keys():
- matches = set("{0!r}]".format(k) for k in obj.keys()
- if repr(k).startswith(r.word))
+ matches = set(
+ "{0!r}]".format(k)
+ for k in obj.keys()
+ if repr(k).startswith(r.word)
+ )
return matches if matches else None
else:
return None
@@ -378,16 +437,15 @@ def format(self, match):
class MagicMethodCompletion(BaseCompletionType):
-
def matches(self, cursor_offset, line, **kwargs):
- if 'current_block' not in kwargs:
+ if "current_block" not in kwargs:
return None
- current_block = kwargs['current_block']
+ current_block = kwargs["current_block"]
r = self.locate(cursor_offset, line)
if r is None:
return None
- if 'class' not in current_block:
+ if "class" not in current_block:
return None
return set(name for name in MAGIC_METHODS if name.startswith(r.word))
@@ -396,15 +454,14 @@ def locate(self, current_offset, line):
class GlobalCompletion(BaseCompletionType):
-
def matches(self, cursor_offset, line, **kwargs):
"""Compute matches when text is a simple name.
Return a list of all keywords, built-in functions and names currently
defined in self.namespace that match.
"""
- if 'locals_' not in kwargs:
+ if "locals_" not in kwargs:
return None
- locals_ = kwargs['locals_']
+ locals_ = kwargs["locals_"]
r = self.locate(cursor_offset, line)
if r is None:
@@ -417,12 +474,14 @@ def matches(self, cursor_offset, line, **kwargs):
matches.add(word)
for nspace in (builtins.__dict__, locals_):
for word, val in iteritems(nspace):
- word = try_decode(word, 'ascii')
+ word = try_decode(word, "ascii")
# if identifier isn't ascii, don't complete (syntax error)
if word is None:
continue
- if (self.method_match(word, n, r.word) and
- word != "__builtins__"):
+ if (
+ self.method_match(word, n, r.word)
+ and word != "__builtins__"
+ ):
matches.add(_callable_postfix(val, word))
return matches if matches else None
@@ -431,11 +490,10 @@ def locate(self, current_offset, line):
class ParameterNameCompletion(BaseCompletionType):
-
def matches(self, cursor_offset, line, **kwargs):
- if 'argspec' not in kwargs:
+ if "argspec" not in kwargs:
return None
- argspec = kwargs['argspec']
+ argspec = kwargs["argspec"]
if not argspec:
return None
@@ -443,12 +501,17 @@ def matches(self, cursor_offset, line, **kwargs):
if r is None:
return None
if argspec:
- matches = set(name + '=' for name in argspec[1][0]
- if isinstance(name, string_types) and
- name.startswith(r.word))
+ matches = set(
+ name + "="
+ for name in argspec[1][0]
+ if isinstance(name, string_types) and name.startswith(r.word)
+ )
if py3:
- matches.update(name + '=' for name in argspec[1][4]
- if name.startswith(r.word))
+ matches.update(
+ name + "="
+ for name in argspec[1][4]
+ if name.startswith(r.word)
+ )
return matches if matches else None
def locate(self, current_offset, line):
@@ -461,9 +524,9 @@ def locate(self, current_offset, line):
return lineparts.current_expression_attribute(current_offset, line)
def matches(self, cursor_offset, line, **kwargs):
- if 'locals_' not in kwargs:
+ if "locals_" not in kwargs:
return None
- locals_ = kwargs['locals_']
+ locals_ = kwargs["locals_"]
if locals_ is None:
locals_ = __main__.__dict__
@@ -476,7 +539,7 @@ def matches(self, cursor_offset, line, **kwargs):
return set()
with inspection.AttrCleaner(obj):
# strips leading dot
- matches = [m[1:] for m in self.attr_lookup(obj, '', attr.word)]
+ matches = [m[1:] for m in self.attr_lookup(obj, "", attr.word)]
return set(m for m in matches if few_enough_underscores(attr.word, m))
@@ -484,24 +547,28 @@ def matches(self, cursor_offset, line, **kwargs):
try:
import jedi
except ImportError:
+
class MultilineJediCompletion(BaseCompletionType):
def matches(self, cursor_offset, line, **kwargs):
return None
+
+
else:
- class JediCompletion(BaseCompletionType):
+ class JediCompletion(BaseCompletionType):
def matches(self, cursor_offset, line, **kwargs):
- if 'history' not in kwargs:
+ if "history" not in kwargs:
return None
- history = kwargs['history']
+ history = kwargs["history"]
if not lineparts.current_word(cursor_offset, line):
return None
- history = '\n'.join(history) + '\n' + line
+ history = "\n".join(history) + "\n" + line
try:
- script = jedi.Script(history, len(history.splitlines()),
- cursor_offset, 'fake.py')
+ script = jedi.Script(
+ history, len(history.splitlines()), cursor_offset, "fake.py"
+ )
completions = script.completions()
except (jedi.NotFoundError, IndexError, KeyError):
# IndexError for #483
@@ -516,11 +583,12 @@ def matches(self, cursor_offset, line, **kwargs):
self._orig_start = None
return None
- first_letter = line[self._orig_start:self._orig_start + 1]
+ first_letter = line[self._orig_start : self._orig_start + 1]
- matches = [try_decode(c.name, 'ascii') for c in completions]
- if any(not m.lower().startswith(matches[0][0].lower())
- for m in matches):
+ matches = [try_decode(c.name, "ascii") for c in completions]
+ if any(
+ not m.lower().startswith(matches[0][0].lower()) for m in matches
+ ):
# Too general - giving completions starting with multiple
# letters
return None
@@ -535,17 +603,19 @@ def locate(self, cursor_offset, line):
class MultilineJediCompletion(JediCompletion):
def matches(self, cursor_offset, line, **kwargs):
- if 'current_block' not in kwargs or 'history' not in kwargs:
+ if "current_block" not in kwargs or "history" not in kwargs:
return None
- current_block = kwargs['current_block']
- history = kwargs['history']
-
- if '\n' in current_block:
- assert cursor_offset <= len(line), "%r %r" % (cursor_offset,
- line)
- results = super(MultilineJediCompletion,
- self).matches(cursor_offset, line,
- history=history)
+ current_block = kwargs["current_block"]
+ history = kwargs["history"]
+
+ if "\n" in current_block:
+ assert cursor_offset <= len(line), "%r %r" % (
+ cursor_offset,
+ line,
+ )
+ results = super(MultilineJediCompletion, self).matches(
+ cursor_offset, line, history=history
+ )
return results
else:
return None
@@ -575,8 +645,10 @@ def get_completer(completers, cursor_offset, line, **kwargs):
# Instead of crashing the UI, log exceptions from autocompleters.
logger = logging.getLogger(__name__)
logger.debug(
- 'Completer {} failed with unhandled exception: {}'.format(
- completer, e))
+ "Completer {} failed with unhandled exception: {}".format(
+ completer, e
+ )
+ )
continue
if matches is not None:
return sorted(matches), (completer if matches else None)
@@ -591,9 +663,10 @@ def get_default_completer(mode=SIMPLE):
FilenameCompletion(mode=mode),
MagicMethodCompletion(mode=mode),
MultilineJediCompletion(mode=mode),
- CumulativeCompleter((GlobalCompletion(mode=mode),
- ParameterNameCompletion(mode=mode)),
- mode=mode),
+ CumulativeCompleter(
+ (GlobalCompletion(mode=mode), ParameterNameCompletion(mode=mode)),
+ mode=mode,
+ ),
AttrCompletion(mode=mode),
ExpressionAttributeCompletion(mode=mode),
)
@@ -601,13 +674,12 @@ def get_default_completer(mode=SIMPLE):
def get_completer_bpython(cursor_offset, line, **kwargs):
""""""
- return get_completer(get_default_completer(),
- cursor_offset, line, **kwargs)
+ return get_completer(get_default_completer(), cursor_offset, line, **kwargs)
def _callable_postfix(value, word):
"""rlcompleter's _callable_postfix done right."""
with inspection.AttrCleaner(value):
if inspection.is_callable(value):
- word += '('
+ word += "("
return word
diff --git a/bpython/cli.py b/bpython/cli.py
index 14415a3a6..589f49045 100644
--- a/bpython/cli.py
+++ b/bpython/cli.py
@@ -51,7 +51,8 @@
import functools
import struct
-if platform.system() != 'Windows':
+
+if platform.system() != "Windows":
import signal # Windows does not have job control
import termios # Windows uses curses
import fcntl # Windows uses curses
@@ -105,7 +106,7 @@ def calculate_screen_lines(tokens, width, cursor=0):
lines = 1
pos = cursor
for (token, value) in tokens:
- if token is Token.Text and value == '\n':
+ if token is Token.Text and value == "\n":
lines += 1
else:
pos += len(value)
@@ -122,6 +123,7 @@ def newfunc(self, *args, **kwargs):
return func(self, *args, **kwargs)
else:
return getattr(self.get_dest(), newfunc.__name__)(*args, **kwargs)
+
return newfunc
@@ -184,17 +186,17 @@ def readline(self, size=-1):
someone does something weird to stop it from blowing up."""
if not size:
- return ''
+ return ""
elif self.buffer:
buffer = self.buffer.pop(0)
else:
- buffer = ''
+ buffer = ""
curses.raw(True)
try:
- while not buffer.endswith(('\n', '\r')):
+ while not buffer.endswith(("\n", "\r")):
key = self.interface.get_key()
- if key in [curses.erasechar(), 'KEY_BACKSPACE']:
+ if key in [curses.erasechar(), "KEY_BACKSPACE"]:
y, x = self.interface.scr.getyx()
if buffer:
self.interface.scr.delch(y, x - 1)
@@ -202,9 +204,10 @@ def readline(self, size=-1):
continue
elif key == chr(4) and not buffer:
# C-d
- return ''
- elif (key not in ('\n', '\r') and
- (len(key) > 1 or unicodedata.category(key) == 'Cc')):
+ return ""
+ elif key not in ("\n", "\r") and (
+ len(key) > 1 or unicodedata.category(key) == "Cc"
+ ):
continue
sys.stdout.write(key)
# Include the \n in the buffer - raw_input() seems to deal with trailing
@@ -226,7 +229,7 @@ def readline(self, size=-1):
def read(self, size=None):
if size == 0:
- return ''
+ return ""
data = list()
while size is None or size > 0:
@@ -237,10 +240,11 @@ def read(self, size=None):
size -= len(line)
data.append(line)
- return ''.join(data)
+ return "".join(data)
def readlines(self, size=-1):
- return list(iter(self.readline, ''))
+ return list(iter(self.readline, ""))
+
# TODO:
#
@@ -270,36 +274,37 @@ def make_colors(config):
# blacK, Red, Green, Yellow, Blue, Magenta, Cyan, White, Default:
c = {
- 'k': 0,
- 'r': 1,
- 'g': 2,
- 'y': 3,
- 'b': 4,
- 'm': 5,
- 'c': 6,
- 'w': 7,
- 'd': -1,
+ "k": 0,
+ "r": 1,
+ "g": 2,
+ "y": 3,
+ "b": 4,
+ "m": 5,
+ "c": 6,
+ "w": 7,
+ "d": -1,
}
- if platform.system() == 'Windows':
- c = dict(list(c.items()) +
- [
- ('K', 8),
- ('R', 9),
- ('G', 10),
- ('Y', 11),
- ('B', 12),
- ('M', 13),
- ('C', 14),
- ('W', 15),
- ]
+ if platform.system() == "Windows":
+ c = dict(
+ list(c.items())
+ + [
+ ("K", 8),
+ ("R", 9),
+ ("G", 10),
+ ("Y", 11),
+ ("B", 12),
+ ("M", 13),
+ ("C", 14),
+ ("W", 15),
+ ]
)
for i in range(63):
if i > 7:
j = i // 8
else:
- j = c[config.color_scheme['background']]
+ j = c[config.color_scheme["background"]]
curses.init_pair(i + 1, i % 8, j)
return c
@@ -316,7 +321,7 @@ def confirm(self, q):
except ValueError:
return False
- return reply.lower() in (_('y'), _('yes'))
+ return reply.lower() in (_("y"), _("yes"))
def notify(self, s, n=10, wait_for_keypress=False):
return self.statusbar.message(s, n)
@@ -326,22 +331,21 @@ def file_prompt(self, s):
class CLIRepl(repl.Repl):
-
def __init__(self, scr, interp, statusbar, config, idle=None):
super(CLIRepl, self).__init__(interp, config)
self.interp.writetb = self.writetb
self.scr = scr
- self.stdout_hist = '' # native str (bytes in Py2, unicode in Py3)
- self.list_win = newwin(get_colpair(config, 'background'), 1, 1, 1, 1)
+ self.stdout_hist = "" # native str (bytes in Py2, unicode in Py3)
+ self.list_win = newwin(get_colpair(config, "background"), 1, 1, 1, 1)
self.cpos = 0
self.do_exit = False
self.exit_value = ()
- self.f_string = ''
+ self.f_string = ""
self.idle = idle
self.in_hist = False
self.paste_mode = False
self.last_key_press = time.time()
- self.s = ''
+ self.s = ""
self.statusbar = statusbar
self.formatter = BPythonFormatter(config.color_scheme)
self.interact = CLIInteraction(self.config, statusbar=self.statusbar)
@@ -354,8 +358,13 @@ def _get_cursor_offset(self):
def _set_cursor_offset(self, offset):
self.cpos = len(self.s) - offset
- cursor_offset = property(_get_cursor_offset, _set_cursor_offset, None,
- "The cursor offset from the beginning of the line")
+
+ cursor_offset = property(
+ _get_cursor_offset,
+ _set_cursor_offset,
+ None,
+ "The cursor offset from the beginning of the line",
+ )
def addstr(self, s):
"""Add a string to the current input line and figure out
@@ -365,7 +374,7 @@ def addstr(self, s):
self.s += s
else:
l = len(self.s)
- self.s = self.s[:l - self.cpos] + s + self.s[l - self.cpos:]
+ self.s = self.s[: l - self.cpos] + s + self.s[l - self.cpos :]
self.complete()
@@ -403,7 +412,7 @@ def bs(self, delete_tabs=True):
self.s = self.s[:-n]
else:
- self.s = self.s[:-self.cpos - 1] + self.s[-self.cpos:]
+ self.s = self.s[: -self.cpos - 1] + self.s[-self.cpos :]
self.print_line(self.s, clr=True)
@@ -414,22 +423,24 @@ def bs_word(self):
pos = len(self.s) - self.cpos - 1
deleted = []
# First we delete any space to the left of the cursor.
- while pos >= 0 and self.s[pos] == ' ':
+ while pos >= 0 and self.s[pos] == " ":
deleted.append(self.s[pos])
pos -= self.bs()
# Then we delete a full word.
- while pos >= 0 and self.s[pos] != ' ':
+ while pos >= 0 and self.s[pos] != " ":
deleted.append(self.s[pos])
pos -= self.bs()
- return ''.join(reversed(deleted))
+ return "".join(reversed(deleted))
def check(self):
"""Check if paste mode should still be active and, if not, deactivate
it and force syntax highlighting."""
- if (self.paste_mode
- and time.time() - self.last_key_press > self.config.paste_time):
+ if (
+ self.paste_mode
+ and time.time() - self.last_key_press > self.config.paste_time
+ ):
self.paste_mode = False
self.print_line(self.s)
@@ -438,7 +449,7 @@ def clear_current_line(self):
used to prevent autoindentation from occurring after a
traceback."""
repl.Repl.clear_current_line(self)
- self.s = ''
+ self.s = ""
def clear_wrapped_lines(self):
"""Clear the wrapped lines of the current input."""
@@ -462,9 +473,12 @@ def complete(self, tab=False):
list_win_visible = repl.Repl.complete(self, tab)
if list_win_visible:
try:
- self.show_list(self.matches_iter.matches, self.arg_pos,
- topline=self.funcprops,
- formatter=self.matches_iter.completer.format)
+ self.show_list(
+ self.matches_iter.matches,
+ self.arg_pos,
+ topline=self.funcprops,
+ formatter=self.matches_iter.completer.format,
+ )
except curses.error:
# XXX: This is a massive hack, it will go away when I get
# cusswords into a good enough state that we can start
@@ -481,9 +495,9 @@ def clrtobol(self):
self.clear_wrapped_lines()
if not self.cpos:
- self.s = ''
+ self.s = ""
else:
- self.s = self.s[-self.cpos:]
+ self.s = self.s[-self.cpos :]
self.print_line(self.s, clr=True)
self.scr.redrawwin()
@@ -494,13 +508,18 @@ def _get_current_line(self):
def _set_current_line(self, line):
self.s = line
- current_line = property(_get_current_line, _set_current_line, None,
- "The characters of the current line")
+
+ current_line = property(
+ _get_current_line,
+ _set_current_line,
+ None,
+ "The characters of the current line",
+ )
def cut_to_buffer(self):
"""Clear from cursor to end of line, placing into cut buffer"""
- self.cut_buffer = self.s[-self.cpos:]
- self.s = self.s[:-self.cpos]
+ self.cut_buffer = self.s[-self.cpos :]
+ self.s = self.s[: -self.cpos]
self.cpos = 0
self.print_line(self.s, clr=True)
self.scr.redrawwin()
@@ -522,29 +541,29 @@ def echo(self, s, redraw=True):
if not py3 and isinstance(s, unicode):
s = s.encode(getpreferredencoding())
- a = get_colpair(self.config, 'output')
- if '\x01' in s:
- rx = re.search('\x01([A-Za-z])([A-Za-z]?)', s)
+ a = get_colpair(self.config, "output")
+ if "\x01" in s:
+ rx = re.search("\x01([A-Za-z])([A-Za-z]?)", s)
if rx:
fg = rx.groups()[0]
bg = rx.groups()[1]
col_num = self._C[fg.lower()]
- if bg and bg != 'I':
+ if bg and bg != "I":
col_num *= self._C[bg.lower()]
a = curses.color_pair(int(col_num) + 1)
- if bg == 'I':
+ if bg == "I":
a = a | curses.A_REVERSE
- s = re.sub('\x01[A-Za-z][A-Za-z]?', '', s)
+ s = re.sub("\x01[A-Za-z][A-Za-z]?", "", s)
if fg.isupper():
a = a | curses.A_BOLD
- s = s.replace('\x03', '')
- s = s.replace('\x01', '')
+ s = s.replace("\x03", "")
+ s = s.replace("\x01", "")
# Replace NUL bytes, as addstr raises an exception otherwise
- s = s.replace('\0', '')
+ s = s.replace("\0", "")
# Replace \r\n bytes, as addstr remove the current line otherwise
- s = s.replace('\r\n', '\n')
+ s = s.replace("\r\n", "\n")
self.scr.addstr(s, a)
@@ -608,7 +627,7 @@ def search(self):
self.print_line(self.s, clr=True)
def get_key(self):
- key = ''
+ key = ""
while True:
try:
key += self.scr.getkey()
@@ -617,7 +636,7 @@ def get_key(self):
# encoded string in Python 3 as well, but of
# type str instead of bytes, hence convert it to
# bytes first and decode then
- key = key.encode('latin-1').decode(getpreferredencoding())
+ key = key.encode("latin-1").decode(getpreferredencoding())
else:
key = key.decode(getpreferredencoding())
self.scr.nodelay(False)
@@ -637,7 +656,7 @@ def get_key(self):
if key:
return key
else:
- if key != '\x00':
+ if key != "\x00":
t = time.time()
self.paste_mode = (
t - self.last_key_press <= self.config.paste_time
@@ -645,7 +664,7 @@ def get_key(self):
self.last_key_press = t
return key
else:
- key = ''
+ key = ""
finally:
if self.idle:
self.idle(self)
@@ -659,13 +678,13 @@ def get_line(self):
which returns None if Enter is pressed (that means "Return",
idiot)."""
- self.s = ''
+ self.s = ""
self.rl_history.reset()
self.iy, self.ix = self.scr.getyx()
if not self.paste_mode:
for _ in range(self.next_indentation()):
- self.p_key('\t')
+ self.p_key("\t")
self.cpos = 0
@@ -717,16 +736,17 @@ def mkargspec(self, topline, in_arg, down):
self.list_win.resize(3, max_w)
h, w = self.list_win.getmaxyx()
- self.list_win.addstr('\n ')
- self.list_win.addstr(fn,
- get_colpair(self.config, 'name') | curses.A_BOLD)
- self.list_win.addstr(': (', get_colpair(self.config, 'name'))
+ self.list_win.addstr("\n ")
+ self.list_win.addstr(
+ fn, get_colpair(self.config, "name") | curses.A_BOLD
+ )
+ self.list_win.addstr(": (", get_colpair(self.config, "name"))
maxh = self.scr.getmaxyx()[0]
if is_bound_method and isinstance(in_arg, int):
in_arg += 1
- punctuation_colpair = get_colpair(self.config, 'punctuation')
+ punctuation_colpair = get_colpair(self.config, "punctuation")
for k, i in enumerate(args):
y, x = self.list_win.getyx()
@@ -748,12 +768,12 @@ def mkargspec(self, topline, in_arg, down):
else:
break
r += 1
- self.list_win.addstr('\n\t')
+ self.list_win.addstr("\n\t")
- if str(i) == 'self' and k == 0:
- color = get_colpair(self.config, 'name')
+ if str(i) == "self" and k == 0:
+ color = get_colpair(self.config, "name")
else:
- color = get_colpair(self.config, 'token')
+ color = get_colpair(self.config, "token")
if k == in_arg or i == in_arg:
color |= curses.A_BOLD
@@ -766,41 +786,44 @@ def mkargspec(self, topline, in_arg, down):
else:
self.list_win.addstr(str(i), color)
if kw is not None:
- self.list_win.addstr('=', punctuation_colpair)
- self.list_win.addstr(kw, get_colpair(self.config, 'token'))
+ self.list_win.addstr("=", punctuation_colpair)
+ self.list_win.addstr(kw, get_colpair(self.config, "token"))
if k != len(args) - 1:
- self.list_win.addstr(', ', punctuation_colpair)
+ self.list_win.addstr(", ", punctuation_colpair)
if _args:
if args:
- self.list_win.addstr(', ', punctuation_colpair)
- self.list_win.addstr('*%s' % (_args, ),
- get_colpair(self.config, 'token'))
+ self.list_win.addstr(", ", punctuation_colpair)
+ self.list_win.addstr(
+ "*%s" % (_args,), get_colpair(self.config, "token")
+ )
if py3 and kwonly:
if not _args:
if args:
- self.list_win.addstr(', ', punctuation_colpair)
- self.list_win.addstr('*', punctuation_colpair)
+ self.list_win.addstr(", ", punctuation_colpair)
+ self.list_win.addstr("*", punctuation_colpair)
marker = object()
for arg in kwonly:
- self.list_win.addstr(', ', punctuation_colpair)
- color = get_colpair(self.config, 'token')
+ self.list_win.addstr(", ", punctuation_colpair)
+ color = get_colpair(self.config, "token")
if arg == in_arg:
color |= curses.A_BOLD
self.list_win.addstr(arg, color)
default = kwonly_defaults.get(arg, marker)
if default is not marker:
- self.list_win.addstr('=', punctuation_colpair)
- self.list_win.addstr(repr(default),
- get_colpair(self.config, 'token'))
+ self.list_win.addstr("=", punctuation_colpair)
+ self.list_win.addstr(
+ repr(default), get_colpair(self.config, "token")
+ )
if _kwargs:
if args or _args or (py3 and kwonly):
- self.list_win.addstr(', ', punctuation_colpair)
- self.list_win.addstr('**%s' % (_kwargs, ),
- get_colpair(self.config, 'token'))
- self.list_win.addstr(')', punctuation_colpair)
+ self.list_win.addstr(", ", punctuation_colpair)
+ self.list_win.addstr(
+ "**%s" % (_kwargs,), get_colpair(self.config, "token")
+ )
+ self.list_win.addstr(")", punctuation_colpair)
return r
@@ -841,11 +864,11 @@ def p_key(self, key):
"""Process a keypress"""
if key is None:
- return ''
+ return ""
config = self.config
- if platform.system() == 'Windows':
+ if platform.system() == "Windows":
C_BACK = chr(127)
BACKSP = chr(8)
else:
@@ -854,178 +877,179 @@ def p_key(self, key):
if key == C_BACK: # C-Backspace (on my computer anyway!)
self.clrtobol()
- key = '\n'
+ key = "\n"
# Don't return; let it get handled
if key == chr(27): # Escape Key
- return ''
+ return ""
- if key in (BACKSP, 'KEY_BACKSPACE'):
+ if key in (BACKSP, "KEY_BACKSPACE"):
self.bs()
self.complete()
- return ''
+ return ""
elif key in key_dispatch[config.delete_key] and not self.s:
# Delete on empty line exits
self.do_exit = True
return None
- elif key in ('KEY_DC', ) + key_dispatch[config.delete_key]:
+ elif key in ("KEY_DC",) + key_dispatch[config.delete_key]:
self.delete()
self.complete()
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- return ''
+ return ""
elif key in key_dispatch[config.undo_key]: # C-r
n = self.prompt_undo()
if n > 0:
self.undo(n=n)
- return ''
+ return ""
elif key in key_dispatch[config.search_key]:
self.search()
- return ''
+ return ""
- elif key in ('KEY_UP', ) + key_dispatch[config.up_one_line_key]:
+ elif key in ("KEY_UP",) + key_dispatch[config.up_one_line_key]:
# Cursor Up/C-p
self.back()
- return ''
+ return ""
- elif key in ('KEY_DOWN', ) + key_dispatch[config.down_one_line_key]:
+ elif key in ("KEY_DOWN",) + key_dispatch[config.down_one_line_key]:
# Cursor Down/C-n
self.fwd()
- return ''
+ return ""
- elif key in ("KEY_LEFT", ' ^B', chr(2)): # Cursor Left or ^B
+ elif key in ("KEY_LEFT", " ^B", chr(2)): # Cursor Left or ^B
self.mvc(1)
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- elif key in ("KEY_RIGHT", '^F', chr(6)): # Cursor Right or ^F
+ elif key in ("KEY_RIGHT", "^F", chr(6)): # Cursor Right or ^F
self.mvc(-1)
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- elif key in ("KEY_HOME", '^A', chr(1)): # home or ^A
+ elif key in ("KEY_HOME", "^A", chr(1)): # home or ^A
self.home()
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- elif key in ("KEY_END", '^E', chr(5)): # end or ^E
+ elif key in ("KEY_END", "^E", chr(5)): # end or ^E
self.end()
# Redraw (as there might have been highlighted parens)
self.print_line(self.s)
- elif key in ("KEY_NPAGE", '\T'): # page_down or \T
+ elif key in ("KEY_NPAGE", "\T"): # page_down or \T
self.hend()
self.print_line(self.s)
- elif key in ("KEY_PPAGE", '\S'): # page_up or \S
+ elif key in ("KEY_PPAGE", "\S"): # page_up or \S
self.hbegin()
self.print_line(self.s)
elif key in key_dispatch[config.cut_to_buffer_key]: # cut to buffer
self.cut_to_buffer()
- return ''
+ return ""
elif key in key_dispatch[config.yank_from_buffer_key]:
# yank from buffer
self.yank_from_buffer()
- return ''
+ return ""
elif key in key_dispatch[config.clear_word_key]:
self.cut_buffer = self.bs_word()
self.complete()
- return ''
+ return ""
elif key in key_dispatch[config.clear_line_key]:
self.clrtobol()
- return ''
+ return ""
elif key in key_dispatch[config.clear_screen_key]:
self.s_hist = [self.s_hist[-1]]
self.highlighted_paren = None
self.redraw()
- return ''
+ return ""
elif key in key_dispatch[config.exit_key]:
if not self.s:
self.do_exit = True
return None
else:
- return ''
+ return ""
elif key in key_dispatch[config.save_key]:
self.write2file()
- return ''
+ return ""
elif key in key_dispatch[config.pastebin_key]:
self.pastebin()
- return ''
+ return ""
elif key in key_dispatch[config.copy_clipboard_key]:
self.copy2clipboard()
- return ''
+ return ""
elif key in key_dispatch[config.last_output_key]:
- page(self.stdout_hist[self.prev_block_finished:-4])
- return ''
+ page(self.stdout_hist[self.prev_block_finished : -4])
+ return ""
elif key in key_dispatch[config.show_source_key]:
try:
source = self.get_source_of_current_name()
except repl.SourceNotFound as e:
- self.statusbar.message('%s' % (e, ))
+ self.statusbar.message("%s" % (e,))
else:
if config.highlight_show_source:
- source = format(PythonLexer().get_tokens(source),
- TerminalFormatter())
+ source = format(
+ PythonLexer().get_tokens(source), TerminalFormatter()
+ )
page(source)
- return ''
+ return ""
- elif key in ('\n', '\r', 'PADENTER'):
+ elif key in ("\n", "\r", "PADENTER"):
self.lf()
return None
- elif key == '\t':
+ elif key == "\t":
return self.tab()
- elif key == 'KEY_BTAB':
+ elif key == "KEY_BTAB":
return self.tab(back=True)
elif key in key_dispatch[config.suspend_key]:
- if platform.system() != 'Windows':
+ if platform.system() != "Windows":
self.suspend()
- return ''
+ return ""
else:
self.do_exit = True
return None
- elif key == '\x18':
+ elif key == "\x18":
return self.send_current_line_to_editor()
- elif key == '\x03':
+ elif key == "\x03":
raise KeyboardInterrupt()
- elif key[0:3] == 'PAD' and not key in ('PAD0', 'PADSTOP'):
+ elif key[0:3] == "PAD" and not key in ("PAD0", "PADSTOP"):
pad_keys = {
- 'PADMINUS': '-',
- 'PADPLUS': '+',
- 'PADSLASH': '/',
- 'PADSTAR': '*',
+ "PADMINUS": "-",
+ "PADPLUS": "+",
+ "PADSLASH": "/",
+ "PADSTAR": "*",
}
try:
self.addstr(pad_keys[key])
self.print_line(self.s)
except KeyError:
- return ''
- elif len(key) == 1 and not unicodedata.category(key) == 'Cc':
+ return ""
+ elif len(key) == 1 and not unicodedata.category(key) == "Cc":
self.addstr(key)
self.print_line(self.s)
else:
- return ''
+ return ""
return True
@@ -1056,8 +1080,8 @@ def print_line(self, s, clr=False, newline=False):
self.scr.refresh()
if o:
- for t in o.split('\x04'):
- self.echo(t.rstrip('\n'))
+ for t in o.split("\x04"):
+ self.echo(t.rstrip("\n"))
if self.cpos:
t = self.cpos
@@ -1068,23 +1092,27 @@ def print_line(self, s, clr=False, newline=False):
def prompt(self, more):
"""Show the appropriate Python prompt"""
if not more:
- self.echo("\x01%s\x03%s" %
- (self.config.color_scheme['prompt'], self.ps1))
+ self.echo(
+ "\x01%s\x03%s" % (self.config.color_scheme["prompt"], self.ps1)
+ )
if py3:
self.stdout_hist += self.ps1
else:
self.stdout_hist += self.ps1.encode(getpreferredencoding())
- self.s_hist.append('\x01%s\x03%s\x04' %
- (self.config.color_scheme['prompt'], self.ps1))
+ self.s_hist.append(
+ "\x01%s\x03%s\x04"
+ % (self.config.color_scheme["prompt"], self.ps1)
+ )
else:
- prompt_more_color = self.config.color_scheme['prompt_more']
+ prompt_more_color = self.config.color_scheme["prompt_more"]
self.echo("\x01%s\x03%s" % (prompt_more_color, self.ps2))
if py3:
self.stdout_hist += self.ps2
else:
self.stdout_hist += self.ps2.encode(getpreferredencoding())
- self.s_hist.append('\x01%s\x03%s\x04' %
- (prompt_more_color, self.ps2))
+ self.s_hist.append(
+ "\x01%s\x03%s\x04" % (prompt_more_color, self.ps2)
+ )
def push(self, s, insert_into_history=True):
# curses.raw(True) prevents C-c from causing a SIGINT
@@ -1106,10 +1134,10 @@ def redraw(self):
if not s:
continue
self.iy, self.ix = self.scr.getyx()
- for i in s.split('\x04'):
+ for i in s.split("\x04"):
self.echo(i, redraw=False)
if k < len(self.s_hist) - 1:
- self.scr.addstr('\n')
+ self.scr.addstr("\n")
self.iy, self.ix = self.scr.getyx()
self.print_line(self.s)
self.scr.refresh()
@@ -1126,18 +1154,18 @@ def repl(self):
# Use our own helper function because Python's will use real stdin and
# stdout instead of our wrapped
- self.push('from bpython._internal import _help as help\n', False)
+ self.push("from bpython._internal import _help as help\n", False)
self.iy, self.ix = self.scr.getyx()
self.more = False
while not self.do_exit:
- self.f_string = ''
+ self.f_string = ""
self.prompt(self.more)
try:
inp = self.get_line()
except KeyboardInterrupt:
- self.statusbar.message('KeyboardInterrupt')
- self.scr.addstr('\n')
+ self.statusbar.message("KeyboardInterrupt")
+ self.scr.addstr("\n")
self.scr.touchwin()
self.scr.refresh()
continue
@@ -1149,14 +1177,14 @@ def repl(self):
self.history.append(inp)
self.s_hist[-1] += self.f_string
if py3:
- self.stdout_hist += inp + '\n'
+ self.stdout_hist += inp + "\n"
else:
- self.stdout_hist += inp.encode(getpreferredencoding()) + '\n'
+ self.stdout_hist += inp.encode(getpreferredencoding()) + "\n"
stdout_position = len(self.stdout_hist)
self.more = self.push(inp)
if not self.more:
self.prev_block_finished = stdout_position
- self.s = ''
+ self.s = ""
return self.exit_value
def reprint_line(self, lineno, tokens):
@@ -1175,10 +1203,11 @@ def reprint_line(self, lineno, tokens):
if real_lineno < 0:
return
- self.scr.move(real_lineno,
- len(self.ps1) if lineno == 0 else len(self.ps2))
+ self.scr.move(
+ real_lineno, len(self.ps1) if lineno == 0 else len(self.ps2)
+ )
line = format(tokens, BPythonFormatter(self.config.color_scheme))
- for string in line.split('\x04'):
+ for string in line.split("\x04"):
self.echo(string)
def resize(self):
@@ -1195,14 +1224,14 @@ def getstdout(self):
"""This method returns the 'spoofed' stdout buffer, for writing to a
file or sending to a pastebin or whatever."""
- return self.stdout_hist + '\n'
+ return self.stdout_hist + "\n"
def reevaluate(self):
"""Clear the buffer, redraw the screen and re-evaluate the history"""
self.evaluating = True
- self.stdout_hist = ''
- self.f_string = ''
+ self.stdout_hist = ""
+ self.f_string = ""
self.buffer = []
self.scr.erase()
self.s_hist = []
@@ -1214,21 +1243,21 @@ def reevaluate(self):
self.iy, self.ix = self.scr.getyx()
for line in self.history:
if py3:
- self.stdout_hist += line + '\n'
+ self.stdout_hist += line + "\n"
else:
- self.stdout_hist += line.encode(getpreferredencoding()) + '\n'
+ self.stdout_hist += line.encode(getpreferredencoding()) + "\n"
self.print_line(line)
self.s_hist[-1] += self.f_string
# I decided it was easier to just do this manually
# than to make the print_line and history stuff more flexible.
- self.scr.addstr('\n')
+ self.scr.addstr("\n")
self.more = self.push(line)
self.prompt(self.more)
self.iy, self.ix = self.scr.getyx()
self.cpos = 0
indent = repl.next_indentation(self.s, self.config.tab_length)
- self.s = ''
+ self.s = ""
self.scr.refresh()
if self.buffer:
@@ -1236,17 +1265,17 @@ def reevaluate(self):
self.tab()
self.evaluating = False
- #map(self.push, self.history)
+ # map(self.push, self.history)
# ^-- That's how simple this method was at first :(
def write(self, s):
"""For overriding stdout defaults"""
- if '\x04' in s:
- for block in s.split('\x04'):
+ if "\x04" in s:
+ for block in s.split("\x04"):
self.write(block)
return
- if s.rstrip() and '\x03' in s:
- t = s.split('\x03')[1]
+ if s.rstrip() and "\x03" in s:
+ t = s.split("\x03")[1]
else:
t = s
@@ -1261,7 +1290,9 @@ def write(self, s):
self.echo(s)
self.s_hist.append(s.rstrip())
- def show_list(self, items, arg_pos, topline=None, formatter=None, current_item=None):
+ def show_list(
+ self, items, arg_pos, topline=None, formatter=None, current_item=None
+ ):
shared = Struct()
shared.cols = 0
@@ -1269,7 +1300,7 @@ def show_list(self, items, arg_pos, topline=None, formatter=None, current_item=N
shared.wl = 0
y, x = self.scr.getyx()
h, w = self.scr.getmaxyx()
- down = (y < h // 2)
+ down = y < h // 2
if down:
max_h = h - y
else:
@@ -1307,16 +1338,16 @@ def lsize():
if items:
# visible items (we'll append until we can't fit any more in)
- v_items = [items[0][:max_w - 3]]
+ v_items = [items[0][: max_w - 3]]
lsize()
else:
v_items = []
for i in items[1:]:
- v_items.append(i[:max_w - 3])
+ v_items.append(i[: max_w - 3])
if not lsize():
del v_items[-1]
- v_items[-1] = '...'
+ v_items[-1] = "..."
break
rows = shared.rows
@@ -1340,14 +1371,15 @@ def lsize():
w = t
if height_offset and display_rows + 5 >= max_h:
- del v_items[-(cols * (height_offset)):]
+ del v_items[-(cols * (height_offset)) :]
if self.docstring is None:
self.list_win.resize(rows + 2, w)
else:
- docstring = self.format_docstring(self.docstring, max_w - 2,
- max_h - height_offset)
- docstring_string = ''.join(docstring)
+ docstring = self.format_docstring(
+ self.docstring, max_w - 2, max_h - height_offset
+ )
+ docstring_string = "".join(docstring)
rows += len(docstring)
self.list_win.resize(rows, max_w)
@@ -1357,28 +1389,30 @@ def lsize():
self.list_win.mvwin(y - rows - 2, 0)
if v_items:
- self.list_win.addstr('\n ')
+ self.list_win.addstr("\n ")
if not py3:
encoding = getpreferredencoding()
for ix, i in enumerate(v_items):
- padding = (wl - len(i)) * ' '
+ padding = (wl - len(i)) * " "
if i == current_item:
- color = get_colpair(self.config, 'operator')
+ color = get_colpair(self.config, "operator")
else:
- color = get_colpair(self.config, 'main')
+ color = get_colpair(self.config, "main")
if not py3:
i = i.encode(encoding)
self.list_win.addstr(i + padding, color)
- if ((cols == 1 or (ix and not (ix + 1) % cols))
- and ix + 1 < len(v_items)):
- self.list_win.addstr('\n ')
+ if (cols == 1 or (ix and not (ix + 1) % cols)) and ix + 1 < len(
+ v_items
+ ):
+ self.list_win.addstr("\n ")
if self.docstring is not None:
if not py3 and isinstance(docstring_string, unicode):
- docstring_string = docstring_string.encode(encoding, 'ignore')
- self.list_win.addstr('\n' + docstring_string,
- get_colpair(self.config, 'comment'))
+ docstring_string = docstring_string.encode(encoding, "ignore")
+ self.list_win.addstr(
+ "\n" + docstring_string, get_colpair(self.config, "comment")
+ )
# XXX: After all the trouble I had with sizing the list box (I'm not very good
# at that type of thing) I decided to do this bit of tidying up here just to
# make sure there's no unnecessary blank lines, it makes things look nicer.
@@ -1388,7 +1422,7 @@ def lsize():
self.statusbar.win.touchwin()
self.statusbar.win.noutrefresh()
- self.list_win.attron(get_colpair(self.config, 'main'))
+ self.list_win.attron(get_colpair(self.config, "main"))
self.list_win.border()
self.scr.touchwin()
self.scr.cursyncup()
@@ -1412,7 +1446,7 @@ def size(self):
def suspend(self):
"""Suspend the current process for shell job control."""
- if platform.system() != 'Windows':
+ if platform.system() != "Windows":
curses.endwin()
os.kill(os.getpid(), signal.SIGSTOP)
@@ -1435,7 +1469,7 @@ def tab(self, back=False):
if not num_spaces:
num_spaces = self.config.tab_length
- self.addstr(' ' * num_spaces)
+ self.addstr(" " * num_spaces)
self.print_line(self.s)
return True
@@ -1458,13 +1492,17 @@ def tab(self, back=False):
# 4. swap current word for a match list item
elif self.matches_iter.matches:
- current_match = back and self.matches_iter.previous() \
- or next(self.matches_iter)
+ current_match = (
+ back and self.matches_iter.previous() or next(self.matches_iter)
+ )
try:
- self.show_list(self.matches_iter.matches, self.arg_pos,
- topline=self.funcprops,
- formatter=self.matches_iter.completer.format,
- current_item=current_match)
+ self.show_list(
+ self.matches_iter.matches,
+ self.arg_pos,
+ topline=self.funcprops,
+ formatter=self.matches_iter.completer.format,
+ current_item=current_match,
+ )
except curses.error:
# XXX: This is a massive hack, it will go away when I get
# cusswords into a good enough state that we can start
@@ -1483,8 +1521,9 @@ def undo(self, n=1):
def writetb(self, lines):
for line in lines:
- self.write('\x01%s\x03%s' % (self.config.color_scheme['error'],
- line))
+ self.write(
+ "\x01%s\x03%s" % (self.config.color_scheme["error"], line)
+ )
def yank_from_buffer(self):
"""Paste the text from the cut buffer at the current cursor location"""
@@ -1492,28 +1531,28 @@ def yank_from_buffer(self):
self.print_line(self.s, clr=True)
def send_current_line_to_editor(self):
- lines = self.send_to_external_editor(self.s).split('\n')
- self.s = ''
+ lines = self.send_to_external_editor(self.s).split("\n")
+ self.s = ""
self.print_line(self.s)
while lines and not lines[-1]:
lines.pop()
if not lines:
- return ''
+ return ""
- self.f_string = ''
+ self.f_string = ""
self.cpos = -1 # Set cursor position to -1 to prevent paren matching
self.iy, self.ix = self.scr.getyx()
self.evaluating = True
for line in lines:
if py3:
- self.stdout_hist += line + '\n'
+ self.stdout_hist += line + "\n"
else:
- self.stdout_hist += line.encode(getpreferredencoding()) + '\n'
+ self.stdout_hist += line.encode(getpreferredencoding()) + "\n"
self.history.append(line)
self.print_line(line)
self.s_hist[-1] += self.f_string
- self.scr.addstr('\n')
+ self.scr.addstr("\n")
self.more = self.push(line)
self.prompt(self.more)
self.iy, self.ix = self.scr.getyx()
@@ -1521,7 +1560,7 @@ def send_current_line_to_editor(self):
self.cpos = 0
indent = repl.next_indentation(self.s, self.config.tab_length)
- self.s = ''
+ self.s = ""
self.scr.refresh()
if self.buffer:
@@ -1530,7 +1569,7 @@ def send_current_line_to_editor(self):
self.print_line(self.s)
self.scr.redrawwin()
- return ''
+ return ""
class Statusbar(object):
@@ -1564,7 +1603,7 @@ def __init__(self, scr, pwin, background, config, s=None, c=None):
self.config = config
- self.s = s or ''
+ self.s = s or ""
self._s = self.s
self.c = c
self.timer = 0
@@ -1611,12 +1650,12 @@ def message(self, s, n=3):
self.timer = time.time() + n
self.settext(s)
- def prompt(self, s=''):
+ def prompt(self, s=""):
"""Prompt the user for some input (with the optional prompt 's') and
return the input text, then restore the statusbar to its original
value."""
- self.settext(s or '? ', p=True)
+ self.settext(s or "? ", p=True)
iy, ix = self.win.getyx()
def bs(s):
@@ -1628,7 +1667,7 @@ def bs(s):
self.win.move(y, x - 1)
return s
- o = ''
+ o = ""
while True:
c = self.win.getch()
@@ -1645,7 +1684,7 @@ def bs(s):
# literal
elif 0 < c < 127:
c = chr(c)
- self.win.addstr(c, get_colpair(self.config, 'prompt'))
+ self.win.addstr(c, get_colpair(self.config, "prompt"))
o += c
self.settext(self._s)
@@ -1660,7 +1699,7 @@ def settext(self, s, c=None, p=False):
self.win.erase()
if len(s) >= self.w:
- s = s[:self.w - 1]
+ s = s[: self.w - 1]
self.s = s
if c:
@@ -1691,7 +1730,7 @@ def init_wins(scr, config):
status bar at the bottom with some stuff in it)"""
# TODO: Document better what stuff is on the status bar.
- background = get_colpair(config, 'background')
+ background = get_colpair(config, "background")
h, w = gethw()
main_win = newwin(background, h - 1, w, 0, 0)
@@ -1701,18 +1740,20 @@ def init_wins(scr, config):
# problems that needed dirty hackery to fix. :)
commands = (
- (_('Rewind'), config.undo_key),
- (_('Save'), config.save_key),
- (_('Pastebin'), config.pastebin_key),
- (_('Pager'), config.last_output_key),
- (_('Show Source'), config.show_source_key)
+ (_("Rewind"), config.undo_key),
+ (_("Save"), config.save_key),
+ (_("Pastebin"), config.pastebin_key),
+ (_("Pager"), config.last_output_key),
+ (_("Show Source"), config.show_source_key),
)
- message = ' '.join('<%s> %s' % (key, command) for command, key in commands
- if key)
+ message = " ".join(
+ "<%s> %s" % (key, command) for command, key in commands if key
+ )
- statusbar = Statusbar(scr, main_win, background, config, message,
- get_colpair(config, 'main'))
+ statusbar = Statusbar(
+ scr, main_win, background, config, message, get_colpair(config, "main")
+ )
return main_win, statusbar
@@ -1725,7 +1766,7 @@ def sigwinch(unused_scr):
def sigcont(unused_scr):
sigwinch(unused_scr)
# Forces the redraw
- curses.ungetch('\x00')
+ curses.ungetch("\x00")
def gethw():
@@ -1744,10 +1785,10 @@ def gethw():
"""
- if platform.system() != 'Windows':
+ if platform.system() != "Windows":
h, w = struct.unpack(
- "hhhh",
- fcntl.ioctl(sys.__stdout__, termios.TIOCGWINSZ, "\000" * 8))[0:2]
+ "hhhh", fcntl.ioctl(sys.__stdout__, termios.TIOCGWINSZ, "\000" * 8)
+ )[0:2]
else:
from ctypes import windll, create_string_buffer
@@ -1760,8 +1801,19 @@ def gethw():
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
if res:
- (bufx, bufy, curx, cury, wattr,
- left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
+ (
+ bufx,
+ bufy,
+ curx,
+ cury,
+ wattr,
+ left,
+ top,
+ right,
+ bottom,
+ maxx,
+ maxy,
+ ) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
else:
@@ -1787,7 +1839,7 @@ def idle(caller):
if key != -1:
curses.ungetch(key)
else:
- curses.ungetch('\x00')
+ curses.ungetch("\x00")
caller.statusbar.check()
caller.check()
@@ -1833,7 +1885,7 @@ def newwin(background, *args):
"""Wrapper for curses.newwin to automatically set background colour on any
newly created window."""
win = curses.newwin(*args)
- win.bkgd(' ', background)
+ win.bkgd(" ", background)
return win
@@ -1860,8 +1912,7 @@ def curses_wrapper(func, *args, **kwargs):
curses.endwin()
-def main_curses(scr, args, config, interactive=True, locals_=None,
- banner=None):
+def main_curses(scr, args, config, interactive=True, locals_=None, banner=None):
"""main function for the curses convenience wrapper
Initialise the two main objects: the interpreter
@@ -1879,12 +1930,14 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
global colors
DO_RESIZE = False
- if platform.system() != 'Windows':
- old_sigwinch_handler = signal.signal(signal.SIGWINCH,
- lambda *_: sigwinch(scr))
+ if platform.system() != "Windows":
+ old_sigwinch_handler = signal.signal(
+ signal.SIGWINCH, lambda *_: sigwinch(scr)
+ )
# redraw window after being suspended
old_sigcont_handler = signal.signal(
- signal.SIGCONT, lambda *_: sigcont(scr))
+ signal.SIGCONT, lambda *_: sigcont(scr)
+ )
stdscr = scr
try:
@@ -1924,7 +1977,7 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
curses.raw(False)
return (exit_value, clirepl.getstdout())
else:
- sys.path.insert(0, '')
+ sys.path.insert(0, "")
try:
clirepl.startup()
except OSError as e:
@@ -1934,11 +1987,11 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
if banner is not None:
clirepl.write(banner)
- clirepl.write('\n')
+ clirepl.write("\n")
exit_value = clirepl.repl()
- if hasattr(sys, 'exitfunc'):
+ if hasattr(sys, "exitfunc"):
sys.exitfunc()
- delattr(sys, 'exitfunc')
+ delattr(sys, "exitfunc")
main_win.erase()
main_win.refresh()
@@ -1947,7 +2000,7 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
curses.raw(False)
# Restore signal handlers
- if platform.system() != 'Windows':
+ if platform.system() != "Windows":
signal.signal(signal.SIGWINCH, old_sigwinch_handler)
signal.signal(signal.SIGCONT, old_sigcont_handler)
@@ -1966,8 +2019,13 @@ def main(args=None, locals_=None, banner=None):
try:
(exit_value, output) = curses_wrapper(
- main_curses, exec_args, config, options.interactive, locals_,
- banner=banner)
+ main_curses,
+ exec_args,
+ config,
+ options.interactive,
+ locals_,
+ banner=banner,
+ )
finally:
sys.stdin = orig_stdin
sys.stderr = orig_stderr
@@ -1976,12 +2034,12 @@ def main(args=None, locals_=None, banner=None):
# Fake stdout data so everything's still visible after exiting
if config.flush_output and not options.quiet:
sys.stdout.write(output)
- if hasattr(sys.stdout, 'flush'):
+ if hasattr(sys.stdout, "flush"):
sys.stdout.flush()
return repl.extract_exit_value(exit_value)
-if __name__ == '__main__':
+if __name__ == "__main__":
sys.exit(main())
# vim: sw=4 ts=4 sts=4 ai et
diff --git a/bpython/clipboard.py b/bpython/clipboard.py
index 89a419f32..aee429b9e 100644
--- a/bpython/clipboard.py
+++ b/bpython/clipboard.py
@@ -38,8 +38,9 @@ class XClipboard(object):
"""Manage clipboard with xclip."""
def copy(self, content):
- process = subprocess.Popen(['xclip', '-i', '-selection', 'clipboard'],
- stdin=subprocess.PIPE)
+ process = subprocess.Popen(
+ ["xclip", "-i", "-selection", "clipboard"], stdin=subprocess.PIPE
+ )
process.communicate(content.encode(getpreferredencoding()))
if process.returncode != 0:
raise CopyFailed()
@@ -49,15 +50,16 @@ class OSXClipboard(object):
"""Manage clipboard with pbcopy."""
def copy(self, content):
- process = subprocess.Popen(['pbcopy', 'w'], stdin=subprocess.PIPE)
+ process = subprocess.Popen(["pbcopy", "w"], stdin=subprocess.PIPE)
process.communicate(content.encode(getpreferredencoding()))
if process.returncode != 0:
raise CopyFailed()
def command_exists(command):
- process = subprocess.Popen(['which', command], stderr=subprocess.STDOUT,
- stdout=subprocess.PIPE)
+ process = subprocess.Popen(
+ ["which", command], stderr=subprocess.STDOUT, stdout=subprocess.PIPE
+ )
process.communicate()
return process.returncode == 0
@@ -66,12 +68,14 @@ def command_exists(command):
def get_clipboard():
"""Get best clipboard handling implementation for current system."""
- if platform.system() == 'Darwin':
- if command_exists('pbcopy'):
+ if platform.system() == "Darwin":
+ if command_exists("pbcopy"):
return OSXClipboard()
- if (platform.system() in ('Linux', 'FreeBSD', 'OpenBSD') and
- os.getenv('DISPLAY') is not None):
- if command_exists('xclip'):
+ if (
+ platform.system() in ("Linux", "FreeBSD", "OpenBSD")
+ and os.getenv("DISPLAY") is not None
+ ):
+ if command_exists("xclip"):
return XClipboard()
return None
diff --git a/bpython/config.py b/bpython/config.py
index d9a2147cd..456479b7a 100644
--- a/bpython/config.py
+++ b/bpython/config.py
@@ -32,18 +32,18 @@ def can_encode(c):
def supports_box_chars():
"""Check if the encoding supports Unicode box characters."""
- return all(map(can_encode, u'│─└┘┌┐'))
+ return all(map(can_encode, "│─└┘┌┐"))
def get_config_home():
"""Returns the base directory for bpython's configuration files."""
- xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '~/.config')
- return os.path.join(xdg_config_home, 'bpython')
+ xdg_config_home = os.environ.get("XDG_CONFIG_HOME", "~/.config")
+ return os.path.join(xdg_config_home, "bpython")
def default_config_path():
"""Returns bpython's default configuration file path."""
- return os.path.join(get_config_home(), 'config')
+ return os.path.join(get_config_home(), "config")
def fill_config_with_default_values(config, default_values):
@@ -53,7 +53,7 @@ def fill_config_with_default_values(config, default_values):
for (opt, val) in iteritems(default_values[section]):
if not config.has_option(section, opt):
- config.set(section, opt, '%s' % (val, ))
+ config.set(section, opt, "%s" % (val,))
def loadini(struct, configfile):
@@ -63,103 +63,104 @@ def loadini(struct, configfile):
config = ConfigParser()
defaults = {
- 'general': {
- 'arg_spec': True,
- 'auto_display_list': True,
- 'autocomplete_mode': default_completion,
- 'color_scheme': 'default',
- 'complete_magic_methods': True,
- 'dedent_after': 1,
- 'default_autoreload': False,
- 'editor': os.environ.get('VISUAL', os.environ.get('EDITOR', 'vi')),
- 'flush_output': True,
- 'highlight_show_source': True,
- 'hist_duplicates': True,
- 'hist_file': '~/.pythonhist',
- 'hist_length': 1000,
- 'paste_time': 0.02,
- 'pastebin_confirm': True,
- 'pastebin_expiry': '1week',
- 'pastebin_helper': '',
- 'pastebin_removal_url': 'https://bpaste.net/remove/$removal_id',
- 'pastebin_show_url': 'https://bpaste.net/show/$paste_id',
- 'pastebin_url': 'https://bpaste.net/json/new',
- 'save_append_py': False,
- 'single_undo_time': 1.0,
- 'syntax': True,
- 'tab_length': 4,
- 'unicode_box': True
+ "general": {
+ "arg_spec": True,
+ "auto_display_list": True,
+ "autocomplete_mode": default_completion,
+ "color_scheme": "default",
+ "complete_magic_methods": True,
+ "dedent_after": 1,
+ "default_autoreload": False,
+ "editor": os.environ.get("VISUAL", os.environ.get("EDITOR", "vi")),
+ "flush_output": True,
+ "highlight_show_source": True,
+ "hist_duplicates": True,
+ "hist_file": "~/.pythonhist",
+ "hist_length": 1000,
+ "paste_time": 0.02,
+ "pastebin_confirm": True,
+ "pastebin_expiry": "1week",
+ "pastebin_helper": "",
+ "pastebin_removal_url": "https://bpaste.net/remove/$removal_id",
+ "pastebin_show_url": "https://bpaste.net/show/$paste_id",
+ "pastebin_url": "https://bpaste.net/json/new",
+ "save_append_py": False,
+ "single_undo_time": 1.0,
+ "syntax": True,
+ "tab_length": 4,
+ "unicode_box": True,
},
- 'keyboard': {
- 'backspace': 'C-h',
- 'beginning_of_line': 'C-a',
- 'clear_line': 'C-u',
- 'clear_screen': 'C-l',
- 'clear_word': 'C-w',
- 'copy_clipboard': 'F10',
- 'cut_to_buffer': 'C-k',
- 'delete': 'C-d',
- 'down_one_line': 'C-n',
- 'edit_config': 'F3',
- 'edit_current_block': 'C-x',
- 'end_of_line': 'C-e',
- 'exit': '',
- 'external_editor': 'F7',
- 'help': 'F1',
- 'incremental_search': 'M-s',
- 'last_output': 'F9',
- 'left': 'C-b',
- 'pastebin': 'F8',
- 'reimport': 'F6',
- 'reverse_incremental_search': 'M-r',
- 'right': 'C-f',
- 'save': 'C-s',
- 'search': 'C-o',
- 'show_source': 'F2',
- 'suspend': 'C-z',
- 'toggle_file_watch': 'F5',
- 'transpose_chars': 'C-t',
- 'undo': 'C-r',
- 'up_one_line': 'C-p',
- 'yank_from_buffer': 'C-y'
+ "keyboard": {
+ "backspace": "C-h",
+ "beginning_of_line": "C-a",
+ "clear_line": "C-u",
+ "clear_screen": "C-l",
+ "clear_word": "C-w",
+ "copy_clipboard": "F10",
+ "cut_to_buffer": "C-k",
+ "delete": "C-d",
+ "down_one_line": "C-n",
+ "edit_config": "F3",
+ "edit_current_block": "C-x",
+ "end_of_line": "C-e",
+ "exit": "",
+ "external_editor": "F7",
+ "help": "F1",
+ "incremental_search": "M-s",
+ "last_output": "F9",
+ "left": "C-b",
+ "pastebin": "F8",
+ "reimport": "F6",
+ "reverse_incremental_search": "M-r",
+ "right": "C-f",
+ "save": "C-s",
+ "search": "C-o",
+ "show_source": "F2",
+ "suspend": "C-z",
+ "toggle_file_watch": "F5",
+ "transpose_chars": "C-t",
+ "undo": "C-r",
+ "up_one_line": "C-p",
+ "yank_from_buffer": "C-y",
},
- 'cli': {
- 'suggestion_width': 0.8,
- 'trim_prompts': False,
- },
- 'curtsies': {
- 'list_above': False,
- 'right_arrow_completion': True,
- }}
+ "cli": {"suggestion_width": 0.8, "trim_prompts": False,},
+ "curtsies": {"list_above": False, "right_arrow_completion": True,},
+ }
- default_keys_to_commands = dict((value, key) for (key, value)
- in iteritems(defaults['keyboard']))
+ default_keys_to_commands = dict(
+ (value, key) for (key, value) in iteritems(defaults["keyboard"])
+ )
fill_config_with_default_values(config, defaults)
try:
if not config.read(config_path):
# No config file. If the user has it in the old place then complain
- if os.path.isfile(os.path.expanduser('~/.bpython.ini')):
- sys.stderr.write("Error: It seems that you have a config file at "
- "~/.bpython.ini. Please move your config file to "
- "%s\n" % default_config_path())
+ if os.path.isfile(os.path.expanduser("~/.bpython.ini")):
+ sys.stderr.write(
+ "Error: It seems that you have a config file at "
+ "~/.bpython.ini. Please move your config file to "
+ "%s\n" % default_config_path()
+ )
sys.exit(1)
except UnicodeDecodeError as e:
- sys.stderr.write("Error: Unable to parse config file at '{}' due to an "
- "encoding issue. Please make sure to fix the encoding "
- "of the file or remove it and then try again.\n".format(config_path))
+ sys.stderr.write(
+ "Error: Unable to parse config file at '{}' due to an "
+ "encoding issue. Please make sure to fix the encoding "
+ "of the file or remove it and then try again.\n".format(config_path)
+ )
sys.exit(1)
def get_key_no_doublebind(command):
- default_commands_to_keys = defaults['keyboard']
- requested_key = config.get('keyboard', command)
+ default_commands_to_keys = defaults["keyboard"]
+ requested_key = config.get("keyboard", command)
try:
default_command = default_keys_to_commands[requested_key]
- if (default_commands_to_keys[default_command] ==
- config.get('keyboard', default_command)):
- setattr(struct, '%s_key' % default_command, '')
+ if default_commands_to_keys[default_command] == config.get(
+ "keyboard", default_command
+ ):
+ setattr(struct, "%s_key" % default_command, "")
except KeyError:
pass
@@ -167,113 +168,117 @@ def get_key_no_doublebind(command):
struct.config_path = config_path
- struct.dedent_after = config.getint('general', 'dedent_after')
- struct.tab_length = config.getint('general', 'tab_length')
- struct.auto_display_list = config.getboolean('general',
- 'auto_display_list')
- struct.syntax = config.getboolean('general', 'syntax')
- struct.arg_spec = config.getboolean('general', 'arg_spec')
- struct.paste_time = config.getfloat('general', 'paste_time')
- struct.single_undo_time = config.getfloat('general', 'single_undo_time')
- struct.highlight_show_source = config.getboolean('general',
- 'highlight_show_source')
- struct.hist_file = config.get('general', 'hist_file')
- struct.editor = config.get('general', 'editor')
- struct.hist_length = config.getint('general', 'hist_length')
- struct.hist_duplicates = config.getboolean('general', 'hist_duplicates')
- struct.flush_output = config.getboolean('general', 'flush_output')
+ struct.dedent_after = config.getint("general", "dedent_after")
+ struct.tab_length = config.getint("general", "tab_length")
+ struct.auto_display_list = config.getboolean("general", "auto_display_list")
+ struct.syntax = config.getboolean("general", "syntax")
+ struct.arg_spec = config.getboolean("general", "arg_spec")
+ struct.paste_time = config.getfloat("general", "paste_time")
+ struct.single_undo_time = config.getfloat("general", "single_undo_time")
+ struct.highlight_show_source = config.getboolean(
+ "general", "highlight_show_source"
+ )
+ struct.hist_file = config.get("general", "hist_file")
+ struct.editor = config.get("general", "editor")
+ struct.hist_length = config.getint("general", "hist_length")
+ struct.hist_duplicates = config.getboolean("general", "hist_duplicates")
+ struct.flush_output = config.getboolean("general", "flush_output")
struct.default_autoreload = config.getboolean(
- 'general', 'default_autoreload')
-
- struct.pastebin_key = get_key_no_doublebind('pastebin')
- struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard')
- struct.save_key = get_key_no_doublebind('save')
- struct.search_key = get_key_no_doublebind('search')
- struct.show_source_key = get_key_no_doublebind('show_source')
- struct.suspend_key = get_key_no_doublebind('suspend')
- struct.toggle_file_watch_key = get_key_no_doublebind('toggle_file_watch')
- struct.undo_key = get_key_no_doublebind('undo')
- struct.reimport_key = get_key_no_doublebind('reimport')
+ "general", "default_autoreload"
+ )
+
+ struct.pastebin_key = get_key_no_doublebind("pastebin")
+ struct.copy_clipboard_key = get_key_no_doublebind("copy_clipboard")
+ struct.save_key = get_key_no_doublebind("save")
+ struct.search_key = get_key_no_doublebind("search")
+ struct.show_source_key = get_key_no_doublebind("show_source")
+ struct.suspend_key = get_key_no_doublebind("suspend")
+ struct.toggle_file_watch_key = get_key_no_doublebind("toggle_file_watch")
+ struct.undo_key = get_key_no_doublebind("undo")
+ struct.reimport_key = get_key_no_doublebind("reimport")
struct.reverse_incremental_search_key = get_key_no_doublebind(
- 'reverse_incremental_search')
- struct.incremental_search_key = get_key_no_doublebind('incremental_search')
- struct.up_one_line_key = get_key_no_doublebind('up_one_line')
- struct.down_one_line_key = get_key_no_doublebind('down_one_line')
- struct.cut_to_buffer_key = get_key_no_doublebind('cut_to_buffer')
- struct.yank_from_buffer_key = get_key_no_doublebind('yank_from_buffer')
- struct.clear_word_key = get_key_no_doublebind('clear_word')
- struct.backspace_key = get_key_no_doublebind('backspace')
- struct.clear_line_key = get_key_no_doublebind('clear_line')
- struct.clear_screen_key = get_key_no_doublebind('clear_screen')
- struct.delete_key = get_key_no_doublebind('delete')
-
- struct.left_key = get_key_no_doublebind('left')
- struct.right_key = get_key_no_doublebind('right')
- struct.end_of_line_key = get_key_no_doublebind('end_of_line')
- struct.beginning_of_line_key = get_key_no_doublebind('beginning_of_line')
- struct.transpose_chars_key = get_key_no_doublebind('transpose_chars')
- struct.exit_key = get_key_no_doublebind('exit')
- struct.last_output_key = get_key_no_doublebind('last_output')
- struct.edit_config_key = get_key_no_doublebind('edit_config')
- struct.edit_current_block_key = get_key_no_doublebind('edit_current_block')
- struct.external_editor_key = get_key_no_doublebind('external_editor')
- struct.help_key = get_key_no_doublebind('help')
-
- struct.pastebin_confirm = config.getboolean('general', 'pastebin_confirm')
- struct.pastebin_url = config.get('general', 'pastebin_url')
- struct.pastebin_show_url = config.get('general', 'pastebin_show_url')
- struct.pastebin_removal_url = config.get('general', 'pastebin_removal_url')
- struct.pastebin_expiry = config.get('general', 'pastebin_expiry')
- struct.pastebin_helper = config.get('general', 'pastebin_helper')
-
- struct.cli_suggestion_width = config.getfloat('cli',
- 'suggestion_width')
- struct.cli_trim_prompts = config.getboolean('cli',
- 'trim_prompts')
-
- struct.complete_magic_methods = config.getboolean('general',
- 'complete_magic_methods')
- struct.autocomplete_mode = config.get('general', 'autocomplete_mode')
- struct.save_append_py = config.getboolean('general', 'save_append_py')
-
- struct.curtsies_list_above = config.getboolean('curtsies', 'list_above')
- struct.curtsies_right_arrow_completion = \
- config.getboolean('curtsies', 'right_arrow_completion')
-
- color_scheme_name = config.get('general', 'color_scheme')
+ "reverse_incremental_search"
+ )
+ struct.incremental_search_key = get_key_no_doublebind("incremental_search")
+ struct.up_one_line_key = get_key_no_doublebind("up_one_line")
+ struct.down_one_line_key = get_key_no_doublebind("down_one_line")
+ struct.cut_to_buffer_key = get_key_no_doublebind("cut_to_buffer")
+ struct.yank_from_buffer_key = get_key_no_doublebind("yank_from_buffer")
+ struct.clear_word_key = get_key_no_doublebind("clear_word")
+ struct.backspace_key = get_key_no_doublebind("backspace")
+ struct.clear_line_key = get_key_no_doublebind("clear_line")
+ struct.clear_screen_key = get_key_no_doublebind("clear_screen")
+ struct.delete_key = get_key_no_doublebind("delete")
+
+ struct.left_key = get_key_no_doublebind("left")
+ struct.right_key = get_key_no_doublebind("right")
+ struct.end_of_line_key = get_key_no_doublebind("end_of_line")
+ struct.beginning_of_line_key = get_key_no_doublebind("beginning_of_line")
+ struct.transpose_chars_key = get_key_no_doublebind("transpose_chars")
+ struct.exit_key = get_key_no_doublebind("exit")
+ struct.last_output_key = get_key_no_doublebind("last_output")
+ struct.edit_config_key = get_key_no_doublebind("edit_config")
+ struct.edit_current_block_key = get_key_no_doublebind("edit_current_block")
+ struct.external_editor_key = get_key_no_doublebind("external_editor")
+ struct.help_key = get_key_no_doublebind("help")
+
+ struct.pastebin_confirm = config.getboolean("general", "pastebin_confirm")
+ struct.pastebin_url = config.get("general", "pastebin_url")
+ struct.pastebin_show_url = config.get("general", "pastebin_show_url")
+ struct.pastebin_removal_url = config.get("general", "pastebin_removal_url")
+ struct.pastebin_expiry = config.get("general", "pastebin_expiry")
+ struct.pastebin_helper = config.get("general", "pastebin_helper")
+
+ struct.cli_suggestion_width = config.getfloat("cli", "suggestion_width")
+ struct.cli_trim_prompts = config.getboolean("cli", "trim_prompts")
+
+ struct.complete_magic_methods = config.getboolean(
+ "general", "complete_magic_methods"
+ )
+ struct.autocomplete_mode = config.get("general", "autocomplete_mode")
+ struct.save_append_py = config.getboolean("general", "save_append_py")
+
+ struct.curtsies_list_above = config.getboolean("curtsies", "list_above")
+ struct.curtsies_right_arrow_completion = config.getboolean(
+ "curtsies", "right_arrow_completion"
+ )
+
+ color_scheme_name = config.get("general", "color_scheme")
default_colors = {
- 'keyword': 'y',
- 'name': 'c',
- 'comment': 'b',
- 'string': 'm',
- 'error': 'r',
- 'number': 'G',
- 'operator': 'Y',
- 'punctuation': 'y',
- 'token': 'C',
- 'background': 'd',
- 'output': 'w',
- 'main': 'c',
- 'paren': 'R',
- 'prompt': 'c',
- 'prompt_more': 'g',
- 'right_arrow_suggestion': 'K',
+ "keyword": "y",
+ "name": "c",
+ "comment": "b",
+ "string": "m",
+ "error": "r",
+ "number": "G",
+ "operator": "Y",
+ "punctuation": "y",
+ "token": "C",
+ "background": "d",
+ "output": "w",
+ "main": "c",
+ "paren": "R",
+ "prompt": "c",
+ "prompt_more": "g",
+ "right_arrow_suggestion": "K",
}
- if color_scheme_name == 'default':
+ if color_scheme_name == "default":
struct.color_scheme = default_colors
else:
struct.color_scheme = dict()
- theme_filename = color_scheme_name + '.theme'
- path = os.path.expanduser(os.path.join(get_config_home(),
- theme_filename))
+ theme_filename = color_scheme_name + ".theme"
+ path = os.path.expanduser(
+ os.path.join(get_config_home(), theme_filename)
+ )
try:
load_theme(struct, path, struct.color_scheme, default_colors)
except EnvironmentError:
- sys.stderr.write("Could not load theme '%s'.\n" %
- (color_scheme_name, ))
+ sys.stderr.write(
+ "Could not load theme '%s'.\n" % (color_scheme_name,)
+ )
sys.exit(1)
# expand path of history file
@@ -284,35 +289,35 @@ def get_key_no_doublebind(command):
struct.autocomplete_mode = default_completion
# set box drawing characters
- if config.getboolean('general', 'unicode_box') and supports_box_chars():
- struct.left_border = '│'
- struct.right_border = '│'
- struct.top_border = '─'
- struct.bottom_border = '─'
- struct.left_bottom_corner = '└'
- struct.right_bottom_corner = '┘'
- struct.left_top_corner = '┌'
- struct.right_top_corner = '┐'
+ if config.getboolean("general", "unicode_box") and supports_box_chars():
+ struct.left_border = "│"
+ struct.right_border = "│"
+ struct.top_border = "─"
+ struct.bottom_border = "─"
+ struct.left_bottom_corner = "└"
+ struct.right_bottom_corner = "┘"
+ struct.left_top_corner = "┌"
+ struct.right_top_corner = "┐"
else:
- struct.left_border = '|'
- struct.right_border = '|'
- struct.top_border = '-'
- struct.bottom_border = '-'
- struct.left_bottom_corner = '+'
- struct.right_bottom_corner = '+'
- struct.left_top_corner = '+'
- struct.right_top_corner = '+'
+ struct.left_border = "|"
+ struct.right_border = "|"
+ struct.top_border = "-"
+ struct.bottom_border = "-"
+ struct.left_bottom_corner = "+"
+ struct.right_bottom_corner = "+"
+ struct.left_top_corner = "+"
+ struct.right_top_corner = "+"
def load_theme(struct, path, colors, default_colors):
theme = ConfigParser()
- with open(path, 'r') as f:
+ with open(path, "r") as f:
theme.readfp(f)
- for k, v in chain(theme.items('syntax'), theme.items('interface')):
- if theme.has_option('syntax', k):
- colors[k] = theme.get('syntax', k)
+ for k, v in chain(theme.items("syntax"), theme.items("interface")):
+ if theme.has_option("syntax", k):
+ colors[k] = theme.get("syntax", k)
else:
- colors[k] = theme.get('interface', k)
+ colors[k] = theme.get("interface", k)
# Check against default theme to see if all values are defined
for k, v in iteritems(default_colors):
diff --git a/bpython/curtsies.py b/bpython/curtsies.py
index 92e4c8452..05a3e91c7 100644
--- a/bpython/curtsies.py
+++ b/bpython/curtsies.py
@@ -34,26 +34,31 @@
class FullCurtsiesRepl(BaseRepl):
def __init__(self, config, locals_, banner, interp=None):
self.input_generator = curtsies.input.Input(
- keynames='curtsies',
- sigint_event=True,
- paste_threshold=None)
+ keynames="curtsies", sigint_event=True, paste_threshold=None
+ )
self.window = curtsies.window.CursorAwareWindow(
sys.stdout,
sys.stdin,
keep_last_line=True,
hide_cursor=False,
- extra_bytes_callback=self.input_generator.unget_bytes)
+ extra_bytes_callback=self.input_generator.unget_bytes,
+ )
self._request_refresh = self.input_generator.event_trigger(
- bpythonevents.RefreshRequestEvent)
+ bpythonevents.RefreshRequestEvent
+ )
self._schedule_refresh = self.input_generator.scheduled_event_trigger(
- bpythonevents.ScheduledRefreshRequestEvent)
+ bpythonevents.ScheduledRefreshRequestEvent
+ )
self._request_reload = self.input_generator.threadsafe_event_trigger(
- bpythonevents.ReloadEvent)
- self.interrupting_refresh = (self.input_generator
- .threadsafe_event_trigger(lambda: None))
+ bpythonevents.ReloadEvent
+ )
+ self.interrupting_refresh = self.input_generator.threadsafe_event_trigger(
+ lambda: None
+ )
self.request_undo = self.input_generator.event_trigger(
- bpythonevents.UndoEvent)
+ bpythonevents.UndoEvent
+ )
with self.input_generator:
pass # temp hack to get .original_stty
@@ -63,7 +68,8 @@ def __init__(self, config, locals_, banner, interp=None):
config=config,
banner=banner,
interp=interp,
- orig_tcattrs=self.input_generator.original_stty)
+ orig_tcattrs=self.input_generator.original_stty,
+ )
def get_term_hw(self):
return self.window.get_term_hw()
@@ -91,8 +97,8 @@ def process_event_and_paint(self, e):
except (SystemExitFromCodeRunner, SystemExit) as err:
array, cursor_pos = self.paint(
about_to_exit=True,
- user_quit=isinstance(err,
- SystemExitFromCodeRunner))
+ user_quit=isinstance(err, SystemExitFromCodeRunner),
+ )
scrolled = self.window.render_to_terminal(array, cursor_pos)
self.scroll_offset += scrolled
raise
@@ -133,25 +139,39 @@ def main(args=None, locals_=None, banner=None, welcome_message=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")),
- ]))
+ 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)
+ 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
+ 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
@@ -175,7 +195,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
return extract_exit_value(exit_value)
else:
# expected for interactive sessions (vanilla python does it)
- sys.path.insert(0, '')
+ sys.path.insert(0, "")
if not options.quiet:
print(bpargs.version_banner())
@@ -196,7 +216,7 @@ def main(args=None, locals_=None, banner=None, welcome_message=None):
def _combined_events(event_provider, paste_threshold):
"""Combines consecutive keypress events into paste events."""
- timeout = yield 'nonsense_event' # so send can be used immediately
+ timeout = yield "nonsense_event" # so send can be used immediately
queue = collections.deque()
while True:
e = event_provider.send(timeout)
@@ -228,5 +248,5 @@ def combined_events(event_provider, paste_threshold=3):
return g
-if __name__ == '__main__':
+if __name__ == "__main__":
sys.exit(main())
diff --git a/bpython/curtsiesfrontend/_internal.py b/bpython/curtsiesfrontend/_internal.py
index 7d458e646..4f17cb41f 100644
--- a/bpython/curtsiesfrontend/_internal.py
+++ b/bpython/curtsiesfrontend/_internal.py
@@ -42,7 +42,6 @@ def __call__(self, text):
class _Helper(bpython._internal._Helper):
-
def __init__(self, repl=None):
self._repl = repl
pydoc.pager = self.pager
@@ -61,4 +60,5 @@ def __call__(self, *args, **kwargs):
else:
return super(_Helper, self).__call__(*args, **kwargs)
+
# vim: sw=4 ts=4 sts=4 ai et
diff --git a/bpython/curtsiesfrontend/coderunner.py b/bpython/curtsiesfrontend/coderunner.py
index f9cd19589..ceaab8838 100644
--- a/bpython/curtsiesfrontend/coderunner.py
+++ b/bpython/curtsiesfrontend/coderunner.py
@@ -86,6 +86,7 @@ class CodeRunner(object):
just passes whatever is passed in to run_code(for_code) to the
code greenlet
"""
+
def __init__(self, interp=None, request_refresh=lambda: None):
"""
interp is an interpreter object to use. By default a new one is
@@ -113,8 +114,9 @@ def running(self):
def load_code(self, source):
"""Prep code to be run"""
- assert self.source is None, "you shouldn't load code when some is " \
- "already running"
+ assert self.source is None, (
+ "you shouldn't load code when some is " "already running"
+ )
self.source = source
self.code_context = None
@@ -149,10 +151,11 @@ def run_code(self, for_code=None):
else:
request = self.code_context.switch(for_code)
- logger.debug('request received from code was %r', request)
+ logger.debug("request received from code was %r", request)
if not isinstance(request, RequestFromCodeRunner):
- raise ValueError("Not a valid value from code greenlet: %r" %
- request)
+ raise ValueError(
+ "Not a valid value from code greenlet: %r" % request
+ )
if isinstance(request, (Wait, Refresh)):
self.code_is_waiting = True
if isinstance(request, Refresh):
@@ -172,11 +175,13 @@ def sigint_handler(self, *args):
"""SIGINT handler to use while code is running or request being
fulfilled"""
if greenlet.getcurrent() is self.code_context:
- logger.debug('sigint while running user code!')
+ logger.debug("sigint while running user code!")
raise KeyboardInterrupt()
else:
- logger.debug('sigint while fulfilling code request sigint handler '
- 'running!')
+ logger.debug(
+ "sigint while fulfilling code request sigint handler "
+ "running!"
+ )
self.sigint_happened_in_main_context = True
def _blocking_run_code(self):
@@ -215,7 +220,7 @@ def __init__(self, coderunner, on_write, fileno=1):
def write(self, s, *args, **kwargs):
if not py3 and isinstance(s, str):
- s = s.decode(getpreferredencoding(), 'ignore')
+ s = s.decode(getpreferredencoding(), "ignore")
self.on_write(s, *args, **kwargs)
return self.coderunner.request_from_main_context(force_refresh=True)
diff --git a/bpython/curtsiesfrontend/events.py b/bpython/curtsiesfrontend/events.py
index b7766fbe0..15065d36e 100644
--- a/bpython/curtsiesfrontend/events.py
+++ b/bpython/curtsiesfrontend/events.py
@@ -8,15 +8,17 @@
class ReloadEvent(curtsies.events.Event):
"""Request to rerun REPL session ASAP because imported modules changed"""
- def __init__(self, files_modified=('?',)):
+
+ def __init__(self, files_modified=("?",)):
self.files_modified = files_modified
def __repr__(self):
- return "" % (' & '.join(self.files_modified))
+ return "" % (" & ".join(self.files_modified))
class RefreshRequestEvent(curtsies.events.Event):
"""Request to refresh REPL display ASAP"""
+
def __repr__(self):
return ""
@@ -26,12 +28,14 @@ class ScheduledRefreshRequestEvent(curtsies.events.ScheduledEvent):
Used to schedule the disappearance of status bar message that only shows
for a few seconds"""
+
def __init__(self, when):
super(ScheduledRefreshRequestEvent, self).__init__(when)
def __repr__(self):
- return ("" %
- (self.when - time.time()))
+ return "" % (
+ self.when - time.time()
+ )
class RunStartupFileEvent(curtsies.events.Event):
@@ -40,5 +44,6 @@ class RunStartupFileEvent(curtsies.events.Event):
class UndoEvent(curtsies.events.Event):
"""Request to undo."""
+
def __init__(self, n=1):
self.n = n
diff --git a/bpython/curtsiesfrontend/filewatch.py b/bpython/curtsiesfrontend/filewatch.py
index 576852c03..37ea8f509 100644
--- a/bpython/curtsiesfrontend/filewatch.py
+++ b/bpython/curtsiesfrontend/filewatch.py
@@ -9,9 +9,13 @@
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
except ImportError:
+
def ModuleChangedEventHandler(*args):
return None
+
+
else:
+
class ModuleChangedEventHandler(FileSystemEventHandler):
def __init__(self, paths, on_change):
self.dirs = defaultdict(set)
@@ -35,7 +39,7 @@ def _add_module(self, path):
path = os.path.abspath(path)
for suff in importcompletion.SUFFIXES:
if path.endswith(suff):
- path = path[:-len(suff)]
+ path = path[: -len(suff)]
break
dirname = os.path.dirname(path)
if dirname not in self.dirs:
@@ -75,6 +79,6 @@ def deactivate(self):
def on_any_event(self, event):
dirpath = os.path.dirname(event.src_path)
- paths = [path + '.py' for path in self.dirs[dirpath]]
+ paths = [path + ".py" for path in self.dirs[dirpath]]
if event.src_path in paths:
self.on_change(files_modified=[event.src_path])
diff --git a/bpython/curtsiesfrontend/interaction.py b/bpython/curtsiesfrontend/interaction.py
index 80d1f45a1..65b554ead 100644
--- a/bpython/curtsiesfrontend/interaction.py
+++ b/bpython/curtsiesfrontend/interaction.py
@@ -26,18 +26,21 @@ class StatusBar(BpythonInteraction):
functionality in a evented or callback style, but trying to integrate
bpython.Repl code.
"""
- def __init__(self,
- config,
- permanent_text="",
- request_refresh=lambda: None,
- schedule_refresh=lambda when: None):
- self._current_line = ''
+
+ def __init__(
+ self,
+ config,
+ permanent_text="",
+ request_refresh=lambda: None,
+ schedule_refresh=lambda when: None,
+ ):
+ self._current_line = ""
self.cursor_offset_in_line = 0
self.in_prompt = False
self.in_confirm = False
self.waiting_for_refresh = False
- self.prompt = ''
- self._message = ''
+ self.prompt = ""
+ self._message = ""
self.message_start_time = time.time()
self.message_time = 3
self.permanent_stack = []
@@ -51,7 +54,7 @@ def __init__(self,
super(StatusBar, self).__init__(config)
def push_permanent_message(self, msg):
- self._message = ''
+ self._message = ""
self.permanent_stack.append(msg)
def pop_permanent_message(self, msg):
@@ -72,9 +75,11 @@ def message(self, msg, schedule_refresh=True):
self.schedule_refresh(time.time() + self.message_time)
def _check_for_expired_message(self):
- if (self._message and
- time.time() > self.message_start_time + self.message_time):
- self._message = ''
+ if (
+ self._message
+ and time.time() > self.message_start_time + self.message_time
+ ):
+ self._message = ""
def process_event(self, e):
"""Returns True if shutting down"""
@@ -86,12 +91,13 @@ def process_event(self, e):
for ee in e.events:
# strip control seq
self.add_normal_character(ee if len(ee) == 1 else ee[-1])
- elif e in [''] or isinstance(e, events.SigIntEvent):
+ elif e in [""] or isinstance(e, events.SigIntEvent):
self.request_context.switch(False)
self.escape()
elif e in edit_keys:
self.cursor_offset_in_line, self._current_line = edit_keys[e](
- self.cursor_offset_in_line, self._current_line)
+ self.cursor_offset_in_line, self._current_line
+ )
elif e == "": # TODO can this be removed?
raise KeyboardInterrupt()
elif e == "": # TODO this isn't a very intuitive behavior
@@ -101,7 +107,7 @@ def process_event(self, e):
self.escape()
self.request_context.switch(line)
elif self.in_confirm:
- if e in ('y', 'Y'):
+ if e in ("y", "Y"):
self.request_context.switch(True)
else:
self.request_context.switch(False)
@@ -110,21 +116,23 @@ def process_event(self, e):
self.add_normal_character(e)
def add_normal_character(self, e):
- if e == '':
- e = ' '
+ if e == "":
+ e = " "
if len(e) > 1:
return
- self._current_line = (self._current_line[:self.cursor_offset_in_line] +
- e +
- self._current_line[self.cursor_offset_in_line:])
+ self._current_line = (
+ self._current_line[: self.cursor_offset_in_line]
+ + e
+ + self._current_line[self.cursor_offset_in_line :]
+ )
self.cursor_offset_in_line += 1
def escape(self):
"""unfocus from statusbar, clear prompt state, wait for notify call"""
self.in_prompt = False
self.in_confirm = False
- self.prompt = ''
- self._current_line = ''
+ self.prompt = ""
+ self._current_line = ""
@property
def current_line(self):
@@ -137,7 +145,7 @@ def current_line(self):
return self._message
if self.permanent_stack:
return self.permanent_stack[-1]
- return ''
+ return ""
@property
def should_show_message(self):
diff --git a/bpython/curtsiesfrontend/interpreter.py b/bpython/curtsiesfrontend/interpreter.py
index 139039f5b..57c694ce4 100644
--- a/bpython/curtsiesfrontend/interpreter.py
+++ b/bpython/curtsiesfrontend/interpreter.py
@@ -14,23 +14,23 @@
default_colors = {
- Generic.Error: 'R',
- Keyword: 'd',
- Name: 'c',
- Name.Builtin: 'g',
- Comment: 'b',
- String: 'm',
- Error: 'r',
- Literal: 'd',
- Number: 'M',
- Number.Integer: 'd',
- Operator: 'd',
- Punctuation: 'd',
- Token: 'd',
- Whitespace: 'd',
- Token.Punctuation.Parenthesis: 'R',
- Name.Function: 'd',
- Name.Class: 'd'
+ Generic.Error: "R",
+ Keyword: "d",
+ Name: "c",
+ Name.Builtin: "g",
+ Comment: "b",
+ String: "m",
+ Error: "r",
+ Literal: "d",
+ Number: "M",
+ Number.Integer: "d",
+ Operator: "d",
+ Punctuation: "d",
+ Token: "d",
+ Whitespace: "d",
+ Token.Punctuation.Parenthesis: "R",
+ Name.Function: "d",
+ Name.Class: "d",
}
@@ -48,11 +48,11 @@ class BPythonFormatter(Formatter):
def __init__(self, color_scheme, **options):
self.f_strings = {}
for k, v in iteritems(color_scheme):
- self.f_strings[k] = '\x01%s' % (v,)
+ self.f_strings[k] = "\x01%s" % (v,)
super(BPythonFormatter, self).__init__(**options)
def format(self, tokensource, outfile):
- o = ''
+ o = ""
for token, text in tokensource:
while token not in self.f_strings:
@@ -82,29 +82,30 @@ def write(err_line):
self.outfile = self
def writetb(self, lines):
- tbtext = ''.join(lines)
+ tbtext = "".join(lines)
lexer = get_lexer_by_name("pytb")
self.format(tbtext, lexer)
# TODO for tracebacks get_lexer_by_name("pytb", stripall=True)
def format(self, tbtext, lexer):
traceback_informative_formatter = BPythonFormatter(default_colors)
- traceback_code_formatter = BPythonFormatter({Token: ('d')})
+ traceback_code_formatter = BPythonFormatter({Token: ("d")})
tokens = list(lexer.get_tokens(tbtext))
no_format_mode = False
cur_line = []
for token, text in tokens:
- if text.endswith('\n'):
+ if text.endswith("\n"):
cur_line.append((token, text))
if no_format_mode:
traceback_code_formatter.format(cur_line, self.outfile)
no_format_mode = False
else:
- traceback_informative_formatter.format(cur_line,
- self.outfile)
+ traceback_informative_formatter.format(
+ cur_line, self.outfile
+ )
cur_line = []
- elif text == ' ' and cur_line == []:
+ elif text == " " and cur_line == []:
no_format_mode = True
cur_line.append((token, text))
else:
diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py
index 223ec9e71..7448d4bf8 100644
--- a/bpython/curtsiesfrontend/manual_readline.py
+++ b/bpython/curtsiesfrontend/manual_readline.py
@@ -24,9 +24,9 @@
class AbstractEdits(object):
default_kwargs = {
- 'line': 'hello world',
- 'cursor_offset': 5,
- 'cut_buffer': 'there',
+ "line": "hello world",
+ "cursor_offset": 5,
+ "cut_buffer": "there",
}
def __contains__(self, key):
@@ -42,29 +42,36 @@ def add(self, key, func, overwrite=False):
if overwrite:
del self[key]
else:
- raise ValueError('key %r already has a mapping' % (key,))
+ raise ValueError("key %r already has a mapping" % (key,))
params = getargspec(func)
- args = dict((k, v) for k, v in iteritems(self.default_kwargs)
- if k in params)
+ args = dict(
+ (k, v) for k, v in iteritems(self.default_kwargs) if k in params
+ )
r = func(**args)
if len(r) == 2:
- if hasattr(func, 'kills'):
- raise ValueError('function %r returns two values, but has a '
- 'kills attribute' % (func,))
+ if hasattr(func, "kills"):
+ raise ValueError(
+ "function %r returns two values, but has a "
+ "kills attribute" % (func,)
+ )
self.simple_edits[key] = func
elif len(r) == 3:
- if not hasattr(func, 'kills'):
- raise ValueError('function %r returns three values, but has '
- 'no kills attribute' % (func,))
+ if not hasattr(func, "kills"):
+ raise ValueError(
+ "function %r returns three values, but has "
+ "no kills attribute" % (func,)
+ )
self.cut_buffer_edits[key] = func
else:
- raise ValueError('return type of function %r not recognized' %
- (func,))
+ raise ValueError(
+ "return type of function %r not recognized" % (func,)
+ )
def add_config_attr(self, config_attr, func):
if config_attr in self.awaiting_config:
- raise ValueError('config attribute %r already has a mapping' %
- (config_attr,))
+ raise ValueError(
+ "config attribute %r already has a mapping" % (config_attr,)
+ )
self.awaiting_config[config_attr] = func
def call(self, key, **kwargs):
@@ -119,27 +126,42 @@ def __init__(self):
def mapping_with_config(self, config, key_dispatch):
"""Creates a new mapping object by applying a config object"""
- return ConfiguredEdits(self.simple_edits, self.cut_buffer_edits,
- self.awaiting_config, config, key_dispatch)
+ return ConfiguredEdits(
+ self.simple_edits,
+ self.cut_buffer_edits,
+ self.awaiting_config,
+ config,
+ key_dispatch,
+ )
def on(self, key=None, config=None):
if not ((key is None) ^ (config is None)):
raise ValueError("Must use exactly one of key, config")
if key is not None:
+
def add_to_keybinds(func):
self.add(key, func)
return func
+
return add_to_keybinds
else:
+
def add_to_config(func):
self.add_config_attr(config, func)
return func
+
return add_to_config
class ConfiguredEdits(AbstractEdits):
- def __init__(self, simple_edits, cut_buffer_edits, awaiting_config, config,
- key_dispatch):
+ def __init__(
+ self,
+ simple_edits,
+ cut_buffer_edits,
+ awaiting_config,
+ config,
+ key_dispatch,
+ ):
self.simple_edits = dict(simple_edits)
self.cut_buffer_edits = dict(cut_buffer_edits)
for attr, func in awaiting_config.items():
@@ -160,35 +182,35 @@ def add(self, key, func):
def kills_behind(func):
- func.kills = 'behind'
+ func.kills = "behind"
return func
def kills_ahead(func):
- func.kills = 'ahead'
+ func.kills = "ahead"
return func
-@edit_keys.on(config='left_key')
-@edit_keys.on('')
+@edit_keys.on(config="left_key")
+@edit_keys.on("")
def left_arrow(cursor_offset, line):
return max(0, cursor_offset - 1), line
-@edit_keys.on(config='right_key')
-@edit_keys.on('')
+@edit_keys.on(config="right_key")
+@edit_keys.on("")
def right_arrow(cursor_offset, line):
return min(len(line), cursor_offset + 1), line
-@edit_keys.on(config='beginning_of_line_key')
-@edit_keys.on('')
+@edit_keys.on(config="beginning_of_line_key")
+@edit_keys.on("")
def beginning_of_line(cursor_offset, line):
return 0, line
-@edit_keys.on(config='end_of_line_key')
-@edit_keys.on('')
+@edit_keys.on(config="end_of_line_key")
+@edit_keys.on("")
def end_of_line(cursor_offset, line):
return len(line), line
@@ -196,11 +218,11 @@ def end_of_line(cursor_offset, line):
forward_word_re = LazyReCompile(r"\S\s")
-@edit_keys.on('')
-@edit_keys.on('')
-@edit_keys.on('')
+@edit_keys.on("")
+@edit_keys.on("")
+@edit_keys.on("")
def forward_word(cursor_offset, line):
- match = forward_word_re.search(line[cursor_offset:]+' ')
+ match = forward_word_re.search(line[cursor_offset:] + " ")
delta = match.end() - 1 if match else 0
return (cursor_offset + delta, line)
@@ -212,21 +234,20 @@ def last_word_pos(string):
return index or 0
-@edit_keys.on('')
-@edit_keys.on('')
-@edit_keys.on('')
+@edit_keys.on("")
+@edit_keys.on("")
+@edit_keys.on("")
def back_word(cursor_offset, line):
return (last_word_pos(line[:cursor_offset]), line)
-@edit_keys.on('')
+@edit_keys.on("")
def delete(cursor_offset, line):
- return (cursor_offset,
- line[:cursor_offset] + line[cursor_offset+1:])
+ return (cursor_offset, line[:cursor_offset] + line[cursor_offset + 1 :])
-@edit_keys.on('')
-@edit_keys.on(config='backspace_key')
+@edit_keys.on("")
+@edit_keys.on(config="backspace_key")
def backspace(cursor_offset, line):
if cursor_offset == 0:
return cursor_offset, line
@@ -234,111 +255,127 @@ def backspace(cursor_offset, line):
# front_white = len(line[:cursor_offset]) - \
# len(line[:cursor_offset].lstrip())
to_delete = ((cursor_offset - 1) % INDENT) + 1
- return (cursor_offset - to_delete,
- line[:cursor_offset - to_delete] + line[cursor_offset:])
- return (cursor_offset - 1,
- line[:cursor_offset - 1] + line[cursor_offset:])
+ return (
+ cursor_offset - to_delete,
+ line[: cursor_offset - to_delete] + line[cursor_offset:],
+ )
+ return (cursor_offset - 1, line[: cursor_offset - 1] + line[cursor_offset:])
-@edit_keys.on(config='clear_line_key')
+@edit_keys.on(config="clear_line_key")
def delete_from_cursor_back(cursor_offset, line):
return 0, line[cursor_offset:]
-delete_rest_of_word_re = LazyReCompile(r'\w\b')
+delete_rest_of_word_re = LazyReCompile(r"\w\b")
-@edit_keys.on('') # option-d
+@edit_keys.on("") # option-d
@kills_ahead
def delete_rest_of_word(cursor_offset, line):
m = delete_rest_of_word_re.search(line[cursor_offset:])
if not m:
- return cursor_offset, line, ''
- return (cursor_offset,
- line[:cursor_offset] + line[m.start()+cursor_offset+1:],
- line[cursor_offset:m.start()+cursor_offset+1])
+ return cursor_offset, line, ""
+ return (
+ cursor_offset,
+ line[:cursor_offset] + line[m.start() + cursor_offset + 1 :],
+ line[cursor_offset : m.start() + cursor_offset + 1],
+ )
-delete_word_to_cursor_re = LazyReCompile(r'\s\S')
+delete_word_to_cursor_re = LazyReCompile(r"\s\S")
-@edit_keys.on(config='clear_word_key')
+@edit_keys.on(config="clear_word_key")
@kills_behind
def delete_word_to_cursor(cursor_offset, line):
start = 0
for match in delete_word_to_cursor_re.finditer(line[:cursor_offset]):
start = match.start() + 1
- return (start, line[:start] + line[cursor_offset:],
- line[start:cursor_offset])
+ return (
+ start,
+ line[:start] + line[cursor_offset:],
+ line[start:cursor_offset],
+ )
-@edit_keys.on('')
+@edit_keys.on("")
def yank_prev_prev_killed_text(cursor_offset, line, cut_buffer):
# TODO not implemented - just prev
- return (cursor_offset+len(cut_buffer),
- line[:cursor_offset] + cut_buffer + line[cursor_offset:])
+ return (
+ cursor_offset + len(cut_buffer),
+ line[:cursor_offset] + cut_buffer + line[cursor_offset:],
+ )
-@edit_keys.on(config='yank_from_buffer_key')
+@edit_keys.on(config="yank_from_buffer_key")
def yank_prev_killed_text(cursor_offset, line, cut_buffer):
- return (cursor_offset+len(cut_buffer),
- line[:cursor_offset] + cut_buffer + line[cursor_offset:])
+ return (
+ cursor_offset + len(cut_buffer),
+ line[:cursor_offset] + cut_buffer + line[cursor_offset:],
+ )
-@edit_keys.on(config='transpose_chars_key')
+@edit_keys.on(config="transpose_chars_key")
def transpose_character_before_cursor(cursor_offset, line):
if cursor_offset < 2:
return cursor_offset, line
if cursor_offset == len(line):
return cursor_offset, line[:-2] + line[-1] + line[-2]
- return (min(len(line), cursor_offset + 1),
- line[:cursor_offset - 1] +
- (line[cursor_offset] if len(line) > cursor_offset else '') +
- line[cursor_offset - 1] +
- line[cursor_offset + 1:])
+ return (
+ min(len(line), cursor_offset + 1),
+ line[: cursor_offset - 1]
+ + (line[cursor_offset] if len(line) > cursor_offset else "")
+ + line[cursor_offset - 1]
+ + line[cursor_offset + 1 :],
+ )
-@edit_keys.on('')
+@edit_keys.on("")
def transpose_word_before_cursor(cursor_offset, line):
return cursor_offset, line # TODO Not implemented
+
# TODO undo all changes to line: meta-r
# bonus functions (not part of readline)
-@edit_keys.on('')
+@edit_keys.on("")
def uppercase_next_word(cursor_offset, line):
return cursor_offset, line # TODO Not implemented
-@edit_keys.on(config='cut_to_buffer_key')
+@edit_keys.on(config="cut_to_buffer_key")
@kills_ahead
def delete_from_cursor_forward(cursor_offset, line):
return cursor_offset, line[:cursor_offset], line[cursor_offset:]
-@edit_keys.on('')
+@edit_keys.on("")
def titlecase_next_word(cursor_offset, line):
return cursor_offset, line # TODO Not implemented
-delete_word_from_cursor_back_re = LazyReCompile(r'^|\b\w')
+delete_word_from_cursor_back_re = LazyReCompile(r"^|\b\w")
-@edit_keys.on('')
-@edit_keys.on('')
+@edit_keys.on("")
+@edit_keys.on("")
@kills_behind
def delete_word_from_cursor_back(cursor_offset, line):
"""Whatever my option-delete does in bash on my mac"""
if not line:
- return cursor_offset, line, ''
+ return cursor_offset, line, ""
start = None
for match in delete_word_from_cursor_back_re.finditer(line):
if match.start() < cursor_offset:
start = match.start()
if start is not None:
- return (start, line[:start] + line[cursor_offset:],
- line[start:cursor_offset])
+ return (
+ start,
+ line[:start] + line[cursor_offset:],
+ line[start:cursor_offset],
+ )
else:
- return cursor_offset, line, ''
+ return cursor_offset, line, ""
diff --git a/bpython/curtsiesfrontend/parse.py b/bpython/curtsiesfrontend/parse.py
index 15a4c04d5..33f8c01ea 100644
--- a/bpython/curtsiesfrontend/parse.py
+++ b/bpython/curtsiesfrontend/parse.py
@@ -10,20 +10,20 @@
from curtsies.formatstring import fmtstr, FmtStr
-cnames = dict(zip('krgybmcwd', colors + ('default',)))
+cnames = dict(zip("krgybmcwd", colors + ("default",)))
-def func_for_letter(l, default='k'):
+def func_for_letter(l, default="k"):
"""Returns FmtStr constructor for a bpython-style color code"""
- if l == 'd':
+ if l == "d":
l = default
- elif l == 'D':
+ elif l == "D":
l = default.upper()
return partial(fmtstr, fg=cnames[l.lower()], bold=l.isupper())
-def color_for_letter(l, default='k'):
- if l == 'd':
+def color_for_letter(l, default="k"):
+ if l == "d":
l = default
return cnames[l.lower()]
@@ -37,35 +37,38 @@ def parse(s):
break
start, rest = peel_off_string(rest)
stuff.append(start)
- return (sum((fs_from_match(d) for d in stuff[1:]), fs_from_match(stuff[0]))
- if len(stuff) > 0
- else FmtStr())
+ return (
+ sum((fs_from_match(d) for d in stuff[1:]), fs_from_match(stuff[0]))
+ if len(stuff) > 0
+ else FmtStr()
+ )
def fs_from_match(d):
atts = {}
- if d['fg']:
+ if d["fg"]:
# this isn't according to spec as I understand it
- if d['fg'].isupper():
- d['bold'] = True
+ if d["fg"].isupper():
+ d["bold"] = True
# TODO figure out why boldness isn't based on presence of \x02
- color = cnames[d['fg'].lower()]
- if color != 'default':
- atts['fg'] = FG_COLORS[color]
- if d['bg']:
- if d['bg'] == 'I':
+ color = cnames[d["fg"].lower()]
+ if color != "default":
+ atts["fg"] = FG_COLORS[color]
+ if d["bg"]:
+ if d["bg"] == "I":
# hack for finding the "inverse"
- color = colors[(colors.index(color) + (len(colors) // 2)) %
- len(colors)]
+ color = colors[
+ (colors.index(color) + (len(colors) // 2)) % len(colors)
+ ]
else:
- color = cnames[d['bg'].lower()]
- if color != 'default':
- atts['bg'] = BG_COLORS[color]
- if d['bold']:
- atts['bold'] = True
- return fmtstr(d['string'], **atts)
+ color = cnames[d["bg"].lower()]
+ if color != "default":
+ atts["bg"] = BG_COLORS[color]
+ if d["bold"]:
+ atts["bold"] = True
+ return fmtstr(d["string"], **atts)
peel_off_string_re = LazyReCompile(
@@ -77,13 +80,15 @@ def fs_from_match(d):
(?P[^\x04]*)
\x04
(?P.*)
- """, re.VERBOSE | re.DOTALL)
+ """,
+ re.VERBOSE | re.DOTALL,
+)
def peel_off_string(s):
m = peel_off_string_re.match(s)
assert m, repr(s)
d = m.groupdict()
- rest = d['rest']
- del d['rest']
+ rest = d["rest"]
+ del d["rest"]
return d, rest
diff --git a/bpython/curtsiesfrontend/preprocess.py b/bpython/curtsiesfrontend/preprocess.py
index 279d25d9e..8169ee46a 100644
--- a/bpython/curtsiesfrontend/preprocess.py
+++ b/bpython/curtsiesfrontend/preprocess.py
@@ -8,23 +8,22 @@
# TODO specifically catch IndentationErrors instead of any syntax errors
-indent_empty_lines_re = LazyReCompile(r'\s*')
-tabs_to_spaces_re = LazyReCompile(r'^\t+')
+indent_empty_lines_re = LazyReCompile(r"\s*")
+tabs_to_spaces_re = LazyReCompile(r"^\t+")
def indent_empty_lines(s, compiler):
"""Indents blank lines that would otherwise cause early compilation
Only really works if starting on a new line"""
- lines = s.split('\n')
+ lines = s.split("\n")
ends_with_newline = False
if lines and not lines[-1]:
ends_with_newline = True
lines.pop()
result_lines = []
- for p_line, line, n_line in zip([''] + lines[:-1], lines,
- lines[1:] + ['']):
+ for p_line, line, n_line in zip([""] + lines[:-1], lines, lines[1:] + [""]):
if len(line) == 0:
p_indent = indent_empty_lines_re.match(p_line).group()
n_indent = indent_empty_lines_re.match(n_line).group()
@@ -32,18 +31,19 @@ def indent_empty_lines(s, compiler):
else:
result_lines.append(line)
- return '\n'.join(result_lines) + ('\n' if ends_with_newline else '')
+ return "\n".join(result_lines) + ("\n" if ends_with_newline else "")
def leading_tabs_to_spaces(s):
- lines = s.split('\n')
+ lines = s.split("\n")
result_lines = []
def tab_to_space(m):
- return len(m.group()) * 4 * ' '
+ return len(m.group()) * 4 * " "
+
for line in lines:
result_lines.append(tabs_to_spaces_re.sub(tab_to_space, line))
- return '\n'.join(result_lines)
+ return "\n".join(result_lines)
def preprocess(s, compiler):
diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py
index 6b415fabd..d4b18e387 100644
--- a/bpython/curtsiesfrontend/repl.py
+++ b/bpython/curtsiesfrontend/repl.py
@@ -29,8 +29,12 @@
import bpython
from bpython.repl import Repl as BpythonRepl, SourceNotFound
-from bpython.config import (Struct, loadini, default_config_path,
- getpreferredencoding)
+from bpython.config import (
+ Struct,
+ loadini,
+ default_config_path,
+ getpreferredencoding,
+)
from bpython.formatter import BPythonFormatter
from bpython import autocomplete
from bpython.translations import _
@@ -47,8 +51,10 @@
from bpython.curtsiesfrontend.parse import parse as bpythonparse
from bpython.curtsiesfrontend.parse import func_for_letter, color_for_letter
from bpython.curtsiesfrontend.preprocess import preprocess
-from bpython.curtsiesfrontend.interpreter import (Interp,
- code_finished_will_parse)
+from bpython.curtsiesfrontend.interpreter import (
+ Interp,
+ code_finished_will_parse,
+)
from curtsies.configfile_keynames import keymap as key_dispatch
@@ -83,7 +89,7 @@
See {example_config_url} for an example config file.
Press {config.edit_config_key} to edit this config file.
"""
-EXAMPLE_CONFIG_URL = 'https://raw.githubusercontent.com/bpython/bpython/master/bpython/sample-config'
+EXAMPLE_CONFIG_URL = "https://raw.githubusercontent.com/bpython/bpython/master/bpython/sample-config"
EDIT_SESSION_HEADER = """### current bpython session - make changes and save to reevaluate session.
### lines beginning with ### will be ignored.
### To return to bpython without reevaluating make no changes to this file
@@ -104,11 +110,12 @@ class FakeStdin(object):
In user code, sys.stdin.read() asks the user for interactive input,
so this class returns control to the UI to get that input."""
+
def __init__(self, coderunner, repl, configured_edit_keys=None):
self.coderunner = coderunner
self.repl = repl
self.has_focus = False # whether FakeStdin receives keypress events
- self.current_line = ''
+ self.current_line = ""
self.cursor_offset = 0
self.old_num_lines = 0
self.readline_results = []
@@ -120,18 +127,19 @@ def __init__(self, coderunner, repl, configured_edit_keys=None):
def process_event(self, e):
assert self.has_focus
- logger.debug('fake input processing event %r', e)
+ logger.debug("fake input processing event %r", e)
if isinstance(e, events.PasteEvent):
for ee in e.events:
if ee not in self.rl_char_sequences:
self.add_input_character(ee)
elif e in self.rl_char_sequences:
self.cursor_offset, self.current_line = self.rl_char_sequences[e](
- self.cursor_offset, self.current_line)
+ self.cursor_offset, self.current_line
+ )
elif isinstance(e, events.SigIntEvent):
self.coderunner.sigint_happened_in_main_context = True
self.has_focus = False
- self.current_line = ''
+ self.current_line = ""
self.cursor_offset = 0
self.repl.run_code_and_maybe_finish()
elif e in ("",):
@@ -139,22 +147,22 @@ def process_event(self, e):
elif e in [""]:
pass
- elif e in ['']:
- if self.current_line == '':
- self.repl.send_to_stdin('\n')
+ elif e in [""]:
+ if self.current_line == "":
+ self.repl.send_to_stdin("\n")
self.has_focus = False
- self.current_line = ''
+ self.current_line = ""
self.cursor_offset = 0
- self.repl.run_code_and_maybe_finish(for_code='')
+ self.repl.run_code_and_maybe_finish(for_code="")
else:
pass
elif e in ["\n", "\r", "", ""]:
line = self.current_line
- self.repl.send_to_stdin(line + '\n')
+ self.repl.send_to_stdin(line + "\n")
self.has_focus = False
- self.current_line = ''
+ self.current_line = ""
self.cursor_offset = 0
- self.repl.run_code_and_maybe_finish(for_code=line + '\n')
+ self.repl.run_code_and_maybe_finish(for_code=line + "\n")
else: # add normal character
self.add_input_character(e)
@@ -164,17 +172,19 @@ def process_event(self, e):
self.repl.send_to_stdin(self.current_line)
def add_input_character(self, e):
- if e == '':
- e = ' '
- if e.startswith('<') and e.endswith('>'):
+ if e == "":
+ e = " "
+ if e.startswith("<") and e.endswith(">"):
return
- assert len(e) == 1, 'added multiple characters: %r' % e
- logger.debug('adding normal char %r to current line', e)
-
- c = e if py3 else e.encode('utf8')
- self.current_line = (self.current_line[:self.cursor_offset] +
- c +
- self.current_line[self.cursor_offset:])
+ assert len(e) == 1, "added multiple characters: %r" % e
+ logger.debug("adding normal char %r to current line", e)
+
+ c = e if py3 else e.encode("utf8")
+ self.current_line = (
+ self.current_line[: self.cursor_offset]
+ + c
+ + self.current_line[self.cursor_offset :]
+ )
self.cursor_offset += 1
def readline(self):
@@ -185,7 +195,7 @@ def readline(self):
return value
def readlines(self, size=-1):
- return list(iter(self.readline, ''))
+ return list(iter(self.readline, ""))
def __iter__(self):
return iter(self.readlines())
@@ -211,7 +221,7 @@ def close(self):
@property
def encoding(self):
- return 'UTF8'
+ return "UTF8"
# TODO write a read() method?
@@ -219,6 +229,7 @@ def encoding(self):
class ReevaluateFakeStdin(object):
"""Stdin mock used during reevaluation (undo) so raw_inputs don't have to
be reentered"""
+
def __init__(self, fakestdin, repl):
self.fakestdin = fakestdin
self.repl = repl
@@ -228,20 +239,19 @@ def readline(self):
if self.readline_results:
value = self.readline_results.pop(0)
else:
- value = 'no saved input available'
+ value = "no saved input available"
self.repl.send_to_stdouterr(value)
return value
class ImportLoader(object):
-
def __init__(self, watcher, loader):
self.watcher = watcher
self.loader = loader
def load_module(self, name):
module = self.loader.load_module(name)
- if hasattr(module, '__file__'):
+ if hasattr(module, "__file__"):
self.watcher.track_module(module.__file__)
return module
@@ -249,20 +259,18 @@ def load_module(self, name):
if not py3:
# Remember that pkgutil.ImpLoader is an old style class.
class ImpImportLoader(pkgutil.ImpLoader):
-
def __init__(self, watcher, *args):
self.watcher = watcher
pkgutil.ImpLoader.__init__(self, *args)
def load_module(self, name):
module = pkgutil.ImpLoader.load_module(self, name)
- if hasattr(module, '__file__'):
+ if hasattr(module, "__file__"):
self.watcher.track_module(module.__file__)
return module
class ImportFinder(object):
-
def __init__(self, watcher, old_meta_path):
self.watcher = watcher
self.old_meta_path = old_meta_path
@@ -307,12 +315,14 @@ class BaseRepl(BpythonRepl):
Subclasses are responsible for implementing several methods.
"""
- def __init__(self,
- locals_=None,
- config=None,
- banner=None,
- interp=None,
- orig_tcattrs=None):
+ def __init__(
+ self,
+ locals_=None,
+ config=None,
+ banner=None,
+ interp=None,
+ orig_tcattrs=None,
+ ):
"""
locals_ is a mapping of locals to pass into the interpreter
config is a bpython config.Struct with config attributes
@@ -336,8 +346,11 @@ def __init__(self,
interp.write = self.send_to_stdouterr
if banner is None:
if config.help_key:
- banner = (_('Welcome to bpython!') + ' ' +
- _('Press <%s> for help.') % config.help_key)
+ banner = (
+ _("Welcome to bpython!")
+ + " "
+ + _("Press <%s> for help.") % config.help_key
+ )
else:
banner = None
# only one implemented currently
@@ -348,9 +361,12 @@ def __init__(self,
self.reevaluating = False
self.fake_refresh_requested = False
- self.status_bar = StatusBar(config, '',
- request_refresh=self.request_refresh,
- schedule_refresh=self.schedule_refresh)
+ self.status_bar = StatusBar(
+ config,
+ "",
+ request_refresh=self.request_refresh,
+ schedule_refresh=self.schedule_refresh,
+ )
self.edit_keys = edit_keys.mapping_with_config(config, key_dispatch)
logger.debug("starting parent init")
super(BaseRepl, self).__init__(interp, config)
@@ -363,10 +379,10 @@ def __init__(self,
self.interact = self.status_bar
# line currently being edited, without ps1 (usually '>>> ')
- self._current_line = ''
+ self._current_line = ""
# current line of output - stdout and stdin go here
- self.current_stdouterr_line = ''
+ self.current_stdouterr_line = ""
# lines separated whenever logical line
# length goes over what the terminal width
@@ -393,10 +409,16 @@ def __init__(self,
# filenos match the backing device for libs that expect it,
# but writing to them will do weird things to the display
- self.stdout = FakeOutput(self.coderunner, self.send_to_stdouterr,
- fileno=sys.__stdout__.fileno())
- self.stderr = FakeOutput(self.coderunner, self.send_to_stdouterr,
- fileno=sys.__stderr__.fileno())
+ self.stdout = FakeOutput(
+ self.coderunner,
+ self.send_to_stdouterr,
+ fileno=sys.__stdout__.fileno(),
+ )
+ self.stderr = FakeOutput(
+ self.coderunner,
+ self.send_to_stdouterr,
+ fileno=sys.__stderr__.fileno(),
+ )
self.stdin = FakeStdin(self.coderunner, self, self.edit_keys)
# next paint should clear screen
@@ -427,7 +449,7 @@ def __init__(self,
# 'reverse_incremental_search', 'incremental_search' or None
self.incr_search_mode = None
- self.incr_search_target = ''
+ self.incr_search_target = ""
self.original_modules = set(sys.modules.keys())
@@ -455,7 +477,7 @@ def get_term_hw(self):
"""Returns the current width and height of the display area."""
return (50, 10)
- def _schedule_refresh(self, when='now'):
+ def _schedule_refresh(self, when="now"):
"""Arrange for the bpython display to be refreshed soon.
This method will be called when the Repl wants the display to be
@@ -479,7 +501,7 @@ def _request_refresh(self):
RefreshRequestEvent."""
raise NotImplementedError
- def _request_reload(self, files_modified=('?',)):
+ def _request_reload(self, files_modified=("?",)):
"""Like request_refresh, but for reload requests events."""
raise NotImplementedError
@@ -514,7 +536,7 @@ def request_reload(self, files_modified=()):
if self.watching_files:
self._request_reload(files_modified=files_modified)
- def schedule_refresh(self, when='now'):
+ def schedule_refresh(self, when="now"):
"""Schedule a ScheduledRefreshRequestEvent for when.
Such a event should interrupt if blockied waiting for keyboard input"""
@@ -562,10 +584,16 @@ def sigwinch_handler(self, signum, frame):
self.height, self.width = self.get_term_hw()
cursor_dy = self.get_cursor_vertical_diff()
self.scroll_offset -= cursor_dy
- logger.info('sigwinch! Changed from %r to %r', (old_rows, old_columns),
- (self.height, self.width))
- logger.info('decreasing scroll offset by %d to %d', cursor_dy,
- self.scroll_offset)
+ logger.info(
+ "sigwinch! Changed from %r to %r",
+ (old_rows, old_columns),
+ (self.height, self.width),
+ )
+ logger.info(
+ "decreasing scroll offset by %d to %d",
+ cursor_dy,
+ self.scroll_offset,
+ )
def sigtstp_handler(self, signum, frame):
self.scroll_offset = len(self.lines_for_display)
@@ -577,7 +605,7 @@ def sigtstp_handler(self, signum, frame):
def clean_up_current_line_for_exit(self):
"""Called when trying to exit to prep for final paint"""
- logger.debug('unhighlighting paren for exit')
+ logger.debug("unhighlighting paren for exit")
self.cursor_offset = -1
self.unhighlight_paren()
@@ -601,7 +629,7 @@ def process_control_event(self, e):
pass
elif isinstance(e, bpythonevents.RefreshRequestEvent):
- logger.info('received ASAP refresh request event')
+ logger.info("received ASAP refresh request event")
if self.status_bar.has_focus:
self.status_bar.process_event(e)
else:
@@ -618,8 +646,9 @@ def process_control_event(self, e):
return self.process_event(ctrl_char)
with self.in_paste_mode():
# Might not really be a paste, UI might just be lagging
- if (len(e.events) <= MAX_EVENTS_POSSIBLY_NOT_PASTE and
- any(not is_simple_event(ee) for ee in e.events)):
+ if len(e.events) <= MAX_EVENTS_POSSIBLY_NOT_PASTE and any(
+ not is_simple_event(ee) for ee in e.events
+ ):
for ee in e.events:
if self.stdin.has_focus:
self.stdin.process_event(ee)
@@ -627,8 +656,9 @@ def process_control_event(self, e):
self.process_event(ee)
else:
simple_events = just_simple_events(e.events)
- source = preprocess(''.join(simple_events),
- self.interp.compile)
+ source = preprocess(
+ "".join(simple_events), self.interp.compile
+ )
for ee in source:
if self.stdin.has_focus:
self.stdin.process_event(ee)
@@ -640,7 +670,8 @@ def process_control_event(self, e):
self.startup()
except IOError as e:
self.status_bar.message(
- _('Executing PYTHONSTARTUP failed: %s') % (e, ))
+ _("Executing PYTHONSTARTUP failed: %s") % (e,)
+ )
elif isinstance(e, bpythonevents.UndoEvent):
self.undo(n=e.n)
@@ -649,7 +680,7 @@ def process_control_event(self, e):
return self.stdin.process_event(e)
elif isinstance(e, events.SigIntEvent):
- logger.debug('received sigint event')
+ logger.debug("received sigint event")
self.keyboard_interrupt()
return
@@ -657,9 +688,9 @@ def process_control_event(self, e):
if self.watching_files:
self.clear_modules_and_reevaluate()
self.status_bar.message(
- _('Reloaded at %s because %s modified.') % (
- time.strftime('%X'),
- ' & '.join(e.files_modified)))
+ _("Reloaded at %s because %s modified.")
+ % (time.strftime("%X"), " & ".join(e.files_modified))
+ )
else:
raise ValueError("Don't know how to handle event type: %r" % e)
@@ -672,11 +703,16 @@ def process_key_event(self, e):
if self.stdin.has_focus:
return self.stdin.process_event(e)
- if (e in (key_dispatch[self.config.right_key] +
- key_dispatch[self.config.end_of_line_key] +
- ("",)) and
- self.config.curtsies_right_arrow_completion and
- self.cursor_offset == len(self.current_line)):
+ if (
+ e
+ in (
+ key_dispatch[self.config.right_key]
+ + key_dispatch[self.config.end_of_line_key]
+ + ("",)
+ )
+ and self.config.curtsies_right_arrow_completion
+ and self.cursor_offset == len(self.current_line)
+ ):
self.current_line += self.current_suggestion
self.cursor_offset = len(self.current_line)
@@ -694,9 +730,10 @@ def process_key_event(self, e):
self.incremental_search(reverse=True)
elif e in key_dispatch[self.config.incremental_search_key]:
self.incremental_search()
- elif (e in (("",) +
- key_dispatch[self.config.backspace_key]) and
- self.incr_search_mode):
+ elif (
+ e in (("",) + key_dispatch[self.config.backspace_key])
+ and self.incr_search_mode
+ ):
self.add_to_incremental_search(self, backspace=True)
elif e in self.edit_keys.cut_buffer_edits:
self.readline_kill(e)
@@ -705,7 +742,8 @@ def process_key_event(self, e):
e,
cursor_offset=self.cursor_offset,
line=self.current_line,
- cut_buffer=self.cut_buffer)
+ cut_buffer=self.cut_buffer,
+ )
elif e in key_dispatch[self.config.cut_to_buffer_key]:
self.cut_to_buffer()
elif e in key_dispatch[self.config.reimport_key]:
@@ -722,7 +760,7 @@ def process_key_event(self, e):
raise SystemExit()
elif e in ("\n", "\r", "", "", ""):
self.on_enter()
- elif e == '': # tab
+ elif e == "": # tab
self.on_tab()
elif e in ("",):
self.on_tab(back=True)
@@ -744,7 +782,7 @@ def process_key_event(self, e):
elif e in [""]:
self.incr_search_mode = None
elif e in [""]:
- self.add_normal_character(' ')
+ self.add_normal_character(" ")
else:
self.add_normal_character(e)
@@ -753,46 +791,58 @@ def get_last_word(self):
previous_word = _last_word(self.rl_history.entry)
word = _last_word(self.rl_history.back())
line = self.current_line
- self._set_current_line(line[:len(line) - len(previous_word)] + word,
- reset_rl_history=False)
+ self._set_current_line(
+ line[: len(line) - len(previous_word)] + word,
+ reset_rl_history=False,
+ )
self._set_cursor_offset(
self.cursor_offset - len(previous_word) + len(word),
- reset_rl_history=False)
+ reset_rl_history=False,
+ )
def incremental_search(self, reverse=False, include_current=False):
if self.incr_search_mode is None:
self.rl_history.enter(self.current_line)
- self.incr_search_target = ''
+ self.incr_search_target = ""
else:
if self.incr_search_target:
- line = (self.rl_history.back(
- False, search=True,
- target=self.incr_search_target,
- include_current=include_current)
- if reverse else
- self.rl_history.forward(
- False, search=True,
+ line = (
+ self.rl_history.back(
+ False,
+ search=True,
+ target=self.incr_search_target,
+ include_current=include_current,
+ )
+ if reverse
+ else self.rl_history.forward(
+ False,
+ search=True,
target=self.incr_search_target,
- include_current=include_current))
- self._set_current_line(line,
- reset_rl_history=False,
- clear_special_mode=False)
- self._set_cursor_offset(len(self.current_line),
- reset_rl_history=False,
- clear_special_mode=False)
+ include_current=include_current,
+ )
+ )
+ self._set_current_line(
+ line, reset_rl_history=False, clear_special_mode=False
+ )
+ self._set_cursor_offset(
+ len(self.current_line),
+ reset_rl_history=False,
+ clear_special_mode=False,
+ )
if reverse:
- self.incr_search_mode = 'reverse_incremental_search'
+ self.incr_search_mode = "reverse_incremental_search"
else:
- self.incr_search_mode = 'incremental_search'
+ self.incr_search_mode = "incremental_search"
def readline_kill(self, e):
func = self.edit_keys[e]
- self.cursor_offset, self.current_line, cut = func(self.cursor_offset,
- self.current_line)
+ self.cursor_offset, self.current_line, cut = func(
+ self.cursor_offset, self.current_line
+ )
if self.last_events[-2] == e: # consecutive kill commands accumulative
- if func.kills == 'ahead':
+ if func.kills == "ahead":
self.cut_buffer += cut
- elif func.kills == 'behind':
+ elif func.kills == "behind":
self.cut_buffer = cut + self.cut_buffer
else:
raise ValueError("cut value other than 'ahead' or 'behind'")
@@ -821,15 +871,16 @@ def on_tab(self, back=False):
def only_whitespace_left_of_cursor():
"""returns true if all characters before cursor are whitespace"""
- return not self.current_line[:self.cursor_offset].strip()
+ return not self.current_line[: self.cursor_offset].strip()
- logger.debug('self.matches_iter.matches:%r', self.matches_iter.matches)
+ logger.debug("self.matches_iter.matches:%r", self.matches_iter.matches)
if only_whitespace_left_of_cursor():
- front_ws = (len(self.current_line[:self.cursor_offset]) -
- len(self.current_line[:self.cursor_offset].lstrip()))
+ front_ws = len(self.current_line[: self.cursor_offset]) - len(
+ self.current_line[: self.cursor_offset].lstrip()
+ )
to_add = 4 - (front_ws % self.config.tab_length)
for unused in range(to_add):
- self.add_normal_character(' ')
+ self.add_normal_character(" ")
return
# run complete() if we don't already have matches
@@ -845,23 +896,26 @@ def only_whitespace_left_of_cursor():
self.list_win_visible = self.complete()
elif self.matches_iter.matches:
- self.current_match = (back and self.matches_iter.previous() or
- next(self.matches_iter))
+ self.current_match = (
+ back and self.matches_iter.previous() or next(self.matches_iter)
+ )
cursor_and_line = self.matches_iter.cur_line()
self._cursor_offset, self._current_line = cursor_and_line
# using _current_line so we don't trigger a completion reset
self.list_win_visible = True
def on_control_d(self):
- if self.current_line == '':
+ if self.current_line == "":
raise SystemExit()
else:
- self.current_line = (self.current_line[:self.cursor_offset] +
- self.current_line[(self.cursor_offset + 1):])
+ self.current_line = (
+ self.current_line[: self.cursor_offset]
+ + self.current_line[(self.cursor_offset + 1) :]
+ )
def cut_to_buffer(self):
- self.cut_buffer = self.current_line[self.cursor_offset:]
- self.current_line = self.current_line[:self.cursor_offset]
+ self.cut_buffer = self.current_line[self.cursor_offset :]
+ self.current_line = self.current_line[: self.cursor_offset]
def yank_from_buffer(self):
pass
@@ -873,20 +927,28 @@ def operate_and_get_next(self):
def up_one_line(self):
self.rl_history.enter(self.current_line)
- self._set_current_line(tabs_to_spaces(self.rl_history.back(
- False,
- search=self.config.curtsies_right_arrow_completion)),
+ self._set_current_line(
+ tabs_to_spaces(
+ self.rl_history.back(
+ False, search=self.config.curtsies_right_arrow_completion
+ )
+ ),
update_completion=False,
- reset_rl_history=False)
+ reset_rl_history=False,
+ )
self._set_cursor_offset(len(self.current_line), reset_rl_history=False)
def down_one_line(self):
self.rl_history.enter(self.current_line)
- self._set_current_line(tabs_to_spaces(self.rl_history.forward(
- False,
- search=self.config.curtsies_right_arrow_completion)),
+ self._set_current_line(
+ tabs_to_spaces(
+ self.rl_history.forward(
+ False, search=self.config.curtsies_right_arrow_completion
+ )
+ ),
update_completion=False,
- reset_rl_history=False)
+ reset_rl_history=False,
+ )
self._set_cursor_offset(len(self.current_line), reset_rl_history=False)
def process_simple_keypress(self, e):
@@ -898,17 +960,17 @@ def process_simple_keypress(self, e):
self.process_event(bpythonevents.RefreshRequestEvent())
elif isinstance(e, events.Event):
pass # ignore events
- elif e == '':
- self.add_normal_character(' ')
+ elif e == "":
+ self.add_normal_character(" ")
else:
self.add_normal_character(e)
def send_current_block_to_external_editor(self, filename=None):
text = self.send_to_external_editor(self.get_current_block())
- lines = [line for line in text.split('\n')]
+ lines = [line for line in text.split("\n")]
while lines and not lines[-1].split():
lines.pop()
- events = '\n'.join(lines + ([''] if len(lines) == 1 else ['', '']))
+ events = "\n".join(lines + ([""] if len(lines) == 1 else ["", ""]))
self.clear_current_block()
with self.in_paste_mode():
for e in events:
@@ -917,48 +979,53 @@ def send_current_block_to_external_editor(self, filename=None):
def send_session_to_external_editor(self, filename=None):
for_editor = EDIT_SESSION_HEADER
- for_editor += '\n'.join(line[len(self.ps1):]
- if line.startswith(self.ps1) else
- line[len(self.ps2):]
- if line.startswith(self.ps2) else
- '### ' + line
- for line in self.getstdout().split('\n'))
+ for_editor += "\n".join(
+ line[len(self.ps1) :]
+ if line.startswith(self.ps1)
+ else line[len(self.ps2) :]
+ if line.startswith(self.ps2)
+ else "### " + line
+ for line in self.getstdout().split("\n")
+ )
text = self.send_to_external_editor(for_editor)
if text == for_editor:
self.status_bar.message(
- _('Session not reevaluated because it was not edited'))
+ _("Session not reevaluated because it was not edited")
+ )
return
- lines = text.split('\n')
+ lines = text.split("\n")
if not lines[-1].strip():
lines.pop() # strip last line if empty
- if lines[-1].startswith('### '):
+ if lines[-1].startswith("### "):
current_line = lines[-1][4:]
else:
- current_line = ''
- from_editor = [line for line in lines if line[:3] != '###']
+ current_line = ""
+ from_editor = [line for line in lines if line[:3] != "###"]
if all(not line.strip() for line in from_editor):
self.status_bar.message(
- _('Session not reevaluated because saved file was blank'))
+ _("Session not reevaluated because saved file was blank")
+ )
return
- source = preprocess('\n'.join(from_editor), self.interp.compile)
- lines = source.split('\n')
+ source = preprocess("\n".join(from_editor), self.interp.compile)
+ lines = source.split("\n")
self.history = lines
self.reevaluate(insert_into_history=True)
self.current_line = current_line
self.cursor_offset = len(self.current_line)
- self.status_bar.message(_('Session edited and reevaluated'))
+ self.status_bar.message(_("Session edited and reevaluated"))
def clear_modules_and_reevaluate(self):
if self.watcher:
self.watcher.reset()
cursor, line = self.cursor_offset, self.current_line
- for modname in (set(sys.modules.keys()) - self.original_modules):
+ for modname in set(sys.modules.keys()) - self.original_modules:
del sys.modules[modname]
self.reevaluate(insert_into_history=True)
self.cursor_offset, self.current_line = cursor, line
- self.status_bar.message(_('Reloaded at %s by user.') %
- (time.strftime('%X'), ))
+ self.status_bar.message(
+ _("Reloaded at %s by user.") % (time.strftime("%X"),)
+ )
def toggle_file_watch(self):
if self.watcher:
@@ -973,8 +1040,12 @@ def toggle_file_watch(self):
self.watching_files = True
self.watcher.activate()
else:
- self.status_bar.message(_('Auto-reloading not available because '
- 'watchdog not installed.'))
+ self.status_bar.message(
+ _(
+ "Auto-reloading not available because "
+ "watchdog not installed."
+ )
+ )
# Handler Helpers
def add_normal_character(self, char):
@@ -983,15 +1054,20 @@ def add_normal_character(self, char):
if self.incr_search_mode:
self.add_to_incremental_search(char)
else:
- self._set_current_line((self.current_line[:self.cursor_offset] +
- char +
- self.current_line[self.cursor_offset:]),
- update_completion=False,
- reset_rl_history=False,
- clear_special_mode=False)
+ self._set_current_line(
+ (
+ self.current_line[: self.cursor_offset]
+ + char
+ + self.current_line[self.cursor_offset :]
+ ),
+ update_completion=False,
+ reset_rl_history=False,
+ clear_special_mode=False,
+ )
self.cursor_offset += 1
- if (self.config.cli_trim_prompts and
- self.current_line.startswith(self.ps1)):
+ if self.config.cli_trim_prompts and self.current_line.startswith(
+ self.ps1
+ ):
self.current_line = self.current_line[4:]
self.cursor_offset = max(0, self.cursor_offset - 4)
@@ -1006,12 +1082,12 @@ def add_to_incremental_search(self, char=None, backspace=False):
self.incr_search_target = self.incr_search_target[:-1]
else:
self.incr_search_target += char
- if self.incr_search_mode == 'reverse_incremental_search':
+ if self.incr_search_mode == "reverse_incremental_search":
self.incremental_search(reverse=True, include_current=True)
- elif self.incr_search_mode == 'incremental_search':
+ elif self.incr_search_mode == "incremental_search":
self.incremental_search(include_current=True)
else:
- raise ValueError('add_to_incremental_search not in a special mode')
+ raise ValueError("add_to_incremental_search not in a special mode")
def update_completion(self, tab=False):
"""Update visible docstring and matches and box visibility"""
@@ -1024,16 +1100,19 @@ def update_completion(self, tab=False):
def predicted_indent(self, line):
# TODO get rid of this! It's repeated code! Combine with Repl.
- logger.debug('line is %r', line)
- indent = len(re.match(r'[ ]*', line).group())
- if line.endswith(':'):
+ logger.debug("line is %r", line)
+ indent = len(re.match(r"[ ]*", line).group())
+ if line.endswith(":"):
indent = max(0, indent + self.config.tab_length)
- elif line and line.count(' ') == len(line):
+ elif line and line.count(" ") == len(line):
indent = max(0, indent - self.config.tab_length)
- elif (line and ':' not in line and line.strip().startswith(
- ('return', 'pass', 'raise', 'yield'))):
+ elif (
+ line
+ and ":" not in line
+ and line.strip().startswith(("return", "pass", "raise", "yield"))
+ ):
indent = max(0, indent - self.config.tab_length)
- logger.debug('indent we found was %s', indent)
+ logger.debug("indent we found was %s", indent)
return indent
def push(self, line, insert_into_history=True):
@@ -1047,12 +1126,16 @@ def push(self, line, insert_into_history=True):
self.saved_indent = self.predicted_indent(line)
if self.config.syntax:
- display_line = bpythonparse(format(
- self.tokenize(line), self.formatter))
+ display_line = bpythonparse(
+ format(self.tokenize(line), self.formatter)
+ )
# self.tokenize requires that the line not be in self.buffer yet
- logger.debug('display line being pushed to buffer: %r -> %r',
- line, display_line)
+ logger.debug(
+ "display line being pushed to buffer: %r -> %r",
+ line,
+ display_line,
+ )
self.display_buffer.append(display_line)
else:
self.display_buffer.append(fmtstr(line))
@@ -1061,14 +1144,15 @@ def push(self, line, insert_into_history=True):
self.insert_into_history(line)
self.buffer.append(line)
- code_to_run = '\n'.join(self.buffer)
+ code_to_run = "\n".join(self.buffer)
- logger.debug('running %r in interpreter', self.buffer)
- c, code_will_parse = code_finished_will_parse('\n'.join(self.buffer),
- self.interp.compile)
+ logger.debug("running %r in interpreter", self.buffer)
+ c, code_will_parse = code_finished_will_parse(
+ "\n".join(self.buffer), self.interp.compile
+ )
self.saved_predicted_parse_error = not code_will_parse
if c:
- logger.debug('finished - buffer cleared')
+ logger.debug("finished - buffer cleared")
self.cursor_offset = 0
self.display_lines.extend(self.display_buffer_lines)
self.display_buffer = []
@@ -1090,10 +1174,12 @@ def run_code_and_maybe_finish(self, for_code=None):
indent = 0
if self.rl_history.index == 0:
- self._set_current_line(' ' * indent, update_completion=True)
+ self._set_current_line(" " * indent, update_completion=True)
else:
- self._set_current_line(self.rl_history.entries[-self.rl_history.index],
- reset_rl_history=False)
+ self._set_current_line(
+ self.rl_history.entries[-self.rl_history.index],
+ reset_rl_history=False,
+ )
self.cursor_offset = len(self.current_line)
def keyboard_interrupt(self):
@@ -1101,10 +1187,12 @@ def keyboard_interrupt(self):
self.cursor_offset = -1
self.unhighlight_paren()
self.display_lines.extend(self.display_buffer_lines)
- self.display_lines.extend(paint.display_linize(
- self.current_cursor_line, self.width))
- self.display_lines.extend(paint.display_linize(
- "KeyboardInterrupt", self.width))
+ self.display_lines.extend(
+ paint.display_linize(self.current_cursor_line, self.width)
+ )
+ self.display_lines.extend(
+ paint.display_linize("KeyboardInterrupt", self.width)
+ )
self.clear_current_block(remove_from_history=False)
def unhighlight_paren(self):
@@ -1119,12 +1207,14 @@ def unhighlight_paren(self):
# then this is the current line, so don't worry about it
return
self.highlighted_paren = None
- logger.debug('trying to unhighlight a paren on line %r', lineno)
- logger.debug('with these tokens: %r', saved_tokens)
+ logger.debug("trying to unhighlight a paren on line %r", lineno)
+ logger.debug("with these tokens: %r", saved_tokens)
new = bpythonparse(format(saved_tokens, self.formatter))
- self.display_buffer[lineno] = self.display_buffer[lineno] \
- .setslice_with_length(0, len(new), new,
- len(self.display_buffer[lineno]))
+ self.display_buffer[lineno] = self.display_buffer[
+ lineno
+ ].setslice_with_length(
+ 0, len(new), new, len(self.display_buffer[lineno])
+ )
def clear_current_block(self, remove_from_history=True):
self.display_buffer = []
@@ -1134,11 +1224,11 @@ def clear_current_block(self, remove_from_history=True):
self.buffer = []
self.cursor_offset = 0
self.saved_indent = 0
- self.current_line = ''
+ self.current_line = ""
self.cursor_offset = len(self.current_line)
def get_current_block(self):
- return '\n'.join(self.buffer + [self.current_line])
+ return "\n".join(self.buffer + [self.current_line])
def send_to_stdouterr(self, output):
"""Send unicode strings or FmtStr to Repl stdout or stderr
@@ -1147,24 +1237,33 @@ def send_to_stdouterr(self, output):
tracebacks already formatted."""
if not output:
return
- lines = output.split('\n')
- logger.debug('display_lines: %r', self.display_lines)
+ lines = output.split("\n")
+ logger.debug("display_lines: %r", self.display_lines)
self.current_stdouterr_line += lines[0]
if len(lines) > 1:
- self.display_lines.extend(paint.display_linize(
- self.current_stdouterr_line, self.width, blank_line=True))
self.display_lines.extend(
- sum((paint.display_linize(line, self.width,
- blank_line=True)
- for line in lines[1:-1]), []))
+ paint.display_linize(
+ self.current_stdouterr_line, self.width, blank_line=True
+ )
+ )
+ self.display_lines.extend(
+ sum(
+ (
+ paint.display_linize(line, self.width, blank_line=True)
+ for line in lines[1:-1]
+ ),
+ [],
+ )
+ )
self.current_stdouterr_line = lines[-1]
- logger.debug('display_lines: %r', self.display_lines)
+ logger.debug("display_lines: %r", self.display_lines)
def send_to_stdin(self, line):
- if line.endswith('\n'):
+ if line.endswith("\n"):
self.display_lines.extend(
- paint.display_linize(self.current_output_line, self.width))
- self.current_output_line = ''
+ paint.display_linize(self.current_output_line, self.width)
+ )
+ self.current_output_line = ""
# formatting, output
@property
@@ -1177,22 +1276,29 @@ def done(self):
def current_line_formatted(self):
"""The colored current line (no prompt, not wrapped)"""
if self.config.syntax:
- fs = bpythonparse(format(self.tokenize(self.current_line),
- self.formatter))
+ fs = bpythonparse(
+ format(self.tokenize(self.current_line), self.formatter)
+ )
if self.incr_search_mode:
if self.incr_search_target in self.current_line:
fs = fmtfuncs.on_magenta(self.incr_search_target).join(
- fs.split(self.incr_search_target))
- elif (self.rl_history.saved_line and
- self.rl_history.saved_line in self.current_line):
- if (self.config.curtsies_right_arrow_completion and
- self.rl_history.index != 0):
+ fs.split(self.incr_search_target)
+ )
+ elif (
+ self.rl_history.saved_line
+ and self.rl_history.saved_line in self.current_line
+ ):
+ if (
+ self.config.curtsies_right_arrow_completion
+ and self.rl_history.index != 0
+ ):
fs = fmtfuncs.on_magenta(self.rl_history.saved_line).join(
- fs.split(self.rl_history.saved_line))
- logger.debug('Display line %r -> %r', self.current_line, fs)
+ fs.split(self.rl_history.saved_line)
+ )
+ logger.debug("Display line %r -> %r", self.current_line, fs)
else:
fs = fmtstr(self.current_line)
- if hasattr(self, 'old_fs') and str(fs) != str(self.old_fs):
+ if hasattr(self, "old_fs") and str(fs) != str(self.old_fs):
pass
self.old_fs = fs
return fs
@@ -1207,10 +1313,11 @@ def display_buffer_lines(self):
"""The display lines (wrapped, colored, +prompts) of current buffer"""
lines = []
for display_line in self.display_buffer:
- prompt = func_for_letter(self.config.color_scheme['prompt'])
- more = func_for_letter(self.config.color_scheme['prompt_more'])
- display_line = ((more(self.ps2) if lines else prompt(self.ps1)) +
- display_line)
+ prompt = func_for_letter(self.config.color_scheme["prompt"])
+ more = func_for_letter(self.config.color_scheme["prompt_more"])
+ display_line = (
+ more(self.ps2) if lines else prompt(self.ps1)
+ ) + display_line
for line in paint.display_linize(display_line, self.width):
lines.append(line)
return lines
@@ -1218,33 +1325,42 @@ def display_buffer_lines(self):
@property
def display_line_with_prompt(self):
"""colored line with prompt"""
- prompt = func_for_letter(self.config.color_scheme['prompt'])
- more = func_for_letter(self.config.color_scheme['prompt_more'])
- if self.incr_search_mode == 'reverse_incremental_search':
- return (prompt('(reverse-i-search)`{}\': '.format(
- self.incr_search_target)) + self.current_line_formatted)
- elif self.incr_search_mode == 'incremental_search':
- return (prompt('(i-search)`%s\': '.format(
- self.incr_search_target)) + self.current_line_formatted)
- return ((prompt(self.ps1) if self.done else more(self.ps2)) +
- self.current_line_formatted)
+ prompt = func_for_letter(self.config.color_scheme["prompt"])
+ more = func_for_letter(self.config.color_scheme["prompt_more"])
+ if self.incr_search_mode == "reverse_incremental_search":
+ return (
+ prompt(
+ "(reverse-i-search)`{}': ".format(self.incr_search_target)
+ )
+ + self.current_line_formatted
+ )
+ elif self.incr_search_mode == "incremental_search":
+ return (
+ prompt("(i-search)`%s': ".format(self.incr_search_target))
+ + self.current_line_formatted
+ )
+ return (
+ prompt(self.ps1) if self.done else more(self.ps2)
+ ) + self.current_line_formatted
@property
def current_cursor_line_without_suggestion(self):
"""Current line, either output/input or Python prompt + code"""
- value = (self.current_output_line +
- ('' if self.coderunner.running else
- self.display_line_with_prompt))
- logger.debug('current cursor line: %r', value)
+ value = self.current_output_line + (
+ "" if self.coderunner.running else self.display_line_with_prompt
+ )
+ logger.debug("current cursor line: %r", value)
return value
@property
def current_cursor_line(self):
if self.config.curtsies_right_arrow_completion:
suggest = func_for_letter(
- self.config.color_scheme['right_arrow_suggestion'])
- return (self.current_cursor_line_without_suggestion +
- suggest(self.current_suggestion))
+ self.config.color_scheme["right_arrow_suggestion"]
+ )
+ return self.current_cursor_line_without_suggestion + suggest(
+ self.current_suggestion
+ )
else:
return self.current_cursor_line_without_suggestion
@@ -1253,8 +1369,8 @@ def current_suggestion(self):
if self.current_line:
for entry in reversed(self.rl_history.entries):
if entry.startswith(self.current_line):
- return entry[len(self.current_line):]
- return ''
+ return entry[len(self.current_line) :]
+ return ""
@property
def current_output_line(self):
@@ -1263,12 +1379,16 @@ def current_output_line(self):
@current_output_line.setter
def current_output_line(self, value):
- self.current_stdouterr_line = ''
- self.stdin.current_line = '\n'
-
- def paint(self, about_to_exit=False, user_quit=False,
- try_preserve_history_height=30,
- min_infobox_height=5):
+ self.current_stdouterr_line = ""
+ self.stdin.current_line = "\n"
+
+ def paint(
+ self,
+ about_to_exit=False,
+ user_quit=False,
+ try_preserve_history_height=30,
+ min_infobox_height=5,
+ ):
"""Returns an array of min_height or more rows and width columns, plus
cursor position
@@ -1287,16 +1407,18 @@ def paint(self, about_to_exit=False, user_quit=False,
self.clean_up_current_line_for_exit()
width, min_height = self.width, self.height
- show_status_bar = ((bool(self.status_bar.should_show_message) or
- self.status_bar.has_focus) and
- not self.request_paint_to_pad_bottom)
+ show_status_bar = (
+ bool(self.status_bar.should_show_message)
+ or self.status_bar.has_focus
+ ) and not self.request_paint_to_pad_bottom
if show_status_bar:
# because we're going to tack the status bar on at the end, shoot
# for an array one less than the height of the screen
min_height -= 1
- current_line_start_row = (len(self.lines_for_display) -
- max(0, self.scroll_offset))
+ current_line_start_row = len(self.lines_for_display) - max(
+ 0, self.scroll_offset
+ )
# TODO how is the situation of self.scroll_offset < 0 possible?
# or show_status_bar and about_to_exit ?
if self.request_paint_to_clear_screen:
@@ -1312,8 +1434,9 @@ def paint(self, about_to_exit=False, user_quit=False,
# TODO test case of current line filling up the whole screen (there
# aren't enough rows to show it)
- current_line = paint.paint_current_line(min_height, width,
- self.current_cursor_line)
+ current_line = paint.paint_current_line(
+ min_height, width, self.current_cursor_line
+ )
# needs to happen before we calculate contents of history because
# calculating self.current_cursor_line has the side effect of
# unhighlighting parens in buffer
@@ -1321,22 +1444,28 @@ def paint(self, about_to_exit=False, user_quit=False,
def move_screen_up(current_line_start_row):
# move screen back up a screen minus a line
while current_line_start_row < 0:
- logger.debug('scroll_offset was %s, current_line_start_row '
- 'was %s', self.scroll_offset,
- current_line_start_row)
+ logger.debug(
+ "scroll_offset was %s, current_line_start_row " "was %s",
+ self.scroll_offset,
+ current_line_start_row,
+ )
self.scroll_offset = self.scroll_offset - self.height
- current_line_start_row = (len(self.lines_for_display) -
- max(-1, self.scroll_offset))
- logger.debug('scroll_offset changed to %s, '
- 'current_line_start_row changed to %s',
- self.scroll_offset, current_line_start_row)
+ current_line_start_row = len(self.lines_for_display) - max(
+ -1, self.scroll_offset
+ )
+ logger.debug(
+ "scroll_offset changed to %s, "
+ "current_line_start_row changed to %s",
+ self.scroll_offset,
+ current_line_start_row,
+ )
return current_line_start_row
if self.inconsistent_history and not self.history_already_messed_up:
logger.debug(INCONSISTENT_HISTORY_MSG)
self.history_already_messed_up = True
msg = INCONSISTENT_HISTORY_MSG
- arr[0, 0:min(len(msg), width)] = [msg[:width]]
+ arr[0, 0 : min(len(msg), width)] = [msg[:width]]
current_line_start_row += 1 # for the message
# to make up for the scroll that will be received after the
@@ -1344,89 +1473,117 @@ def move_screen_up(current_line_start_row):
self.scroll_offset -= 1
current_line_start_row = move_screen_up(current_line_start_row)
- logger.debug('current_line_start_row: %r', current_line_start_row)
+ logger.debug("current_line_start_row: %r", current_line_start_row)
- history = paint.paint_history(max(0, current_line_start_row - 1),
- width, self.lines_for_display)
- arr[1:history.height + 1, :history.width] = history
+ history = paint.paint_history(
+ max(0, current_line_start_row - 1),
+ width,
+ self.lines_for_display,
+ )
+ arr[1 : history.height + 1, : history.width] = history
if arr.height <= min_height:
# force scroll down to hide broken history message
- arr[min_height, 0] = ' '
+ arr[min_height, 0] = " "
elif current_line_start_row < 0:
# if current line trying to be drawn off the top of the screen
logger.debug(CONTIGUITY_BROKEN_MSG)
msg = CONTIGUITY_BROKEN_MSG
- arr[0, 0:min(len(msg), width)] = [msg[:width]]
+ arr[0, 0 : min(len(msg), width)] = [msg[:width]]
current_line_start_row = move_screen_up(current_line_start_row)
- history = paint.paint_history(max(0, current_line_start_row - 1),
- width, self.lines_for_display)
- arr[1:history.height + 1, :history.width] = history
+ history = paint.paint_history(
+ max(0, current_line_start_row - 1),
+ width,
+ self.lines_for_display,
+ )
+ arr[1 : history.height + 1, : history.width] = history
if arr.height <= min_height:
# force scroll down to hide broken history message
- arr[min_height, 0] = ' '
+ arr[min_height, 0] = " "
else:
assert current_line_start_row >= 0
logger.debug("no history issues. start %i", current_line_start_row)
- history = paint.paint_history(current_line_start_row, width,
- self.lines_for_display)
- arr[:history.height, :history.width] = history
+ history = paint.paint_history(
+ current_line_start_row, width, self.lines_for_display
+ )
+ arr[: history.height, : history.width] = history
self.inconsistent_history = False
if user_quit: # quit() or exit() in interp
- current_line_start_row = (current_line_start_row -
- current_line.height)
- logger.debug("---current line row slice %r, %r",
- current_line_start_row,
- current_line_start_row + current_line.height)
+ current_line_start_row = (
+ current_line_start_row - current_line.height
+ )
+ logger.debug(
+ "---current line row slice %r, %r",
+ current_line_start_row,
+ current_line_start_row + current_line.height,
+ )
logger.debug("---current line col slice %r, %r", 0, current_line.width)
- arr[current_line_start_row:(current_line_start_row +
- current_line.height),
- 0:current_line.width] = current_line
+ arr[
+ current_line_start_row : (
+ current_line_start_row + current_line.height
+ ),
+ 0 : current_line.width,
+ ] = current_line
if current_line.height > min_height:
return arr, (0, 0) # short circuit, no room for infobox
- lines = paint.display_linize(self.current_cursor_line + 'X', width)
+ lines = paint.display_linize(self.current_cursor_line + "X", width)
# extra character for space for the cursor
current_line_end_row = current_line_start_row + len(lines) - 1
current_line_height = current_line_end_row - current_line_start_row
if self.stdin.has_focus:
cursor_row, cursor_column = divmod(
- len(self.current_stdouterr_line) +
- self.stdin.cursor_offset, width)
+ len(self.current_stdouterr_line) + self.stdin.cursor_offset,
+ width,
+ )
assert cursor_column >= 0, cursor_column
elif self.coderunner.running: # TODO does this ever happen?
cursor_row, cursor_column = divmod(
- (len(self.current_cursor_line_without_suggestion) +
- self.cursor_offset),
- width)
+ (
+ len(self.current_cursor_line_without_suggestion)
+ + self.cursor_offset
+ ),
+ width,
+ )
assert cursor_column >= 0, (
- cursor_column, len(self.current_cursor_line),
- len(self.current_line), self.cursor_offset)
+ cursor_column,
+ len(self.current_cursor_line),
+ len(self.current_line),
+ self.cursor_offset,
+ )
else:
cursor_row, cursor_column = divmod(
- (len(self.current_cursor_line_without_suggestion) -
- len(self.current_line) + self.cursor_offset),
- width)
+ (
+ len(self.current_cursor_line_without_suggestion)
+ - len(self.current_line)
+ + self.cursor_offset
+ ),
+ width,
+ )
assert cursor_column >= 0, (
- cursor_column, len(self.current_cursor_line),
- len(self.current_line), self.cursor_offset)
+ cursor_column,
+ len(self.current_cursor_line),
+ len(self.current_line),
+ self.cursor_offset,
+ )
cursor_row += current_line_start_row
if self.list_win_visible and not self.coderunner.running:
- logger.debug('infobox display code running')
+ logger.debug("infobox display code running")
visible_space_above = history.height
potential_space_below = min_height - current_line_end_row - 1
- visible_space_below = (potential_space_below -
- self.get_top_usable_line())
+ visible_space_below = (
+ potential_space_below - self.get_top_usable_line()
+ )
if self.config.curtsies_list_above:
info_max_rows = max(visible_space_above, visible_space_below)
@@ -1434,65 +1591,84 @@ def move_screen_up(current_line_start_row):
# Logic for determining size of completion box
# smallest allowed over-full completion box
preferred_height = max(
- # always make infobox at least this height
- min_infobox_height,
-
- # use this value if there's so much space that we can
- # preserve this try_preserve_history_height rows history
- min_height - try_preserve_history_height)
-
- info_max_rows = min(max(visible_space_below,
- preferred_height),
- min_height - current_line_height - 1)
+ # always make infobox at least this height
+ min_infobox_height,
+ # use this value if there's so much space that we can
+ # preserve this try_preserve_history_height rows history
+ min_height - try_preserve_history_height,
+ )
+
+ info_max_rows = min(
+ max(visible_space_below, preferred_height),
+ min_height - current_line_height - 1,
+ )
infobox = paint.paint_infobox(
- info_max_rows,
- int(width * self.config.cli_suggestion_width),
- self.matches_iter.matches,
- self.funcprops,
- self.arg_pos,
- self.current_match,
- self.docstring,
- self.config,
- self.matches_iter.completer.format
- if self.matches_iter.completer else None)
-
- if (visible_space_below >= infobox.height or
- not self.config.curtsies_list_above):
- arr[current_line_end_row + 1:(current_line_end_row + 1 +
- infobox.height),
- 0:infobox.width] = infobox
+ info_max_rows,
+ int(width * self.config.cli_suggestion_width),
+ self.matches_iter.matches,
+ self.funcprops,
+ self.arg_pos,
+ self.current_match,
+ self.docstring,
+ self.config,
+ self.matches_iter.completer.format
+ if self.matches_iter.completer
+ else None,
+ )
+
+ if (
+ visible_space_below >= infobox.height
+ or not self.config.curtsies_list_above
+ ):
+ arr[
+ current_line_end_row
+ + 1 : (current_line_end_row + 1 + infobox.height),
+ 0 : infobox.width,
+ ] = infobox
else:
- arr[current_line_start_row - infobox.height:
- current_line_start_row, 0:infobox.width] = infobox
- logger.debug('infobox of shape %r added to arr of shape %r',
- infobox.shape, arr.shape)
-
- logger.debug('about to exit: %r', about_to_exit)
+ arr[
+ current_line_start_row
+ - infobox.height : current_line_start_row,
+ 0 : infobox.width,
+ ] = infobox
+ logger.debug(
+ "infobox of shape %r added to arr of shape %r",
+ infobox.shape,
+ arr.shape,
+ )
+
+ logger.debug("about to exit: %r", about_to_exit)
if show_status_bar:
- statusbar_row = (min_height
- if arr.height == min_height else arr.height)
+ statusbar_row = (
+ min_height if arr.height == min_height else arr.height
+ )
if about_to_exit:
arr[statusbar_row, :] = FSArray(1, width)
else:
arr[statusbar_row, :] = paint.paint_statusbar(
- 1, width, self.status_bar.current_line, self.config)
+ 1, width, self.status_bar.current_line, self.config
+ )
if self.presentation_mode:
rows = arr.height
columns = arr.width
last_key_box = paint.paint_last_events(
- rows, columns,
- [events.pp_event(x) for x in self.last_events if x],
- self.config)
- arr[arr.height - last_key_box.height:arr.height,
- arr.width - last_key_box.width:arr.width] = last_key_box
-
- if self.config.color_scheme['background'] not in ('d', 'D'):
+ rows,
+ columns,
+ [events.pp_event(x) for x in self.last_events if x],
+ self.config,
+ )
+ arr[
+ arr.height - last_key_box.height : arr.height,
+ arr.width - last_key_box.width : arr.width,
+ ] = last_key_box
+
+ if self.config.color_scheme["background"] not in ("d", "D"):
for r in range(arr.height):
- bg = color_for_letter(self.config.color_scheme['background'])
+ bg = color_for_letter(self.config.color_scheme["background"])
arr[r] = fmtstr(arr[r], bg=bg)
- logger.debug('returning arr of size %r', arr.shape)
- logger.debug('cursor pos: %r', (cursor_row, cursor_column))
+ logger.debug("returning arr of size %r", arr.shape)
+ logger.debug("cursor pos: %r", (cursor_row, cursor_column))
return arr, (cursor_row, cursor_column)
@contextlib.contextmanager
@@ -1505,19 +1681,24 @@ def in_paste_mode(self):
self.update_completion()
def __repr__(self):
- s = ''
- s += '<' + repr(type(self)) + '\n'
- s += " cursor_offset:" + repr(self.cursor_offset) + '\n'
- s += " num display lines:" + repr(len(self.display_lines)) + '\n'
- s += " lines scrolled down:" + repr(self.scroll_offset) + '\n'
- s += '>'
+ s = ""
+ s += "<" + repr(type(self)) + "\n"
+ s += " cursor_offset:" + repr(self.cursor_offset) + "\n"
+ s += " num display lines:" + repr(len(self.display_lines)) + "\n"
+ s += " lines scrolled down:" + repr(self.scroll_offset) + "\n"
+ s += ">"
return s
def _get_current_line(self):
return self._current_line
- def _set_current_line(self, line, update_completion=True,
- reset_rl_history=True, clear_special_mode=True):
+ def _set_current_line(
+ self,
+ line,
+ update_completion=True,
+ reset_rl_history=True,
+ clear_special_mode=True,
+ ):
if self._current_line == line:
return
self._current_line = line
@@ -1531,14 +1712,20 @@ def _set_current_line(self, line, update_completion=True,
self.special_mode = None
self.unhighlight_paren()
- current_line = property(_get_current_line, _set_current_line, None,
- "The current line")
+ current_line = property(
+ _get_current_line, _set_current_line, None, "The current line"
+ )
def _get_cursor_offset(self):
return self._cursor_offset
- def _set_cursor_offset(self, offset, update_completion=True,
- reset_rl_history=False, clear_special_mode=True):
+ def _set_cursor_offset(
+ self,
+ offset,
+ update_completion=True,
+ reset_rl_history=False,
+ clear_special_mode=True,
+ ):
if self._cursor_offset == offset:
return
if self.paste_mode:
@@ -1554,9 +1741,12 @@ def _set_cursor_offset(self, offset, update_completion=True,
self.update_completion()
self.unhighlight_paren()
- cursor_offset = property(_get_cursor_offset, _set_cursor_offset, None,
- "The current cursor offset from the front of the "
- "line")
+ cursor_offset = property(
+ _get_cursor_offset,
+ _set_cursor_offset,
+ None,
+ "The current cursor offset from the front of the " "line",
+ )
def echo(self, msg, redraw=True):
"""
@@ -1570,24 +1760,25 @@ def echo(self, msg, redraw=True):
@property
def cpos(self):
- "many WATs were had - it's the pos from the end of the line back"""
+ "many WATs were had - it's the pos from the end of the line back" ""
return len(self.current_line) - self.cursor_offset
def reprint_line(self, lineno, tokens):
logger.debug("calling reprint line with %r %r", lineno, tokens)
if self.config.syntax:
self.display_buffer[lineno] = bpythonparse(
- format(tokens, self.formatter))
+ format(tokens, self.formatter)
+ )
def take_back_buffer_line(self):
assert len(self.buffer) > 0
if len(self.buffer) == 1:
self._cursor_offset = 0
- self.current_line = ''
+ self.current_line = ""
else:
line = self.buffer[-1]
indent = self.predicted_indent(line)
- self._current_line = indent * ' '
+ self._current_line = indent * " "
self.cursor_offset = len(self.current_line)
self.display_buffer.pop()
self.buffer.pop()
@@ -1642,40 +1833,53 @@ def reevaluate(self, insert_into_history=False):
sys.stdin = self.stdin
self.reevaluating = False
- num_lines_onscreen = (len(self.lines_for_display) -
- max(0, self.scroll_offset))
- display_lines_offscreen = self.display_lines[:len(self.display_lines) -
- num_lines_onscreen]
- old_display_lines_offscreen = old_display_lines[:(
- len(self.display_lines) - num_lines_onscreen)]
- logger.debug('old_display_lines_offscreen %s', '|'.join(
- str(x) for x in old_display_lines_offscreen))
- logger.debug(' display_lines_offscreen %s', '|'.join(
- str(x) for x in display_lines_offscreen))
- if ((old_display_lines_offscreen[:len(display_lines_offscreen)] !=
- display_lines_offscreen) and
- not self.history_already_messed_up):
+ num_lines_onscreen = len(self.lines_for_display) - max(
+ 0, self.scroll_offset
+ )
+ display_lines_offscreen = self.display_lines[
+ : len(self.display_lines) - num_lines_onscreen
+ ]
+ old_display_lines_offscreen = old_display_lines[
+ : (len(self.display_lines) - num_lines_onscreen)
+ ]
+ logger.debug(
+ "old_display_lines_offscreen %s",
+ "|".join(str(x) for x in old_display_lines_offscreen),
+ )
+ logger.debug(
+ " display_lines_offscreen %s",
+ "|".join(str(x) for x in display_lines_offscreen),
+ )
+ if (
+ old_display_lines_offscreen[: len(display_lines_offscreen)]
+ != display_lines_offscreen
+ ) and not self.history_already_messed_up:
self.inconsistent_history = True
- logger.debug('after rewind, self.inconsistent_history is %r',
- self.inconsistent_history)
+ logger.debug(
+ "after rewind, self.inconsistent_history is %r",
+ self.inconsistent_history,
+ )
self._cursor_offset = 0
- self.current_line = ''
+ self.current_line = ""
def initialize_interp(self):
- self.coderunner.interp.locals['_repl'] = self
+ self.coderunner.interp.locals["_repl"] = self
self.coderunner.interp.runsource(
- 'from bpython.curtsiesfrontend._internal '
- 'import _Helper')
- self.coderunner.interp.runsource('help = _Helper(_repl)\n')
+ "from bpython.curtsiesfrontend._internal " "import _Helper"
+ )
+ self.coderunner.interp.runsource("help = _Helper(_repl)\n")
- del self.coderunner.interp.locals['_repl']
- del self.coderunner.interp.locals['_Helper']
+ del self.coderunner.interp.locals["_repl"]
+ del self.coderunner.interp.locals["_Helper"]
def getstdout(self):
lines = self.lines_for_display + [self.current_line_formatted]
- s = '\n'.join(x.s if isinstance(x, FmtStr) else x for x in lines) \
- if lines else ''
+ s = (
+ "\n".join(x.s if isinstance(x, FmtStr) else x for x in lines)
+ if lines
+ else ""
+ )
return s
def focus_on_subprocess(self, args):
@@ -1688,10 +1892,12 @@ def focus_on_subprocess(self, args):
sys.__stdout__.write(terminal.save)
sys.__stdout__.write(terminal.move(0, 0))
sys.__stdout__.flush()
- p = subprocess.Popen(args,
- stdin=self.orig_stdin,
- stderr=sys.__stderr__,
- stdout=sys.__stdout__)
+ p = subprocess.Popen(
+ args,
+ stdin=self.orig_stdin,
+ stderr=sys.__stderr__,
+ stdout=sys.__stdout__,
+ )
p.wait()
sys.__stdout__.write(terminal.restore)
sys.__stdout__.flush()
@@ -1712,56 +1918,72 @@ def show_source(self):
try:
source = self.get_source_of_current_name()
except SourceNotFound as e:
- self.status_bar.message('%s' % (e, ))
+ self.status_bar.message("%s" % (e,))
else:
if self.config.highlight_show_source:
- source = format(PythonLexer().get_tokens(source),
- TerminalFormatter())
+ source = format(
+ PythonLexer().get_tokens(source), TerminalFormatter()
+ )
self.pager(source)
def help_text(self):
- return self.version_help_text() + '\n' + self.key_help_text()
+ return self.version_help_text() + "\n" + self.key_help_text()
def version_help_text(self):
- return (('bpython-curtsies version %s' % bpython.__version__) + ' ' +
- ('using curtsies version %s' % curtsies.__version__) + '\n' +
- HELP_MESSAGE.format(config_file_location=default_config_path(),
- example_config_url=EXAMPLE_CONFIG_URL,
- config=self.config))
+ return (
+ ("bpython-curtsies version %s" % bpython.__version__)
+ + " "
+ + ("using curtsies version %s" % curtsies.__version__)
+ + "\n"
+ + HELP_MESSAGE.format(
+ config_file_location=default_config_path(),
+ example_config_url=EXAMPLE_CONFIG_URL,
+ config=self.config,
+ )
+ )
def key_help_text(self):
- NOT_IMPLEMENTED = ('suspend', 'cut to buffer', 'search', 'last output',
- 'yank from buffer', 'cut to buffer')
+ NOT_IMPLEMENTED = (
+ "suspend",
+ "cut to buffer",
+ "search",
+ "last output",
+ "yank from buffer",
+ "cut to buffer",
+ )
pairs = []
- pairs.append(['complete history suggestion',
- 'right arrow at end of line'])
- pairs.append(['previous match with current line', 'up arrow'])
- for functionality, key in [(attr[:-4].replace('_', ' '),
- getattr(self.config, attr))
- for attr in self.config.__dict__
- if attr.endswith('key')]:
+ pairs.append(
+ ["complete history suggestion", "right arrow at end of line"]
+ )
+ pairs.append(["previous match with current line", "up arrow"])
+ for functionality, key in [
+ (attr[:-4].replace("_", " "), getattr(self.config, attr))
+ for attr in self.config.__dict__
+ if attr.endswith("key")
+ ]:
if functionality in NOT_IMPLEMENTED:
- key = 'Not Implemented'
- if key == '':
- key = 'Disabled'
+ key = "Not Implemented"
+ if key == "":
+ key = "Disabled"
pairs.append([functionality, key])
max_func = max(len(func) for func, key in pairs)
- return '\n'.join('%s : %s' % (func.rjust(max_func), key)
- for func, key in pairs)
+ return "\n".join(
+ "%s : %s" % (func.rjust(max_func), key) for func, key in pairs
+ )
def is_nop(char):
- return unicodedata.category(unicode(char)) == 'Cc'
+ return unicodedata.category(unicode(char)) == "Cc"
def tabs_to_spaces(line):
- return line.replace('\t', ' ')
+ return line.replace("\t", " ")
def _last_word(line):
- return line.split().pop() if line.split() else ''
+ return line.split().pop() if line.split() else ""
def compress_paste_event(paste_event):
@@ -1788,11 +2010,11 @@ def just_simple_events(event_list):
for e in event_list:
# '\n' necessary for pastes
if e in ("", "", "", "\n", "\r"):
- simple_events.append('\n')
+ simple_events.append("\n")
elif isinstance(e, events.Event):
pass # ignore events
- elif e == '