From 18515bde8955cfddcfef9c852ab1861459cdb445 Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:41:18 +0100 Subject: [PATCH 1/6] build(docs): maintenance Add docker image for docs. Remove unnecessary git submodule update. --- Makefile | 1 - docker-compose.yaml | 6 ++++++ docs/Dockerfile | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 docs/Dockerfile diff --git a/Makefile b/Makefile index 408b1f4df..00b11fb2e 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,6 @@ remove-cassettes: .PHONY: new-docs new-docs: - git submodule update --init --recursive --depth 1; \ cd docs; \ npm install; \ hugo server diff --git a/docker-compose.yaml b/docker-compose.yaml index 3b0c04ae2..5b30e2b75 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -41,6 +41,12 @@ services: HEADER_HOST: localhost command: ["python3", "upload_demo_layout.py"] + docs: + build: + context: . + dockerfile: docs/Dockerfile + ports: + - "1313:1313" volumes: gooddata-cn-ce-data: diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 000000000..3899eef5d --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,14 @@ +FROM node:20.11.1-bookworm-slim + +RUN npm install -g hugo-extended@0.117.0 + +COPY docs docs + +RUN apt-get update && \ + apt-get install -y git make golang-go curl + +WORKDIR docs +RUN npm install + +# accessible on http://localhost:1313/docs/ +ENTRYPOINT ["hugo", "server", "--bind", "0.0.0.0"] From 5197a4238c993f3f9e73936beafbf37da8887ea6 Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:43:12 +0100 Subject: [PATCH 2/6] feat(docs): replace "insight" in docs JIRA: PSDK-172 --- docs/content/en/docs/_index.md | 15 ++++---- .../en/docs/execution/exports/_index.md | 8 ++--- ... => export_tabular_by_visualization_id.md} | 18 +++++----- docs/content/en/docs/pandas-overview.md | 4 +-- .../workspace-content/_index.md | 4 +-- .../{for_insight.md => for_visualization.md} | 18 +++++----- .../workspace-content/get_insight.md | 35 ------------------- .../workspace-content/get_insights.md | 29 --------------- .../workspace-content/get_visualization.md | 35 +++++++++++++++++++ .../workspace-content/get_visualizations.md | 29 +++++++++++++++ 10 files changed, 99 insertions(+), 96 deletions(-) rename docs/content/en/docs/execution/exports/{export_tabular_by_insight_id.md => export_tabular_by_visualization_id.md} (79%) rename docs/content/en/docs/workspace-content/workspace-content/{for_insight.md => for_visualization.md} (59%) delete mode 100644 docs/content/en/docs/workspace-content/workspace-content/get_insight.md delete mode 100644 docs/content/en/docs/workspace-content/workspace-content/get_insights.md create mode 100644 docs/content/en/docs/workspace-content/workspace-content/get_visualization.md create mode 100644 docs/content/en/docs/workspace-content/workspace-content/get_visualizations.md diff --git a/docs/content/en/docs/_index.md b/docs/content/en/docs/_index.md index ac64edba1..0ee5beb52 100644 --- a/docs/content/en/docs/_index.md +++ b/docs/content/en/docs/_index.md @@ -52,25 +52,28 @@ Integrate GoodData analytics into your continuous delivery practices by, for exa ```python # Reads visualizations from workspace -insights = sdk.insights.get_insights("123") +visualizations = sdk.visualizations.get_visualizations("123") # Iterate through visualizations and check if they are valid -for insight in insights: +for visualization in visualizations: try: - sdk.tables.for_insight("123", insight) + sdk.visualizations.for_visualization("123", visualization) except Exception: - print(f"Visualization {insight.title} is broken.") + print(f"Visualization {visualization.title} is broken.") ``` #### Create data pipelines -Export your data, levarage services like machine learning to transform your data and import the data back into GoodData to visualize the results and gain insights. In the Example below, we demonstrate GoodPandas, which can leverage machine learning practices. +Export your data, +levarage services like machine learning to transform your data +and import the data back into GoodData to visualize the results and gain visualizations. +In the Example below, we demonstrate GoodPandas, which can leverage machine learning practices. ```python pandas = GoodPandas(os.getenv('HOST'), os.getenv('TOKEN')) df = pandas.data_frames(workspace_id="123") -campaign_spend = df.for_insight("campaign_spend") +campaign_spend = df.for_visualization("campaign_spend") # Now you have a dataframe with data from your visualization # You can do linear regression, clustering, predictions, analysis, etc. diff --git a/docs/content/en/docs/execution/exports/_index.md b/docs/content/en/docs/execution/exports/_index.md index d8b1701a6..5c7ad8607 100644 --- a/docs/content/en/docs/execution/exports/_index.md +++ b/docs/content/en/docs/execution/exports/_index.md @@ -11,7 +11,7 @@ Create dashboard exports or automate your pipelines. Can be for [example](#examp * [export_pdf](./export_pdf/) * [export_tabular](./export_tabular/) -* [export_tabular_by_insight_id](./export_tabular_by_insight_id/) +* [export_tabular_by_visualization_id](./export_tabular_by_visualization_id/) ## Example @@ -58,10 +58,10 @@ def send_mail(send_from, send_to, subject, text, files, server): def export_tabular(): - # Export a particular insight in the desired format (CSV / XLSX) - sdk.export.export_tabular_by_insight_id( + # Export a particular visualization in the desired format (CSV / XLSX) + sdk.export.export_tabular_by_visualization_id( workspace_id = "demo", - insight_id = "revenue", + visualization_id = "revenue", file_format = "CSV", file_name = "revenue_export.csv" ) diff --git a/docs/content/en/docs/execution/exports/export_tabular_by_insight_id.md b/docs/content/en/docs/execution/exports/export_tabular_by_visualization_id.md similarity index 79% rename from docs/content/en/docs/execution/exports/export_tabular_by_insight_id.md rename to docs/content/en/docs/execution/exports/export_tabular_by_visualization_id.md index 26929fcef..3d849983a 100644 --- a/docs/content/en/docs/execution/exports/export_tabular_by_insight_id.md +++ b/docs/content/en/docs/execution/exports/export_tabular_by_visualization_id.md @@ -1,13 +1,13 @@ --- -title: "export_tabular_by_insight_id" -linkTitle: "export_tabular_by_insight_id" +title: "export_tabular_by_visualization_id" +linkTitle: "export_tabular_by_visualization_id" weight: 110 superheading: "export." --- -``export_tabular_by_insight_id( +``export_tabular_by_visualization_id( workspace_id: str, - insight_id: str, + visualization_id: str, file_format: str, file_name: Optional[str] = None, settings: Optional[ExportSettings] = None, @@ -17,7 +17,7 @@ superheading: "export." max_retry: float = 5.0, )`` - Exports the tabular data for an Insight by its ID. + Exports the tabular data for an visualization by its ID. @@ -25,8 +25,8 @@ superheading: "export." {{< parameter p_name="workspace_id" p_type="string" >}} The ID of the GoodData Workspace. {{< /parameter >}} -{{< parameter p_name="insight_id" p_type="string" >}} -The ID of the GoodData Insight. +{{< parameter p_name="visualization_id" p_type="string" >}} +The ID of the GoodData visualization. {{< /parameter >}} {{< parameter p_name="file_format" p_type="string" >}} The format of the file to be exported. @@ -63,7 +63,7 @@ host = "https://www.example.com" token = "" sdk = GoodDataSdk.create(host, token) -sdk.export.export_tabular_by_insight_id( - workspace_id="demo", insight_id="campaign_spend", file_format="CSV") +sdk.export.export_tabular_by_visualization_id( + workspace_id="demo", visualization_id="campaign_spend", file_format="CSV") ``` diff --git a/docs/content/en/docs/pandas-overview.md b/docs/content/en/docs/pandas-overview.md index 605ee353d..ca09e8eaa 100644 --- a/docs/content/en/docs/pandas-overview.md +++ b/docs/content/en/docs/pandas-overview.md @@ -92,9 +92,9 @@ non_indexed_df = frames.not_indexed( ) ) -# create data frame based on the contents of the insight. if the insight contains labels and +# create data frame based on the contents of the visualization. if the visualization contains labels and # measures, the data frame will contain index or hierarchical index. -insight_df = frames.for_insight('insight_id') +df = frames.for_visualization('visualization_id') # create data frame based on the content of the items dict. if the dict contains both labels # and measures, the frame will contain index or hierarchical index. diff --git a/docs/content/en/docs/workspace-content/workspace-content/_index.md b/docs/content/en/docs/workspace-content/workspace-content/_index.md index 981a79323..8890d8f08 100644 --- a/docs/content/en/docs/workspace-content/workspace-content/_index.md +++ b/docs/content/en/docs/workspace-content/workspace-content/_index.md @@ -19,7 +19,7 @@ Within a multitenant workspace hierarchy, the analytical model of a parent works ### Entity methods * [get_full_catalog](./get_full_catalog/) -* [get_insights](./get_insights/) +* [get_visualizations](./get_visualizations/) * [get_metrics_catalog](./get_metrics_catalog/) * [get_facts_catalog](./get_facts_catalog/) * [get_attributes_catalog](./get_attributes_catalog/) @@ -32,7 +32,7 @@ Within a multitenant workspace hierarchy, the analytical model of a parent works ### Table methods -* [for_insight](./for_insight/) +* [for_visualization](./for_visualization/) * [for_items](./for_items/) ## Example diff --git a/docs/content/en/docs/workspace-content/workspace-content/for_insight.md b/docs/content/en/docs/workspace-content/workspace-content/for_visualization.md similarity index 59% rename from docs/content/en/docs/workspace-content/workspace-content/for_insight.md rename to docs/content/en/docs/workspace-content/workspace-content/for_visualization.md index 7ebc87886..9fc68ab92 100644 --- a/docs/content/en/docs/workspace-content/workspace-content/for_insight.md +++ b/docs/content/en/docs/workspace-content/workspace-content/for_visualization.md @@ -1,22 +1,22 @@ --- -title: "for_insight" -linkTitle: "for_insight" +title: "for_visualization" +linkTitle: "for_visualization" weight: 10 superheading: "tables." --- -``for_insight(workspace_id: str, insight: Insight)`` +``for_visualization(workspace_id: str, visualization: Visualization)`` -Gets data as an ExecutionTable from the given visualization. +Get data as an ExecutionTable from the given visualization. -{{% parameters-block title="Parameters" %}} +{{% parameters-block title="Parameters" %}} {{< parameter p_name="workspace_id" p_type="string" >}} Workspace identification string e.g. "demo" {{< /parameter >}} -{{< parameter p_name="insight" p_type="Insight" >}} -Insight object, representing a visualization. +{{< parameter p_name="visualization" p_type="Visualization" >}} +Visualization object, representing a visualization. {{< /parameter >}} {{% /parameters-block %}} @@ -30,9 +30,9 @@ Visualization data wrapper object. ```python # Get visualization -campaign_spend_insight = sdk.insights.get_insight(workspace_id="123", insight_id="campaign_spend") +campaign_spend = sdk.visualizations.get_visualization(workspace_id="123", visualization_id="campaign_spend") # Get the visualization as Execution Table -sdk.tables.for_insight(workspace_id="123", insight=campaign_spend_insight) +sdk.tables.for_visualization(workspace_id="123", visualization=campaign_spend) # ExecutionTable( # response=Execution( diff --git a/docs/content/en/docs/workspace-content/workspace-content/get_insight.md b/docs/content/en/docs/workspace-content/workspace-content/get_insight.md deleted file mode 100644 index 827270977..000000000 --- a/docs/content/en/docs/workspace-content/workspace-content/get_insight.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: "get_insight" -linkTitle: "get_insight" -weight: 15 -superheading: "insights." ---- - - - -``get_insight(workspace_id: str, insight_id: str)`` - -Gets a single visualization from a workspace. - - -{{% parameters-block title="Parameters" %}} -{{< parameter p_name="workspace_id" p_type="string" >}} -Workspace identification string e.g. "demo" -{{< /parameter >}} -{{< parameter p_name="insight_id" p_type="string" >}} -Insight identifier string e.g. "bikes" -{{< /parameter >}} -{{% /parameters-block %}} - -{{% parameters-block title="Returns"%}} -{{< parameter p_type="Insight" >}} -A single Insight object contains side loaded metadata about the entities it references -{{< /parameter >}} -{{% /parameters-block %}} - -## Example - -```python -# Get all visualizations -insights = sdk.insights.get_insights(workspace_id="123") -``` diff --git a/docs/content/en/docs/workspace-content/workspace-content/get_insights.md b/docs/content/en/docs/workspace-content/workspace-content/get_insights.md deleted file mode 100644 index cc15dad32..000000000 --- a/docs/content/en/docs/workspace-content/workspace-content/get_insights.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: "get_insights" -linkTitle: "get_insights" -weight: 15 -superheading: "insights." ---- - -``get_insights(workspace_id: str)`` - -Gets a list of visualization objects. - -{{% parameters-block title="Parameters" %}} -{{< parameter p_name="workspace_id" p_type="string" >}} -Workspace identification string e.g. "demo" -{{< /parameter >}} -{{% /parameters-block %}} - -{{% parameters-block title="Returns"%}} -{{< parameter p_type="list[Insight]" >}} -All available insights, each insight will contain side loaded metadata about the entities it references -{{< /parameter >}} -{{% /parameters-block %}} - -## Example - -```python -# Get all visualizations -insights = sdk.insights.get_insights(workspace_id="123") -``` diff --git a/docs/content/en/docs/workspace-content/workspace-content/get_visualization.md b/docs/content/en/docs/workspace-content/workspace-content/get_visualization.md new file mode 100644 index 000000000..b19c40829 --- /dev/null +++ b/docs/content/en/docs/workspace-content/workspace-content/get_visualization.md @@ -0,0 +1,35 @@ +--- +title: "get_visualization" +linkTitle: "get_visualization" +weight: 15 +superheading: "visualizations." +--- + + + +``get_visualization(workspace_id: str, visualization_id: str)`` + +Get a single visualization from a workspace. + + +{{% parameters-block title="Parameters" %}} +{{< parameter p_name="workspace_id" p_type="string" >}} +Workspace identification string e.g. "demo" +{{< /parameter >}} +{{< parameter p_name="visualization_id" p_type="string" >}} +Visualization identifier string e.g. "bikes" +{{< /parameter >}} +{{% /parameters-block %}} + +{{% parameters-block title="Returns"%}} +{{< parameter p_type="Visualization" >}} +A single Visualization object contains side loaded metadata about the entities it references +{{< /parameter >}} +{{% /parameters-block %}} + +## Example + +```python +# Get all visualizations +visualizations = sdk.visualizations.get_visualizations(workspace_id="123") +``` diff --git a/docs/content/en/docs/workspace-content/workspace-content/get_visualizations.md b/docs/content/en/docs/workspace-content/workspace-content/get_visualizations.md new file mode 100644 index 000000000..6ee8f4921 --- /dev/null +++ b/docs/content/en/docs/workspace-content/workspace-content/get_visualizations.md @@ -0,0 +1,29 @@ +--- +title: "get_visualizations" +linkTitle: "get_visualizations" +weight: 15 +superheading: "visualizations." +--- + +``get_visualizations(workspace_id: str)`` + +Get a list of visualization objects. + +{{% parameters-block title="Parameters" %}} +{{< parameter p_name="workspace_id" p_type="string" >}} +Workspace identification string e.g. "demo" +{{< /parameter >}} +{{% /parameters-block %}} + +{{% parameters-block title="Returns"%}} +{{< parameter p_type="list[Visualization]" >}} +All available visualizations, each visualization will contain side loaded metadata about the entities it references +{{< /parameter >}} +{{% /parameters-block %}} + +## Example + +```python +# Get all visualizations +visualizations = sdk.visualizations.get_visualizations(workspace_id="123") +``` From 354d2f33017aac001df900ece4c48d198e086300 Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:43:38 +0100 Subject: [PATCH 3/6] feat(gooddata-dbt): replace "insight" in gooddata-dbt JIRA: PSDK-172 --- gooddata-dbt/README.md | 4 +- gooddata-dbt/gooddata_dbt/args.py | 6 +- gooddata-dbt/gooddata_dbt/dbt_plugin.py | 66 +++++++++++-------- .../gooddata_dbt/gooddata/api_wrapper.py | 12 ++-- gooddata-dbt/gooddata_dbt/gooddata/config.py | 2 +- gooddata-dbt/gooddata_dbt/sdk_wrapper.py | 8 +-- gooddata-dbt/gooddata_example.yml | 4 +- gooddata-dbt/tests/gooddata_example.yml | 8 +-- 8 files changed, 59 insertions(+), 51 deletions(-) diff --git a/gooddata-dbt/README.md b/gooddata-dbt/README.md index e673d2c1b..eb4f199ff 100644 --- a/gooddata-dbt/README.md +++ b/gooddata-dbt/README.md @@ -56,8 +56,8 @@ The plugin provides the following use cases: - Reads content of `gooddata_layout` folder and deploys analytics model to GoodData - store_analytics - Reads analytics model from GoodData instance and stores it to disk to `gooddata_layout` folder -- test_insights - - Lists all insights(reports) from GoodData instance, and executes each report to validate it +- test_visualizations + - Lists all visualizations execution from GoodData instance, and executes each report to validate it - dbt_cloud - Runs dbt cloud job through their API. Alternative to running dbt-core locally. - If running in CI pipeline, it can also notify about performance degradations in a form of GitHub/Gitlab comment. diff --git a/gooddata-dbt/gooddata_dbt/args.py b/gooddata-dbt/gooddata_dbt/args.py index dab15e29b..596543687 100644 --- a/gooddata-dbt/gooddata_dbt/args.py +++ b/gooddata-dbt/gooddata_dbt/args.py @@ -190,8 +190,8 @@ def parse_arguments(description: str) -> argparse.Namespace: set_gooddata_upper_case_args(store_analytics) store_analytics.set_defaults(method="store_analytics") - test_insights = subparsers.add_parser("test_insights") - set_environment_id_arg(test_insights) - test_insights.set_defaults(method="test_insights") + test_visualizations = subparsers.add_parser("test_visualizations") + set_environment_id_arg(test_visualizations) + test_visualizations.set_defaults(method="test_visualizations") return parser.parse_args() diff --git a/gooddata-dbt/gooddata_dbt/dbt_plugin.py b/gooddata-dbt/gooddata_dbt/dbt_plugin.py index 5e5fb05ba..83800846f 100644 --- a/gooddata-dbt/gooddata_dbt/dbt_plugin.py +++ b/gooddata-dbt/gooddata_dbt/dbt_plugin.py @@ -19,7 +19,7 @@ from gooddata_dbt.sdk_wrapper import GoodDataSdkWrapper from gooddata_dbt.utils import get_duration, report_message_to_git_vendor -from gooddata_sdk import CatalogDeclarativeModel, CatalogScanModelRequest, CatalogWorkspace, GoodDataSdk, Insight +from gooddata_sdk import CatalogDeclarativeModel, CatalogScanModelRequest, CatalogWorkspace, GoodDataSdk, Visualization # TODO - upgrade AIO, cleanup, start from scratch, test everything @@ -135,69 +135,77 @@ def store_analytics( ) -async def execute_insight(sdk_wrapper: GoodDataSdkWrapper, workspace_id: str, insight: Insight) -> None: - sdk_wrapper.sdk_facade.execute_insight(workspace_id, insight) +async def execute_visualization( + sdk_wrapper: GoodDataSdkWrapper, workspace_id: str, visualization: Visualization +) -> None: + sdk_wrapper.sdk_facade.execute_visualization(workspace_id, visualization) -async def test_insight( +async def test_visualization( logger: logging.Logger, sdk_wrapper: GoodDataSdkWrapper, workspace_id: str, - insight: Insight, + visualization: Visualization, ) -> dict: - logger.info(f"Executing insight {insight.id=} {insight.title=} ...") + logger.info(f"Executing visualization {visualization.id=} {visualization.title=} ...") start = time() try: - await execute_insight(sdk_wrapper, workspace_id, insight) + await execute_visualization(sdk_wrapper, workspace_id, visualization) duration = get_duration(start) - logger.info(f"Test successful {insight.id=} {insight.title=} duration={duration}(ms)") - return {"id": insight.id, "title": insight.title, "duration": duration, "status": "success"} + logger.info(f"Test successful {visualization.id=} {visualization.title=} duration={duration}(ms)") + return {"id": visualization.id, "title": visualization.title, "duration": duration, "status": "success"} except Exception as e: duration = get_duration(start) - logger.error(f"Test failed {insight.id=} {insight.title=} duration={duration}(ms) reason={str(e)}") - return {"id": insight.id, "title": insight.title, "duration": duration, "status": "failed", "reason": str(e)} + logger.error(f"Test failed {visualization.id=} {visualization.title=} duration={duration}(ms) reason={str(e)}") + return { + "id": visualization.id, + "title": visualization.title, + "duration": duration, + "status": "failed", + "reason": str(e), + } -async def safe_test_insight( +async def safe_test_visualization( logger: logging.Logger, sdk_wrapper: GoodDataSdkWrapper, workspace_id: str, - insight: Insight, + visualization: Visualization, semaphore: Semaphore, ) -> dict: async with semaphore: # semaphore limits num of simultaneous executions - return await test_insight( + return await test_visualization( logger, sdk_wrapper, workspace_id, - insight, + visualization, ) -async def test_insights( +async def test_visualizations( logger: logging.Logger, sdk_wrapper: GoodDataSdkWrapper, workspace_id: str, skip_tests: Optional[List[str]], - test_insights_parallelism: int = 1, + test_visualizations_parallelism: int = 1, ) -> None: start = time() - logger.info(f"Test insights {workspace_id=}") - insights = sdk_wrapper.sdk_facade.get_insights(workspace_id) - semaphore = asyncio.Semaphore(test_insights_parallelism) + logger.info(f"Test visualizations {workspace_id=}") + visualizations = sdk_wrapper.sdk_facade.get_visualizations(workspace_id) + semaphore = asyncio.Semaphore(test_visualizations_parallelism) tasks = [] - for insight in insights: - if skip_tests is not None and insight.id in skip_tests: - logger.info(f"Skip test insight={insight.title} (requested in gooddata.yaml)") + for visualization in visualizations: + if skip_tests is not None and visualization.id in skip_tests: + logger.info(f"Skip test visualization={visualization.title} (requested in gooddata.yaml)") else: - tasks.append(safe_test_insight(logger, sdk_wrapper, workspace_id, insight, semaphore)) + tasks.append(safe_test_visualization(logger, sdk_wrapper, workspace_id, visualization, semaphore)) results = await asyncio.gather(*tasks) duration = get_duration(start) errors = [result for result in results if result["status"] == "failed"] if len(errors) > 0: - raise Exception(f"Test insights failed {workspace_id=} {duration=}(ms) {errors=}") + raise Exception(f"Test visualizations failed {workspace_id=} {duration=}(ms) {errors=}") else: - logger.info(f"Test insights finished {workspace_id=} {duration=}(ms)") + logger.info(f"Test visualizations finished {workspace_id=} {duration=}(ms)") def create_localized_workspaces( @@ -359,10 +367,10 @@ def process_organization( deploy_analytics(logger, sdk_wrapper, workspace_id, data_product) if data_product.localization: create_localized_workspaces(logger, data_product, sdk_wrapper.sdk_facade, workspace_id) - elif args.method == "test_insights": - parallelism = gd_config.global_properties.test_insights_parallelism or 1 + elif args.method == "test_visualizations": + parallelism = gd_config.global_properties.test_visualizations_parallelism or 1 asyncio.run( - test_insights(logger, sdk_wrapper, workspace_id, data_product.skip_tests, parallelism) + test_visualizations(logger, sdk_wrapper, workspace_id, data_product.skip_tests, parallelism) ) else: raise Exception(f"Unsupported method requested in args: {args.method}") diff --git a/gooddata-dbt/gooddata_dbt/gooddata/api_wrapper.py b/gooddata-dbt/gooddata_dbt/gooddata/api_wrapper.py index 526c35aee..78ea74c60 100644 --- a/gooddata-dbt/gooddata_dbt/gooddata/api_wrapper.py +++ b/gooddata-dbt/gooddata_dbt/gooddata/api_wrapper.py @@ -17,7 +17,7 @@ CatalogScanModelRequest, CatalogWorkspace, GoodDataSdk, - Insight, + Visualization, ) DataSource = Union[CatalogDataSourcePostgres, CatalogDataSourceSnowflake, CatalogDataSourceVertica] @@ -29,18 +29,18 @@ def __init__(self, sdk: GoodDataSdk, logger: logging.Logger, dry_run: bool = Fal self.logger = logger self.dry_run = dry_run - def get_insights(self, workspace_id: str) -> List[Insight]: + def get_visualizations(self, workspace_id: str) -> List[Visualization]: if self.dry_run: self.logger.info("Dry run - skipping insights listing") return [] else: - return self.sdk.insights.get_insights(workspace_id) + return self.sdk.visualizations.get_visualizations(workspace_id) - def execute_insight(self, workspace_id: str, insight: Insight) -> None: + def execute_visualization(self, workspace_id: str, visualization: Visualization) -> None: if self.dry_run: - self.logger.info("Dry run - skipping insights execution") + self.logger.info("Dry run - skipping visualization execution") else: - self.sdk.tables.for_insight(workspace_id, insight) + self.sdk.tables.for_visualization(workspace_id, visualization) def scan_data_source(self, data_source_id: str, scan_request: CatalogScanModelRequest) -> CatalogDeclarativeTables: if self.dry_run: diff --git a/gooddata-dbt/gooddata_dbt/gooddata/config.py b/gooddata-dbt/gooddata_dbt/gooddata/config.py index 516ca5b44..d851988b3 100644 --- a/gooddata-dbt/gooddata_dbt/gooddata/config.py +++ b/gooddata-dbt/gooddata_dbt/gooddata/config.py @@ -48,7 +48,7 @@ class GoodDataConfigOrganization(Base): @attrs.define(auto_attribs=True, kw_only=True) class GoodDataGlobalConfig(Base): - test_insights_parallelism: Optional[int] = 1 + test_visualizations_parallelism: Optional[int] = 1 @attrs.define(auto_attribs=True, kw_only=True) diff --git a/gooddata-dbt/gooddata_dbt/sdk_wrapper.py b/gooddata-dbt/gooddata_dbt/sdk_wrapper.py index 458bdb368..44c65e695 100644 --- a/gooddata-dbt/gooddata_dbt/sdk_wrapper.py +++ b/gooddata-dbt/gooddata_dbt/sdk_wrapper.py @@ -54,11 +54,11 @@ def wait_for_gooddata_is_up(self, timeout: int) -> None: self.sdk.support.wait_till_available(timeout=timeout) self.logger.info(f"Host {host} is up") - def pre_cache_insights(self, workspaces: Optional[List] = None) -> None: + def pre_cache_visualizations(self, workspaces: Optional[List] = None) -> None: if not workspaces: workspaces = [w.id for w in self.sdk.catalog_workspace.list_workspaces()] for workspace_id in workspaces: - insights = self.sdk.insights.get_insights(workspace_id) + visualizations = self.sdk.visualizations.get_visualizations(workspace_id) - for insight in insights: - self.sdk.tables.for_insight(workspace_id, insight) + for visualization in visualizations: + self.sdk.tables.for_visualization(workspace_id, visualization) diff --git a/gooddata-dbt/gooddata_example.yml b/gooddata-dbt/gooddata_example.yml index a1c888de9..41d5323d7 100644 --- a/gooddata-dbt/gooddata_example.yml +++ b/gooddata-dbt/gooddata_example.yml @@ -33,9 +33,9 @@ data_products: environment_setup_id: default model_ids: - hubspot - # If execution of an insight fails, and you need some time to fix it + # If execution of an visualization fails, and you need some time to fix it skip_tests: - - "" + - "" # You can deliver data products to multiple organizations. Each organization can contain different (sub)set of products organizations: diff --git a/gooddata-dbt/tests/gooddata_example.yml b/gooddata-dbt/tests/gooddata_example.yml index 6d6159efe..ef822b139 100644 --- a/gooddata-dbt/tests/gooddata_example.yml +++ b/gooddata-dbt/tests/gooddata_example.yml @@ -23,11 +23,11 @@ data_products: - github - faa # Example of why and how to use skip_tests: - # TODO - this insight cannot be calculated by Python SDK: + # TODO - this visualization cannot be calculated by Python SDK: # The limit for maximum size of the dimension without metrics was exceeded(100_000). - # Fix it either in Python SDK or in the insight + # Fix it either in Python SDK or in the visualization skip_tests: - - "insight_1" + - "visualization_1" localization: from_language: en to: @@ -56,4 +56,4 @@ organizations: # Global configuration for all data products global_properties: - test_insights_parallelism: 2 + test_visualizations_parallelism: 2 From 2fd4b3e914e23a4d941fb1ddfe45de163716a4ee Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:44:11 +0100 Subject: [PATCH 4/6] feat(gooddata-fdw): replace "insight" in gooddata-fdw JIRA: PSDK-172 --- gooddata-fdw/gooddata_fdw/executor.py | 4 ++-- gooddata-fdw/gooddata_fdw/import_workspace.py | 21 +++++++++++++------ gooddata-fdw/gooddata_fdw/naming.py | 12 +++++------ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/gooddata-fdw/gooddata_fdw/executor.py b/gooddata-fdw/gooddata_fdw/executor.py index 3fc1edc6f..18beda5b1 100644 --- a/gooddata-fdw/gooddata_fdw/executor.py +++ b/gooddata-fdw/gooddata_fdw/executor.py @@ -60,8 +60,8 @@ def execute( self, quals: list[Qual], columns: list[str], sort_keys: Optional[list[Any]] = None ) -> Generator[dict[str, Any], None, None]: results_reader = InsightTableResultReader(self._table_columns, columns) - insight = self._sdk.insights.get_insight(self._workspace, self._insight) - table = self._sdk.tables.for_insight(self._workspace, insight) + insight = self._sdk.visualizations.get_visualization(self._workspace, self._insight) + table = self._sdk.tables.for_visualization(self._workspace, insight) return results_reader.read_all_rows(table) diff --git a/gooddata-fdw/gooddata_fdw/import_workspace.py b/gooddata-fdw/gooddata_fdw/import_workspace.py index f29026cf3..12c40407a 100644 --- a/gooddata-fdw/gooddata_fdw/import_workspace.py +++ b/gooddata-fdw/gooddata_fdw/import_workspace.py @@ -14,7 +14,14 @@ InsightColumnNamingStrategy, ) from gooddata_fdw.pg_logging import _log_debug, _log_info, _log_warn -from gooddata_sdk import CatalogWorkspaceContent, GoodDataSdk, Insight, InsightAttribute, InsightMetric, ObjId +from gooddata_sdk import ( + CatalogWorkspaceContent, + GoodDataSdk, + ObjId, + Visualization, + VisualizationAttribute, + VisualizationMetric, +) def _metric_format_to_precision(metric_format: Optional[str]) -> Optional[str]: @@ -85,7 +92,7 @@ def import_tables(self) -> list[TableDefinition]: _log_debug("loading full catalog") catalog = self._sdk.catalog_workspace_content.get_full_catalog(self._workspace) _log_debug("loading all insights") - insights = self._sdk.insights.get_insights(self._workspace) + insights = self._sdk.visualizations.get_visualizations(self._workspace) tables = [] for insight in insights: @@ -108,7 +115,9 @@ def import_tables(self) -> list[TableDefinition]: return tables - def _table_columns_from_insight(self, insight: Insight, catalog: CatalogWorkspaceContent) -> list[ColumnDefinition]: + def _table_columns_from_insight( + self, insight: Visualization, catalog: CatalogWorkspaceContent + ) -> list[ColumnDefinition]: column_naming = DefaultInsightColumnNaming() attr_cols = [self._attribute_to_table_column(attr, column_naming, catalog) for attr in insight.attributes] metric_cols = [self._metric_to_table_column(metric, column_naming, catalog) for metric in insight.metrics] @@ -117,7 +126,7 @@ def _table_columns_from_insight(self, insight: Insight, catalog: CatalogWorkspac @staticmethod def _attribute_to_table_column( - attr: InsightAttribute, column_naming: InsightColumnNamingStrategy, catalog: CatalogWorkspaceContent + attr: VisualizationAttribute, column_naming: InsightColumnNamingStrategy, catalog: CatalogWorkspaceContent ) -> ColumnDefinition: column_name = column_naming.col_name_for_attribute(attr) _log_debug(f'creating col def "{column_name}" for attribute "{attr.label_id}"') @@ -132,7 +141,7 @@ def _attribute_to_table_column( ) def _metric_to_table_column( - self, metric: InsightMetric, column_naming: InsightColumnNamingStrategy, catalog: CatalogWorkspaceContent + self, metric: VisualizationMetric, column_naming: InsightColumnNamingStrategy, catalog: CatalogWorkspaceContent ) -> ColumnDefinition: column_name = column_naming.col_name_for_metric(metric) metric_format = self._get_insight_metric_format(metric, catalog) @@ -156,7 +165,7 @@ def _metric_to_table_column( # InsightMetric do not contain format in case of stored metrics @staticmethod - def _get_insight_metric_format(metric: InsightMetric, catalog: CatalogWorkspaceContent) -> Optional[str]: + def _get_insight_metric_format(metric: VisualizationMetric, catalog: CatalogWorkspaceContent) -> Optional[str]: if metric.format: return metric.format elif metric.item_id: diff --git a/gooddata-fdw/gooddata_fdw/naming.py b/gooddata-fdw/gooddata_fdw/naming.py index d53f303ae..4e9fc3e8e 100644 --- a/gooddata-fdw/gooddata_fdw/naming.py +++ b/gooddata-fdw/gooddata_fdw/naming.py @@ -41,7 +41,7 @@ def _ensure_unique(candidate: str, used_names: dict[str, bool]) -> str: class InsightTableNamingStrategy: - def table_name_for_insight(self, insight: sdk.Insight) -> str: + def table_name_for_insight(self, insight: sdk.Visualization) -> str: raise NotImplementedError() @@ -49,7 +49,7 @@ class DefaultInsightTableNaming(InsightTableNamingStrategy): def __init__(self) -> None: self._uniques: dict[str, bool] = dict() - def table_name_for_insight(self, insight: sdk.Insight) -> str: + def table_name_for_insight(self, insight: sdk.Visualization) -> str: new_name = _sanitize_str_for_postgres(insight.title, self._uniques) self._uniques[new_name] = True @@ -57,10 +57,10 @@ def table_name_for_insight(self, insight: sdk.Insight) -> str: class InsightColumnNamingStrategy: - def col_name_for_attribute(self, attr: sdk.InsightAttribute) -> str: + def col_name_for_attribute(self, attr: sdk.VisualizationAttribute) -> str: raise NotImplementedError() - def col_name_for_metric(self, attr: sdk.InsightMetric) -> str: + def col_name_for_metric(self, attr: sdk.VisualizationMetric) -> str: raise NotImplementedError() @@ -68,13 +68,13 @@ class DefaultInsightColumnNaming(InsightColumnNamingStrategy): def __init__(self) -> None: self._uniques: dict[str, bool] = dict() - def col_name_for_attribute(self, attr: sdk.InsightAttribute) -> str: + def col_name_for_attribute(self, attr: sdk.VisualizationAttribute) -> str: new_name = _sanitize_str_for_postgres(attr.label_id, self._uniques) self._uniques[new_name] = True return new_name - def col_name_for_metric(self, metric: sdk.InsightMetric) -> str: + def col_name_for_metric(self, metric: sdk.VisualizationMetric) -> str: # if simple measure, use the item identifier (nice, readable) # otherwise try alias # otherwise try title From 6cf3fa5649ef4f8cb4f382e5cb3122a2b48d5ada Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:44:51 +0100 Subject: [PATCH 5/6] feat(gooddata-pandas): replace "insight" in gooddata-pandas JIRA: PSDK-172 --- gooddata-pandas/gooddata_pandas/dataframe.py | 34 +++++++++++++------ gooddata-pandas/gooddata_pandas/utils.py | 23 ++++++++----- ....yaml => dataframe_for_visualization.yaml} | 0 ... => dataframe_for_visualization_date.yaml} | 0 ...dataframe_for_visualization_no_index.yaml} | 0 .../dataframe/test_dataframe_for_insight.py | 18 +++++----- 6 files changed, 47 insertions(+), 28 deletions(-) rename gooddata-pandas/tests/dataframe/fixtures/{dataframe_for_insight.yaml => dataframe_for_visualization.yaml} (100%) rename gooddata-pandas/tests/dataframe/fixtures/{dataframe_for_insight_date.yaml => dataframe_for_visualization_date.yaml} (100%) rename gooddata-pandas/tests/dataframe/fixtures/{dataframe_for_insight_no_index.yaml => dataframe_for_visualization_no_index.yaml} (100%) diff --git a/gooddata-pandas/gooddata_pandas/dataframe.py b/gooddata-pandas/gooddata_pandas/dataframe.py index 29666e44b..d757ffc60 100644 --- a/gooddata-pandas/gooddata_pandas/dataframe.py +++ b/gooddata-pandas/gooddata_pandas/dataframe.py @@ -2,6 +2,7 @@ from __future__ import annotations from typing import Optional, Tuple, Union +from warnings import warn import pandas @@ -15,7 +16,7 @@ ) from gooddata_pandas.utils import ( ColumnsDef, - DefaultInsightColumnNaming, + DefaultVisualizationColumnNaming, IndexDef, LabelItemDef, _to_item, @@ -43,7 +44,7 @@ class DataFrameFactory: -> pandas.DataFrame: - for_items(self, items: ColumnsDef, filter_by: Optional[Union[Filter, list[Filter]]] = None, auto_index: bool = True) -> pandas.DataFrame: - - for_insight(self, insight_id: str, auto_index: bool = True) + - for_visualization(self, visualization_id: str, auto_index: bool = True) -> pandas.DataFrame: - result_cache_metadata_for_exec_result_id(self, result_id: str) -> ResultCacheMetadata: @@ -159,28 +160,39 @@ def for_items( filter_by=filter_by, ) - def for_insight(self, insight_id: str, auto_index: bool = True) -> pandas.DataFrame: + def for_visualization(self, visualization_id: str, auto_index: bool = True) -> pandas.DataFrame: """ - Creates a data frame with columns based on the content of the insight with the provided identifier. + Creates a data frame with columns based on the content of the visualization with the provided identifier. Args: - insight_id (str): Insight identifier. + visualization_id (str): Visualization identifier. auto_index (bool): Default True. Enables creation of DataFrame with index depending on the contents - of the insight. + of the visualization. Returns: pandas.DataFrame: A DataFrame instance. """ - naming = DefaultInsightColumnNaming() - insight = self._sdk.insights.get_insight(workspace_id=self._workspace_id, insight_id=insight_id) - filter_by = [f.as_computable() for f in insight.filters] + naming = DefaultVisualizationColumnNaming() + visualization = self._sdk.visualizations.get_visualization( + workspace_id=self._workspace_id, visualization_id=visualization_id + ) + filter_by = [f.as_computable() for f in visualization.filters] columns: ColumnsDef = { - **{naming.col_name_for_attribute(a): a.as_computable() for a in insight.attributes}, - **{naming.col_name_for_metric(m): m.as_computable() for m in insight.metrics}, + **{naming.col_name_for_attribute(a): a.as_computable() for a in visualization.attributes}, + **{naming.col_name_for_metric(m): m.as_computable() for m in visualization.metrics}, } return self.for_items(columns, filter_by=filter_by, auto_index=auto_index) + def for_insight(self, insight_id: str, auto_index: bool = True) -> pandas.DataFrame: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use 'for_visualization' method instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.for_visualization(insight_id, auto_index) + def result_cache_metadata_for_exec_result_id(self, result_id: str) -> ResultCacheMetadata: """ Retrieves result cache metadata for given :result_id: diff --git a/gooddata-pandas/gooddata_pandas/utils.py b/gooddata-pandas/gooddata_pandas/utils.py index ec29706ef..0dd0d45b9 100644 --- a/gooddata-pandas/gooddata_pandas/utils.py +++ b/gooddata-pandas/gooddata_pandas/utils.py @@ -8,7 +8,15 @@ import pandas from pandas import Index, MultiIndex -from gooddata_sdk import Attribute, CatalogAttribute, InsightAttribute, InsightMetric, Metric, ObjId, SimpleMetric +from gooddata_sdk import ( + Attribute, + CatalogAttribute, + Metric, + ObjId, + SimpleMetric, + VisualizationAttribute, + VisualizationMetric, +) from gooddata_sdk.type_converter import AttributeConverterStore, DateConverter, DatetimeConverter, IntegerConverter LabelItemDef = Union[Attribute, ObjId, str] @@ -16,7 +24,6 @@ IndexDef = Union[LabelItemDef, Dict[str, LabelItemDef]] ColumnsDef = Dict[str, DataItemDef] - # register external pandas types to converters IntegerConverter.set_external_fnc(lambda self, value: pandas.to_numeric(value)) DateConverter.set_external_fnc(lambda self, value: pandas.to_datetime(value)) @@ -162,10 +169,10 @@ def make_pandas_index(index: dict) -> Optional[Union[Index, MultiIndex]]: return _idx -class DefaultInsightColumnNaming: +class DefaultVisualizationColumnNaming: def __init__(self) -> None: """ - Initialize a DefaultInsightColumnNaming instance with an empty dictionary for unique names. + Initialize a DefaultVisualizationColumnNaming instance with an empty dictionary for unique names. """ self._uniques: dict[str, int] = dict() @@ -206,24 +213,24 @@ def _ensure_unique(self, candidate: str) -> str: self._uniques[unique_candidate] = 1 return unique_candidate - def col_name_for_attribute(self, attr: InsightAttribute) -> str: + def col_name_for_attribute(self, attr: VisualizationAttribute) -> str: """ Generate a unique column name for the given attribute. Args: - attr (InsightAttribute): The attribute. + attr (VisualizationAttribute): The attribute. Returns: str: The unique column name. """ return self._ensure_unique(attr.label_id) - def col_name_for_metric(self, measure: InsightMetric) -> str: + def col_name_for_metric(self, measure: VisualizationMetric) -> str: """ Generate a unique column name for the given metric. Args: - measure (InsightMetric): The metric. + measure (VisualizationMetric): The metric. Returns: str: The unique column name. diff --git a/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight.yaml b/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization.yaml similarity index 100% rename from gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight.yaml rename to gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization.yaml diff --git a/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight_date.yaml b/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization_date.yaml similarity index 100% rename from gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight_date.yaml rename to gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization_date.yaml diff --git a/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight_no_index.yaml b/gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization_no_index.yaml similarity index 100% rename from gooddata-pandas/tests/dataframe/fixtures/dataframe_for_insight_no_index.yaml rename to gooddata-pandas/tests/dataframe/fixtures/dataframe_for_visualization_no_index.yaml diff --git a/gooddata-pandas/tests/dataframe/test_dataframe_for_insight.py b/gooddata-pandas/tests/dataframe/test_dataframe_for_insight.py index 8ebb6be3c..4d4df2aa0 100644 --- a/gooddata-pandas/tests/dataframe/test_dataframe_for_insight.py +++ b/gooddata-pandas/tests/dataframe/test_dataframe_for_insight.py @@ -11,11 +11,11 @@ _fixtures_dir = _current_dir / "fixtures" -@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_insight_date.yaml")) -def test_dataframe_for_insight_date(gdf: DataFrameFactory): +@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_visualization_date.yaml")) +def test_dataframe_for_visualization_date(gdf: DataFrameFactory): # 2 metrics grouped by date dimension with data for last 12 months # exact numbers cannot be checked as date data are changed each AIO build - df = gdf.for_insight(insight_id="customers_trend") + df = gdf.for_visualization(visualization_id="customers_trend") assert len(df) == 12 assert len(df.index.names) == 1 @@ -26,10 +26,10 @@ def test_dataframe_for_insight_date(gdf: DataFrameFactory): assert df.columns[1] == "revenue_per_customer" -@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_insight.yaml")) -def test_dataframe_for_insight(gdf: DataFrameFactory): +@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_visualization.yaml")) +def test_dataframe_for_visualization(gdf: DataFrameFactory): # 4 metrics grouped by 2 attributes, filters are set to all - df = gdf.for_insight(insight_id="revenue_and_quantity_by_product_and_category") + df = gdf.for_visualization(visualization_id="revenue_and_quantity_by_product_and_category") assert df.index.names[0] == "products.category" assert df.index.names[1] == "product_name" @@ -39,10 +39,10 @@ def test_dataframe_for_insight(gdf: DataFrameFactory): assert df.columns[3] == "revenue" -@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_insight_no_index.yaml")) -def test_dataframe_for_insight_no_index(gdf: DataFrameFactory): +@gd_vcr.use_cassette(str(_fixtures_dir / "dataframe_for_visualization_no_index.yaml")) +def test_dataframe_for_visualization_no_index(gdf: DataFrameFactory): # 4 metrics grouped by 2 attributes, filters are set to all - df = gdf.for_insight(insight_id="revenue_and_quantity_by_product_and_category", auto_index=False) + df = gdf.for_visualization(visualization_id="revenue_and_quantity_by_product_and_category", auto_index=False) assert df.columns[0] == "products.category" assert df.columns[1] == "product_name" From 22b2297f7810c0005c331ac1fb0195086cfc922c Mon Sep 17 00:00:00 2001 From: hkad98 Date: Fri, 1 Mar 2024 15:45:09 +0100 Subject: [PATCH 6/6] feat(gooddata-sdk): replace "insight" in gooddata-sdk JIRA: PSDK-172 --- gooddata-sdk/README.md | 4 +- gooddata-sdk/gooddata_sdk/__init__.py | 13 +- .../gooddata_sdk/catalog/export/service.py | 78 +++++-- .../gooddata_sdk/catalog/workspace/service.py | 12 +- gooddata-sdk/gooddata_sdk/sdk.py | 14 +- gooddata-sdk/gooddata_sdk/table.py | 103 +++++---- .../{insight.py => visualization.py} | 209 ++++++++++++++---- ... test_export_csv_by_visualization_id.yaml} | 0 ...est_export_excel_by_visualization_id.yaml} | 0 .../tests/export/test_export_service.py | 24 +- gooddata-sdk/tests/gd_test_config.yaml | 4 +- gooddata-sdk/tests/overview.md | 4 +- gooddata-sdk/tests/table/test_table.py | 8 +- .../{insight => visualization}/__init__.py | 0 .../{insight => visualization}/fixtures.py | 0 ...metric_date_attribute_show_all_values.json | 0 .../resources/one_metric_two_attributes.json | 0 .../resources/single_attribute.json | 0 ...wo_metrics_multiple_attribute_buckets.json | 0 .../resources/with_arithmetic_metric.json | 0 .../resources/with_attribute_filters.json | 0 .../resources/with_date_filters.json | 0 .../with_funky_attribute_filters.json | 0 .../resources/with_metric_value_filter.json | 0 .../resources/with_pop_metric.json | 0 .../with_previous_period_metric.json | 0 .../resources/with_ranking_filter.json | 0 ...te_attribute_show_all_values.snapshot.json | 0 .../one_metric_two_attributes.snapshot.json | 0 .../snapshots/single_attribute.snapshot.json | 0 ...s_multiple_attribute_buckets.snapshot.json | 0 .../with_arithmetic_metric.snapshot.json | 0 .../with_attribute_filters.snapshot.json | 0 .../snapshots/with_date_filters.snapshot.json | 0 ...with_funky_attribute_filters.snapshot.json | 0 .../with_metric_value_filter.snapshot.json | 0 .../snapshots/with_pop_metric.snapshot.json | 0 .../with_previous_period_metric.snapshot.json | 0 .../with_ranking_filter.snapshot.json | 0 .../test_visualization.py} | 16 +- 40 files changed, 345 insertions(+), 144 deletions(-) rename gooddata-sdk/gooddata_sdk/{insight.py => visualization.py} (70%) rename gooddata-sdk/tests/export/fixtures/{test_export_csv_by_insight_id.yaml => test_export_csv_by_visualization_id.yaml} (100%) rename gooddata-sdk/tests/export/fixtures/{test_export_excel_by_insight_id.yaml => test_export_excel_by_visualization_id.yaml} (100%) rename gooddata-sdk/tests/{insight => visualization}/__init__.py (100%) rename gooddata-sdk/tests/{insight => visualization}/fixtures.py (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/one_metric_date_attribute_show_all_values.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/one_metric_two_attributes.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/single_attribute.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/two_metrics_multiple_attribute_buckets.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_arithmetic_metric.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_attribute_filters.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_date_filters.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_funky_attribute_filters.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_metric_value_filter.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_pop_metric.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_previous_period_metric.json (100%) rename gooddata-sdk/tests/{insight => visualization}/resources/with_ranking_filter.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/one_metric_date_attribute_show_all_values.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/one_metric_two_attributes.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/single_attribute.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/two_metrics_multiple_attribute_buckets.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_arithmetic_metric.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_attribute_filters.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_date_filters.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_funky_attribute_filters.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_metric_value_filter.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_pop_metric.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_previous_period_metric.snapshot.json (100%) rename gooddata-sdk/tests/{insight => visualization}/snapshots/with_ranking_filter.snapshot.json (100%) rename gooddata-sdk/tests/{insight/test_insight.py => visualization/test_visualization.py} (67%) diff --git a/gooddata-sdk/README.md b/gooddata-sdk/README.md index 19a934f92..cb581bfb2 100644 --- a/gooddata-sdk/README.md +++ b/gooddata-sdk/README.md @@ -41,9 +41,9 @@ sdk = gooddata_sdk.GoodDataSdk.create(host, token) workspace_id = "demo" insight_id = "customers_trend" # reads insight from workspace -insight = sdk.insights.get_insight(workspace_id, insight_id) +insight = sdk.visualizations.get_visualization(workspace_id, insight_id) # triggers computation for the insight. the result will be returned in a tabular form -table = sdk.tables.for_insight(workspace_id, insight) +table = sdk.tables.for_visualization(workspace_id, insight) # and this is how you can read data row-by-row and do something with it for row in table.read_all(): diff --git a/gooddata-sdk/gooddata_sdk/__init__.py b/gooddata-sdk/gooddata_sdk/__init__.py index 476b224bf..10d20ff74 100644 --- a/gooddata-sdk/gooddata_sdk/__init__.py +++ b/gooddata-sdk/gooddata_sdk/__init__.py @@ -211,10 +211,21 @@ SimpleMetric, ) from gooddata_sdk.compute.service import ComputeService -from gooddata_sdk.insight import Insight, InsightAttribute, InsightBucket, InsightMetric, InsightService from gooddata_sdk.sdk import GoodDataSdk from gooddata_sdk.table import ExecutionTable, TableService from gooddata_sdk.utils import SideLoads +from gooddata_sdk.visualization import ( + Insight, + InsightAttribute, + InsightBucket, + InsightMetric, + InsightService, + Visualization, + VisualizationAttribute, + VisualizationBucket, + VisualizationMetric, + VisualizationService, +) # by default don't log anything logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/gooddata-sdk/gooddata_sdk/catalog/export/service.py b/gooddata-sdk/gooddata_sdk/catalog/export/service.py index cf1eec3bb..f5acdbd83 100644 --- a/gooddata-sdk/gooddata_sdk/catalog/export/service.py +++ b/gooddata-sdk/gooddata_sdk/catalog/export/service.py @@ -2,6 +2,7 @@ import time from pathlib import Path from typing import Callable, Optional, Tuple, Union +from warnings import warn from gooddata_api_client.exceptions import NotFoundException from gooddata_api_client.model.pdf_export_request import PdfExportRequest @@ -16,8 +17,8 @@ SimpleMetric, ) from gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase -from gooddata_sdk.insight import InsightService from gooddata_sdk.table import ExecutionTable, TableService +from gooddata_sdk.visualization import VisualizationService class ExportService(CatalogServiceBase): @@ -41,8 +42,8 @@ class ExportService(CatalogServiceBase): Export a PDF of a GoodData Dashboard. export_tabular: Export Tabular data from a GoodData Dashboard. - export_tabular_by_insight_id: - Exports the tabular data of a particular insight id. + export_tabular_by_visualization_id: + Exports the tabular data of a particular visualization id. """ def __init__(self, api_client: GoodDataApiClient) -> None: @@ -252,7 +253,8 @@ def export_tabular( @staticmethod def _custom_overrides_labels(exec_table: ExecutionTable, metrics_format: str = "#,##0") -> ExportCustomOverride: """ - Insights by default use generated hash as local_id therefore we might want to use dummy logic to replace it. + Visualizations by default use generated hash as local_id, + therefore, we might want to use dummy logic to replace it. For attributes by label.id For metrics by item.id """ @@ -267,19 +269,33 @@ def _custom_overrides_labels(exec_table: ExecutionTable, metrics_format: str = " } return ExportCustomOverride(labels=labels, metrics=metrics) - def _get_insight_exec_table(self, workspace_id: str, insight_id: str) -> Tuple[ExecutionTable, str]: + def _get_visualization_exec_table(self, workspace_id: str, visualization_id: str) -> Tuple[ExecutionTable, str]: try: - insight = InsightService(self._client).get_insight(workspace_id=workspace_id, insight_id=insight_id) - return TableService(self._client).for_insight(workspace_id=workspace_id, insight=insight), insight.title + visualization = VisualizationService(self._client).get_visualization( + workspace_id=workspace_id, visualization_id=visualization_id + ) + return TableService(self._client).for_visualization( + workspace_id=workspace_id, visualization=visualization + ), visualization.title except NotFoundException: raise ValueError( - f"Either workspace workspace_id='{workspace_id}' or insight insight_id='{insight_id}' does not exist." + f"Either workspace workspace_id='{workspace_id}' " + f"or visualization visualization_id='{visualization_id}' does not exist." ) - def export_tabular_by_insight_id( + def _get_insight_exec_table(self, workspace_id: str, insight_id: str) -> Tuple[ExecutionTable, str]: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use '_get_visualization_exec_table' method instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._get_visualization_exec_table(workspace_id, insight_id) + + def export_tabular_by_visualization_id( self, workspace_id: str, - insight_id: str, + visualization_id: str, file_format: str, file_name: Optional[str] = None, settings: Optional[ExportSettings] = None, @@ -289,15 +305,15 @@ def export_tabular_by_insight_id( max_retry: float = 5.0, ) -> None: """ - Exports the tabular data of a particular insight id. + Exports the tabular data of a particular visualization id. Args: - workspace_id (str): The workspace id from which the insight is to be exported. - insight_id (str): The id of the insight to be exported. + workspace_id (str): The workspace id from which the visualization is to be exported. + visualization_id (str): The id of the visualization to be exported. file_format (str): The format of the file to be exported. file_name (Optional[str], optional): The name which the exported file should have. Defaults to None. settings (Optional[ExportSettings], optional): Any additional settings for the export. Defaults to None. - store_path (Union[str, Path], optional): The path to store the exported file. Defaults to Path.cwd(). + store_path (Union[str, Path], optional): The path to store the exported file. Default to Path.cwd(). timeout (float, optional): The maximum time to wait for the export to finish. Defaults to 60.0. retry (float, optional): Initial wait time (in seconds) before retrying to get the exported content. Defaults to 0.2. @@ -306,9 +322,9 @@ def export_tabular_by_insight_id( Returns: None """ - exec_table, insight_tile = self._get_insight_exec_table(workspace_id, insight_id) + exec_table, visualization_tile = self._get_visualization_exec_table(workspace_id, visualization_id) custom_override = self._custom_overrides_labels(exec_table) - file_name = file_name if file_name is not None else insight_tile + file_name = file_name if file_name is not None else visualization_tile export_request = ExportRequest( format=file_format, execution_result=exec_table.result_id, @@ -324,3 +340,33 @@ def export_tabular_by_insight_id( retry=retry, max_retry=max_retry, ) + + def export_tabular_by_insight_id( + self, + workspace_id: str, + insight_id: str, + file_format: str, + file_name: Optional[str] = None, + settings: Optional[ExportSettings] = None, + store_path: Union[str, Path] = Path.cwd(), + timeout: float = 60.0, + retry: float = 0.2, + max_retry: float = 5.0, + ) -> None: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use 'export_tabular_by_visualization_id' method instead.", + DeprecationWarning, + stacklevel=2, + ) + self.export_tabular_by_visualization_id( + workspace_id, + insight_id, + file_format, + file_name, + settings, + store_path, + timeout, + retry, + max_retry, + ) diff --git a/gooddata-sdk/gooddata_sdk/catalog/workspace/service.py b/gooddata-sdk/gooddata_sdk/catalog/workspace/service.py index 59051d709..683b7fdd0 100644 --- a/gooddata-sdk/gooddata_sdk/catalog/workspace/service.py +++ b/gooddata-sdk/gooddata_sdk/catalog/workspace/service.py @@ -687,9 +687,9 @@ def get_texts_to_translate( for metric in workspace_content.analytics.metrics or []: self.add_title_description(to_translate, metric.title, metric.description) if workspace_content.analytics: - for insight in workspace_content.analytics.visualization_objects or []: - self.add_title_description(to_translate, insight.title, insight.description) - for bucket in insight.content["buckets"]: + for visualization in workspace_content.analytics.visualization_objects or []: + self.add_title_description(to_translate, visualization.title, visualization.description) + for bucket in visualization.content["buckets"]: for item in bucket["items"]: if "measure" in item: if "alias" in item["measure"]: @@ -741,9 +741,9 @@ def set_translated_texts( for metric in new_workspace_content.analytics.metrics or []: self.set_title_description(metric, translated) if new_workspace_content.analytics: - for insight in new_workspace_content.analytics.visualization_objects or []: - self.set_title_description(insight, translated) - for bucket in insight.content["buckets"]: + for visualization in new_workspace_content.analytics.visualization_objects or []: + self.set_title_description(visualization, translated) + for bucket in visualization.content["buckets"]: for item in bucket["items"]: if "measure" in item: if "alias" in item["measure"]: diff --git a/gooddata-sdk/gooddata_sdk/sdk.py b/gooddata-sdk/gooddata_sdk/sdk.py index 53d7c1396..1b2df903a 100644 --- a/gooddata-sdk/gooddata_sdk/sdk.py +++ b/gooddata-sdk/gooddata_sdk/sdk.py @@ -3,6 +3,7 @@ from pathlib import Path from typing import Optional +from warnings import warn from gooddata_sdk.catalog.data_source.service import CatalogDataSourceService from gooddata_sdk.catalog.export.service import ExportService @@ -13,10 +14,10 @@ from gooddata_sdk.catalog.workspace.service import CatalogWorkspaceService from gooddata_sdk.client import GoodDataApiClient from gooddata_sdk.compute.service import ComputeService -from gooddata_sdk.insight import InsightService from gooddata_sdk.support import SupportService from gooddata_sdk.table import TableService from gooddata_sdk.utils import PROFILES_FILE_PATH, profile_content +from gooddata_sdk.visualization import InsightService, VisualizationService class GoodDataSdk: @@ -74,6 +75,7 @@ def __init__(self, client: GoodDataApiClient) -> None: self._catalog_user = CatalogUserService(self._client) self._compute = ComputeService(self._client) self._insights = InsightService(self._client) + self._visualizations = VisualizationService(self._client) self._tables = TableService(self._client) self._support = SupportService(self._client) self._catalog_permission = CatalogPermissionService(self._client) @@ -101,8 +103,18 @@ def compute(self) -> ComputeService: @property def insights(self) -> InsightService: + warn( + "This property is deprecated and it will be removed in v1.20.0 release. " + "Please use 'visualizations' property instead.", + DeprecationWarning, + stacklevel=2, + ) return self._insights + @property + def visualizations(self) -> VisualizationService: + return self._visualizations + @property def tables(self) -> TableService: return self._tables diff --git a/gooddata-sdk/gooddata_sdk/table.py b/gooddata-sdk/gooddata_sdk/table.py index 4cae12eb6..b0e763d15 100644 --- a/gooddata-sdk/gooddata_sdk/table.py +++ b/gooddata-sdk/gooddata_sdk/table.py @@ -3,6 +3,7 @@ from operator import attrgetter from typing import Any, Generator, List, Optional, Union +from warnings import warn from attrs import define, field, frozen from attrs.setters import frozen as frozen_attr @@ -19,7 +20,14 @@ from gooddata_sdk.compute.model.filter import Filter from gooddata_sdk.compute.model.metric import Metric from gooddata_sdk.compute.service import ComputeService -from gooddata_sdk.insight import BucketType, Insight, InsightBucket, InsightMetric, InsightTotal +from gooddata_sdk.visualization import ( + BucketType, + Insight, + Visualization, + VisualizationBucket, + VisualizationMetric, + VisualizationTotal, +) _MEASURE_GROUP_IDENTIFIER = "measureGroup" _TOTAL_ORDER = ["SUM", "MAX", "MIN", "AVG", "MED"] @@ -234,7 +242,7 @@ class TotalDefinitionOrdering: total: TotalDefinition @classmethod - def create(cls, total: TotalDefinition, measures: list[InsightMetric]) -> TotalDefinitionOrdering: + def create(cls, total: TotalDefinition, measures: list[VisualizationMetric]) -> TotalDefinitionOrdering: metric_ordering = [m.local_id for m in measures] return cls( function_order=_TOTAL_ORDER.index(total.aggregation.upper()), @@ -243,7 +251,7 @@ def create(cls, total: TotalDefinition, measures: list[InsightMetric]) -> TotalD ) -def _create_dimension(bucket: InsightBucket, measures_item_identifier: Optional[str] = None) -> TableDimension: +def _create_dimension(bucket: VisualizationBucket, measures_item_identifier: Optional[str] = None) -> TableDimension: item_ids = [a.local_id for a in bucket.attributes] if measures_item_identifier is not None: item_ids.append(measures_item_identifier) @@ -254,39 +262,39 @@ def _create_dimension(bucket: InsightBucket, measures_item_identifier: Optional[ ) -def _create_dimensions(insight: Insight) -> list[TableDimension]: +def _create_dimensions(visualization: Visualization) -> list[TableDimension]: # TODO: measures item id placement should reflect table transposition setting - measures_item_identifier = _MEASURE_GROUP_IDENTIFIER if insight.metrics else None - row_bucket = insight.get_bucket_of_type(BucketType.ROWS) - col_bucket = insight.get_bucket_of_type(BucketType.COLS) + measures_item_identifier = _MEASURE_GROUP_IDENTIFIER if visualization.metrics else None + row_bucket = visualization.get_bucket_of_type(BucketType.ROWS) + col_bucket = visualization.get_bucket_of_type(BucketType.COLS) return [ _create_dimension(row_bucket), _create_dimension(col_bucket, measures_item_identifier), ] -def _marginal_total_local_identifier(total: InsightTotal, dim_idx: int) -> str: +def _marginal_total_local_identifier(total: VisualizationTotal, dim_idx: int) -> str: return f"marginal_total_{total.type}_{total.measure_id}_by_{total.attribute_id}_{dim_idx}" -def _sub_total_column_local_identifier(total: InsightTotal, dim_idx: int) -> str: +def _sub_total_column_local_identifier(total: VisualizationTotal, dim_idx: int) -> str: return f"subtotal_column_{total.type}_{total.measure_id}_by_{total.attribute_id}_{dim_idx}" -def _sub_total_row_local_identifier(total: InsightTotal, dim_idx: int) -> str: +def _sub_total_row_local_identifier(total: VisualizationTotal, dim_idx: int) -> str: return f"subtotal_row_{total.type}_{total.measure_id}_by_{total.attribute_id}_{dim_idx}" -def _grand_total_local_identifier(total: InsightTotal, dim_idx: int) -> str: +def _grand_total_local_identifier(total: VisualizationTotal, dim_idx: int) -> str: return f"total_of_totals_{total.type}_{total.measure_id}_by_{total.attribute_id}_{dim_idx}" -def _total_local_identifier(total: InsightTotal, dim_idx: int) -> str: +def _total_local_identifier(total: VisualizationTotal, dim_idx: int) -> str: return f"total_{total.type}_{total.measure_id}_by_{total.attribute_id}_{dim_idx}" def _convert_total_dimensions( - total: InsightTotal, dimension: TableDimension, idx: int, all_dims: list[TableDimension] + total: VisualizationTotal, dimension: TableDimension, idx: int, all_dims: list[TableDimension] ) -> Any: item_idx = dimension.item_ids.index(total.attribute_id) total_dim_items = dimension.item_ids[0:item_idx] @@ -347,7 +355,7 @@ def update_compute_info(self, col_total_attr_id: str, row_total_attr_id: str) -> self.column_subtotal_dimension_index = self.col_attr_ids.index(col_total_attr_id) -def _get_additional_totals(insight: Insight, dimensions: list[TableDimension]) -> list[TotalDefinition]: +def _get_additional_totals(visualization: Visualization, dimensions: list[TableDimension]) -> list[TotalDefinition]: """Construct special cases of pivot table totals. These special cases are - @@ -360,8 +368,8 @@ def _get_additional_totals(insight: Insight, dimensions: list[TableDimension]) - totalDimensions items based on the attribute and column identifiers order in buckets. """ totals: list[TotalDefinition] = [] - row_bucket = insight.get_bucket_of_type(BucketType.ROWS) - col_bucket = insight.get_bucket_of_type(BucketType.COLS) + row_bucket = visualization.get_bucket_of_type(BucketType.ROWS) + col_bucket = visualization.get_bucket_of_type(BucketType.COLS) tci = TotalsComputeInfo( row_attr_ids=[a.local_id for a in row_bucket.attributes], @@ -391,7 +399,7 @@ def _get_additional_totals(insight: Insight, dimensions: list[TableDimension]) - return totals -def _extend_grand_totals(row_index: int, row_total: InsightTotal, tci: TotalsComputeInfo) -> TotalDefinition: +def _extend_grand_totals(row_index: int, row_total: VisualizationTotal, tci: TotalsComputeInfo) -> TotalDefinition: # Extend grand totals payload row_dim = [TotalDimension(idx=0, items=tci.measure_group_rows)] if tci.measure_group_rows else [] col_dim = [TotalDimension(idx=1, items=tci.measure_group_cols)] if tci.measure_group_cols else [] @@ -403,7 +411,9 @@ def _extend_grand_totals(row_index: int, row_total: InsightTotal, tci: TotalsCom ) -def _extend_marginal_totals_of_cols(row_index: int, row_total: InsightTotal, tci: TotalsComputeInfo) -> TotalDefinition: +def _extend_marginal_totals_of_cols( + row_index: int, row_total: VisualizationTotal, tci: TotalsComputeInfo +) -> TotalDefinition: # Extend marginal of columns within rows grand totals payload row_dim = [TotalDimension(idx=0, items=tci.measure_group_rows)] if tci.measure_group_rows else [] col_dim = [ @@ -420,7 +430,9 @@ def _extend_marginal_totals_of_cols(row_index: int, row_total: InsightTotal, tci ) -def _extend_marginal_totals_of_rows(row_index: int, row_total: InsightTotal, tci: TotalsComputeInfo) -> TotalDefinition: +def _extend_marginal_totals_of_rows( + row_index: int, row_total: VisualizationTotal, tci: TotalsComputeInfo +) -> TotalDefinition: # Extend marginal totals of rows within column grand totals payload return TotalDefinition( local_id=_sub_total_column_local_identifier(row_total, row_index), @@ -439,7 +451,7 @@ def _extend_marginal_totals_of_rows(row_index: int, row_total: InsightTotal, tci ) -def _extend_marginal_totals(col_index: int, row_total: InsightTotal, tci: TotalsComputeInfo) -> TotalDefinition: +def _extend_marginal_totals(col_index: int, row_total: VisualizationTotal, tci: TotalsComputeInfo) -> TotalDefinition: # Extend marginal totals payload return TotalDefinition( local_id=_marginal_total_local_identifier(row_total, col_index), @@ -458,11 +470,11 @@ def _extend_marginal_totals(col_index: int, row_total: InsightTotal, tci: Totals ) -def _get_computable_totals(insight: Insight, dimensions: list[TableDimension]) -> list[TotalDefinition]: +def _get_computable_totals(visualization: Visualization, dimensions: list[TableDimension]) -> list[TotalDefinition]: """ Extracts total definitions from execution definition dimensions and converts them into total specifications for Tiger AFM. Execution definition defines totals by a measure, aggregation function, and the attribute for whose - values we want the totals. In Tiger, measure and aggregation function remains the same, but the `totalDimensions` + values we want the totals. In Tiger, measure and aggregation function remain the same, but the `totalDimensions` with `totalDimensionItems` are best understood as coordinates for the resulting structure where the totals should be placed. This implicitly decides which attributes should be used. This allows for multidimensional totals, but such totals are impossible to define in the execution definition. @@ -470,7 +482,7 @@ def _get_computable_totals(insight: Insight, dimensions: list[TableDimension]) - processed_totals = [] for dim in dimensions: bucket_type = _GET_BUCKET_TYPE_OF_DIM_INDEX[dim.idx] - bucket = insight.get_bucket_of_type(bucket_type) + bucket = visualization.get_bucket_of_type(bucket_type) dim_totals_with_order = [] for total in bucket.totals: total_def = TotalDefinition( @@ -484,36 +496,36 @@ def _get_computable_totals(insight: Insight, dimensions: list[TableDimension]) - dimensions, ), ) - dim_totals_with_order.append(TotalDefinitionOrdering.create(total_def, insight.metrics)) + dim_totals_with_order.append(TotalDefinitionOrdering.create(total_def, visualization.metrics)) dim_totals_with_order.sort(key=attrgetter("function_order", "order")) processed_totals.append([t.total for t in dim_totals_with_order]) totals = [total for dim_totals in processed_totals if dim_totals for total in dim_totals] - if not insight.has_row_and_col_totals(): + if not visualization.has_row_and_col_totals(): return totals - new_totals = _get_additional_totals(insight, dimensions) + new_totals = _get_additional_totals(visualization, dimensions) return totals + new_totals -def _get_exec_for_pivot(insight: Insight) -> ExecutionDefinition: - dimensions = _create_dimensions(insight) - totals = _get_computable_totals(insight, dimensions) +def _get_exec_for_pivot(visualization: Visualization) -> ExecutionDefinition: + dimensions = _create_dimensions(visualization) + totals = _get_computable_totals(visualization, dimensions) return ExecutionDefinition( - attributes=[a.as_computable() for a in insight.attributes], - metrics=[m.as_computable() for m in insight.metrics], - filters=[cf for cf in [f.as_computable() for f in insight.filters] if not cf.is_noop()], + attributes=[a.as_computable() for a in visualization.attributes], + metrics=[m.as_computable() for m in visualization.metrics], + filters=[cf for cf in [f.as_computable() for f in visualization.filters] if not cf.is_noop()], dimensions=[d.item_ids for d in dimensions], totals=totals, ) -def get_exec_for_non_pivot(insight: Insight) -> ExecutionDefinition: +def get_exec_for_non_pivot(visualization: Visualization) -> ExecutionDefinition: return _prepare_tabular_definition( - attributes=[a.as_computable() for a in insight.attributes], - metrics=[m.as_computable() for m in insight.metrics], - filters=[cf for cf in [f.as_computable() for f in insight.filters] if not cf.is_noop()], + attributes=[a.as_computable() for a in visualization.attributes], + metrics=[m.as_computable() for m in visualization.metrics], + filters=[cf for cf in [f.as_computable() for f in visualization.filters] if not cf.is_noop()], ) @@ -530,16 +542,25 @@ class TableService: def __init__(self, api_client: GoodDataApiClient) -> None: self._compute = ComputeService(api_client) - def for_insight(self, workspace_id: str, insight: Insight) -> ExecutionTable: - # Assume the received insight is a pivot table if it contains row ("attribute") bucket + def for_visualization(self, workspace_id: str, visualization: Visualization) -> ExecutionTable: + # Assume the received visualization is a pivot table if it contains row ("attribute") bucket exec_def = ( - _get_exec_for_pivot(insight) - if insight.has_bucket_of_type(BucketType.ROWS) - else get_exec_for_non_pivot(insight) + _get_exec_for_pivot(visualization) + if visualization.has_bucket_of_type(BucketType.ROWS) + else get_exec_for_non_pivot(visualization) ) response = self._compute.for_exec_def(workspace_id=workspace_id, exec_def=exec_def) return _as_table(response) + def for_insight(self, workspace_id: str, insight: Insight) -> ExecutionTable: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use 'for_visualization' method instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.for_visualization(workspace_id=workspace_id, visualization=insight) + def for_items( self, workspace_id: str, items: list[Union[Attribute, Metric]], filters: Optional[list[Filter]] = None ) -> ExecutionTable: diff --git a/gooddata-sdk/gooddata_sdk/insight.py b/gooddata-sdk/gooddata_sdk/visualization.py similarity index 70% rename from gooddata-sdk/gooddata_sdk/insight.py rename to gooddata-sdk/gooddata_sdk/visualization.py index 0cd9f382a..98108348a 100644 --- a/gooddata-sdk/gooddata_sdk/insight.py +++ b/gooddata-sdk/gooddata_sdk/visualization.py @@ -5,6 +5,7 @@ from collections import defaultdict from enum import Enum from typing import Any, Optional, Union, cast +from warnings import warn from gooddata_sdk.client import GoodDataApiClient from gooddata_sdk.compute.model.attribute import Attribute @@ -31,8 +32,10 @@ from gooddata_sdk.utils import IdObjType, SideLoads, load_all_entities, safeget # -# Conversion from types stored in insight into the goodata_afm_client models. Insight is created by GD.UI SDK -# and is persisted in the freeform 'vis object' in the metadata. The types from SDK model are stored there. +# Conversion from types stored in visualization into the gooddata_afm_client models. +# Visualization is created by GD.UI SDK +# and is persisted in the freeform 'vis object' in the metadata. +# The types from SDK model are stored there. # _GRANULARITY_CONVERSION = { @@ -76,7 +79,7 @@ class BucketType(Enum): """ - Enum used for differentiating between types of Insight buckets. + Enum used for differentiating between types of Visualization buckets. """ UNDEFINED = 0 @@ -260,9 +263,9 @@ def _convert_metric_to_computable(metric: dict[str, Any]) -> Metric: # -class InsightMetric: +class VisualizationMetric: """ - Represents metric placed on an insight. + Represents metric placed on a visualization. Note: this has different shape than object passed to execution. """ @@ -330,7 +333,7 @@ def __repr__(self) -> str: return f"metric(local_id={self.local_id})" -class InsightAttribute: +class VisualizationAttribute: def __init__(self, attribute: dict[str, Any]) -> None: self._attribute = attribute self._a: dict[str, Any] = attribute["attribute"] @@ -365,7 +368,7 @@ def __repr__(self) -> str: return f"attribute(local_id={self.local_id}, show_all_values={self.show_all_values})" -class InsightTotal: +class VisualizationTotal: def __init__(self, total: dict[str, Any]) -> None: self._t = total @@ -388,7 +391,7 @@ def __repr__(self) -> str: return f"total(type={self.type}, measureIdentifier={self.measure_id}, attributeIdentifier={self.attribute_id})" -class InsightFilter: +class VisualizationFilter: def __init__(self, f: dict[str, Any]) -> None: self._filter = f @@ -402,12 +405,12 @@ def __repr__(self) -> str: return repr(self._filter) -class InsightBucket: +class VisualizationBucket: def __init__(self, bucket: dict[str, Any]) -> None: self._b = bucket - self._metrics: Optional[list[InsightMetric]] = None - self._attributes: Optional[list[InsightAttribute]] = None - self._totals: Optional[list[InsightTotal]] = None + self._metrics: Optional[list[VisualizationMetric]] = None + self._attributes: Optional[list[VisualizationAttribute]] = None + self._totals: Optional[list[VisualizationTotal]] = None self.type = _LOCAL_ID_TO_BUCKET_TYPE[self.local_id] @property @@ -419,23 +422,23 @@ def items(self) -> list[dict[str, Any]]: return self._b["items"] @property - def metrics(self) -> list[InsightMetric]: + def metrics(self) -> list[VisualizationMetric]: if self._metrics is None: - self._metrics = [InsightMetric(item) for item in self.items if "measure" in item] + self._metrics = [VisualizationMetric(item) for item in self.items if "measure" in item] return self._metrics @property - def attributes(self) -> list[InsightAttribute]: + def attributes(self) -> list[VisualizationAttribute]: if self._attributes is None: - self._attributes = [InsightAttribute(item) for item in self.items if "attribute" in item] + self._attributes = [VisualizationAttribute(item) for item in self.items if "attribute" in item] return self._attributes @property - def totals(self) -> list[InsightTotal]: + def totals(self) -> list[VisualizationTotal]: if self._totals is None: - self._totals = [InsightTotal(total) for total in self._b["totals"]] if "totals" in self._b else [] + self._totals = [VisualizationTotal(total) for total in self._b["totals"]] if "totals" in self._b else [] return self._totals @@ -446,14 +449,14 @@ def __repr__(self) -> str: return f"bucket(local_id={self.local_id}, items_count={len(self.items)}, total_count={len(self.totals)})" -class Insight: +class Visualization: def __init__( self, from_vis_obj: dict[str, Any], side_loads: Optional[SideLoads] = None, ) -> None: self._vo = from_vis_obj - self._filters = [InsightFilter(f) for f in self._vo["attributes"]["content"]["filters"]] + self._filters = [VisualizationFilter(f) for f in self._vo["attributes"]["content"]["filters"]] self._side_loads = SideLoads([]) if side_loads is None else side_loads @property @@ -474,15 +477,15 @@ def are_relations_valid(self) -> str: return self._vo["attributes"].get("areRelationsValid", "true") @property - def buckets(self) -> list[InsightBucket]: - return [InsightBucket(b) for b in self._vo["attributes"]["content"]["buckets"]] + def buckets(self) -> list[VisualizationBucket]: + return [VisualizationBucket(b) for b in self._vo["attributes"]["content"]["buckets"]] @property - def filters(self) -> list[InsightFilter]: + def filters(self) -> list[VisualizationFilter]: return self._filters @filters.setter - def filters(self, filters: list[InsightFilter]) -> None: + def filters(self, filters: list[VisualizationFilter]) -> None: self._filters = filters @property @@ -498,19 +501,19 @@ def vis_url(self) -> str: return self._vo["attributes"]["content"]["visualizationUrl"] @property - def metrics(self) -> list[InsightMetric]: + def metrics(self) -> list[VisualizationMetric]: return [m for b in self.buckets for m in b.metrics] @property - def attributes(self) -> list[InsightAttribute]: + def attributes(self) -> list[VisualizationAttribute]: return [a for b in self.buckets for a in b.attributes] - def get_bucket_of_type(self, bucket_type: BucketType) -> InsightBucket: + def get_bucket_of_type(self, bucket_type: BucketType) -> VisualizationBucket: for b in self.buckets: if b.type == bucket_type: return b # Return empty bucket if not found - return InsightBucket({"items": [], "localIdentifier": _BUCKET_TYPE_TO_LOCAL_ID[bucket_type]}) + return VisualizationBucket({"items": [], "localIdentifier": _BUCKET_TYPE_TO_LOCAL_ID[bucket_type]}) def has_bucket_of_type(self, bucket_type: BucketType) -> bool: for b in self.buckets: @@ -531,25 +534,29 @@ def get_metadata(self, id_obj: IdObjType) -> Optional[Any]: if not self._side_loads: return None - # otherwise try to use the id object as is + # otherwise, try to use the id object as is return self._side_loads.find(id_obj) def __str__(self) -> str: return self.__repr__() def __repr__(self) -> str: - return f"insight(title='{self.title}', id='{self.id}', buckets='{str(self.buckets)}')'" + return f"visualization(title='{self.title}', id='{self.id}', buckets='{str(self.buckets)}')'" -class InsightService: +class VisualizationService: """ - Insight Service allows retrieval of insights from a local GD workspace. The insights are returned as instances of - Insight which allows convenient introspection and necessary functions to convert the insight into a form where it + Visualization Service allows retrieval of visualizations from a local GD workspace. + The visualizations are returned as instances of + Visualization, + which allows convenient introspection and necessary functions to convert the visualization into a form where it can be sent for computation. - Note: the insights are created using GD Analytical Designer or using GoodData.UI SDK. They are stored as - visualization objects with a free-form body. This body is specific for AD & SDK. - The Insight wrapper exists to take care of these discrepancies. + Note: the visualizations are created using GD Analytical Designer or using GoodData.UI SDK. + They are stored as + visualization objects with a free-form body. + This body is specific for AD & SDK. + The Visualization wrapper exists to take care of these discrepancies. """ # Note on the disabled checking: @@ -561,17 +568,19 @@ class InsightService: def __init__(self, api_client: GoodDataApiClient) -> None: self._entities_api = api_client.entities_api - def get_insights(self, workspace_id: str) -> list[Insight]: + def get_visualizations(self, workspace_id: str) -> list[Visualization]: """ - Gets all insights for a workspace. The insights will contain side loaded metadata for all execution entities + Gets all visualizations for a workspace. + The visualizations will contain side loaded metadata for all execution entities that they reference. Args: workspace_id (str): Workspace identification string e.g. "demo" Returns: - list[Insight]: - All available insights, each insight will contain side loaded metadata about the entities it references + list[Visualization]: + All available visualizations, + each visualization will contain side loaded metadata about the entities it references """ get_func = functools.partial( self._entities_api.get_all_entities_visualization_objects, @@ -583,27 +592,129 @@ def get_insights(self, workspace_id: str) -> list[Insight]: vis_objects = load_all_entities(get_func) side_loads = SideLoads(vis_objects.included) - return [Insight(vis_obj, side_loads) for vis_obj in vis_objects.data] + return [Visualization(vis_obj, side_loads) for vis_obj in vis_objects.data] - def get_insight(self, workspace_id: str, insight_id: str) -> Insight: - """Gets a single insight from a workspace. + def get_visualization(self, workspace_id: str, visualization_id: str) -> Visualization: + """Gets a single visualization from a workspace. Args: workspace_id (str): Workspace identification string e.g. "demo" - insight_id (str): - Insight identifier string e.g. "bikes" + visualization_id (str): + Visualization identifier string e.g. "bikes" Returns: - Insight: - A single Insight object contains side loaded metadata about the entities it references + Visualization: + A single visualization object contains side loaded metadata about the entities it references """ vis_obj = self._entities_api.get_entity_visualization_objects( workspace_id, - object_id=insight_id, + object_id=visualization_id, include=["ALL"], _check_return_type=False, ) side_loads = SideLoads(vis_obj.included) - return Insight(vis_obj.data, side_loads) + return Visualization(vis_obj.data, side_loads) + + def get_insights(self, workspace_id: str) -> list[Visualization]: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use 'get_visualizations' method instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.get_visualizations(workspace_id) + + def get_insight(self, workspace_id: str, insight_id: str) -> Visualization: + warn( + "This method is deprecated and it will be removed in v1.20.0 release. " + "Please use 'get_visualization' method instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.get_visualization(workspace_id, insight_id) + + +# Note: the classes below are going to be deprecated + + +class InsightMetric(VisualizationMetric): + def __init__(self, metric: dict[str, Any]) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationMetric' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(metric) + + +class InsightAttribute(VisualizationAttribute): + def __init__(self, attribute: dict[str, Any]) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationAttribute' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(attribute) + + +class InsightTotal(VisualizationTotal): + def __init__(self, total: dict[str, Any]) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationTotal' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(total) + + +class InsightFilter(VisualizationFilter): + def __init__(self, f: dict[str, Any]) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationFilter' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(f) + + +class InsightBucket(VisualizationBucket): + def __init__(self, bucket: dict[str, Any]) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationBucket' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(bucket) + + +class Insight(Visualization): + def __init__( + self, + from_vis_obj: dict[str, Any], + side_loads: Optional[SideLoads] = None, + ) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'Visualization' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(from_vis_obj, side_loads) + + +class InsightService(VisualizationService): + def __init__(self, api_client: GoodDataApiClient) -> None: + warn( + "This class is deprecated and it will be removed in v1.20.0 release. " + "Please use 'VisualizationService' class instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(api_client) diff --git a/gooddata-sdk/tests/export/fixtures/test_export_csv_by_insight_id.yaml b/gooddata-sdk/tests/export/fixtures/test_export_csv_by_visualization_id.yaml similarity index 100% rename from gooddata-sdk/tests/export/fixtures/test_export_csv_by_insight_id.yaml rename to gooddata-sdk/tests/export/fixtures/test_export_csv_by_visualization_id.yaml diff --git a/gooddata-sdk/tests/export/fixtures/test_export_excel_by_insight_id.yaml b/gooddata-sdk/tests/export/fixtures/test_export_excel_by_visualization_id.yaml similarity index 100% rename from gooddata-sdk/tests/export/fixtures/test_export_excel_by_insight_id.yaml rename to gooddata-sdk/tests/export/fixtures/test_export_excel_by_visualization_id.yaml diff --git a/gooddata-sdk/tests/export/test_export_service.py b/gooddata-sdk/tests/export/test_export_service.py index 6eca38087..b134796d3 100644 --- a/gooddata-sdk/tests/export/test_export_service.py +++ b/gooddata-sdk/tests/export/test_export_service.py @@ -70,14 +70,14 @@ def _tabular_export_base(test_config, export_format: str): _validate_clean(goal_path) -def _tabular_by_insight_id_base(test_config, export_format: str): +def _tabular_by_visualization_id_base(test_config, export_format: str): sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) workspace_id = test_config["workspace"] - insight_id = test_config["insight_id"] - insight_name = test_config["insight_name"] - goal_path = _exports_dir / f"{insight_name}.{export_format.lower()}" - sdk.export.export_tabular_by_insight_id( - workspace_id=workspace_id, insight_id=insight_id, file_format=export_format, store_path=_exports_dir + visualization_id = test_config["visualization_id"] + visualization_name = test_config["visualization_name"] + goal_path = _exports_dir / f"{visualization_name}.{export_format.lower()}" + sdk.export.export_tabular_by_visualization_id( + workspace_id=workspace_id, visualization_id=visualization_id, file_format=export_format, store_path=_exports_dir ) _validate_clean(goal_path) @@ -92,11 +92,11 @@ def test_export_excel(test_config): _tabular_export_base(test_config, "XLSX") -@gd_vcr.use_cassette(str(_fixtures_dir / "test_export_csv_by_insight_id.yaml")) -def test_export_by_insight_id_csv(test_config): - _tabular_by_insight_id_base(test_config, "CSV") +@gd_vcr.use_cassette(str(_fixtures_dir / "test_export_csv_by_visualization_id.yaml")) +def test_export_by_visualization_id_csv(test_config): + _tabular_by_visualization_id_base(test_config, "CSV") -@gd_vcr.use_cassette(str(_fixtures_dir / "test_export_excel_by_insight_id.yaml")) -def test_export_by_insight_id_excel(test_config): - _tabular_by_insight_id_base(test_config, "XLSX") +@gd_vcr.use_cassette(str(_fixtures_dir / "test_export_excel_by_visualization_id.yaml")) +def test_export_by_visualization_id_excel(test_config): + _tabular_by_visualization_id_base(test_config, "XLSX") diff --git a/gooddata-sdk/tests/gd_test_config.yaml b/gooddata-sdk/tests/gd_test_config.yaml index 80fb96917..7951b884d 100644 --- a/gooddata-sdk/tests/gd_test_config.yaml +++ b/gooddata-sdk/tests/gd_test_config.yaml @@ -18,5 +18,5 @@ demo_user: "demo" admin_user_group: "adminGroup" bigquery_token: "eyJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsICJwcm9qZWN0X2lkIjogIlBST0pFQ1RfSUQiLCAicHJpdmF0ZV9rZXlfaWQiOiAiS0VZX0lEIiwgInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuUFJJVkFURV9LRVlcbi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS1cbiIsICJjbGllbnRfZW1haWwiOiAiU0VSVklDRV9BQ0NPVU5UX0VNQUlMIiwgImNsaWVudF9pZCI6ICJDTElFTlRfSUQiLCAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL2F1dGgiLCAidG9rZW5fdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwgImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3JvYm90L3YxL21ldGFkYXRhL3g1MDkvU0VSVklDRV9BQ0NPVU5UX0VNQUlMIn0=" bigquery_token_file: '{"type": "service_account", "project_id": "PROJECT_ID", "private_key_id": "KEY_ID", "private_key": "-----BEGIN PRIVATE KEY-----\\nPRIVATE_KEY\\n-----END PRIVATE KEY-----\\n", "client_email": "SERVICE_ACCOUNT_EMAIL", "client_id": "CLIENT_ID", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/SERVICE_ACCOUNT_EMAIL"}' -insight_id: "customers_trend" -insight_name: "Customers Trend" +visualization_id: "customers_trend" +visualization_name: "Customers Trend" diff --git a/gooddata-sdk/tests/overview.md b/gooddata-sdk/tests/overview.md index 7bef4faec..434bdf12b 100644 --- a/gooddata-sdk/tests/overview.md +++ b/gooddata-sdk/tests/overview.md @@ -7,7 +7,7 @@ to simplify assertions in tests that verify different conversion logic. ## Unit tests with snapshots Check out the documentation of [pytest-snapshot](https://pypi.org/project/pytest-snapshot/) to learn more and then look at -some of the test for [compute_model](./compute_model) or [insight](./insight) to compute model conversions. +some of the test for [compute_model](./compute_model) or [visualization](./visualization) to compute model conversions. There are three important things to remember: @@ -27,7 +27,7 @@ There are three important things to remember: ### Type conversion tests -There are a bunch of tests in [compute_model](./compute_model) and [insight](./insight) whose purpose is to verify +There are a bunch of tests in [compute_model](./compute_model) and [insight](./visualization) whose purpose is to verify that conversion from internal models to the API models (stored in gooddata-api-client) work as intended. diff --git a/gooddata-sdk/tests/table/test_table.py b/gooddata-sdk/tests/table/test_table.py index 11f65e7d2..4f07cd156 100644 --- a/gooddata-sdk/tests/table/test_table.py +++ b/gooddata-sdk/tests/table/test_table.py @@ -7,7 +7,7 @@ import pytest from tests_support.vcrpy_utils import get_vcr -from gooddata_sdk import Attribute, GoodDataSdk, Insight, ObjId, PositiveAttributeFilter, SimpleMetric, table +from gooddata_sdk import Attribute, GoodDataSdk, ObjId, PositiveAttributeFilter, SimpleMetric, Visualization, table gd_vcr = get_vcr() @@ -22,7 +22,7 @@ def load_json(path): return json.load(f) -def _insight_filename_to_snapshot_name(path): +def _visualization_filename_to_snapshot_name(path): return path.name.replace(".json", ".snapshot.json") @@ -132,9 +132,9 @@ def test_pivot_to_exec_def(filename, snapshot): 1cattr = 1 additional col attributes """ vis_obj = load_json(filename) - insight = Insight(vis_obj) + visualization = Visualization(vis_obj) - exec_def = table._get_exec_for_pivot(insight) + exec_def = table._get_exec_for_pivot(visualization) result = exec_def.as_api_model().to_dict() snapshot.snapshot_dir = _snapshot_dir diff --git a/gooddata-sdk/tests/insight/__init__.py b/gooddata-sdk/tests/visualization/__init__.py similarity index 100% rename from gooddata-sdk/tests/insight/__init__.py rename to gooddata-sdk/tests/visualization/__init__.py diff --git a/gooddata-sdk/tests/insight/fixtures.py b/gooddata-sdk/tests/visualization/fixtures.py similarity index 100% rename from gooddata-sdk/tests/insight/fixtures.py rename to gooddata-sdk/tests/visualization/fixtures.py diff --git a/gooddata-sdk/tests/insight/resources/one_metric_date_attribute_show_all_values.json b/gooddata-sdk/tests/visualization/resources/one_metric_date_attribute_show_all_values.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/one_metric_date_attribute_show_all_values.json rename to gooddata-sdk/tests/visualization/resources/one_metric_date_attribute_show_all_values.json diff --git a/gooddata-sdk/tests/insight/resources/one_metric_two_attributes.json b/gooddata-sdk/tests/visualization/resources/one_metric_two_attributes.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/one_metric_two_attributes.json rename to gooddata-sdk/tests/visualization/resources/one_metric_two_attributes.json diff --git a/gooddata-sdk/tests/insight/resources/single_attribute.json b/gooddata-sdk/tests/visualization/resources/single_attribute.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/single_attribute.json rename to gooddata-sdk/tests/visualization/resources/single_attribute.json diff --git a/gooddata-sdk/tests/insight/resources/two_metrics_multiple_attribute_buckets.json b/gooddata-sdk/tests/visualization/resources/two_metrics_multiple_attribute_buckets.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/two_metrics_multiple_attribute_buckets.json rename to gooddata-sdk/tests/visualization/resources/two_metrics_multiple_attribute_buckets.json diff --git a/gooddata-sdk/tests/insight/resources/with_arithmetic_metric.json b/gooddata-sdk/tests/visualization/resources/with_arithmetic_metric.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_arithmetic_metric.json rename to gooddata-sdk/tests/visualization/resources/with_arithmetic_metric.json diff --git a/gooddata-sdk/tests/insight/resources/with_attribute_filters.json b/gooddata-sdk/tests/visualization/resources/with_attribute_filters.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_attribute_filters.json rename to gooddata-sdk/tests/visualization/resources/with_attribute_filters.json diff --git a/gooddata-sdk/tests/insight/resources/with_date_filters.json b/gooddata-sdk/tests/visualization/resources/with_date_filters.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_date_filters.json rename to gooddata-sdk/tests/visualization/resources/with_date_filters.json diff --git a/gooddata-sdk/tests/insight/resources/with_funky_attribute_filters.json b/gooddata-sdk/tests/visualization/resources/with_funky_attribute_filters.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_funky_attribute_filters.json rename to gooddata-sdk/tests/visualization/resources/with_funky_attribute_filters.json diff --git a/gooddata-sdk/tests/insight/resources/with_metric_value_filter.json b/gooddata-sdk/tests/visualization/resources/with_metric_value_filter.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_metric_value_filter.json rename to gooddata-sdk/tests/visualization/resources/with_metric_value_filter.json diff --git a/gooddata-sdk/tests/insight/resources/with_pop_metric.json b/gooddata-sdk/tests/visualization/resources/with_pop_metric.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_pop_metric.json rename to gooddata-sdk/tests/visualization/resources/with_pop_metric.json diff --git a/gooddata-sdk/tests/insight/resources/with_previous_period_metric.json b/gooddata-sdk/tests/visualization/resources/with_previous_period_metric.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_previous_period_metric.json rename to gooddata-sdk/tests/visualization/resources/with_previous_period_metric.json diff --git a/gooddata-sdk/tests/insight/resources/with_ranking_filter.json b/gooddata-sdk/tests/visualization/resources/with_ranking_filter.json similarity index 100% rename from gooddata-sdk/tests/insight/resources/with_ranking_filter.json rename to gooddata-sdk/tests/visualization/resources/with_ranking_filter.json diff --git a/gooddata-sdk/tests/insight/snapshots/one_metric_date_attribute_show_all_values.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/one_metric_date_attribute_show_all_values.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/one_metric_date_attribute_show_all_values.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/one_metric_date_attribute_show_all_values.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/one_metric_two_attributes.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/one_metric_two_attributes.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/one_metric_two_attributes.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/one_metric_two_attributes.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/single_attribute.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/single_attribute.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/single_attribute.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/single_attribute.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/two_metrics_multiple_attribute_buckets.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/two_metrics_multiple_attribute_buckets.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/two_metrics_multiple_attribute_buckets.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/two_metrics_multiple_attribute_buckets.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_arithmetic_metric.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_arithmetic_metric.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_arithmetic_metric.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_arithmetic_metric.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_attribute_filters.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_attribute_filters.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_attribute_filters.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_attribute_filters.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_date_filters.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_date_filters.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_date_filters.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_date_filters.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_funky_attribute_filters.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_funky_attribute_filters.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_funky_attribute_filters.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_funky_attribute_filters.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_metric_value_filter.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_metric_value_filter.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_metric_value_filter.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_metric_value_filter.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_pop_metric.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_pop_metric.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_pop_metric.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_pop_metric.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_previous_period_metric.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_previous_period_metric.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_previous_period_metric.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_previous_period_metric.snapshot.json diff --git a/gooddata-sdk/tests/insight/snapshots/with_ranking_filter.snapshot.json b/gooddata-sdk/tests/visualization/snapshots/with_ranking_filter.snapshot.json similarity index 100% rename from gooddata-sdk/tests/insight/snapshots/with_ranking_filter.snapshot.json rename to gooddata-sdk/tests/visualization/snapshots/with_ranking_filter.snapshot.json diff --git a/gooddata-sdk/tests/insight/test_insight.py b/gooddata-sdk/tests/visualization/test_visualization.py similarity index 67% rename from gooddata-sdk/tests/insight/test_insight.py rename to gooddata-sdk/tests/visualization/test_visualization.py index 15f5ee30e..5e7427d15 100644 --- a/gooddata-sdk/tests/insight/test_insight.py +++ b/gooddata-sdk/tests/visualization/test_visualization.py @@ -6,34 +6,34 @@ import pytest -from gooddata_sdk import Insight +from gooddata_sdk import Visualization from gooddata_sdk.compute.model.execution import compute_model_to_api_model -from tests.insight.fixtures import load_vis_obj +from tests.visualization.fixtures import load_vis_obj _current_dir = os.path.dirname(os.path.abspath(__file__)) _resources_dir = os.path.join(_current_dir, "resources") -def _insight_filename_to_snapshot_name(absolute_path): +def _visualization_filename_to_snapshot_name(absolute_path): return os.path.basename(absolute_path).replace(".json", ".snapshot.json") @pytest.mark.parametrize("filename", [os.path.join(_resources_dir, d) for d in os.listdir(_resources_dir)]) def test_attribute_filters_to_api_model(filename, snapshot): vis_obj = load_vis_obj(filename) - insight = Insight(vis_obj) + visualization = Visualization(vis_obj) # it is essential to define snapshot dir using absolute path, otherwise snapshots cannot be found when # running in tox snapshot.snapshot_dir = os.path.join(_current_dir, "snapshots") - attributes = [a.as_computable() for a in insight.attributes] - metrics = [m.as_computable() for m in insight.metrics] - filters = [f.as_computable() for f in insight.filters] + attributes = [a.as_computable() for a in visualization.attributes] + metrics = [m.as_computable() for m in visualization.metrics] + filters = [f.as_computable() for f in visualization.filters] afm = compute_model_to_api_model(attributes, metrics, filters) snapshot.assert_match( json.dumps(afm.to_dict(), indent=4, sort_keys=True), - _insight_filename_to_snapshot_name(filename), + _visualization_filename_to_snapshot_name(filename), )