Skip to content

Commit 4e1cec4

Browse files
author
Harry (Roman Hartig)
authored
Merge pull request #636 from gooddata/rha/cq-345/primary-labels
fix(gooddata-pandas): Allow mapping primaryLabelValue in result convertor
2 parents 03a03bf + 5cbf1d0 commit 4e1cec4

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

gooddata-pandas/gooddata_pandas/dataframe.py

+3
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ def for_exec_result_id(
269269
result_size_dimensions_limits: ResultSizeDimensions = (),
270270
result_size_bytes_limit: Optional[int] = None,
271271
use_local_ids_in_headers: bool = False,
272+
use_primary_labels_in_attributes: bool = False,
272273
page_size: int = _DEFAULT_PAGE_SIZE,
273274
) -> Tuple[pandas.DataFrame, DataFrameMetadata]:
274275
"""
@@ -298,6 +299,7 @@ def for_exec_result_id(
298299
result_size_dimensions_limits (ResultSizeDimensions): A tuple containing maximum size of result dimensions.
299300
result_size_bytes_limit (Optional[int]): Maximum size of result in bytes.
300301
use_local_ids_in_headers (bool): Use local identifier in headers.
302+
use_primary_labels_in_attributes (bool): Use primary labels in attributes.
301303
page_size (int): Number of records per page.
302304
303305
Returns:
@@ -322,5 +324,6 @@ def for_exec_result_id(
322324
result_size_dimensions_limits=result_size_dimensions_limits,
323325
result_size_bytes_limit=result_size_bytes_limit,
324326
use_local_ids_in_headers=use_local_ids_in_headers,
327+
use_primary_labels_in_attributes=use_primary_labels_in_attributes,
325328
page_size=page_size,
326329
)

gooddata-pandas/gooddata_pandas/result_convertor.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ def _create_header_mapper(
306306
dim: int,
307307
label_overrides: Optional[LabelOverrides] = None,
308308
use_local_ids_in_headers: bool = False,
309+
use_primary_labels_in_attributes: bool = False,
309310
) -> Callable[[Any, Optional[int]], Optional[str]]:
310311
"""
311312
Prepares a header mapper function which translates header structures into appropriate labels used
@@ -317,6 +318,7 @@ def _create_header_mapper(
317318
label_overrides (Optional[LabelOverrides]): Label overrides. Defaults to None.
318319
use_local_ids_in_headers (bool): Use local identifiers of header attributes and metrics. Optional.
319320
Defaults to False.
321+
use_primary_labels_in_attributes (bool): Use primary labels in attributes. Optional. Defaults to False.
320322
321323
Returns:
322324
Callable[[Any, Optional[int]], Optional[str]]: Mapper function.
@@ -334,7 +336,10 @@ def _mapper(header: Any, header_idx: Optional[int]) -> Optional[str]:
334336
pass
335337
elif "attributeHeader" in header:
336338
if "labelValue" in header["attributeHeader"]:
337-
label = header["attributeHeader"]["labelValue"]
339+
if use_primary_labels_in_attributes:
340+
label = header["attributeHeader"]["primaryLabelValue"]
341+
else:
342+
label = header["attributeHeader"]["labelValue"]
338343
# explicitly handle '(empty value)' if it's None otherwise it's not recognizable in final MultiIndex
339344
# backend represents ^^^ by "" (datasource value is "") or None (datasource value is NULL) therefore
340345
# if both representation are used it's necessary to set label to unique header label (space) to avoid
@@ -376,6 +381,7 @@ def _headers_to_index(
376381
response: BareExecutionResponse,
377382
label_overrides: LabelOverrides,
378383
use_local_ids_in_headers: bool = False,
384+
use_primary_labels_in_attributes: bool = False,
379385
) -> Optional[pandas.Index]:
380386
"""Converts headers to a pandas MultiIndex.
381387
@@ -388,6 +394,8 @@ def _headers_to_index(
388394
response (BareExecutionResponse): The execution response object with all data.
389395
label_overrides (LabelOverrides): A dictionary containing label overrides for the headers.
390396
use_local_ids_in_headers (bool, optional): If True, uses local Ids in headers, otherwise not. Defaults to False.
397+
use_primary_labels_in_attributes (bool, optional): If True, uses primary labels in attributes, otherwise not.
398+
Defaults to False.
391399
392400
Returns:
393401
Optional[pandas.Index]: A pandas MultiIndex object created from the headers, or None if the headers are empty.
@@ -400,6 +408,7 @@ def _headers_to_index(
400408
dim=dim_idx,
401409
label_overrides=label_overrides,
402410
use_local_ids_in_headers=use_local_ids_in_headers,
411+
use_primary_labels_in_attributes=use_primary_labels_in_attributes,
403412
)
404413

405414
return pandas.MultiIndex.from_arrays(
@@ -467,6 +476,7 @@ def convert_execution_response_to_dataframe(
467476
result_size_dimensions_limits: ResultSizeDimensions,
468477
result_size_bytes_limit: Optional[int] = None,
469478
use_local_ids_in_headers: bool = False,
479+
use_primary_labels_in_attributes: bool = False,
470480
page_size: int = _DEFAULT_PAGE_SIZE,
471481
) -> Tuple[pandas.DataFrame, DataFrameMetadata]:
472482
"""
@@ -480,6 +490,8 @@ def convert_execution_response_to_dataframe(
480490
result_size_dimensions_limits (ResultSizeDimensions): Dimension limits for the dataframe.
481491
result_size_bytes_limit (Optional[int], default=None): Size limit in bytes for the dataframe.
482492
use_local_ids_in_headers (bool, default=False): Use local ids in headers if True, else use default settings.
493+
use_primary_labels_in_attributes (bool, default=False): Use primary labels in attributes if True, else use
494+
default settings.
483495
page_size (int, default=_DEFAULT_PAGE_SIZE): Size of the page.
484496
485497
Returns:
@@ -503,13 +515,15 @@ def convert_execution_response_to_dataframe(
503515
response=execution_response,
504516
label_overrides=label_overrides,
505517
use_local_ids_in_headers=use_local_ids_in_headers,
518+
use_primary_labels_in_attributes=use_primary_labels_in_attributes,
506519
),
507520
columns=_headers_to_index(
508521
dim_idx=1,
509522
headers=full_headers,
510523
response=execution_response,
511524
label_overrides=label_overrides,
512525
use_local_ids_in_headers=use_local_ids_in_headers,
526+
use_primary_labels_in_attributes=use_primary_labels_in_attributes,
513527
),
514528
)
515529

gooddata-sdk/gooddata_sdk/catalog/workspace/service.py

+23
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import attrs
1515
from gooddata_api_client.exceptions import NotFoundException
16+
from gooddata_api_client.model.resolve_settings_request import ResolveSettingsRequest
1617

1718
from gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase
1819
from gooddata_sdk.catalog.permission.service import CatalogPermissionService
@@ -188,6 +189,8 @@ def resolve_all_workspace_settings(self, workspace_id: str) -> dict:
188189
:param workspace_id: Workspace ID
189190
:return: Dict of settings
190191
"""
192+
# note: in case some settings were recently added and the API client was not regenerated it can fail on
193+
# invalid value when validating allowed types on the client side before request is sent to the server
191194
resolved_workspace_settings = [
192195
setting.to_dict()
193196
for setting in self._client.actions_api.workspace_resolve_all_settings(
@@ -197,6 +200,26 @@ def resolve_all_workspace_settings(self, workspace_id: str) -> dict:
197200
]
198201
return {setting["type"]: setting for setting in resolved_workspace_settings}
199202

203+
def resolve_workspace_settings(self, workspace_id: str, settings: list) -> dict:
204+
"""
205+
Resolves values for given settings in a workspace by current user, workspace, organization, or default settings
206+
and return them as a dictionary. Proper parsing is up to the caller.
207+
TODO: long-term we should return a proper entity object.
208+
209+
:param workspace_id: Workspace ID
210+
:param settings: List of settings to resolve
211+
:return: Dict of settings
212+
"""
213+
resolved_workspace_settings = [
214+
setting.to_dict()
215+
for setting in self._client.actions_api.workspace_resolve_settings(
216+
workspace_id,
217+
ResolveSettingsRequest(settings=settings),
218+
_check_return_type=False,
219+
)
220+
]
221+
return {setting["type"]: setting for setting in resolved_workspace_settings}
222+
200223
# Declarative methods - workspaces
201224

202225
def get_declarative_workspaces(self, exclude: Optional[List[str]] = None) -> CatalogDeclarativeWorkspaces:

0 commit comments

Comments
 (0)