Skip to content

Commit 318e93d

Browse files
committed
Merge in main branch to stay up to date
2 parents a9826fd + ec72900 commit 318e93d

File tree

10 files changed

+832
-42
lines changed

10 files changed

+832
-42
lines changed

AUTHORS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ Other contributors are (in alphabetical order):
88
* Federico Ceratto <federico dot ceratto at gmail dot com>
99
* Pavel Panchekha <pavpanchekha at gmail dot com>
1010
* Simon de Vlieger <simon at ikanobori dot jp>
11-
11+
* Marien Zwart <marien dot zwart at gmail dot com>
1212

1313
Many thanks for all contributions!

ROADMAP

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ bpython.gtk_
2222

2323
common
2424
- test suite
25+
26+
v1.0
27+
----
28+
- Ditch curses for an urwid/twisted loop

bpython/args.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@
77
import sys
88
import code
99
from optparse import OptionParser, OptionGroup
10-
from itertools import takewhile
1110

1211
from bpython import __version__
1312
from bpython.config import loadini, Struct, migrate_rc
1413

14+
15+
class OptionParserFailed(ValueError):
16+
"""Raised by the RaisingOptionParser for a bogus commandline."""
17+
18+
19+
class RaisingOptionParser(OptionParser):
20+
def error(self, msg):
21+
raise OptionParserFailed()
22+
23+
1524
def parse(args, extras=None):
1625
"""Receive an argument list - if None, use sys.argv - parse all args and
1726
take appropriate action. Also receive optional extra options: this should
@@ -39,10 +48,16 @@ def parse(args, extras=None):
3948
if args is None:
4049
args = sys.argv[1:]
4150

42-
parser = OptionParser(usage='Usage: %prog [options] [file [args]]\n'
43-
'NOTE: If bpython sees an argument it does '
44-
'not know, execution falls back to the '
45-
'regular Python interpreter.')
51+
parser = RaisingOptionParser(
52+
usage='Usage: %prog [options] [file [args]]\n'
53+
'NOTE: If bpython sees an argument it does '
54+
'not know, execution falls back to the '
55+
'regular Python interpreter.')
56+
# This is not sufficient if bpython gains its own -m support
57+
# (instead of falling back to Python itself for that).
58+
# That's probably fixable though, for example by having that
59+
# option swallow all remaining arguments in a callback.
60+
parser.disable_interspersed_args()
4661
parser.add_option('--config', '-c', default='~/.bpython/config',
4762
help='use CONFIG instead of default config file')
4863
parser.add_option('--interactive', '-i', action='store_true',
@@ -59,17 +74,11 @@ def parse(args, extras=None):
5974
extras_group.add_option(option)
6075
parser.add_option_group(extras_group)
6176

62-
all_args = set(parser._short_opt.keys() + parser._long_opt.keys())
63-
if args and not all_args.intersection(arg.split('=')[0] for arg in args):
77+
try:
78+
options, args = parser.parse_args(args)
79+
except OptionParserFailed:
6480
# Just let Python handle this
6581
os.execv(sys.executable, [sys.executable] + args)
66-
else:
67-
# Split args in bpython args and args for the executed file
68-
real_args = list(takewhile(lambda arg: arg.split('=')[0] in all_args,
69-
args))
70-
exec_args = args[len(real_args):]
71-
72-
options, args = parser.parse_args(real_args)
7382

7483
if options.version:
7584
print 'bpython version', __version__,
@@ -91,7 +100,7 @@ def parse(args, extras=None):
91100

92101
loadini(config, options.config)
93102

94-
return config, options, exec_args
103+
return config, options, args
95104

96105
def exec_code(interpreter, args):
97106
"""

bpython/cli.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def make_colors(config):
240240
class CLIRepl(Repl):
241241

242242
def __init__(self, scr, interp, statusbar, config, idle=None):
243-
Repl.__init__(self, interp, config, idle)
243+
Repl.__init__(self, interp, config)
244244
interp.writetb = self.writetb
245245
self.scr = scr
246246
self.list_win = newwin(get_colpair(config, 'background'), 1, 1, 1, 1)
@@ -253,6 +253,7 @@ def __init__(self, scr, interp, statusbar, config, idle=None):
253253
self.last_key_press = time.time()
254254
self.s = ''
255255
self.statusbar = statusbar
256+
self.formatter = BPythonFormatter(config.color_scheme)
256257

257258
def addstr(self, s):
258259
"""Add a string to the current input line and figure out
@@ -462,13 +463,6 @@ def echo(self, s, redraw=True):
462463
# Replace NUL bytes, as addstr raises an exception otherwise
463464
s = s.replace('\x00', '')
464465

465-
screen_height, screen_width = self.scr.getmaxyx()
466-
if self.iy >= (screen_height - 1):
467-
lines = (self.ix + len(s)) // screen_width
468-
if lines > 0:
469-
self.scr.scroll(lines)
470-
self.iy -= lines
471-
self.scr.move(self.iy, self.ix)
472466
self.scr.addstr(s, a)
473467

474468
if redraw and not self.evaluating:
@@ -865,8 +859,7 @@ def print_line(self, s, clr=False, newline=False):
865859
self.highlighted_paren = None
866860

867861
if self.config.syntax and (not self.paste_mode or newline):
868-
o = format(self.tokenize(s, newline),
869-
BPythonFormatter(self.config.color_scheme))
862+
o = format(self.tokenize(s, newline), self.formatter)
870863
else:
871864
o = s
872865

@@ -1622,6 +1615,7 @@ def main(args=None, locals_=None, banner=None):
16221615

16231616

16241617
if __name__ == '__main__':
1618+
from bpython.cli import main
16251619
main()
16261620

16271621
# vim: sw=4 ts=4 sts=4 ai et

bpython/formatter.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,14 @@ class BPythonFormatter(Formatter):
8383
See the Pygments source for more info; it's pretty
8484
straightforward."""
8585

86-
f_strings = {}
87-
8886
def __init__(self, color_scheme, **options):
89-
if not self.f_strings:
90-
for k, v in theme_map.iteritems():
91-
self.f_strings[k] = '\x01%s' % (color_scheme[v],)
92-
if k is Parenthesis:
93-
# FIXME: Find a way to make this the inverse of the current
94-
# background colour
95-
self.f_strings[k] += 'I'
87+
self.f_strings = {}
88+
for k, v in theme_map.iteritems():
89+
self.f_strings[k] = '\x01%s' % (color_scheme[v],)
90+
if k is Parenthesis:
91+
# FIXME: Find a way to make this the inverse of the current
92+
# background colour
93+
self.f_strings[k] += 'I'
9694
Formatter.__init__(self, **options)
9795

9896
def format(self, tokensource, outfile):

bpython/gtk_.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,5 @@ def main(args=None):
695695

696696

697697
if __name__ == '__main__':
698+
from bpython.gtk_ import main
698699
main()

bpython/importcompletion.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ def find_modules(path):
7575
# Possibly a package
7676
if '.' in name:
7777
continue
78+
elif os.path.isdir(os.path.join(path, name)):
79+
# Unfortunately, CPython just crashes if there is a directory
80+
# which ends with a python extension, so work around.
81+
continue
7882
name = os.path.splitext(name)[0]
7983
try:
8084
fo, pathname, _ = imp.find_module(name, [path])
@@ -99,6 +103,8 @@ def find_all_modules(path=None):
99103
path = sys.path
100104

101105
for p in path:
106+
if not path:
107+
path = os.curdir
102108
for module in find_modules(p):
103109
modules.add(module)
104110
yield

bpython/inspection.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#
2323

2424
from __future__ import with_statement
25+
import collections
2526
import inspect
2627
import pydoc
2728
import re
@@ -31,6 +32,17 @@
3132
from pygments.lexers import PythonLexer
3233
from pygments.token import Token
3334

35+
try:
36+
collections.Callable
37+
has_collections_callable = True
38+
try:
39+
import types
40+
types.InstanceType
41+
has_instance_type = True
42+
except AttributeError:
43+
has_instance_type = False
44+
except AttributeError:
45+
has_collections_callable = False
3446

3547
py3 = sys.version_info[0] == 3
3648

@@ -223,3 +235,13 @@ def is_eval_safe_name(string):
223235
return all(part.isidentifier() for part in string.split('.'))
224236
else:
225237
return all(_name.match(part) for part in string.split('.'))
238+
239+
240+
def is_callable(obj):
241+
if has_instance_type and isinstance(obj, types.InstanceType):
242+
# Work around a Python bug, see issue 7624
243+
return callable(obj)
244+
elif has_collections_callable:
245+
return isinstance(obj, collections.Callable)
246+
else:
247+
return callable(obj)

bpython/repl.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,13 @@ class Repl(object):
270270
XXX Subclasses should implement echo, current_line, cw
271271
"""
272272

273-
def __init__(self, interp, config, idle=None):
274-
"""Initialise the repl with, unfortunately, a curses screen passed to
275-
it. This needs to be split up so the curses crap isn't in here.
273+
def __init__(self, interp, config):
274+
"""Initialise the repl.
276275
277276
interp is a Python code.InteractiveInterpreter instance
278277
279-
The optional 'idle' parameter is a function that the repl call while
280-
it's blocking (waiting for keypresses). This, again, should be in a
281-
different class"""
278+
config is a populated bpython.config.Struct.
279+
"""
282280

283281
self.config = config
284282
self.cut_buffer = ''
@@ -365,7 +363,7 @@ def attr_lookup(self, obj, expr, attr):
365363
def _callable_postfix(self, value, word):
366364
"""rlcompleter's _callable_postfix done right."""
367365
with inspection.AttrCleaner(value):
368-
if hasattr(value, '__call__'):
366+
if inspection.is_callable(value):
369367
word += '('
370368
return word
371369

0 commit comments

Comments
 (0)