From e418c611c53e701ec057d48bddada19b1cca1538 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Tue, 21 Jul 2026 23:08:09 -0700 Subject: [PATCH] feat: consolidate and export public type aliases from tableauserverclient.types HyperAction*, FilePath, FileObject*, PathOrFile*, AddResponse, IDPAttributes, IDPProperty, and HasIdpConfigurationID were defined locally in endpoint files (in some cases duplicated across 4 files) but not importable from the top-level package. Users annotating calls to update_hyper_data(), publish(), download(), add_to_schedule(), or OIDC methods had to import from internal modules. Move all shared type aliases to tableauserverclient/types.py and re-export from tableauserverclient/__init__.py. Co-Authored-By: Claude Sonnet 4.6 --- tableauserverclient/__init__.py | 33 ++++++++++ .../server/endpoint/custom_views_endpoint.py | 8 +-- .../server/endpoint/datasources_endpoint.py | 64 +++++-------------- .../server/endpoint/flows_endpoint.py | 10 +-- .../server/endpoint/oidc_endpoint.py | 15 +---- .../server/endpoint/schedules_endpoint.py | 3 +- .../server/endpoint/workbooks_endpoint.py | 19 +++--- tableauserverclient/types.py | 62 ++++++++++++++++++ 8 files changed, 127 insertions(+), 87 deletions(-) create mode 100644 tableauserverclient/types.py diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index 7241f23ca..b90fae944 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -58,6 +58,24 @@ WorkbookItem, ) +from tableauserverclient.types import ( + AddResponse, + FilePath, + FileObject, + FileObjectR, + FileObjectW, + HasIdpConfigurationID, + HyperAction, + HyperActionCondition, + HyperActionRow, + HyperActionTable, + IDPAttributes, + IDPProperty, + PathOrFile, + PathOrFileR, + PathOrFileW, +) + from tableauserverclient.server import ( CSVRequestOptions, ExcelRequestOptions, @@ -76,6 +94,7 @@ ) __all__ = [ + "AddResponse", "BackgroundJobItem", "CollectionItem", "ColumnItem", @@ -96,13 +115,24 @@ "FailedSignInError", "FavoriteItem", "FileuploadItem", + "FilePath", + "FileObject", + "FileObjectR", + "FileObjectW", "Filter", "FlowItem", "FlowRunItem", "get_versions", "GroupItem", "GroupSetItem", + "HasIdpConfigurationID", "HourlyInterval", + "HyperAction", + "HyperActionCondition", + "HyperActionRow", + "HyperActionTable", + "IDPAttributes", + "IDPProperty", "ImageRequestOptions", "IntervalItem", "JobItem", @@ -122,6 +152,9 @@ "Permission", "PermissionsRule", "PersonalAccessTokenAuth", + "PathOrFile", + "PathOrFileR", + "PathOrFileW", "ProjectItem", "RequestOptions", "Resource", diff --git a/tableauserverclient/server/endpoint/custom_views_endpoint.py b/tableauserverclient/server/endpoint/custom_views_endpoint.py index 55f0c7ea2..105140677 100644 --- a/tableauserverclient/server/endpoint/custom_views_endpoint.py +++ b/tableauserverclient/server/endpoint/custom_views_endpoint.py @@ -32,12 +32,8 @@ update the name or owner of a custom view. """ -FilePath = str | os.PathLike -FileObject = io.BufferedReader | io.BytesIO -FileObjectR = io.BufferedReader | io.BytesIO -FileObjectW = io.BufferedWriter | io.BytesIO -PathOrFileR = FilePath | FileObjectR -PathOrFileW = FilePath | FileObjectW +from tableauserverclient.types import FilePath, FileObject, FileObjectR, FileObjectW, PathOrFileR, PathOrFileW + io_types_r = (io.BufferedReader, io.BytesIO) io_types_w = (io.BufferedWriter, io.BytesIO) diff --git a/tableauserverclient/server/endpoint/datasources_endpoint.py b/tableauserverclient/server/endpoint/datasources_endpoint.py index f5212485a..db38ee624 100644 --- a/tableauserverclient/server/endpoint/datasources_endpoint.py +++ b/tableauserverclient/server/endpoint/datasources_endpoint.py @@ -4,16 +4,29 @@ import os from pathlib import Path -from typing import Literal, TYPE_CHECKING, TypedDict, TypeVar, overload +from typing import Literal, TYPE_CHECKING, TypeVar, overload from collections.abc import Iterable, Sequence from tableauserverclient.models.dqw_item import DQWItem from tableauserverclient.server.query import QuerySet +from tableauserverclient.types import ( + FilePath, + FileObject, + FileObjectR, + FileObjectW, + PathOrFile, + PathOrFileR, + PathOrFileW, + HyperAction, + HyperActionCondition, + HyperActionRow, + HyperActionTable, + AddResponse, +) if TYPE_CHECKING: from tableauserverclient.server import Server from tableauserverclient.models import PermissionsRule - from .schedules_endpoint import AddResponse from tableauserverclient.server.endpoint.dqw_endpoint import _DataQualityWarningEndpoint from tableauserverclient.server.endpoint.endpoint import DownloadableMixin, QuerysetEndpoint, api, parameter_added_in @@ -44,53 +57,6 @@ io_types_r = (io.BytesIO, io.BufferedReader) -FilePath = str | os.PathLike -FileObject = io.BufferedReader | io.BytesIO -PathOrFile = FilePath | FileObject - -FileObjectR = io.BufferedReader | io.BytesIO -FileObjectW = io.BufferedWriter | io.BytesIO -PathOrFileR = FilePath | FileObjectR -PathOrFileW = FilePath | FileObjectW - - -HyperActionCondition = TypedDict( - "HyperActionCondition", - { - "op": str, - "target-col": str, - "source-col": str, - }, -) - -HyperActionRow = TypedDict( - "HyperActionRow", - { - "action": Literal[ - "update", - "upsert", - "delete", - ], - "source-table": str, - "target-table": str, - "condition": HyperActionCondition, - }, -) - -HyperActionTable = TypedDict( - "HyperActionTable", - { - "action": Literal[ - "insert", - "replace", - ], - "source-table": str, - "target-table": str, - }, -) - -HyperAction = HyperActionTable | HyperActionRow - _UNSET = object() diff --git a/tableauserverclient/server/endpoint/flows_endpoint.py b/tableauserverclient/server/endpoint/flows_endpoint.py index 8595006b8..b44ccb803 100644 --- a/tableauserverclient/server/endpoint/flows_endpoint.py +++ b/tableauserverclient/server/endpoint/flows_endpoint.py @@ -33,18 +33,12 @@ from tableauserverclient.helpers.logging import logger +from tableauserverclient.types import FilePath, FileObjectR, FileObjectW, PathOrFileR, PathOrFileW, AddResponse + if TYPE_CHECKING: from tableauserverclient.models import DQWItem from tableauserverclient.models.permissions_item import PermissionsRule from tableauserverclient.server.request_options import RequestOptions - from tableauserverclient.server.endpoint.schedules_endpoint import AddResponse - - -FilePath = str | os.PathLike -FileObjectR = io.BufferedReader | io.BytesIO -FileObjectW = io.BufferedWriter | io.BytesIO -PathOrFileR = FilePath | FileObjectR -PathOrFileW = FilePath | FileObjectW class Flows(QuerysetEndpoint[FlowItem], TaggingMixin[FlowItem], DownloadableMixin): diff --git a/tableauserverclient/server/endpoint/oidc_endpoint.py b/tableauserverclient/server/endpoint/oidc_endpoint.py index 1e6abd559..7b583f350 100644 --- a/tableauserverclient/server/endpoint/oidc_endpoint.py +++ b/tableauserverclient/server/endpoint/oidc_endpoint.py @@ -1,26 +1,15 @@ -from typing import Protocol, Union, TYPE_CHECKING +from typing import TYPE_CHECKING from tableauserverclient.models.oidc_item import SiteOIDCConfiguration from tableauserverclient.server.endpoint import Endpoint from tableauserverclient.server.request_factory import RequestFactory from tableauserverclient.server.endpoint.endpoint import api +from tableauserverclient.types import IDPAttributes, IDPProperty, HasIdpConfigurationID if TYPE_CHECKING: from tableauserverclient.models.site_item import SiteAuthConfiguration from tableauserverclient.server.server import Server -class IDPAttributes(Protocol): - idp_configuration_id: str - - -class IDPProperty(Protocol): - @property - def idp_configuration_id(self) -> str: ... - - -HasIdpConfigurationID = str | IDPAttributes - - class OIDC(Endpoint): def __init__(self, server: "Server") -> None: self.parent_srv = server diff --git a/tableauserverclient/server/endpoint/schedules_endpoint.py b/tableauserverclient/server/endpoint/schedules_endpoint.py index 321d0120b..fc92661a7 100644 --- a/tableauserverclient/server/endpoint/schedules_endpoint.py +++ b/tableauserverclient/server/endpoint/schedules_endpoint.py @@ -2,7 +2,6 @@ import copy import logging import warnings -from collections import namedtuple from typing import TYPE_CHECKING, Any, Callable, Literal, overload from .endpoint import Endpoint, api, parameter_added_in @@ -10,10 +9,10 @@ from tableauserverclient.server import RequestFactory from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem, ExtractItem from tableauserverclient.models.schedule_item import parse_batch_schedule_state +from tableauserverclient.types import AddResponse from tableauserverclient.helpers.logging import logger -AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created")) OK = AddResponse(result=True, error=None, warnings=None, task_created=None) if TYPE_CHECKING: diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index 8310d58b3..7741a5685 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -36,11 +36,20 @@ ) from collections.abc import Iterable, Sequence +from tableauserverclient.types import ( + FilePath, + FileObject, + FileObjectR, + FileObjectW, + PathOrFileR, + PathOrFileW, + AddResponse, +) + if TYPE_CHECKING: from tableauserverclient.server import Server from tableauserverclient.server.request_options import RequestOptions, PDFRequestOptions, PPTXRequestOptions from tableauserverclient.models import DatasourceItem - from tableauserverclient.server.endpoint.schedules_endpoint import AddResponse io_types_r = (io.BytesIO, io.BufferedReader) @@ -51,14 +60,6 @@ from tableauserverclient.helpers.logging import logger -FilePath = str | os.PathLike -FileObject = io.BufferedReader | io.BytesIO -FileObjectR = io.BufferedReader | io.BytesIO -FileObjectW = io.BufferedWriter | io.BytesIO -PathOrFileR = FilePath | FileObjectR -PathOrFileW = FilePath | FileObjectW - - _UNSET = object() diff --git a/tableauserverclient/types.py b/tableauserverclient/types.py new file mode 100644 index 000000000..2a6b25ce0 --- /dev/null +++ b/tableauserverclient/types.py @@ -0,0 +1,62 @@ +import io +import os +from collections import namedtuple +from typing import Literal, Protocol, TypedDict + +# File path and object type aliases used across publish/download methods +FilePath = str | os.PathLike +FileObject = io.BufferedReader | io.BytesIO +FileObjectR = io.BufferedReader | io.BytesIO +FileObjectW = io.BufferedWriter | io.BytesIO +PathOrFile = FilePath | FileObject +PathOrFileR = FilePath | FileObjectR +PathOrFileW = FilePath | FileObjectW + + +# Hyper action types for Datasources.update_hyper_data() +HyperActionCondition = TypedDict( + "HyperActionCondition", + { + "op": str, + "target-col": str, + "source-col": str, + }, +) + +HyperActionRow = TypedDict( + "HyperActionRow", + { + "action": Literal["update", "upsert", "delete"], + "source-table": str, + "target-table": str, + "condition": HyperActionCondition, + }, +) + +HyperActionTable = TypedDict( + "HyperActionTable", + { + "action": Literal["insert", "replace"], + "source-table": str, + "target-table": str, + }, +) + +HyperAction = HyperActionTable | HyperActionRow + + +# Return type for Schedules.add_to_schedule() +AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created")) + + +# IDP types for OIDC endpoint +class IDPAttributes(Protocol): + idp_configuration_id: str + + +class IDPProperty(Protocol): + @property + def idp_configuration_id(self) -> str: ... + + +HasIdpConfigurationID = str | IDPAttributes