From 362a15b96237cb70ac491e7cb6dd4ca9b70ff84e Mon Sep 17 00:00:00 2001 From: "Shankar.KV" Date: Wed, 24 Jun 2026 19:17:51 +0530 Subject: [PATCH 1/4] checks for python interpreters --- .../check_apt/verify_no_conda_path.py | 58 +++++++++++++++++ .../check_conda/verify_conda_path.py | 62 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py create mode 100644 test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py diff --git a/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py b/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py new file mode 100644 index 00000000..1eb86e29 --- /dev/null +++ b/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class AptSysPathCheck(udf.TestCase): + def setUp(self): + self.schema = "SYS_PATH_CHECK_APT" + self.query(f'CREATE SCHEMA {self.schema}', ignore_errors=True) + self.query(f'OPEN SCHEMA {self.schema}', ignore_errors=True) + + def tearDown(self): + self.query(f'DROP SCHEMA {self.schema} CASCADE', ignore_errors=True) + + def test_apt_runtime_does_not_use_conda_paths(self): + """ + For apt-based Python runtimes, sys.executable and sys.path entries + must not point to /opt/conda. + """ + self.query(udf.fixindent(''' + CREATE OR REPLACE python3 SCALAR SCRIPT + check_apt_runtime_no_conda_paths() + RETURNS VARCHAR(10000) AS + + import sys + from pathlib import Path + + def normalize(path_value): + try: + return str(Path(path_value).resolve()) + except Exception: + return str(path_value) + + def run(ctx): + failures = [] + + executable = normalize(sys.executable) + if "/opt/conda" in executable: + failures.append(f"sys.executable contains /opt/conda: {executable}") + + for path_entry in [entry for entry in sys.path if entry]: + normalized_path = normalize(path_entry) + if "/opt/conda" in normalized_path: + failures.append( + f"sys.path contains /opt/conda entry: {normalized_path}" + ) + + return "; ".join(failures) if failures else "OK" + / + ''')) + + rows = self.query("SELECT check_apt_runtime_no_conda_paths()") + result = rows[0][0] + self.assertEqual(result, "OK", f"Apt runtime conda-path check failed. Got: {result}") + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py b/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py new file mode 100644 index 00000000..afd14213 --- /dev/null +++ b/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class CondaSysPathCheck(udf.TestCase): + def setUp(self): + self.schema = "SYS_PATH_CHECK_CONDA" + self.query(f'CREATE SCHEMA {self.schema}', ignore_errors=True) + self.query(f'OPEN SCHEMA {self.schema}', ignore_errors=True) + + def tearDown(self): + self.query(f'DROP SCHEMA {self.schema} CASCADE', ignore_errors=True) + + def test_conda_interpreter_and_sys_path(self): + """ + For conda flavor, Python runtimes shall be: + 1) sys.executable resolves to /opt/conda + 2) first non-empty sys.path entry resolves to /opt/conda + """ + self.query(udf.fixindent(''' + CREATE OR REPLACE python3 SCALAR SCRIPT + check_conda_runtime() + RETURNS VARCHAR(10000) AS + + import sys + from pathlib import Path + + def normalize(path_value): + try: + return str(Path(path_value).resolve()) + except Exception: + return str(path_value) + + def run(ctx): + failures = [] + + executable = normalize(sys.executable) + if not executable.startswith("/opt/conda"): + failures.append(f"sys.executable outside /opt/conda: {executable}") + + path_entries = [entry for entry in sys.path if entry] + if not path_entries: + failures.append("sys.path has no non-empty entries") + else: + first_path = normalize(path_entries[0]) + if not first_path.startswith("/opt/conda"): + failures.append( + f"sys.path first entry outside /opt/conda: {first_path}" + ) + + return "; ".join(failures) if failures else "OK" + / + ''')) + + rows = self.query("SELECT check_conda_runtime()") + result = rows[0][0] + self.assertEqual(result, "OK", f"Conda runtime check failed. Got: {result}") + + +if __name__ == '__main__': + udf.main() From 850fd02fdc9c368d28573a3e0a6acb5081055cbb Mon Sep 17 00:00:00 2001 From: "Shankar.KV" Date: Wed, 24 Jun 2026 20:05:57 +0530 Subject: [PATCH 2/4] making the workflow changes --- flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json | 2 +- flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.10-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.10/ci.json | 2 +- flavors/template-Exasol-all-python-3.12-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.12/ci.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json index 47735860..b05e7035 100644 --- a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all"], + "folders": ["python3/all", "python3/python_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json index 47735860..b05e7035 100644 --- a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all"], + "folders": ["python3/all", "python3/python_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.10-conda/ci.json b/flavors/template-Exasol-all-python-3.10-conda/ci.json index 33a91a99..9e48b1cf 100644 --- a/flavors/template-Exasol-all-python-3.10-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.10-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all"], + "folders": ["python3/all", "python3/python_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.10/ci.json b/flavors/template-Exasol-all-python-3.10/ci.json index 0695644a..284ebe75 100644 --- a/flavors/template-Exasol-all-python-3.10/ci.json +++ b/flavors/template-Exasol-all-python-3.10/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all/fast"], + "folders": ["python3/all/fast", "python3/python_apt"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.12-conda/ci.json b/flavors/template-Exasol-all-python-3.12-conda/ci.json index bc677241..c2ffd538 100644 --- a/flavors/template-Exasol-all-python-3.12-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.12-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all"], + "folders": ["python3/all", "python3/python_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.12/ci.json b/flavors/template-Exasol-all-python-3.12/ci.json index 41f72a5e..ca244118 100644 --- a/flavors/template-Exasol-all-python-3.12/ci.json +++ b/flavors/template-Exasol-all-python-3.12/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all"], + "folders": ["python3/all", "python3/python_apt"], "goal": "release", "generic_language_tests": [] }, From e2d2a9af494c284d29d94b11892ab983d81157f2 Mon Sep 17 00:00:00 2001 From: "Shankar.KV" Date: Thu, 25 Jun 2026 12:52:17 +0530 Subject: [PATCH 3/4] fixing the paths --- flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json | 2 +- flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.10-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.10/ci.json | 2 +- flavors/template-Exasol-all-python-3.12-conda/ci.json | 2 +- flavors/template-Exasol-all-python-3.12/ci.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json index b05e7035..68018ecc 100644 --- a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all", "python3/python_conda"], + "folders": ["python3/all", "python3/sys_path_check/check_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json index b05e7035..68018ecc 100644 --- a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all", "python3/python_conda"], + "folders": ["python3/all", "python3/sys_path_check/check_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.10-conda/ci.json b/flavors/template-Exasol-all-python-3.10-conda/ci.json index 9e48b1cf..cca2b0cc 100644 --- a/flavors/template-Exasol-all-python-3.10-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.10-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all", "python3/python_conda"], + "folders": ["python3/all", "python3/sys_path_check/check_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.10/ci.json b/flavors/template-Exasol-all-python-3.10/ci.json index 284ebe75..120a4c91 100644 --- a/flavors/template-Exasol-all-python-3.10/ci.json +++ b/flavors/template-Exasol-all-python-3.10/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all/fast", "python3/python_apt"], + "folders": ["python3/all/fast", "python3/sys_path_check/check_apt"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.12-conda/ci.json b/flavors/template-Exasol-all-python-3.12-conda/ci.json index c2ffd538..8c6e69e7 100644 --- a/flavors/template-Exasol-all-python-3.12-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.12-conda/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all", "python3/python_conda"], + "folders": ["python3/all", "python3/sys_path_check/check_conda"], "goal": "release", "generic_language_tests": [] }, diff --git a/flavors/template-Exasol-all-python-3.12/ci.json b/flavors/template-Exasol-all-python-3.12/ci.json index ca244118..16e04aad 100644 --- a/flavors/template-Exasol-all-python-3.12/ci.json +++ b/flavors/template-Exasol-all-python-3.12/ci.json @@ -6,7 +6,7 @@ { "name": "python", "files": [], - "folders": ["python3/all", "python3/python_apt"], + "folders": ["python3/all", "python3/sys_path_check/check_apt"], "goal": "release", "generic_language_tests": [] }, From b78180b59de6f71b317a81e9dbbd2c107846dea0 Mon Sep 17 00:00:00 2001 From: "Shankar.KV" Date: Thu, 25 Jun 2026 12:53:08 +0530 Subject: [PATCH 4/4] only values are retunred from UDF. not checks --- .../check_apt/verify_no_conda_path.py | 42 ++++++++++++------- .../check_conda/verify_conda_path.py | 41 ++++++++++-------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py b/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py index 1eb86e29..7a7e0b88 100644 --- a/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py +++ b/test_container/tests/test/python3/sys_path_check/check_apt/verify_no_conda_path.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +import json + from exasol_python_test_framework import udf @@ -22,6 +24,7 @@ def test_apt_runtime_does_not_use_conda_paths(self): check_apt_runtime_no_conda_paths() RETURNS VARCHAR(10000) AS + import json import sys from pathlib import Path @@ -32,26 +35,37 @@ def normalize(path_value): return str(path_value) def run(ctx): - failures = [] - executable = normalize(sys.executable) - if "/opt/conda" in executable: - failures.append(f"sys.executable contains /opt/conda: {executable}") - - for path_entry in [entry for entry in sys.path if entry]: - normalized_path = normalize(path_entry) - if "/opt/conda" in normalized_path: - failures.append( - f"sys.path contains /opt/conda entry: {normalized_path}" - ) + normalized_sys_path_entries = [ + normalize(path_entry) for path_entry in sys.path if path_entry + ] - return "; ".join(failures) if failures else "OK" + return json.dumps( + { + "sys_executable": executable, + "sys_path_entries": normalized_sys_path_entries, + } + ) / ''')) rows = self.query("SELECT check_apt_runtime_no_conda_paths()") - result = rows[0][0] - self.assertEqual(result, "OK", f"Apt runtime conda-path check failed. Got: {result}") + result = json.loads(rows[0][0]) + + executable = result["sys_executable"] + sys_path_entries = result["sys_path_entries"] + + self.assertNotIn( + "/opt/conda", + executable, + f"sys.executable shall not contain /opt/conda; But the value is {executable}", + ) + for path_entry in sys_path_entries: + self.assertNotIn( + "/opt/conda", + path_entry, + f"sys.path entry shall not contain /opt/conda; But the value is {path_entry}", + ) if __name__ == '__main__': diff --git a/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py b/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py index afd14213..ede2f44e 100644 --- a/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py +++ b/test_container/tests/test/python3/sys_path_check/check_conda/verify_conda_path.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +import json + from exasol_python_test_framework import udf @@ -23,6 +25,7 @@ def test_conda_interpreter_and_sys_path(self): check_conda_runtime() RETURNS VARCHAR(10000) AS + import json import sys from pathlib import Path @@ -33,29 +36,33 @@ def normalize(path_value): return str(path_value) def run(ctx): - failures = [] - executable = normalize(sys.executable) - if not executable.startswith("/opt/conda"): - failures.append(f"sys.executable outside /opt/conda: {executable}") - path_entries = [entry for entry in sys.path if entry] - if not path_entries: - failures.append("sys.path has no non-empty entries") - else: - first_path = normalize(path_entries[0]) - if not first_path.startswith("/opt/conda"): - failures.append( - f"sys.path first entry outside /opt/conda: {first_path}" - ) - - return "; ".join(failures) if failures else "OK" + first_path = normalize(path_entries[0]) if path_entries else "" + + return json.dumps( + { + "sys_executable": executable, + "first_sys_path_entry": first_path, + } + ) / ''')) rows = self.query("SELECT check_conda_runtime()") - result = rows[0][0] - self.assertEqual(result, "OK", f"Conda runtime check failed. Got: {result}") + result = json.loads(rows[0][0]) + + executable = result["sys_executable"] + first_path = result["first_sys_path_entry"] + + self.assertTrue( + executable.startswith("/opt/conda"), + f"sys.executable shall start with /opt/conda; But the value is {executable}", + ) + self.assertTrue( + first_path.startswith("/opt/conda"), + f"sys.path first entry shall start with /opt/conda; But the value is {first_path}", + ) if __name__ == '__main__':