Skip to content

Commit ac8dccd

Browse files
authored
chore(versions): Upgrade minimum python version (#1465)
* chore(versions): Upgrade minimum python version As of October, 2024, Python 3.8 is out of support. Upgrading syntax to target Python 3.9. Adds builds for Python 3.13. --------- Co-authored-by: Jordan Woods <13803242+jorwoods@users.noreply.github.com>
1 parent 60a3a2f commit ac8dccd

File tree

136 files changed

+948
-990
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+948
-990
lines changed

.github/workflows/run-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
os: [ubuntu-latest, macos-latest, windows-latest]
16-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
16+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13-dev']
1717

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

pyproject.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,26 @@ dependencies = [
1818
'urllib3>=2.2.2,<3',
1919
'typing_extensions>=4.0.1',
2020
]
21-
requires-python = ">=3.7"
21+
requires-python = ">=3.9"
2222
classifiers = [
2323
"Programming Language :: Python",
2424
"Programming Language :: Python :: 3",
25-
"Programming Language :: Python :: 3.8",
2625
"Programming Language :: Python :: 3.9",
2726
"Programming Language :: Python :: 3.10",
2827
"Programming Language :: Python :: 3.11",
29-
"Programming Language :: Python :: 3.12"
28+
"Programming Language :: Python :: 3.12",
29+
"Programming Language :: Python :: 3.13"
3030
]
3131
[project.urls]
3232
repository = "https://github.com/tableau/server-client-python"
3333

3434
[project.optional-dependencies]
35-
test = ["black==23.7", "build", "mypy==1.4", "pytest>=7.0", "pytest-cov", "pytest-subtests",
35+
test = ["black==24.8", "build", "mypy==1.4", "pytest>=7.0", "pytest-cov", "pytest-subtests",
3636
"requests-mock>=1.0,<2.0"]
3737

3838
[tool.black]
3939
line-length = 120
40-
target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312']
40+
target-version = ['py39', 'py310', 'py311', 'py312', 'py313']
4141

4242
[tool.mypy]
4343
check_untyped_defs = false

samples/add_default_permission.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ def main():
6363
for permission in new_default_permissions:
6464
grantee = permission.grantee
6565
capabilities = permission.capabilities
66-
print("\nCapabilities for {0} {1}:".format(grantee.tag_name, grantee.id))
66+
print(f"\nCapabilities for {grantee.tag_name} {grantee.id}:")
6767

6868
for capability in capabilities:
69-
print("\t{0} - {1}".format(capability, capabilities[capability]))
69+
print(f"\t{capability} - {capabilities[capability]}")
7070

7171
# Uncomment lines below to DELETE the new capability and the new project
7272
# rules_to_delete = TSC.PermissionsRule(

samples/create_group.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import os
1212

1313
from datetime import time
14-
from typing import List
1514

1615
import tableauserverclient as TSC
1716
from tableauserverclient import ServerResponseError
@@ -63,23 +62,23 @@ def main():
6362

6463
if args.file:
6564
filepath = os.path.abspath(args.file)
66-
print("Add users to site from file {}:".format(filepath))
67-
added: List[TSC.UserItem]
68-
failed: List[TSC.UserItem, TSC.ServerResponseError]
65+
print(f"Add users to site from file {filepath}:")
66+
added: list[TSC.UserItem]
67+
failed: list[TSC.UserItem, TSC.ServerResponseError]
6968
added, failed = server.users.create_from_file(filepath)
7069
for user, error in failed:
7170
print(user, error.code)
7271
if error.code == "409017":
7372
user = server.users.filter(name=user.name)[0]
7473
added.append(user)
75-
print("Adding users to group:{}".format(added))
74+
print(f"Adding users to group:{added}")
7675
for user in added:
77-
print("Adding user {}".format(user))
76+
print(f"Adding user {user}")
7877
try:
7978
server.groups.add_user(group, user.id)
8079
except ServerResponseError as serverError:
8180
if serverError.code == "409011":
82-
print("user {} is already a member of group {}".format(user.name, group.name))
81+
print(f"user {user.name} is already a member of group {group.name}")
8382
else:
8483
raise rError
8584

samples/create_project.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def main():
8484
server.projects.populate_datasource_default_permissions(changed_project),
8585
server.projects.populate_permissions(changed_project)
8686
# Projects have default permissions set for the object types they contain
87-
print("Permissions from project {}:".format(changed_project.id))
87+
print(f"Permissions from project {changed_project.id}:")
8888
print(changed_project.permissions)
8989
print(
9090
changed_project.default_workbook_permissions,

samples/create_schedules.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def main():
5555
)
5656
try:
5757
hourly_schedule = server.schedules.create(hourly_schedule)
58-
print("Hourly schedule created (ID: {}).".format(hourly_schedule.id))
58+
print(f"Hourly schedule created (ID: {hourly_schedule.id}).")
5959
except Exception as e:
6060
print(e)
6161

@@ -71,7 +71,7 @@ def main():
7171
)
7272
try:
7373
daily_schedule = server.schedules.create(daily_schedule)
74-
print("Daily schedule created (ID: {}).".format(daily_schedule.id))
74+
print(f"Daily schedule created (ID: {daily_schedule.id}).")
7575
except Exception as e:
7676
print(e)
7777

@@ -89,7 +89,7 @@ def main():
8989
)
9090
try:
9191
weekly_schedule = server.schedules.create(weekly_schedule)
92-
print("Weekly schedule created (ID: {}).".format(weekly_schedule.id))
92+
print(f"Weekly schedule created (ID: {weekly_schedule.id}).")
9393
except Exception as e:
9494
print(e)
9595
options = TSC.RequestOptions()
@@ -112,7 +112,7 @@ def main():
112112
)
113113
try:
114114
monthly_schedule = server.schedules.create(monthly_schedule)
115-
print("Monthly schedule created (ID: {}).".format(monthly_schedule.id))
115+
print(f"Monthly schedule created (ID: {monthly_schedule.id}).")
116116
except Exception as e:
117117
print(e)
118118

samples/explore_datasource.py

+6-11
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ def main():
5454
new_datasource = server.datasources.publish(
5555
new_datasource, args.publish, TSC.Server.PublishMode.Overwrite
5656
)
57-
print("Datasource published. ID: {}".format(new_datasource.id))
57+
print(f"Datasource published. ID: {new_datasource.id}")
5858
else:
5959
print("Publish failed. Could not find the default project.")
6060

6161
# Gets all datasource items
6262
all_datasources, pagination_item = server.datasources.get()
63-
print("\nThere are {} datasources on site: ".format(pagination_item.total_available))
63+
print(f"\nThere are {pagination_item.total_available} datasources on site: ")
6464
print([datasource.name for datasource in all_datasources])
6565

6666
if all_datasources:
@@ -69,20 +69,15 @@ def main():
6969

7070
# Populate connections
7171
server.datasources.populate_connections(sample_datasource)
72-
print("\nConnections for {}: ".format(sample_datasource.name))
73-
print(
74-
[
75-
"{0}({1})".format(connection.id, connection.datasource_name)
76-
for connection in sample_datasource.connections
77-
]
78-
)
72+
print(f"\nConnections for {sample_datasource.name}: ")
73+
print([f"{connection.id}({connection.datasource_name})" for connection in sample_datasource.connections])
7974

8075
# Add some tags to the datasource
8176
original_tag_set = set(sample_datasource.tags)
8277
sample_datasource.tags.update("a", "b", "c", "d")
8378
server.datasources.update(sample_datasource)
84-
print("\nOld tag set: {}".format(original_tag_set))
85-
print("New tag set: {}".format(sample_datasource.tags))
79+
print(f"\nOld tag set: {original_tag_set}")
80+
print(f"New tag set: {sample_datasource.tags}")
8681

8782
# Delete all tags that were added by setting tags to original
8883
sample_datasource.tags = original_tag_set

samples/explore_favorites.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def main():
3939
# get all favorites on site for the logged on user
4040
user: TSC.UserItem = TSC.UserItem()
4141
user.id = server.user_id
42-
print("Favorites for user: {}".format(user.id))
42+
print(f"Favorites for user: {user.id}")
4343
server.favorites.get(user)
4444
print(user.favorites)
4545

@@ -57,7 +57,7 @@ def main():
5757
if views is not None and len(views) > 0:
5858
my_view = views[0]
5959
server.favorites.add_favorite_view(user, my_view)
60-
print("View added to favorites. View Name: {}, View ID: {}".format(my_view.name, my_view.id))
60+
print(f"View added to favorites. View Name: {my_view.name}, View ID: {my_view.id}")
6161

6262
all_datasource_items, pagination_item = server.datasources.get()
6363
if all_datasource_items:
@@ -70,12 +70,10 @@ def main():
7070
)
7171

7272
server.favorites.delete_favorite_workbook(user, my_workbook)
73-
print(
74-
"Workbook deleted from favorites. Workbook Name: {}, Workbook ID: {}".format(my_workbook.name, my_workbook.id)
75-
)
73+
print(f"Workbook deleted from favorites. Workbook Name: {my_workbook.name}, Workbook ID: {my_workbook.id}")
7674

7775
server.favorites.delete_favorite_view(user, my_view)
78-
print("View deleted from favorites. View Name: {}, View ID: {}".format(my_view.name, my_view.id))
76+
print(f"View deleted from favorites. View Name: {my_view.name}, View ID: {my_view.id}")
7977

8078
server.favorites.delete_favorite_datasource(user, my_datasource)
8179
print(

samples/explore_site.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def main():
4949

5050
if args.delete:
5151
print("You can only delete the site you are currently in")
52-
print("Delete site `{}`?".format(current_site.name))
52+
print(f"Delete site `{current_site.name}`?")
5353
# server.sites.delete(server.site_id)
5454

5555
elif args.create:

samples/explore_webhooks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ def main():
5252
new_webhook.event = "datasource-created"
5353
print(new_webhook)
5454
new_webhook = server.webhooks.create(new_webhook)
55-
print("Webhook created. ID: {}".format(new_webhook.id))
55+
print(f"Webhook created. ID: {new_webhook.id}")
5656

5757
# Gets all webhook items
5858
all_webhooks, pagination_item = server.webhooks.get()
59-
print("\nThere are {} webhooks on site: ".format(pagination_item.total_available))
59+
print(f"\nThere are {pagination_item.total_available} webhooks on site: ")
6060
print([webhook.name for webhook in all_webhooks])
6161

6262
if all_webhooks:

samples/explore_workbook.py

+14-19
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ def main():
5959
if default_project is not None:
6060
new_workbook = TSC.WorkbookItem(default_project.id)
6161
new_workbook = server.workbooks.publish(new_workbook, args.publish, overwrite_true)
62-
print("Workbook published. ID: {}".format(new_workbook.id))
62+
print(f"Workbook published. ID: {new_workbook.id}")
6363
else:
6464
print("Publish failed. Could not find the default project.")
6565

6666
# Gets all workbook items
6767
all_workbooks, pagination_item = server.workbooks.get()
68-
print("\nThere are {} workbooks on site: ".format(pagination_item.total_available))
68+
print(f"\nThere are {pagination_item.total_available} workbooks on site: ")
6969
print([workbook.name for workbook in all_workbooks])
7070

7171
if all_workbooks:
@@ -78,27 +78,22 @@ def main():
7878

7979
# Populate views
8080
server.workbooks.populate_views(sample_workbook)
81-
print("\nName of views in {}: ".format(sample_workbook.name))
81+
print(f"\nName of views in {sample_workbook.name}: ")
8282
print([view.name for view in sample_workbook.views])
8383

8484
# Populate connections
8585
server.workbooks.populate_connections(sample_workbook)
86-
print("\nConnections for {}: ".format(sample_workbook.name))
87-
print(
88-
[
89-
"{0}({1})".format(connection.id, connection.datasource_name)
90-
for connection in sample_workbook.connections
91-
]
92-
)
86+
print(f"\nConnections for {sample_workbook.name}: ")
87+
print([f"{connection.id}({connection.datasource_name})" for connection in sample_workbook.connections])
9388

9489
# Update tags and show_tabs flag
9590
original_tag_set = set(sample_workbook.tags)
9691
sample_workbook.tags.update("a", "b", "c", "d")
9792
sample_workbook.show_tabs = True
9893
server.workbooks.update(sample_workbook)
99-
print("\nWorkbook's old tag set: {}".format(original_tag_set))
100-
print("Workbook's new tag set: {}".format(sample_workbook.tags))
101-
print("Workbook tabbed: {}".format(sample_workbook.show_tabs))
94+
print(f"\nWorkbook's old tag set: {original_tag_set}")
95+
print(f"Workbook's new tag set: {sample_workbook.tags}")
96+
print(f"Workbook tabbed: {sample_workbook.show_tabs}")
10297

10398
# Delete all tags that were added by setting tags to original
10499
sample_workbook.tags = original_tag_set
@@ -109,8 +104,8 @@ def main():
109104
original_tag_set = set(sample_view.tags)
110105
sample_view.tags.add("view_tag")
111106
server.views.update(sample_view)
112-
print("\nView's old tag set: {}".format(original_tag_set))
113-
print("View's new tag set: {}".format(sample_view.tags))
107+
print(f"\nView's old tag set: {original_tag_set}")
108+
print(f"View's new tag set: {sample_view.tags}")
114109

115110
# Delete tag from just one view
116111
sample_view.tags = original_tag_set
@@ -119,14 +114,14 @@ def main():
119114
if args.download:
120115
# Download
121116
path = server.workbooks.download(sample_workbook.id, args.download)
122-
print("\nDownloaded workbook to {}".format(path))
117+
print(f"\nDownloaded workbook to {path}")
123118

124119
if args.preview_image:
125120
# Populate workbook preview image
126121
server.workbooks.populate_preview_image(sample_workbook)
127122
with open(args.preview_image, "wb") as f:
128123
f.write(sample_workbook.preview_image)
129-
print("\nDownloaded preview image of workbook to {}".format(os.path.abspath(args.preview_image)))
124+
print(f"\nDownloaded preview image of workbook to {os.path.abspath(args.preview_image)}")
130125

131126
# get custom views
132127
cvs, _ = server.custom_views.get()
@@ -153,10 +148,10 @@ def main():
153148
server.workbooks.populate_powerpoint(sample_workbook)
154149
with open(args.powerpoint, "wb") as f:
155150
f.write(sample_workbook.powerpoint)
156-
print("\nDownloaded powerpoint of workbook to {}".format(os.path.abspath(args.powerpoint)))
151+
print(f"\nDownloaded powerpoint of workbook to {os.path.abspath(args.powerpoint)}")
157152

158153
if args.delete:
159-
print("deleting {}".format(c.id))
154+
print(f"deleting {c.id}")
160155
unlucky = TSC.CustomViewItem(c.id)
161156
server.custom_views.delete(unlucky.id)
162157

samples/export.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ def main():
6060
item = server.views.get_by_id(args.resource_id)
6161

6262
if not item:
63-
print("No item found for id {}".format(args.resource_id))
63+
print(f"No item found for id {args.resource_id}")
6464
exit(1)
6565

66-
print("Item found: {}".format(item.name))
66+
print(f"Item found: {item.name}")
6767
# We have a number of different types and functions for each different export type.
6868
# We encode that information above in the const=(...) parameter to the add_argument function to make
6969
# the code automatically adapt for the type of export the user is doing.
@@ -83,7 +83,7 @@ def main():
8383
if args.file:
8484
filename = args.file
8585
else:
86-
filename = "out.{}".format(extension)
86+
filename = f"out.{extension}"
8787

8888
populate(item, options)
8989
with open(filename, "wb") as f:

samples/extracts.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def main():
4747
with server.auth.sign_in(tableau_auth):
4848
# Gets all workbook items
4949
all_workbooks, pagination_item = server.workbooks.get()
50-
print("\nThere are {} workbooks on site: ".format(pagination_item.total_available))
50+
print(f"\nThere are {pagination_item.total_available} workbooks on site: ")
5151
print([workbook.name for workbook in all_workbooks])
5252

5353
if all_workbooks:

samples/filter_sort_groups.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def main():
7171
group_name = filtered_groups.pop().name
7272
print(group_name)
7373
else:
74-
error = "No project named '{}' found".format(filter_group_name)
74+
error = f"No project named '{filter_group_name}' found"
7575
print(error)
7676

7777
# Or, try the above with the django style filtering

samples/filter_sort_projects.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def main():
6868
project_name = filtered_projects.pop().name
6969
print(project_name)
7070
else:
71-
error = "No project named '{}' found".format(filter_project_name)
71+
error = f"No project named '{filter_project_name}' found"
7272
print(error)
7373

7474
create_example_project(name="Example 1", server=server)

samples/getting_started/1_hello_server.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ def main():
1212
# This is the domain for Tableau's Developer Program
1313
server_url = "https://10ax.online.tableau.com"
1414
server = TSC.Server(server_url)
15-
print("Connected to {}".format(server.server_info.baseurl))
16-
print("Server information: {}".format(server.server_info))
15+
print(f"Connected to {server.server_info.baseurl}")
16+
print(f"Server information: {server.server_info}")
1717
print("Sign up for a test site at https://www.tableau.com/developer")
1818

1919

0 commit comments

Comments
 (0)