From 7dbda1654e03ca141f541d745d44e3355f8e0fb8 Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:22:01 -0800 Subject: [PATCH 1/8] test new python versions #137 --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 36f1c60..f7c5d65 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest, windows-latest, macos-latest ] - python-version: [ "3.9", "3.10", "3.11" ] + python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 849aa84798bc81bc4e0c51ac0cee3449f153b278 Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 13:43:44 -0500 Subject: [PATCH 2/8] replace OS simulation with OS-dependent test skipping #138 --- source/lib/JMSLab/tests/_test_helpers.py | 21 ---------------- source/lib/JMSLab/tests/test_build_matlab.py | 7 +++--- source/lib/JMSLab/tests/test_build_stata.py | 26 +++++++++----------- source/lib/JMSLab/tests/test_log.py | 13 +++++----- 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/source/lib/JMSLab/tests/_test_helpers.py b/source/lib/JMSLab/tests/_test_helpers.py index 7b6a402..710a0d3 100644 --- a/source/lib/JMSLab/tests/_test_helpers.py +++ b/source/lib/JMSLab/tests/_test_helpers.py @@ -10,27 +10,6 @@ from .._exception_classes import BadExtensionError -def platform_patch(platform, path): - ''' - This script produces a mock.patch decorator that mocks sys.platform - as `platform` in both the module given by `path` and, if possible, - this module's imported misc module. - ''' - main_patch = mock.patch('%s.sys.platform' % path, platform) - - # Try to also patch misc.sys.platform - try: - misc_path = '%s.misc.sys.platform' % path - # Check whether misc_path is a valid module - importlib.util.find_spec(misc_path) - misc_patch = mock.patch(misc_path, platform) - total_patch = lambda f: misc_patch(main_patch(f)) - except ImportError: - total_patch = main_patch - - return total_patch - - def command_match(command, language, which = None): match = None diff --git a/source/lib/JMSLab/tests/test_build_matlab.py b/source/lib/JMSLab/tests/test_build_matlab.py index 81abe83..a191612 100644 --- a/source/lib/JMSLab/tests/test_build_matlab.py +++ b/source/lib/JMSLab/tests/test_build_matlab.py @@ -7,6 +7,7 @@ import shutil import os import re +import sys # Import testing helper modules from . import _test_helpers as helpers @@ -32,7 +33,7 @@ class TestBuildMatlab(unittest.TestCase): def setUp(self): (TESTDIR / 'build').mkdir(exist_ok = True) - @helpers.platform_patch('darwin', path) + @unittest.skipUnless(os.name == 'posix', 'Unix-like (POSIX) only test') @subprocess_patch def test_unix(self, mock_check_output): ''' @@ -57,7 +58,7 @@ def check_call(self, mock_check_output, options): for option in options: self.assertIn(option, command.split(' ')) - @helpers.platform_patch('win32', path) + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') @subprocess_patch def test_windows(self, mock_check_output): ''' @@ -69,7 +70,7 @@ def test_windows(self, mock_check_output): helpers.standard_test(self, build_matlab, 'm') self.check_call(mock_check_output, ['-nosplash', '-minimize', '-wait']) - @helpers.platform_patch('riscos', path) + @unittest.skipUnless(sys.platform != 'win32' and os.name != 'posix', 'Non-Unix / non-Windows test') @subprocess_patch def test_other_os(self, mock_check_output): ''' diff --git a/source/lib/JMSLab/tests/test_build_stata.py b/source/lib/JMSLab/tests/test_build_stata.py index 2d3be16..c1dc31f 100644 --- a/source/lib/JMSLab/tests/test_build_stata.py +++ b/source/lib/JMSLab/tests/test_build_stata.py @@ -6,6 +6,7 @@ import unittest import shutil import os +import sys # Import testing helper modules from . import _test_helpers as helpers @@ -31,7 +32,7 @@ class TestBuildStata(unittest.TestCase): def setUp(self): (TESTDIR / 'build').mkdir(exist_ok = True) - @helpers.platform_patch('darwin', path) + @unittest.skipUnless(os.name == 'posix', 'Unix-like (POSIX) only test') @mock.patch('%s.misc.is_in_path' % path) @subprocess_patch def test_unix(self, mock_check_output, mock_path): @@ -43,7 +44,7 @@ def test_unix(self, mock_check_output, mock_path): helpers.standard_test(self, build_stata, 'do', env = env, system_mock = mock_check_output) - @helpers.platform_patch('win32', path) + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') @mock.patch('%s.misc.is_in_path' % path) @mock.patch('%s.misc.is_64_windows' % path) @subprocess_patch @@ -60,7 +61,7 @@ def test_windows(self, mock_check_output, mock_is_64, mock_path): helpers.standard_test(self, build_stata, 'do', env = env, system_mock = mock_check_output) - @helpers.platform_patch('cygwin', path) + @unittest.skipUnless(sys.platform != 'win32' and os.name != 'posix', 'Non-Unix / non-Windows test') @mock.patch('%s.misc.is_in_path' % path) @subprocess_patch def test_other_platform(self, mock_check_output, mock_path): @@ -85,7 +86,7 @@ def test_other_platform(self, mock_check_output, mock_path): source = 'test_script.do', env = env) - @helpers.platform_patch('darwin', path) + @unittest.skipUnless(os.name == 'posix', 'Unix-like (POSIX) only test') @subprocess_patch def test_stata_unix(self, mock_check_output): mock_check_output.side_effect = fx.make_stata_side_effect(STATA) @@ -93,7 +94,7 @@ def test_stata_unix(self, mock_check_output): helpers.standard_test(self, build_stata, 'do', env = env, system_mock = mock_check_output) - @helpers.platform_patch('win32', path) + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') @subprocess_patch def test_stata_windows(self, mock_check_output): mock_check_output.side_effect = fx.make_stata_side_effect(STATA) @@ -131,15 +132,12 @@ def test_no_executable_in_path(self, mock_check_output, mock_path): mock_path.side_effect = fx.make_stata_path_effect('') env = {'executable_names': {'stata': None}} - with helpers.platform_patch('darwin', path), self.assertRaises(ExecCallError): - build_stata(target = 'test_output.txt', - source = 'test_script.do', - env = env) - - with helpers.platform_patch('win32', path), self.assertRaises(ExecCallError): - build_stata(target = 'test_output.txt', - source = 'test_script.do', - env = env) + + if os.name == 'posix' or sys.platform == 'win32': + with self.assertRaises(ExecCallError): + build_stata(target = 'test_output.txt', + source = 'test_script.do', + env = env) @subprocess_patch def test_unavailable_executable(self, mock_check_output): diff --git a/source/lib/JMSLab/tests/test_log.py b/source/lib/JMSLab/tests/test_log.py index 83d37b2..b4af3e6 100644 --- a/source/lib/JMSLab/tests/test_log.py +++ b/source/lib/JMSLab/tests/test_log.py @@ -64,7 +64,7 @@ def test_start_log_popen_on_unix(self, mock_open, mock_popen): mock_popen.assert_called_with('tee -a test_log.txt', 'w') # Set the platform to Windows - @helpers.platform_patch('win32', '%s.misc' % path) + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') def test_start_log_stdout_on_windows(self): ''' Test that start_log() leads stdout to be captured in @@ -84,7 +84,8 @@ def test_start_log_stdout_on_windows(self): message_match = r'^\*\*\* New build: \{[0-9\s\-:]+\} \*\*\*\n%s$' % test self.assertTrue(re.search(message_match, log_contents.strip())) - @helpers.platform_patch('win32', '%s.misc' % path) + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') + @mock.patch('%s.os.popen' % path) @mock.patch('%s.open' % path) def test_start_log_open_on_windows(self, mock_open, mock_popen): @@ -99,11 +100,11 @@ def test_start_log_open_on_windows(self, mock_open, mock_popen): mock_popen.assert_not_called() - @helpers.platform_patch('cygwin', '%s.misc' % path) + @unittest.skipUnless(sys.platform != 'win32' and os.name != 'posix', 'Non-Unix / non-Windows test') def test_start_log_other_os(self): ''' Test start_log()'s behaviour when run on a platform other - than Windows, Darwin, or Linux. + than Windows, or Unix (We don't expect it to change sys.stdout, but we expect it to set sys.stderr to sys.stdout.) ''' @@ -118,7 +119,7 @@ def test_start_log_other_os(self): log.start_log(mode = 'develop') self.assertEqual(sys.stderr, test_file) - @helpers.platform_patch('darwin', '%s.misc' % path) + @unittest.skipUnless(os.name == 'posix', 'Unix-like (POSIX) only test') def test_invalid_mode(self): '''Check behaviour when mode argument is invalid''' with self.assertRaises(Exception): @@ -127,7 +128,7 @@ def test_invalid_mode(self): with self.assertRaises(Exception): log.start_log(mode = None) - @helpers.platform_patch('darwin', '%s.misc' % path) + @unittest.skipUnless(os.name == 'posix', 'Unix-like (POSIX) only test') def test_start_log_nonstring_input(self): ''' Test start_log()'s behaviour when its log argument is From c4758b7e761cceabdee9a66e28693daa11a9aac3 Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 13:45:58 -0500 Subject: [PATCH 3/8] update indentation #138 --- source/lib/JMSLab/tests/test_log.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/lib/JMSLab/tests/test_log.py b/source/lib/JMSLab/tests/test_log.py index b4af3e6..44c4f37 100644 --- a/source/lib/JMSLab/tests/test_log.py +++ b/source/lib/JMSLab/tests/test_log.py @@ -63,7 +63,6 @@ def test_start_log_popen_on_unix(self, mock_open, mock_popen): log.start_log(mode = 'develop', log = 'test_log.txt') mock_popen.assert_called_with('tee -a test_log.txt', 'w') - # Set the platform to Windows @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') def test_start_log_stdout_on_windows(self): ''' @@ -84,8 +83,7 @@ def test_start_log_stdout_on_windows(self): message_match = r'^\*\*\* New build: \{[0-9\s\-:]+\} \*\*\*\n%s$' % test self.assertTrue(re.search(message_match, log_contents.strip())) - @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') - + @unittest.skipUnless(sys.platform == 'win32', 'Windows-only test') @mock.patch('%s.os.popen' % path) @mock.patch('%s.open' % path) def test_start_log_open_on_windows(self, mock_open, mock_popen): From 7b0b4193a1dcc2d54db41b5f68520501feca77d7 Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:10:50 -0500 Subject: [PATCH 4/8] improve unix OS test #138 --- source/lib/JMSLab/misc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/lib/JMSLab/misc.py b/source/lib/JMSLab/misc.py index 7d4280b..21809a7 100644 --- a/source/lib/JMSLab/misc.py +++ b/source/lib/JMSLab/misc.py @@ -1,5 +1,4 @@ import os -import sys import datetime from pathlib import Path @@ -20,8 +19,7 @@ def is_unix(): This function return True if the user's platform is Unix and false otherwise. ''' - unix = ['darwin', 'linux', 'linux2'] - return sys.platform in unix + return os.name == 'posix' def is_64_windows(): From 4058202de13362f46f0daf07cc15f15759e7ba0f Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:12:08 -0500 Subject: [PATCH 5/8] add sys import to misc #138 --- source/lib/JMSLab/tests/test_misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/lib/JMSLab/tests/test_misc.py b/source/lib/JMSLab/tests/test_misc.py index 704e4ea..e1675d5 100644 --- a/source/lib/JMSLab/tests/test_misc.py +++ b/source/lib/JMSLab/tests/test_misc.py @@ -3,6 +3,7 @@ from unittest import mock from pathlib import Path +import sys import unittest import datetime import os From 4e98d537144ddabdfadaa71765b7e4a6c5cc255d Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:12:58 -0500 Subject: [PATCH 6/8] restore old sys setup #138 --- source/lib/JMSLab/misc.py | 1 + source/lib/JMSLab/tests/test_misc.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lib/JMSLab/misc.py b/source/lib/JMSLab/misc.py index 21809a7..aa82445 100644 --- a/source/lib/JMSLab/misc.py +++ b/source/lib/JMSLab/misc.py @@ -1,5 +1,6 @@ import os import datetime +import sys from pathlib import Path from .builders.executables import get_executable_path diff --git a/source/lib/JMSLab/tests/test_misc.py b/source/lib/JMSLab/tests/test_misc.py index e1675d5..704e4ea 100644 --- a/source/lib/JMSLab/tests/test_misc.py +++ b/source/lib/JMSLab/tests/test_misc.py @@ -3,7 +3,6 @@ from unittest import mock from pathlib import Path -import sys import unittest import datetime import os From d34f52c272f2797aa1008481d059ada0f30ea2bb Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:18:04 -0500 Subject: [PATCH 7/8] Revert "improve unix OS test #138" This reverts commit 7b0b4193a1dcc2d54db41b5f68520501feca77d7. --- source/lib/JMSLab/misc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/lib/JMSLab/misc.py b/source/lib/JMSLab/misc.py index aa82445..2a178b0 100644 --- a/source/lib/JMSLab/misc.py +++ b/source/lib/JMSLab/misc.py @@ -1,4 +1,5 @@ import os +import sys import datetime import sys @@ -20,7 +21,8 @@ def is_unix(): This function return True if the user's platform is Unix and false otherwise. ''' - return os.name == 'posix' + unix = ['darwin', 'linux', 'linux2'] + return sys.platform in unix def is_64_windows(): From 638a881d3a145c6f8dbe00890d608ac489ac0b4d Mon Sep 17 00:00:00 2001 From: Chris Liao <33707455+liaochris@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:18:28 -0500 Subject: [PATCH 8/8] Update misc.py --- source/lib/JMSLab/misc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/source/lib/JMSLab/misc.py b/source/lib/JMSLab/misc.py index 2a178b0..7d4280b 100644 --- a/source/lib/JMSLab/misc.py +++ b/source/lib/JMSLab/misc.py @@ -1,7 +1,6 @@ import os import sys import datetime -import sys from pathlib import Path from .builders.executables import get_executable_path