diff --git a/.flake8 b/.flake8 index 32ee067..70ecf2a 100644 --- a/.flake8 +++ b/.flake8 @@ -1,4 +1,4 @@ [flake8] -extend-ignore=E203 +extend-ignore=E203, D107 max-line-length=100 docstring-convention=google \ No newline at end of file diff --git a/.github/workflows/docstr-coverage.yml b/.github/workflows/docstr-coverage.yml index 2a970da..cf7c595 100644 --- a/.github/workflows/docstr-coverage.yml +++ b/.github/workflows/docstr-coverage.yml @@ -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 \ No newline at end of file + - run: docstr-coverage --skip-init \ No newline at end of file diff --git a/.gitignore b/.gitignore index b8078c0..cdcc69b 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 4d06154..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -default_stages: [push] -repos: -- repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - verbose: true -- repo: https://github.com/HunterMcGushion/docstr_coverage - rev: v2.2.0 - hooks: - - id: docstr-coverage - verbose: true -- repo: local - hooks: - - id: pytest - name: pytest - entry: pytest - language: system - pass_filenames: false - types: [python] - verbose: true \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index ca9d6c4..f93f862 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -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 diff --git a/docs/tmdl.md b/docs/tmdl.md new file mode 100644 index 0000000..187e8e6 --- /dev/null +++ b/docs/tmdl.md @@ -0,0 +1 @@ +:::pytabular.tmdl.Tmdl \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 662aa47..c091be9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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 diff --git a/pyproject.toml b/pyproject.toml index f37dba5..ac031ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" }, ] @@ -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" diff --git a/pytabular/__init__.py b/pytabular/__init__.py index 64bfa84..f49bcb9 100644 --- a/pytabular/__init__.py +++ b/pytabular/__init__.py @@ -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...") diff --git a/pytabular/tmdl.py b/pytabular/tmdl.py new file mode 100644 index 0000000..305b424 --- /dev/null +++ b/pytabular/tmdl.py @@ -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 diff --git a/test/conftest.py b/test/conftest.py index 67f83d0..5c5b0c3 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -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. diff --git a/test/run_versions.bat b/test/run_versions.bat deleted file mode 100644 index dda824e..0000000 --- a/test/run_versions.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo on -pyenv shell 3.8.9 & python3 -m pytest & -pyenv shell 3.9.13 & python3 -m pytest & -pyenv shell 3.10.6 & python3 -m pytest & -pyenv shell 3.11.9 & python3 -m pytest & -pyenv shell 3.12.6 & python3 -m pytest & -pause & pause \ No newline at end of file diff --git a/test/test_10logic_utils.py b/test/test_10logic_utils.py index 3220601..0ed7bd2 100644 --- a/test/test_10logic_utils.py +++ b/test/test_10logic_utils.py @@ -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 @@ -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] diff --git a/test/test_11document.py b/test/test_11document.py index 8ee45f4..da4bb47 100644 --- a/test/test_11document.py +++ b/test/test_11document.py @@ -1,6 +1,5 @@ """Tests to cover the document.py file.""" -from test.config import testing_parameters import pytest import pytabular as p import os @@ -8,7 +7,6 @@ from test.conftest import TestStorage -@pytest.mark.parametrize("model", testing_parameters) def test_basic_document_funcionality(model): """Tests basic documentation functionality.""" try: diff --git a/test/test_12tmdl.py b/test/test_12tmdl.py new file mode 100644 index 0000000..236eecc --- /dev/null +++ b/test/test_12tmdl.py @@ -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 diff --git a/test/test_1sanity.py b/test/test_1sanity.py index 7fb8250..2c18ca5 100644 --- a/test/test_1sanity.py +++ b/test/test_1sanity.py @@ -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) diff --git a/test/test_2object.py b/test/test_2object.py index ae2fe27..81b228d 100644 --- a/test/test_2object.py +++ b/test/test_2object.py @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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") @@ -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") @@ -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 diff --git a/test/test_3tabular.py b/test/test_3tabular.py index 0fc08e2..7ac63dc 100644 --- a/test/test_3tabular.py +++ b/test/test_3tabular.py @@ -3,10 +3,9 @@ import pytest import pandas as pd import pytabular as p -from test.config import testingtablename, testing_parameters, get_test_path +from test.config import testingtablename, get_test_path -@pytest.mark.parametrize("model", testing_parameters) def test_basic_query(model): """Tests a basic query execution.""" int_result = model.query("EVALUATE {1}") @@ -21,7 +20,6 @@ def test_basic_query(model): ] -@pytest.mark.parametrize("model", testing_parameters) def test_datatype_query(model): """Tests the results of different datatypes.""" for query in datatype_queries: @@ -29,7 +27,6 @@ def test_datatype_query(model): assert result == query[0] -@pytest.mark.parametrize("model", testing_parameters) def test_file_query(model): """Test `query()` via a file.""" singlevaltest = get_test_path() + "\\singlevaltest.dax" @@ -38,37 +35,31 @@ def test_file_query(model): assert model.query(singlevaltest) == 1 and model.query(dfvaltest).equals(dfdupe) -@pytest.mark.parametrize("model", testing_parameters) def test_repr_str(model): """Testing successful `__repr__()` on model.""" assert isinstance(model.__repr__(), str) -@pytest.mark.parametrize("model", testing_parameters) def test_pytables_count(model): """Testing row count of testingtable.""" assert model.Tables[testingtablename].row_count() > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_pytables_refresh(model): """Tests refrshing table of testingtable.""" assert len(model.Tables[testingtablename].refresh()) > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_pypartition_refresh(model): """Tests refreshing partition of testingtable.""" assert len(model.Tables[testingtablename].Partitions[0].refresh()) > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_pypartitions_refresh(model): """Tests refreshing partitions of testingtable.""" assert len(model.Tables[testingtablename].Partitions.refresh()) > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_pyobjects_adding(model): """Tests adding a PyObject.""" table = model.Tables.find(testingtablename) @@ -76,7 +67,6 @@ def test_pyobjects_adding(model): assert len(table) == 2 -@pytest.mark.parametrize("model", testing_parameters) def test_nonetype_decimal_bug(model): """Tests the pesky nonetype decimal bug.""" query_str = """ @@ -90,40 +80,34 @@ def test_nonetype_decimal_bug(model): assert len(model.query(query_str)) == 3 -@pytest.mark.parametrize("model", testing_parameters) def test_table_last_refresh_times(model): """Really just testing the the function completes successfully and returns df.""" assert isinstance(model.Tables.last_refresh(), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_return_zero_row_tables(model): """Testing that `find_zero_rows()`.""" assert isinstance(model.Tables.find_zero_rows(), p.pytabular.PyTables) -@pytest.mark.parametrize("model", testing_parameters) def test_get_dependencies(model): """Tests execution of `PyMeasure.get_dependencies()`.""" dependencies = model.Measures[0].get_dependencies() assert len(dependencies) > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_disconnect(model): """Tests `Disconnect()` from `Tabular` class.""" model.disconnect() assert model.Server.Connected is False -@pytest.mark.parametrize("model", testing_parameters) def test_reconnect(model): """Tests `Reconnect()` from `Tabular` class.""" model.reconnect() assert model.Server.Connected is True -@pytest.mark.parametrize("model", testing_parameters) def test_reconnect_savechanges(model): """This will test the `reconnect()` gets called in `save_changes()`.""" model.disconnect() @@ -131,20 +115,17 @@ def test_reconnect_savechanges(model): assert model.Server.Connected is True -@pytest.mark.parametrize("model", testing_parameters) def test_is_process(model): """Checks that `Is_Process()` from `Tabular` class returns bool.""" assert isinstance(model.is_process(), bool) -@pytest.mark.parametrize("model", testing_parameters) def test_bad_table(model): """Checks for unable to find table exception.""" with pytest.raises(Exception): model.refresh("badtablename") -@pytest.mark.parametrize("model", testing_parameters) def test_refresh_dict(model): """Checks for refreshing dictionary.""" table = model.Tables[testingtablename] @@ -152,7 +133,6 @@ def test_refresh_dict(model): assert isinstance(refresh, pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_refresh_dict_pypartition(model): """Checks for refreshing dictionary with PyPartition.""" table = model.Tables[testingtablename] @@ -160,7 +140,6 @@ def test_refresh_dict_pypartition(model): assert isinstance(refresh, pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_bad_partition(model): """Checks for refreshing dictionary failure.""" table = model.Tables[testingtablename] diff --git a/test/test_4measure.py b/test/test_4measure.py index 5c18d38..807584c 100644 --- a/test/test_4measure.py +++ b/test/test_4measure.py @@ -1,10 +1,6 @@ """Bulk of pytests for `PyMeasure()` class.""" -import pytest -from test.config import testing_parameters - -@pytest.mark.parametrize("model", testing_parameters) def test_create_measure(model): """Test Creating Measure.""" name = "Test Measure" diff --git a/test/test_5column.py b/test/test_5column.py index 6f1567f..a44a0cd 100644 --- a/test/test_5column.py +++ b/test/test_5column.py @@ -1,46 +1,39 @@ """pytest for the column.py file. Covers the PyColumn and PyColumns classes.""" -from test.config import testing_parameters, testingtablename -import pytest +from test.config import testingtablename import pandas as pd from numpy import int64 -@pytest.mark.parametrize("model", testing_parameters) def test_values(model): """Tests for `Values()` of PyColumn class.""" vals = model.Tables[testingtablename].Columns[1].values() assert isinstance(vals, pd.DataFrame) or isinstance(vals, int) -@pytest.mark.parametrize("model", testing_parameters) def test_distinct_count_no_blank(model): """Tests No_Blank=True for `Distinct_Count()` of PyColumn class.""" vals = model.Tables[testingtablename].Columns[1].distinct_count(no_blank=True) assert isinstance(vals, int64) -@pytest.mark.parametrize("model", testing_parameters) def test_distinct_count_blank(model): """Tests No_Blank=False for `Distinct_Count()` of PyColumn class.""" vals = model.Tables[testingtablename].Columns[1].distinct_count(no_blank=False) assert isinstance(vals, int64) -@pytest.mark.parametrize("model", testing_parameters) def test_get_sample_values(model): """Tests for `get_sample_values()` of PyColumn class.""" sample_vals = model.Tables[testingtablename].Columns[1].get_sample_values() assert isinstance(sample_vals, pd.DataFrame) or isinstance(sample_vals, int) -@pytest.mark.parametrize("model", testing_parameters) def test_query_every_column(model): """Tests `Query_All()` of PyColumns class.""" assert isinstance(model.Tables[testingtablename].Columns.query_all(), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_dependencies(model): """Tests execution of `PyColumn().get_dependencies()`.""" df = model.Tables[0].Columns[1].get_dependencies() diff --git a/test/test_6table.py b/test/test_6table.py index aa1c12e..daea7a7 100644 --- a/test/test_6table.py +++ b/test/test_6table.py @@ -1,60 +1,50 @@ """pytest for the table.py file. Covers the PyTable and PyTables classes.""" -from test.config import testing_parameters, testingtablename -import pytest +from test.config import testingtablename import pandas as pd from datetime import datetime -@pytest.mark.parametrize("model", testing_parameters) def test_row_count(model): """Tests for `Row_Count()` of PyTable class.""" assert model.Tables[testingtablename].row_count() > 0 -@pytest.mark.parametrize("model", testing_parameters) def test_refresh(model): """Tests for `Refresh()` of PyTable class.""" assert isinstance(model.Tables[testingtablename].refresh(), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_last_refresh(model): """Tests for `Last_Refresh()` of PyTable class.""" assert isinstance(model.Tables[testingtablename].last_refresh(), datetime) -@pytest.mark.parametrize("model", testing_parameters) def test_related(model): """Tests for `Related()` of PyTable class.""" assert isinstance(model.Tables[testingtablename].related(), type(model.Tables)) -@pytest.mark.parametrize("model", testing_parameters) def test_refresh_pytables(model): """Tests for `Refresh()` of PyTables class.""" assert isinstance(model.Tables.find(testingtablename).refresh(), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_query_all_pytables(model): """Tests for `Query_All()` of PyTables class.""" assert isinstance(model.Tables.query_all(), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_find_zero_rows_pytables(model): """Tests for `Find_Zero_Rows()` of PyTables class.""" assert isinstance(model.Tables.find_zero_rows(), type(model.Tables)) -@pytest.mark.parametrize("model", testing_parameters) def test_last_refresh_pytables_true(model): """Tests group_partition=True for `Last_Refresh()` of PyTables class.""" assert isinstance(model.Tables.last_refresh(group_partition=True), pd.DataFrame) -@pytest.mark.parametrize("model", testing_parameters) def test_last_refresh_pytables_false(model): """Tests group_partition=False for `Last_Refresh()` of PyTables class.""" assert isinstance(model.Tables.last_refresh(group_partition=False), pd.DataFrame) diff --git a/test/test_7tabular_tracing.py b/test/test_7tabular_tracing.py index 816cd89..36526a2 100644 --- a/test/test_7tabular_tracing.py +++ b/test/test_7tabular_tracing.py @@ -1,19 +1,16 @@ """pytest for the table.py file. Covers the PyTable and PyTables classes.""" -from test.config import testing_parameters, testingtablename -import pytest +from test.config import testingtablename import pytabular as p from test.conftest import TestStorage -@pytest.mark.parametrize("model", testing_parameters) def test_disconnect_for_trace(model): """Tests `disconnect()` from `Tabular` class.""" model.disconnect() assert model.Server.Connected is False -@pytest.mark.parametrize("model", testing_parameters) def test_reconnect_update(model): """This will test the `reconnect()`. @@ -24,7 +21,6 @@ def test_reconnect_update(model): assert model.Server.Connected is True -@pytest.mark.parametrize("model", testing_parameters) def test_query_monitor_start(model): """This will test the `QueryMonitor` trace and `start()` it.""" query_trace = p.QueryMonitor(model) @@ -33,14 +29,12 @@ def test_query_monitor_start(model): assert TestStorage.query_trace.Trace.IsStarted -@pytest.mark.parametrize("model", testing_parameters) def test_query_monitor_stop(model): """Tests `stop()` of `QueryMonitor` trace.""" TestStorage.query_trace.stop() assert TestStorage.query_trace.Trace.IsStarted is False -@pytest.mark.parametrize("model", testing_parameters) def test_query_monitor_drop(model): """Tests `drop()` of `QueryMonitor` trace.""" assert TestStorage.query_trace.drop() is None diff --git a/test/test_8bpa.py b/test/test_8bpa.py index b59f2f8..a153d38 100644 --- a/test/test_8bpa.py +++ b/test/test_8bpa.py @@ -1,12 +1,9 @@ """pytest for bpa.""" -import pytest import pytabular as p -from test.config import testing_parameters from os import getcwd -@pytest.mark.parametrize("model", testing_parameters) def test_bpa(model): """Testing execution of `model.analyze_bpa()`.""" te2 = p.TabularEditor(verify_download=False).exe @@ -14,13 +11,11 @@ def test_bpa(model): assert isinstance(model.analyze_bpa(te2, bpa), list) -@pytest.mark.parametrize("model", testing_parameters) def test_te2_custom_file_path(model): """Testing TE2 Class.""" assert isinstance(p.TabularEditor(getcwd()), p.TabularEditor) -@pytest.mark.parametrize("model", testing_parameters) def test_bpa_custom_file_path(model): """Testing BPA Class.""" assert isinstance(p.BPA(getcwd()), p.BPA) diff --git a/test/test_9custom.py b/test/test_9custom.py index 25f005c..8a6b145 100644 --- a/test/test_9custom.py +++ b/test/test_9custom.py @@ -4,11 +4,9 @@ So seperating out... To one day sunset and remove. """ -from test.config import testing_parameters, testingtablename -import pytest +from test.config import testingtablename -@pytest.mark.parametrize("model", testing_parameters) def test_backingup_table(model): """Tests model.backup_table().""" model.backup_table(testingtablename) @@ -24,7 +22,6 @@ def test_backingup_table(model): ) -@pytest.mark.parametrize("model", testing_parameters) def test_revert_table2(model): """Tests model.revert_table().""" model.revert_table(testingtablename) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..9368bb2 --- /dev/null +++ b/tox.ini @@ -0,0 +1,46 @@ +[tox] +env_list = docstring, linter, mkdocs, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 + +[testenv] +description = "run unit tests" +skip_install = True +; Currently managing these dependencies in two spots... +; pyproject.toml & tox.ini +; need to figure that out +setenv = + VIRTUALENV_NO_SETUPTOOLS=1 +deps = + pythonnet>=3.0.3 + clr-loader>=0.2.6 + xmltodict==0.13.0 + pandas>=1.4.3 + requests>=2.28.1 + rich>=12.5.1 + pytest +commands = + pytest + +[testenv:docstring] +description = check docstring coverage +skip_install=True +deps = + docstr-coverage==2.3.2 +commands = docstr-coverage --skip-init + +[testenv:linter] +description = run linters +skip_install = True +deps = flake8 + pep8-naming + flake8-docstrings +commands = flake8 pytabular test --count + +[testenv:mkdocs] +description = check doc creation +skip_install = True +deps = + mkdocstrings[python] + mkdocs-material + mkdocs + mkdocs-gen-files +commands = mkdocs build \ No newline at end of file