From 8db90b07b697ab84a22bf876cab6455e31db24ea Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Tue, 31 Jan 2023 17:04:06 +0100 Subject: [PATCH 01/22] Update README.md --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 63d0a2e..3afd8fa 100644 --- a/README.md +++ b/README.md @@ -248,5 +248,18 @@ tables = model.Tables[TABLE_NAME].Related() tables.Refresh() ``` +## Documenting a Model + +Args: +- Docs Location: +- Friendly Name: + +### Refreshing a Power BI Premium Model + +### Refreshing a Analysis Server Model + +### Refreshing a Power BI > Local Model. +- The Local model doesn't have a name, only an Id. So we need to Supply a "Friendly Name". + ### Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) \ No newline at end of file +See [CONTRIBUTING.md](CONTRIBUTING.md) From e82f137859d7ad0d1cbf6be21c36a547921c3a9d Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Tue, 7 Feb 2023 21:47:54 +0100 Subject: [PATCH 02/22] Update README.md --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3afd8fa..7d5dc92 100644 --- a/README.md +++ b/README.md @@ -251,15 +251,54 @@ tables.Refresh() ## Documenting a Model Args: -- Docs Location: -- Friendly Name: +```python +model: Tabular, +friendly_name: str = str(), +save_location: str = "docs", +general_page_url: str = "1-general-information.md", +measure_page_url: str = "2-measures.md", +table_page_url: str = "3-tables.md", +column_page_url: str = "4-columns.md", +roles_page_url: str = "5-roles.md", +``` + +### Documenting a Power BI Premium Model +```python +import pytabular +import logging -### Refreshing a Power BI Premium Model +logger = logging.getLogger("PyTabular") +model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") -### Refreshing a Analysis Server Model +docs = pytabular.ModelDocumenter(model) +docs.set_transalation(True, 'en-US') +docs.save_documentation() +``` + +### Documenting a Analysis Server Model +```python +import pytabular -### Refreshing a Power BI > Local Model. +# Connect to the Analysis Server Model +model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") + +# Initiate the Docs +docs = pytabular.ModelDocumenter(model) + +# Save docs to the default location +docs.save_documentation() +``` +### Documenting a Power BI > Local Model. - The Local model doesn't have a name, only an Id. So we need to Supply a "Friendly Name". +```python +import pytabular +import logging + +logger = logging.getLogger("PyTabular") +model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") +docs = pytabular.ModelDocumenter(model) +docs.save_documentation() +``` ### Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) From b9f83594b14e5333612014887b833df7ae97df66 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Tue, 7 Feb 2023 22:00:53 +0100 Subject: [PATCH 03/22] Update README.md --- README.md | 66 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7d5dc92..145a5fa 100644 --- a/README.md +++ b/README.md @@ -249,55 +249,81 @@ tables.Refresh() ``` ## Documenting a Model - +The Tabular model co Args: -```python -model: Tabular, -friendly_name: str = str(), -save_location: str = "docs", -general_page_url: str = "1-general-information.md", -measure_page_url: str = "2-measures.md", -table_page_url: str = "3-tables.md", -column_page_url: str = "4-columns.md", -roles_page_url: str = "5-roles.md", -``` +- **model**: Tabular, +- **friendly_name**: str = str(), + +To specify the location of the docs, just supply the save location with a new folder name argument. +- **save_location**: str = "docs", + +Each page in the generation process has it's own specific name, with these arguments you can rename them to your liking. +- **general_page_url**: str = "1-general-information.md", +- **measure_page_url**: str = "2-measures.md", +- **table_page_url**: str = "3-tables.md", +- **column_page_url**: str = "4-columns.md", +- **roles_page_url**: str = "5-roles.md", + +### Documenting a Model +The simpelst way to document a tabular model is to connect to the model, and initialize the documentation and execute `save_documentation()`. -### Documenting a Power BI Premium Model ```python import pytabular -import logging -logger = logging.getLogger("PyTabular") +# Connect to a Tabular Model Model model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") +# Initiate the Docs docs = pytabular.ModelDocumenter(model) -docs.set_transalation(True, 'en-US') + +# Save docs to the default location docs.save_documentation() ``` -### Documenting a Analysis Server Model + +### Documenting a Model with Cultures +Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'). + ```python import pytabular -# Connect to the Analysis Server Model +# Connect to a Tabular Model Model model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") # Initiate the Docs docs = pytabular.ModelDocumenter(model) +# Set the translation for documentation to an available culture. +docs = pytabular.ModelDocumenter(model) + +# By setting the Tranlsations to `True` it will check if it exists and if it does, +# it will start using the translations for the docs +docs.set_transalation( + enable_translations=True, + culture = 'en-US' + ) + # Save docs to the default location docs.save_documentation() ``` ### Documenting a Power BI > Local Model. -- The Local model doesn't have a name, only an Id. So we need to Supply a "Friendly Name". +The Local model doesn't have a name, only an Id. So we need to Supply a "Friendly Name", which will be used to store the markdown files. ```python import pytabular -import logging -logger = logging.getLogger("PyTabular") +# Connect to a Tabular Model Model model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") +# Initiate the Docs docs = pytabular.ModelDocumenter(model) + +# Set the translation for documentation to an available culture. +docs = pytabular.ModelDocumenter( + model = model, + friendly_name = "Adventure Works" +) + +# Save docs to the default location docs.save_documentation() ``` ### Contributing From adb0541ee37d3d1ecb539c3f7301e7af64bffbcd Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Tue, 7 Feb 2023 22:10:13 +0100 Subject: [PATCH 04/22] Update README.md --- README.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 145a5fa..9ef741b 100644 --- a/README.md +++ b/README.md @@ -249,20 +249,23 @@ tables.Refresh() ``` ## Documenting a Model -The Tabular model co +The Tabular model contains a lot of information that can be used to generation documentation if filled in. Currently the markdown files are generated with the Docusaurs heading in place, but this will be changed in future to support multiple documentation platforms. + +**Tip**: With Tabular Editor 2 (Free) or 3 (Paid) you can easily add Descriptioms, Translations (Cultures) and other additonal information that can later be used for generating the documentation. + Args: -- **model**: Tabular, -- **friendly_name**: str = str(), +- **model**: Tabular +- **friendly_name**: Default > No Value To specify the location of the docs, just supply the save location with a new folder name argument. -- **save_location**: str = "docs", +- **save_location**: Default > docs Each page in the generation process has it's own specific name, with these arguments you can rename them to your liking. -- **general_page_url**: str = "1-general-information.md", -- **measure_page_url**: str = "2-measures.md", -- **table_page_url**: str = "3-tables.md", -- **column_page_url**: str = "4-columns.md", -- **roles_page_url**: str = "5-roles.md", +- **general_page_url**: Default > 1-general-information.md +- **measure_page_url**: Default > 2-measures.md +- **table_page_url**: Default > 3-tables.md +- **column_page_url**: Default > 4-columns.md +- **roles_page_url**: Default > 5-roles.md ### Documenting a Model The simpelst way to document a tabular model is to connect to the model, and initialize the documentation and execute `save_documentation()`. @@ -271,7 +274,7 @@ The simpelst way to document a tabular model is to connect to the model, and ini import pytabular # Connect to a Tabular Model Model -model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") +model = pytabular.Tabular(CONNECTION_STR) # Initiate the Docs docs = pytabular.ModelDocumenter(model) @@ -280,7 +283,6 @@ docs = pytabular.ModelDocumenter(model) docs.save_documentation() ``` - ### Documenting a Model with Cultures Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'). @@ -288,7 +290,7 @@ Some model creators choose to add cultures to a tabular model for different kind import pytabular # Connect to a Tabular Model Model -model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") +model = pytabular.Tabular(CONNECTION_STR) # Initiate the Docs docs = pytabular.ModelDocumenter(model) @@ -307,17 +309,14 @@ docs.set_transalation( docs.save_documentation() ``` ### Documenting a Power BI > Local Model. -The Local model doesn't have a name, only an Id. So we need to Supply a "Friendly Name", which will be used to store the markdown files. +The Local model doesn't have a "name", only an Id. So we need to Supply a "Friendly Name", which will be used to store the markdown files. ```python import pytabular # Connect to a Tabular Model Model -model = pytabular.Tabular(f"{SERVER};Catalog={INITIAL_CATALOG}") - -# Initiate the Docs -docs = pytabular.ModelDocumenter(model) +model = pytabular.Tabular(CONNECTION_STR) -# Set the translation for documentation to an available culture. +# Initiate the Docs and set a friendly name to store the markdown files. docs = pytabular.ModelDocumenter( model = model, friendly_name = "Adventure Works" From 238da72b9eb7c48dd21955d12cfd9594b3a49377 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:09:03 +0100 Subject: [PATCH 05/22] Update document.py --- pytabular/document.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pytabular/document.py b/pytabular/document.py index 332276d..6ce6f97 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -54,6 +54,7 @@ def __init__( self.table_page: str = str() self.column_page: str = str() self.roles_page: str = str() + self.category_page: str = str() self.category_file_name: str = "_category_.yml" self.general_page_url: str = general_page_url From fd37dbc32f8852ee5e24a2c0092cb732329893bf Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:18:21 +0100 Subject: [PATCH 06/22] Update README.md --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2befd34..d3f81c1 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,9 @@ model = pytabular.Tabular(CONNECTION_STR) # Initiate the Docs docs = pytabular.ModelDocumenter(model) +# Generate the pages. +docs.generate_documentation_pages() + # Save docs to the default location docs.save_documentation() ``` @@ -376,15 +379,16 @@ model = pytabular.Tabular(CONNECTION_STR) docs = pytabular.ModelDocumenter(model) # Set the translation for documentation to an available culture. -docs = pytabular.ModelDocumenter(model) - # By setting the Tranlsations to `True` it will check if it exists and if it does, # it will start using the translations for the docs -docs.set_transalation( - enable_translations=True, +docs.set_translations( + enable_translations = True, culture = 'en-US' ) +# Generate the pages. +docs.generate_documentation_pages() + # Save docs to the default location docs.save_documentation() ``` @@ -402,6 +406,9 @@ docs = pytabular.ModelDocumenter( friendly_name = "Adventure Works" ) +# Generate the pages. +docs.generate_documentation_pages() + # Save docs to the default location docs.save_documentation() ``` From 6e140ce113b210f948d6620b6a8a6f9efaf92886 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:20:14 +0100 Subject: [PATCH 07/22] Update document.py --- pytabular/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytabular/document.py b/pytabular/document.py index 6ce6f97..903e71f 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -54,7 +54,7 @@ def __init__( self.table_page: str = str() self.column_page: str = str() self.roles_page: str = str() - self.category_page: str = str() + self.category_page: str = str() self.category_file_name: str = "_category_.yml" self.general_page_url: str = general_page_url From b7d014bdfbf18bb7ba72b66628ab10bc17b7afb4 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:21:08 +0100 Subject: [PATCH 08/22] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d3f81c1..03abccc 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,9 @@ model = pytabular.Tabular(CONNECTION_STR) # Initiate the Docs docs = pytabular.ModelDocumenter(model) +# Generate the pages. +docs.generate_documentation_pages() + # Save docs to the default location docs.save_documentation() ``` @@ -170,6 +173,9 @@ docs.set_transalation( enable_translations = True, culture = 'en-US' ) + +# Generate the pages. +docs.generate_documentation_pages() # Save docs to the default location docs.save_documentation() @@ -189,6 +195,9 @@ docs = pytabular.ModelDocumenter( save_location = "my-docs-folder" ) +# Generate the pages. +docs.generate_documentation_pages() + # Save docs to the default location docs.save_documentation() ``` From e1e3b6a46c19ed30de01ad94d7170c6bb609d62a Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:24:23 +0100 Subject: [PATCH 09/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03abccc..ae2f9d0 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ docs.save_documentation() ``` #### Documenting a Model with Cultures -Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'). +Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'`). ```python import pytabular From 74a1dae91cfa9993b9406f57d55a7816a749d5c8 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Fri, 10 Feb 2023 16:27:26 +0100 Subject: [PATCH 10/22] Update README.md --- README.md | 91 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index ae2f9d0..76869aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # PyTabular [![PyPI version](https://badge.fury.io/py/python-tabular.svg)](https://badge.fury.io/py/python-tabular) [![Downloads](https://pepy.tech/badge/python-tabular)](https://pepy.tech/project/python-tabular) @@ -114,93 +113,6 @@ model.Tables['Table Name'].Columns['Column Name'].distinct_count() #or model.Tables['Table Name'].Columns['Column Name'].values() ``` -### Documenting a Model -The Tabular model contains a lot of information that can be used to generation documentation if filled in. Currently the markdown files are generated with the Docusaurs heading in place, but this will be changed in future to support multiple documentation platforms. - -**Tip**: With Tabular Editor 2 (Free) or 3 (Paid) you can easily add Descriptioms, Translations (Cultures) and other additonal information that can later be used for generating the documentation. - -#### Args: -- **model**: Tabular -- **friendly_name**: Default > No Value - -To specify the location of the docs, just supply the save location with a new folder name argument. -- **save_location**: Default > docs - -Each page in the generation process has it's own specific name, with these arguments you can rename them to your liking. -- **general_page_url**: Default > 1-general-information.md -- **measure_page_url**: Default > 2-measures.md -- **table_page_url**: Default > 3-tables.md -- **column_page_url**: Default > 4-columns.md -- **roles_page_url**: Default > 5-roles.md - -#### Documenting a Model -The simpelst way to document a tabular model is to connect to the model, and initialize the documentation and execute `save_documentation()`. - -```python -import pytabular - -# Connect to a Tabular Model Model -model = pytabular.Tabular(CONNECTION_STR) - -# Initiate the Docs -docs = pytabular.ModelDocumenter(model) - -# Generate the pages. -docs.generate_documentation_pages() - -# Save docs to the default location -docs.save_documentation() -``` - -#### Documenting a Model with Cultures -Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'`). - -```python -import pytabular - -# Connect to a Tabular Model Model -model = pytabular.Tabular(CONNECTION_STR) - -# Initiate the Docs -docs = pytabular.ModelDocumenter(model) - -# Set the translation for documentation to an available culture. -docs = pytabular.ModelDocumenter(model) - -# By setting the Tranlsations to `True` it will check if it exists and if it does, -# it will start using the translations for the docs -docs.set_transalation( - enable_translations = True, - culture = 'en-US' - ) - -# Generate the pages. -docs.generate_documentation_pages() - -# Save docs to the default location -docs.save_documentation() -``` -#### Documenting a Power BI Desktop Model -The Local model doesn't have a "name", only an Id. So we need to Supply a "Friendly Name", which will be used to store the markdown files. The result of this example with be a folder `my-docs-folder` with a subfolder `Adventure Works` where all the files are stored. -```python -import pytabular - -# Connect to a Tabular Model Model -model = pytabular.Tabular(CONNECTION_STR) - -# Initiate the Docs, set a friendly name to store the markdown files and overwrite the default location. -docs = pytabular.ModelDocumenter( - model = model, - friendly_name = "Adventure Works", - save_location = "my-docs-folder" -) - -# Generate the pages. -docs.generate_documentation_pages() - -# Save docs to the default location -docs.save_documentation() -``` ### Use Cases @@ -376,7 +288,7 @@ docs.save_documentation() ``` ### Documenting a Model with Cultures -Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'). +Some model creators choose to add cultures to a tabular model for different kinds of reasons. We can leverage those cultures to use the translation names instead of the original object names. In order to this you can set translations to `True` and specify the culture you want to use (e.g. `'en-US'`). ```python import pytabular @@ -421,5 +333,6 @@ docs.generate_documentation_pages() # Save docs to the default location docs.save_documentation() ``` + ### Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) From 9f8ea615d16ba84fb16fb310bbcc3a1a43301b05 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Sun, 12 Feb 2023 22:33:32 +0100 Subject: [PATCH 11/22] Refactored the documenting part, need to clean some more up. --- pytabular/document/__init__.py | 1 + pytabular/{ => document}/document.py | 355 +++++++++++++++------------ 2 files changed, 193 insertions(+), 163 deletions(-) create mode 100644 pytabular/document/__init__.py rename pytabular/{ => document}/document.py (67%) diff --git a/pytabular/document/__init__.py b/pytabular/document/__init__.py new file mode 100644 index 0000000..2e97d02 --- /dev/null +++ b/pytabular/document/__init__.py @@ -0,0 +1 @@ +# Check if needed to make sure the sub module works. \ No newline at end of file diff --git a/pytabular/document.py b/pytabular/document/document.py similarity index 67% rename from pytabular/document.py rename to pytabular/document/document.py index 1dc4b10..978ca01 100644 --- a/pytabular/document.py +++ b/pytabular/document/document.py @@ -6,16 +6,14 @@ from pathlib import Path -from measure import PyMeasure -from table import PyTable -from column import PyColumn -from culture import PyCulture - -from .pytabular import Tabular +from pytabular.table import PyTable +from pytabular.column import PyColumn +from pytabular.culture import PyCulture +from pytabular.measure import PyMeasure +from pytabular.pytabular import Tabular logger = logging.getLogger("PyTabular") - class ModelDocumenter: """The ModelDocumenter class can generate documentation. @@ -166,7 +164,7 @@ def save_page(self, content: str, page_name: str, keep_file: bool = False) -> No target_file = self.save_path / page_name if keep_file and target_file.exists(): - logger.info(f"{page_name} already exists -> fill will not overwritten.") + logger.info(f"{page_name} already exists -> file will not overwritten.") else: logger.info(f"Results are written to -> {page_name}.") @@ -255,50 +253,33 @@ def create_markdown_for_measure(self, object: PyMeasure) -> str: "\\n", "" ) - return f""" -### {object_caption} -**Description**: -> {object_description} - -
- -
Display Folder
-
{object.DisplayFolder}
- -
Table Name
-
{object.Parent.Name}
- -
Format String
-
{object.FormatString}
- -
Is Hidden
-
{object.IsHidden}
- -
- -```dax title="Technical: {object.Name}" -{ - object.Expression -} -``` - ---- -""" + object_properties = '' + + obj_text = [ + f"### {object_caption}", + "**Description**:", + f"> {object_description}", + "" + f"{object_properties}", + "", + f'```dax title="Technical: {object.Name}"', + f" {object.Expression}", + "```", + "---" + ] + return "\n".join(obj_text) def generate_markdown_measure_page(self) -> str: """Based on the measure objects it generates a measure page.""" prev_display_folder = "" markdown_template = [ - f"""--- -sidebar_position: 3 -title: Measures -description: This page contains all measures for the {self.model.Name} model, \ -including the description, \ -format string, and other technical details. ---- - -# Measures for {self.model.Name} -""" + "---", + "sidebar_position: 3", + "title: Measures", + f"description: This page contains all measures for the {self.model.Name} model, including the description, format string, and other technical details." + "---" + "", + f"# Measures for {self.model.Name}" ] measures = sorted( @@ -316,7 +297,7 @@ def generate_markdown_measure_page(self) -> str: markdown_template.append(self.create_markdown_for_measure(measure)) - return "".join(markdown_template) + return "\n".join(markdown_template) def create_markdown_for_table(self, object: PyTable) -> str: """This functions returns the markdown for a table. @@ -338,6 +319,32 @@ def create_markdown_for_table(self, object: PyTable) -> str: "\\n", "" ) + object_details = '' + """ +
+
Measures (#)
+
{len(object.Measures)}
+ +
Columns (#)
+
{len(object.Columns)}
+ +
Partitions (#)
+
{len(object.Partitions)}
+ +
Data Category
+
{object.DataCategory or "Regular Table"}
+ +
Is Hidden
+
{object.IsHidden}
+ +
Table Type
+
{object.Partitions[0].ObjectType}
+ +
Source Type
+
{object.Partitions[0].SourceType}
+
+ """ + partition_type = "" partition_source = "" @@ -351,86 +358,54 @@ def create_markdown_for_table(self, object: PyTable) -> str: partition_type = "sql" partition_source = object.Partitions[0].Source.Query - return f""" -### {object_caption} -**Description**: -> {object_description} - -
-
Measures (#)
-
{len(object.Measures)}
- -
Columns (#)
-
{len(object.Columns)}
- -
Partitions (#)
-
{len(object.Partitions)}
- -
Data Category
-
{object.DataCategory or "Regular Table"}
- -
Is Hidden
-
{object.IsHidden}
- -
Table Type
-
{object.Partitions[0].ObjectType}
- -
Source Type
-
{object.Partitions[0].SourceType}
-
- -```{partition_type} title="Table Source: {object.Name}" -{ - partition_source -} -``` - ---- - -""" + obj_text = [ + f"### {object_caption}", + "**Description**: ", + "> {object_description}", + "", + f"{object_details}", + "", + f"```{partition_type} title="Table Source: {object.Name}", + f" {partition_source}", + "```", + "---" + ] def generate_markdown_table_page(self) -> str: """This function generates the markdown tables documentation for the tables in the Model.""" - markdown_template = f"""--- -sidebar_position: 2 -title: Tables -description: This page contains all columns with tables for {self.model.Name}, \ -including the description, \ -and technical details. ---- - -# Tables {self.model.Name} - - """ + markdown_template = [ + "---", + "sidebar_position: 2", + "title: Tables", + f"description: This page contains all columns with tables for {self.model.Name}, including the description, and technical details.", + "---", + f"# Tables {self.model.Name}" + ] for table in self.model.Tables: - markdown_template += self.create_markdown_for_table(table) + markdown_template.append(self.create_markdown_for_table(table)) - return markdown_template + return "\n".join(markdown_template) def generate_markdown_column_page(self) -> str: """This function generates the markdown for documentation about columns in the Model.""" - markdown_template = f"""--- -sidebar_position: 4 -title: Columns -description: This page contains all columns with Columns for {self.model.Name}, \ -including the description, format string, and other technical details. ---- - - """ + markdown_template = [ + "---" + "sidebar_position: 4" + f"title: Columns description: This page contains all columns with Columns for {self.model.Name}, including the description, format string, and other technical details." + "---" + ] for table in self.model.Tables: - markdown_template += f""" -## Columns for {table.Name} - """ + markdown_template.append(f"## Columns for {table.Name}") for column in table.Columns: if "RowNumber" in column.Name: continue - markdown_template += self.create_markdown_for_column(column) + markdown_template.append(self.create_markdown_for_column(column)) - return markdown_template + return "\n".join(markdown_template) def create_markdown_for_column(self, object: PyColumn) -> str: """Generates the Markdown for a specifc column. @@ -445,73 +420,127 @@ def create_markdown_for_column(self, object: PyColumn) -> str: or object.Name ) - object_description = (object.Description or "No Description available").replace( - "\\n", "" - ) + object_description = object.Description.replace("\\n", "") or "No Description available" - basic_info = f""" -### {object_caption} {self.create_object_reference( - object=object.Name, - object_parent=object.Parent.Name - )} -**Description**: -> {object_description} + object_heading = f"""{object_caption} {self.create_object_reference( object=object.Name, object_parent=object.Parent.Name)}""" -
-
Column Name
-
{object.Name}
+ object_details = '' + """ +
+
Column Name
+
{object.Name}
-
Object Type
-
{object.ObjectType}
+
Object Type
+
{object.ObjectType}
-
Type
-
{object.Type}
+
Type
+
{object.Type}
-
Is Available In Excel
-
{object.IsAvailableInMDX}
+
Is Available In Excel
+
{object.IsAvailableInMDX}
-
Is Hidden
-
{object.IsHidden}
+
Is Hidden
+
{object.IsHidden}
-
Data Category
-
{object.DataCategory}
+
Data Category
+
{object.DataCategory}
-
Data Type
-
{object.DataType}
+
Data Type
+
{object.DataType}
-
DisplayFolder
-
{object.DisplayFolder}
+
DisplayFolder
+
{object.DisplayFolder}
-
-""" +
""" + obj_text = [ + f"### {object_heading}", + "**Description**:" + f"> {object_description}" + "", + f"{object_details}" + ] if str(object.Type) == "Calculated": - basic_info += f""" -```dax title="Technical: {object.Name}" -{ - object.Expression -} -``` - """ - return ( - basic_info - + """ ---- - """ - ) + obj_text.append[ + f"```dax title="Technical: {object.Name}", + f" {object.Expression}", + "```" + ] + obj_text.append("---") + + return "\n".join(obj_text) + def generate_category_file(self): """Docusaurs can generate an index. The category yaml will make that happen. """ - return f"""position: 2 # float position is supported -label: '{self.model_name}' -collapsible: true # make the category collapsible -collapsed: true # keep the category open by default -link: - type: generated-index - title: Documentation Overview -customProps: - description: To be added in the future. -""" + + obj_text = [ + "position: 2 # float position is supported", + f"label: '{self.model_name}'", + "collapsible: true # make the category collapsible", + "collapsed: true # keep the category open by default", + " link:", + " type: generated-index", + " title: Documentation Overview", + "customProps:", + " description: To be added in the future." + ] + + return "\n".join(obj_text) + @staticmethod + def select_object_properties(self, properties : list[dict]) -> str: + """ + Generate the section for object properties, + you can select your own properties to display + by providing a the properties in a list of + dicts. + + Args: + Self. + Properties (dict): The ones you want to show. + + Returns: + str: + + Examples: + + Input + ``` + [ + { "Display Folder": "Sales Order Information" }, + { "Is Hidden": "False" }, + { "Format String": "#.###,## } + ] + ``` + + Output: + ``` +
+
Display Folder
+
Sales Order Information
+ +
Is Hidden
+
False
+ +
Format String
+
#.###,##
+
+ ``` + """ + + obj_text = [ + "
" + ] + + for obj_prop in properties: + for caption, text in obj_prop.items(): + obj_text.append(f"
{caption}
") + obj_text.append(f"
{text}
") + obj_text.append(f"") + + obj_text.append("
") + + return "\n".join(obj_text) From f06967b5e416e7a4dcd54fcc02246f2ded5b4e82 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Sun, 12 Feb 2023 22:48:43 +0100 Subject: [PATCH 12/22] Tables and Colums, Need to do Measures --- pytabular/document/document.py | 94 +++++++++++++--------------------- 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/pytabular/document/document.py b/pytabular/document/document.py index 978ca01..3458230 100644 --- a/pytabular/document/document.py +++ b/pytabular/document/document.py @@ -253,14 +253,26 @@ def create_markdown_for_measure(self, object: PyMeasure) -> str: "\\n", "" ) - object_properties = '' + + # TODO: Resolve to make sure it's for measures. + object_properties = [ + { "Column Name": object.Name }, + { "Object Type": object.ObjectType }, + { "Type": object.Type }, + { "Is Available In Excel": object.IsAvailableInMDX }, + { "Is Hidden": object.IsHidden }, + { "Data Category": object.DataCategory }, + { "Data Type": object.DataType }, + { "Display Folder": object.DisplayFolder } + ] + obj_text = [ f"### {object_caption}", "**Description**:", f"> {object_description}", "" - f"{object_properties}", + f"{self.select_object_properties(object_properties)}" "", f'```dax title="Technical: {object.Name}"', f" {object.Expression}", @@ -319,31 +331,15 @@ def create_markdown_for_table(self, object: PyTable) -> str: "\\n", "" ) - object_details = '' - """ -
-
Measures (#)
-
{len(object.Measures)}
- -
Columns (#)
-
{len(object.Columns)}
- -
Partitions (#)
-
{len(object.Partitions)}
- -
Data Category
-
{object.DataCategory or "Regular Table"}
- -
Is Hidden
-
{object.IsHidden}
- -
Table Type
-
{object.Partitions[0].ObjectType}
- -
Source Type
-
{object.Partitions[0].SourceType}
-
- """ + object_properties = [ + { "Measures (#)": len(object.Measures) }, + { "Columns (#)": len(object.Columns) }, + { "Partiton (#)": len(object.Partitions) }, + { "Data Category": object.DataCategory or "Regular Table" }, + { "Is Hidden": object.IsHidden }, + { "Table Type": object.Partitions[0].ObjectType }, + { "Source Type": object.Partitions[0].SourceType } + ] partition_type = "" partition_source = "" @@ -363,7 +359,7 @@ def create_markdown_for_table(self, object: PyTable) -> str: "**Description**: ", "> {object_description}", "", - f"{object_details}", + f"{self.select_object_properties(object_properties)}" "", f"```{partition_type} title="Table Source: {object.Name}", f" {partition_source}", @@ -424,40 +420,23 @@ def create_markdown_for_column(self, object: PyColumn) -> str: object_heading = f"""{object_caption} {self.create_object_reference( object=object.Name, object_parent=object.Parent.Name)}""" - object_details = '' - """ -
-
Column Name
-
{object.Name}
- -
Object Type
-
{object.ObjectType}
- -
Type
-
{object.Type}
- -
Is Available In Excel
-
{object.IsAvailableInMDX}
- -
Is Hidden
-
{object.IsHidden}
- -
Data Category
-
{object.DataCategory}
- -
Data Type
-
{object.DataType}
- -
DisplayFolder
-
{object.DisplayFolder}
+ object_properties = [ + { "Column Name": object.Name }, + { "Object Type": object.ObjectType }, + { "Type": object.Type }, + { "Is Available In Excel": object.IsAvailableInMDX }, + { "Is Hidden": object.IsHidden }, + { "Data Category": object.DataCategory }, + { "Data Type": object.DataType }, + { "Display Folder": object.DisplayFolder } + ] -
""" obj_text = [ f"### {object_heading}", "**Description**:" f"> {object_description}" "", - f"{object_details}" + f"{self.select_object_properties(object_properties)}" ] if str(object.Type) == "Calculated": @@ -490,8 +469,9 @@ def generate_category_file(self): ] return "\n".join(obj_text) + @staticmethod - def select_object_properties(self, properties : list[dict]) -> str: + def select_object_properties(properties : list[dict]) -> str: """ Generate the section for object properties, you can select your own properties to display From c4056a92192f2e798bedc385876062069ecd43f8 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Mon, 13 Feb 2023 08:46:56 +0100 Subject: [PATCH 13/22] Refactored Document.py --- pytabular/{document => }/document.py | 247 ++++++++++++++------------- pytabular/document/__init__.py | 1 - 2 files changed, 131 insertions(+), 117 deletions(-) rename pytabular/{document => }/document.py (76%) delete mode 100644 pytabular/document/__init__.py diff --git a/pytabular/document/document.py b/pytabular/document.py similarity index 76% rename from pytabular/document/document.py rename to pytabular/document.py index 3458230..52d9fec 100644 --- a/pytabular/document/document.py +++ b/pytabular/document.py @@ -6,14 +6,15 @@ from pathlib import Path -from pytabular.table import PyTable -from pytabular.column import PyColumn -from pytabular.culture import PyCulture -from pytabular.measure import PyMeasure -from pytabular.pytabular import Tabular +from table import PyTable +from column import PyColumn +from culture import PyCulture +from measure import PyMeasure +from pytabular import Tabular logger = logging.getLogger("PyTabular") + class ModelDocumenter: """The ModelDocumenter class can generate documentation. @@ -65,7 +66,7 @@ def __init__( # Translation information self.culture_include: bool = False self.culture_selected: str = "en-US" - self.culture_object: PyCulture = None + self.culture_object: PyCulture # Documentation Parts self.general_page: str = str() @@ -136,7 +137,7 @@ def set_translations( else: self.culture_include = enable_translations - def set_model_friendly_name(self): + def set_model_friendly_name(self) -> str: """Replaces the model name to a friendly string, so it can be used in an URL.""" return (self.model_name).replace(" ", "-").replace("_", "-").lower() @@ -249,49 +250,46 @@ def create_markdown_for_measure(self, object: PyMeasure) -> str: or object.Name ) - object_description = (object.Description or "No Description available").replace( + obj_description = (object.Description or "No Description available").replace( "\\n", "" ) - - # TODO: Resolve to make sure it's for measures. object_properties = [ - { "Column Name": object.Name }, - { "Object Type": object.ObjectType }, - { "Type": object.Type }, - { "Is Available In Excel": object.IsAvailableInMDX }, - { "Is Hidden": object.IsHidden }, - { "Data Category": object.DataCategory }, - { "Data Type": object.DataType }, - { "Display Folder": object.DisplayFolder } + {"Measure Name": object.Name}, + {"Display Folder": object.DisplayFolder}, + {"Format String": object.FormatString}, + {"Is Hidden": "Yes" if object.IsHidden else "No"}, ] - obj_text = [ f"### {object_caption}", "**Description**:", - f"> {object_description}", - "" - f"{self.select_object_properties(object_properties)}" - "", + f"> {obj_description}", + "" f"{self.generate_object_properties(object_properties)}" "", f'```dax title="Technical: {object.Name}"', f" {object.Expression}", "```", - "---" + "---", ] return "\n".join(obj_text) def generate_markdown_measure_page(self) -> str: - """Based on the measure objects it generates a measure page.""" + """This function generates the page that + Contains the measure documentation. + + Returns: + str: The full markdown text that is needed + make it compatible with Docusaurus. + """ prev_display_folder = "" markdown_template = [ "---", "sidebar_position: 3", "title: Measures", - f"description: This page contains all measures for the {self.model.Name} model, including the description, format string, and other technical details." - "---" + f"description: This page contains all measures for the {self.model.Name} model, including the description, format string, and other technical details.", + "---", "", - f"# Measures for {self.model.Name}" + f"# Measures for {self.model.Name}", ] measures = sorted( @@ -327,18 +325,18 @@ def create_markdown_for_table(self, object: PyTable) -> str: or object.Name ) - object_description = (object.Description or "No Description available").replace( + obj_description = (object.Description or "No Description available").replace( "\\n", "" ) object_properties = [ - { "Measures (#)": len(object.Measures) }, - { "Columns (#)": len(object.Columns) }, - { "Partiton (#)": len(object.Partitions) }, - { "Data Category": object.DataCategory or "Regular Table" }, - { "Is Hidden": object.IsHidden }, - { "Table Type": object.Partitions[0].ObjectType }, - { "Source Type": object.Partitions[0].SourceType } + {"Measures (#)": len(object.Measures)}, + {"Columns (#)": len(object.Columns)}, + {"Partiton (#)": len(object.Partitions)}, + {"Data Category": object.DataCategory or "Regular Table"}, + {"Is Hidden": object.IsHidden}, + {"Table Type": object.Partitions[0].ObjectType}, + {"Source Type": object.Partitions[0].SourceType}, ] partition_type = "" @@ -357,57 +355,50 @@ def create_markdown_for_table(self, object: PyTable) -> str: obj_text = [ f"### {object_caption}", "**Description**: ", - "> {object_description}", + f"> {obj_description}", + "", + f"{self.generate_object_properties(object_properties)}", "", - f"{self.select_object_properties(object_properties)}" - "", - f"```{partition_type} title="Table Source: {object.Name}", + f'```{partition_type} title="Table Source: {object.Name}"', f" {partition_source}", "```", - "---" + "---", ] + return "\n".join(obj_text) + def generate_markdown_table_page(self) -> str: - """This function generates the markdown tables documentation for the tables in the Model.""" + """This function generates the markdown tables documentation + for the tables in the Model. + + Returns: + str: Will be appended to the page text. + """ markdown_template = [ "---", "sidebar_position: 2", "title: Tables", f"description: This page contains all columns with tables for {self.model.Name}, including the description, and technical details.", "---", - f"# Tables {self.model.Name}" - ] - - for table in self.model.Tables: - markdown_template.append(self.create_markdown_for_table(table)) - - return "\n".join(markdown_template) - - def generate_markdown_column_page(self) -> str: - """This function generates the markdown for documentation about columns in the Model.""" - markdown_template = [ - "---" - "sidebar_position: 4" - f"title: Columns description: This page contains all columns with Columns for {self.model.Name}, including the description, format string, and other technical details." - "---" + "", + f"# Tables {self.model.Name}", ] - for table in self.model.Tables: - markdown_template.append(f"## Columns for {table.Name}") - - for column in table.Columns: - if "RowNumber" in column.Name: - continue - - markdown_template.append(self.create_markdown_for_column(column)) - + markdown_template.extend( + self.create_markdown_for_table(table) for table in self.model.Tables + ) return "\n".join(markdown_template) def create_markdown_for_column(self, object: PyColumn) -> str: - """Generates the Markdown for a specifc column. + """Generates the Markdown for a specifc column. If a columns + is calculated, then it also shows the expression for + that column in DAX. - If a colums is calculated, then it also shows - the expression for that column in DAX. + Args: + object (PyColumn): Needs PyColumn objects input + + Returns: + str: Will be appended to the page text. """ object_caption = ( self.get_object_caption( @@ -416,46 +407,75 @@ def create_markdown_for_column(self, object: PyColumn) -> str: or object.Name ) - object_description = object.Description.replace("\\n", "") or "No Description available" + obj_description = ( + object.Description.replace("\\n", "") or "No Description available" + ) - object_heading = f"""{object_caption} {self.create_object_reference( object=object.Name, object_parent=object.Parent.Name)}""" + obj_heading = f"""{object_caption} {self.create_object_reference(object=object.Name, object_parent=object.Parent.Name)}""" object_properties = [ - { "Column Name": object.Name }, - { "Object Type": object.ObjectType }, - { "Type": object.Type }, - { "Is Available In Excel": object.IsAvailableInMDX }, - { "Is Hidden": object.IsHidden }, - { "Data Category": object.DataCategory }, - { "Data Type": object.DataType }, - { "Display Folder": object.DisplayFolder } + {"Column Name": object.Name}, + {"Object Type": object.ObjectType}, + {"Type": object.Type}, + {"Is Available In Excel": object.IsAvailableInMDX}, + {"Is Hidden": object.IsHidden}, + {"Data Category": object.DataCategory}, + {"Data Type": object.DataType}, + {"Display Folder": object.DisplayFolder}, ] obj_text = [ - f"### {object_heading}", - "**Description**:" - f"> {object_description}" + f"### {obj_heading}", + "**Description**:", + f"> {obj_description}", "", - f"{self.select_object_properties(object_properties)}" + f"{self.generate_object_properties(object_properties)}", ] if str(object.Type) == "Calculated": - obj_text.append[ - f"```dax title="Technical: {object.Name}", - f" {object.Expression}", - "```" - ] - + obj_text.extend( + ( + f'```dax title="Technical: {object.Name}"', + f" {object.Expression}", + "```", + ) + ) obj_text.append("---") return "\n".join(obj_text) - - def generate_category_file(self): - """Docusaurs can generate an index. + + def generate_markdown_column_page(self) -> str: + """This function generates the markdown for documentation + about columns in the Model. - The category yaml will make that happen. + Returns: + str: Will be appended to the page text. """ + markdown_template = [ + "---", + "sidebar_position: 4", + f"title: Columns description: This page contains all columns with Columns for {self.model.Name}, including the description, format string, and other technical details.", + "---", + "" + ] + + for table in self.model.Tables: + markdown_template.append(f"## Columns for {table.Name}") + + markdown_template.extend( + self.create_markdown_for_column(column) + for column in table.Columns + if "RowNumber" not in column.Name + ) + return "\n".join(markdown_template) + + def generate_category_file(self) -> str: + """Docusaurs can generate an index based on the files that + are in the directory. The category yaml will make that happen. + Returns: + str: Text that will be the base of _category_.yml. + """ obj_text = [ "position: 2 # float position is supported", f"label: '{self.model_name}'", @@ -465,38 +485,38 @@ def generate_category_file(self): " type: generated-index", " title: Documentation Overview", "customProps:", - " description: To be added in the future." - ] + " description: To be added in the future.", + ] return "\n".join(obj_text) - - @staticmethod - def select_object_properties(properties : list[dict]) -> str: + + @staticmethod + def generate_object_properties(properties: list[dict[str, str]]) -> str: """ Generate the section for object properties, you can select your own properties to display - by providing a the properties in a list of + by providing a the properties in a list of dicts. Args: Self. - Properties (dict): The ones you want to show. - + Properties (dict): The ones you want to show. + Returns: str: - - Examples: - + + Examples: + Input ``` [ { "Display Folder": "Sales Order Information" }, - { "Is Hidden": "False" }, + { "Is Hidden": "False" }, { "Format String": "#.###,## } ] ``` - - Output: + + Output: ```
Display Folder
@@ -508,19 +528,14 @@ def select_object_properties(properties : list[dict]) -> str:
Format String
#.###,##
- ``` - """ + ``` + """ - obj_text = [ - "
" - ] + obj_text = ["
"] for obj_prop in properties: for caption, text in obj_prop.items(): - obj_text.append(f"
{caption}
") - obj_text.append(f"
{text}
") - obj_text.append(f"") - + obj_text.extend((f"
{caption}
", f"
{text}
", "")) obj_text.append("
") return "\n".join(obj_text) diff --git a/pytabular/document/__init__.py b/pytabular/document/__init__.py deleted file mode 100644 index 2e97d02..0000000 --- a/pytabular/document/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Check if needed to make sure the sub module works. \ No newline at end of file From ead95484d6c0409f1fc36963a52aecf2b5b0f7f0 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Mon, 13 Feb 2023 16:08:50 +0100 Subject: [PATCH 14/22] Bugfix: CalculationGroupSource in Partitions - Doesn't have Query as Property. --- pytabular/document.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pytabular/document.py b/pytabular/document.py index 52d9fec..b3e18d2 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -348,10 +348,13 @@ def create_markdown_for_table(self, object: PyTable) -> str: elif str(object.Partitions[0].SourceType) == "M": partition_type = "powerquery" partition_source = object.Partitions[0].Source.Expression + elif str(object.Partitions[0].SourceType) == "CalculationGroupSource": + partition_type = "" + partition_source = "" else: partition_type = "sql" partition_source = object.Partitions[0].Source.Query - + obj_text = [ f"### {object_caption}", "**Description**: ", From 5c6513ffebf50d342a314ac4f9bf3e81a027120c Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Mon, 13 Feb 2023 16:19:46 +0100 Subject: [PATCH 15/22] Bugfix: CalculationGroup Source. --- pytabular/document.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pytabular/document.py b/pytabular/document.py index b3e18d2..a5a28ab 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -341,6 +341,8 @@ def create_markdown_for_table(self, object: PyTable) -> str: partition_type = "" partition_source = "" + + logger.debug(f"{object_caption} => {str(object.Partitions[0].SourceType)}") if str(object.Partitions[0].SourceType) == "Calculated": partition_type = "dax" @@ -348,7 +350,7 @@ def create_markdown_for_table(self, object: PyTable) -> str: elif str(object.Partitions[0].SourceType) == "M": partition_type = "powerquery" partition_source = object.Partitions[0].Source.Expression - elif str(object.Partitions[0].SourceType) == "CalculationGroupSource": + elif str(object.Partitions[0].SourceType) == "CalculationGroup": partition_type = "" partition_source = "" else: From 05f786b70da5009ae2b4330b7e5bef0a37ac4184 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 21:36:40 +0100 Subject: [PATCH 16/22] Added Docstrings (docs / cult) Bugfix in Translations Refactoring docs --- pytabular/culture.py | 20 +++++++++-- pytabular/document.py | 84 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/pytabular/culture.py b/pytabular/culture.py index 3781e23..c4c031c 100644 --- a/pytabular/culture.py +++ b/pytabular/culture.py @@ -17,12 +17,18 @@ def __init__(self, object, model) -> None: self.ObjectTranslations = self.set_translation() def set_translation(self) -> List[dict]: - """Based on the culture, it creates a list of dicts with available translations.""" + """Based on the culture, it creates a list of dicts with available translations. + Note: The model object doesn't have a Parent object. + Returns: + List[dict]: Translations per object. + """ return [ { "object_translation": translation.Value, "object_name": translation.Object.Name, - "object_parent_name": translation.Object.Parent.Name, + "object_parent_name": translation.Object.Parent.Name + if translation.Object.Parent + else "", "object_type": str(translation.Property), } for translation in self._object.ObjectTranslations @@ -35,9 +41,17 @@ def get_translation( By default it will search for the "Caption" object type, due to fact that a Display folder and Description can also have translations. + + Args: + object_name (str): Object name that you want to translate. + object_parent_name (str): Parent Object name that you want to translate. + object_type (str, optional): The Display Folders can also have translations. + Defaults to "Caption" > Object translation. + + Returns: + dict: With translation of the object. """ try: - # Removed walrus operator so it can be compatible with with python versions before 3.8 translations = [ d for d in self.ObjectTranslations diff --git a/pytabular/document.py b/pytabular/document.py index a5a28ab..17eac20 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -91,10 +91,18 @@ def __init__( def create_object_reference(self, object: str, object_parent: str) -> str: """Create a Custom ID for link sections in the docs. + Scope is only Docusaurus. This is based on the technical names in the model, so not the once in the translations. This makes it possible to link based on dependencies. + + Args: + object (str): Object Name + object_parent (str): Object Parent (e.g. Table) + + Returns: + str: String that can be used for custom linking """ url_reference = f"{object_parent}-{object}".replace(" ", "") return f"{{#{url_reference}}}" @@ -106,19 +114,36 @@ def generate_documentation_pages(self) -> None: self.column_page = self.generate_markdown_column_page() self.category_page = self.generate_category_file() - def get_object_caption(self, object_name: str, object_parent: str): - """Retrieves the caption of an object, based on the translations in the culture.""" + def get_object_caption(self, object_name: str, object_parent: str) -> str: + """Retrieves the caption of an object, based on the translations in the culture. + If no culture is present, the object_name is returned + Args: + object_name (str): Object Name + object_parent (str): Object Parent Name + + Returns: + str: Translated object. + """ if self.culture_include: - return self.culture_object.get_translation( - object_name=object_name, object_parent_name=object_parent - ).get("object_translation") + return str( + self.culture_object.get_translation( + object_name=object_name, object_parent_name=object_parent + ).get("object_translation") + ) return object_name def set_translations( self, enable_translations: bool = False, culture: str = "en-US" ) -> None: - """Set translations to active or inactive, depending on the needs of the users.""" + """Set translations to active or inactive, depending on the needs of the users. + + Args: + enable_translations (bool, optional): Flag to enable or disable translations. + Defaults to False. + culture (str, optional): Set culture that needs to be used in the docs. + Defaults to "en-US". + """ logger.info(f"Using Translations set to > {enable_translations}") if enable_translations: @@ -138,11 +163,19 @@ def set_translations( self.culture_include = enable_translations def set_model_friendly_name(self) -> str: - """Replaces the model name to a friendly string, so it can be used in an URL.""" + """Replaces the model name to a friendly string, so it can be used in an URL. + + Returns: + str: Friendly model name used in url for docs. + """ return (self.model_name).replace(" ", "-").replace("_", "-").lower() def set_save_path(self) -> Path: - """Set the location of the documentation.""" + """Set the location of the documentation. + + Returns: + Path: Path where the docs are saved. + """ return Path(f"{self.save_location}/{self.friendly_name}") def save_page(self, content: str, page_name: str, keep_file: bool = False) -> None: @@ -242,6 +275,12 @@ def create_markdown_for_measure(self, object: PyMeasure) -> str: """Create Markdown for a specific measure. That can later on be used for generating the whole measure page. + + Args: + object (PyMeasure): The measure to document. + + Returns: + str: Markdown section for specific Measure """ object_caption = ( self.get_object_caption( @@ -286,7 +325,9 @@ def generate_markdown_measure_page(self) -> str: "---", "sidebar_position: 3", "title: Measures", - f"description: This page contains all measures for the {self.model.Name} model, including the description, format string, and other technical details.", + "description: This page contains all measures for " + f"the {self.model.Name} model, including the description, " + "format string, and other technical details.", "---", "", f"# Measures for {self.model.Name}", @@ -341,7 +382,7 @@ def create_markdown_for_table(self, object: PyTable) -> str: partition_type = "" partition_source = "" - + logger.debug(f"{object_caption} => {str(object.Partitions[0].SourceType)}") if str(object.Partitions[0].SourceType) == "Calculated": @@ -356,7 +397,7 @@ def create_markdown_for_table(self, object: PyTable) -> str: else: partition_type = "sql" partition_source = object.Partitions[0].Source.Query - + obj_text = [ f"### {object_caption}", "**Description**: ", @@ -383,7 +424,9 @@ def generate_markdown_table_page(self) -> str: "---", "sidebar_position: 2", "title: Tables", - f"description: This page contains all columns with tables for {self.model.Name}, including the description, and technical details.", + "description: This page contains all columns with " + f"tables for {self.model.Name}, including the description, " + "and technical details.", "---", "", f"# Tables {self.model.Name}", @@ -416,7 +459,12 @@ def create_markdown_for_column(self, object: PyColumn) -> str: object.Description.replace("\\n", "") or "No Description available" ) - obj_heading = f"""{object_caption} {self.create_object_reference(object=object.Name, object_parent=object.Parent.Name)}""" + obj_reference = self.create_object_reference( + object=object.Name, + object_parent=object.Parent.Name + ) + + obj_heading = f"""{object_caption} {obj_reference}""" object_properties = [ {"Column Name": object.Name}, @@ -448,7 +496,7 @@ def create_markdown_for_column(self, object: PyColumn) -> str: obj_text.append("---") return "\n".join(obj_text) - + def generate_markdown_column_page(self) -> str: """This function generates the markdown for documentation about columns in the Model. @@ -459,9 +507,11 @@ def generate_markdown_column_page(self) -> str: markdown_template = [ "---", "sidebar_position: 4", - f"title: Columns description: This page contains all columns with Columns for {self.model.Name}, including the description, format string, and other technical details.", + f"title: Columns description: This page contains all columns with " + f"Columns for {self.model.Name} " + "including the description, format string, and other technical details.", "---", - "" + "", ] for table in self.model.Tables: @@ -473,7 +523,7 @@ def generate_markdown_column_page(self) -> str: if "RowNumber" not in column.Name ) return "\n".join(markdown_template) - + def generate_category_file(self) -> str: """Docusaurs can generate an index based on the files that are in the directory. The category yaml will make that happen. From 44b45729b747a5bb3cfacb5ba41db16f3555ffc3 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 22:02:31 +0100 Subject: [PATCH 17/22] Updated the docstring requirements. --- pytabular/culture.py | 5 ++++- pytabular/document.py | 34 ++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pytabular/culture.py b/pytabular/culture.py index c4c031c..3f09e6d 100644 --- a/pytabular/culture.py +++ b/pytabular/culture.py @@ -18,7 +18,10 @@ def __init__(self, object, model) -> None: def set_translation(self) -> List[dict]: """Based on the culture, it creates a list of dicts with available translations. - Note: The model object doesn't have a Parent object. + + The model object doesn't have a Parent object. So that will stay + empty. + Returns: List[dict]: Translations per object. """ diff --git a/pytabular/document.py b/pytabular/document.py index 17eac20..0cba68d 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -91,11 +91,11 @@ def __init__( def create_object_reference(self, object: str, object_parent: str) -> str: """Create a Custom ID for link sections in the docs. - Scope is only Docusaurus. This is based on the technical names in the model, so not the once in the translations. This makes it - possible to link based on dependencies. + possible to link based on dependencies. + (Scope is only Docusaurus.) Args: object (str): Object Name @@ -116,7 +116,9 @@ def generate_documentation_pages(self) -> None: def get_object_caption(self, object_name: str, object_parent: str) -> str: """Retrieves the caption of an object, based on the translations in the culture. + If no culture is present, the object_name is returned + Args: object_name (str): Object Name object_parent (str): Object Parent Name @@ -313,8 +315,7 @@ def create_markdown_for_measure(self, object: PyMeasure) -> str: return "\n".join(obj_text) def generate_markdown_measure_page(self) -> str: - """This function generates the page that - Contains the measure documentation. + """This function generates the meausure documation page. Returns: str: The full markdown text that is needed @@ -414,8 +415,7 @@ def create_markdown_for_table(self, object: PyTable) -> str: return "\n".join(obj_text) def generate_markdown_table_page(self) -> str: - """This function generates the markdown tables documentation - for the tables in the Model. + """This function generates the markdown for table documentation. Returns: str: Will be appended to the page text. @@ -438,8 +438,9 @@ def generate_markdown_table_page(self) -> str: return "\n".join(markdown_template) def create_markdown_for_column(self, object: PyColumn) -> str: - """Generates the Markdown for a specifc column. If a columns - is calculated, then it also shows the expression for + """Generates the Markdown for a specifc column. + + If a columns is calculated, then it also shows the expression for that column in DAX. Args: @@ -498,8 +499,7 @@ def create_markdown_for_column(self, object: PyColumn) -> str: return "\n".join(obj_text) def generate_markdown_column_page(self) -> str: - """This function generates the markdown for documentation - about columns in the Model. + """This function generates the markdown for the colums documentation. Returns: str: Will be appended to the page text. @@ -525,8 +525,11 @@ def generate_markdown_column_page(self) -> str: return "\n".join(markdown_template) def generate_category_file(self) -> str: - """Docusaurs can generate an index based on the files that - are in the directory. The category yaml will make that happen. + """Docusaurs can generate an index based on the files. + + The files that are in the same directory as _category_.ym will + be use to create an index and a navigation. For more information + see Docusaurus documentation. Returns: str: Text that will be the base of _category_.yml. @@ -547,9 +550,9 @@ def generate_category_file(self) -> str: @staticmethod def generate_object_properties(properties: list[dict[str, str]]) -> str: - """ - Generate the section for object properties, - you can select your own properties to display + """Generate the section for object properties. + + You can select your own properties to display by providing a the properties in a list of dicts. @@ -561,7 +564,6 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str: str: Examples: - Input ``` [ From c33b4dfbdba0ddc3ae39345799b502351873ff57 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 22:08:05 +0100 Subject: [PATCH 18/22] Adjusted some more errors --- pytabular/culture.py | 4 ++-- pytabular/document.py | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pytabular/culture.py b/pytabular/culture.py index 3f09e6d..59fa5cb 100644 --- a/pytabular/culture.py +++ b/pytabular/culture.py @@ -19,9 +19,9 @@ def __init__(self, object, model) -> None: def set_translation(self) -> List[dict]: """Based on the culture, it creates a list of dicts with available translations. - The model object doesn't have a Parent object. So that will stay + The model object doesn't have a Parent object. So that will stay empty. - + Returns: List[dict]: Translations per object. """ diff --git a/pytabular/document.py b/pytabular/document.py index 0cba68d..983011f 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -94,8 +94,8 @@ def create_object_reference(self, object: str, object_parent: str) -> str: This is based on the technical names in the model, so not the once in the translations. This makes it - possible to link based on dependencies. - (Scope is only Docusaurus.) + possible to link based on dependencies. + (Scope is only Docusaurus) Args: object (str): Object Name @@ -116,8 +116,8 @@ def generate_documentation_pages(self) -> None: def get_object_caption(self, object_name: str, object_parent: str) -> str: """Retrieves the caption of an object, based on the translations in the culture. - - If no culture is present, the object_name is returned + + If no culture is present, the object_name is returned. Args: object_name (str): Object Name @@ -438,8 +438,8 @@ def generate_markdown_table_page(self) -> str: return "\n".join(markdown_template) def create_markdown_for_column(self, object: PyColumn) -> str: - """Generates the Markdown for a specifc column. - + """Generates the Markdown for a specifc column. + If a columns is calculated, then it also shows the expression for that column in DAX. @@ -526,7 +526,7 @@ def generate_markdown_column_page(self) -> str: def generate_category_file(self) -> str: """Docusaurs can generate an index based on the files. - + The files that are in the same directory as _category_.ym will be use to create an index and a navigation. For more information see Docusaurus documentation. @@ -556,13 +556,6 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str: by providing a the properties in a list of dicts. - Args: - Self. - Properties (dict): The ones you want to show. - - Returns: - str: - Examples: Input ``` @@ -586,6 +579,13 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str:
#.###,##
``` + + Args: + Self. + Properties (dict): The ones you want to show. + + Returns: + str: HTML used in the markdown. """ obj_text = ["
"] From 36e3aaa8ab732b42e5335bc984a6877446ec03be Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 22:12:48 +0100 Subject: [PATCH 19/22] Adjusted last flake8 errors --- pytabular/document.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/pytabular/document.py b/pytabular/document.py index 983011f..53b99ee 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -118,7 +118,7 @@ def get_object_caption(self, object_name: str, object_parent: str) -> str: """Retrieves the caption of an object, based on the translations in the culture. If no culture is present, the object_name is returned. - + Args: object_name (str): Object Name object_parent (str): Object Parent Name @@ -556,17 +556,22 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str: by providing a the properties in a list of dicts. - Examples: - Input - ``` + Args: + Self. + Properties (dict): The ones you want to show. + + Returns: + str: HTML used in the markdown. + + Example: + ```python [ { "Display Folder": "Sales Order Information" }, { "Is Hidden": "False" }, { "Format String": "#.###,## } ] ``` - - Output: + Returns: ```
Display Folder
@@ -579,15 +584,7 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str:
#.###,##
``` - - Args: - Self. - Properties (dict): The ones you want to show. - - Returns: - str: HTML used in the markdown. """ - obj_text = ["
"] for obj_prop in properties: From fa1ae19271c36afebf78fb3940a1372bf978e855 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 22:12:49 +0100 Subject: [PATCH 20/22] Adjusted last flake8 errors From 9fda043e3d236b3074f4a1f6948263f65d9924c0 Mon Sep 17 00:00:00 2001 From: Daan Damhuis Date: Wed, 15 Feb 2023 22:13:41 +0100 Subject: [PATCH 21/22] Removed whitespace --- pytabular/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytabular/document.py b/pytabular/document.py index 53b99ee..6deb948 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -562,7 +562,7 @@ def generate_object_properties(properties: list[dict[str, str]]) -> str: Returns: str: HTML used in the markdown. - + Example: ```python [ From dfa0b6faca04483b7bafea83cdfb7599600ade80 Mon Sep 17 00:00:00 2001 From: Curtis Stallings Date: Wed, 15 Feb 2023 16:52:40 -0600 Subject: [PATCH 22/22] Typing Error for anything before python 3.9 --- pytabular/document.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytabular/document.py b/pytabular/document.py index 6deb948..30bd6ed 100644 --- a/pytabular/document.py +++ b/pytabular/document.py @@ -11,6 +11,7 @@ from culture import PyCulture from measure import PyMeasure from pytabular import Tabular +from typing import List, Dict logger = logging.getLogger("PyTabular") @@ -549,7 +550,7 @@ def generate_category_file(self) -> str: return "\n".join(obj_text) @staticmethod - def generate_object_properties(properties: list[dict[str, str]]) -> str: + def generate_object_properties(properties: List[Dict[str, str]]) -> str: """Generate the section for object properties. You can select your own properties to display