From 74bfb043df006446e39f68cd3e7840d6b01a5c7e Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 10:47:03 -0500 Subject: [PATCH 01/11] Add tests for Status type conversion --- mlos_bench/mlos_bench/environments/status.py | 7 +- .../tests/environments/test_status.py | 82 +++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 mlos_bench/mlos_bench/tests/environments/test_status.py diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index 0341698d34..70107f3f84 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -23,15 +23,18 @@ class Status(enum.Enum): TIMED_OUT = 7 @staticmethod - def from_str(status_str: str) -> "Status": + def from_str(status_str: str | int) -> "Status": """Convert a string to a Status enum.""" + if not isinstance(status_str, str): + _LOG.warning("Expected type %s for status: %s", type(status_str), status_str) + status_str = str(status_str) if status_str.isdigit(): try: return Status(int(status_str)) except ValueError: _LOG.warning("Unknown status: %d", int(status_str)) try: - status_str = status_str.upper() + status_str = status_str.upper().strip() return Status[status_str] except KeyError: _LOG.warning("Unknown status: %s", status_str) diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py new file mode 100644 index 0000000000..2d5d2a27d4 --- /dev/null +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -0,0 +1,82 @@ +""" +Unit tests for the :py:class:`mlos_bench.environments.status.Status` class. + +Tests the :py:meth:`mlos_bench.environments.status.Status.from_str` static method +for correct parsing of both numeric and string representations of each Status, +as well as handling of invalid input. +""" + +from typing import Any + +import pytest + +from mlos_bench.environments.status import Status + +@pytest.mark.parametrize( + ["input_str", "expected_status"], + [ + ("UNKNOWN", Status.UNKNOWN), + ("0", Status.UNKNOWN), + ("PENDING", Status.PENDING), + ("1", Status.PENDING), + ("READY", Status.READY), + ("2", Status.READY), + ("RUNNING", Status.RUNNING), + ("3", Status.RUNNING), + ("SUCCEEDED", Status.SUCCEEDED), + ("4", Status.SUCCEEDED), + ("CANCELED", Status.CANCELED), + ("5", Status.CANCELED), + ("FAILED", Status.FAILED), + ("6", Status.FAILED), + ("TIMED_OUT", Status.TIMED_OUT), + ("7", Status.TIMED_OUT), + (" TIMED_OUT ", Status.TIMED_OUT), + ] +) +def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: + """ + Test :py:meth:`Status.from_str` with valid string and numeric representations. + + Parameters + ---------- + input_str : str + String representation of the status. + expected_status : Status + Expected Status enum value. + """ + assert ( + Status.from_str(input_str) == expected_status + ), f"Expected {expected_status} for input: {input_str}" + # Check lowercase representation + assert ( + Status.from_str(input_str.lower()) == expected_status + ), f"Expected {expected_status} for input: {input_str.lower()}" + if input_str.isdigit(): + # Also test the numeric representation + assert ( + Status.from_str(int(input_str)) == expected_status # type: ignore + ), f"Expected {expected_status} for input: {int(input_str)}" + + +@pytest.mark.parametrize( + "invalid_input", + [ + "UNKNOWABLE", + "8", + "-1", + "successful", + "", + None, + 123, + [], + {}, + ] +) +def test_status_from_str_invalid(invalid_input: Any) -> None: + """ + Test :py:meth:`Status.from_str` raises ValueError for invalid input. + """ + assert ( + Status.from_str(invalid_input) == Status.UNKNOWN + ), f"Expected Status.UNKNOWN for invalid input: {invalid_input}" From c77f31ba90634825c1e0282784f9d84cea7db878 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 15:51:58 +0000 Subject: [PATCH 02/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../mlos_bench/tests/environments/test_status.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py index 2d5d2a27d4..234ee6dad5 100644 --- a/mlos_bench/mlos_bench/tests/environments/test_status.py +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -1,3 +1,7 @@ +# +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# """ Unit tests for the :py:class:`mlos_bench.environments.status.Status` class. @@ -12,6 +16,7 @@ from mlos_bench.environments.status import Status + @pytest.mark.parametrize( ["input_str", "expected_status"], [ @@ -32,7 +37,7 @@ ("TIMED_OUT", Status.TIMED_OUT), ("7", Status.TIMED_OUT), (" TIMED_OUT ", Status.TIMED_OUT), - ] + ], ) def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: """ @@ -71,12 +76,10 @@ def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: 123, [], {}, - ] + ], ) def test_status_from_str_invalid(invalid_input: Any) -> None: - """ - Test :py:meth:`Status.from_str` raises ValueError for invalid input. - """ + """Test :py:meth:`Status.from_str` raises ValueError for invalid input.""" assert ( Status.from_str(invalid_input) == Status.UNKNOWN ), f"Expected Status.UNKNOWN for invalid input: {invalid_input}" From 42258629f099468cc35ac47e944b5a656ff7c108 Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 11:41:28 -0500 Subject: [PATCH 03/11] improvements on docstring instructions --- .github/instructions/python.instructions.md | 8 ++++++++ mlos_bench/mlos_bench/environments/status.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/instructions/python.instructions.md b/.github/instructions/python.instructions.md index df4f92b5ec..0453691a62 100644 --- a/.github/instructions/python.instructions.md +++ b/.github/instructions/python.instructions.md @@ -8,6 +8,14 @@ applyTo: '**/*.py' - All functions, methods, classes, and attributes should have docstrings. +- Docstrings should be formatted using the [NumPy style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html) format. + + - The docstring should include a summary of the function or method's purpose, followed by a description of its parameters and return values. + + - The docstring should also include any exceptions that may be raised by the function or method. + + - Where possible docstring should include an executable example of how to use the function or method, including any important details about its usage. + - Docstrings should include Sphinx style crossref directives for functions, methods, classes, attributes, and data whenever possible using `:py:class:` or `:py:func:` or `:py:meth:` or `:py:attr:` or `:py:data` syntax, respectively, See Also diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index 70107f3f84..0dfbde066d 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -23,7 +23,7 @@ class Status(enum.Enum): TIMED_OUT = 7 @staticmethod - def from_str(status_str: str | int) -> "Status": + def from_str(status_str: str) -> "Status": """Convert a string to a Status enum.""" if not isinstance(status_str, str): _LOG.warning("Expected type %s for status: %s", type(status_str), status_str) From 3d8a783d454a0054cb07543c66c9278bf4be317e Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 11:53:18 -0500 Subject: [PATCH 04/11] type tweaks --- mlos_bench/mlos_bench/environments/status.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index 0dfbde066d..f2b7d83f52 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -6,6 +6,7 @@ import enum import logging +from typing import Any _LOG = logging.getLogger(__name__) @@ -23,7 +24,7 @@ class Status(enum.Enum): TIMED_OUT = 7 @staticmethod - def from_str(status_str: str) -> "Status": + def from_str(status_str: Any) -> "Status": """Convert a string to a Status enum.""" if not isinstance(status_str, str): _LOG.warning("Expected type %s for status: %s", type(status_str), status_str) From 34137a44ba0a1c52a994330ede691c75c40c529a Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 11:55:46 -0500 Subject: [PATCH 05/11] Revert "improvements on docstring instructions" This reverts commit 42258629f099468cc35ac47e944b5a656ff7c108. --- .github/instructions/python.instructions.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/instructions/python.instructions.md b/.github/instructions/python.instructions.md index 0453691a62..df4f92b5ec 100644 --- a/.github/instructions/python.instructions.md +++ b/.github/instructions/python.instructions.md @@ -8,14 +8,6 @@ applyTo: '**/*.py' - All functions, methods, classes, and attributes should have docstrings. -- Docstrings should be formatted using the [NumPy style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html) format. - - - The docstring should include a summary of the function or method's purpose, followed by a description of its parameters and return values. - - - The docstring should also include any exceptions that may be raised by the function or method. - - - Where possible docstring should include an executable example of how to use the function or method, including any important details about its usage. - - Docstrings should include Sphinx style crossref directives for functions, methods, classes, attributes, and data whenever possible using `:py:class:` or `:py:func:` or `:py:meth:` or `:py:attr:` or `:py:data` syntax, respectively, See Also From eebb21454b14b93e6e72b8ec1b7bb9a934cdf86f Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 14:31:18 -0500 Subject: [PATCH 06/11] stash completed statuses in a more reusable way --- mlos_bench/mlos_bench/environments/status.py | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index f2b7d83f52..aff4a25631 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -50,16 +50,17 @@ def is_good(self) -> bool: Status.SUCCEEDED, } + # Class based accessor method to avoid circular import + @staticmethod + def completed_statuses() -> set["Status"]: + """Get the set of :py:data:`.COMPLETED_STATUSES`.""" + return COMPLETED_STATUSES + def is_completed(self) -> bool: """Check if the status of the benchmark/environment Trial or Experiment is one - of {SUCCEEDED, CANCELED, FAILED, TIMED_OUT}. + of :py:data:`.COMPLETED_STATUSES`. """ - return self in { - Status.SUCCEEDED, - Status.CANCELED, - Status.FAILED, - Status.TIMED_OUT, - } + return self in COMPLETED_STATUSES def is_pending(self) -> bool: """Check if the status of the benchmark/environment Trial or Experiment is @@ -96,3 +97,12 @@ def is_timed_out(self) -> bool: TIMED_OUT. """ return self == Status.TIMED_OUT + + +COMPLETED_STATUSES = { + Status.SUCCEEDED, + Status.CANCELED, + Status.FAILED, + Status.TIMED_OUT, +} +"""The set of completed statuses.""" From 15abbb5d561c1ddfacef9e06479e0cd78330b597 Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Tue, 13 May 2025 14:37:11 -0500 Subject: [PATCH 07/11] more tests and status tweaks --- mlos_bench/mlos_bench/environments/status.py | 6 + .../tests/environments/test_status.py | 257 ++++++++++++++++++ 2 files changed, 263 insertions(+) diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index aff4a25631..7da72e72bd 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -74,6 +74,12 @@ def is_ready(self) -> bool: """ return self == Status.READY + def is_running(self) -> bool: + """Check if the status of the benchmark/environment Trial or Experiment is + RUNNING. + """ + return self == Status.RUNNING + def is_succeeded(self) -> bool: """Check if the status of the benchmark/environment Trial or Experiment is SUCCEEDED. diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py index 234ee6dad5..56d26030fc 100644 --- a/mlos_bench/mlos_bench/tests/environments/test_status.py +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -83,3 +83,260 @@ def test_status_from_str_invalid(invalid_input: Any) -> None: assert ( Status.from_str(invalid_input) == Status.UNKNOWN ), f"Expected Status.UNKNOWN for invalid input: {invalid_input}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, True), + (Status.READY, True), + (Status.RUNNING, True), + (Status.SUCCEEDED, True), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_good(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_good` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_good method. + """ + assert status.is_good() == expected_result, f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, True), + (Status.CANCELED, True), + (Status.FAILED, True), + (Status.TIMED_OUT, True), + ], +) +def test_status_is_completed(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_completed` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_completed method. + """ + assert ( + status.is_completed() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, True), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, False), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_pending(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_pending` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_pending method. + """ + assert ( + status.is_pending() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, True), + (Status.RUNNING, False), + (Status.SUCCEEDED, False), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_ready(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_ready` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_ready method. + """ + assert status.is_ready() == expected_result, f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, True), + (Status.SUCCEEDED, False), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_running(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_running` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_running method. + """ + assert ( + status.is_running() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, True), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_succeeded(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_succeeded` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_succeeded method. + """ + assert ( + status.is_succeeded() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, False), + (Status.CANCELED, True), + (Status.FAILED, False), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_canceled(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_canceled` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_canceled method. + """ + assert ( + status.is_canceled() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, False), + (Status.CANCELED, False), + (Status.FAILED, True), + (Status.TIMED_OUT, False), + ], +) +def test_status_is_failed(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_failed` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_failed method. + """ + assert ( + status.is_failed() == expected_result + ), f"Expected {expected_result} for status: {status}" + + +@pytest.mark.parametrize( + ["status", "expected_result"], + [ + (Status.UNKNOWN, False), + (Status.PENDING, False), + (Status.READY, False), + (Status.RUNNING, False), + (Status.SUCCEEDED, False), + (Status.CANCELED, False), + (Status.FAILED, False), + (Status.TIMED_OUT, True), + ], +) +def test_status_is_timed_out(status: Status, expected_result: bool) -> None: + """ + Test :py:meth:`Status.is_timed_out` for various statuses. + + Parameters + ---------- + status : Status + The Status enum value to test. + expected_result : bool + Expected result of the is_timed_out method. + """ + assert ( + status.is_timed_out() == expected_result + ), f"Expected {expected_result} for status: {status}" From 535ead04e94f7fcff57b947b455ffa5087627c15 Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Mon, 19 May 2025 12:12:47 -0500 Subject: [PATCH 08/11] switch to frozenset --- mlos_bench/mlos_bench/environments/status.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index 7da72e72bd..6cafd6f7bb 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -105,10 +105,12 @@ def is_timed_out(self) -> bool: return self == Status.TIMED_OUT -COMPLETED_STATUSES = { - Status.SUCCEEDED, - Status.CANCELED, - Status.FAILED, - Status.TIMED_OUT, -} +COMPLETED_STATUSES = frozenset( + { + Status.SUCCEEDED, + Status.CANCELED, + Status.FAILED, + Status.TIMED_OUT, + } +) """The set of completed statuses.""" From b370787a4ed7f678d947e8a3e52462c4338ff9dd Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Mon, 19 May 2025 12:13:04 -0500 Subject: [PATCH 09/11] tweak --- mlos_bench/mlos_bench/tests/environments/test_status.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py index 56d26030fc..351643c1f7 100644 --- a/mlos_bench/mlos_bench/tests/environments/test_status.py +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -79,7 +79,10 @@ def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: ], ) def test_status_from_str_invalid(invalid_input: Any) -> None: - """Test :py:meth:`Status.from_str` raises ValueError for invalid input.""" + """ + Test :py:meth:`Status.from_str` returns :py:attr:`Status.UNKNOWN` for + invalid input. + """ assert ( Status.from_str(invalid_input) == Status.UNKNOWN ), f"Expected Status.UNKNOWN for invalid input: {invalid_input}" From 18d41e5f92f45298930197d27bcd4688190aa21c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 17:13:31 +0000 Subject: [PATCH 10/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mlos_bench/mlos_bench/tests/environments/test_status.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py index 351643c1f7..a8dfdd61b8 100644 --- a/mlos_bench/mlos_bench/tests/environments/test_status.py +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -79,9 +79,8 @@ def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: ], ) def test_status_from_str_invalid(invalid_input: Any) -> None: - """ - Test :py:meth:`Status.from_str` returns :py:attr:`Status.UNKNOWN` for - invalid input. + """Test :py:meth:`Status.from_str` returns :py:attr:`Status.UNKNOWN` for invalid + input. """ assert ( Status.from_str(invalid_input) == Status.UNKNOWN From a9f3b08b8c0062108662c8a1712c8c26c9ce9365 Mon Sep 17 00:00:00 2001 From: Brian Kroth Date: Mon, 19 May 2025 12:21:07 -0500 Subject: [PATCH 11/11] type fixups --- mlos_bench/mlos_bench/environments/status.py | 2 +- mlos_bench/mlos_bench/tests/environments/test_status.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mlos_bench/mlos_bench/environments/status.py b/mlos_bench/mlos_bench/environments/status.py index 6cafd6f7bb..6d76d7206c 100644 --- a/mlos_bench/mlos_bench/environments/status.py +++ b/mlos_bench/mlos_bench/environments/status.py @@ -52,7 +52,7 @@ def is_good(self) -> bool: # Class based accessor method to avoid circular import @staticmethod - def completed_statuses() -> set["Status"]: + def completed_statuses() -> frozenset["Status"]: """Get the set of :py:data:`.COMPLETED_STATUSES`.""" return COMPLETED_STATUSES diff --git a/mlos_bench/mlos_bench/tests/environments/test_status.py b/mlos_bench/mlos_bench/tests/environments/test_status.py index a8dfdd61b8..3c0a9bccf3 100644 --- a/mlos_bench/mlos_bench/tests/environments/test_status.py +++ b/mlos_bench/mlos_bench/tests/environments/test_status.py @@ -60,7 +60,7 @@ def test_status_from_str_valid(input_str: str, expected_status: Status) -> None: if input_str.isdigit(): # Also test the numeric representation assert ( - Status.from_str(int(input_str)) == expected_status # type: ignore + Status.from_str(int(input_str)) == expected_status ), f"Expected {expected_status} for input: {int(input_str)}"