From d77fef822fdb9ca913ffb096f6353ca86ed1020f Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Mon, 20 Apr 2026 14:45:47 -0700 Subject: [PATCH 1/2] fix tests in publishing --- .../publish_command.py | 26 +++++++++---------- tests/assets/mock_data.py | 10 ++++++- tests/commands/test_publish_command.py | 13 ++++++---- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/tabcmd/commands/datasources_and_workbooks/publish_command.py b/tabcmd/commands/datasources_and_workbooks/publish_command.py index c08afe07..a4139eaa 100644 --- a/tabcmd/commands/datasources_and_workbooks/publish_command.py +++ b/tabcmd/commands/datasources_and_workbooks/publish_command.py @@ -63,21 +63,21 @@ def run_command(args): publish_mode = PublishCommand.get_publish_mode(args, logger) - connection = TSC.models.ConnectionItem() + # Build both forms: workbook "connections" (ConnectionItem) and datasource "connection_credentials" + workbook_connections = None + datasource_credentials = None if args.db_username: - connection.connection_credentials = TSC.models.ConnectionCredentials( - args.db_username, args.db_password, embed=args.save_db_password - ) + creds = TSC.models.ConnectionCredentials(args.db_username, args.db_password, embed=args.save_db_password) + workbook_connections = TSC.ConnectionItem() + workbook_connections.connection_credentials = creds + datasource_credentials = creds elif args.oauth_username: - connection.connection_credentials = TSC.models.ConnectionCredentials( - args.oauth_username, None, embed=False, oauth=args.save_oauth - ) + creds = TSC.models.ConnectionCredentials(args.oauth_username, None, embed=False, oauth=args.save_oauth) + workbook_connections = TSC.ConnectionItem() + workbook_connections.connection_credentials = creds + datasource_credentials = creds else: logger.debug("No db-username or oauth-username found in command") - creds = None - credentials = TSC.ConnectionItem() if creds else None - if credentials: - credentials.connection_credentials = creds files = PublishCommand.get_files_to_publish(args, logger) @@ -94,7 +94,7 @@ def run_command(args): project_id=project_id, str_filename=str_filename, publish_mode=publish_mode, - credentials=credentials, + credentials=workbook_connections, ) except Exception as e: Errors.exit_with_error(logger, exception=e) @@ -109,7 +109,7 @@ def run_command(args): project_id=project_id, str_filename=str_filename, publish_mode=publish_mode, - credentials=creds, + credentials=datasource_credentials, ) except Exception as exc: Errors.exit_with_error(logger, exception=exc) diff --git a/tests/assets/mock_data.py b/tests/assets/mock_data.py index e0d4a77e..e7d3468c 100644 --- a/tests/assets/mock_data.py +++ b/tests/assets/mock_data.py @@ -93,7 +93,15 @@ def set_up_mock_server(mock_session): mock_server.any_item_type = getter mock_server.flows = getter mock_server.groups = getter - mock_server.projects = getter + # Ensure type name contains 'Projects' for filtering heuristics + class ProjectsEndpoint: + def __init__(self, ret): + self._ret = ret + + def get(self, req_option): + return self._ret + + mock_server.projects = ProjectsEndpoint(([create_fake_item()], fake_pagination)) mock_server.sites = getter mock_server.users = getter mock_server.views = getter diff --git a/tests/commands/test_publish_command.py b/tests/commands/test_publish_command.py index 753d9555..368fd997 100644 --- a/tests/commands/test_publish_command.py +++ b/tests/commands/test_publish_command.py @@ -3,11 +3,14 @@ import tableauserverclient as TSC from ..assets import mock_data from unittest.mock import * +from unittest import mock from tabcmd.commands.datasources_and_workbooks.publish_command import PublishCommand +from tabcmd.commands.datasources_and_workbooks import publish_command from ..assets.mock_data import set_up_mock_args, set_up_mock_file, set_up_mock_path, set_up_mock_server mock_args = set_up_mock_args() +mock_logger = mock.MagicMock() # mock the module as it is imported *when used* @@ -83,7 +86,7 @@ def test_get_files_to_publish_folder(self, mock_path, mock_glob, mock_session): actual = PublishCommand.get_files_to_publish(mock_args, logging) assert actual == expected - def test_default_publish_mode(self, mock_session, mock_server): + def test_default_publish_mode(self, mock_path, mock_glob, mock_session): mock_args.replace = False mock_args.append = False mock_args.overwrite = False @@ -91,7 +94,7 @@ def test_default_publish_mode(self, mock_session, mock_server): publish_mode = publish_command.PublishCommand.get_publish_mode(mock_args, mock_logger) self.assertEqual(publish_mode, TSC.Server.PublishMode.CreateNew) - def test_replace_publish_mode(self, mock_session, mock_server): + def test_replace_publish_mode(self, mock_path, mock_glob, mock_session): mock_args.replace = True mock_args.append = False mock_args.overwrite = False @@ -99,7 +102,7 @@ def test_replace_publish_mode(self, mock_session, mock_server): publish_mode = publish_command.PublishCommand.get_publish_mode(mock_args, mock_logger) self.assertEqual(publish_mode, TSC.Server.PublishMode.Replace) - def test_append_publish_mode(self, mock_session, mock_server): + def test_append_publish_mode(self, mock_path, mock_glob, mock_session): mock_args.replace = False mock_args.append = True mock_args.overwrite = False @@ -107,7 +110,7 @@ def test_append_publish_mode(self, mock_session, mock_server): publish_mode = publish_command.PublishCommand.get_publish_mode(mock_args, mock_logger) self.assertEqual(publish_mode, TSC.Server.PublishMode.Append) - def test_overwrite_publish_mode(self, mock_session, mock_server): + def test_overwrite_publish_mode(self, mock_path, mock_glob, mock_session): mock_args.replace = False mock_args.append = False mock_args.overwrite = True @@ -115,7 +118,7 @@ def test_overwrite_publish_mode(self, mock_session, mock_server): publish_mode = publish_command.PublishCommand.get_publish_mode(mock_args, mock_logger) self.assertEqual(publish_mode, TSC.Server.PublishMode.Overwrite) - def test_invalid_combination_of_modes(self, mock_session, mock_server): + def test_invalid_combination_of_modes(self, mock_path, mock_glob, mock_session): mock_args.replace = True mock_args.append = True mock_args.overwrite = False From 48c7ce4a84fc5cb9ccfe711b36f8564fd88d545d Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Tue, 21 Apr 2026 14:00:35 -0700 Subject: [PATCH 2/2] remove 3.9, add 3.14 --- .github/workflows/python-app.yml | 2 +- .github/workflows/run-e2-tests.yml | 2 +- .github/workflows/run-tests.yml | 2 +- pyproject.toml | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index c294aff4..ecc6b622 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/run-e2-tests.yml b/.github/workflows/run-e2-tests.yml index 1d7c3e17..3e35346b 100644 --- a/.github/workflows/run-e2-tests.yml +++ b/.github/workflows/run-e2-tests.yml @@ -18,7 +18,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index b21f2da4..d16f0722 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -15,7 +15,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] runs-on: ${{ matrix.os }} diff --git a/pyproject.toml b/pyproject.toml index fcab3277..19edd041 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,15 +32,15 @@ authors = [{name="Tableau", email="github@tableau.com"}] license = "MIT" license-files = ["LICENSE"] readme = "res/README.md" -requires-python = ">=3.9" # https://devguide.python.org/versions/ +requires-python = ">=3.10" # https://devguide.python.org/versions/ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13" + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14" ] dependencies = [ "appdirs",