Skip to content

Commit 79472c1

Browse files
author
Elliot Boschwitz
authored
Set auto expand to false if less pager is installed (#423)
* Set auto expand to false if less pager is installed * Added tests and improved testability of code
1 parent d423efa commit 79472c1

File tree

4 files changed

+111
-7
lines changed

4 files changed

+111
-7
lines changed

mssqlcli/mssql_cli.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
from mssqlcli.sqltoolsclient import SqlToolsClient
4545
from mssqlcli.packages import special
4646
from mssqlcli.mssqlbuffer import mssql_is_multiline
47+
from mssqlcli.util import is_command_valid
4748
import mssqlcli.localized_strings as localized
4849

4950
# Query tuples are used for maintaining history
@@ -97,15 +98,18 @@ class MssqlCli(object):
9798
def set_default_pager(self, config):
9899
configured_pager = config['main'].get('pager')
99100
os_environ_pager = os.environ.get('PAGER')
101+
is_less_installed = is_command_valid(['less', '--version'])
102+
default_pager = configured_pager or os_environ_pager or \
103+
('less -SRXF' if is_less_installed else False) or None
100104

101105
if configured_pager:
102106
self.logger.info(
103107
'Default pager found in config file: "%s"', configured_pager)
104-
os.environ['PAGER'] = configured_pager
105108
elif os_environ_pager:
106109
self.logger.info('Default pager found in PAGER environment variable: "%s"',
107110
os_environ_pager)
108-
os.environ['PAGER'] = os_environ_pager
111+
elif is_less_installed:
112+
self.logger.info('Default pager set to Less')
109113
else:
110114
self.logger.info(
111115
'No default pager found in environment. Using os default pager')
@@ -115,6 +119,9 @@ def set_default_pager(self, config):
115119
if not os.environ.get('LESS'):
116120
os.environ['LESS'] = '-SRXF'
117121

122+
os.environ['PAGER'] = default_pager
123+
return default_pager
124+
118125
def __init__(self, options):
119126

120127
# Load config.
@@ -123,16 +130,13 @@ def __init__(self, options):
123130
self.initialize_logging()
124131
self.logger = logging.getLogger(u'mssqlcli.main')
125132

126-
self.set_default_pager(c)
127133
self.interactive_mode = options.interactive_mode
128134

129135
self.table_format = c['main']['table_format']
130136
self.decimal_format = c['data_formats']['decimal']
131137
self.float_format = c['data_formats']['float']
132138
self.null_string = c['main'].get('null_string', '<null>')
133139
self.expanded_output = c['main']['expand'] == 'always'
134-
self.auto_expand = options.auto_vertical_output or c['main']['expand'] == 'auto'
135-
self.prompt_session = None
136140
self.integrated_auth = options.integrated_auth
137141
self.less_chatty = bool(
138142
options.less_chatty) or c['main'].as_bool('less_chatty') or self.interactive_mode
@@ -152,6 +156,12 @@ def __init__(self, options):
152156
}
153157

154158
if self.interactive_mode:
159+
pager = self.set_default_pager(c)
160+
self.prompt_session = None
161+
162+
# set auto_expand to false if less is detected with auto expand
163+
self.auto_expand = options.auto_vertical_output \
164+
or (c['main']['expand'] == 'auto' and pager != 'less -SRXF')
155165
self.multiline = c['main'].as_bool('multi_line')
156166
self.multiline_mode = c['main'].get('multi_line_mode', 'tsql')
157167
self.vi_mode = c['main'].as_bool('vi')
@@ -559,7 +569,7 @@ def _evaluate_command(self, text):
559569
all_success = False
560570
continue
561571

562-
if self.auto_expand and self.prompt_session:
572+
if self.interactive_mode and self.auto_expand and self.prompt_session:
563573
max_width = self.prompt_session.output.get_size().columns
564574
else:
565575
max_width = None

mssqlcli/util.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from os import devnull
2+
import subprocess
3+
14
def encode(s):
25
try:
36
return s.encode('utf-8')
@@ -14,3 +17,20 @@ def decode(s):
1417
except (AttributeError, SyntaxError, UnicodeEncodeError):
1518
pass
1619
return s
20+
21+
def is_command_valid(command):
22+
"""
23+
Checks if command is recognized on machine. Used to determine installations
24+
of 'less' pager.
25+
"""
26+
if not command:
27+
return False
28+
29+
try:
30+
# call command silentyly
31+
with open(devnull, 'wb') as no_out:
32+
subprocess.call(command, stdout=no_out, stderr=no_out)
33+
except OSError:
34+
return False
35+
else:
36+
return True

tests/mssqltestutils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import mssqlcli.sqltoolsclient as sqltoolsclient
66
import mssqlcli.mssqlcliclient as mssqlcliclient
77
from mssqlcli.mssql_cli import MssqlCli
8+
from mssqlcli.config import get_config
89
from mssqlcli.mssqlclioptionsparser import create_parser
910
from utility import random_str
1011

@@ -70,6 +71,14 @@ def create_mssql_cli_options(**nondefault_options):
7071

7172
return default_mssql_cli_options
7273

74+
def create_mssql_cli_config(options=None):
75+
"""
76+
Create config from options.
77+
"""
78+
if not options:
79+
options = create_mssql_cli_options()
80+
return get_config(options.mssqlclirc_file)
81+
7382
def shutdown(connection):
7483
connection.shutdown()
7584

tests/test_interactive_mode.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
import os
2+
import sys
13
import pytest
4+
import utility
5+
from mssqlcli.util import is_command_valid
26
from mssqltestutils import (
37
create_mssql_cli,
8+
create_mssql_cli_config,
49
shutdown,
510
test_queries,
611
get_file_contents,
712
get_io_paths
813
)
914

10-
class TestInteractiveModeQueries:
15+
class TestInteractiveMode:
16+
"""
17+
Fixture used at class-level.
18+
"""
1119
@staticmethod
1220
@pytest.fixture(scope='class')
1321
def mssqlcli():
@@ -19,6 +27,7 @@ def mssqlcli():
1927
yield mssqlcli
2028
shutdown(mssqlcli)
2129

30+
class TestInteractiveModeQueries(TestInteractiveMode):
2231
@staticmethod
2332
@pytest.mark.parametrize("query_str, test_file", test_queries)
2433
@pytest.mark.timeout(60)
@@ -73,3 +82,59 @@ def invalid_run(**options):
7382
finally:
7483
if mssqlcli is not None:
7584
shutdown(mssqlcli)
85+
86+
class TestInteractiveModePager(TestInteractiveMode):
87+
"""
88+
Test default pager setting.
89+
"""
90+
91+
@staticmethod
92+
@pytest.mark.timeout(60)
93+
def test_pager_environ(mssqlcli):
94+
"""
95+
Defaults to environment variable with no config value for pager
96+
"""
97+
os.environ['PAGER'] = 'testing environ value'
98+
99+
config = create_mssql_cli_config()
100+
101+
# remove config pager value if exists
102+
if 'pager' in config['main'].keys():
103+
config['main'].pop('pager')
104+
105+
assert mssqlcli.set_default_pager(config) == 'testing environ value'
106+
107+
os.environ['PAGER'] = 'less -SRXF'
108+
assert mssqlcli.set_default_pager(config) == 'less -SRXF'
109+
110+
@staticmethod
111+
@pytest.mark.timeout(60)
112+
def test_pager_config(mssqlcli):
113+
"""
114+
Defaults to config value over environment variable
115+
"""
116+
os.environ['PAGER'] = 'less -SRXF'
117+
config_value = 'testing config value'
118+
119+
config = create_mssql_cli_config()
120+
config['main']['pager'] = config_value
121+
assert mssqlcli.set_default_pager(config) == config_value
122+
123+
@staticmethod
124+
@pytest.mark.timeout(60)
125+
def test_valid_command():
126+
"""
127+
Checks valid command by running mssql-cli executable in repo
128+
"""
129+
if sys.platform == 'win32':
130+
exe_name = 'mssql-cli.bat'
131+
else:
132+
exe_name = 'mssql-cli'
133+
134+
assert is_command_valid([os.path.join(utility.ROOT_DIR, exe_name), '--version'])
135+
136+
@staticmethod
137+
@pytest.mark.timeout(60)
138+
def test_invalid_command():
139+
assert not is_command_valid(None)
140+
assert not is_command_valid('')

0 commit comments

Comments
 (0)