Skip to content

Commit 3a817cc

Browse files
committed
resolve merge conflicts
2 parents 1e3f9f2 + ecff461 commit 3a817cc

File tree

32 files changed

+2199
-132
lines changed

32 files changed

+2199
-132
lines changed

AUTHORS

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ bpython is written and maintained by Bob Farrell and Andreas Stuehrk
66
Other contributors are (in alphabetical order):
77

88
* Federico Ceratto <federico dot ceratto at gmail dot com>
9+
* Ingrid Cheung
10+
* Martha Girdler <martha at cheezburger dot com>
11+
* Eike Hein <sho at eikehein dot com>
12+
* Allison Kaptur <allison dot kaptur at gmail dot com>
13+
* Brandon Navra <brandon dot navra at gmail dot com>
914
* Michele Orrù <maker dot py at gmail dot com>
1015
* Pavel Panchekha <pavpanchekha at gmail dot com>
1116
* Sebastian Ramacher <s dot ramacher at gmx dot at>
1217
* Amjith Ramanujam <amjith dot r at gmail dot com>
1318
* Simon de Vlieger <simon at ikanobori dot jp>
1419
* Marien Zwart <marien dot zwart at gmail dot com>
15-
* Brandon Navra <brandon dot navra at gmail dot com>
20+
1621

1722
Many thanks for all contributions!

CHANGELOG

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
Changelog
22
=========
33

4-
Since v0.11
5-
___________
4+
dev
5+
---
6+
7+
We want to give special thanks to the Hacker School project-
8+
(https://www.hackerschool.com/) for choosing bpython as their pet hacking
9+
project. In special we would like to thank the following people for contributing
10+
their code to bpython:
11+
12+
- Martha Girdler
13+
- Allison Kaptur
14+
- Ingrid Cheung
15+
16+
We'd also like to thank Eike Hein for contributing his pastebin code which now
17+
makes it possible to paste using a 3rd party program unlocking a whole slew of
18+
pastebins for bpython users.
619

720
* Added a new pastebin_helper config option to name an executable that should
821
perform pastebin upload on bpython's behalf. If set, this overrides
@@ -11,6 +24,10 @@ ___________
1124
* Fixed a bug causing pastebin upload to fail after a previous attempt was
1225
unsuccessful. A duplicate pastebin error would be displayed in this case,
1326
despite the original upload having failed.
27+
* Added more key shortcuts to bpython.urwid
28+
* Smarter dedenting after certain expressions
29+
* #74 fixed broken completion when auto_display_list was disabled
30+
1431

1532
v0.11
1633
-----

bpython/args.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from bpython import __version__
1212
from bpython.config import default_config_path, loadini, Struct
13+
from bpython.translations import _
1314

1415

1516
class OptionParserFailed(ValueError):
@@ -49,24 +50,24 @@ def parse(args, extras=None, ignore_stdin=False):
4950
args = sys.argv[1:]
5051

5152
parser = RaisingOptionParser(
52-
usage='Usage: %prog [options] [file [args]]\n'
53+
usage=_('Usage: %prog [options] [file [args]]\n'
5354
'NOTE: If bpython sees an argument it does '
5455
'not know, execution falls back to the '
55-
'regular Python interpreter.')
56+
'regular Python interpreter.'))
5657
# This is not sufficient if bpython gains its own -m support
5758
# (instead of falling back to Python itself for that).
5859
# That's probably fixable though, for example by having that
5960
# option swallow all remaining arguments in a callback.
6061
parser.disable_interspersed_args()
6162
parser.add_option('--config', default=default_config_path(),
62-
help='use CONFIG instead of default config file')
63+
help=_('Use CONFIG instead of default config file.'))
6364
parser.add_option('--interactive', '-i', action='store_true',
64-
help='Drop to bpython shell after running file '
65-
'instead of exiting')
65+
help=_('Drop to bpython shell after running file '
66+
'instead of exiting.'))
6667
parser.add_option('--quiet', '-q', action='store_true',
67-
help="Don't flush the output to stdout.")
68+
help=_("Don't flush the output to stdout."))
6869
parser.add_option('--version', '-V', action='store_true',
69-
help='print version and exit')
70+
help=_('Print version and exit.'))
7071

7172
if extras is not None:
7273
extras_group = OptionGroup(parser, extras[0], extras[1])

bpython/cli.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ def complete(self, tab=False):
436436
if self.list_win_visible and not self.config.auto_display_list:
437437
self.scr.touchwin()
438438
self.list_win_visible = False
439+
self.matches_iter.update()
439440
return
440441

441442
if self.config.auto_display_list or tab:
@@ -1699,7 +1700,6 @@ def gethw():
16991700
"""
17001701

17011702
if platform.system() != 'Windows':
1702-
import struct
17031703
h, w = struct.unpack(
17041704
"hhhh",
17051705
fcntl.ioctl(sys.__stdout__, termios.TIOCGWINSZ, "\000" * 8))[0:2]
@@ -1715,7 +1715,6 @@ def gethw():
17151715
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
17161716

17171717
if res:
1718-
import struct
17191718
(bufx, bufy, curx, cury, wattr,
17201719
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
17211720
sizex = right - left + 1
@@ -1888,7 +1887,6 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
18881887

18891888

18901889
def main(args=None, locals_=None, banner=None):
1891-
locale.setlocale(locale.LC_ALL, "")
18921890
translations.init()
18931891

18941892

bpython/repl.py

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from bpython.translations import _
5151
from bpython.autocomplete import Autocomplete
5252

53+
5354
# Needed for special handling of __abstractmethods__
5455
# abc only exists since 2.6, so check both that it exists and that it's
5556
# the one we're expecting
@@ -720,16 +721,16 @@ def pastebin(self, s=None):
720721
s = self.getstdout()
721722

722723
if (self.config.pastebin_confirm and
723-
not self.interact.confirm("Pastebin buffer? (y/N) ")):
724-
self.interact.notify("Pastebin aborted")
724+
not self.interact.confirm(_("Pastebin buffer? (y/N) "))):
725+
self.interact.notify(_("Pastebin aborted"))
725726
return
726727
return self.do_pastebin(s)
727728

728729
def do_pastebin(self, s):
729730
"""Actually perform the upload."""
730731
if s == self.prev_pastebin_content:
731-
self.interact.notify('Duplicate pastebin. Previous URL: ' +
732-
self.prev_pastebin_url)
732+
self.interact.notify(_('Duplicate pastebin. Previous URL: %s') %
733+
(self.prev_pastebin_url, ))
733734
return self.prev_pastebin_url
734735

735736
if self.config.pastebin_helper:
@@ -742,16 +743,16 @@ def do_pastebin_xmlrpc(self, s):
742743
try:
743744
pasteservice = ServerProxy(self.config.pastebin_url)
744745
except IOError, e:
745-
self.interact.notify("Pastebin error for URL '%s': %s" %
746+
self.interact.notify(_("Pastebin error for URL '%s': %s") %
746747
(self.config.pastebin_url, str(e)))
747748
return
748749

749-
self.interact.notify('Posting data to pastebin...')
750+
self.interact.notify(_('Posting data to pastebin...'))
750751
try:
751752
paste_id = pasteservice.pastes.newPaste('pycon', s, '', '', '',
752753
self.config.pastebin_private)
753754
except (SocketError, XMLRPCError), e:
754-
self.interact.notify('Upload failed: %s' % (str(e), ) )
755+
self.interact.notify(_('Upload failed: %s') % (str(e), ) )
755756
return
756757

757758
self.prev_pastebin_content = s
@@ -760,12 +761,12 @@ def do_pastebin_xmlrpc(self, s):
760761
paste_id = urlquote(paste_id)
761762
paste_url = paste_url_template.safe_substitute(paste_id=paste_id)
762763
self.prev_pastebin_url = paste_url
763-
self.interact.notify('Pastebin URL: %s' % (paste_url, ), 10)
764+
self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10)
764765
return paste_url
765766

766767
def do_pastebin_helper(self, s):
767768
"""Call out to helper program for pastebin upload."""
768-
self.interact.notify('Posting data to pastebin...')
769+
self.interact.notify(_('Posting data to pastebin...'))
769770

770771
try:
771772
helper = subprocess.Popen('',
@@ -777,34 +778,34 @@ def do_pastebin_helper(self, s):
777778
paste_url = output.split()[0]
778779
except OSError, e:
779780
if e.errno == errno.ENOENT:
780-
self.interact.notify('Upload failed: '
781-
'Helper program not found.')
781+
self.interact.notify(_('Upload failed: '
782+
'Helper program not found.'))
782783
else:
783-
self.interact.notify('Upload failed: '
784-
'Helper program could not be run.')
784+
self.interact.notify(_('Upload failed: '
785+
'Helper program could not be run.'))
785786
return
786787

787788
if helper.returncode != 0:
788-
self.interact.notify('Upload failed: '
789-
'Helper program returned non-zero exit '
790-
'status %s.' % (helper.returncode, ))
789+
self.interact.notify(_('Upload failed: '
790+
'Helper program returned non-zero exit '
791+
'status %s.' % (helper.returncode, )))
791792
return
792793

793794
if not paste_url:
794-
self.interact.notify('Upload failed: '
795-
'No output from helper program.')
795+
self.interact.notify(_('Upload failed: '
796+
'No output from helper program.'))
796797
return
797798
else:
798799
parsed_url = urlparse(paste_url)
799800
if (not parsed_url.scheme
800801
or any(unicodedata.category(c) == 'Cc' for c in paste_url)):
801-
self.interact.notify("Upload failed: "
802-
"Failed to recognize the helper "
803-
"program's output as an URL.")
802+
self.interact.notify(_("Upload failed: "
803+
"Failed to recognize the helper "
804+
"program's output as an URL."))
804805
return
805806

806807
self.prev_pastebin_content = s
807-
self.interact.notify('Pastebin URL: %s' % (paste_url, ), 10)
808+
self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10)
808809
return paste_url
809810

810811
def push(self, s, insert_into_history=True):
@@ -970,6 +971,9 @@ def next_indentation(line, tab_length):
970971
indentation = (len(line) - len(line.lstrip(' '))) // tab_length
971972
if line.rstrip().endswith(':'):
972973
indentation += 1
974+
elif indentation >= 1:
975+
if line.lstrip().startswith(('return', 'pass', 'raise', 'yield')):
976+
indentation -= 1
973977
return indentation
974978

975979

bpython/test/test_keys.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,68 @@
11
import unittest
22
import bpython.keys as keys
33

4-
class TestKeys(unittest.TestCase):
4+
class TestCLIKeys(unittest.TestCase):
55
def test_keymap_map(self):
66
"""Verify KeyMap.map being a dictionary with the correct
77
length."""
8-
self.assertEqual(len(keys.key_dispatch.map), 43)
8+
self.assertEqual(len(keys.cli_key_dispatch.map), 43)
99

1010
def test_keymap_setitem(self):
1111
"""Verify keys.KeyMap correctly setting items."""
12-
keys.key_dispatch['simon'] = 'awesome';
13-
self.assertEqual(keys.key_dispatch['simon'], 'awesome')
12+
keys.cli_key_dispatch['simon'] = 'awesome';
13+
self.assertEqual(keys.cli_key_dispatch['simon'], 'awesome')
1414

1515
def test_keymap_delitem(self):
1616
"""Verify keys.KeyMap correctly removing items."""
17-
keys.key_dispatch['simon'] = 'awesome'
18-
del keys.key_dispatch['simon']
19-
if 'simon' in keys.key_dispatch.map:
17+
keys.cli_key_dispatch['simon'] = 'awesome'
18+
del keys.cli_key_dispatch['simon']
19+
if 'simon' in keys.cli_key_dispatch.map:
2020
raise Exception('Key still exists in dictionary')
2121

2222
def test_keymap_getitem(self):
2323
"""Verify keys.KeyMap correctly looking up items."""
24-
self.assertEqual(keys.key_dispatch['C-['], (chr(27), '^['))
25-
self.assertEqual(keys.key_dispatch['F11'], ('KEY_F(11)',))
26-
self.assertEqual(keys.key_dispatch['C-a'], ('\x01', '^A'))
24+
self.assertEqual(keys.cli_key_dispatch['C-['], (chr(27), '^['))
25+
self.assertEqual(keys.cli_key_dispatch['F11'], ('KEY_F(11)',))
26+
self.assertEqual(keys.cli_key_dispatch['C-a'], ('\x01', '^A'))
2727

2828
def test_keymap_keyerror(self):
2929
"""Verify keys.KeyMap raising KeyError when getting undefined key"""
3030
def raiser():
31-
keys.key_dispatch['C-asdf']
32-
keys.key_dispatch['C-qwerty']
31+
keys.cli_key_dispatch['C-asdf']
32+
keys.cli_key_dispatch['C-qwerty']
3333
self.assertRaises(KeyError, raiser);
3434

35+
class TestUrwidKeys(unittest.TestCase):
36+
def test_keymap_map(self):
37+
"""Verify KeyMap.map being a dictionary with the correct
38+
length."""
39+
self.assertEqual(len(keys.urwid_key_dispatch.map), 64)
40+
41+
def test_keymap_setitem(self):
42+
"""Verify keys.KeyMap correctly setting items."""
43+
keys.urwid_key_dispatch['simon'] = 'awesome';
44+
self.assertEqual(keys.urwid_key_dispatch['simon'], 'awesome')
45+
46+
def test_keymap_delitem(self):
47+
"""Verify keys.KeyMap correctly removing items."""
48+
keys.urwid_key_dispatch['simon'] = 'awesome'
49+
del keys.urwid_key_dispatch['simon']
50+
if 'simon' in keys.urwid_key_dispatch.map:
51+
raise Exception('Key still exists in dictionary')
52+
53+
def test_keymap_getitem(self):
54+
"""Verify keys.KeyMap correctly looking up items."""
55+
self.assertEqual(keys.urwid_key_dispatch['F11'], 'f11')
56+
self.assertEqual(keys.urwid_key_dispatch['C-a'], 'ctrl a')
57+
self.assertEqual(keys.urwid_key_dispatch['M-a'], 'meta a')
58+
59+
def test_keymap_keyerror(self):
60+
"""Verify keys.KeyMap raising KeyError when getting undefined key"""
61+
def raiser():
62+
keys.urwid_key_dispatch['C-asdf']
63+
keys.urwid_key_dispatch['C-qwerty']
64+
self.assertRaises(KeyError, raiser);
65+
66+
3567
if __name__ == '__main__':
3668
unittest.main()

bpython/test/test_repl.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ def test_name_in_assignment_without_spaces(self):
217217
self.assertTrue(self.repl.get_args())
218218
self.assertEqual(self.repl.current_func.__name__, "range")
219219

220+
self.setInputLine("{x:range(")
221+
self.assertTrue(self.repl.get_args())
222+
self.assertEqual(self.repl.current_func.__name__, "range")
223+
224+
self.setInputLine("foo(1, 2, x,range(")
225+
self.assertEqual(self.repl.current_func.__name__, "range")
226+
220227
def test_nonexistent_name(self):
221228
self.setInputLine("spamspamspam(")
222229
self.assertFalse(self.repl.get_args())

bpython/translations/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import gettext
2+
import locale
23
import os.path
3-
from sys import version_info
4+
import sys
45

56
from bpython import package_dir
67

78
translator = None
89

9-
if version_info >= (3, 0):
10+
if sys.version_info >= (3, 0):
1011
def _(message):
1112
return translator.gettext(message)
1213
else:
@@ -15,6 +16,15 @@ def _(message):
1516

1617

1718
def init(locale_dir=None, languages=None):
19+
try:
20+
locale.setlocale(locale.LC_ALL, '')
21+
except locale.Error:
22+
# This means that the user's environment is broken. Let's just continue
23+
# with the default C locale.
24+
sys.stderr.write("Error: Your locale settings are not supported by "
25+
"the system. Using the fallback 'C' locale instead. "
26+
"Please fix your locale settings.\n")
27+
1828
global translator
1929
if locale_dir is None:
2030
locale_dir = os.path.join(package_dir, 'translations')

0 commit comments

Comments
 (0)