Skip to content

Commit 7744d7c

Browse files
committed
Automatically detect the best shell
1 parent 36f37ea commit 7744d7c

File tree

3 files changed

+77
-50
lines changed

3 files changed

+77
-50
lines changed

tests/test_cli.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,13 @@ def test_shell(
516516
assert expected_output.format(**template_ctx) in result.output
517517

518518

519-
@pytest.mark.parametrize("cli_cmd", ['shell', ('shell', '--pdb')])
519+
@pytest.mark.parametrize(
520+
"cli_cmd",
521+
[
522+
'shell',
523+
('shell', '--pdb'),
524+
],
525+
)
520526
@pytest.mark.parametrize(
521527
"cli_args,inputs,env,template_ctx,exception,message",
522528
[
@@ -605,12 +611,23 @@ def test_shell_target_missing(
605611
assert message.format(**template_ctx) in result.output
606612

607613

614+
@pytest.mark.parametrize(
615+
"cli_cmd",
616+
[
617+
# 'shell',
618+
# ('shell', '--pdb'),
619+
('shell', '--code'),
620+
# ('shell', '--bpython'),
621+
# ('shell', '--ptipython'),
622+
# ('shell', '--ptpython'),
623+
# ('shell', '--ipython'),
624+
],
625+
)
608626
@pytest.mark.parametrize(
609627
"cli_args,inputs,env,message",
610628
[
611629
(
612630
[
613-
'shell',
614631
'-L{SOCKET_NAME}',
615632
],
616633
[],
@@ -619,7 +636,6 @@ def test_shell_target_missing(
619636
),
620637
(
621638
[
622-
'shell',
623639
'-L{SOCKET_NAME}',
624640
],
625641
[],
@@ -629,6 +645,7 @@ def test_shell_target_missing(
629645
],
630646
)
631647
def test_shell_plus(
648+
cli_cmd,
632649
cli_args,
633650
inputs,
634651
env,
@@ -652,7 +669,9 @@ def test_shell_plus(
652669
SERVER_SOCKET_NAME=server.socket_name,
653670
)
654671

655-
cli_args[:] = [cli_arg.format(**template_ctx) for cli_arg in cli_args]
672+
cli_cmd = list(cli_cmd) if isinstance(cli_cmd, (list, tuple)) else [cli_cmd]
673+
cli_args = cli_cmd + [cli_arg.format(**template_ctx) for cli_arg in cli_args]
674+
656675
for k, v in env.items():
657676
monkeypatch.setenv(k, v.format(**template_ctx))
658677

tmuxp/cli.py

+34-10
Original file line numberDiff line numberDiff line change
@@ -671,22 +671,44 @@ def startup(config_dir):
671671
'command',
672672
help='Instead of opening shell, execute python code in libtmux and exit',
673673
)
674+
@click.option(
675+
'--best',
676+
'shell',
677+
flag_value='best',
678+
help='Use best shell available in site packages',
679+
default=True,
680+
)
681+
@click.option('--pdb', 'shell', flag_value='pdb', help='Use plain pdb')
682+
@click.option(
683+
'--code', 'shell', flag_value='code', help='Use stdlib\'s code.interact()'
684+
)
685+
@click.option(
686+
'--ptipython', 'shell', flag_value='ptipython', help='Use ptpython + ipython'
687+
)
688+
@click.option('--ptpython', 'shell', flag_value='ptpython', help='Use ptpython')
689+
@click.option('--ipython', 'shell', flag_value='ipython', help='Use ipython')
690+
@click.option('--bpython', 'shell', flag_value='bpython', help='Use bpython')
674691
@click.option(
675692
'--use-pythonrc/--no-startup',
676693
'use_pythonrc',
677-
help='Load the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.',
694+
help='Load PYTHONSTARTUP env var and ~/.pythonrc.py script in --code',
678695
default=False,
679696
)
680-
@click.option('--pdb', 'shell', flag_value='pdb', help='Use plain pdb')
681697
@click.option(
682-
'--code', 'shell', flag_value='code', help='Use stdlib\'s code.interact()'
698+
'--use-vi-mode/--no-vi-mode',
699+
'use_vi_mode',
700+
help='Use vi-mode in ptpython/ptipython',
701+
default=False,
683702
)
684-
@click.option('--ptipython', 'shell', flag_value='pdb', help='Use ptpython + ipython')
685-
@click.option('--ptpython', 'shell', flag_value='pdb', help='Use ptpython')
686-
@click.option('--ipython', 'shell', flag_value='pdb', help='Use ipython')
687-
@click.option('--bpython', 'shell', flag_value='pdb', help='Use bpython')
688703
def command_shell(
689-
session_name, window_name, socket_name, socket_path, command, shell, use_pythonrc
704+
session_name,
705+
window_name,
706+
socket_name,
707+
socket_path,
708+
command,
709+
shell,
710+
use_pythonrc,
711+
use_vi_mode,
690712
):
691713
"""Launch python shell for tmux server, session, window and pane.
692714
@@ -724,12 +746,14 @@ def command_shell(
724746
from .shell import launch
725747

726748
launch(
749+
shell=shell,
750+
use_pythonrc=use_pythonrc, # shell: code
751+
use_vi_mode=use_vi_mode, # shell: ptpython, ptipython
752+
# tmux environment / libtmux variables
727753
server=server,
728754
session=session,
729755
window=window,
730756
pane=pane,
731-
use_pythonrc=use_pythonrc,
732-
shell=shell,
733757
)
734758

735759

tmuxp/shell.py

+20-36
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ def detect_best_shell():
7272
return 'code'
7373

7474

75-
def get_bpython(options, extra_args):
76-
try:
77-
from bpython import embed # NOQA F841
78-
except ImportError:
79-
return traceback.format_exc()
75+
def get_bpython(options, extra_args=None):
76+
if extra_args is None:
77+
extra_args = {}
78+
79+
from bpython import embed # NOQA F841
8080

8181
def launch_bpython():
8282
imported_objects = get_launch_args(**options)
@@ -104,15 +104,11 @@ def launch_ipython():
104104

105105
return launch_ipython
106106
except ImportError:
107-
str_exc = traceback.format_exc()
108107
# IPython < 0.11
109108
# Explicitly pass an empty list as arguments, because otherwise
110109
# IPython would use sys.argv from this script.
111110
# Notebook not supported for IPython < 0.11.
112-
try:
113-
from IPython.Shell import IPShell
114-
except ImportError:
115-
return str_exc + "\n" + traceback.format_exc()
111+
from IPython.Shell import IPShell
116112

117113
def launch_ipython():
118114
imported_objects = get_launch_args(**options)
@@ -122,30 +118,26 @@ def launch_ipython():
122118
return launch_ipython
123119

124120

125-
def get_ptpython(self, options):
121+
def get_ptpython(options, vi_mode=False):
126122
try:
127123
from ptpython.repl import embed, run_config
128124
except ImportError:
129-
tb = traceback.format_exc()
130-
try: # prompt_toolkit < v0.27
131-
from prompt_toolkit.contrib.repl import embed, run_config
132-
except ImportError:
133-
return tb
125+
from prompt_toolkit.contrib.repl import embed, run_config
134126

135-
def run_ptpython():
127+
def launch_ptpython():
136128
imported_objects = get_launch_args(**options)
137129
history_filename = os.path.expanduser('~/.ptpython_history')
138130
embed(
139131
globals=imported_objects,
140132
history_filename=history_filename,
141-
vi_mode=options['vi_mode'],
133+
vi_mode=vi_mode,
142134
configure=run_config,
143135
)
144136

145-
return run_ptpython
137+
return launch_ptpython
146138

147139

148-
def get_ptipython(options):
140+
def get_ptipython(options, vi_mode=False):
149141
"""Based on django-extensions
150142
151143
Run renamed to launch, get_imported_objects renamed to get_launch_args
@@ -154,20 +146,17 @@ def get_ptipython(options):
154146
from ptpython.ipython import embed
155147
from ptpython.repl import run_config
156148
except ImportError:
157-
tb = traceback.format_exc()
158-
try: # prompt_toolkit < v0.27
159-
from prompt_toolkit.contrib.ipython import embed
160-
from prompt_toolkit.contrib.repl import run_config
161-
except ImportError:
162-
return tb
149+
# prompt_toolkit < v0.27
150+
from prompt_toolkit.contrib.ipython import embed
151+
from prompt_toolkit.contrib.repl import run_config
163152

164153
def launch_ptipython():
165154
imported_objects = get_launch_args(**options)
166155
history_filename = os.path.expanduser('~/.ptpython_history')
167156
embed(
168157
user_ns=imported_objects,
169158
history_filename=history_filename,
170-
vi_mode=options['vi_mode'],
159+
vi_mode=vi_mode,
171160
configure=run_config,
172161
)
173162

@@ -226,30 +215,25 @@ def get_code(use_pythonrc, imported_objects):
226215
pythonrc_code = handle.read()
227216
# Match the behavior of the cpython shell where an error in
228217
# PYTHONSTARTUP prints an exception and continues.
229-
try:
230-
exec(compile(pythonrc_code, pythonrc, 'exec'), imported_objects)
231-
except Exception:
232-
import traceback
233-
234-
traceback.print_exc()
218+
exec(compile(pythonrc_code, pythonrc, 'exec'), imported_objects)
235219

236220
def launch_code():
237221
code.interact(local=imported_objects)
238222

239223
return launch_code
240224

241225

242-
def launch(shell='best', use_pythonrc=False, **kwargs):
226+
def launch(shell='best', use_pythonrc=False, use_vi_mode=False, **kwargs):
243227
# Also allowing passing shell='code' to force using code.interact
244228
imported_objects = get_launch_args(**kwargs)
245229

246230
if shell == 'best':
247231
shell = detect_best_shell()
248232

249233
if shell == 'ptipython':
250-
launch = get_ptipython(options=kwargs)
234+
launch = get_ptipython(options=kwargs, vi_mode=use_vi_mode)
251235
elif shell == 'ptpython':
252-
launch = get_ptpython(options=kwargs)
236+
launch = get_ptpython(options=kwargs, vi_mode=use_vi_mode)
253237
elif shell == 'ipython':
254238
launch = get_ipython(options=kwargs)
255239
elif shell == 'bpython':

0 commit comments

Comments
 (0)