def get( self, endpoint: str, team: Optional[str] = None, retry: bool = False, raw: bool = False, debug: bool = False, ): """Get something from the server trough HTTP Parameters ---------- endpoint : str Recipient of the HTTP operation retry : bool Retry to perform the operation. Set to False on recursive calls. raw : bool Flag for returning raw response debug : bool Debugging flag. In this case failed requests get printed Returns ------- dict Dictionary which contains the server response Raises ------ NotFound Resource not found Unauthorized Action is not authorized """ response = requests.get(urljoin(self.url, endpoint), headers=self._get_headers(team)) if response.status_code == 401: raise Unauthorized() if response.status_code == 404: raise NotFound(urljoin(self.url, endpoint)) if response.status_code != 200 and retry: if debug: print( f"Client get request response ({response.json()}) with unexpected status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint})") time.sleep(10) return self.get(endpoint=endpoint, retry=False) if raw: return response else: return self._decode_response(response, debug)
def _raise_if_known_error(self, response: Response, endpoint: str) -> None: if response.status_code == 401: raise Unauthorized() if response.status_code == 404: raise NotFound(urljoin(self.url, endpoint)) if self._has_json_response(response): body = response.json() is_name_taken: Optional[bool] = None if isinstance(body, Dict): is_name_taken = body.get( "errors", {}).get("name") == ["has already been taken"] if response.status_code == 422: if is_name_taken: raise NameTaken raise ValidationError(body) if response.status_code == 429: error_code: Optional[str] = None try: error_code = response.json()["errors"]["code"] except: pass if error_code == "INSUFFICIENT_REMAINING_STORAGE": raise InsufficientStorage()
def _delete( self, endpoint: str, payload: Optional[Dict[Any, Any]] = None, team_slug: Optional[str] = None, retry: bool = False, ) -> Union[Dict[str, Any], List[Dict[str, Any]]]: if payload is None: payload = {} response: requests.Response = requests.delete( urljoin(self.url, endpoint), json=payload, headers=self._get_headers(team_slug)) self.log.debug( f"Client DELETE request response ({self._get_response_debug_text(response)}) with unexpected status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint})") self._raise_if_known_error(response, endpoint) if not response.ok and retry: time.sleep(10) return self._delete(endpoint, payload=payload, retry=False) response.raise_for_status() return self._decode_response(response)
def _put_raw(self, endpoint: str, payload: Dict[str, Any], team_slug: Optional[str] = None, retry: bool = False) -> Response: response: requests.Response = requests.put( urljoin(self.url, endpoint), json=payload, headers=self._get_headers(team_slug)) self.log.debug( f"Client PUT request got response ({self._get_response_debug_text(response)}) with status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint}, payload={payload})") self._raise_if_known_error(response, endpoint) if not response.ok and retry: time.sleep(10) return self._put_raw(endpoint, payload=payload, retry=False) response.raise_for_status() return response
def post( self, endpoint: str, payload: Optional[Dict] = None, team: Optional[str] = None, retry: bool = False, error_handlers: Optional[list] = None, debug: bool = False, ): """Post something new on the server trough HTTP Parameters ---------- endpoint : str Recipient of the HTTP operation payload : dict What you want to put on the server (typically json encoded) retry : bool Retry to perform the operation. Set to False on recursive calls. refresh : bool Flag for use the refresh token instead debug : bool Debugging flag. In this case failed requests get printed Returns ------- dict Dictionary which contains the server response """ if payload is None: payload = {} if error_handlers is None: error_handlers = [] response = requests.post(urljoin(self.url, endpoint), json=payload, headers=self._get_headers(team)) if response.status_code == 401: raise Unauthorized() if response.status_code != 200: for error_handler in error_handlers: error_handler(response.status_code, response.json()) if debug: print( f"Client get request response ({response.json()}) with unexpected status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint}, payload={payload})") if retry: time.sleep(10) return self.post(endpoint, payload=payload, retry=False) return self._decode_response(response, debug)
def put( self, endpoint: str, payload: Dict, team: Optional[str] = None, retry: bool = False, debug: bool = False, ): """Put something on the server trough HTTP Parameters ---------- endpoint : str Recipient of the HTTP operation payload : dict What you want to put on the server (typically json encoded) retry : bool Retry to perform the operation. Set to False on recursive calls. debug : bool Debugging flag. In this case failed requests get printed Returns ------- dict Dictionary which contains the server response """ response = requests.put(urljoin(self.url, endpoint), json=payload, headers=self._get_headers(team)) if response.status_code == 401: raise Unauthorized() if response.status_code == 429: error_code = response.json()["errors"]["code"] if error_code == "INSUFFICIENT_REMAINING_STORAGE": raise InsufficientStorage() if response.status_code != 200 and retry: if debug: print( f"Client get request response ({response.json()}) with unexpected status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint}, payload={payload})") time.sleep(10) return self.put(endpoint, payload=payload, retry=False) return self._decode_response(response, debug)
def from_api_key(cls, api_key: str, datasets_dir: Optional[Path] = None) -> "Client": """ Factory method to create a client given an API key. Parameters ---------- api_key: str API key to use to authenticate the client datasets_dir : Optional[Path] String where the client should be initialized from (aka the root path). Defaults to None. Returns ------- Client The initialized client. """ if not datasets_dir: datasets_dir = Path.home() / ".darwin" / "datasets" headers: Dict[str, str] = { "Content-Type": "application/json", "Authorization": f"ApiKey {api_key}" } api_url: str = Client.default_api_url() response: requests.Response = requests.get(urljoin( api_url, "/users/token_info"), headers=headers) if not response.ok: raise InvalidLogin() data: Dict[str, Any] = response.json() team: str = data["selected_team"]["slug"] config: Config = Config(path=None) config.set_team(team=team, api_key=api_key, datasets_dir=str(datasets_dir)) config.set_global(api_endpoint=api_url, base_url=Client.default_base_url()) return cls(config=config, default_team=team)
def from_api_key(cls, api_key: str, datasets_dir: Optional[Path] = None): """Factory method to create a client given an API key Parameters ---------- api_key: str API key to use to authenticate the client datasets_dir : str String where the client should be initialized from (aka the root path) Returns ------- Client The inited client """ if datasets_dir is None: datasets_dir = Path.home() / ".darwin" / "datasets" headers = { "Content-Type": "application/json", "Authorization": f"ApiKey {api_key}" } api_url = Client.default_api_url() response = requests.get(urljoin(api_url, "/users/token_info"), headers=headers) if response.status_code != 200: raise InvalidLogin() data = response.json() team_id = data["selected_team"]["id"] team = [ team["slug"] for team in data["teams"] if team["id"] == team_id ][0] config = Config(path=None) config.set_team(team=team, api_key=api_key, datasets_dir=str(datasets_dir)) config.set_global(api_endpoint=api_url, base_url=Client.default_base_url()) return cls(config=config, default_team=team)
def _get_raw(self, endpoint: str, team_slug: Optional[str] = None, retry: bool = False) -> Response: response: Response = requests.get(urljoin(self.url, endpoint), headers=self._get_headers(team_slug)) self.log.debug( f"Client GET request response ({self._get_response_debug_text(response)}) with status " f"({response.status_code}). " f"Client: ({self})" f"Request: (endpoint={endpoint})") self._raise_if_known_error(response, endpoint) if not response.ok and retry: time.sleep(10) return self._get_raw(endpoint=endpoint, retry=False) response.raise_for_status() return response
def remote_path(self) -> Path: """Returns an URL specifying the location of the remote dataset""" return Path( urljoin(self.client.base_url, f"/datasets/{self.dataset_id}"))
def workview_url_for_item(self, item): return urljoin( self.client.base_url, f"/workview?dataset={self.dataset_id}&image={item.seq}")
def it_strips_correctly(): assert (urljoin("http://www.darwin.v7labs.com/", "/users/token_info") == "http://www.darwin.v7labs.com/users/token_info")
def it_returns_an_url(): assert urljoin("api", "teams") == "api/teams"