diff --git a/src/apihub_client/generic_client.py b/src/apihub_client/generic_client.py index 9e89482..203d4af 100644 --- a/src/apihub_client/generic_client.py +++ b/src/apihub_client/generic_client.py @@ -1,5 +1,6 @@ import logging import time +from urllib.parse import parse_qs, urlparse import requests @@ -32,6 +33,26 @@ def __init__( self.base_url = base_url.rstrip("/") self.headers = {"apikey": self.api_key} + def _extract_execution_id_from_url(self, url: str) -> str | None: + """ + Extract execution_id from a URL's query parameters. + + Args: + url: URL containing execution_id parameter + + Returns: + str | None: The execution_id if found, None otherwise + """ + try: + parsed_url = urlparse(url) + query_params = parse_qs(parsed_url.query) + execution_ids = query_params.get("execution_id") + if execution_ids: + return execution_ids[0] # Get the first value + except Exception as e: + self.logger.warning("Failed to extract execution_id from URL: %s", e) + return None + def process( self, endpoint: str, @@ -76,6 +97,13 @@ def process( data = response.json() execution_id = data.get("execution_id") + + # If execution_id is not directly available, try to extract from status_api + if not execution_id: + status_api = data.get("message", {}).get("status_api") + if status_api: + execution_id = self._extract_execution_id_from_url(status_api) + self.logger.info( "Processing started successfully. Execution ID: %s", execution_id ) @@ -119,7 +147,17 @@ def get_result(self, endpoint: str, execution_id: str) -> dict: ) response = requests.get(url, headers=self.headers, params=params) - if response.status_code != 200: + if response.status_code == 422: + # Handle 422 status which may indicate processing in progress + try: + data = response.json() + if "status" in data: + return data + except (ValueError, KeyError): + # JSON parsing failed or status key missing, treat as error + pass + raise ApiHubClientException(response.text, response.status_code) + elif response.status_code != 200: raise ApiHubClientException(response.text, response.status_code) return response.json() @@ -170,7 +208,7 @@ def wait_for_completion( ), None, ) - elif status in ["PROCESSING", "IN_PROGRESS", "RUNNING"]: + elif status in ["PROCESSING", "IN_PROGRESS", "RUNNING", "EXECUTING"]: # Continue polling pass else: diff --git a/test/test_imports.py b/test/test_imports.py deleted file mode 100644 index 93cc5ee..0000000 --- a/test/test_imports.py +++ /dev/null @@ -1,151 +0,0 @@ -"""Test module imports and package-level functionality.""" - - -class TestPackageImports: - """Test cases for package imports.""" - - def test_main_package_imports(self): - """Test importing main classes from the package.""" - # This should import all main classes and trigger __init__.py coverage - from apihub_client import ( - ApiHubClient, - ApiHubClientException, - DocSplitterClient, - GenericUnstractClient, - ) - - # Verify classes are importable and are actually classes - assert ApiHubClient is not None - assert ApiHubClientException is not None - assert DocSplitterClient is not None - assert GenericUnstractClient is not None - - # Verify they are actually classes/exceptions - assert callable(ApiHubClient) - assert callable(ApiHubClientException) - assert callable(DocSplitterClient) - assert callable(GenericUnstractClient) - - def test_package_metadata(self): - """Test package metadata is accessible.""" - import apihub_client - - # Check metadata attributes exist - assert hasattr(apihub_client, "__version__") - assert hasattr(apihub_client, "__author__") - assert hasattr(apihub_client, "__email__") - assert hasattr(apihub_client, "__all__") - - # Check metadata values - assert apihub_client.__version__ == "0.1.1" - assert apihub_client.__author__ == "Unstract Team" - assert apihub_client.__email__ == "support@unstract.com" - - # Check __all__ contains expected items - expected_all = [ - "ApiHubClient", - "ApiHubClientException", - "DocSplitterClient", - "GenericUnstractClient", - ] - assert apihub_client.__all__ == expected_all - - def test_direct_module_imports(self): - """Test direct module imports work.""" - from apihub_client.client import ApiHubClient, ApiHubClientException - from apihub_client.doc_splitter import DocSplitterClient - from apihub_client.generic_client import GenericUnstractClient - - # Verify classes are importable - assert ApiHubClient is not None - assert ApiHubClientException is not None - assert DocSplitterClient is not None - assert GenericUnstractClient is not None - - def test_client_instantiation(self): - """Test that clients can be instantiated from package imports.""" - from apihub_client import ( - ApiHubClient, - DocSplitterClient, - GenericUnstractClient, - ) - - # Test ApiHubClient instantiation - api_client = ApiHubClient(api_key="test_key", base_url="https://test.com") - assert api_client.api_key == "test_key" - assert api_client.base_url == "https://test.com" - - # Test DocSplitterClient instantiation - doc_client = DocSplitterClient(api_key="test_key", base_url="https://test.com") - assert doc_client.api_key == "test_key" - assert doc_client.base_url == "https://test.com" - - # Test GenericUnstractClient instantiation - generic_client = GenericUnstractClient( - api_key="test_key", base_url="https://test.com" - ) - assert generic_client.api_key == "test_key" - assert generic_client.base_url == "https://test.com" - - def test_exception_instantiation(self): - """Test that exception can be instantiated from package imports.""" - from apihub_client import ApiHubClientException - - # Test exception creation - exc = ApiHubClientException("Test message", 400) - assert exc.message == "Test message" - assert exc.status_code == 400 - - # Test exception string representation - str_repr = str(exc) - assert "Test message" in str_repr - assert "400" in str_repr - - def test_star_import(self): - """Test that star import works correctly.""" - # This imports everything in __all__ - exec("from apihub_client import *") # noqa: S102 - - # Check that the main classes are available in local scope - locals_dict = locals() - assert "ApiHubClient" in locals_dict - assert "ApiHubClientException" in locals_dict - assert "DocSplitterClient" in locals_dict - assert "GenericUnstractClient" in locals_dict - - def test_package_docstring(self): - """Test package docstring is accessible.""" - import apihub_client - - assert apihub_client.__doc__ is not None - assert "Unstract API Hub Python Client" in apihub_client.__doc__ - assert "dynamic, extensible Python client" in apihub_client.__doc__ - - def test_import_order_independence(self): - """Test that imports work regardless of order.""" - # Import in different order - from apihub_client import ( - ApiHubClient, # noqa: F401 - ApiHubClientException, # noqa: F401 - DocSplitterClient, # noqa: F401 - GenericUnstractClient, - ) - - # Should work fine - client = GenericUnstractClient(api_key="test", base_url="https://test.com") - assert client.api_key == "test" - - def test_submodule_access(self): - """Test that submodules are accessible through the package.""" - import apihub_client - - # Should be able to access submodules - assert hasattr(apihub_client, "client") - assert hasattr(apihub_client, "doc_splitter") - assert hasattr(apihub_client, "generic_client") - - # Should be able to access classes through submodules - assert hasattr(apihub_client.client, "ApiHubClient") - assert hasattr(apihub_client.client, "ApiHubClientException") - assert hasattr(apihub_client.doc_splitter, "DocSplitterClient") - assert hasattr(apihub_client.generic_client, "GenericUnstractClient")