Skip to content

Commit

Permalink
0.27 (tableau#1272)
Browse files Browse the repository at this point in the history
* fix: TableauIDWithMFA added to the user_item model to allow creating users on Tableau Cloud with MFA enabled (tableau#1216)
* fix: make project optional in datasources tableau#1210
* fix: allow setting timeout on workbook endpoint tableau#1087
* fix: can't certify datasource on publish tableau#1058 
* fix filter in operator spaces bug (tableau#1259)
* fix: remove logging configuration from TSC (tableau#1248)
* Hotfix schedule_item.py for issue 1237 (tableau#1239), Remove duplicate assignments to fields (tableau#1244)
* Fix shared attribute for custom views (tableau#1280)

New functionality
* enable filtering for Excel downloads tableau#1209, tableau#1281
* query view by content url tableau#456  
* update datasource to use bridge (tableau#1224)
* Add JWTAuth, add repr using qualname
* Add publish samples attribute (tableau#1264)
* add support for custom schedules in TOL (tableau#1273)
* Enable asJob for group update (tableau#1276)


Co-authored-by: Tim Payne <[email protected]>
Co-authored-by: Lars Breddemann <[email protected]>
Co-authored-by: jorwoods <[email protected]>
Co-authored-by: Austin <[email protected]>
Co-authored-by: Yasuhisa Yoshida <[email protected]>
Co-authored-by: Brian Cantoni <[email protected]>
Co-authored-by: a-torres-2 <[email protected]>
Co-authored-by: Łukasz Włodarczyk <[email protected]>
  • Loading branch information
9 people authored Sep 22, 2023
1 parent 307d8a2 commit 341dcd2
Show file tree
Hide file tree
Showing 36 changed files with 541 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/meta-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v1
- uses: actions/setup-python@v4
with:
python-version: 3.7
- name: Build dist files
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10', '3.11']

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -33,4 +33,4 @@ jobs:
- name: Test build
if: always()
run: |
python -m build
python -m build
26 changes: 14 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools>=45.0", "versioneer>=0.24", "wheel"]
requires = ["setuptools>=68.0", "versioneer>=0.29", "wheel"]
build-backend = "setuptools.build_meta"

[project]
Expand All @@ -12,39 +12,41 @@ license = {file = "LICENSE"}
readme = "README.md"

dependencies = [
'defusedxml>=0.7.1',
'packaging>=22.0', # bumping to minimum version required by black
'requests>=2.28',
'urllib3~=1.26.8',
'defusedxml>=0.7.1', # latest as at 7/31/23
'packaging>=23.1', # latest as at 7/31/23
'requests>=2.31', # latest as at 7/31/23
'urllib3==2.0.4', # latest as at 7/31/23
]
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10"
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
]
[project.urls]
repository = "https://github.com/tableau/server-client-python"

[project.optional-dependencies]
test = ["argparse", "black", "mock", "mypy", "pytest>=7.0", "pytest-subtests", "requests-mock>=1.0,<2.0"]
test = ["argparse", "black==23.7", "mock", "mypy==1.4", "pytest>=7.0", "pytest-subtests", "requests-mock>=1.0,<2.0"]

[tool.black]
line-length = 120
target-version = ['py37', 'py38', 'py39', 'py310']
target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312']

[tool.mypy]
check_untyped_defs = false
disable_error_code = [
'misc',
'import'
# tableauserverclient\server\endpoint\datasources_endpoint.py:48: error: Cannot assign multiple types to name "FilePath" without an explicit "Type[...]" annotation [misc]
'annotation-unchecked' # can be removed when check_untyped_defs = true
]
files = ["tableauserverclient", "test"]
show_error_codes = true
ignore_missing_imports = true

ignore_missing_imports = true # defusedxml library has no types
[tool.pytest.ini_options]
testpaths = ["test"]
addopts = "--junitxml=./test.junit.xml"
84 changes: 84 additions & 0 deletions samples/create_extract_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
####
# This script demonstrates how to create extract tasks in Tableau Cloud
# using the Tableau Server Client.
#
# To run the script, you must have installed Python 3.7 or later.
####


import argparse
import logging

from datetime import time

import tableauserverclient as TSC


def main():
parser = argparse.ArgumentParser(description="Creates sample extract refresh task.")
# Common options; please keep those in sync across all samples
parser.add_argument("--server", "-s", help="server address")
parser.add_argument("--site", "-S", help="site name")
parser.add_argument("--token-name", "-p", help="name of the personal access token used to sign into the server")
parser.add_argument("--token-value", "-v", help="value of the personal access token used to sign into the server")
parser.add_argument(
"--logging-level",
"-l",
choices=["debug", "info", "error"],
default="error",
help="desired logging level (set to error by default)",
)
# Options specific to this sample:
# This sample has no additional options, yet. If you add some, please add them here

args = parser.parse_args()

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
logging.basicConfig(level=logging_level)

tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site)
server = TSC.Server(args.server, use_server_version=False)
server.add_http_options({"verify": False})
server.use_server_version()
with server.auth.sign_in(tableau_auth):
# Monthly Schedule
# This schedule will run on the 15th of every month at 11:30PM
monthly_interval = TSC.MonthlyInterval(start_time=time(23, 30), interval_value=15)
monthly_schedule = TSC.ScheduleItem(
None,
None,
None,
None,
monthly_interval,
)

# Default to using first workbook found in server
all_workbook_items, pagination_item = server.workbooks.get()
my_workbook: TSC.WorkbookItem = all_workbook_items[0]

target_item = TSC.Target(
my_workbook.id, # the id of the workbook or datasource
"workbook", # alternatively can be "datasource"
)

extract_item = TSC.TaskItem(
None,
"FullRefresh",
None,
None,
None,
monthly_schedule,
None,
target_item,
)

try:
response = server.tasks.create(extract_item)
print(response)
except Exception as e:
print(e)


if __name__ == "__main__":
main()
9 changes: 8 additions & 1 deletion samples/create_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ def main():
server.use_server_version()

# Without parent_id specified, projects are created at the top level.
top_level_project = TSC.ProjectItem(name="Top Level Project")
# With the publish-samples attribute, the project will be created with sample items
top_level_project = TSC.ProjectItem(
name="Top Level Project",
description="A sample tsc project",
content_permissions=None,
parent_id=None,
samples=True,
)
top_level_project = create_project(server, top_level_project)

# Specifying parent_id creates a nested projects.
Expand Down
10 changes: 10 additions & 0 deletions samples/explore_workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def main():
parser.add_argument(
"--preview-image", "-i", metavar="FILENAME", help="filename (a .png file) to save the preview image"
)
parser.add_argument(
"--powerpoint", "-ppt", metavar="FILENAME", help="filename (a .ppt file) to save the powerpoint deck"
)

args = parser.parse_args()

Expand Down Expand Up @@ -145,6 +148,13 @@ def main():
f.write(c.image)
print("saved to " + filename)

if args.powerpoint:
# Populate workbook preview image
server.workbooks.populate_powerpoint(sample_workbook)
with open(args.powerpoint, "wb") as f:
f.write(sample_workbook.powerpoint)
print("\nDownloaded powerpoint of workbook to {}".format(os.path.abspath(args.powerpoint)))

if args.delete:
print("deleting {}".format(c.id))
unlucky = TSC.CustomViewItem(c.id)
Expand Down
21 changes: 21 additions & 0 deletions samples/getting_started/1_hello_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
####
# Getting started Part One of Three
# This script demonstrates how to use the Tableau Server Client to connect to a server
# You don't need to have a site or any experience with Tableau to run it
#
####

import tableauserverclient as TSC


def main():
# This is the domain for Tableau's Developer Program
server_url = "https://10ax.online.tableau.com"
server = TSC.Server(server_url)
print("Connected to {}".format(server.server_info.baseurl))
print("Server information: {}".format(server.server_info))
print("Sign up for a test site at https://www.tableau.com/developer")


if __name__ == "__main__":
main()
50 changes: 50 additions & 0 deletions samples/getting_started/2_hello_site.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
####
# Getting started Part Two of Three
# This script demonstrates how to use the Tableau Server Client to
# view the content on an existing site on Tableau Server/Online
# It assumes that you have already got a site and can visit it in a browser
#
####

import getpass
import tableauserverclient as TSC


# 0 - launch your Tableau site in a web browser and look at the url to set the values below
def main():
# 1 - replace with your server domain: stop at the slash
server_url = "https://10ax.online.tableau.com"

# 2 - optional - change to false **for testing only** if you get a certificate error
use_ssl = True

server = TSC.Server(server_url, use_server_version=True, http_options={"verify": use_ssl})
print("Connected to {}".format(server.server_info.baseurl))

# 3 - replace with your site name exactly as it looks in the url
# e.g https://my-server/#/site/this-is-your-site-url-name/not-this-part
site_url_name = "" # leave empty if there is no site name in the url (you are on the default site)

# 4 - replace with your username.
# REMEMBER: if you are using Tableau Online, your username is the entire email address
username = "your-username-here"
password = getpass.getpass("Your password:") # so you don't save it in this file
tableau_auth = TSC.TableauAuth(username, password, site_id=site_url_name)

# OR instead of username+password, uncomment this section to use a Personal Access Token
# token_name = "your-token-name"
# token_value = "your-token-value-long-random-string"
# tableau_auth = TSC.PersonalAccessTokenAuth(token_name, token_value, site_id=site_url_name)

with server.auth.sign_in(tableau_auth):
projects, pagination = server.projects.get()
if projects:
print("{} projects".format(pagination.total_available))
project = projects[0]
print(project.name)

print("Done")


if __name__ == "__main__":
main()
Loading

0 comments on commit 341dcd2

Please sign in to comment.