From 2df18292736d48dd587bc8fb7e0dcf35efd99f78 Mon Sep 17 00:00:00 2001 From: Arvind Kandpal Date: Tue, 28 Jul 2026 12:51:14 +0530 Subject: [PATCH] Fix --mode inheritance for SOURCE command in cqlsh The SOURCE command spawns a subshell that was previously defaulting to tabular mode, ignoring the --mode flag passed to the parent shell. This fix propagates the mode to the subshell so that automation relying on CSV/JSON output doesn't silently revert to tabular formatting. Added regression tests in test_cqlsh_output.py to verify both CSV and JSON modes are preserved. --- pylib/cqlshlib/cqlshmain.py | 3 +- pylib/cqlshlib/test/test_cqlsh_output.py | 48 +++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/pylib/cqlshlib/cqlshmain.py b/pylib/cqlshlib/cqlshmain.py index de0da15b31..9c8178fedc 100755 --- a/pylib/cqlshlib/cqlshmain.py +++ b/pylib/cqlshlib/cqlshmain.py @@ -1552,7 +1552,8 @@ class Shell(cmd.Cmd): request_timeout=self.session.default_timeout, connect_timeout=self.conn.connect_timeout, is_subshell=True, - auth_provider=self.auth_provider) + auth_provider=self.auth_provider, + mode=self.mode) # duplicate coverage related settings in subshell if self.coverage: subshell.coverage = True diff --git a/pylib/cqlshlib/test/test_cqlsh_output.py b/pylib/cqlshlib/test/test_cqlsh_output.py index 731d500ba1..59542c37bb 100644 --- a/pylib/cqlshlib/test/test_cqlsh_output.py +++ b/pylib/cqlshlib/test/test_cqlsh_output.py @@ -1199,4 +1199,50 @@ class TestCqlshOutput(BaseTestCase): finally: cleanup_q2 = "DELETE FROM %s.has_all_types WHERE num = 9999;" % ks cqlsh_testcall(args=('--mode', 'json'), prompt=None, env=self.default_env, - tty=False, input=cleanup_q2 + '\n') \ No newline at end of file + tty=False, input=cleanup_q2 + '\n') + + def test_source_inherits_mode(self): + """SOURCE subshell must inherit --mode from the parent shell (not revert to tabular).""" + import json + import tempfile + import os + + ks = get_keyspace() + query = "SELECT a, b FROM twenty_rows_table WHERE a IN ('1', '2');\n" + + # Write the query to a temporary SOURCE file + with tempfile.NamedTemporaryFile(mode='w', suffix='.cql', delete=False) as f: + f.write(query) + source_file = f.name + + try: + # Run cqlsh --mode json and SOURCE the file + source_cmd = "SOURCE '%s';\n" % source_file + output, result = cqlsh_testcall(args=('--mode', 'json'), prompt=None, + env=self.default_env, tty=False, + input=source_cmd) + self.assertEqual(0, result) + try: + rows = json.loads(output) + self.assertIsInstance(rows, list, + msg='SOURCE with --mode json must produce a JSON array') + self.assertEqual(len(rows), 2) + results = {(item['a'], item['b']) for item in rows} + self.assertIn(('1', '1'), results) + self.assertIn(('2', '2'), results) + except ValueError as e: + self.fail("SOURCE output is not valid JSON (mode not inherited): %s\nOutput: %r" + % (e, output)) + + # Also verify CSV mode is inherited + output_csv, result_csv = cqlsh_testcall(args=('--mode', 'csv'), prompt=None, + env=self.default_env, tty=False, + input=source_cmd) + self.assertEqual(0, result_csv) + import csv, io + reader = csv.reader(io.StringIO(output_csv.strip())) + csv_rows = list(reader) + self.assertGreater(len(csv_rows), 1, msg='SOURCE with --mode csv must produce CSV rows') + self.assertIn('a', csv_rows[0], msg='First CSV row must be a header') + finally: + os.unlink(source_file) \ No newline at end of file