diff --git a/docs/docs/building-applications/7-edge.md b/docs/docs/building-applications/7-edge.md index 03f6a21f..873b81d3 100644 --- a/docs/docs/building-applications/7-edge.md +++ b/docs/docs/building-applications/7-edge.md @@ -21,7 +21,7 @@ image queries will not appear in the cloud dashboard. To configure the Groundlight SDK to use the edge endpoint, you can either pass the endpoint URL to the Groundlight constructor like: -```python +```python notest from groundlight import Groundlight gl = Groundlight(endpoint="http://localhost:6717") ``` diff --git a/src/groundlight/cli.py b/src/groundlight/cli.py index 7ea962d5..c15c4035 100644 --- a/src/groundlight/cli.py +++ b/src/groundlight/cli.py @@ -6,7 +6,6 @@ from groundlight import Groundlight from groundlight.client import ApiTokenError -from groundlight.config import API_TOKEN_HELP_MESSAGE cli_app = typer.Typer( no_args_is_help=True, @@ -55,8 +54,8 @@ def groundlight(): cli_func = class_func_to_cli(method) cli_app.command()(cli_func) cli_app() - except ApiTokenError: - print(API_TOKEN_HELP_MESSAGE) + except ApiTokenError as e: + print(e) if __name__ == "__main__": diff --git a/src/groundlight/client.py b/src/groundlight/client.py index 244a4c0d..d7a8fc69 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -10,11 +10,12 @@ from openapi_client import Configuration from openapi_client.api.detectors_api import DetectorsApi from openapi_client.api.image_queries_api import ImageQueriesApi +from openapi_client.exceptions import UnauthorizedException from openapi_client.model.detector_creation_input import DetectorCreationInput from urllib3.exceptions import InsecureRequestWarning from groundlight.binary_labels import Label, convert_display_label_to_internal, convert_internal_label_to_display -from groundlight.config import API_TOKEN_HELP_MESSAGE, API_TOKEN_VARIABLE_NAME, DISABLE_TLS_VARIABLE_NAME +from groundlight.config import API_TOKEN_MISSING_HELP_MESSAGE, API_TOKEN_VARIABLE_NAME, DISABLE_TLS_VARIABLE_NAME from groundlight.encodings import url_encode_dict from groundlight.images import ByteStreamWrapper, parse_supported_image_types from groundlight.internalapi import ( @@ -29,7 +30,11 @@ logger = logging.getLogger("groundlight.sdk") -class ApiTokenError(Exception): +class GroundlightClientError(Exception): + pass + + +class ApiTokenError(GroundlightClientError): pass @@ -102,12 +107,15 @@ def __init__( self.endpoint = sanitize_endpoint_url(endpoint) configuration = Configuration(host=self.endpoint) - if api_token is None: + if not api_token: try: # Retrieve the API token from environment variable api_token = os.environ[API_TOKEN_VARIABLE_NAME] except KeyError as e: - raise ApiTokenError(API_TOKEN_HELP_MESSAGE) from e + raise ApiTokenError(API_TOKEN_MISSING_HELP_MESSAGE) from e + if not api_token: + raise ApiTokenError("No API token found. GROUNDLIGHT_API_TOKEN environment variable is set but blank") + self.api_token_prefix = api_token[:12] should_disable_tls_verification = disable_tls_verification @@ -129,6 +137,29 @@ def __init__( self.api_client = GroundlightApiClient(configuration) self.detectors_api = DetectorsApi(self.api_client) self.image_queries_api = ImageQueriesApi(self.api_client) + self._verify_connectivity() + + def _verify_connectivity(self) -> None: + """ + Verify that the client can connect to the Groundlight service, and raise a helpful + exception if it cannot. + """ + try: + # a simple query to confirm that the endpoint & API token are working + self.list_detectors(page=1, page_size=1) + except UnauthorizedException as e: + msg = ( + f"Invalid API token '{self.api_token_prefix}...' connecting to endpoint " + f"'{self.endpoint}'. Endpoint is responding, but API token is probably invalid." + ) + raise ApiTokenError(msg) from e + except Exception as e: + msg = ( + f"Error connecting to Groundlight using API token '{self.api_token_prefix}...'" + f" at endpoint '{self.endpoint}'. Endpoint might be invalid or unreachable? " + "Check https://status.groundlight.ai/ for service status." + ) + raise GroundlightClientError(msg) from e @staticmethod def _fixup_image_query(iq: ImageQuery) -> ImageQuery: diff --git a/src/groundlight/config.py b/src/groundlight/config.py index a2f8893d..b70d4842 100644 --- a/src/groundlight/config.py +++ b/src/groundlight/config.py @@ -7,7 +7,7 @@ __all__ = ["API_TOKEN_WEB_URL", "API_TOKEN_VARIABLE_NAME", "DEFAULT_ENDPOINT", "DISABLE_TLS_VARIABLE_NAME"] -API_TOKEN_HELP_MESSAGE = ( +API_TOKEN_MISSING_HELP_MESSAGE = ( "No API token found. Please put your token in an environment variable " f'named "{API_TOKEN_VARIABLE_NAME}". If you don\'t have a token, you can ' f"create one at {API_TOKEN_WEB_URL}"