diff --git a/.forgejo/workflows/forgejo-ci.yaml b/.forgejo/workflows/forgejo-ci.yaml new file mode 100644 index 0000000..491bb6b --- /dev/null +++ b/.forgejo/workflows/forgejo-ci.yaml @@ -0,0 +1,68 @@ +on: [push] + +env: + BUILD_DIR: "." + +jobs: + test: + runs-on: docker + + container: + image: modjular/modjular-python-testing:3.13 + + steps: + - name: Test Echo + run: echo 'Starting up the tests...' + + - name: Check version and distribution + run: | + uname -srm + cat /etc/os-release + + - name: Install pyenv and nodejs + run: | + sudo apt-get update + + sudo apt-get install build-essential git nodejs npm -y + pyenv install 3.10.18 && pyenv local 3.10.18 + pyenv install 3.11.13 && pyenv local 3.11.13 + pyenv install 3.12.10 && pyenv local 3.12.10 + pyenv install 3.13.5 && pyenv local 3.13.5 + + - name: Clone Repository + id: clone + uses: actions/checkout@v4 + with: + ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} + ssh-known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} + + - name: Install requirements + id: install + run: | + pyenv local 3.10.18 + pip install -r requirements-dev.txt + pip install tox + pyenv local 3.11.13 + pip install -r requirements-dev.txt + pip install tox + pyenv local 3.12.10 + pip install -r requirements-dev.txt + pip install tox + pyenv local 3.13.5 + pip install -r requirements-dev.txt + pip install tox + + - name: Run the tests + run: | + pyenv local 3.10.18 3.11.13 3.12.10 3.13.5 + tox -e lint,py310,py311,py312,py313,coverage -p all + + - name: Upload coverage artifacts + uses: https://code.forgejo.org/forgejo/upload-artifact@v4 + with: + name: coverage-reports + path: | + unit_tests_report.xml + unit_tests_report.html + coverage_report.xml + htmlcov diff --git a/src/cleverswarm_python_client/cswarm_benchmark_client.py b/src/cleverswarm_python_client/cswarm_benchmark_client.py index 4e1e668..708d8ef 100644 --- a/src/cleverswarm_python_client/cswarm_benchmark_client.py +++ b/src/cleverswarm_python_client/cswarm_benchmark_client.py @@ -19,6 +19,7 @@ CleverSwarm - text to knowledge graph extraction benchmark client. import argparse import logging +import sys from pathlib import Path from typing import Dict, List, Set @@ -221,6 +222,8 @@ class BenchmarkCLI(object): print("Type: {}".format(job["type"])) print("Status: {}".format(job["status"])) print("Retries: {}".format(job["retries_count"])) + print("Machine ID: {}".format(job["machine_id"])) + print("Worker ID: {}".format(job["worker_id"])) print("Input file type: {}".format((job["file_type"]))) if detailed: print("Unstructured text input files:") @@ -278,6 +281,15 @@ class BenchmarkCLI(object): def main(): """Main entry point for the benchmark client console script.""" + + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) + handler.setFormatter(formatter) + logger.addHandler(handler) + parser = argparse.ArgumentParser( description="CleverSwarm benchmark client for REST API." ) diff --git a/src/cleverswarm_python_client/cswarm_text_to_kg_client.py b/src/cleverswarm_python_client/cswarm_text_to_kg_client.py index 1a4bc9b..184e041 100644 --- a/src/cleverswarm_python_client/cswarm_text_to_kg_client.py +++ b/src/cleverswarm_python_client/cswarm_text_to_kg_client.py @@ -19,6 +19,7 @@ CleverSwarm - unstructured text to knowledge graph triplets extractor client. import argparse import logging +import sys from pathlib import Path from typing import Any, Dict @@ -187,6 +188,8 @@ class TextoToKGCLI(object): print("Type: {}".format(job["type"])) print("Status: {}".format(job["status"])) print("Retries: {}".format(job["retries_count"])) + print("Machine ID: {}".format(job["machine_id"])) + print("Worker ID: {}".format(job["worker_id"])) print("Input file type: {}".format((job["file_type"]))) if is_detailed: print("Unstructured text input files:") @@ -207,6 +210,15 @@ class TextoToKGCLI(object): def main(): """Main entry point for the text-to-KG client console script.""" + + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) + handler.setFormatter(formatter) + logger.addHandler(handler) + parser = argparse.ArgumentParser( description="CleverSwarm unstructured text to Knowledge Graph triplets client for REST API." ) diff --git a/src/cleverswarm_python_client/libs/cleverswarm_client.py b/src/cleverswarm_python_client/libs/cleverswarm_client.py index e874dfa..6fe5d43 100644 --- a/src/cleverswarm_python_client/libs/cleverswarm_client.py +++ b/src/cleverswarm_python_client/libs/cleverswarm_client.py @@ -22,7 +22,7 @@ import os import time from getpass import getpass from pathlib import Path -from typing import Any, Dict, List, Self +from typing import Any, Dict, List import requests @@ -143,7 +143,7 @@ class CleverSwarmClient(object): ) retries += 1 - def update_token(self, query_username: bool = False) -> Self: + def update_token(self, query_username: bool = False) -> "CleverSwarmClient": """ Updates the session authorization token. :return: the BenchmarkClient instance @@ -157,7 +157,6 @@ class CleverSwarmClient(object): if self._username is None or query_username: self._username = input("Please enter your username: ") password = getpass("Please enter your password: ") - # TODO Hash password data = {"username": self._username, "password": password} r = requests.post( diff --git a/src/cleverswarm_python_client/libs/file_type_enum.py b/src/cleverswarm_python_client/libs/file_type_enum.py index e5492ca..dceb433 100644 --- a/src/cleverswarm_python_client/libs/file_type_enum.py +++ b/src/cleverswarm_python_client/libs/file_type_enum.py @@ -1,14 +1,28 @@ -from enum import StrEnum +import sys + +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + + class StrEnum(str, Enum): + def _generate_next_value_(name, start, count, last_values): + return name + + def __str__(self): + return self.value class FileTypeAPI(StrEnum): AutoDetect = "AutoDetect" + PDF = "PDF" Markdown = "Markdown" PlainText = "PlainText" class FileType(StrEnum): JSONL = "JSONL" + PDF = "PDF" Markdown = "Markdown" PlainText = "PlainText" Unknown = "Unknown" diff --git a/src/cleverswarm_python_client/libs/job_enums.py b/src/cleverswarm_python_client/libs/job_enums.py index d183ec2..d841d39 100644 --- a/src/cleverswarm_python_client/libs/job_enums.py +++ b/src/cleverswarm_python_client/libs/job_enums.py @@ -17,7 +17,19 @@ Module that contains the enumerations found when interfacing with Benchmark clie limitations under the License. """ -from enum import StrEnum +import sys + +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + + class StrEnum(str, Enum): + def _generate_next_value_(name, start, count, last_values): + return name + + def __str__(self): + return self.value class JobType(StrEnum): diff --git a/src/cleverswarm_python_client/libs/response_type_enum.py b/src/cleverswarm_python_client/libs/response_type_enum.py index fa52d94..a64556b 100644 --- a/src/cleverswarm_python_client/libs/response_type_enum.py +++ b/src/cleverswarm_python_client/libs/response_type_enum.py @@ -1,4 +1,16 @@ -from enum import StrEnum +import sys + +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + + class StrEnum(str, Enum): + def _generate_next_value_(name, start, count, last_values): + return name + + def __str__(self): + return self.value class ResponseTypeAPI(StrEnum): diff --git a/tests/test_cleverswarm_client.py b/tests/test_cleverswarm_client.py index 61b4081..4913aa1 100644 --- a/tests/test_cleverswarm_client.py +++ b/tests/test_cleverswarm_client.py @@ -111,27 +111,6 @@ class TestCleverSwarmClient: assert client._timeout == 30 assert client._triplets_template == "custom_{}_output.jsonl" - def test_client_file_operations_with_real_files(self): - """Test client file operations with real files.""" - with tempfile.TemporaryDirectory() as temp_dir: - # Create test files - text_file = Path(temp_dir) / "test.txt" - json_file = Path(temp_dir) / "test.json" - owl_file = Path(temp_dir) / "test.owl" - - text_file.write_text("Test content") - json_file.write_text('{"test": "data"}') - owl_file.write_text('test') - - # Test that files exist and can be used - assert text_file.exists() - assert json_file.exists() - assert owl_file.exists() - - # Test that we can create a client and it recognizes the files - client = CleverSwarmClient("http://localhost:8000/api/v0/") - assert client._base_url == "http://localhost:8000/api/v0/" - def test_file_validation_with_missing_files(self): """Test file validation with missing files.""" # Test with non-existent files - this should raise InvalidFileException before calling update_token @@ -157,10 +136,27 @@ class TestCleverSwarmClient: json_file.write_text('{"test": "data"}') jsonl_file.write_text('{"test": "data"}') - # These should not raise exceptions + # Test that files exist and are valid files assert text_file.exists() + assert text_file.is_file() assert json_file.exists() + assert json_file.is_file() assert jsonl_file.exists() + assert jsonl_file.is_file() + + # Test that the client can validate these files by calling create_benchmark_job + # We need to mock the update_token and the HTTP request to avoid actual API calls + with patch.object(self.client, 'update_token'): + with patch.object(self.client, '_generic_http_request_executor') as mock_executor: + # Mock the executor to return the job_id directly + mock_executor.return_value = "test_job_123" + + # This should not raise InvalidFileException + result = self.client.create_benchmark_job( + text_file, json_file, jsonl_file, True + ) + + assert result == "test_job_123" def test_client_state_management(self): """Test client state management.""" @@ -273,6 +269,7 @@ class TestCleverSwarmClient: assert FileTypeAPI.AutoDetect == "AutoDetect" assert FileTypeAPI.Markdown == "Markdown" assert FileTypeAPI.PlainText == "PlainText" + assert FileTypeAPI.PDF == "PDF" def test_response_type_enum_values(self): """Test ResponseTypeAPI enum values.""" @@ -850,4 +847,4 @@ class TestCleverSwarmClientHTTP: raise ValueError("Unexpected error") with pytest.raises(UnexpectedConditionException): - self.client._generic_http_request_executor(test_func) \ No newline at end of file + self.client._generic_http_request_executor(test_func) diff --git a/tests/test_cswarm_benchmark_client.py b/tests/test_cswarm_benchmark_client.py index f6312b2..b829559 100644 --- a/tests/test_cswarm_benchmark_client.py +++ b/tests/test_cswarm_benchmark_client.py @@ -448,13 +448,15 @@ class TestBenchmarkCLIUtilityMethods: "type": "Benchmark", "status": "Completed", "retries_count": 0, - "file_type": "JSONL" + "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001" } ] mock_client.get_jobs_list.return_value = mock_jobs mock_client_class.return_value = mock_client self.cli._client = mock_client - + self.cli.print_server_jobs() captured = capsys.readouterr() @@ -473,6 +475,8 @@ class TestBenchmarkCLIUtilityMethods: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ground_truth_sources": ["gt.jsonl"] @@ -481,7 +485,7 @@ class TestBenchmarkCLIUtilityMethods: mock_client.get_jobs_list.return_value = mock_jobs mock_client_class.return_value = mock_client self.cli._client = mock_client - + self.cli.print_server_jobs(detailed=True) captured = capsys.readouterr() diff --git a/tests/test_cswarm_benchmark_client_extended.py b/tests/test_cswarm_benchmark_client_extended.py index c035bed..a5eb7f3 100644 --- a/tests/test_cswarm_benchmark_client_extended.py +++ b/tests/test_cswarm_benchmark_client_extended.py @@ -60,6 +60,8 @@ class TestBenchmarkCLIExtended: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"], @@ -67,7 +69,7 @@ class TestBenchmarkCLIExtended: "ground_truth_sources": ["test_gt.jsonl"] } ] - + with patch.object(self.cli, 'list_server_jobs') as mock_list: mock_list.return_value = mock_jobs self.cli.print_server_jobs(detailed=True) @@ -82,13 +84,15 @@ class TestBenchmarkCLIExtended: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"], "ground_truth_sources": ["test_gt.jsonl"] } ] - + with patch.object(self.cli, 'list_server_jobs') as mock_list: mock_list.return_value = mock_jobs self.cli.print_server_jobs(detailed=True) diff --git a/tests/test_cswarm_text_to_kg_client.py b/tests/test_cswarm_text_to_kg_client.py index a7b0b1f..94fedbe 100644 --- a/tests/test_cswarm_text_to_kg_client.py +++ b/tests/test_cswarm_text_to_kg_client.py @@ -534,11 +534,13 @@ class TestTextoToKGCLIJobPrinting: "type": "UnstructuredWithOntology", "status": "Completed", "retries_count": 0, - "file_type": "JSONL" + "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001" } ] mock_list_jobs.return_value = mock_jobs - + self.cli.print_server_jobs() captured = capsys.readouterr() @@ -556,13 +558,15 @@ class TestTextoToKGCLIJobPrinting: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"] } ] mock_list_jobs.return_value = mock_jobs - + self.cli.print_server_jobs(is_detailed=True) captured = capsys.readouterr() @@ -582,6 +586,8 @@ class TestTextoToKGCLIJobPrinting: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"], @@ -589,7 +595,7 @@ class TestTextoToKGCLIJobPrinting: } ] mock_list_jobs.return_value = mock_jobs - + self.cli.print_server_jobs(is_detailed=True) captured = capsys.readouterr() diff --git a/tests/test_cswarm_text_to_kg_client_extended.py b/tests/test_cswarm_text_to_kg_client_extended.py index 9c62ee2..6b1bb7b 100644 --- a/tests/test_cswarm_text_to_kg_client_extended.py +++ b/tests/test_cswarm_text_to_kg_client_extended.py @@ -182,13 +182,15 @@ class TestTextoToKGCLIExtended: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"] } ] mock_client.get_jobs_list.return_value = mock_jobs - + with patch('builtins.print') as mock_print: self.cli.print_server_jobs() assert mock_print.call_count > 0 @@ -204,6 +206,8 @@ class TestTextoToKGCLIExtended: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"], @@ -211,7 +215,7 @@ class TestTextoToKGCLIExtended: } ] mock_client.get_jobs_list.return_value = mock_jobs - + with patch('builtins.print') as mock_print: self.cli.print_server_jobs(is_detailed=True) assert mock_print.call_count > 0 @@ -227,13 +231,15 @@ class TestTextoToKGCLIExtended: "status": "Completed", "retries_count": 0, "file_type": "JSONL", + "machine_id": "machine-001", + "worker_id": "worker-001", "unstructured_sources": ["test.txt"], "ontology_sources": ["test.json"], "ontology_spec_sources": ["test.owl"] } ] mock_client.get_jobs_list.return_value = mock_jobs - + with patch('builtins.print') as mock_print: self.cli.print_server_jobs(is_detailed=True) assert mock_print.call_count > 0 diff --git a/tests/test_detailed_eval_extended.py b/tests/test_detailed_eval_extended.py index 5156b3b..faf0ecf 100644 --- a/tests/test_detailed_eval_extended.py +++ b/tests/test_detailed_eval_extended.py @@ -43,7 +43,10 @@ class TestDetailedEvalExtendedSimple: encoder = CustomEncoder() test_set = {1, 2, 3, "test"} result = encoder.default(test_set) - assert result == [1, 2, 3, "test"] + # Convert result back to set for order-independent comparison + assert set(result) == test_set + # Also verify it's a list + assert isinstance(result, list) def test_custom_encoder_with_non_set(self): """Test CustomEncoder with non-set objects.""" diff --git a/tests/test_file_type_enum.py b/tests/test_file_type_enum.py index 9338027..7cc76b1 100644 --- a/tests/test_file_type_enum.py +++ b/tests/test_file_type_enum.py @@ -30,6 +30,7 @@ class TestFileTypeAPI: assert FileTypeAPI.AutoDetect == "AutoDetect" assert FileTypeAPI.Markdown == "Markdown" assert FileTypeAPI.PlainText == "PlainText" + assert FileTypeAPI.PDF == "PDF" def test_enum_membership(self): """Test that FileTypeAPI members can be checked for membership.""" @@ -37,6 +38,7 @@ class TestFileTypeAPI: assert FileTypeAPI.AutoDetect in FileTypeAPI assert FileTypeAPI.Markdown in FileTypeAPI assert FileTypeAPI.PlainText in FileTypeAPI + assert FileTypeAPI.PDF in FileTypeAPI # Test string value membership (Python 3.12+ only) import sys @@ -44,13 +46,14 @@ class TestFileTypeAPI: assert "AutoDetect" in FileTypeAPI assert "Markdown" in FileTypeAPI assert "PlainText" in FileTypeAPI + assert "PDF" in FileTypeAPI assert "InvalidType" not in FileTypeAPI def test_enum_iteration(self): """Test that FileTypeAPI can be iterated over.""" values = list(FileTypeAPI) - expected_values = ["AutoDetect", "Markdown", "PlainText"] - assert len(values) == 3 + expected_values = ["AutoDetect", "Markdown", "PlainText", "PDF"] + assert len(values) == 4 for value in expected_values: assert value in values @@ -59,6 +62,7 @@ class TestFileTypeAPI: assert FileTypeAPI.AutoDetect == "AutoDetect" assert FileTypeAPI.Markdown == "Markdown" assert FileTypeAPI.PlainText == "PlainText" + assert FileTypeAPI.PDF == "PDF" assert FileTypeAPI.AutoDetect != FileTypeAPI.Markdown def test_enum_string_representation(self): @@ -66,6 +70,7 @@ class TestFileTypeAPI: assert str(FileTypeAPI.AutoDetect) == "AutoDetect" assert str(FileTypeAPI.Markdown) == "Markdown" assert str(FileTypeAPI.PlainText) == "PlainText" + assert str(FileTypeAPI.PDF) == "PDF" def test_enum_repr(self): """Test repr representation of FileTypeAPI values.""" @@ -73,18 +78,14 @@ class TestFileTypeAPI: assert "FileTypeAPI.AutoDetect" in repr(FileTypeAPI.AutoDetect) assert "FileTypeAPI.Markdown" in repr(FileTypeAPI.Markdown) assert "FileTypeAPI.PlainText" in repr(FileTypeAPI.PlainText) + assert "FileTypeAPI.PDF" in repr(FileTypeAPI.PDF) def test_enum_inheritance(self): """Test that FileTypeAPI inherits from StrEnum.""" - from enum import StrEnum + # Import StrEnum from the same module where FileTypeAPI is defined + from cleverswarm_python_client.libs.file_type_enum import StrEnum assert issubclass(FileTypeAPI, StrEnum) - def test_enum_equality_with_string(self): - """Test that FileTypeAPI values are equal to their string representations.""" - assert FileTypeAPI.AutoDetect == "AutoDetect" - assert FileTypeAPI.Markdown == "Markdown" - assert FileTypeAPI.PlainText == "PlainText" - def test_enum_case_sensitivity(self): """Test that FileTypeAPI values are case sensitive.""" assert FileTypeAPI.AutoDetect != "autodetect" @@ -100,6 +101,7 @@ class TestFileType: assert FileType.JSONL == "JSONL" assert FileType.Markdown == "Markdown" assert FileType.PlainText == "PlainText" + assert FileType.PDF == "PDF" assert FileType.Unknown == "Unknown" def test_enum_membership(self): @@ -108,6 +110,7 @@ class TestFileType: assert FileType.JSONL in FileType assert FileType.Markdown in FileType assert FileType.PlainText in FileType + assert FileType.PDF in FileType assert FileType.Unknown in FileType # Test string value membership (Python 3.12+ only) @@ -116,14 +119,15 @@ class TestFileType: assert "JSONL" in FileType assert "Markdown" in FileType assert "PlainText" in FileType + assert "PDF" in FileType assert "Unknown" in FileType assert "InvalidType" not in FileType def test_enum_iteration(self): """Test that FileType can be iterated over.""" values = list(FileType) - expected_values = ["JSONL", "Markdown", "PlainText", "Unknown"] - assert len(values) == 4 + expected_values = ["JSONL", "Markdown", "PlainText", "PDF", "Unknown"] + assert len(values) == 5 for value in expected_values: assert value in values @@ -132,6 +136,7 @@ class TestFileType: assert FileType.JSONL == "JSONL" assert FileType.Markdown == "Markdown" assert FileType.PlainText == "PlainText" + assert FileType.PDF == "PDF" assert FileType.Unknown == "Unknown" assert FileType.JSONL != FileType.Markdown @@ -140,6 +145,7 @@ class TestFileType: assert str(FileType.JSONL) == "JSONL" assert str(FileType.Markdown) == "Markdown" assert str(FileType.PlainText) == "PlainText" + assert str(FileType.PDF) == "PDF" assert str(FileType.Unknown) == "Unknown" def test_enum_repr(self): @@ -148,20 +154,15 @@ class TestFileType: assert "FileType.JSONL" in repr(FileType.JSONL) assert "FileType.Markdown" in repr(FileType.Markdown) assert "FileType.PlainText" in repr(FileType.PlainText) + assert "FileType.PDF" in repr(FileType.PDF) assert "FileType.Unknown" in repr(FileType.Unknown) def test_enum_inheritance(self): """Test that FileType inherits from StrEnum.""" - from enum import StrEnum + # Import StrEnum from the same module where FileType is defined + from cleverswarm_python_client.libs.file_type_enum import StrEnum assert issubclass(FileType, StrEnum) - def test_enum_equality_with_string(self): - """Test that FileType values are equal to their string representations.""" - assert FileType.JSONL == "JSONL" - assert FileType.Markdown == "Markdown" - assert FileType.PlainText == "PlainText" - assert FileType.Unknown == "Unknown" - def test_enum_case_sensitivity(self): """Test that FileType values are case sensitive.""" assert FileType.JSONL != "jsonl" diff --git a/tests/test_job_enums.py b/tests/test_job_enums.py index 20f6796..cc6803a 100644 --- a/tests/test_job_enums.py +++ b/tests/test_job_enums.py @@ -76,7 +76,8 @@ class TestJobType: def test_enum_inheritance(self): """Test that JobType inherits from StrEnum.""" - from enum import StrEnum + # Import StrEnum from the same module where JobType is defined + from cleverswarm_python_client.libs.job_enums import StrEnum assert issubclass(JobType, StrEnum) def test_enum_equality_with_string(self): @@ -165,7 +166,8 @@ class TestJobStatus: def test_enum_inheritance(self): """Test that JobStatus inherits from StrEnum.""" - from enum import StrEnum + # Import StrEnum from the same module where JobStatus is defined + from cleverswarm_python_client.libs.job_enums import StrEnum assert issubclass(JobStatus, StrEnum) def test_enum_equality_with_string(self): diff --git a/tests/test_response_type_enum.py b/tests/test_response_type_enum.py index 5592817..a40b417 100644 --- a/tests/test_response_type_enum.py +++ b/tests/test_response_type_enum.py @@ -70,7 +70,8 @@ class TestResponseTypeAPI: def test_enum_inheritance(self): """Test that ResponseTypeAPI inherits from StrEnum.""" - from enum import StrEnum + # Import StrEnum from the same module where ResponseTypeAPI is defined + from cleverswarm_python_client.libs.response_type_enum import StrEnum assert issubclass(ResponseTypeAPI, StrEnum) def test_enum_equality_with_string(self): diff --git a/tox.ini b/tox.ini index 6a1c43f..6e33bc7 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,7 @@ deps = isort>=5.9.1 commands = flake8 --append-config=tox.ini src/cleverswarm_python_client - black -t py311 -t py312 -t py313 --check src/cleverswarm_python_client + black -t py310 -t py311 -t py312 -t py313 --check src/cleverswarm_python_client isort --check-only --profile black src/cleverswarm_python_client [testenv:type] @@ -45,7 +45,7 @@ deps = black>=25.9.0 isort>=5.9.1 commands = - black -t py311 -t py312 -t py313 src/cleverswarm_python_client tests + black -t py310 -t py311 -t py312 -t py313 src/cleverswarm_python_client tests isort --profile black src/cleverswarm_python_client tests [flake8]