From 0c29cafb4850eaeae862aefb745dc76211f6e975 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 27 Jul 2026 11:06:48 +1000 Subject: [PATCH 1/5] settings --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 100eba6..e548495 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,9 @@ "editor.renderWhitespace": "all", "editor.rulers": [ 76 ], "editor.tabSize": 2, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, "files.exclude": { "**/__pycache__": true, "**/*.egg-info": true, From c26793deab3677d9de6317238253049da4a5c3e3 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 27 Jul 2026 11:19:22 +1000 Subject: [PATCH 2/5] fix: fixed failure message to be passed to `MissingValueException` --- pyclasp/option_argument.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pyclasp/option_argument.py b/pyclasp/option_argument.py index 7b5531e..0d78562 100644 --- a/pyclasp/option_argument.py +++ b/pyclasp/option_argument.py @@ -148,7 +148,23 @@ def _set_value(self, value, from_ctor=False): pass else: - raise MissingValueException("the '%s' option does not have a value to be interpreted as an integer" % (self.name)) + if arg_spec.value_type == bool: + + type_name = "boolean" + elif arg_spec.value_type == float: + + type_name = "a number" + elif arg_spec.value_type == int: + + type_name = "an integer" + elif _SUPPORT_long and arg_spec.value_type == long: + + type_name = "a long integer" + else: + + type_name = "a value" + + raise MissingValueException("the '%s' option does not have a value to be interpreted as %s" % (self.name, type_name)) self.given_value = given_value From c1ce03436b80a282e13adc76946cebc17a2e70e6 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 27 Jul 2026 11:41:47 +1000 Subject: [PATCH 3/5] feature: added unit-tests to exercise the observed failure --- tests/test_typed_values.py | 91 +++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/tests/test_typed_values.py b/tests/test_typed_values.py index 308bbe4..3ca005b 100755 --- a/tests/test_typed_values.py +++ b/tests/test_typed_values.py @@ -303,10 +303,44 @@ def test_empty_option_value_of_type_int(self): argv = ( "myprog", "--length=" ) - with self.assertRaises(clasp.MissingValueException): + with self.assertRaises(clasp.MissingValueException) as ctx: clasp.parse(argv, specifications) + self.assertEqual("the '--length' option does not have a value to be interpreted as an integer", str(ctx.exception)) + + + def test_empty_option_value_of_type_float(self): + + specifications = ( + + clasp.option('--length', alias='-l', value_type=float), + ) + + argv = ( 'myprog', '--length=' ) + + with self.assertRaises(clasp.MissingValueException) as ctx: + + clasp.parse(argv, specifications) + + self.assertEqual("the '--length' option does not have a value to be interpreted as a number", str(ctx.exception)) + + + def test_empty_option_value_of_type_bool(self): + + specifications = ( + + clasp.option('--length', alias='-l', value_type=bool), + ) + + argv = ( 'myprog', '--length=' ) + + with self.assertRaises(clasp.MissingValueException) as ctx: + + clasp.parse(argv, specifications) + + self.assertEqual("the '--length' option does not have a value to be interpreted as boolean", str(ctx.exception)) + def test_empty_option_value_of_type_int_2(self): @@ -442,6 +476,61 @@ def test_flags_of_flags_and_options_combined(self): self.assertEqual(0, len(args.values)) + def test_reproduce_falsy_default_issue(self): + + specifications = ( + clasp.option( + "--depth", + alias="-d", + default=0, + value_type=int, + ), + clasp.option( + "--exchange", + alias="-e", + required=True, + value_type=str, + ), + ) + + argv = ('liquidity-assessor', '-e', 'bybit', '-d', '10') + args = clasp.parse(argv, specifications) + + self.assertEqual(2, len(args.options)) + + depth_option = next(opt for opt in args.options if opt.name == '--depth') + self.assertEqual(10, depth_option.value) + + exchange_option = next(opt for opt in args.options if opt.name == '--exchange') + self.assertEqual('bybit', exchange_option.value) + + + def test_reproduce_falsy_default_issue_with_default_used(self): + + specifications = ( + clasp.option( + "--depth", + alias="-d", + default=0, + value_type=int, + ), + clasp.option( + "--exchange", + alias="-e", + required=True, + value_type=str, + ), + ) + + argv = ('liquidity-assessor', '-e', 'bybit') + args = clasp.parse(argv, specifications) + + # In CLASP, options with defaults are not automatically added to args.options unless specified on the CLI or if we lookup/access them? + # Wait, let's verify if they are added or not. + self.assertEqual(1, len(args.options)) + exchange_option = args.options[0] + self.assertEqual('bybit', exchange_option.value) + if '__main__' == __name__: From 72318cfa79b64fe08796244cd77a89fa70d802fc Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 27 Jul 2026 11:42:53 +1000 Subject: [PATCH 4/5] fix: falsy default values causing `MissingValueException` for option arguments Using a truthiness check `if given_value:` on option arguments causes valid, falsy default values (such as `0`, `0.0`, or `False`) to be treated as if they were missing or not set. This leads to an incorrect `MissingValueException` being raised during command-line argument parsing. Replacing this with an explicit `is not None` check allows falsy default values to be correctly recognized, processed, and validated according to their respective value types. --- pyclasp/option_argument.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyclasp/option_argument.py b/pyclasp/option_argument.py index 0d78562..67ab05f 100644 --- a/pyclasp/option_argument.py +++ b/pyclasp/option_argument.py @@ -85,7 +85,7 @@ def _set_value(self, value, from_ctor=False): given_value = arg_spec.default_value - if given_value: + if given_value is not None: if arg_spec.value_type: From d4f3e9f961c6a321ea5ad1016a7076e499861db8 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 27 Jul 2026 11:46:01 +1000 Subject: [PATCH 5/5] 0.8.12 --- CHANGES.md | 6 ++++++ pyclasp/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 664b2f5..19ff324 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,12 @@ # **CLASP.Python** Changes +## 0.8.12 - 28th July 2026 + +* fixed falsy default values causing `MissingValueException` for option arguments; +* fixed failure message to be passed to `MissingValueException`; + + ## 0.8.11 - 27th July 2026 * ~ packaging & boilerplate improvements: diff --git a/pyclasp/__init__.py b/pyclasp/__init__.py index 7d1f47d..30977d0 100644 --- a/pyclasp/__init__.py +++ b/pyclasp/__init__.py @@ -10,7 +10,7 @@ __license__ = "BSD-3-Clause" __maintainer__ = "Matt Wilson" __status__ = "Beta" -__version__ = "0.8.11" +__version__ = "0.8.12" from .exceptions import * from .flag_specification import FlagSpecification, flag diff --git a/setup.py b/setup.py index 1901d62..d394e62 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name="pyclasp", python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*', - version='0.8.11', + version='0.8.12', author="Matt Wilson", author_email="matthew@synesis.com.au",