Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
extend-ignore=E203
extend-ignore=E203, D107
max-line-length=100
docstring-convention=google
2 changes: 1 addition & 1 deletion .github/workflows/docstr-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ jobs:
python-version: '3.10'
- run: pip install --upgrade pip
- run: pip install docstr-coverage==2.2.0
- run: docstr-coverage
- run: docstr-coverage --skip-init
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ docs/_config.yml# Byte-compiled / optimized / DLL files
*$py.class
/Best_Practice_Analyzer
/Tabular_Editor_2
*.tmdl

# Test files for new functionality
test-notebook.ipynb
Expand Down
21 changes: 0 additions & 21 deletions .pre-commit-config.yaml

This file was deleted.

1 change: 0 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
exclude pytabular/localsecret.py
include pytabular/dll/Microsoft.AnalysisServices.AdomdClient.dll
include pytabular/dll/Microsoft.AnalysisServices.Core.dll
include pytabular/dll/Microsoft.AnalysisServices.dll
Expand Down
1 change: 1 addition & 0 deletions docs/tmdl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:::pytabular.tmdl.Tmdl
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ nav:
- best_practice_analyzer: best_practice_analyzer.md
- pbi_helper: pbi_helper.md
- logic_utils: logic_utils.md
- tmdl: tmdl.md
- Running Traces: tabular_tracing.md
- Documenting Model: document.md
- Contributing: CONTRIBUTING.md
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "python_tabular"
version = "0.5.5"
version = "0.5.6"
authors = [
{ name="Curtis Stallings", email="curtisrstallings@gmail.com" },
]
Expand All @@ -25,6 +25,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Development Status :: 5 - Production/Stable",
"Operating System :: Microsoft",
"License :: OSI Approved :: MIT License"
Expand Down
1 change: 1 addition & 0 deletions pytabular/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
from .query import Connection
from .pbi_helper import find_local_pbi_instances
from .document import ModelDocumenter
from .tmdl import Tmdl


logger.info("Import successful...")
45 changes: 45 additions & 0 deletions pytabular/tmdl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""See [TMDL Scripting].(https://learn.microsoft.com/en-us/analysis-services/tmdl/tmdl-overview).

Run `Tmdl(model).save_to_folder()` to save tmdl of model.
Run `Tmdl(model).execute()` to execute a specific set of tmdl scripts.
"""

from Microsoft.AnalysisServices.Tabular import TmdlSerializer


class Tmdl:
"""Specify the specific model you want to use for scripting.

Args:
model (Tabular): Initialize with Tabular model.
"""
def __init__(self, model):
self.model = model

def save_to_folder(self, path: str = "tmdl"):
"""Runs `SerializeModelToFolder` from .net library.

Args:
path (str, optional): directory where to save tmdl structure.
Defaults to "tmdl".
"""
TmdlSerializer.SerializeModelToFolder(self.model._object, path)
return True

def execute(self, path: str = "tmdl", auto_save: bool = True):
"""Runs `DeserializeModelFromFolder` from .net library.

Args:
path (str, optional): directory to look for tmdl scripts.
Defaults to "tmdl".
auto_save (bool, optional): You can set to false
if you want to precheck a few things, but will need to
run `model.save_changes()`. Setting to `True` will go ahead
and execute `model.save_changes()` Defaults to True.
"""
model_object = TmdlSerializer.DeserializeModelFromFolder(path)
model_object.CopyTo(self.model._object)
if auto_save:
return self.model.save_changes()
else:
return True
10 changes: 10 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ def remove_testing_table(model):
model.SaveChanges()


def pytest_generate_tests(metafunc):
"""Creates the model param for most tests.

Will update to use a semantic model via online connection
vs. connecting to a local model.
"""
if "model" in metafunc.fixturenames:
metafunc.parametrize("model", [local_pbix], ids=[local_pbix.Name])


def pytest_sessionstart(session):
"""Run at pytest start.

Expand Down
7 changes: 0 additions & 7 deletions test/run_versions.bat

This file was deleted.

2 changes: 0 additions & 2 deletions test/test_10logic_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""pytest for the table.py file. Covers the PyTable and PyTables classes."""

from test.config import testing_parameters
import pytest
from pytabular import logic_utils
import pandas as pd
Expand Down Expand Up @@ -54,7 +53,6 @@ def test_dataframe_to_dict(df):
assert isinstance(logic_utils.dataframe_to_dict(df), list)


@pytest.mark.parametrize("model", testing_parameters)
def test_dict_to_markdown_table(model):
"""Tests `dict_to_markdown_table()` function."""
dependencies = [measure.get_dependencies() for measure in model.Measures]
Expand Down
2 changes: 0 additions & 2 deletions test/test_11document.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
"""Tests to cover the document.py file."""

from test.config import testing_parameters
import pytest
import pytabular as p
import os
from pytabular import logic_utils
from test.conftest import TestStorage


@pytest.mark.parametrize("model", testing_parameters)
def test_basic_document_funcionality(model):
"""Tests basic documentation functionality."""
try:
Expand Down
18 changes: 18 additions & 0 deletions test/test_12tmdl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Tests to cover the tmdl.py file."""

import pytabular as p

path = "tmdl_testing"


def test_tmdl_save(model):
"""Tests basic tmdl save to folder functionality."""
stf = p.Tmdl(model).save_to_folder(path)
assert stf


def test_tmdl_execute(model):
"""Tests basic tmdl execute functionality."""
exec = p.Tmdl(model).execute(path, False)
p.logic_utils.remove_folder_and_contents(path)
assert exec
7 changes: 1 addition & 6 deletions test/test_1sanity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,19 @@
Or am I crazy person about to descend into madness.
"""

import pytest
from Microsoft.AnalysisServices.Tabular import Database
from test.config import testing_parameters


@pytest.mark.parametrize("model", testing_parameters)
def test_sanity_check(model):
def test_sanity_check():
"""Just in case... I might be crazy."""
assert 1 == 1


@pytest.mark.parametrize("model", testing_parameters)
def test_connection(model):
"""Does a quick check on connection to `Tabular()` class."""
assert model.Server.Connected


@pytest.mark.parametrize("model", testing_parameters)
def test_database(model):
"""Tests that `model.Database` is actually a Database."""
assert isinstance(model.Database, Database)
14 changes: 0 additions & 14 deletions test/test_2object.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"""pytest for the table.py file. Covers the PyTable and PyTables classes."""

from test.config import testing_parameters
import pytest
from pytabular import Tabular


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_model(model):
"""Tests successful `__rich_repr()` `on Tabular()` class."""
try:
Expand All @@ -14,7 +12,6 @@ def test_rich_repr_model(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_table(model):
"""Tests successful `__rich_repr()` `on PyTable()` class."""
try:
Expand All @@ -23,7 +20,6 @@ def test_rich_repr_table(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_tables(model):
"""Tests successful `__rich_repr()` `on PyTables()` class."""
try:
Expand All @@ -32,7 +28,6 @@ def test_rich_repr_tables(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_column(model):
"""Tests successful `__rich_repr()` `on PyColumn()` class."""
try:
Expand All @@ -41,7 +36,6 @@ def test_rich_repr_column(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_columns(model):
"""Tests successful `__rich_repr()` `on PyColumns()` class."""
try:
Expand All @@ -50,7 +44,6 @@ def test_rich_repr_columns(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_partition(model):
"""Tests successful `__rich_repr()` `on PyPartition()` class."""
try:
Expand All @@ -59,7 +52,6 @@ def test_rich_repr_partition(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_partitions(model):
"""Tests successful `__rich_repr()` `on PyPartitions()` class."""
try:
Expand All @@ -68,7 +60,6 @@ def test_rich_repr_partitions(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_measure(model):
"""Tests successful `__rich_repr()` `on PyMeasure()` class."""
try:
Expand All @@ -77,7 +68,6 @@ def test_rich_repr_measure(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_rich_repr_measures(model):
"""Tests successful `__rich_repr()` `on PyMeasures()` class."""
try:
Expand All @@ -86,13 +76,11 @@ def test_rich_repr_measures(model):
pytest.fail("__rich_repr__() failed")


@pytest.mark.parametrize("model", testing_parameters)
def test_get_attr(model):
"""Tests custom get attribute from `PyObject` class."""
assert isinstance(model.Tables[0].Model, Tabular)


@pytest.mark.parametrize("model", testing_parameters)
def test_iadd_tables(model):
"""Tests `__iadd__()` with `PyTables()`."""
a = model.Tables.find("Sales")
Expand All @@ -101,7 +89,6 @@ def test_iadd_tables(model):
assert len(a.find("Date")) > 0


@pytest.mark.parametrize("model", testing_parameters)
def test_iadd_table(model):
"""Tests `__iadd__()` with a `PyTable()`."""
a = model.Tables.find("Sales")
Expand All @@ -110,7 +97,6 @@ def test_iadd_table(model):
assert len(a.find("Date")) > 0


@pytest.mark.parametrize("model", testing_parameters)
def test_find_measure(model):
"""Tests `find()` with a `PyMeasure()`."""
a = model.Measures[0].Name
Expand Down
Loading