diff --git a/README.md b/README.md
index c41e44e..615809a 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
### What is it?
-PyTabular is a python package that allows for programmatic execution on your tabular models! This is possible thanks to [Pythonnet](https://pythonnet.github.io/) and Microsoft's [.Net APIs on Azure Analysis Services](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices?view=analysisservices-dotnet). The package should have the dll files included when you import it.
+PyTabular is a python package that allows for programmatic execution on your tabular models! This is possible thanks to [Pythonnet](https://pythonnet.github.io/) and Microsoft's [.Net APIs on Azure Analysis Services](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices?view=analysisservices-dotnet). The package should have the dll files included when you import it. See [Documentation Here](https://curts0.github.io/PyTabular/)
### Getting Started
@@ -28,17 +28,17 @@ DAX Query
# Returns a Pandas DataFrame
```
-Refresh Tables and Partitions
+[Refresh Tables and Partitions](https://curts0.github.io/PyTabular/Tabular/#refresh)
```python
- #filter down the collection to what you want to refresh
- tables_to_refresh = [table for table in model.Tables if table.Name in ['Table1','Table2','Table3']]
-
+ #Can be str(table name only), Table object, Partition object, or an iterable combination of the three.
+ model.Refresh('Table Name')
+ tables_to_refresh = ['Table Name 1', 'Table Name 2',
, ]
#Queue up the tables and partitions that you want to refresh.
model.Refresh(tables_to_refresh)
#Once you are ready, update to execute the refresh
- model.Update()
+ model.SaveChanges()
```
Built In Dax Query Helpers
@@ -71,6 +71,4 @@ Run BPA from TE2
TE2 = pytabular.TE2() #Feel free to input your TE2 File path or this will download for you.
BPA = pytabular.BPA() #Fee free to input your own BPA file or this will download for you from: https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json
model.Analyze_BPA(TE2.EXE_Path,BPA.Location) #This will output a list of BPA violations...
-```
-
-I'm working on converting everything to the google docstring format and using those to populate the documentation. I still have some formatting issues to work through, but that should help with understanding what this package can do.
\ No newline at end of file
+```
\ No newline at end of file
diff --git a/dist/python_tabular-0.0.20.tar.gz b/dist/python_tabular-0.0.20.tar.gz
deleted file mode 100644
index 3c90be1..0000000
Binary files a/dist/python_tabular-0.0.20.tar.gz and /dev/null differ
diff --git a/dist/python_tabular-0.0.20-py3-none-any.whl b/dist/python_tabular-0.0.30-py3-none-any.whl
similarity index 99%
rename from dist/python_tabular-0.0.20-py3-none-any.whl
rename to dist/python_tabular-0.0.30-py3-none-any.whl
index dc43e2e..0fdb60c 100644
Binary files a/dist/python_tabular-0.0.20-py3-none-any.whl and b/dist/python_tabular-0.0.30-py3-none-any.whl differ
diff --git a/dist/python_tabular-0.0.30.tar.gz b/dist/python_tabular-0.0.30.tar.gz
new file mode 100644
index 0000000..b14b3a5
Binary files /dev/null and b/dist/python_tabular-0.0.30.tar.gz differ
diff --git a/docs/BPA.md b/docs/BPA.md
index 73c02ff..272eff0 100644
--- a/docs/BPA.md
+++ b/docs/BPA.md
@@ -2,7 +2,7 @@
## BPA
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L374)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L393)
```python
BPA(
rules_location: str = 'https: //raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json'
@@ -11,7 +11,5 @@ BPA(
---
-Best Practice Analyzer Class
-Can provide Url, Json File Path, or Python List.
-If nothing is provided it will default to Microsofts Analysis Services report with BPA Rules.
-https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json
+_summary_
+
diff --git a/docs/Examples.md b/docs/Examples.md
index 6aa41c6..fe076d8 100644
--- a/docs/Examples.md
+++ b/docs/Examples.md
@@ -51,3 +51,30 @@ Example to add to model model.Create_Table(p.Table_Last_Refresh_Times(model),'Re
* **DataFrame** : pd dataframe with the RefreshedTime property: https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.partition.refreshedtime?view=analysisservices-dotnet#microsoft-analysisservices-tabular-partition-refreshedtime
If group_partition == True and the table has multiple partitions, then df.groupby(by["tables"]).max()
+
+----
+
+
+### BPA_Violations_To_DF
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/basic_checks.py\#L50)
+```python
+.BPA_Violations_To_DF(
+ model: pytabular.Tabular, te2: str, bpa: str
+)
+```
+
+---
+Runs BPA Analyzer from TE2 and outputs result into a DF.
+
+
+**Args**
+
+* **model** (pytabular.Tabular) : Tabular Model Class
+* **te2** (str) : TE2 Exe File Path (Can use TE2().EXE_path)
+* **bpa** (str) : BPA File Location (Can use BPA().Location)
+
+
+**Returns**
+
+* **DataFrame** : Super simple right now. Just splits into two columns.. The object in violation and the rule.
+
diff --git a/docs/TE2.md b/docs/TE2.md
index 28fd238..ca9b27f 100644
--- a/docs/TE2.md
+++ b/docs/TE2.md
@@ -2,7 +2,7 @@
## TE2
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L399)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L417)
```python
TE2(
TE_Location = 'https: //github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip'
@@ -11,7 +11,6 @@ TE2(
---
-TE2 Class, to use any built TabularEditor Command Line Scripts
-https://docs.tabulareditor.com/te2/Command-line-Options.html
-#https://github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip
-#https://cdn.tabulareditor.com/files/TabularEditor.2.16.7.zip
+TE2 Class, to use any built TabularEditor Command Line Scripts
+[TE2 Command Line Example](https://docs.tabulareditor.com/te2/Command-line-Options.html)
+[TE2 Download](https://github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip)
diff --git a/docs/Tabular.md b/docs/Tabular.md
index 1edaf25..c4fee9f 100644
--- a/docs/Tabular.md
+++ b/docs/Tabular.md
@@ -2,7 +2,7 @@
## Tabular
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L20)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L21)
```python
Tabular(
CONNECTION_STR: str
@@ -23,8 +23,23 @@ Tabular Class to perform operations:[Microsoft.AnalysisServices.Tabular](https:/
**Methods:**
+### .Reload_Model_Info
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L53)
+```python
+.Reload_Model_Info()
+```
+
+---
+Runs on __init__ iterates through details, can be called after any model changes. Called in SaveChanges()
+
+
+**Returns**
+
+* **bool** : True if successful
+
+
### .Disconnect
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L55)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L64)
```python
.Disconnect()
```
@@ -39,27 +54,25 @@ Disconnects from Model
### .Refresh
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L70)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L79)
```python
.Refresh(
- iterable_items: List, RefreshType = RefreshType.Full
+ Object: Union[str, Table, Partition, Iterable], RefreshType = RefreshType.Full
)
```
---
-Input iterable Collections for the function to run through.
-It will add the collection items into a Refresh Request.
-To execute refresh run through Update()
+Input Object(s) to be refreshed in the tabular model. Combine with .SaveChanges() to actually run the refresh on the model.
**Args**
-* **iterable_items** (List) : Must be refreshable Tabular objects.
-* **RefreshType** (_type_, optional) : _description_. Defaults to RefreshType.Full.
+* **Object** (Union[str,Table,Partition,Iterable]) : Can be str(table name only), Table object, Partition object, or an iterable combination of the three.
+* **RefreshType** (_type_, optional) : [RefreshType](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.refreshtype?view=analysisservices-dotnet). Defaults to RefreshType.Full.
### .Update
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L82)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L100)
```python
.Update(
UpdateOptions: UpdateOptions = UpdateOptions.ExpandFull
@@ -81,7 +94,7 @@ To execute refresh run through Update()
### .SaveChanges
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L93)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L111)
```python
.SaveChanges()
```
@@ -96,7 +109,7 @@ Just a simple wrapper to call self.Model.SaveChanges()
bool:
### .Backup_Table
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L102)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L121)
```python
.Backup_Table(
table_str: str
@@ -120,7 +133,7 @@ Refresh is performed from source during backup.
### .Revert_Table
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L169)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L188)
```python
.Revert_Table(
table_str: str
@@ -148,7 +161,7 @@ Example scenario ->
### .Query
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L237)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L256)
```python
.Query(
Query_Str: str
@@ -170,7 +183,7 @@ Executes Query on Model and Returns Results in Pandas DataFrame
### .Query_Every_Column
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L267)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L286)
```python
.Query_Every_Column(
query_function: str = 'COUNTROWS(VALUES(_))'
@@ -193,7 +206,7 @@ This will dynamically create a query to pull all columns from the model and run
### .Query_Every_Table
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L289)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L308)
```python
.Query_Every_Table(
query_function: str = 'COUNTROWS(_)'
@@ -216,7 +229,7 @@ It will replace the _ with the table to run.
### .Analyze_BPA
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L309)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L328)
```python
.Analyze_BPA(
Tabular_Editor_Exe: str, Best_Practice_Analyzer: str
@@ -241,7 +254,7 @@ https://docs.tabulareditor.com/te2/Command-line-Options.html
### .Create_Table
-[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L333)
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/pytabular.py\#L352)
```python
.Create_Table(
df: pd.DataFrame, table_name: str
diff --git a/docs/Utils.md b/docs/Utils.md
index 71342d9..1fdd606 100644
--- a/docs/Utils.md
+++ b/docs/Utils.md
@@ -47,3 +47,45 @@ WiP takes dataframe columns and gets respective tabular column datatype. ([NumP
* **Dict** : EX {'col1': , 'col2': , 'col3': }
+
+----
+
+
+### pd_dataframe_to_m_expression
+[source](https://github.com/Curts0/PyTabular\blob\master\pytabular/logic_utils.py\#L75)
+```python
+.pd_dataframe_to_m_expression(
+ df: pd.DataFrame
+)
+```
+
+---
+This will take a pandas dataframe and convert to an m expression
+For example this DF:
+ col1 col2
+0 1 3
+1 2 4
+
+|
+|
+V
+
+Will convert to this expression string:
+let
+Source=#table({"col1","col2"},
+{
+{"1","3"},{"2","4"}
+})
+in
+Source
+
+
+**Args**
+
+* **df** (pd.DataFrame) : Pandas DataFrame
+
+
+**Returns**
+
+* **str** : Currently only returning string values in your tabular model.
+
diff --git a/docs/index.md b/docs/index.md
index c41e44e..615809a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -6,7 +6,7 @@
### What is it?
-PyTabular is a python package that allows for programmatic execution on your tabular models! This is possible thanks to [Pythonnet](https://pythonnet.github.io/) and Microsoft's [.Net APIs on Azure Analysis Services](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices?view=analysisservices-dotnet). The package should have the dll files included when you import it.
+PyTabular is a python package that allows for programmatic execution on your tabular models! This is possible thanks to [Pythonnet](https://pythonnet.github.io/) and Microsoft's [.Net APIs on Azure Analysis Services](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices?view=analysisservices-dotnet). The package should have the dll files included when you import it. See [Documentation Here](https://curts0.github.io/PyTabular/)
### Getting Started
@@ -28,17 +28,17 @@ DAX Query
# Returns a Pandas DataFrame
```
-Refresh Tables and Partitions
+[Refresh Tables and Partitions](https://curts0.github.io/PyTabular/Tabular/#refresh)
```python
- #filter down the collection to what you want to refresh
- tables_to_refresh = [table for table in model.Tables if table.Name in ['Table1','Table2','Table3']]
-
+ #Can be str(table name only), Table object, Partition object, or an iterable combination of the three.
+ model.Refresh('Table Name')
+ tables_to_refresh = ['Table Name 1', 'Table Name 2', , ]
#Queue up the tables and partitions that you want to refresh.
model.Refresh(tables_to_refresh)
#Once you are ready, update to execute the refresh
- model.Update()
+ model.SaveChanges()
```
Built In Dax Query Helpers
@@ -71,6 +71,4 @@ Run BPA from TE2
TE2 = pytabular.TE2() #Feel free to input your TE2 File path or this will download for you.
BPA = pytabular.BPA() #Fee free to input your own BPA file or this will download for you from: https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json
model.Analyze_BPA(TE2.EXE_Path,BPA.Location) #This will output a list of BPA violations...
-```
-
-I'm working on converting everything to the google docstring format and using those to populate the documentation. I still have some formatting issues to work through, but that should help with understanding what this package can do.
\ No newline at end of file
+```
\ No newline at end of file
diff --git a/mkgendocs.yml b/mkgendocs.yml
index 65be15d..1296e2d 100644
--- a/mkgendocs.yml
+++ b/mkgendocs.yml
@@ -22,8 +22,10 @@ pages:
functions:
- Return_Zero_Row_Tables
- Table_Last_Refresh_Times
+ - BPA_Violations_To_DF
- page: "Utils.md"
source: 'pytabular/logic_utils.py'
functions:
- ticks_to_datetime
- - pandas_datatype_to_tabular_datatype
\ No newline at end of file
+ - pandas_datatype_to_tabular_datatype
+ - pd_dataframe_to_m_expression
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 253fbe4..d5e66ba 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "python_tabular"
-version = "0.0.20"
+version = "0.0.30"
authors = [
{ name="Curtis Stallings", email="curtisrstallings@gmail.com" },
]
diff --git a/pytabular/basic_checks.py b/pytabular/basic_checks.py
index 399a18f..e263045 100644
--- a/pytabular/basic_checks.py
+++ b/pytabular/basic_checks.py
@@ -48,6 +48,16 @@ def Table_Last_Refresh_Times(model:pytabular.Tabular, group_partition:bool = Tru
return df
def BPA_Violations_To_DF(model:pytabular.Tabular,te2:str, bpa:str) -> pd.DataFrame:
+ '''Runs BPA Analyzer from TE2 and outputs result into a DF.
+
+ Args:
+ model (pytabular.Tabular): Tabular Model Class
+ te2 (str): TE2 Exe File Path (Can use TE2().EXE_path)
+ bpa (str): BPA File Location (Can use BPA().Location)
+
+ Returns:
+ pd.DataFrame: Super simple right now. Just splits into two columns.. The object in violation and the rule.
+ '''
results = model.Analyze_BPA(te2,bpa)
data = [rule.replace(' violates rule ','^').replace('\"','').split('^') for rule in results]
columns = ["Object","Violation"]
diff --git a/pytabular/logic_utils.py b/pytabular/logic_utils.py
index b5e37a5..ec89454 100644
--- a/pytabular/logic_utils.py
+++ b/pytabular/logic_utils.py
@@ -73,25 +73,30 @@ def dax_tableconstructor_rows_expression_generator(list_of_strings: list[str]) -
return
return True
def pd_dataframe_to_m_expression(df:pd.DataFrame) -> str:
- '''
- This will take a pandas dataframe and convert to an m expression
- For example this DF:
- col1 col2
- 0 1 3
- 1 2 4
-
- |
- |
- V
-
- Will convert to this expression string:
- let
- Source=#table({"col1","col2"},
- {
- {"1","3"},{"2","4"}
- })
- in
+ '''This will take a pandas dataframe and convert to an m expression
+ For example this DF:
+ col1 col2
+ 0 1 3
+ 1 2 4
+
+ |
+ |
+ V
+
+ Will convert to this expression string:
+ let
+ Source=#table({"col1","col2"},
+ {
+ {"1","3"},{"2","4"}
+ })
+ in
Source
+
+ Args:
+ df (pd.DataFrame): Pandas DataFrame
+
+ Returns:
+ str: Currently only returning string values in your tabular model.
'''
def m_list_expression_generator(list_of_strings:List[str]) -> str:
'''
diff --git a/pytabular/pytabular.py b/pytabular/pytabular.py
index 32de6ce..dd2e6e5 100644
--- a/pytabular/pytabular.py
+++ b/pytabular/pytabular.py
@@ -8,7 +8,8 @@
from Microsoft.AnalysisServices import UpdateOptions
logging.debug('Importing Other Packages...')
-from typing import List
+from typing import List, Union
+from collections.abc import Iterable
import requests as r
import pandas as pd
import json
@@ -41,10 +42,7 @@ def __init__(self,CONNECTION_STR:str):
logging.debug(f'Connected to Model - {self.Model.Name}')
self.DaxConnection = AdomdConnection()
self.DaxConnection.ConnectionString = f"{self.Server.ConnectionString}Password='{self.Server.ConnectionInfo.Password}'"
- self.Tables = [table for table in self.Model.Tables.GetEnumerator()]
- self.Columns = [column for table in self.Tables for column in table.Columns.GetEnumerator()]
- self.Partitions = [partition for table in self.Tables for partition in table.Partitions.GetEnumerator()]
- self.Measures = [measure for table in self.Tables for measure in table.Measures.GetEnumerator()]
+ self.Reload_Model_Info()
logging.debug(f'Class Initialization Completed')
logging.debug(f'Registering Disconnect on Termination...')
atexit.register(self.Disconnect)
@@ -52,6 +50,17 @@ def __init__(self,CONNECTION_STR:str):
pass
def __repr__(self) -> str:
return f'{self.Server.Name}::{self.Database.Name}::{self.Model.Name}\n{self.Database.EstimatedSize} Estimated Size\n{len(self.Tables)} Tables\n{len(self.Columns)} Columns\n{len(self.Partitions)} Partitions\n{len(self.Measures)} Measures'
+ def Reload_Model_Info(self) -> bool:
+ '''Runs on __init__ iterates through details, can be called after any model changes. Called in SaveChanges()
+
+ Returns:
+ bool: True if successful
+ '''
+ self.Tables = [table for table in self.Model.Tables.GetEnumerator()]
+ self.Columns = [column for table in self.Tables for column in table.Columns.GetEnumerator()]
+ self.Partitions = [partition for table in self.Tables for partition in table.Partitions.GetEnumerator()]
+ self.Measures = [measure for table in self.Tables for measure in table.Measures.GetEnumerator()]
+ return True
def Disconnect(self) -> bool:
'''Disconnects from Model
@@ -67,18 +76,27 @@ def Disconnect(self) -> bool:
else:
logging.debug(f'Disconnect Successful')
return True
- def Refresh(self, iterable_items: List, RefreshType=RefreshType.Full) -> None:
- '''Input iterable Collections for the function to run through.
- It will add the collection items into a Refresh Request.
- To execute refresh run through Update()
+ def Refresh(self, Object:Union[str,Table,Partition,Iterable], RefreshType=RefreshType.Full) -> None:
+ '''Input Object(s) to be refreshed in the tabular model. Combine with .SaveChanges() to actually run the refresh on the model.
Args:
- iterable_items (List): Must be refreshable Tabular objects.
- RefreshType (_type_, optional): _description_. Defaults to RefreshType.Full.
- '''
- for collection in iterable_items:
- logging.debug(f'Adding {collection.Name} to Refresh Request')
- collection.RequestRefresh(RefreshType)
+ Object (Union[str,Table,Partition,Iterable]): Can be str(table name only), Table object, Partition object, or an iterable combination of the three.
+ RefreshType (_type_, optional): [RefreshType](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.refreshtype?view=analysisservices-dotnet). Defaults to RefreshType.Full.
+ '''
+ logging.debug(f'Beginning RequestRefresh cadence...')
+ def refresh(object):
+ if isinstance(object,str):
+ logging.info(f'Requesting refresh for {object}')
+ table = [table for table in self.Tables if table.Name == object][0]
+ table.RequestRefresh(RefreshType)
+ else:
+ logging.info(f'Requesting refresh for {object.Name}')
+ object.RequestRefresh(RefreshType)
+ if isinstance(Object,Iterable):
+ [refresh(object) for object in Object]
+ else:
+ refresh(Object)
+ Object.RequestRefresh(RefreshType)
def Update(self, UpdateOptions:UpdateOptions =UpdateOptions.ExpandFull) -> None:
'''[Update Model](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.majorobject.update?view=analysisservices-dotnet#microsoft-analysisservices-majorobject-update(microsoft-analysisservices-updateoptions))
@@ -96,7 +114,8 @@ def SaveChanges(self) -> bool:
Returns:
bool:
- '''
+ '''
+ self.Reload_Model_Info()
self.Model.SaveChanges()
return True
def Backup_Table(self,table_str:str) -> bool:
@@ -372,11 +391,10 @@ def Create_Table(self,df:pd.DataFrame, table_name:str) -> bool:
class BPA:
- '''
- Best Practice Analyzer Class
- Can provide Url, Json File Path, or Python List.
- If nothing is provided it will default to Microsofts Analysis Services report with BPA Rules.
- https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json
+ '''_summary_
+ '''
+ '''Best Practice Analyzer Class. Can provide Url, Json File Path, or Python List. If nothing is provided it will default to Microsofts Analysis Services report with BPA Rules.
+ [Default BPA](https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json)
'''
def __init__(self,rules_location:str='https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json') -> None:
'''
@@ -397,11 +415,9 @@ def __init__(self,rules_location:str='https://raw.githubusercontent.com/microsof
pass
#Todo... subclass with a namedtuple
class TE2:
- '''
- TE2 Class, to use any built TabularEditor Command Line Scripts
- https://docs.tabulareditor.com/te2/Command-line-Options.html
- #https://github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip
- #https://cdn.tabulareditor.com/files/TabularEditor.2.16.7.zip
+ '''TE2 Class, to use any built TabularEditor Command Line Scripts
+ [TE2 Command Line Example](https://docs.tabulareditor.com/te2/Command-line-Options.html)
+ [TE2 Download](https://github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip)
'''
def __init__(self,TE_Location='https://github.com/TabularEditor/TabularEditor/releases/download/2.16.7/TabularEditor.Portable.zip') -> None:
logging.debug(f'Checking for TE2 in {os.getcwd()}')
diff --git a/test/test_tabular.py b/test/test_tabular.py
index 33b0289..afd72a6 100644
--- a/test/test_tabular.py
+++ b/test/test_tabular.py
@@ -6,9 +6,10 @@
aas = pytabular.Tabular(localsecret.CONNECTION_STR['FIN 500'])
gen2 = pytabular.Tabular(localsecret.CONNECTION_STR['GEN2TEST'])
+testing_parameters = [(aas),(gen2)]
testingtable = 'PyTestTable'
-pytestmark = pytest.mark.parametrize("model",[(aas),(gen2)])
+@pytest.mark.parametrize("model",testing_parameters)
def test_connection(model):
'''
Does a quick check to the Tabular Class
@@ -16,39 +17,49 @@ def test_connection(model):
'''
assert model.Server.Connected
+@pytest.mark.parametrize("model",testing_parameters)
def test_database(model):
assert isinstance(model.Database,Database)
+@pytest.mark.parametrize("model",testing_parameters)
def test_query(model):
- '''
- Does a quick query on the model and checks if it will return expected value
- '''
df = model.Query('EVALUATE {1}')
assert df.iloc[0]['[Value]'] == 1
-def remove_py_tables(model):
- table_check = [table for table in model.Tables if testingtable in table.Name]
+
+def remove_testing_table(model):
+ table_check = [table for table in model.Model.Tables.GetEnumerator() if testingtable in table.Name]
for table in table_check:
model.Model.Tables.Remove(table)
- model.Model.SaveChanges()
- return True
+ model.SaveChanges()
+@pytest.mark.parametrize("model",testing_parameters)
def test_pre_table_checks(model):
- assert remove_py_tables(model) == True
+ remove_testing_table(model)
+ assert len([table for table in model.Model.Tables.GetEnumerator() if testingtable in table.Name]) == 0
+@pytest.mark.parametrize("model",testing_parameters)
def test_create_table(model):
df = pd.DataFrame(data={'col1':[1,2,3],'col2':['four','five','six']})
- assert model.Create_Table(df,testingtable) == True
+ assert model.Create_Table(df,testingtable)
+@pytest.mark.parametrize("model",testing_parameters)
def test_backingup_table(model):
- assert model.Backup_Table(testingtable) == True
+ model.Backup_Table(testingtable)
+ assert len([table for table in model.Model.Tables.GetEnumerator() if f'{testingtable}_backup' == table.Name]) == 1
+@pytest.mark.parametrize("model",testing_parameters)
def test_revert_table(model):
- assert model.Revert_Table(testingtable) == True
+ model.Revert_Table(testingtable)
+ assert len([table for table in model.Model.Tables.GetEnumerator() if f'{testingtable}' == table.Name]) == 1
+
+@pytest.mark.parametrize("model",testing_parameters)
def test_table_removal(model):
- assert remove_py_tables(model) == True
+ remove_testing_table(model)
+ assert len([table for table in model.Model.Tables.GetEnumerator() if testingtable in table.Name]) == 0
+@pytest.mark.parametrize("model",testing_parameters)
def test_bpa(model):
te2 = pytabular.TE2().EXE_Path
bpa = pytabular.BPA().Location