8000 Merging v0.10 changes from development to master by shinchris · Pull Request #573 · tableau/server-client-python · GitHub
[go: up one dir, main page]

Skip to content

Merging v0.10 changes from development to master #573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ba2796f
Quick Fix for NonXMLErrorException (#515)
t8y8 Oct 24, 2019
82de656
Fix filename behavior and refactor (#517)
t8y8 Oct 31, 2019
808e5b9
Runtime error in permissions_endpoint (#513)
martinbpeters Nov 4, 2019
5eccf20
Close missing brackets in log texts (#508)
shrmnk Nov 5, 2019
c366694
Fixes move_workbook_sites sample to work properly (#503)
Nov 5, 2019
9c19aa3
Add webhooks (#523)
Nov 12, 2019
bdc6215
Project permissions fixes and tests (#527)
martinbpeters Nov 18, 2019
8c3a40a
Added Tasks Delete method & tests (#524)
martinbpeters Nov 18, 2019
04ed840
add test endpoint for webhooks and sample code to use them
jacalata Nov 22, 2019
1c60b01
add some getting started instructions for contributors
jacalata Nov 22, 2019
9a1a43a
address cr feedback
jacalata Nov 23, 2019
83eb785
remove schrodingers newline
jacalata Nov 25, 2019
f89b1d5
tests and lint passing
jacalata Nov 25, 2019
62f0f94
Merge pull request #532 from tableau/webhooks-fixes
jacalata Nov 26, 2019
308705d
Adds description as a read-only attribute of WorkbookItem (#533)
jorgeFons Dec 4, 2019
90343ac
Add support for materializeViews as schedule and task type (#542)
guodah Dec 13, 2019
0f6a5bc
Fix minor bug in request factory (#544)
guodah Dec 19, 2019
8000
d8651a7
Fix minor bug in request factory due to bool(time(0,0))==False in Pyt…
guodah Dec 30, 2019
963d09b
Add site-name (#549)
illonage Jan 9, 2020
a5caa7c
Receiving warnings in schedule creation (#550)
guodah Jan 14, 2020
10381bc
Add warnings when adding workbook to schedule (#551)
guodah Jan 17, 2020
f4f8530
change version requirement for urllib3
jacalata Feb 3, 2020
15ee44b
update expected value in test to be url-encoded
jacalata Feb 3, 2020
0b3dc62
Added functionality to update projects' parent_id (#560)
wolkiewiczk Feb 12, 2020
300307d
Enabled moving projects too the root. (#567)
wolkiewiczk Feb 14, 2020
a0fb114
Prepares branch for a new release (#572)
Feb 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
dist: xenial
language: python
python:
- "2.7"
- "3.5"
- "3.6"
- "3.7"
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 0.10 (21 Feb 2020)

* Added a way to handle non-xml errors (#515)
* Added Webhooks endpoints for create, delete, get, list, and test (#523, #532)
* Added delete method in the tasks endpoint (#524)
* Added description attribute to WorkbookItem (#533)
* Added support for materializeViews as schedule and task types (#542)
* Added warnings to schedules (#550, #551)
* Added ability to update parent_id attribute of projects (#560, #567)
* Improved filename behavior for download endpoints (#517)
* Improved logging (#508)
* Fixed runtime error in permissions endpoint (#513)
* Fixed move_workbook_sites sample (#503)
* Fixed project permissions endpoints (#527)
* Fixed login.py sample to accept site name (#549)

## 0.9 (4 Oct 2019)

* Added Metadata API endpoints (#431)
Expand Down
7 changes: 6 additions & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ The following people have contributed to this project to make it possible, and w
* [Christian Oliff](https://github.com/coliff)
* [Albin Antony](https://github.com/user9747)
* [prae04](https://github.com/prae04)
* [Martin Peters](https://github.com/martinbpeters)
* [Sherman K](https://github.com/shrmnk)
* [Jorge Fonseca](https://github.com/JorgeFonseca)
* [Kacper Wolkiewicz](https://github.com/wolkiewiczk)
* [Dahai Guo](https://github.com/guodah)
* [Geraldine Zanolli](https://github.com/illonage)

## Core Team

Expand All @@ -41,4 +47,3 @@ The following people have contributed to this project to make it possible, and w
* [Priya Reguraman](https://github.com/preguraman)
* [Jac Fitzgerald](https://github.com/jacalata)
* [Dan Zucker](https://github.com/dzucker-tab)
* [Irwin Dolobowsky](https://github.com/irwando)
11 changes: 11 additions & 0 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,14 @@ creating a PR can be found in the [Development Guide](https://tableau.github.io/
If the feature is complex or has multiple solutions that could be equally appropriate approaches, it would be helpful to file an issue to discuss the
design trade-offs of each solution before implementing, to allow us to collectively arrive at the best solution, which most likely exists in the middle
somewhere.


## Getting Started
> pip install versioneer
> python setup.py build
> python setup.py test
>

### before committing
Our CI runs include a python lint run, so you should run this locally and fix complaints before committing as this will fail your checkin
> pycodestyle tableauserverclient test samples
82 changes: 82 additions & 0 deletions samples/explore_webhooks.py
F438
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
####
# This script demonstrates how to use the Tableau Server Client
# to interact with webhooks. It explores the different
# functions that the Server API supports on webhooks.
#
# With no flags set, this sample will query all webhooks,
# pick one webhook and print the name of the webhook.
# Adding flags will demonstrate the specific feature
# on top of the general operations.
####

import argparse
import getpass
import logging
import os.path

import tableauserverclient as TSC


def main():

parser = argparse.ArgumentParser(description='Explore webhook functions supported by the Server API.')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--site', '-S', default=None)
parser.add_argument('-p', default=None, help='password')
parser.add_argument('--create', '-c', help='create a webhook')
parser.add_argument('--delete', '-d', help='delete a webhook', action='store_true')
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
help='desired logging level (set to error by default)')

args = parser.parse_args()
if args.p is None:
password = getpass.getpass("Password: ")
else:
password = args.p

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

# SIGN IN
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
print("Signing in to " + args.server + " [" + args.site + "] as " + args.username)
server = TSC.Server(args.server)

# Set http options to disable verifying SSL
server.add_http_options({'verify': False})

server.use_server_version()

with server.auth.sign_in(tableau_auth):

# Create webhook if create flag is set (-create, -c)
if args.create:

new_webhook = TSC.WebhookItem()
new_webhook.name = args.create
new_webhook.url = "https://ifttt.com/maker-url"
new_webhook.event = "datasource-created"
print(new_webhook)
new_webhook = server.webhooks.create(new_webhook)
print("Webhook created. ID: {}".format(new_webhook.id))

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

if all_webhooks:
# Pick one webhook from the list and delete it
sample_webhook = all_webhooks[0]
# sample_webhook.delete()
print("+++"+sample_webhook.name)

if (args.delete):
print("Deleting webhook " + sample_webhook.name)
server.webhooks.delete(sample_webhook.id)


if __name__ == '__main__':
main()
22 changes: 12 additions & 10 deletions samples/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,36 @@
import argparse
import getpass
import logging
import os
import sys

import tableauserverclient as TSC


def main():
parser = argparse.ArgumentParser(description='List out the names and LUIDs for different resource types')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--password', '-p', default=None, help='password for the user')
parser.add_argument('--site', '-S', default="", help='site to log into, do not specify for default site')
parser.add_argument('--token-name', '-n', required=True, help='username to signin under')
parser.add_argument('--token', '-t', help='personal access token for logging in')

parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
help='desired logging level (set to error by default)')

parser.add_argument('resource_type', choices=['workbook', 'datasource', 'project', 'view', 'job'])
parser.add_argument('resource_type', choices=['workbook', 'datasource', 'project', 'view', 'job', 'webhooks'])

args = parser.parse_args()

if args.password is None:
password = getpass.getpass("Password: ")
else:
password = args.password
token = os.environ.get('TOKEN', args.token)
if not token:
print("--token or TOKEN environment variable needs to be set")
sys.exit(1)

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

# SIGN IN
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, token, site_id=args.site)
server = TSC.Server(args.server, use_server_version=True)
with server.auth.sign_in(tableau_auth):
endpoint = {
Expand All @@ -44,6 +45,7 @@ def main():
'view': server.views,
'job': server.jobs,
'project': server.projects,
'webhooks': server.webhooks,
}.get(args.resource_type)

for resource in TSC.Pager(endpoint.get):
Expand Down
5 changes: 3 additions & 2 deletions samples/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def main():
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--username', '-u', help='username to sign into the server')
group.add_argument('--token-name', '-n', help='name of the personal access token used to sign into the server')
parser.add_argument('--sitename', '-S', default=None)

args = parser.parse_args()

Expand All @@ -41,9 +42,9 @@ def main():

else:
# Trying to authenticate using personal access tokens.
personal_access_token = getpass.getpass("Personal Access Token: ")
personal_access_token = input("Personal Access Token: ")
tableau_auth = TSC.PersonalAccessTokenAuth(token_name=args.token_name,
personal_access_token=personal_access_token)
personal_access_token=personal_access_token, site_id=args.sitename)
with server.auth.sign_in_with_personal_access_token(tableau_auth):
print('Logged in successfully')

Expand Down
25 changes: 9 additions & 16 deletions samples/move_workbook_sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def main():
workbook_path = source_server.workbooks.download(all_workbooks[0].id, tmpdir)

# Step 4: Check if destination site exists, then sign in to the site
pagination_info, all_sites = source_server.sites.get()
all_sites, pagination_info = source_server.sites.get()
found_destination_site = any((True for site in all_sites if
args.destination_site.lower() == site.content_url.lower()))
if not found_destination_site:
Expand All @@ -71,21 +71,14 @@ def main():
# because of the different auth token and site ID.
with dest_server.auth.sign_in(tableau_auth):

# Step 5: Find destination site's default project
pagination_info, dest_projects = dest_server.projects.get()
target_project = next((project for project in dest_projects if project.is_default()), None)

# Step 6: If default project is found, form a new workbook item and publish.
if target_project is not None:
new_workbook = TSC.WorkbookItem(name=args.workbook_name, project_id=target_project.id)
new_workbook = dest_server.workbooks.publish(new_workbook, workbook_path,
mode=TSC.Server.PublishMode.Overwrite)
print("Successfully moved {0} ({1})".format(new_workbook.name, new_workbook.id))
else:
error = "The default project could not be found."
raise LookupError(error)

# Step 7: Delete workbook from source site and delete temp directory
# Step 5: Create a new workbook item and publish workbook. Note that
# an empty project_id will publish to the 'Default' project.
new_workbook = TSC.WorkbookItem(name=args.workbook_name, project_id="")
new_workbook = dest_server.workbooks.publish(new_workbook, workbook_path,
mode=TSC.Server.PublishMode.Overwrite)
print("Successfully moved {0} ({1})".format(new_workbook.name, new_workbook.id))

# Step 6: Delete workbook from source site and delete temp directory
source_server.workbooks.delete(all_workbooks[0].id)

finally:
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
setup_requires=pytest_runner,
install_requires=[
'requests>=2.11,<3.0',
'urllib3==1.24.3'
'urllib3>=1.24.3,<2.0'
],
tests_require=[
'requests-mock>=1.0,<2.0',
'pytest'
'pytest',
'mock'
]
)
3 changes: 2 additions & 1 deletion tableauserverclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
GroupItem, JobItem, BackgroundJobItem, PaginationItem, ProjectItem, ScheduleItem,\
SiteItem, TableauAuth, PersonalAccessTokenAuth, UserItem, ViewItem, WorkbookItem, UnpopulatedPropertyError,\
HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem, TaskItem,\
SubscriptionItem, Target, PermissionsRule, Permission, DatabaseItem, TableItem, ColumnItem, FlowItem
SubscriptionItem, Target, PermissionsRule, Permission, DatabaseItem, TableItem, ColumnItem, FlowItem, \
WebhookItem, PersonalAccessTokenAuth
from .server import RequestOptions, CSVRequestOptions, ImageRequestOptions, PDFRequestOptions, Filter, Sort, \
Server, ServerResponseError, MissingRequiredFieldError, NotSignedInError, Pager
from ._version import get_versions
Expand Down
16 changes: 16 additions & 0 deletions tableauserverclient/filesys_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import os
ALLOWED_SPECIAL = (' ', '.', '_', '-')


def to_filename(string_to_sanitize):
sanitized = (c for c in string_to_sanitize if c.isalnum() or c in ALLOWED_SPECIAL)
return "".join(sanitized)


def make_download_path(filepath, filename):
download_path = None

if filepath is None:
download_path = filename

elif os.path.isdir(filepath):
download_path = os.path.join(filepath, filename)

else:
download_path = filepath + os.path.splitext(filename)[1]

return download_path
2 changes: 2 additions & 0 deletions tableauserverclient/models/__init__.py
E999
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
from .workbook_item import WorkbookItem
from .subscription_item import SubscriptionItem
from .permissions_item import PermissionsRule, Permission
from .webhook_item import WebhookItem
from .personal_access_token_auth import PersonalAccessTokenAuth
9 changes: 9 additions & 0 deletions tableauserverclient/models/pagination_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,12 @@ def from_response(cls, resp, ns):
pagination_item._page_size = int(pagination_xml.get('pageSize', '-1'))
pagination_item._total_available = int(pagination_xml.get('totalAvailable', '-1'))
return pagination_item

@classmethod
def from_single_page_list(cls, l):
item = cls()
item._page_number = 1
item._page_size = len(l)
item._total_available = len(l)

return item
3 changes: 3 additions & 0 deletions tableauserverclient/models/personal_access_token_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ def __init__(self, token_name, personal_access_token, site_id=''):
@property
def credentials(self):
return {'personalAccessTokenName': self.token_name, 'personalAccessTokenSecret': self.personal_access_token}

def __repr__(self):
return "<PersonalAccessToken name={} token={}>".format(self.token_name, self.personal_access_token)
Loading
0