diff --git a/gooddata-pandas/gooddata_pandas/data_access.py b/gooddata-pandas/gooddata_pandas/data_access.py index cc509030e..442d00c8d 100644 --- a/gooddata-pandas/gooddata_pandas/data_access.py +++ b/gooddata-pandas/gooddata_pandas/data_access.py @@ -312,12 +312,10 @@ def _extract_for_metrics_only(response: ExecutionResponse, cols: list, col_to_me """ exec_def = response.exec_def result = response.read_result(len(exec_def.metrics)) - data = dict() + if len(result.data) == 0: + return {col: [] for col in cols} - for col in cols: - data[col] = [result.data[col_to_metric_idx[col]]] - - return data + return {col: [result.data[col_to_metric_idx[col]]] for col in cols} def _find_attribute(attributes: list[CatalogAttribute], id_obj: IdObjType) -> Union[CatalogAttribute, None]: diff --git a/gooddata-pandas/tests/dataframe/fixtures/filtered_empty_df.yaml b/gooddata-pandas/tests/dataframe/fixtures/filtered_empty_df.yaml new file mode 100644 index 000000000..9d094074c --- /dev/null +++ b/gooddata-pandas/tests/dataframe/fixtures/filtered_empty_df.yaml @@ -0,0 +1,200 @@ +# (C) 2024 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/actions/workspaces/demo/execution/afm/execute + body: + execution: + attributes: [] + filters: + - relativeDateFilter: + dataset: + identifier: + id: date + type: dataset + from: 1 + granularity: YEAR + to: 2 + measures: + - definition: + measure: + item: + identifier: + id: revenue + type: metric + computeRatio: false + filters: [] + localIdentifier: m_revenue + resultSpec: + dimensions: + - itemIdentifiers: + - measureGroup + localIdentifier: dim_0 + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + content-length: + - '307' + set-cookie: + - SPRING_REDIRECT_URI=; Max-Age=0; Expires=Tue, 08 Oct 2024 13:35:16 GMT; + Path=/; HTTPOnly; SameSite=Lax + body: + string: + executionResponse: + dimensions: + - headers: + - measureGroupHeaders: + - localIdentifier: m_revenue + format: $#,##0 + name: Revenue + localIdentifier: dim_0 + links: + executionResult: a8a633b8ec1bc44a3007020033d582740a2a95b7:6e97188bfff240406a2b583fe6e4065f304eb2250a658fcf497dc142a3377e80 + - request: + method: GET + uri: http://localhost:3000/api/v1/actions/workspaces/demo/execution/afm/execute/result/a8a633b8ec1bc44a3007020033d582740a2a95b7%3A6e97188bfff240406a2b583fe6e4065f304eb2250a658fcf497dc142a3377e80?offset=0&limit=1 + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + content-length: + - '131' + set-cookie: + - SPRING_REDIRECT_URI=; Max-Age=0; Expires=Tue, 08 Oct 2024 13:35:16 GMT; + Path=/; HTTPOnly; SameSite=Lax + body: + string: + data: [] + dimensionHeaders: + - headerGroups: + - headers: [] + grandTotals: [] + paging: + count: + - 0 + offset: + - 0 + total: + - 0 diff --git a/gooddata-pandas/tests/dataframe/test_not_indexed_dataframe.py b/gooddata-pandas/tests/dataframe/test_not_indexed_dataframe.py index 5a67638e5..4ea02d2ae 100644 --- a/gooddata-pandas/tests/dataframe/test_not_indexed_dataframe.py +++ b/gooddata-pandas/tests/dataframe/test_not_indexed_dataframe.py @@ -2,7 +2,7 @@ from pathlib import Path from gooddata_pandas import DataFrameFactory -from gooddata_sdk import PositiveAttributeFilter +from gooddata_sdk import ObjId, PositiveAttributeFilter, RelativeDateFilter, SimpleMetric from tests_support.vcrpy_utils import get_vcr gd_vcr = get_vcr() @@ -75,3 +75,17 @@ def test_empty_not_indexed_dataframe(gdf: DataFrameFactory): assert df.columns[0] == "product_name" assert df.columns[1] == "amount_of_top_customers" assert df.columns[2] == "total_revenue" + + +@gd_vcr.use_cassette(str(_fixtures_dir / "filtered_empty_df.yaml")) +def test_filter_empty_df(gdf: DataFrameFactory): + my_metric = SimpleMetric(local_id="m_revenue", item=ObjId(id="revenue", type="metric")) + my_filter = RelativeDateFilter( + dataset=ObjId(id="date", type="dataset"), + granularity="YEAR", + from_shift=1, + to_shift=2, + ) + df = gdf.not_indexed(columns=dict(my_metric=my_metric), filter_by=[my_filter]) + assert df.empty + assert df.columns[0] == "my_metric"