Skip to content

Commit

Permalink
Add support for using bearer token and release 1.2.0 (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
erlendvollset authored Oct 1, 2019
1 parent 9272f4e commit 7b5bb9a
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 110 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ Changes are grouped as follows
- Concurrent reads for all resource types using `/cursors` endpoints
- Upserts for all resource types
- Separate read/write fields on data classes

## [Unreleased]

## [1.2.0] - 2019-10-01
### Added
- Support for authenticating with bearer tokens. Can now supply a jwt or jwt-factory to CogniteClient. This token will override any api-key which has been set.

## [1.1.12] - 2019-10-01
### Fixed
- Fixed a bug in time series pagination where getting 100k datapoints could cause a missing id error when using include_outside_points.
Expand Down
2 changes: 1 addition & 1 deletion cognite/client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from cognite.client._cognite_client import CogniteClient

__version__ = "1.1.12"
__version__ = "1.2.0"
26 changes: 21 additions & 5 deletions cognite/client/_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import re
from collections import UserList
from http import cookiejar
from typing import Any, Dict, List, Union
from typing import Any, Callable, Dict, List, Optional, Union
from urllib.parse import urljoin

import requests.utils
Expand Down Expand Up @@ -142,7 +142,14 @@ def _do_request(self, method: str, url_path: str, **kwargs):
def _configure_headers(self, additional_headers):
headers = CaseInsensitiveDict()
headers.update(requests.utils.default_headers())
headers["api-key"] = self._config.api_key
if self._config.token is None:
headers["api-key"] = self._config.api_key
elif isinstance(self._config.token, str):
headers["Authentication"] = "Bearer {}".format(self._config.token)
elif isinstance(self._config.token, Callable):
headers["Authentication"] = "Bearer {}".format(self._config.token())
else:
raise TypeError("'token' must be str, Callable, or None.")
headers["content-type"] = "application/json"
headers["accept"] = "application/json"
headers["x-cdp-sdk"] = "CognitePythonSDK:{}".format(utils._auxiliary.get_current_sdk_version())
Expand Down Expand Up @@ -626,7 +633,8 @@ def _raise_API_error(res: Response, payload: Dict):
error_details["missing"] = missing
if duplicated:
error_details["duplicated"] = duplicated

error_details["headers"] = res.request.headers.copy()
APIClient._sanitize_headers(error_details["headers"])
log.debug("HTTP Error %s %s %s: %s", code, res.request.method, res.request.url, msg, extra=error_details)
raise CogniteAPIError(msg, code, x_request_id, missing=missing, duplicated=duplicated, extra=extra)

Expand All @@ -638,15 +646,23 @@ def _log_request(res: Response, **kwargs):

extra = kwargs.copy()
extra["headers"] = res.request.headers.copy()
if "api-key" in extra.get("headers", {}):
extra["headers"]["api-key"] = None
APIClient._sanitize_headers(extra["headers"])
if extra["payload"] is None:
del extra["payload"]

http_protocol_version = ".".join(list(str(res.raw.version)))

log.debug("HTTP/{} {} {} {}".format(http_protocol_version, method, url, status_code), extra=extra)

@staticmethod
def _sanitize_headers(headers: Optional[Dict]):
if headers is None:
return
if "api-key" in headers:
headers["api-key"] = "***"
if "Authentication" in headers:
headers["Authentication"] = "***"

def _apply_model_hosting_emulator_url_filter(self, full_url):
mlh_emul_url = os.getenv("MODEL_HOSTING_EMULATOR_URL")
if mlh_emul_url is not None:
Expand Down
6 changes: 5 additions & 1 deletion cognite/client/_cognite_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import warnings
from typing import Any, Dict
from typing import Any, Callable, Dict, Union

from cognite.client import utils
from cognite.client._api.assets import AssetsAPI
Expand Down Expand Up @@ -30,6 +30,8 @@ class CogniteClient:
max_workers (int): Max number of workers to spawn when parallelizing data fetching. Defaults to 10.
headers (Dict): Additional headers to add to all requests.
timeout (int): Timeout on requests sent to the api. Defaults to 30 seconds.
token (Union[str, Callable[[], str]]): A jwt or method which takes no arguments and returns a jwt to use for authentication.
This will override any api-key set.
debug (bool): Configures logger to log extra request details to stderr.
"""

Expand All @@ -44,6 +46,7 @@ def __init__(
max_workers: int = None,
headers: Dict[str, str] = None,
timeout: int = None,
token: Union[str, Callable[[], str], None] = None,
debug: bool = False,
):
self._config = ClientConfig(
Expand All @@ -54,6 +57,7 @@ def __init__(
max_workers=max_workers,
headers=headers,
timeout=timeout,
token=token,
debug=debug,
)
self.login = LoginAPI(self._config, cognite_client=self)
Expand Down
11 changes: 7 additions & 4 deletions cognite/client/utils/_client_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
import pprint
import sys
import warnings
from typing import *
Expand Down Expand Up @@ -63,6 +64,7 @@ def __init__(
max_workers: int = None,
headers: Dict[str, str] = None,
timeout: int = None,
token: Union[Callable[[], str], str] = None,
debug: bool = False,
):
super().__init__()
Expand All @@ -74,9 +76,10 @@ def __init__(
self.max_workers = max_workers or self.max_workers
self.headers = headers or self.headers
self.timeout = timeout or self.timeout
self.token = token

if self.api_key is None:
raise CogniteAPIKeyError("No API key has been specified")
if self.api_key is None and self.token is None:
raise CogniteAPIKeyError("No API key or token has been specified")

if self.client_name is None:
raise ValueError(
Expand All @@ -95,7 +98,7 @@ def __init__(
pass

def __str__(self):
return json.dumps(self.__dict__, indent=4)
return pprint.pformat(self.__dict__, indent=4)

def __repr__(self):
def _repr_html_(self):
return self.__str__()
Loading

0 comments on commit 7b5bb9a

Please sign in to comment.