Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- #[25](https://github.com/braincube-io/python-connector/issues/25): support `{braincube-name}` as a placeholder in `braincube_base_url` configuration.

## [2.4.1 - 2021-04-22](https://github.com/braincube-io/python-connector/compare/2.4.0...2.4.1)

### Fixed
Expand Down
74 changes: 62 additions & 12 deletions braincube_connector/bases/base_entity.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-

from typing import Any, Dict, List
from typing import Any, Dict, List, Optional

from braincube_connector import client, parameters
from braincube_connector import client, parameters, constants
from braincube_connector.bases import base

NAME = "name"
Expand All @@ -12,16 +12,27 @@
class BaseEntity(base.Base):
"""Basics components of an entity requested by the connector."""

def __init__(self, bcid: str, name: str, metadata: Dict[str, Any], path: str = ""):
def __init__(
self,
bcid: str,
name: str,
metadata: Dict[str, Any],
path: str = constants.EMPTY_STRING,
braincube_name: str = constants.EMPTY_STRING,
parent_entity: Optional["BaseEntity"] = None,
Comment thread
adrienhenry marked this conversation as resolved.
):
"""Initialize BaseEntity.

Args:
bcid: Unique identifier of the object in braincube.
name: Usual name of the object.
metadata: Raw metadata associated to the object.
path: Path of the entity on the server.
braincube_name: name of the braincube linked to this entity,
useful if you use a placeholder in your config.
parent_entity: parent of this entity, used to retrieve the braincube name if needed.
"""
self.initialize(bcid, name, metadata, path)
self.initialize(bcid, name, metadata, path, braincube_name, parent_entity)

def __repr__(self) -> str:
"""Produce the a detailed description of the BaseEntity object.
Expand All @@ -33,12 +44,13 @@ def __repr__(self) -> str:
return "<{self_str} at {addr}>".format(self_str=description, addr=hex(id(self)))

@classmethod
def create_from_json(cls, json_data: Dict[str, str], entity_path: str, **kwargs) -> Any:
def create_from_json(cls, json_data: Dict[str, str], entity_path: str, caller, **kwargs) -> Any:
"""Create an entity from a raw json.

Args:
json_data: Json dictionary obtained from a request to the webservice.
entity_path: Path of the entity on the webservice.
caller: class used to call this method, useful to indicate which is the parent entity.
**kwargs: Additional keyword argument to pass to an object initialization.

Returns:
Expand All @@ -51,36 +63,59 @@ def create_from_json(cls, json_data: Dict[str, str], entity_path: str, **kwargs)
json_data[cls.get_parameter_key(NAME)],
json_data,
entity_path,
parent_entity=caller,
**kwargs,
)
return entity

@classmethod
def create_singleton_from_path(cls, request_path: str, entity_path: str, **kwargs) -> Any:
def create_singleton_from_path(
cls,
request_path: str,
entity_path: str,
caller,
braincube_name: str = constants.EMPTY_STRING,
**kwargs,
) -> Any:
"""Create an entity from a request path.

Args:
request_path: Webservice path to request.
entity_path: Path of the entity on the webservice.
caller: class used to call this method, useful to indicate which is the parent entity.
braincube_name: name of the braincube linked to this entity,
useful if you use a placeholder in your config.
**kwargs: Additional keyword argument to pass to an object initialization.

Returns:
The created entity.
"""
json_data = client.request_ws(request_path.format(webservice="braincube"))
return cls.create_from_json(json_data, entity_path, **kwargs)
json_data = client.request_ws(
request_path.format(webservice="braincube"), braincube_name=braincube_name
)
return cls.create_from_json(json_data, entity_path, caller, **kwargs)

@classmethod
def create_collection_from_path(
cls, request_path: str, entity_path: str, page: int = -1, page_size: int = -1, **kwargs,
cls,
request_path: str,
entity_path: str,
caller,
page: int = -1,
page_size: int = -1,
braincube_name: str = constants.EMPTY_STRING,
**kwargs,
) -> List[Any]:
"""Create many memory_base from a request path.

Args:
request_path: Webservice path to request.
entity_path: Path of the entity on the webservice.
caller: class used to call this method, useful to indicate which is the parent entity.
page: Index of page to return, all pages are return if page=-1
page_size: Number of memory_base per page.
braincube_name: name of the braincube linked to this entity,
useful if you use a placeholder in your config.
**kwargs: Additional keyword argument to pass to an object initialization.

Returns:
Expand All @@ -95,10 +130,12 @@ def create_collection_from_path(
json_data = client.request_ws(
"{path}?offset={offset}&size={size}".format(
path=request_path.format(webservice="braincube"), offset=offset, size=page_size,
)
),
braincube_name=braincube_name,
)
new_entities = [
cls.create_from_json(elmt, entity_path, **kwargs) for elmt in json_data["items"]
cls.create_from_json(elmt, entity_path, caller, **kwargs)
for elmt in json_data["items"]
]
entity_list += new_entities
if not new_entities or page > -1:
Expand All @@ -123,21 +160,34 @@ def get_bcid(self) -> str:
"""
return self._bcid

def initialize(self, bcid: str, name: str, metadata: Dict[str, Any], path: str = ""):
def initialize(
self,
bcid: str,
name: str,
metadata: Dict[str, Any],
path: str = constants.EMPTY_STRING,
braincube_name: str = constants.EMPTY_STRING,
parent_entity: Optional["BaseEntity"] = None,
):
"""Initialize BaseEntity.

Args:
bcid: Unique identifier of the object in braincube.
name: Usual name of the object.
metadata: Raw metadata associated to the object.
path: Path of the entity on the server.
braincube_name: name of the braincube linked to this entity,
useful if you use a placeholder in your config.
parent_entity: parent of this entity, used to retrieve the braincube name if needed.
"""
self._bcid = bcid
self._name = name
self._metadata = metadata
if "{bcid}" in path:
path = path.replace("{bcid}", str(self._bcid))
self._path = path
self._braincube_name = braincube_name
self._parent_entity = parent_entity

@classmethod
def get_parameter_key(cls, key) -> str:
Expand Down
34 changes: 30 additions & 4 deletions braincube_connector/bases/resource_getter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,31 @@

from typing import Any, Tuple, Union

from braincube_connector import tools
from braincube_connector import tools, constants


class ResourceGetter(object):
"""Class that handles getting child resources."""

def __init__(self):
"""Initialize ResourceGetter."""
self._path = ""
self._path = constants.EMPTY_STRING
self._braincube_name = constants.EMPTY_STRING
self._parent_entity = None

def get_braincube_name(self):
"""Get an object's braincube name.

Returns:
A braincube name.
"""
if self._braincube_name:
return self._braincube_name

if self._parent_entity:
return self._parent_entity.get_braincube_name()

return constants.EMPTY_STRING

def get_braincube_path(self) -> str:
"""Get an object's parent braincube path.
Expand All @@ -21,7 +37,11 @@ def get_braincube_path(self) -> str:
return (self._path.split("{webservice}"))[0]

def _get_resource(
self, resource_class: Any, bcid: Union[str, int], singleton_path: str = "", **kwargs,
self,
resource_class: Any,
bcid: Union[str, int],
singleton_path: str = constants.EMPTY_STRING,
**kwargs,
):
"""Get a resource from its bcId.

Expand All @@ -40,10 +60,14 @@ def _get_resource(
resource_class.entity_path.replace("{bcid}", str(bcid)),
resource_class.request_one_path if not singleton_path else singleton_path,
),
self,
braincube_name=self.get_braincube_name(),
**kwargs,
)

def _get_resource_list(self, resource_class: Any, collection_path: str = "", **kwargs):
def _get_resource_list(
self, resource_class: Any, collection_path: str = constants.EMPTY_STRING, **kwargs,
):
"""Get a list a of resources from a list of ids.

Args:
Expand All @@ -61,6 +85,8 @@ def _get_resource_list(self, resource_class: Any, collection_path: str = "", **k
resource_class.request_many_path if not collection_path else collection_path,
request_list=True,
),
self,
braincube_name=self.get_braincube_name(),
**kwargs,
)

Expand Down
8 changes: 7 additions & 1 deletion braincube_connector/braincube.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ def __init__(self, product_id: str, name: str, metadata: Dict[str, Any]):
metadata: Raw metadata associated to the Braincube.
"""
self._product_id = product_id
super().__init__(name, name, metadata, "braincube/{bc_name}".format(bc_name=name))

entity_path = "braincube/{bc_name}".format(bc_name=name)
if client.get_instance().has_placeholder_in_braincube_url():
entity_path = ""

super().__init__(name, name, metadata, entity_path)
self._braincube_name = name

def get_memory_base(self, mb_bcid: Union[str, int]) -> memory_base.MemoryBase:
"""Get a MemoryBase object from its id.
Expand Down
30 changes: 23 additions & 7 deletions braincube_connector/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ def __init__(
if instances.get_instance(INSTANCE_KEY) is not None:
raise Exception("A client has already been inialized.")
else:
config_dict = tools.check_config(config_dict=config_dict, config_file=config_file)
self._sso_url = tools.get_sso_base_url(config_dict)
self._braincube_base_url = tools.get_braincube_base_url(config_dict)
self._verify = config_dict.get(constants.VERIFY_CERT, True) # noqa: WPS425
self._authentication = self._build_authentication(config_dict)
self._config_dict = tools.check_config(config_dict=config_dict, config_file=config_file)
self._sso_url = tools.get_sso_base_url(self._config_dict)
self._braincube_base_url = tools.get_braincube_base_url(self._config_dict)
self._verify = self._config_dict.get(constants.VERIFY_CERT, True) # noqa: WPS425
self._authentication = self._build_authentication(self._config_dict)
available_braincube_infos = self._request_braincubes()
self._braincube_infos = available_braincube_infos
self._timeout = timeout
Expand All @@ -54,6 +54,7 @@ def request_ws(
rtype: str = "GET",
api: bool = True,
response_as_json: bool = True,
braincube_name: str = "",
) -> Dict[str, Any]:
"""Make a request at a given path on the client's domain.

Expand All @@ -64,6 +65,8 @@ def request_ws(
rtype: Request type (GET, POST).
api: Requests the API server on the domain.
response_as_json: parse a json output to a python dictionary.
braincube_name: name of the Braincube you want to use to do this request.
Usefull when you have {braincube-name} in your base URL

Returns:
The request's json output or the full response.
Expand All @@ -72,7 +75,7 @@ def request_ws(
if api:
base_url = self._braincube_base_url

url = tools.build_url(base_url, path)
url = tools.build_url(base_url, path, braincube_name)

if not headers:
headers = self._headers
Expand All @@ -92,6 +95,16 @@ def get_braincube_infos(self) -> Dict[str, Any]:
"""
return self._braincube_infos

def has_placeholder_in_braincube_url(self):
"""Indicates whether or not braincube_base_url contains a placeholder.

The placeholder format is given by constants.BRAINCUBE_NAME_PLACEHOLDER.

Returns:
Returns a boolean indicating whether or not braincube_base_url contains a placeholder
"""
return constants.BRAINCUBE_NAME_PLACEHOLDER in self._braincube_base_url

def _request_braincubes(self) -> Dict[str, Any]:
"""Request the accessible braincube to the sso server.

Expand Down Expand Up @@ -168,6 +181,7 @@ def request_ws(
rtype: str = "GET",
api: bool = True,
response_as_json: bool = True,
braincube_name: str = "",
) -> Dict[str, Any]:
"""Make a request at a given path on the client's domain.

Expand All @@ -178,9 +192,11 @@ def request_ws(
rtype: Request type (GET, POST).
api: Requests the API server on the domain.
response_as_json: parse a json output to a python dictionary.
braincube_name: name of the braincube on which is made the request,
useful if you use a placeholder in your config

Returns:
The request's json output or the full response.
"""
cli = get_instance()
return cli.request_ws(path, headers, body_data, rtype, api, response_as_json)
return cli.request_ws(path, headers, body_data, rtype, api, response_as_json, braincube_name)
2 changes: 2 additions & 0 deletions braincube_connector/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
OAUTH2_KEY = "oauth2_token"
SSO_TOKEN_KEY = "IPLSSOTOKEN" # noqa: S105
VERIFY_CERT = "verify"
BRAINCUBE_NAME_PLACEHOLDER = "{braincube-name}"
EMPTY_STRING = ""
24 changes: 0 additions & 24 deletions braincube_connector/memory_base/memory_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,27 +172,3 @@ def get_order_variable_long_id(self) -> str:
if order_id:
return order_id
raise KeyError("The memory base contains neither a reference nor a order key.")

def _get_resource(self, resource_class: Any, bcid: Union[str, int]): # type: ignore
"""Get a resource from its bcId.

Args:
resource_class: Class of the resource to get.
bcid: Event bcid.

Returns:
A resource description.
"""
return super()._get_resource(resource_class, bcid, memory_base=self)

def _get_resource_list(self, resource_class: Any, **kwargs): # type: ignore
"""Get a list a of resources from a list of ids.

Args:
resource_class: Class of the resources to get.
**kwargs: Optional page and page_size or parent (memory_base).

Returns:
A list of resources.
"""
return super()._get_resource_list(resource_class, memory_base=self, **kwargs)
Loading