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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.2.0
6.3.0
62 changes: 62 additions & 0 deletions exabel_data_sdk/client/api/api_client/grpc/kpi_grpc_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from exabel_data_sdk.client.api.api_client.exabel_api_group import ExabelApiGroup
from exabel_data_sdk.client.api.api_client.grpc.base_grpc_client import BaseGrpcClient
from exabel_data_sdk.client.api.api_client.kpi_api_client import KpiApiClient
from exabel_data_sdk.client.client_config import ClientConfig
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_service_pb2 import (
ListCompanyBaseModelResultsRequest,
ListCompanyBaseModelResultsResponse,
ListCompanyHierarchicalModelResultsRequest,
ListCompanyHierarchicalModelResultsResponse,
ListCompanyKpiMappingResultsRequest,
ListCompanyKpiMappingResultsResponse,
ListCompanyKpiModelResultsRequest,
ListCompanyKpiModelResultsResponse,
ListKpiMappingResultsRequest,
ListKpiMappingResultsResponse,
)
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_service_pb2_grpc import KpiServiceStub


class KpiGrpcClient(KpiApiClient, BaseGrpcClient):
"""
Client which sends KPI requests to the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
super().__init__(config, ExabelApiGroup.ANALYTICS_API)
self.stub = KpiServiceStub(self.channel)

def list_kpi_mapping_results(
self, request: ListKpiMappingResultsRequest
) -> ListKpiMappingResultsResponse:
return self.stub.ListKpiMappingResults(
request, metadata=self.metadata, timeout=self.config.timeout
)

def list_company_base_model_results(
self, request: ListCompanyBaseModelResultsRequest
) -> ListCompanyBaseModelResultsResponse:
return self.stub.ListCompanyBaseModelResults(
request, metadata=self.metadata, timeout=self.config.timeout
)

def list_company_hierarchical_model_results(
self, request: ListCompanyHierarchicalModelResultsRequest
) -> ListCompanyHierarchicalModelResultsResponse:
return self.stub.ListCompanyHierarchicalModelResults(
request, metadata=self.metadata, timeout=self.config.timeout
)

def list_company_kpi_mapping_results(
self, request: ListCompanyKpiMappingResultsRequest
) -> ListCompanyKpiMappingResultsResponse:
return self.stub.ListCompanyKpiMappingResults(
request, metadata=self.metadata, timeout=self.config.timeout
)

def list_company_kpi_model_results(
self, request: ListCompanyKpiModelResultsRequest
) -> ListCompanyKpiModelResultsResponse:
return self.stub.ListCompanyKpiModelResults(
request, metadata=self.metadata, timeout=self.config.timeout
)
50 changes: 50 additions & 0 deletions exabel_data_sdk/client/api/api_client/kpi_api_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from abc import ABC, abstractmethod

from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_service_pb2 import (
ListCompanyBaseModelResultsRequest,
ListCompanyBaseModelResultsResponse,
ListCompanyHierarchicalModelResultsRequest,
ListCompanyHierarchicalModelResultsResponse,
ListCompanyKpiMappingResultsRequest,
ListCompanyKpiMappingResultsResponse,
ListCompanyKpiModelResultsRequest,
ListCompanyKpiModelResultsResponse,
ListKpiMappingResultsRequest,
ListKpiMappingResultsResponse,
)


class KpiApiClient(ABC):
"""
Superclass for clients that sends KPI requests to the Exabel Analytics API.
"""

@abstractmethod
def list_kpi_mapping_results(
self, request: ListKpiMappingResultsRequest
) -> ListKpiMappingResultsResponse:
"""List KPI mapping results for a single KPI mapping collection."""

@abstractmethod
def list_company_base_model_results(
self, request: ListCompanyBaseModelResultsRequest
) -> ListCompanyBaseModelResultsResponse:
"""List base model results for a company."""

@abstractmethod
def list_company_hierarchical_model_results(
self, request: ListCompanyHierarchicalModelResultsRequest
) -> ListCompanyHierarchicalModelResultsResponse:
"""List hierarchical model results for a company."""

@abstractmethod
def list_company_kpi_mapping_results(
self, request: ListCompanyKpiMappingResultsRequest
) -> ListCompanyKpiMappingResultsResponse:
"""List KPI mapping results for a single company KPI."""

@abstractmethod
def list_company_kpi_model_results(
self, request: ListCompanyKpiModelResultsRequest
) -> ListCompanyKpiModelResultsResponse:
"""List model results for a single company KPI."""
28 changes: 28 additions & 0 deletions exabel_data_sdk/client/api/data_classes/company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from dataclasses import dataclass

from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_messages_pb2 import Company as ProtoCompany


@dataclass
class Company:
"""
A company.

Attributes:
name: The resource name of the company.
display_name: The display name of the company.
bloomberg_ticker: The Bloomberg ticker of the company.
"""

name: str
display_name: str
bloomberg_ticker: str

@staticmethod
def from_proto(proto: ProtoCompany) -> "Company":
"""Create a Company from the given protobuf Company."""
return Company(
name=proto.name,
display_name=proto.display_name,
bloomberg_ticker=proto.bloomberg_ticker,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from dataclasses import dataclass
from typing import List, Sequence

from exabel_data_sdk.client.api.data_classes.company import Company
from exabel_data_sdk.client.api.data_classes.kpi import Kpi
from exabel_data_sdk.client.api.data_classes.kpi_mapping_result_data import KpiMappingResultData
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_messages_pb2 import (
CompanyKpiMappingResults as ProtoCompanyKpiMappingResults,
)
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_messages_pb2 import (
SingleCompanyKpiMappingResults as ProtoSingleCompanyKpiMappingResults,
)


@dataclass
class SingleCompanyKpiMappingResults:
"""
KPI mapping results for a single company KPI.

Attributes:
kpi: The KPI.
data: The results.
"""

kpi: Kpi
data: List[KpiMappingResultData]

@staticmethod
def from_proto(proto: ProtoSingleCompanyKpiMappingResults) -> "SingleCompanyKpiMappingResults":
"""
Create a SingleCompanyKpiMappingResults from the given protobuf
SingleCompanyKpiMappingResults.
"""
return SingleCompanyKpiMappingResults(
kpi=Kpi.from_proto(proto.kpi),
data=[KpiMappingResultData.from_proto(d) for d in proto.data],
)


@dataclass
class CompanyKpiMappingResults:
"""
KPI mapping results for a company.

Attributes:
company: The company.
results: The results.
"""

company: Company
results: Sequence[SingleCompanyKpiMappingResults]

@staticmethod
def from_proto(proto: ProtoCompanyKpiMappingResults) -> "CompanyKpiMappingResults":
"""Create a CompanyKpiMappingResults from the given protobuf CompanyKpiMappingResults."""
return CompanyKpiMappingResults(
company=Company.from_proto(proto.entity),
results=[SingleCompanyKpiMappingResults.from_proto(r) for r in proto.kpi_results],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from dataclasses import dataclass

from exabel_data_sdk.client.api.data_classes.kpi import Kpi
from exabel_data_sdk.client.api.data_classes.kpi_model import KpiModel
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_messages_pb2 import (
CompanyKpiModelResult as ProtoCompanyKpiModelResult,
)


@dataclass
class CompanyKpiModelResult:
"""
A company KPI model result.

Attributes:
kpi: The KPI.
model: The KPI model.
accessible_mappings_count: The number of accessible KPI mappings for the current user.
total_mappings_count: The total number of KPI mappings.
models_count: The number of KPI models.
"""

kpi: Kpi
model: KpiModel
accessible_mappings_count: int
total_mappings_count: int
models_count: int

@staticmethod
def from_proto(proto: ProtoCompanyKpiModelResult) -> "CompanyKpiModelResult":
"""Create a CompanyKpiModelResult from the given protobuf CompanyKpiModelResult."""
return CompanyKpiModelResult(
kpi=Kpi.from_proto(proto.kpi),
model=KpiModel.from_proto(proto.model),
accessible_mappings_count=proto.accessible_mappings_count,
total_mappings_count=proto.total_mappings_count,
models_count=proto.models_count,
)
44 changes: 44 additions & 0 deletions exabel_data_sdk/client/api/data_classes/company_kpi_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from dataclasses import dataclass
from typing import Optional, Sequence

from exabel_data_sdk.client.api.data_classes.kpi_mapping_model import KpiMappingModel
from exabel_data_sdk.client.api.data_classes.kpi_model import KpiModel
from exabel_data_sdk.stubs.exabel.api.analytics.v1.kpi_service_pb2 import (
ListCompanyKpiModelResultsResponse,
)


@dataclass
class CompanyKpiModels:
"""
Models for a company KPI.

Attributes:
exabel_model: The Exabel model.
hierarchical_model: The hierarchical model.
custom_models: The custom models.
kpi_mapping_models: The KPI mapping models.
"""

exabel_model: Optional[KpiModel]
hierarchical_model: Optional[KpiModel]
custom_models: Sequence[KpiModel]
kpi_mapping_models: Sequence[KpiMappingModel]

@staticmethod
def from_proto(proto: ListCompanyKpiModelResultsResponse) -> "CompanyKpiModels":
"""Create a CompanyKpiModelResult from the given ListCompanyKpiModelResultsResponse."""
return CompanyKpiModels(
exabel_model=(
KpiModel.from_proto(proto.exabel_model) if proto.HasField("exabel_model") else None
),
hierarchical_model=(
KpiModel.from_proto(proto.hierarchical_model)
if proto.HasField("hierarchical_model")
else None
),
custom_models=[KpiModel.from_proto(model) for model in proto.custom_models],
kpi_mapping_models=[
KpiMappingModel.from_proto(model) for model in proto.kpi_mapping_models
],
)
46 changes: 35 additions & 11 deletions exabel_data_sdk/client/api/data_classes/data_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ class DataSet:
A data set resource in the Data API.

Attributes:
name (str): The resource name of the data set, for example "dataSets/ns.mydata".
display_name (str): The display name of the data set.
description (str): One or more paragraphs of text description.
signals ([str]): Resource names of signals this data set contains.
read_only (bool): Whether this resource is read only.
name (str): The resource name of the data set, for example,
"dataSets/ns.mydata".
display_name (str): The display name of the data set.
description (str): One or more paragraphs of text description.
signals ([str]): Resource names of signals this data set contains.
read_only (bool): Whether this resource is read only.
derived_signals ([str]): Resource names of signals this data set contains.
highlighted_signals ([str]): Resource names of signals this data set contains.
"""

def __init__(
Expand All @@ -22,31 +25,40 @@ def __init__(
description: str = "",
signals: Optional[Sequence[str]] = None,
read_only: bool = False,
derived_signals: Optional[Sequence[str]] = None,
highlighted_signals: Optional[Sequence[str]] = None,
):
"""
Create a data set resource in the Data API.

Args:
name (str): The resource name of the data set, for example "dataSets/ns.mydata".
display_name: The display name of the data set.
description: One or more paragraphs of text description.
signals: Resource names of signals this data set contains.
read_only: Whether this resource is read only.
name (str): The resource name of the data set, for example,
"dataSets/ns.mydata".
display_name: The display name of the data set.
description: One or more paragraphs of text description.
signals: Resource names of signals this data set contains.
read_only: Whether this resource is read only.
derived_signals: Resource names of derived signals for this data set.
highlighted_signals: Resource names of highlighted signals for this data set.
"""
self.name = name
self.display_name = display_name
self.description = description
self.read_only = read_only
self.signals = signals or []
self.derived_signals = derived_signals or []
self.highlighted_signals = highlighted_signals or []

@staticmethod
def from_proto(data_set: ProtoDataSet) -> "DataSet":
"""Create an DataSet from the given protobuf DataSet."""
"""Create a DataSet from the given protobuf DataSet."""
return DataSet(
name=data_set.name,
display_name=data_set.display_name,
description=data_set.description,
signals=list(data_set.signals),
derived_signals=list(data_set.derived_signals),
highlighted_signals=list(data_set.highlighted_signals),
read_only=data_set.read_only,
)

Expand All @@ -57,6 +69,8 @@ def to_proto(self) -> ProtoDataSet:
display_name=self.display_name,
description=self.description,
signals=self.signals if self.signals else None,
derived_signals=self.derived_signals if self.derived_signals else None,
highlighted_signals=self.highlighted_signals if self.highlighted_signals else None,
)

def __eq__(self, other: object) -> bool:
Expand All @@ -68,12 +82,16 @@ def __eq__(self, other: object) -> bool:
and self.description == other.description
and self.read_only == other.read_only
and sorted(self.signals) == sorted(other.signals)
and self.derived_signals == other.derived_signals
and sorted(self.highlighted_signals) == sorted(other.highlighted_signals)
)

def __repr__(self) -> str:
return (
f"DataSet(name='{self.name}', display_name='{self.display_name}', "
f"description='{self.description}', signals={self.signals}, "
f"derived_signals={self.derived_signals}, "
f"highlighted_signals={self.highlighted_signals}, "
f"read_only={self.read_only})"
)

Expand All @@ -91,3 +109,9 @@ def print_data_set(data_set: DataSet) -> None:
print("Signals:")
for signal in sorted(data_set.signals):
print(f"\t{signal}")
print("Derived signals:")
for signal in sorted(data_set.derived_signals):
print(f"\t{signal}")
print("Highlighted signals:")
for signal in sorted(data_set.highlighted_signals):
print(f"\t{signal}")
Loading