Skip to content

Commit

Permalink
Release with security and functionality updates (tableau#1021)
Browse files Browse the repository at this point in the history
Switched to using defused_xml for xml attack protection
added linting and type hints
improve experience with self-signed certificates/invalid ssl
updated samples
new item types: metrics, revisions for datasources and workbooks
features: support adding flows to schedules, exporting workbooks to powerpoint
fixes: delete extracts
  • Loading branch information
jacalata authored Apr 6, 2022
1 parent 4a1656e commit 9ec60ac
Show file tree
Hide file tree
Showing 165 changed files with 6,657 additions and 4,292 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/meta-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: types and style checks

on: [push, pull_request]

jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.10']

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

steps:
- uses: actions/checkout@v2

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

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[test]
- name: Format with black
run: |
black --check --line-length 120 tableauserverclient samples test
- name: Run Mypy tests
if: always()
run: |
mypy --show-error-codes --disable-error-code misc --disable-error-code import tableauserverclient test
37 changes: 37 additions & 0 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Publish to PyPi

# This will publish a package to TestPyPi (and real Pypi if run on master) with a version
# number generated by versioneer from the most recent tag looking like v____
# TODO: maybe move this into the package job so all release-based actions are together
on:
workflow_dispatch:
push:
branches:
- master

jobs:
build-n-publish:
name: Build dist files for PyPi
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v1
with:
python-version: 3.8
- name: Build dist files
run: |
python -m pip install --upgrade pip
pip install -e .[test]
python setup.py sdist --formats=gztar
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
- name: Publish distribution 📦 to PyPI
if: github.ref == 'refs/heads/master'
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.PYPI_API_TOKEN }}
9 changes: 4 additions & 5 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Python tests

on: [push]
on: [push, pull_request]

jobs:
build:
Expand All @@ -24,13 +24,12 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -e .[test]
pip install mypy
- name: Test with pytest
if: always()
run: |
pytest test
- name: Run Mypy but allow failures
- name: Run Mypy tests
run: |
mypy --show-error-codes --disable-error-code misc tableauserverclient
continue-on-error: true
mypy --show-error-codes --disable-error-code misc --disable-error-code import tableauserverclient test
1 change: 1 addition & 0 deletions .github/workflows/slack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
name: Sends a message to Slack when a push, a pull request or an issue is made
steps:
- name: Send message to Slack API
continue-on-error: true
uses: archive/[email protected]
id: notify
with:
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@

## 0.18.0 (6 April 2022)
* Switched to using defused_xml for xml attack protection
* added linting and type hints
* improve experience with self-signed certificates/invalid ssl
* updated samples
* new item types: metrics, revisions for datasources and workbooks
* features: support adding flows to schedules, exporting workbooks to powerpoint
* fixes: delete extracts

## 0.17.0 (20 October 2021)
* Added support for accepting parameters for post request of the metadata api (#850)
* Fixed jobs.get_by_id(job_id) example & reference docs (#867, #868)
Expand Down
7 changes: 2 additions & 5 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ recursive-include test *.json
recursive-include test *.pdf
recursive-include test *.png
recursive-include test *.py
recursive-include test *.tde
recursive-include test *.tds
recursive-include test *.tdsx
recursive-include test *.twb
recursive-include test *.twbx
recursive-include test *.xml
global-include *.pyi
global-include *.typed
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Use the Tableau Server Client (TSC) library to increase your productivity as you
* Create users and groups.
* Query projects, sites, and more.

This repository contains Python source code and sample files. Python versions 3.6 and up are supported.
This repository contains Python source code for the library and sample files showing how to use it. Python versions 3.6 and up are supported.

To see sample code that works directly with the REST API (in Java, Python, or Postman), visit the [REST API Samples](https://github.com/tableau/rest-api-samples) repo.

For more information on installing and using TSC, see the documentation:
<https://tableau.github.io/server-client-python/docs/>
Expand Down
13 changes: 11 additions & 2 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,23 @@ python setup.py build
python setup.py test
```

### To use your locally built version
```shell
pip install .
```

### 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.

```shell
# this will run the formatter without making changes
black --line-length 120 tableauserverclient --check
black --line-length 120 tableauserverclient test samples --check

# this will format the directory and code for you
black --line-length 120 tableauserverclient
black --line-length 120 tableauserverclient test samples

# this will run type checking
pip install mypy
mypy --show-error-codes --disable-error-code misc --disable-error-code import tableauserverclient test
```
32 changes: 18 additions & 14 deletions samples/add_default_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@


def main():
parser = argparse.ArgumentParser(description='Add workbook default permissions for a given project.')
parser = argparse.ArgumentParser(description="Add workbook default permissions for a given project.")
# Common options; please keep those in sync across all samples
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', help='site name')
parser.add_argument('--token-name', '-p', required=True,
help='name of the personal access token used to sign into the server')
parser.add_argument('--token-value', '-v', required=True,
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)')
parser.add_argument("--server", "-s", required=True, help="server address")
parser.add_argument("--site", "-S", help="site name")
parser.add_argument(
"--token-name", "-p", required=True, help="name of the personal access token used to sign into the server"
)
parser.add_argument(
"--token-value", "-v", required=True, 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

Expand Down Expand Up @@ -53,10 +60,7 @@ def main():
new_capabilities = {TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Allow}

# Each PermissionRule in the list contains a grantee and a dict of capabilities
new_rules = [TSC.PermissionsRule(
grantee=default_permissions.grantee,
capabilities=new_capabilities
)]
new_rules = [TSC.PermissionsRule(grantee=default_permissions.grantee, capabilities=new_capabilities)]

new_default_permissions = server.projects.update_workbook_default_permissions(project, new_rules)

Expand All @@ -78,5 +82,5 @@ def main():
# server.projects.delete(project.id)


if __name__ == '__main__':
if __name__ == "__main__":
main()
29 changes: 18 additions & 11 deletions samples/create_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@

def main():

parser = argparse.ArgumentParser(description='Creates a sample user group.')
parser = argparse.ArgumentParser(description="Creates a sample user group.")
# Common options; please keep those in sync across all samples
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', help='site name')
parser.add_argument('--token-name', '-p', required=True,
help='name of the personal access token used to sign into the server')
parser.add_argument('--token-value', '-v', required=True,
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)')
parser.add_argument("--server", "-s", required=True, help="server address")
parser.add_argument("--site", "-S", help="site name")
parser.add_argument(
"--token-name", "-p", required=True, help="name of the personal access token used to sign into the server"
)
parser.add_argument(
"--token-value", "-v", required=True, 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

Expand All @@ -38,10 +45,10 @@ def main():
tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site)
server = TSC.Server(args.server, use_server_version=True)
with server.auth.sign_in(tableau_auth):
group = TSC.GroupItem('test')
group = TSC.GroupItem("test")
group = server.groups.create(group)
print(group)


if __name__ == '__main__':
if __name__ == "__main__":
main()
49 changes: 30 additions & 19 deletions samples/create_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,34 @@
import tableauserverclient as TSC


def create_project(server, project_item):
def create_project(server, project_item, samples=False):
try:
project_item = server.projects.create(project_item)
print('Created a new project called: %s' % project_item.name)
project_item = server.projects.create(project_item, samples)
print("Created a new project called: %s" % project_item.name)
return project_item
except TSC.ServerResponseError:
print('We have already created this project: %s' % project_item.name)
print("We have already created this project: %s" % project_item.name)
sys.exit(1)


def main():
parser = argparse.ArgumentParser(description='Create new projects.')
parser = argparse.ArgumentParser(description="Create new projects.")
# Common options; please keep those in sync across all samples
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', help='site name')
parser.add_argument('--token-name', '-p', required=True,
help='name of the personal access token used to sign into the server')
parser.add_argument('--token-value', '-v', required=True,
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)')
parser.add_argument("--server", "-s", required=True, help="server address")
parser.add_argument("--site", "-S", help="site name")
parser.add_argument(
"--token-name", "-p", required=True, help="name of the personal access token used to sign into the server"
)
parser.add_argument(
"--token-value", "-v", required=True, 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

Expand All @@ -45,23 +52,27 @@ def main():
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=True)
server = TSC.Server(args.server)
server.use_server_version()
with server.auth.sign_in(tableau_auth):
# Use highest Server REST API version available
server.use_server_version()

# Without parent_id specified, projects are created at the top level.
top_level_project = TSC.ProjectItem(name='Top Level Project')
top_level_project = TSC.ProjectItem(name="Top Level Project")
top_level_project = create_project(server, top_level_project)

# Specifying parent_id creates a nested projects.
child_project = TSC.ProjectItem(name='Child Project', parent_id=top_level_project.id)
child_project = create_project(server, child_project)
child_project = TSC.ProjectItem(name="Child Project", parent_id=top_level_project.id)
child_project = create_project(server, child_project, samples=True)

# Projects can be nested at any level.
grand_child_project = TSC.ProjectItem(name='Grand Child Project', parent_id=child_project.id)
grand_child_project = TSC.ProjectItem(name="Grand Child Project", parent_id=child_project.id)
grand_child_project = create_project(server, grand_child_project)

# Projects can be updated
changed_project = server.projects.update(grand_child_project, samples=True)

if __name__ == '__main__':

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

0 comments on commit 9ec60ac

Please sign in to comment.