diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a0917c7b6..45b9548c1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -25,13 +25,10 @@ jobs: pip install -e .[test] pip install mypy - - name: Lint with pycodestyle - run: | - pycodestyle tableauserverclient test samples - - name: Test with pytest run: | pytest test + - name: Run Mypy but allow failures run: | mypy --show-error-codes --disable-error-code misc tableauserverclient diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index b438d8a2e..2eadcdfa1 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -1,13 +1,54 @@ from .namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE -from .models import ConnectionCredentials, ConnectionItem, DataAlertItem, DatasourceItem,\ - 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, \ - WebhookItem, PersonalAccessTokenAuth -from .server import RequestOptions, CSVRequestOptions, ImageRequestOptions, PDFRequestOptions, Filter, Sort, \ - Server, ServerResponseError, MissingRequiredFieldError, NotSignedInError, Pager +from .models import ( + ConnectionCredentials, + ConnectionItem, + DataAlertItem, + DatasourceItem, + 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, + WebhookItem, + PersonalAccessTokenAuth, +) +from .server import ( + RequestOptions, + CSVRequestOptions, + ImageRequestOptions, + PDFRequestOptions, + Filter, + Sort, + Server, + ServerResponseError, + MissingRequiredFieldError, + NotSignedInError, + Pager, +) from ._version import get_versions -__version__ = get_versions()['version'] + +__version__ = get_versions()["version"] __VERSION__ = __version__ del get_versions diff --git a/tableauserverclient/_version.py b/tableauserverclient/_version.py index 9f576606a..c8afb10d4 100644 --- a/tableauserverclient/_version.py +++ b/tableauserverclient/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -58,17 +57,18 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +76,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None) + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +115,19 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +183,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +200,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +234,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +242,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +267,16 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out return pieces # tag @@ -279,10 +285,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +298,11 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +333,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +447,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +473,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +493,7 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass @@ -495,13 +502,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +525,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/tableauserverclient/filesys_helpers.py b/tableauserverclient/filesys_helpers.py index 11051fdf4..1663ee9e8 100644 --- a/tableauserverclient/filesys_helpers.py +++ b/tableauserverclient/filesys_helpers.py @@ -1,5 +1,6 @@ import os -ALLOWED_SPECIAL = (' ', '.', '_', '-') + +ALLOWED_SPECIAL = (" ", ".", "_", "-") def to_filename(string_to_sanitize): @@ -37,10 +38,10 @@ def get_file_type(file): # This reference lists magic file signatures: https://www.garykessler.net/library/file_sigs.html MAGIC_BYTES = { - 'zip': bytes.fromhex("504b0304"), - 'tde': bytes.fromhex("20020162"), - 'xml': bytes.fromhex("3c3f786d6c20"), - 'hyper': bytes.fromhex("487970657208000001000000") + "zip": bytes.fromhex("504b0304"), + "tde": bytes.fromhex("20020162"), + "xml": bytes.fromhex("3c3f786d6c20"), + "hyper": bytes.fromhex("487970657208000001000000"), } # Peek first bytes of a file diff --git a/tableauserverclient/models/column_item.py b/tableauserverclient/models/column_item.py index 9bf198220..a95d005ca 100644 --- a/tableauserverclient/models/column_item.py +++ b/tableauserverclient/models/column_item.py @@ -48,7 +48,7 @@ def _set_values(self, id, name, description, remote_type): def from_response(cls, resp, ns): all_column_items = list() parsed_response = ET.fromstring(resp) - all_column_xml = parsed_response.findall('.//t:column', namespaces=ns) + all_column_xml = parsed_response.findall(".//t:column", namespaces=ns) for column_xml in all_column_xml: (id, name, description, remote_type) = cls._parse_element(column_xml, ns) @@ -60,9 +60,9 @@ def from_response(cls, resp, ns): @staticmethod def _parse_element(column_xml, ns): - id = column_xml.get('id', None) - name = column_xml.get('name', None) - description = column_xml.get('description', None) - remote_type = column_xml.get('remoteType', None) + id = column_xml.get("id", None) + name = column_xml.get("name", None) + description = column_xml.get("description", None) + remote_type = column_xml.get("remoteType", None) return id, name, description, remote_type diff --git a/tableauserverclient/models/connection_credentials.py b/tableauserverclient/models/connection_credentials.py index c883a515a..db65de0ad 100644 --- a/tableauserverclient/models/connection_credentials.py +++ b/tableauserverclient/models/connection_credentials.py @@ -35,12 +35,12 @@ def oauth(self, value): @classmethod def from_xml_element(cls, parsed_response, ns): - connection_creds_xml = parsed_response.find('.//t:connectionCredentials', namespaces=ns) + connection_creds_xml = parsed_response.find(".//t:connectionCredentials", namespaces=ns) - name = connection_creds_xml.get('name', None) - password = connection_creds_xml.get('password', None) - embed = connection_creds_xml.get('embed', None) - oAuth = connection_creds_xml.get('oAuth', None) + name = connection_creds_xml.get("name", None) + password = connection_creds_xml.get("password", None) + embed = connection_creds_xml.get("embed", None) + oAuth = connection_creds_xml.get("oAuth", None) connection_creds = cls(name, password, embed, oAuth) return connection_creds diff --git a/tableauserverclient/models/connection_item.py b/tableauserverclient/models/connection_item.py index 8f923fecb..018c093c7 100644 --- a/tableauserverclient/models/connection_item.py +++ b/tableauserverclient/models/connection_item.py @@ -32,34 +32,33 @@ def connection_type(self): return self._connection_type def __repr__(self): - return ( - "".format(**self.__dict__) + return "".format( + **self.__dict__ ) @classmethod def from_response(cls, resp, ns): all_connection_items = list() parsed_response = ET.fromstring(resp) - all_connection_xml = parsed_response.findall('.//t:connection', namespaces=ns) + all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns) for connection_xml in all_connection_xml: connection_item = cls() - connection_item._id = connection_xml.get('id', None) - connection_item._connection_type = connection_xml.get('type', None) - connection_item.embed_password = string_to_bool(connection_xml.get('embedPassword', '')) - connection_item.server_address = connection_xml.get('serverAddress', None) - connection_item.server_port = connection_xml.get('serverPort', None) - connection_item.username = connection_xml.get('userName', None) - datasource_elem = connection_xml.find('.//t:datasource', namespaces=ns) + connection_item._id = connection_xml.get("id", None) + connection_item._connection_type = connection_xml.get("type", None) + connection_item.embed_password = string_to_bool(connection_xml.get("embedPassword", "")) + connection_item.server_address = connection_xml.get("serverAddress", None) + connection_item.server_port = connection_xml.get("serverPort", None) + connection_item.username = connection_xml.get("userName", None) + datasource_elem = connection_xml.find(".//t:datasource", namespaces=ns) if datasource_elem is not None: - connection_item._datasource_id = datasource_elem.get('id', None) - connection_item._datasource_name = datasource_elem.get('name', None) + connection_item._datasource_id = datasource_elem.get("id", None) + connection_item._datasource_name = datasource_elem.get("name", None) all_connection_items.append(connection_item) return all_connection_items @classmethod def from_xml_element(cls, parsed_response, ns): - ''' + """ @@ -68,27 +67,25 @@ def from_xml_element(cls, parsed_response, ns): - ''' + """ all_connection_items = list() - all_connection_xml = parsed_response.findall('.//t:connection', namespaces=ns) + all_connection_xml = parsed_response.findall(".//t:connection", namespaces=ns) for connection_xml in all_connection_xml: connection_item = cls() - connection_item.server_address = connection_xml.get('serverAddress', None) - connection_item.server_port = connection_xml.get('serverPort', None) + connection_item.server_address = connection_xml.get("serverAddress", None) + connection_item.server_port = connection_xml.get("serverPort", None) - connection_credentials = connection_xml.find( - './/t:connectionCredentials', namespaces=ns) + connection_credentials = connection_xml.find(".//t:connectionCredentials", namespaces=ns) if connection_credentials is not None: - connection_item.connection_credentials = ConnectionCredentials.from_xml_element( - connection_credentials) + connection_item.connection_credentials = ConnectionCredentials.from_xml_element(connection_credentials) return all_connection_items # Used to convert string represented boolean to a boolean type def string_to_bool(s): - return s.lower() == 'true' + return s.lower() == "true" diff --git a/tableauserverclient/models/data_acceleration_report_item.py b/tableauserverclient/models/data_acceleration_report_item.py index 2b443a3d1..eab6c24cd 100644 --- a/tableauserverclient/models/data_acceleration_report_item.py +++ b/tableauserverclient/models/data_acceleration_report_item.py @@ -3,9 +3,15 @@ class DataAccelerationReportItem(object): class ComparisonRecord(object): - def __init__(self, site, sheet_uri, unaccelerated_session_count, - avg_non_accelerated_plt, accelerated_session_count, - avg_accelerated_plt): + def __init__( + self, + site, + sheet_uri, + unaccelerated_session_count, + avg_non_accelerated_plt, + accelerated_session_count, + avg_accelerated_plt, + ): self._site = site self._sheet_uri = sheet_uri self._unaccelerated_session_count = unaccelerated_session_count @@ -46,26 +52,43 @@ def comparison_records(self): @staticmethod def _parse_element(comparison_record_xml, ns): - site = comparison_record_xml.get('site', None) - sheet_uri = comparison_record_xml.get('sheetURI', None) - unaccelerated_session_count = comparison_record_xml.get('unacceleratedSessionCount', None) - avg_non_accelerated_plt = comparison_record_xml.get('averageNonAcceleratedPLT', None) - accelerated_session_count = comparison_record_xml.get('acceleratedSessionCount', None) - avg_accelerated_plt = comparison_record_xml.get('averageAcceleratedPLT', None) - return site, sheet_uri, unaccelerated_session_count, avg_non_accelerated_plt, \ - accelerated_session_count, avg_accelerated_plt + site = comparison_record_xml.get("site", None) + sheet_uri = comparison_record_xml.get("sheetURI", None) + unaccelerated_session_count = comparison_record_xml.get("unacceleratedSessionCount", None) + avg_non_accelerated_plt = comparison_record_xml.get("averageNonAcceleratedPLT", None) + accelerated_session_count = comparison_record_xml.get("acceleratedSessionCount", None) + avg_accelerated_plt = comparison_record_xml.get("averageAcceleratedPLT", None) + return ( + site, + sheet_uri, + unaccelerated_session_count, + avg_non_accelerated_plt, + accelerated_session_count, + avg_accelerated_plt, + ) @classmethod def from_response(cls, resp, ns): comparison_records = list() parsed_response = ET.fromstring(resp) - all_comparison_records_xml = parsed_response.findall('.//t:comparisonRecord', namespaces=ns) + all_comparison_records_xml = parsed_response.findall(".//t:comparisonRecord", namespaces=ns) for comparison_record_xml in all_comparison_records_xml: - (site, sheet_uri, unaccelerated_session_count, avg_non_accelerated_plt, - accelerated_session_count, avg_accelerated_plt) = cls._parse_element(comparison_record_xml, ns) + ( + site, + sheet_uri, + unaccelerated_session_count, + avg_non_accelerated_plt, + accelerated_session_count, + avg_accelerated_plt, + ) = cls._parse_element(comparison_record_xml, ns) comparison_record = DataAccelerationReportItem.ComparisonRecord( - site, sheet_uri, unaccelerated_session_count, avg_non_accelerated_plt, - accelerated_session_count, avg_accelerated_plt) + site, + sheet_uri, + unaccelerated_session_count, + avg_non_accelerated_plt, + accelerated_session_count, + avg_accelerated_plt, + ) comparison_records.append(comparison_record) return cls(comparison_records) diff --git a/tableauserverclient/models/data_alert_item.py b/tableauserverclient/models/data_alert_item.py index 559050b4b..c924b6ab2 100644 --- a/tableauserverclient/models/data_alert_item.py +++ b/tableauserverclient/models/data_alert_item.py @@ -7,11 +7,11 @@ class DataAlertItem(object): class Frequency: - Once = 'Once' - Frequently = 'Frequently' - Hourly = 'Hourly' - Daily = 'Daily' - Weekly = 'Weekly' + Once = "Once" + Frequently = "Frequently" + Hourly = "Hourly" + Daily = "Daily" + Weekly = "Weekly" def __init__(self): self._id = None @@ -33,7 +33,9 @@ def __init__(self): def __repr__(self): return "".format(**self.__dict__) + public={public}>".format( + **self.__dict__ + ) @property def id(self): @@ -114,10 +116,25 @@ def project_id(self): def project_name(self): return self._project_name - def _set_values(self, id, subject, creatorId, createdAt, updatedAt, - frequency, public, recipients, owner_id, owner_name, - view_id, view_name, workbook_id, workbook_name, project_id, - project_name): + def _set_values( + self, + id, + subject, + creatorId, + createdAt, + updatedAt, + frequency, + public, + recipients, + owner_id, + owner_name, + view_id, + view_name, + workbook_id, + workbook_name, + project_id, + project_name, + ): if id is not None: self._id = id if subject: @@ -155,7 +172,7 @@ def _set_values(self, id, subject, creatorId, createdAt, updatedAt, def from_response(cls, resp, ns): all_alert_items = list() parsed_response = ET.fromstring(resp) - all_alert_xml = parsed_response.findall('.//t:dataAlert', namespaces=ns) + all_alert_xml = parsed_response.findall(".//t:dataAlert", namespaces=ns) for alert_xml in all_alert_xml: kwargs = cls._parse_element(alert_xml, ns) @@ -168,30 +185,30 @@ def from_response(cls, resp, ns): @staticmethod def _parse_element(alert_xml, ns): kwargs = dict() - kwargs['id'] = alert_xml.get('id', None) - kwargs['subject'] = alert_xml.get('subject', None) - kwargs['creatorId'] = alert_xml.get('creatorId', None) - kwargs['createdAt'] = alert_xml.get('createdAt', None) - kwargs['updatedAt'] = alert_xml.get('updatedAt', None) - kwargs['frequency'] = alert_xml.get('frequency', None) - kwargs['public'] = alert_xml.get('public', None) - - owner = alert_xml.findall('.//t:owner', namespaces=ns)[0] - kwargs['owner_id'] = owner.get('id', None) - kwargs['owner_name'] = owner.get('name', None) - - view_response = alert_xml.findall('.//t:view', namespaces=ns)[0] - kwargs['view_id'] = view_response.get('id', None) - kwargs['view_name'] = view_response.get('name', None) - - workbook_response = view_response.findall('.//t:workbook', namespaces=ns)[0] - kwargs['workbook_id'] = workbook_response.get('id', None) - kwargs['workbook_name'] = workbook_response.get('name', None) - project_response = view_response.findall('.//t:project', namespaces=ns)[0] - kwargs['project_id'] = project_response.get('id', None) - kwargs['project_name'] = project_response.get('name', None) - - recipients = alert_xml.findall('.//t:recipient', namespaces=ns) - kwargs['recipients'] = [recipient.get('id', None) for recipient in recipients] + kwargs["id"] = alert_xml.get("id", None) + kwargs["subject"] = alert_xml.get("subject", None) + kwargs["creatorId"] = alert_xml.get("creatorId", None) + kwargs["createdAt"] = alert_xml.get("createdAt", None) + kwargs["updatedAt"] = alert_xml.get("updatedAt", None) + kwargs["frequency"] = alert_xml.get("frequency", None) + kwargs["public"] = alert_xml.get("public", None) + + owner = alert_xml.findall(".//t:owner", namespaces=ns)[0] + kwargs["owner_id"] = owner.get("id", None) + kwargs["owner_name"] = owner.get("name", None) + + view_response = alert_xml.findall(".//t:view", namespaces=ns)[0] + kwargs["view_id"] = view_response.get("id", None) + kwargs["view_name"] = view_response.get("name", None) + + workbook_response = view_response.findall(".//t:workbook", namespaces=ns)[0] + kwargs["workbook_id"] = workbook_response.get("id", None) + kwargs["workbook_name"] = workbook_response.get("name", None) + project_response = view_response.findall(".//t:project", namespaces=ns)[0] + kwargs["project_id"] = project_response.get("id", None) + kwargs["project_name"] = project_response.get("name", None) + + recipients = alert_xml.findall(".//t:recipient", namespaces=ns) + kwargs["recipients"] = [recipient.get("id", None) for recipient in recipients] return kwargs diff --git a/tableauserverclient/models/database_item.py b/tableauserverclient/models/database_item.py index 5a7e74737..a319606e4 100644 --- a/tableauserverclient/models/database_item.py +++ b/tableauserverclient/models/database_item.py @@ -6,8 +6,8 @@ class DatabaseItem(object): class ContentPermissions: - LockedToProject = 'LockedToDatabase' - ManagedByOwner = 'ManagedByOwner' + LockedToProject = "LockedToDatabase" + ManagedByOwner = "ManagedByOwner" def __init__(self, name, description=None, content_permissions=None): self._id = None @@ -163,64 +163,64 @@ def tables(self): def _set_values(self, database_values): # ID & Settable - if 'id' in database_values: - self._id = database_values['id'] + if "id" in database_values: + self._id = database_values["id"] - if 'contact' in database_values: - self._contact_id = database_values['contact']['id'] + if "contact" in database_values: + self._contact_id = database_values["contact"]["id"] - if 'name' in database_values: - self._name = database_values['name'] + if "name" in database_values: + self._name = database_values["name"] - if 'description' in database_values: - self._description = database_values['description'] + if "description" in database_values: + self._description = database_values["description"] - if 'isCertified' in database_values: - self._certified = string_to_bool(database_values['isCertified']) + if "isCertified" in database_values: + self._certified = string_to_bool(database_values["isCertified"]) - if 'certificationNote' in database_values: - self._certification_note = database_values['certificationNote'] + if "certificationNote" in database_values: + self._certification_note = database_values["certificationNote"] # Not settable, alphabetical - if 'connectionType' in database_values: - self._connection_type = database_values['connectionType'] + if "connectionType" in database_values: + self._connection_type = database_values["connectionType"] - if 'connectorUrl' in database_values: - self._connector_url = database_values['connectorUrl'] + if "connectorUrl" in database_values: + self._connector_url = database_values["connectorUrl"] - if 'contentPermissions' in database_values: - self._content_permissions = database_values['contentPermissions'] + if "contentPermissions" in database_values: + self._content_permissions = database_values["contentPermissions"] - if 'isEmbedded' in database_values: - self._embedded = string_to_bool(database_values['isEmbedded']) + if "isEmbedded" in database_values: + self._embedded = string_to_bool(database_values["isEmbedded"]) - if 'fileExtension' in database_values: - self._file_extension = database_values['fileExtension'] + if "fileExtension" in database_values: + self._file_extension = database_values["fileExtension"] - if 'fileId' in database_values: - self._file_id = database_values['fileId'] + if "fileId" in database_values: + self._file_id = database_values["fileId"] - if 'filePath' in database_values: - self._file_path = database_values['filePath'] + if "filePath" in database_values: + self._file_path = database_values["filePath"] - if 'hostName' in database_values: - self._host_name = database_values['hostName'] + if "hostName" in database_values: + self._host_name = database_values["hostName"] - if 'mimeType' in database_values: - self._mime_type = database_values['mimeType'] + if "mimeType" in database_values: + self._mime_type = database_values["mimeType"] - if 'port' in database_values: - self._port = int(database_values['port']) + if "port" in database_values: + self._port = int(database_values["port"]) - if 'provider' in database_values: - self._provider = database_values['provider'] + if "provider" in database_values: + self._provider = database_values["provider"] - if 'requestUrl' in database_values: - self._request_url = database_values['requestUrl'] + if "requestUrl" in database_values: + self._request_url = database_values["requestUrl"] - if 'type' in database_values: - self._metadata_type = database_values['type'] + if "type" in database_values: + self._metadata_type = database_values["type"] def _set_permissions(self, permissions): self._permissions = permissions @@ -235,11 +235,11 @@ def _set_default_permissions(self, permissions, content_type): def from_response(cls, resp, ns): all_database_items = list() parsed_response = ET.fromstring(resp) - all_database_xml = parsed_response.findall('.//t:database', namespaces=ns) + all_database_xml = parsed_response.findall(".//t:database", namespaces=ns) for database_xml in all_database_xml: parsed_database = cls._parse_element(database_xml, ns) - database_item = cls(parsed_database['name']) + database_item = cls(parsed_database["name"]) database_item._set_values(parsed_database) all_database_items.append(database_item) return all_database_items @@ -247,12 +247,12 @@ def from_response(cls, resp, ns): @staticmethod def _parse_element(database_xml, ns): database_values = database_xml.attrib.copy() - contact = database_xml.find('.//t:contact', namespaces=ns) + contact = database_xml.find(".//t:contact", namespaces=ns) if contact is not None: - database_values['contact'] = contact.attrib.copy() + database_values["contact"] = contact.attrib.copy() return database_values # Used to convert string represented boolean to a boolean type def string_to_bool(s): - return s.lower() == 'true' + return s.lower() == "true" diff --git a/tableauserverclient/models/datasource_item.py b/tableauserverclient/models/datasource_item.py index a50d5a412..219df39c2 100644 --- a/tableauserverclient/models/datasource_item.py +++ b/tableauserverclient/models/datasource_item.py @@ -8,9 +8,9 @@ class DatasourceItem(object): class AskDataEnablement: - Enabled = 'Enabled' - Disabled = 'Disabled' - SiteDefault = 'SiteDefault' + Enabled = "Enabled" + Disabled = "Disabled" + SiteDefault = "SiteDefault" def __init__(self, project_id, name=None): self._ask_data_enablement = None @@ -48,7 +48,7 @@ def ask_data_enablement(self, value): @property def connections(self): if self._connections is None: - error = 'Datasource item must be populated with connections first.' + error = "Datasource item must be populated with connections first." raise UnpopulatedPropertyError(error) return self._connections() @@ -144,19 +144,71 @@ def _set_permissions(self, permissions): def _parse_common_elements(self, datasource_xml, ns): if not isinstance(datasource_xml, ET.Element): - datasource_xml = ET.fromstring(datasource_xml).find('.//t:datasource', namespaces=ns) + datasource_xml = ET.fromstring(datasource_xml).find(".//t:datasource", namespaces=ns) if datasource_xml is not None: - (ask_data_enablement, certified, certification_note, _, _, _, _, encrypt_extracts, has_extracts, - _, _, owner_id, project_id, project_name, _, updated_at, use_remote_query_agent, - webpage_url) = self._parse_element(datasource_xml, ns) - self._set_values(ask_data_enablement, certified, certification_note, None, None, None, None, - encrypt_extracts, has_extracts, None, None, owner_id, project_id, project_name, None, - updated_at, use_remote_query_agent, webpage_url) + ( + ask_data_enablement, + certified, + certification_note, + _, + _, + _, + _, + encrypt_extracts, + has_extracts, + _, + _, + owner_id, + project_id, + project_name, + _, + updated_at, + use_remote_query_agent, + webpage_url, + ) = self._parse_element(datasource_xml, ns) + self._set_values( + ask_data_enablement, + certified, + certification_note, + None, + None, + None, + None, + encrypt_extracts, + has_extracts, + None, + None, + owner_id, + project_id, + project_name, + None, + updated_at, + use_remote_query_agent, + webpage_url, + ) return self - def _set_values(self, ask_data_enablement, certified, certification_note, content_url, created_at, datasource_type, - description, encrypt_extracts, has_extracts, id_, name, owner_id, project_id, project_name, tags, - updated_at, use_remote_query_agent, webpage_url): + def _set_values( + self, + ask_data_enablement, + certified, + certification_note, + content_url, + created_at, + datasource_type, + description, + encrypt_extracts, + has_extracts, + id_, + name, + owner_id, + project_id, + project_name, + tags, + updated_at, + use_remote_query_agent, + webpage_url, + ): if ask_data_enablement is not None: self._ask_data_enablement = ask_data_enablement if certification_note: @@ -171,9 +223,9 @@ def _set_values(self, ask_data_enablement, certified, certification_note, conten if description: self.description = description if encrypt_extracts is not None: - self.encrypt_extracts = str(encrypt_extracts).lower() == 'true' + self.encrypt_extracts = str(encrypt_extracts).lower() == "true" if has_extracts is not None: - self._has_extracts = str(has_extracts).lower() == 'true' + self._has_extracts = str(has_extracts).lower() == "true" if id_ is not None: self._id = id_ if name: @@ -190,7 +242,7 @@ def _set_values(self, ask_data_enablement, certified, certification_note, conten if updated_at: self._updated_at = updated_at if use_remote_query_agent is not None: - self._use_remote_query_agent = str(use_remote_query_agent).lower() == 'true' + self._use_remote_query_agent = str(use_remote_query_agent).lower() == "true" if webpage_url: self._webpage_url = webpage_url @@ -198,58 +250,108 @@ def _set_values(self, ask_data_enablement, certified, certification_note, conten def from_response(cls, resp, ns): all_datasource_items = list() parsed_response = ET.fromstring(resp) - all_datasource_xml = parsed_response.findall('.//t:datasource', namespaces=ns) + all_datasource_xml = parsed_response.findall(".//t:datasource", namespaces=ns) for datasource_xml in all_datasource_xml: - (ask_data_enablement, certified, certification_note, content_url, created_at, datasource_type, - description, encrypt_extracts, has_extracts, id_, name, owner_id, project_id, project_name, tags, - updated_at, use_remote_query_agent, webpage_url) = cls._parse_element(datasource_xml, ns) + ( + ask_data_enablement, + certified, + certification_note, + content_url, + created_at, + datasource_type, + description, + encrypt_extracts, + has_extracts, + id_, + name, + owner_id, + project_id, + project_name, + tags, + updated_at, + use_remote_query_agent, + webpage_url, + ) = cls._parse_element(datasource_xml, ns) datasource_item = cls(project_id) - datasource_item._set_values(ask_data_enablement, certified, certification_note, content_url, - created_at, datasource_type, description, encrypt_extracts, - has_extracts, id_, name, owner_id, None, project_name, tags, updated_at, - use_remote_query_agent, webpage_url) + datasource_item._set_values( + ask_data_enablement, + certified, + certification_note, + content_url, + created_at, + datasource_type, + description, + encrypt_extracts, + has_extracts, + id_, + name, + owner_id, + None, + project_name, + tags, + updated_at, + use_remote_query_agent, + webpage_url, + ) all_datasource_items.append(datasource_item) return all_datasource_items @staticmethod def _parse_element(datasource_xml, ns): - certification_note = datasource_xml.get('certificationNote', None) - certified = str(datasource_xml.get('isCertified', None)).lower() == 'true' - content_url = datasource_xml.get('contentUrl', None) - created_at = parse_datetime(datasource_xml.get('createdAt', None)) - datasource_type = datasource_xml.get('type', None) - description = datasource_xml.get('description', None) - encrypt_extracts = datasource_xml.get('encryptExtracts', None) - has_extracts = datasource_xml.get('hasExtracts', None) - id_ = datasource_xml.get('id', None) - name = datasource_xml.get('name', None) - updated_at = parse_datetime(datasource_xml.get('updatedAt', None)) - use_remote_query_agent = datasource_xml.get('useRemoteQueryAgent', None) - webpage_url = datasource_xml.get('webpageUrl', None) + certification_note = datasource_xml.get("certificationNote", None) + certified = str(datasource_xml.get("isCertified", None)).lower() == "true" + content_url = datasource_xml.get("contentUrl", None) + created_at = parse_datetime(datasource_xml.get("createdAt", None)) + datasource_type = datasource_xml.get("type", None) + description = datasource_xml.get("description", None) + encrypt_extracts = datasource_xml.get("encryptExtracts", None) + has_extracts = datasource_xml.get("hasExtracts", None) + id_ = datasource_xml.get("id", None) + name = datasource_xml.get("name", None) + updated_at = parse_datetime(datasource_xml.get("updatedAt", None)) + use_remote_query_agent = datasource_xml.get("useRemoteQueryAgent", None) + webpage_url = datasource_xml.get("webpageUrl", None) tags = None - tags_elem = datasource_xml.find('.//t:tags', namespaces=ns) + tags_elem = datasource_xml.find(".//t:tags", namespaces=ns) if tags_elem is not None: tags = TagItem.from_xml_element(tags_elem, ns) project_id = None project_name = None - project_elem = datasource_xml.find('.//t:project', namespaces=ns) + project_elem = datasource_xml.find(".//t:project", namespaces=ns) if project_elem is not None: - project_id = project_elem.get('id', None) - project_name = project_elem.get('name', None) + project_id = project_elem.get("id", None) + project_name = project_elem.get("name", None) owner_id = None - owner_elem = datasource_xml.find('.//t:owner', namespaces=ns) + owner_elem = datasource_xml.find(".//t:owner", namespaces=ns) if owner_elem is not None: - owner_id = owner_elem.get('id', None) + owner_id = owner_elem.get("id", None) ask_data_enablement = None - ask_data_elem = datasource_xml.find('.//t:askData', namespaces=ns) + ask_data_elem = datasource_xml.find(".//t:askData", namespaces=ns) if ask_data_elem is not None: - ask_data_enablement = ask_data_elem.get('enablement', None) - - return (ask_data_enablement, certified, certification_note, content_url, created_at, - datasource_type, description, encrypt_extracts, has_extracts, id_, name, owner_id, - project_id, project_name, tags, updated_at, use_remote_query_agent, webpage_url) + ask_data_enablement = ask_data_elem.get("enablement", None) + + return ( + ask_data_enablement, + certified, + certification_note, + content_url, + created_at, + datasource_type, + description, + encrypt_extracts, + has_extracts, + id_, + name, + owner_id, + project_id, + project_name, + tags, + updated_at, + use_remote_query_agent, + webpage_url, + ) diff --git a/tableauserverclient/models/favorites_item.py b/tableauserverclient/models/favorites_item.py index 7d2408f93..3d6feff5d 100644 --- a/tableauserverclient/models/favorites_item.py +++ b/tableauserverclient/models/favorites_item.py @@ -5,45 +5,45 @@ from .project_item import ProjectItem from .datasource_item import DatasourceItem -logger = logging.getLogger('tableau.models.favorites_item') +logger = logging.getLogger("tableau.models.favorites_item") class FavoriteItem: class Type: - Workbook = 'workbook' - Datasource = 'datasource' - View = 'view' - Project = 'project' + Workbook = "workbook" + Datasource = "datasource" + View = "view" + Project = "project" @classmethod def from_response(cls, xml, namespace): favorites = { - 'datasources': [], - 'projects': [], - 'views': [], - 'workbooks': [], + "datasources": [], + "projects": [], + "views": [], + "workbooks": [], } parsed_response = ET.fromstring(xml) - for workbook in parsed_response.findall('.//t:favorite/t:workbook', namespace): - fav_workbook = WorkbookItem('') + for workbook in parsed_response.findall(".//t:favorite/t:workbook", namespace): + fav_workbook = WorkbookItem("") fav_workbook._set_values(*fav_workbook._parse_element(workbook, namespace)) if fav_workbook: - favorites['workbooks'].append(fav_workbook) - for view in parsed_response.findall('.//t:favorite[t:view]', namespace): + favorites["workbooks"].append(fav_workbook) + for view in parsed_response.findall(".//t:favorite[t:view]", namespace): fav_views = ViewItem.from_xml_element(view, namespace) if fav_views: for fav_view in fav_views: - favorites['views'].append(fav_view) - for datasource in parsed_response.findall('.//t:favorite/t:datasource', namespace): - fav_datasource = DatasourceItem('') + favorites["views"].append(fav_view) + for datasource in parsed_response.findall(".//t:favorite/t:datasource", namespace): + fav_datasource = DatasourceItem("") fav_datasource._set_values(*fav_datasource._parse_element(datasource, namespace)) if fav_datasource: - favorites['datasources'].append(fav_datasource) - for project in parsed_response.findall('.//t:favorite/t:project', namespace): - fav_project = ProjectItem('p') + favorites["datasources"].append(fav_datasource) + for project in parsed_response.findall(".//t:favorite/t:project", namespace): + fav_project = ProjectItem("p") fav_project._set_values(*fav_project._parse_element(project)) if fav_project: - favorites['projects'].append(fav_project) + favorites["projects"].append(fav_project) return favorites diff --git a/tableauserverclient/models/fileupload_item.py b/tableauserverclient/models/fileupload_item.py index bd5a3a85f..a697a5aaf 100644 --- a/tableauserverclient/models/fileupload_item.py +++ b/tableauserverclient/models/fileupload_item.py @@ -17,8 +17,8 @@ def file_size(self): @classmethod def from_response(cls, resp, ns): parsed_response = ET.fromstring(resp) - fileupload_elem = parsed_response.find('.//t:fileUpload', namespaces=ns) + fileupload_elem = parsed_response.find(".//t:fileUpload", namespaces=ns) fileupload_item = cls() - fileupload_item._upload_session_id = fileupload_elem.get('uploadSessionId', None) - fileupload_item._file_size = fileupload_elem.get('fileSize', None) + fileupload_item._upload_session_id = fileupload_elem.get("uploadSessionId", None) + fileupload_item._file_size = fileupload_elem.get("fileSize", None) return fileupload_item diff --git a/tableauserverclient/models/flow_item.py b/tableauserverclient/models/flow_item.py index c978d8175..99e857369 100644 --- a/tableauserverclient/models/flow_item.py +++ b/tableauserverclient/models/flow_item.py @@ -26,7 +26,7 @@ def __init__(self, project_id, name=None): @property def connections(self): if self._connections is None: - error = 'Flow item must be populated with connections first.' + error = "Flow item must be populated with connections first." raise UnpopulatedPropertyError(error) return self._connections() @@ -86,15 +86,15 @@ def _set_permissions(self, permissions): def _parse_common_elements(self, flow_xml, ns): if not isinstance(flow_xml, ET.Element): - flow_xml = ET.fromstring(flow_xml).find('.//t:flow', namespaces=ns) + flow_xml = ET.fromstring(flow_xml).find(".//t:flow", namespaces=ns) if flow_xml is not None: (_, _, _, _, _, updated_at, _, project_id, project_name, owner_id) = self._parse_element(flow_xml, ns) - self._set_values(None, None, None, None, None, updated_at, None, project_id, - project_name, owner_id) + self._set_values(None, None, None, None, None, updated_at, None, project_id, project_name, owner_id) return self - def _set_values(self, id, name, description, webpage_url, created_at, - updated_at, tags, project_id, project_name, owner_id): + def _set_values( + self, id, name, description, webpage_url, created_at, updated_at, tags, project_id, project_name, owner_id + ): if id is not None: self._id = id if name: @@ -121,42 +121,52 @@ def _set_values(self, id, name, description, webpage_url, created_at, def from_response(cls, resp, ns): all_flow_items = list() parsed_response = ET.fromstring(resp) - all_flow_xml = parsed_response.findall('.//t:flow', namespaces=ns) + all_flow_xml = parsed_response.findall(".//t:flow", namespaces=ns) for flow_xml in all_flow_xml: - (id_, name, description, webpage_url, created_at, updated_at, - tags, project_id, project_name, owner_id) = cls._parse_element(flow_xml, ns) + ( + id_, + name, + description, + webpage_url, + created_at, + updated_at, + tags, + project_id, + project_name, + owner_id, + ) = cls._parse_element(flow_xml, ns) flow_item = cls(project_id) - flow_item._set_values(id_, name, description, webpage_url, created_at, updated_at, - tags, None, project_name, owner_id) + flow_item._set_values( + id_, name, description, webpage_url, created_at, updated_at, tags, None, project_name, owner_id + ) all_flow_items.append(flow_item) return all_flow_items @staticmethod def _parse_element(flow_xml, ns): - id_ = flow_xml.get('id', None) - name = flow_xml.get('name', None) - description = flow_xml.get('description', None) - webpage_url = flow_xml.get('webpageUrl', None) - created_at = parse_datetime(flow_xml.get('createdAt', None)) - updated_at = parse_datetime(flow_xml.get('updatedAt', None)) + id_ = flow_xml.get("id", None) + name = flow_xml.get("name", None) + description = flow_xml.get("description", None) + webpage_url = flow_xml.get("webpageUrl", None) + created_at = parse_datetime(flow_xml.get("createdAt", None)) + updated_at = parse_datetime(flow_xml.get("updatedAt", None)) tags = None - tags_elem = flow_xml.find('.//t:tags', namespaces=ns) + tags_elem = flow_xml.find(".//t:tags", namespaces=ns) if tags_elem is not None: tags = TagItem.from_xml_element(tags_elem, ns) project_id = None project_name = None - project_elem = flow_xml.find('.//t:project', namespaces=ns) + project_elem = flow_xml.find(".//t:project", namespaces=ns) if project_elem is not None: - project_id = project_elem.get('id', None) - project_name = project_elem.get('name', None) + project_id = project_elem.get("id", None) + project_name = project_elem.get("name", None) owner_id = None - owner_elem = flow_xml.find('.//t:owner', namespaces=ns) + owner_elem = flow_xml.find(".//t:owner", namespaces=ns) if owner_elem is not None: - owner_id = owner_elem.get('id', None) + owner_id = owner_elem.get("id", None) - return (id_, name, description, webpage_url, created_at, updated_at, tags, project_id, - project_name, owner_id) + return (id_, name, description, webpage_url, created_at, updated_at, tags, project_id, project_name, owner_id) diff --git a/tableauserverclient/models/group_item.py b/tableauserverclient/models/group_item.py index af9465dfb..fdc06604b 100644 --- a/tableauserverclient/models/group_item.py +++ b/tableauserverclient/models/group_item.py @@ -7,11 +7,11 @@ class GroupItem(object): - tag_name = 'group' + tag_name = "group" class LicenseMode: - onLogin = 'onLogin' - onSync = 'onSync' + onLogin = "onLogin" + onSync = "onSync" def __init__(self, name=None, domain_name=None): self._id = None @@ -78,23 +78,23 @@ def _set_users(self, users): def from_response(cls, resp, ns): all_group_items = list() parsed_response = ET.fromstring(resp) - all_group_xml = parsed_response.findall('.//t:group', namespaces=ns) + all_group_xml = parsed_response.findall(".//t:group", namespaces=ns) for group_xml in all_group_xml: - name = group_xml.get('name', None) + name = group_xml.get("name", None) group_item = cls(name) - group_item._id = group_xml.get('id', None) + group_item._id = group_xml.get("id", None) # Domain name is returned in a domain element for some calls - domain_elem = group_xml.find('.//t:domain', namespaces=ns) + domain_elem = group_xml.find(".//t:domain", namespaces=ns) if domain_elem is not None: - group_item.domain_name = domain_elem.get('name', None) + group_item.domain_name = domain_elem.get("name", None) # Import element is returned for both local and AD groups (2020.3+) - import_elem = group_xml.find('.//t:import', namespaces=ns) + import_elem = group_xml.find(".//t:import", namespaces=ns) if import_elem is not None: - group_item.domain_name = import_elem.get('domainName', None) - group_item.license_mode = import_elem.get('grantLicenseMode', None) - group_item.minimum_site_role = import_elem.get('siteRole', None) + group_item.domain_name = import_elem.get("domainName", None) + group_item.license_mode = import_elem.get("grantLicenseMode", None) + group_item.minimum_site_role = import_elem.get("siteRole", None) all_group_items.append(group_item) return all_group_items diff --git a/tableauserverclient/models/interval_item.py b/tableauserverclient/models/interval_item.py index cbc148e88..320e01ef2 100644 --- a/tableauserverclient/models/interval_item.py +++ b/tableauserverclient/models/interval_item.py @@ -62,7 +62,7 @@ def interval(self): @interval.setter def interval(self, interval): - VALID_INTERVALS = {.25, .5, 1, 2, 4, 6, 8, 12} + VALID_INTERVALS = {0.25, 0.5, 1, 2, 4, 6, 8, 12} if float(interval) not in VALID_INTERVALS: error = "Invalid interval {} not in {}".format(interval, str(VALID_INTERVALS)) raise ValueError(error) @@ -73,7 +73,7 @@ def _interval_type_pairs(self): # We use fractional hours for the two minute-based intervals. # Need to convert to minutes from hours here - if self.interval in {.25, .5}: + if self.interval in {0.25, 0.5}: calculated_interval = int(self.interval * 60) interval_type = IntervalItem.Occurrence.Minutes else: diff --git a/tableauserverclient/models/job_item.py b/tableauserverclient/models/job_item.py index 985907ba3..7b7ea4921 100644 --- a/tableauserverclient/models/job_item.py +++ b/tableauserverclient/models/job_item.py @@ -3,8 +3,18 @@ class JobItem(object): - def __init__(self, id_, job_type, progress, created_at, started_at=None, - completed_at=None, finish_code=0, notes=None, mode=None): + def __init__( + self, + id_, + job_type, + progress, + created_at, + started_at=None, + completed_at=None, + finish_code=0, + notes=None, + mode=None, + ): self._id = id_ self._type = job_type self._progress = progress @@ -57,14 +67,15 @@ def mode(self, value): self._mode = value def __repr__(self): - return "".format(**self.__dict__) + return ( + "".format(**self.__dict__) + ) @classmethod def from_response(cls, xml, ns): parsed_response = ET.fromstring(xml) - all_tasks_xml = parsed_response.findall( - './/t:job', namespaces=ns) + all_tasks_xml = parsed_response.findall(".//t:job", namespaces=ns) all_tasks = [JobItem._parse_element(x, ns) for x in all_tasks_xml] @@ -72,16 +83,15 @@ def from_response(cls, xml, ns): @classmethod def _parse_element(cls, element, ns): - id_ = element.get('id', None) - type_ = element.get('type', None) - progress = element.get('progress', None) - created_at = parse_datetime(element.get('createdAt', None)) - started_at = parse_datetime(element.get('startedAt', None)) - completed_at = parse_datetime(element.get('completedAt', None)) - finish_code = element.get('finishCode', -1) - notes = [note.text for note in - element.findall('.//t:notes', namespaces=ns)] or None - mode = element.get('mode', None) + id_ = element.get("id", None) + type_ = element.get("type", None) + progress = element.get("progress", None) + created_at = parse_datetime(element.get("createdAt", None)) + started_at = parse_datetime(element.get("startedAt", None)) + completed_at = parse_datetime(element.get("completedAt", None)) + finish_code = element.get("finishCode", -1) + notes = [note.text for note in element.findall(".//t:notes", namespaces=ns)] or None + mode = element.get("mode", None) return cls(id_, type_, progress, created_at, started_at, completed_at, finish_code, notes, mode) @@ -93,8 +103,9 @@ class Status: Failed = "Failed" Cancelled = "Cancelled" - def __init__(self, id_, created_at, priority, job_type, status, title=None, subtitle=None, started_at=None, - ended_at=None): + def __init__( + self, id_, created_at, priority, job_type, status, title=None, subtitle=None, started_at=None, ended_at=None + ): self._id = id_ self._type = job_type self._status = status @@ -150,20 +161,19 @@ def priority(self): @classmethod def from_response(cls, xml, ns): parsed_response = ET.fromstring(xml) - all_tasks_xml = parsed_response.findall( - './/t:backgroundJob', namespaces=ns) + all_tasks_xml = parsed_response.findall(".//t:backgroundJob", namespaces=ns) return [cls._parse_element(x, ns) for x in all_tasks_xml] @classmethod def _parse_element(cls, element, ns): - id_ = element.get('id', None) - type_ = element.get('jobType', None) - status = element.get('status', None) - created_at = parse_datetime(element.get('createdAt', None)) - started_at = parse_datetime(element.get('startedAt', None)) - ended_at = parse_datetime(element.get('endedAt', None)) - priority = element.get('priority', None) - title = element.get('title', None) - subtitle = element.get('subtitle', None) + id_ = element.get("id", None) + type_ = element.get("jobType", None) + status = element.get("status", None) + created_at = parse_datetime(element.get("createdAt", None)) + started_at = parse_datetime(element.get("startedAt", None)) + ended_at = parse_datetime(element.get("endedAt", None)) + priority = element.get("priority", None) + title = element.get("title", None) + subtitle = element.get("subtitle", None) return cls(id_, created_at, priority, type_, status, title, subtitle, started_at, ended_at) diff --git a/tableauserverclient/models/pagination_item.py b/tableauserverclient/models/pagination_item.py index a1f5409e3..df9ca26e6 100644 --- a/tableauserverclient/models/pagination_item.py +++ b/tableauserverclient/models/pagination_item.py @@ -22,12 +22,12 @@ def total_available(self): @classmethod def from_response(cls, resp, ns): parsed_response = ET.fromstring(resp) - pagination_xml = parsed_response.find('t:pagination', namespaces=ns) + pagination_xml = parsed_response.find("t:pagination", namespaces=ns) pagination_item = cls() if pagination_xml is not None: - pagination_item._page_number = int(pagination_xml.get('pageNumber', '-1')) - pagination_item._page_size = int(pagination_xml.get('pageSize', '-1')) - pagination_item._total_available = int(pagination_xml.get('totalAvailable', '-1')) + pagination_item._page_number = int(pagination_xml.get("pageNumber", "-1")) + pagination_item._page_size = int(pagination_xml.get("pageSize", "-1")) + pagination_item._total_available = int(pagination_xml.get("totalAvailable", "-1")) return pagination_item @classmethod diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index 216315587..113e8525e 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -5,45 +5,43 @@ from .user_item import UserItem from .group_item import GroupItem -logger = logging.getLogger('tableau.models.permissions_item') +logger = logging.getLogger("tableau.models.permissions_item") class Permission: - class Mode: - Allow = 'Allow' - Deny = 'Deny' + Allow = "Allow" + Deny = "Deny" class Capability: - AddComment = 'AddComment' - ChangeHierarchy = 'ChangeHierarchy' - ChangePermissions = 'ChangePermissions' - Connect = 'Connect' - Delete = 'Delete' - Execute = 'Execute' - ExportData = 'ExportData' - ExportImage = 'ExportImage' - ExportXml = 'ExportXml' - Filter = 'Filter' - ProjectLeader = 'ProjectLeader' - Read = 'Read' - ShareView = 'ShareView' - ViewComments = 'ViewComments' - ViewUnderlyingData = 'ViewUnderlyingData' - WebAuthoring = 'WebAuthoring' - Write = 'Write' + AddComment = "AddComment" + ChangeHierarchy = "ChangeHierarchy" + ChangePermissions = "ChangePermissions" + Connect = "Connect" + Delete = "Delete" + Execute = "Execute" + ExportData = "ExportData" + ExportImage = "ExportImage" + ExportXml = "ExportXml" + Filter = "Filter" + ProjectLeader = "ProjectLeader" + Read = "Read" + ShareView = "ShareView" + ViewComments = "ViewComments" + ViewUnderlyingData = "ViewUnderlyingData" + WebAuthoring = "WebAuthoring" + Write = "Write" class Resource: - Workbook = 'workbook' - Datasource = 'datasource' - Flow = 'flow' - Table = 'table' - Database = 'database' - View = 'view' + Workbook = "workbook" + Datasource = "datasource" + Flow = "flow" + Table = "table" + Database = "database" + View = "view" class PermissionsRule(object): - def __init__(self, grantee, capabilities): self.grantee = grantee self.capabilities = capabilities @@ -53,23 +51,20 @@ def from_response(cls, resp, ns=None): parsed_response = ET.fromstring(resp) rules = [] - permissions_rules_list_xml = parsed_response.findall('.//t:granteeCapabilities', - namespaces=ns) + permissions_rules_list_xml = parsed_response.findall(".//t:granteeCapabilities", namespaces=ns) for grantee_capability_xml in permissions_rules_list_xml: capability_dict = {} grantee = PermissionsRule._parse_grantee_element(grantee_capability_xml, ns) - for capability_xml in grantee_capability_xml.findall( - './/t:capabilities/t:capability', namespaces=ns): - name = capability_xml.get('name') - mode = capability_xml.get('mode') + for capability_xml in grantee_capability_xml.findall(".//t:capabilities/t:capability", namespaces=ns): + name = capability_xml.get("name") + mode = capability_xml.get("mode") capability_dict[name] = mode - rule = PermissionsRule(grantee, - capability_dict) + rule = PermissionsRule(grantee, capability_dict) rules.append(rule) return rules @@ -79,17 +74,17 @@ def _parse_grantee_element(grantee_capability_xml, ns): """Use Xpath magic and some string splitting to get the right object type from the xml""" # Get the first element in the tree with an 'id' attribute - grantee_element = grantee_capability_xml.findall('.//*[@id]', namespaces=ns).pop() - grantee_id = grantee_element.get('id', None) - grantee_type = grantee_element.tag.split('}').pop() + grantee_element = grantee_capability_xml.findall(".//*[@id]", namespaces=ns).pop() + grantee_id = grantee_element.get("id", None) + grantee_type = grantee_element.tag.split("}").pop() if grantee_id is None: - logger.error('Cannot find grantee type in response') + logger.error("Cannot find grantee type in response") raise UnknownGranteeTypeError() - if grantee_type == 'user': + if grantee_type == "user": grantee = UserItem.as_reference(grantee_id) - elif grantee_type == 'group': + elif grantee_type == "group": grantee = GroupItem.as_reference(grantee_id) else: raise UnknownGranteeTypeError("No support for grantee type of {}".format(grantee_type)) diff --git a/tableauserverclient/models/personal_access_token_auth.py b/tableauserverclient/models/personal_access_token_auth.py index 13a2391b8..c80a020e8 100644 --- a/tableauserverclient/models/personal_access_token_auth.py +++ b/tableauserverclient/models/personal_access_token_auth.py @@ -1,5 +1,5 @@ class PersonalAccessTokenAuth(object): - def __init__(self, token_name, personal_access_token, site_id=''): + def __init__(self, token_name, personal_access_token, site_id=""): self.token_name = token_name self.personal_access_token = personal_access_token self.site_id = site_id @@ -8,12 +8,7 @@ def __init__(self, token_name, personal_access_token, site_id=''): @property def credentials(self): - return { - 'personalAccessTokenName': self.token_name, - 'personalAccessTokenSecret': self.personal_access_token - } + return {"personalAccessTokenName": self.token_name, "personalAccessTokenSecret": self.personal_access_token} def __repr__(self): - return "".format( - self.token_name, self.personal_access_token - ) + return "".format(self.token_name, self.personal_access_token) diff --git a/tableauserverclient/models/project_item.py b/tableauserverclient/models/project_item.py index 4cfbcb4e9..e8434a0ad 100644 --- a/tableauserverclient/models/project_item.py +++ b/tableauserverclient/models/project_item.py @@ -8,8 +8,8 @@ class ProjectItem(object): class ContentPermissions: - LockedToProject = 'LockedToProject' - ManagedByOwner = 'ManagedByOwner' + LockedToProject = "LockedToProject" + ManagedByOwner = "ManagedByOwner" def __init__(self, name, description=None, content_permissions=None, parent_id=None): self._content_permissions = None @@ -80,14 +80,14 @@ def owner_id(self): @owner_id.setter def owner_id(self, value): - raise NotImplementedError('REST API does not currently support updating project owner.') + raise NotImplementedError("REST API does not currently support updating project owner.") def is_default(self): - return self.name.lower() == 'default' + return self.name.lower() == "default" def _parse_common_tags(self, project_xml, ns): if not isinstance(project_xml, ET.Element): - project_xml = ET.fromstring(project_xml).find('.//t:project', namespaces=ns) + project_xml = ET.fromstring(project_xml).find(".//t:project", namespaces=ns) if project_xml is not None: (_, name, description, content_permissions, parent_id) = self._parse_element(project_xml) @@ -118,7 +118,7 @@ def _set_default_permissions(self, permissions, content_type): def from_response(cls, resp, ns): all_project_items = list() parsed_response = ET.fromstring(resp) - all_project_xml = parsed_response.findall('.//t:project', namespaces=ns) + all_project_xml = parsed_response.findall(".//t:project", namespaces=ns) for project_xml in all_project_xml: (id, name, description, content_permissions, parent_id, owner_id) = cls._parse_element(project_xml) @@ -129,13 +129,13 @@ def from_response(cls, resp, ns): @staticmethod def _parse_element(project_xml): - id = project_xml.get('id', None) - name = project_xml.get('name', None) - description = project_xml.get('description', None) - content_permissions = project_xml.get('contentPermissions', None) - parent_id = project_xml.get('parentProjectId', None) + id = project_xml.get("id", None) + name = project_xml.get("name", None) + description = project_xml.get("description", None) + content_permissions = project_xml.get("contentPermissions", None) + parent_id = project_xml.get("parentProjectId", None) owner_id = None for owner in project_xml: - owner_id = owner.get('id', None) + owner_id = owner.get("id", None) return id, name, description, content_permissions, parent_id, owner_id diff --git a/tableauserverclient/models/property_decorators.py b/tableauserverclient/models/property_decorators.py index f1625d112..153786d4c 100644 --- a/tableauserverclient/models/property_decorators.py +++ b/tableauserverclient/models/property_decorators.py @@ -2,6 +2,7 @@ import re from functools import wraps from ..datetime_helpers import parse_datetime + try: basestring except NameError: @@ -70,13 +71,13 @@ def wrapper(self, value): def property_is_int(range, allowed=None): - '''Takes a range of ints and a list of exemptions to check against + """Takes a range of ints and a list of exemptions to check against when setting a property on a model. The range is a tuple of (min, max) and the allowed list (empty by default) allows values outside that range. This is useful for when we use sentinel values. Example: Revisions allow a range of 2-10000, but use -1 as a sentinel for 'unlimited'. - ''' + """ if allowed is None: allowed = () # Empty tuple for fast no-op testing. @@ -98,7 +99,9 @@ def wrapper(self, value): raise ValueError(error) return func(self, value) + return wrapper + return property_type_decorator @@ -112,12 +115,14 @@ def validate_regex_decorator(self, value): if not compiled_re.match(value): raise ValueError(error) return func(self, value) + return validate_regex_decorator + return wrapper def property_is_datetime(func): - """ Takes the following datetime format and turns it into a datetime object: + """Takes the following datetime format and turns it into a datetime object: 2016-08-18T18:25:36Z @@ -130,11 +135,13 @@ def wrapper(self, value): if isinstance(value, datetime.datetime): return func(self, value) if not isinstance(value, basestring): - raise ValueError("Cannot convert {} into a datetime, cannot update {}".format(value.__class__.__name__, - func.__name__)) + raise ValueError( + "Cannot convert {} into a datetime, cannot update {}".format(value.__class__.__name__, func.__name__) + ) dt = parse_datetime(value) return func(self, dt) + return wrapper @@ -142,15 +149,15 @@ def property_is_data_acceleration_config(func): @wraps(func) def wrapper(self, value): if not isinstance(value, dict): - raise ValueError("{} is not type 'dict', cannot update {})".format(value.__class__.__name__, - func.__name__)) - if len(value) != 4 or not all(attr in value.keys() for attr in ('acceleration_enabled', - 'accelerate_now', - 'last_updated_at', - 'acceleration_status')): + raise ValueError("{} is not type 'dict', cannot update {})".format(value.__class__.__name__, func.__name__)) + if len(value) != 4 or not all( + attr in value.keys() + for attr in ("acceleration_enabled", "accelerate_now", "last_updated_at", "acceleration_status") + ): error = "{} should have 2 keys ".format(func.__name__) error += "'acceleration_enabled' and 'accelerate_now'" error += "instead you have {}".format(value.keys()) raise ValueError(error) return func(self, value) + return wrapper diff --git a/tableauserverclient/models/reference_item.py b/tableauserverclient/models/reference_item.py index 2cf0f0119..48d2ab56a 100644 --- a/tableauserverclient/models/reference_item.py +++ b/tableauserverclient/models/reference_item.py @@ -1,5 +1,4 @@ class ResourceReference(object): - def __init__(self, id_, tag_name): self.id = id_ self.tag_name = tag_name diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py index c93ffe922..b54c20ae9 100644 --- a/tableauserverclient/models/schedule_item.py +++ b/tableauserverclient/models/schedule_item.py @@ -35,7 +35,7 @@ def __init__(self, name, priority, schedule_type, execution_order, interval_item self.schedule_type = schedule_type def __repr__(self): - return "".format(**self.__dict__) + return ''.format(**self.__dict__) @property def created_at(self): @@ -109,27 +109,53 @@ def warnings(self): def _parse_common_tags(self, schedule_xml, ns): if not isinstance(schedule_xml, ET.Element): - schedule_xml = ET.fromstring(schedule_xml).find('.//t:schedule', namespaces=ns) + schedule_xml = ET.fromstring(schedule_xml).find(".//t:schedule", namespaces=ns) if schedule_xml is not None: - (_, name, _, _, updated_at, _, next_run_at, end_schedule_at, execution_order, - priority, interval_item) = self._parse_element(schedule_xml, ns) - - self._set_values(id_=None, - name=name, - state=None, - created_at=None, - updated_at=updated_at, - schedule_type=None, - next_run_at=next_run_at, - end_schedule_at=end_schedule_at, - execution_order=execution_order, - priority=priority, - interval_item=interval_item) + ( + _, + name, + _, + _, + updated_at, + _, + next_run_at, + end_schedule_at, + execution_order, + priority, + interval_item, + ) = self._parse_element(schedule_xml, ns) + + self._set_values( + id_=None, + name=name, + state=None, + created_at=None, + updated_at=updated_at, + schedule_type=None, + next_run_at=next_run_at, + end_schedule_at=end_schedule_at, + execution_order=execution_order, + priority=priority, + interval_item=interval_item, + ) return self - def _set_values(self, id_, name, state, created_at, updated_at, schedule_type, - next_run_at, end_schedule_at, execution_order, priority, interval_item, warnings=None): + def _set_values( + self, + id_, + name, + state, + created_at, + updated_at, + schedule_type, + next_run_at, + end_schedule_at, + execution_order, + priority, + interval_item, + warnings=None, + ): if id_ is not None: self._id = id_ if name: @@ -165,25 +191,38 @@ def from_element(cls, parsed_response, ns): warnings = cls._read_warnings(parsed_response, ns) all_schedule_items = [] - all_schedule_xml = parsed_response.findall('.//t:schedule', namespaces=ns) + all_schedule_xml = parsed_response.findall(".//t:schedule", namespaces=ns) for schedule_xml in all_schedule_xml: - (id_, name, state, created_at, updated_at, schedule_type, next_run_at, - end_schedule_at, execution_order, priority, interval_item) = cls._parse_element(schedule_xml, ns) + ( + id_, + name, + state, + created_at, + updated_at, + schedule_type, + next_run_at, + end_schedule_at, + execution_order, + priority, + interval_item, + ) = cls._parse_element(schedule_xml, ns) schedule_item = cls(name, priority, schedule_type, execution_order, interval_item) - schedule_item._set_values(id_=id_, - name=None, - state=state, - created_at=created_at, - updated_at=updated_at, - schedule_type=None, - next_run_at=next_run_at, - end_schedule_at=end_schedule_at, - execution_order=None, - priority=None, - interval_item=None, - warnings=warnings) + schedule_item._set_values( + id_=id_, + name=None, + state=state, + created_at=created_at, + updated_at=updated_at, + schedule_type=None, + next_run_at=next_run_at, + end_schedule_at=end_schedule_at, + execution_order=None, + priority=None, + interval_item=None, + warnings=warnings, + ) all_schedule_items.append(schedule_item) return all_schedule_items @@ -223,44 +262,58 @@ def _parse_interval_item(parsed_response, frequency, ns): @staticmethod def _parse_element(schedule_xml, ns): - id = schedule_xml.get('id', None) - name = schedule_xml.get('name', None) - state = schedule_xml.get('state', None) - created_at = parse_datetime(schedule_xml.get('createdAt', None)) - updated_at = parse_datetime(schedule_xml.get('updatedAt', None)) - schedule_type = schedule_xml.get('type', None) - frequency = schedule_xml.get('frequency', None) - next_run_at = parse_datetime(schedule_xml.get('nextRunAt', None)) - end_schedule_at = parse_datetime(schedule_xml.get('endScheduleAt', None)) - execution_order = schedule_xml.get('executionOrder', None) - - priority = schedule_xml.get('priority', None) + id = schedule_xml.get("id", None) + name = schedule_xml.get("name", None) + state = schedule_xml.get("state", None) + created_at = parse_datetime(schedule_xml.get("createdAt", None)) + updated_at = parse_datetime(schedule_xml.get("updatedAt", None)) + schedule_type = schedule_xml.get("type", None) + frequency = schedule_xml.get("frequency", None) + next_run_at = parse_datetime(schedule_xml.get("nextRunAt", None)) + end_schedule_at = parse_datetime(schedule_xml.get("endScheduleAt", None)) + execution_order = schedule_xml.get("executionOrder", None) + + priority = schedule_xml.get("priority", None) if priority: priority = int(priority) interval_item = None - frequency_detail_elem = schedule_xml.find('.//t:frequencyDetails', namespaces=ns) + frequency_detail_elem = schedule_xml.find(".//t:frequencyDetails", namespaces=ns) if frequency_detail_elem is not None: interval_item = ScheduleItem._parse_interval_item(frequency_detail_elem, frequency, ns) - return id, name, state, created_at, updated_at, schedule_type, \ - next_run_at, end_schedule_at, execution_order, priority, interval_item + return ( + id, + name, + state, + created_at, + updated_at, + schedule_type, + next_run_at, + end_schedule_at, + execution_order, + priority, + interval_item, + ) @staticmethod def parse_add_to_schedule_response(response, ns): parsed_response = ET.fromstring(response.content) warnings = ScheduleItem._read_warnings(parsed_response, ns) - all_task_xml = parsed_response.findall('.//t:task', namespaces=ns) + all_task_xml = parsed_response.findall(".//t:task", namespaces=ns) - error = "Status {}: {}".format(response.status_code, response.reason) \ - if response.status_code < 200 or response.status_code >= 300 else None + error = ( + "Status {}: {}".format(response.status_code, response.reason) + if response.status_code < 200 or response.status_code >= 300 + else None + ) task_created = len(all_task_xml) > 0 return error, warnings, task_created @staticmethod def _read_warnings(parsed_response, ns): - all_warning_xml = parsed_response.findall('.//t:warning', namespaces=ns) + all_warning_xml = parsed_response.findall(".//t:warning", namespaces=ns) warnings = list() if len(all_warning_xml) > 0 else None for warning_xml in all_warning_xml: - warnings.append(warning_xml.get('message', None)) + warnings.append(warning_xml.get("message", None)) return warnings diff --git a/tableauserverclient/models/server_info_item.py b/tableauserverclient/models/server_info_item.py index 0fcdb1e1e..1f6604662 100644 --- a/tableauserverclient/models/server_info_item.py +++ b/tableauserverclient/models/server_info_item.py @@ -22,10 +22,10 @@ def rest_api_version(self): @classmethod def from_response(cls, resp, ns): parsed_response = ET.fromstring(resp) - product_version_tag = parsed_response.find('.//t:productVersion', namespaces=ns) - rest_api_version_tag = parsed_response.find('.//t:restApiVersion', namespaces=ns) + product_version_tag = parsed_response.find(".//t:productVersion", namespaces=ns) + rest_api_version_tag = parsed_response.find(".//t:restApiVersion", namespaces=ns) - build_number = product_version_tag.get('build', None) + build_number = product_version_tag.get("build", None) product_version = product_version_tag.text rest_api_version = rest_api_version_tag.text diff --git a/tableauserverclient/models/site_item.py b/tableauserverclient/models/site_item.py index f562289ce..ac20e6a89 100644 --- a/tableauserverclient/models/site_item.py +++ b/tableauserverclient/models/site_item.py @@ -1,6 +1,12 @@ import xml.etree.ElementTree as ET -from .property_decorators import (property_is_enum, property_is_boolean, property_matches, - property_not_empty, property_not_nullable, property_is_int) +from .property_decorators import ( + property_is_enum, + property_is_boolean, + property_matches, + property_not_empty, + property_not_nullable, + property_is_int, +) VALID_CONTENT_URL_RE = r"^[a-zA-Z0-9_\-]*$" @@ -8,28 +14,62 @@ class SiteItem(object): class AdminMode: - ContentAndUsers = 'ContentAndUsers' - ContentOnly = 'ContentOnly' + ContentAndUsers = "ContentAndUsers" + ContentOnly = "ContentOnly" class State: - Active = 'Active' - Suspended = 'Suspended' - - def __init__(self, name, content_url, admin_mode=None, user_quota=None, storage_quota=None, - disable_subscriptions=False, subscribe_others_enabled=True, revision_history_enabled=False, - revision_limit=None, data_acceleration_mode=None, flows_enabled=True, cataloging_enabled=True, - editing_flows_enabled=True, scheduling_flows_enabled=True, allow_subscription_attachments=True, - guest_access_enabled=False, cache_warmup_enabled=True, commenting_enabled=True, - extract_encryption_mode=None, request_access_enabled=False, run_now_enabled=True, - tier_explorer_capacity=None, tier_creator_capacity=None, tier_viewer_capacity=None, - data_alerts_enabled=True, commenting_mentions_enabled=True, catalog_obfuscation_enabled=False, - flow_auto_save_enabled=True, web_extraction_enabled=True, metrics_content_type_enabled=True, - notify_site_admins_on_throttle=False, authoring_enabled=True, custom_subscription_email_enabled=False, - custom_subscription_email=False, custom_subscription_footer_enabled=False, - custom_subscription_footer=False, ask_data_mode='EnabledByDefault', named_sharing_enabled=True, - mobile_biometrics_enabled=False, sheet_image_enabled=True, derived_permissions_enabled=False, - user_visibility_mode='FULL', use_default_time_zone=True, time_zone=None, - auto_suspend_refresh_enabled=True, auto_suspend_refresh_inactivity_window=30): + Active = "Active" + Suspended = "Suspended" + + def __init__( + self, + name, + content_url, + admin_mode=None, + user_quota=None, + storage_quota=None, + disable_subscriptions=False, + subscribe_others_enabled=True, + revision_history_enabled=False, + revision_limit=None, + data_acceleration_mode=None, + flows_enabled=True, + cataloging_enabled=True, + editing_flows_enabled=True, + scheduling_flows_enabled=True, + allow_subscription_attachments=True, + guest_access_enabled=False, + cache_warmup_enabled=True, + commenting_enabled=True, + extract_encryption_mode=None, + request_access_enabled=False, + run_now_enabled=True, + tier_explorer_capacity=None, + tier_creator_capacity=None, + tier_viewer_capacity=None, + data_alerts_enabled=True, + commenting_mentions_enabled=True, + catalog_obfuscation_enabled=False, + flow_auto_save_enabled=True, + web_extraction_enabled=True, + metrics_content_type_enabled=True, + notify_site_admins_on_throttle=False, + authoring_enabled=True, + custom_subscription_email_enabled=False, + custom_subscription_email=False, + custom_subscription_footer_enabled=False, + custom_subscription_footer=False, + ask_data_mode="EnabledByDefault", + named_sharing_enabled=True, + mobile_biometrics_enabled=False, + sheet_image_enabled=True, + derived_permissions_enabled=False, + user_visibility_mode="FULL", + use_default_time_zone=True, + time_zone=None, + auto_suspend_refresh_enabled=True, + auto_suspend_refresh_inactivity_window=30, + ): self._admin_mode = None self._id = None self._num_users = None @@ -198,7 +238,7 @@ def flows_enabled(self, value): self._flows_enabled = value def is_default(self): - return self.name.lower() == 'default' + return self.name.lower() == "default" @property def editing_flows_enabled(self): @@ -496,51 +536,171 @@ def auto_suspend_refresh_enabled(self, value): def _parse_common_tags(self, site_xml, ns): if not isinstance(site_xml, ET.Element): - site_xml = ET.fromstring(site_xml).find('.//t:site', namespaces=ns) + site_xml = ET.fromstring(site_xml).find(".//t:site", namespaces=ns) if site_xml is not None: - (_, name, content_url, _, admin_mode, state, - subscribe_others_enabled, disable_subscriptions, revision_history_enabled, - user_quota, storage_quota, revision_limit, num_users, storage, - data_acceleration_mode, flows_enabled, cataloging_enabled, editing_flows_enabled, - scheduling_flows_enabled, allow_subscription_attachments, guest_access_enabled, - cache_warmup_enabled, commenting_enabled, extract_encryption_mode, request_access_enabled, - run_now_enabled, tier_explorer_capacity, tier_creator_capacity, tier_viewer_capacity, data_alerts_enabled, - commenting_mentions_enabled, catalog_obfuscation_enabled, flow_auto_save_enabled, web_extraction_enabled, - metrics_content_type_enabled, notify_site_admins_on_throttle, authoring_enabled, - custom_subscription_email_enabled, custom_subscription_email, custom_subscription_footer_enabled, - custom_subscription_footer, ask_data_mode, named_sharing_enabled, mobile_biometrics_enabled, - sheet_image_enabled, derived_permissions_enabled, user_visibility_mode, use_default_time_zone, time_zone, - auto_suspend_refresh_enabled, auto_suspend_refresh_inactivity_window) = self._parse_element(site_xml, ns) - - self._set_values(None, name, content_url, None, admin_mode, state, subscribe_others_enabled, - disable_subscriptions, revision_history_enabled, user_quota, storage_quota, - revision_limit, num_users, storage, data_acceleration_mode, flows_enabled, - cataloging_enabled, editing_flows_enabled, scheduling_flows_enabled, - allow_subscription_attachments, guest_access_enabled, cache_warmup_enabled, - commenting_enabled, extract_encryption_mode, request_access_enabled, run_now_enabled, - tier_explorer_capacity, tier_creator_capacity, tier_viewer_capacity, data_alerts_enabled, - commenting_mentions_enabled, catalog_obfuscation_enabled, flow_auto_save_enabled, - web_extraction_enabled, metrics_content_type_enabled, notify_site_admins_on_throttle, - authoring_enabled, custom_subscription_email_enabled, custom_subscription_email, - custom_subscription_footer_enabled, custom_subscription_footer, ask_data_mode, - named_sharing_enabled, mobile_biometrics_enabled, sheet_image_enabled, - derived_permissions_enabled, user_visibility_mode, use_default_time_zone, time_zone, - auto_suspend_refresh_enabled, auto_suspend_refresh_inactivity_window) + ( + _, + name, + content_url, + _, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ) = self._parse_element(site_xml, ns) + + self._set_values( + None, + name, + content_url, + None, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ) return self - def _set_values(self, id, name, content_url, status_reason, admin_mode, state, - subscribe_others_enabled, disable_subscriptions, revision_history_enabled, - user_quota, storage_quota, revision_limit, num_users, storage, data_acceleration_mode, - flows_enabled, cataloging_enabled, editing_flows_enabled, scheduling_flows_enabled, - allow_subscription_attachments, guest_access_enabled, cache_warmup_enabled, commenting_enabled, - extract_encryption_mode, request_access_enabled, run_now_enabled, tier_explorer_capacity, - tier_creator_capacity, tier_viewer_capacity, data_alerts_enabled, commenting_mentions_enabled, - catalog_obfuscation_enabled, flow_auto_save_enabled, web_extraction_enabled, - metrics_content_type_enabled, notify_site_admins_on_throttle, authoring_enabled, - custom_subscription_email_enabled, custom_subscription_email, custom_subscription_footer_enabled, - custom_subscription_footer, ask_data_mode, named_sharing_enabled, mobile_biometrics_enabled, - sheet_image_enabled, derived_permissions_enabled, user_visibility_mode, use_default_time_zone, - time_zone, auto_suspend_refresh_enabled, auto_suspend_refresh_inactivity_window): + def _set_values( + self, + id, + name, + content_url, + status_reason, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ): if id is not None: self._id = id if name: @@ -648,133 +808,252 @@ def _set_values(self, id, name, content_url, status_reason, admin_mode, state, def from_response(cls, resp, ns): all_site_items = list() parsed_response = ET.fromstring(resp) - all_site_xml = parsed_response.findall('.//t:site', namespaces=ns) + all_site_xml = parsed_response.findall(".//t:site", namespaces=ns) for site_xml in all_site_xml: - (id, name, content_url, status_reason, admin_mode, state, subscribe_others_enabled, - disable_subscriptions, revision_history_enabled, user_quota, storage_quota, - revision_limit, num_users, storage, data_acceleration_mode, flows_enabled, cataloging_enabled, - editing_flows_enabled, scheduling_flows_enabled, allow_subscription_attachments, guest_access_enabled, - cache_warmup_enabled, commenting_enabled, extract_encryption_mode, request_access_enabled, - run_now_enabled, tier_explorer_capacity, tier_creator_capacity, tier_viewer_capacity, - data_alerts_enabled, commenting_mentions_enabled, catalog_obfuscation_enabled, flow_auto_save_enabled, - web_extraction_enabled, metrics_content_type_enabled, notify_site_admins_on_throttle, - authoring_enabled, custom_subscription_email_enabled, custom_subscription_email, - custom_subscription_footer_enabled, custom_subscription_footer, ask_data_mode, named_sharing_enabled, - mobile_biometrics_enabled, sheet_image_enabled, derived_permissions_enabled, user_visibility_mode, - use_default_time_zone, time_zone, auto_suspend_refresh_enabled, - auto_suspend_refresh_inactivity_window) = cls._parse_element(site_xml, ns) + ( + id, + name, + content_url, + status_reason, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ) = cls._parse_element(site_xml, ns) site_item = cls(name, content_url) - site_item._set_values(id, name, content_url, status_reason, admin_mode, state, subscribe_others_enabled, - disable_subscriptions, revision_history_enabled, user_quota, storage_quota, - revision_limit, num_users, storage, data_acceleration_mode, flows_enabled, - cataloging_enabled, editing_flows_enabled, scheduling_flows_enabled, - allow_subscription_attachments, guest_access_enabled, cache_warmup_enabled, - commenting_enabled, extract_encryption_mode, request_access_enabled, run_now_enabled, - tier_explorer_capacity, tier_creator_capacity, tier_viewer_capacity, - data_alerts_enabled, commenting_mentions_enabled, catalog_obfuscation_enabled, - flow_auto_save_enabled, web_extraction_enabled, metrics_content_type_enabled, - notify_site_admins_on_throttle, authoring_enabled, custom_subscription_email_enabled, - custom_subscription_email, custom_subscription_footer_enabled, - custom_subscription_footer, ask_data_mode, named_sharing_enabled, - mobile_biometrics_enabled, sheet_image_enabled, derived_permissions_enabled, - user_visibility_mode, use_default_time_zone, time_zone, auto_suspend_refresh_enabled, - auto_suspend_refresh_inactivity_window) + site_item._set_values( + id, + name, + content_url, + status_reason, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ) all_site_items.append(site_item) return all_site_items @staticmethod def _parse_element(site_xml, ns): - id = site_xml.get('id', None) - name = site_xml.get('name', None) - content_url = site_xml.get('contentUrl', None) - status_reason = site_xml.get('statusReason', None) - admin_mode = site_xml.get('adminMode', None) - state = site_xml.get('state', None) - subscribe_others_enabled = string_to_bool(site_xml.get('subscribeOthersEnabled', '')) - disable_subscriptions = string_to_bool(site_xml.get('disableSubscriptions', '')) - revision_history_enabled = string_to_bool(site_xml.get('revisionHistoryEnabled', '')) - editing_flows_enabled = string_to_bool(site_xml.get('editingFlowsEnabled', '')) - scheduling_flows_enabled = string_to_bool(site_xml.get('schedulingFlowsEnabled', '')) - allow_subscription_attachments = string_to_bool(site_xml.get('allowSubscriptionAttachments', '')) - guest_access_enabled = string_to_bool(site_xml.get('guestAccessEnabled', '')) - cache_warmup_enabled = string_to_bool(site_xml.get('cacheWarmupEnabled', '')) - commenting_enabled = string_to_bool(site_xml.get('commentingEnabled', '')) - extract_encryption_mode = site_xml.get('extractEncryptionMode', None) - request_access_enabled = string_to_bool(site_xml.get('requestAccessEnabled', '')) - run_now_enabled = string_to_bool(site_xml.get('runNowEnabled', '')) - tier_explorer_capacity = site_xml.get('tierExplorerCapacity', None) + id = site_xml.get("id", None) + name = site_xml.get("name", None) + content_url = site_xml.get("contentUrl", None) + status_reason = site_xml.get("statusReason", None) + admin_mode = site_xml.get("adminMode", None) + state = site_xml.get("state", None) + subscribe_others_enabled = string_to_bool(site_xml.get("subscribeOthersEnabled", "")) + disable_subscriptions = string_to_bool(site_xml.get("disableSubscriptions", "")) + revision_history_enabled = string_to_bool(site_xml.get("revisionHistoryEnabled", "")) + editing_flows_enabled = string_to_bool(site_xml.get("editingFlowsEnabled", "")) + scheduling_flows_enabled = string_to_bool(site_xml.get("schedulingFlowsEnabled", "")) + allow_subscription_attachments = string_to_bool(site_xml.get("allowSubscriptionAttachments", "")) + guest_access_enabled = string_to_bool(site_xml.get("guestAccessEnabled", "")) + cache_warmup_enabled = string_to_bool(site_xml.get("cacheWarmupEnabled", "")) + commenting_enabled = string_to_bool(site_xml.get("commentingEnabled", "")) + extract_encryption_mode = site_xml.get("extractEncryptionMode", None) + request_access_enabled = string_to_bool(site_xml.get("requestAccessEnabled", "")) + run_now_enabled = string_to_bool(site_xml.get("runNowEnabled", "")) + tier_explorer_capacity = site_xml.get("tierExplorerCapacity", None) if tier_explorer_capacity: tier_explorer_capacity = int(tier_explorer_capacity) - tier_creator_capacity = site_xml.get('tierCreatorCapacity', None) + tier_creator_capacity = site_xml.get("tierCreatorCapacity", None) if tier_creator_capacity: tier_creator_capacity = int(tier_creator_capacity) - tier_viewer_capacity = site_xml.get('tierViewerCapacity', None) + tier_viewer_capacity = site_xml.get("tierViewerCapacity", None) if tier_viewer_capacity: tier_viewer_capacity = int(tier_viewer_capacity) - data_alerts_enabled = string_to_bool(site_xml.get('dataAlertsEnabled', '')) - commenting_mentions_enabled = string_to_bool(site_xml.get('commentingMentionsEnabled', '')) - catalog_obfuscation_enabled = string_to_bool(site_xml.get('catalogObfuscationEnabled', '')) - flow_auto_save_enabled = string_to_bool(site_xml.get('flowAutoSaveEnabled', '')) - web_extraction_enabled = string_to_bool(site_xml.get('webExtractionEnabled', '')) - metrics_content_type_enabled = string_to_bool(site_xml.get('metricsContentTypeEnabled', '')) - notify_site_admins_on_throttle = string_to_bool(site_xml.get('notifySiteAdminsOnThrottle', '')) - authoring_enabled = string_to_bool(site_xml.get('authoringEnabled', '')) - custom_subscription_email_enabled = string_to_bool(site_xml.get('customSubscriptionEmailEnabled', '')) - custom_subscription_email = site_xml.get('customSubscriptionEmail', None) - custom_subscription_footer_enabled = string_to_bool(site_xml.get('customSubscriptionFooterEnabled', '')) - custom_subscription_footer = site_xml.get('customSubscriptionFooter', None) - ask_data_mode = site_xml.get('askDataMode', None) - named_sharing_enabled = string_to_bool(site_xml.get('namedSharingEnabled', '')) - mobile_biometrics_enabled = string_to_bool(site_xml.get('mobileBiometricsEnabled', '')) - sheet_image_enabled = string_to_bool(site_xml.get('sheetImageEnabled', '')) - derived_permissions_enabled = string_to_bool(site_xml.get('derivedPermissionsEnabled', '')) - user_visibility_mode = site_xml.get('userVisibilityMode', '') - use_default_time_zone = string_to_bool(site_xml.get('useDefaultTimeZone', '')) - time_zone = site_xml.get('timeZone', None) - auto_suspend_refresh_enabled = string_to_bool(site_xml.get('autoSuspendRefreshEnabled', '')) - auto_suspend_refresh_inactivity_window = site_xml.get('autoSuspendRefreshInactivityWindow', None) + data_alerts_enabled = string_to_bool(site_xml.get("dataAlertsEnabled", "")) + commenting_mentions_enabled = string_to_bool(site_xml.get("commentingMentionsEnabled", "")) + catalog_obfuscation_enabled = string_to_bool(site_xml.get("catalogObfuscationEnabled", "")) + flow_auto_save_enabled = string_to_bool(site_xml.get("flowAutoSaveEnabled", "")) + web_extraction_enabled = string_to_bool(site_xml.get("webExtractionEnabled", "")) + metrics_content_type_enabled = string_to_bool(site_xml.get("metricsContentTypeEnabled", "")) + notify_site_admins_on_throttle = string_to_bool(site_xml.get("notifySiteAdminsOnThrottle", "")) + authoring_enabled = string_to_bool(site_xml.get("authoringEnabled", "")) + custom_subscription_email_enabled = string_to_bool(site_xml.get("customSubscriptionEmailEnabled", "")) + custom_subscription_email = site_xml.get("customSubscriptionEmail", None) + custom_subscription_footer_enabled = string_to_bool(site_xml.get("customSubscriptionFooterEnabled", "")) + custom_subscription_footer = site_xml.get("customSubscriptionFooter", None) + ask_data_mode = site_xml.get("askDataMode", None) + named_sharing_enabled = string_to_bool(site_xml.get("namedSharingEnabled", "")) + mobile_biometrics_enabled = string_to_bool(site_xml.get("mobileBiometricsEnabled", "")) + sheet_image_enabled = string_to_bool(site_xml.get("sheetImageEnabled", "")) + derived_permissions_enabled = string_to_bool(site_xml.get("derivedPermissionsEnabled", "")) + user_visibility_mode = site_xml.get("userVisibilityMode", "") + use_default_time_zone = string_to_bool(site_xml.get("useDefaultTimeZone", "")) + time_zone = site_xml.get("timeZone", None) + auto_suspend_refresh_enabled = string_to_bool(site_xml.get("autoSuspendRefreshEnabled", "")) + auto_suspend_refresh_inactivity_window = site_xml.get("autoSuspendRefreshInactivityWindow", None) if auto_suspend_refresh_inactivity_window: auto_suspend_refresh_inactivity_window = int(auto_suspend_refresh_inactivity_window) - user_quota = site_xml.get('userQuota', None) + user_quota = site_xml.get("userQuota", None) if user_quota: user_quota = int(user_quota) - storage_quota = site_xml.get('storageQuota', None) + storage_quota = site_xml.get("storageQuota", None) if storage_quota: storage_quota = int(storage_quota) - revision_limit = site_xml.get('revisionLimit', None) + revision_limit = site_xml.get("revisionLimit", None) if revision_limit: revision_limit = int(revision_limit) num_users = None storage = None - usage_elem = site_xml.find('.//t:usage', namespaces=ns) + usage_elem = site_xml.find(".//t:usage", namespaces=ns) if usage_elem is not None: - num_users = usage_elem.get('numUsers', None) - storage = usage_elem.get('storage', None) - - data_acceleration_mode = site_xml.get('dataAccelerationMode', '') - - flows_enabled = string_to_bool(site_xml.get('flowsEnabled', '')) - cataloging_enabled = string_to_bool(site_xml.get('catalogingEnabled', '')) - - return id, name, content_url, status_reason, admin_mode, state, subscribe_others_enabled,\ - disable_subscriptions, revision_history_enabled, user_quota, storage_quota,\ - revision_limit, num_users, storage, data_acceleration_mode, flows_enabled, cataloging_enabled,\ - editing_flows_enabled, scheduling_flows_enabled, allow_subscription_attachments, guest_access_enabled,\ - cache_warmup_enabled, commenting_enabled, extract_encryption_mode, request_access_enabled, run_now_enabled,\ - tier_explorer_capacity, tier_creator_capacity, tier_viewer_capacity, data_alerts_enabled,\ - commenting_mentions_enabled, catalog_obfuscation_enabled, flow_auto_save_enabled, web_extraction_enabled,\ - metrics_content_type_enabled, notify_site_admins_on_throttle, authoring_enabled,\ - custom_subscription_email_enabled, custom_subscription_email, custom_subscription_footer_enabled,\ - custom_subscription_footer, ask_data_mode, named_sharing_enabled, mobile_biometrics_enabled,\ - sheet_image_enabled, derived_permissions_enabled, user_visibility_mode, use_default_time_zone, time_zone,\ - auto_suspend_refresh_enabled, auto_suspend_refresh_inactivity_window + num_users = usage_elem.get("numUsers", None) + storage = usage_elem.get("storage", None) + + data_acceleration_mode = site_xml.get("dataAccelerationMode", "") + + flows_enabled = string_to_bool(site_xml.get("flowsEnabled", "")) + cataloging_enabled = string_to_bool(site_xml.get("catalogingEnabled", "")) + + return ( + id, + name, + content_url, + status_reason, + admin_mode, + state, + subscribe_others_enabled, + disable_subscriptions, + revision_history_enabled, + user_quota, + storage_quota, + revision_limit, + num_users, + storage, + data_acceleration_mode, + flows_enabled, + cataloging_enabled, + editing_flows_enabled, + scheduling_flows_enabled, + allow_subscription_attachments, + guest_access_enabled, + cache_warmup_enabled, + commenting_enabled, + extract_encryption_mode, + request_access_enabled, + run_now_enabled, + tier_explorer_capacity, + tier_creator_capacity, + tier_viewer_capacity, + data_alerts_enabled, + commenting_mentions_enabled, + catalog_obfuscation_enabled, + flow_auto_save_enabled, + web_extraction_enabled, + metrics_content_type_enabled, + notify_site_admins_on_throttle, + authoring_enabled, + custom_subscription_email_enabled, + custom_subscription_email, + custom_subscription_footer_enabled, + custom_subscription_footer, + ask_data_mode, + named_sharing_enabled, + mobile_biometrics_enabled, + sheet_image_enabled, + derived_permissions_enabled, + user_visibility_mode, + use_default_time_zone, + time_zone, + auto_suspend_refresh_enabled, + auto_suspend_refresh_inactivity_window, + ) # Used to convert string represented boolean to a boolean type def string_to_bool(s): - return s.lower() == 'true' + return s.lower() == "true" diff --git a/tableauserverclient/models/subscription_item.py b/tableauserverclient/models/subscription_item.py index cdcc468a1..c5ac10168 100644 --- a/tableauserverclient/models/subscription_item.py +++ b/tableauserverclient/models/subscription_item.py @@ -4,7 +4,6 @@ class SubscriptionItem(object): - def __init__(self, subject, schedule_id, user_id, target): self._id = None self.attach_image = True @@ -22,10 +21,14 @@ def __init__(self, subject, schedule_id, user_id, target): def __repr__(self): if self.id is not None: return "".format(**self.__dict__) + return ( + "".format(**self.__dict__) + ) @classmethod def from_response(cls, xml, ns, task_type=Type.ExtractRefresh): parsed_response = ET.fromstring(xml) - all_tasks_xml = parsed_response.findall( - './/t:task/t:{}'.format(task_type), namespaces=ns) + all_tasks_xml = parsed_response.findall(".//t:task/t:{}".format(task_type), namespaces=ns) all_tasks = (TaskItem._parse_element(x, ns) for x in all_tasks_xml) @@ -43,9 +52,9 @@ def _parse_element(cls, element, ns): schedule_item = None target = None last_run_at = None - workbook_element = element.find('.//t:workbook', namespaces=ns) - datasource_element = element.find('.//t:datasource', namespaces=ns) - last_run_at_element = element.find('.//t:lastRunAt', namespaces=ns) + workbook_element = element.find(".//t:workbook", namespaces=ns) + datasource_element = element.find(".//t:datasource", namespaces=ns) + last_run_at_element = element.find(".//t:lastRunAt", namespaces=ns) schedule_item_list = ScheduleItem.from_element(element, ns) if len(schedule_item_list) >= 1: @@ -54,22 +63,23 @@ def _parse_element(cls, element, ns): # according to the Tableau Server REST API documentation, # there should be only one of workbook or datasource if workbook_element is not None: - workbook_id = workbook_element.get('id', None) + workbook_id = workbook_element.get("id", None) target = Target(workbook_id, "workbook") if datasource_element is not None: - datasource_id = datasource_element.get('id', None) + datasource_id = datasource_element.get("id", None) target = Target(datasource_id, "datasource") if last_run_at_element is not None: last_run_at = parse_datetime(last_run_at_element.text) # Server response has different names for task types - task_type = cls._translate_task_type(element.get('type', None)) + task_type = cls._translate_task_type(element.get("type", None)) - priority = int(element.get('priority', -1)) - consecutive_failed_count = int(element.get('consecutiveFailedCount', 0)) - id_ = element.get('id', None) - return cls(id_, task_type, priority, consecutive_failed_count, schedule_item.id, - schedule_item, last_run_at, target) + priority = int(element.get("priority", -1)) + consecutive_failed_count = int(element.get("consecutiveFailedCount", 0)) + id_ = element.get("id", None) + return cls( + id_, task_type, priority, consecutive_failed_count, schedule_item.id, schedule_item, last_run_at, target + ) @staticmethod def _translate_task_type(task_type): diff --git a/tableauserverclient/models/user_item.py b/tableauserverclient/models/user_item.py index b5a05b0d1..b9796cbae 100644 --- a/tableauserverclient/models/user_item.py +++ b/tableauserverclient/models/user_item.py @@ -7,33 +7,33 @@ class UserItem(object): - tag_name = 'user' + tag_name = "user" class Roles: - Interactor = 'Interactor' - Publisher = 'Publisher' - ServerAdministrator = 'ServerAdministrator' - SiteAdministrator = 'SiteAdministrator' - Unlicensed = 'Unlicensed' - UnlicensedWithPublish = 'UnlicensedWithPublish' - Viewer = 'Viewer' - ViewerWithPublish = 'ViewerWithPublish' - Guest = 'Guest' - - Creator = 'Creator' - Explorer = 'Explorer' - ExplorerCanPublish = 'ExplorerCanPublish' - ReadOnly = 'ReadOnly' - SiteAdministratorCreator = 'SiteAdministratorCreator' - SiteAdministratorExplorer = 'SiteAdministratorExplorer' + Interactor = "Interactor" + Publisher = "Publisher" + ServerAdministrator = "ServerAdministrator" + SiteAdministrator = "SiteAdministrator" + Unlicensed = "Unlicensed" + UnlicensedWithPublish = "UnlicensedWithPublish" + Viewer = "Viewer" + ViewerWithPublish = "ViewerWithPublish" + Guest = "Guest" + + Creator = "Creator" + Explorer = "Explorer" + ExplorerCanPublish = "ExplorerCanPublish" + ReadOnly = "ReadOnly" + SiteAdministratorCreator = "SiteAdministratorCreator" + SiteAdministratorExplorer = "SiteAdministratorExplorer" # Online only - SupportUser = 'SupportUser' + SupportUser = "SupportUser" class Auth: - OpenID = 'OpenID' - SAML = 'SAML' - ServerDefault = 'ServerDefault' + OpenID = "OpenID" + SAML = "SAML" + ServerDefault = "ServerDefault" def __init__(self, name=None, site_role=None, auth_setting=None): self._auth_setting = None @@ -126,14 +126,15 @@ def _set_groups(self, groups): def _parse_common_tags(self, user_xml, ns): if not isinstance(user_xml, ET.Element): - user_xml = ET.fromstring(user_xml).find('.//t:user', namespaces=ns) + user_xml = ET.fromstring(user_xml).find(".//t:user", namespaces=ns) if user_xml is not None: (_, _, site_role, _, _, fullname, email, auth_setting, _) = self._parse_element(user_xml, ns) self._set_values(None, None, site_role, None, None, fullname, email, auth_setting, None) return self - def _set_values(self, id, name, site_role, last_login, - external_auth_user_id, fullname, email, auth_setting, domain_name): + def _set_values( + self, id, name, site_role, last_login, external_auth_user_id, fullname, email, auth_setting, domain_name + ): if id is not None: self._id = id if name: @@ -157,13 +158,23 @@ def _set_values(self, id, name, site_role, last_login, def from_response(cls, resp, ns): all_user_items = [] parsed_response = ET.fromstring(resp) - all_user_xml = parsed_response.findall('.//t:user', namespaces=ns) + all_user_xml = parsed_response.findall(".//t:user", namespaces=ns) for user_xml in all_user_xml: - (id, name, site_role, last_login, external_auth_user_id, - fullname, email, auth_setting, domain_name) = cls._parse_element(user_xml, ns) + ( + id, + name, + site_role, + last_login, + external_auth_user_id, + fullname, + email, + auth_setting, + domain_name, + ) = cls._parse_element(user_xml, ns) user_item = cls(name, site_role) - user_item._set_values(id, name, site_role, last_login, external_auth_user_id, - fullname, email, auth_setting, domain_name) + user_item._set_values( + id, name, site_role, last_login, external_auth_user_id, fullname, email, auth_setting, domain_name + ) all_user_items.append(user_item) return all_user_items @@ -173,19 +184,19 @@ def as_reference(id_): @staticmethod def _parse_element(user_xml, ns): - id = user_xml.get('id', None) - name = user_xml.get('name', None) - site_role = user_xml.get('siteRole', None) - last_login = parse_datetime(user_xml.get('lastLogin', None)) - external_auth_user_id = user_xml.get('externalAuthUserId', None) - fullname = user_xml.get('fullName', None) - email = user_xml.get('email', None) - auth_setting = user_xml.get('authSetting', None) + id = user_xml.get("id", None) + name = user_xml.get("name", None) + site_role = user_xml.get("siteRole", None) + last_login = parse_datetime(user_xml.get("lastLogin", None)) + external_auth_user_id = user_xml.get("externalAuthUserId", None) + fullname = user_xml.get("fullName", None) + email = user_xml.get("email", None) + auth_setting = user_xml.get("authSetting", None) domain_name = None - domain_elem = user_xml.find('.//t:domain', namespaces=ns) + domain_elem = user_xml.find(".//t:domain", namespaces=ns) if domain_elem is not None: - domain_name = domain_elem.get('name', None) + domain_name = domain_elem.get("name", None) return id, name, site_role, last_login, external_auth_user_id, fullname, email, auth_setting, domain_name diff --git a/tableauserverclient/models/view_item.py b/tableauserverclient/models/view_item.py index f9b7a2940..f18acfc33 100644 --- a/tableauserverclient/models/view_item.py +++ b/tableauserverclient/models/view_item.py @@ -119,42 +119,42 @@ def _set_permissions(self, permissions): self._permissions = permissions @classmethod - def from_response(cls, resp, ns, workbook_id=''): + def from_response(cls, resp, ns, workbook_id=""): return cls.from_xml_element(ET.fromstring(resp), ns, workbook_id) @classmethod - def from_xml_element(cls, parsed_response, ns, workbook_id=''): + def from_xml_element(cls, parsed_response, ns, workbook_id=""): all_view_items = list() - all_view_xml = parsed_response.findall('.//t:view', namespaces=ns) + all_view_xml = parsed_response.findall(".//t:view", namespaces=ns) for view_xml in all_view_xml: view_item = cls() - usage_elem = view_xml.find('.//t:usage', namespaces=ns) - workbook_elem = view_xml.find('.//t:workbook', namespaces=ns) - owner_elem = view_xml.find('.//t:owner', namespaces=ns) - project_elem = view_xml.find('.//t:project', namespaces=ns) - tags_elem = view_xml.find('.//t:tags', namespaces=ns) - view_item._created_at = parse_datetime(view_xml.get('createdAt', None)) - view_item._updated_at = parse_datetime(view_xml.get('updatedAt', None)) - view_item._id = view_xml.get('id', None) - view_item._name = view_xml.get('name', None) - view_item._content_url = view_xml.get('contentUrl', None) - view_item._sheet_type = view_xml.get('sheetType', None) + usage_elem = view_xml.find(".//t:usage", namespaces=ns) + workbook_elem = view_xml.find(".//t:workbook", namespaces=ns) + owner_elem = view_xml.find(".//t:owner", namespaces=ns) + project_elem = view_xml.find(".//t:project", namespaces=ns) + tags_elem = view_xml.find(".//t:tags", namespaces=ns) + view_item._created_at = parse_datetime(view_xml.get("createdAt", None)) + view_item._updated_at = parse_datetime(view_xml.get("updatedAt", None)) + view_item._id = view_xml.get("id", None) + view_item._name = view_xml.get("name", None) + view_item._content_url = view_xml.get("contentUrl", None) + view_item._sheet_type = view_xml.get("sheetType", None) if usage_elem is not None: - total_view = usage_elem.get('totalViewCount', None) + total_view = usage_elem.get("totalViewCount", None) if total_view: view_item._total_views = int(total_view) if owner_elem is not None: - view_item._owner_id = owner_elem.get('id', None) + view_item._owner_id = owner_elem.get("id", None) if project_elem is not None: - view_item._project_id = project_elem.get('id', None) + view_item._project_id = project_elem.get("id", None) if workbook_id: view_item._workbook_id = workbook_id elif workbook_elem is not None: - view_item._workbook_id = workbook_elem.get('id', None) + view_item._workbook_id = workbook_elem.get("id", None) if tags_elem is not None: tags = TagItem.from_xml_element(tags_elem, ns) diff --git a/tableauserverclient/models/webhook_item.py b/tableauserverclient/models/webhook_item.py index 57bcfeaa4..5fc5c5749 100644 --- a/tableauserverclient/models/webhook_item.py +++ b/tableauserverclient/models/webhook_item.py @@ -3,13 +3,13 @@ import re -NAMESPACE_RE = re.compile(r'^{.*}') +NAMESPACE_RE = re.compile(r"^{.*}") def _parse_event(events): event = events[0] # Strip out the namespace from the tag name - return NAMESPACE_RE.sub('', event.tag) + return NAMESPACE_RE.sub("", event.tag) class WebhookItem(object): @@ -50,7 +50,7 @@ def event(self, value): def from_response(cls, resp, ns): all_webhooks_items = list() parsed_response = ET.fromstring(resp) - all_webhooks_xml = parsed_response.findall('.//t:webhook', namespaces=ns) + all_webhooks_xml = parsed_response.findall(".//t:webhook", namespaces=ns) for webhook_xml in all_webhooks_xml: values = cls._parse_element(webhook_xml, ns) @@ -61,25 +61,24 @@ def from_response(cls, resp, ns): @staticmethod def _parse_element(webhook_xml, ns): - id = webhook_xml.get('id', None) - name = webhook_xml.get('name', None) + id = webhook_xml.get("id", None) + name = webhook_xml.get("name", None) url = None - url_tag = webhook_xml.find('.//t:webhook-destination-http', namespaces=ns) + url_tag = webhook_xml.find(".//t:webhook-destination-http", namespaces=ns) if url_tag is not None: - url = url_tag.get('url', None) + url = url_tag.get("url", None) - event = webhook_xml.findall('.//t:webhook-source/*', namespaces=ns) + event = webhook_xml.findall(".//t:webhook-source/*", namespaces=ns) if event is not None and len(event) > 0: event = _parse_event(event) owner_id = None - owner_tag = webhook_xml.find('.//t:owner', namespaces=ns) + owner_tag = webhook_xml.find(".//t:owner", namespaces=ns) if owner_tag is not None: - owner_id = owner_tag.get('id', None) + owner_id = owner_tag.get("id", None) return id, name, url, event, owner_id def __repr__(self): - return "".format( - self.id, self.name, self.url, self.event) + return "".format(self.id, self.name, self.url, self.event) diff --git a/tableauserverclient/models/workbook_item.py b/tableauserverclient/models/workbook_item.py index 3a3ddcdf9..20597364e 100644 --- a/tableauserverclient/models/workbook_item.py +++ b/tableauserverclient/models/workbook_item.py @@ -28,10 +28,12 @@ def __init__(self, project_id, name=None, show_tabs=False): self.project_id = project_id self.show_tabs = show_tabs self.tags = set() - self.data_acceleration_config = {'acceleration_enabled': None, - 'accelerate_now': None, - 'last_updated_at': None, - 'acceleration_status': None} + self.data_acceleration_config = { + "acceleration_enabled": None, + "accelerate_now": None, + "last_updated_at": None, + "acceleration_status": None, + } self._permissions = None @property @@ -155,21 +157,64 @@ def _set_preview_image(self, preview_image): def _parse_common_tags(self, workbook_xml, ns): if not isinstance(workbook_xml, ET.Element): - workbook_xml = ET.fromstring(workbook_xml).find('.//t:workbook', namespaces=ns) + workbook_xml = ET.fromstring(workbook_xml).find(".//t:workbook", namespaces=ns) if workbook_xml is not None: - (_, _, _, _, _, description, updated_at, _, show_tabs, - project_id, project_name, owner_id, _, _, - data_acceleration_config) = self._parse_element(workbook_xml, ns) - - self._set_values(None, None, None, None, None, description, updated_at, - None, show_tabs, project_id, project_name, owner_id, None, None, - data_acceleration_config) + ( + _, + _, + _, + _, + _, + description, + updated_at, + _, + show_tabs, + project_id, + project_name, + owner_id, + _, + _, + data_acceleration_config, + ) = self._parse_element(workbook_xml, ns) + + self._set_values( + None, + None, + None, + None, + None, + description, + updated_at, + None, + show_tabs, + project_id, + project_name, + owner_id, + None, + None, + data_acceleration_config, + ) return self - def _set_values(self, id, name, content_url, webpage_url, created_at, description, updated_at, - size, show_tabs, project_id, project_name, owner_id, tags, views, - data_acceleration_config): + def _set_values( + self, + id, + name, + content_url, + webpage_url, + created_at, + description, + updated_at, + size, + show_tabs, + project_id, + project_name, + owner_id, + tags, + views, + data_acceleration_config, + ): if id is not None: self._id = id if name: @@ -206,92 +251,139 @@ def _set_values(self, id, name, content_url, webpage_url, created_at, descriptio def from_response(cls, resp, ns): all_workbook_items = list() parsed_response = ET.fromstring(resp) - all_workbook_xml = parsed_response.findall('.//t:workbook', namespaces=ns) + all_workbook_xml = parsed_response.findall(".//t:workbook", namespaces=ns) for workbook_xml in all_workbook_xml: - (id, name, content_url, webpage_url, created_at, description, updated_at, size, show_tabs, - project_id, project_name, owner_id, tags, views, - data_acceleration_config) = cls._parse_element(workbook_xml, ns) + ( + id, + name, + content_url, + webpage_url, + created_at, + description, + updated_at, + size, + show_tabs, + project_id, + project_name, + owner_id, + tags, + views, + data_acceleration_config, + ) = cls._parse_element(workbook_xml, ns) workbook_item = cls(project_id) - workbook_item._set_values(id, name, content_url, webpage_url, created_at, description, updated_at, - size, show_tabs, None, project_name, owner_id, tags, views, - data_acceleration_config) + workbook_item._set_values( + id, + name, + content_url, + webpage_url, + created_at, + description, + updated_at, + size, + show_tabs, + None, + project_name, + owner_id, + tags, + views, + data_acceleration_config, + ) all_workbook_items.append(workbook_item) return all_workbook_items @staticmethod def _parse_element(workbook_xml, ns): - id = workbook_xml.get('id', None) - name = workbook_xml.get('name', None) - content_url = workbook_xml.get('contentUrl', None) - webpage_url = workbook_xml.get('webpageUrl', None) - created_at = parse_datetime(workbook_xml.get('createdAt', None)) - description = workbook_xml.get('description', None) - updated_at = parse_datetime(workbook_xml.get('updatedAt', None)) - - size = workbook_xml.get('size', None) + id = workbook_xml.get("id", None) + name = workbook_xml.get("name", None) + content_url = workbook_xml.get("contentUrl", None) + webpage_url = workbook_xml.get("webpageUrl", None) + created_at = parse_datetime(workbook_xml.get("createdAt", None)) + description = workbook_xml.get("description", None) + updated_at = parse_datetime(workbook_xml.get("updatedAt", None)) + + size = workbook_xml.get("size", None) if size: size = int(size) - show_tabs = string_to_bool(workbook_xml.get('showTabs', '')) + show_tabs = string_to_bool(workbook_xml.get("showTabs", "")) project_id = None project_name = None - project_tag = workbook_xml.find('.//t:project', namespaces=ns) + project_tag = workbook_xml.find(".//t:project", namespaces=ns) if project_tag is not None: - project_id = project_tag.get('id', None) - project_name = project_tag.get('name', None) + project_id = project_tag.get("id", None) + project_name = project_tag.get("name", None) owner_id = None - owner_tag = workbook_xml.find('.//t:owner', namespaces=ns) + owner_tag = workbook_xml.find(".//t:owner", namespaces=ns) if owner_tag is not None: - owner_id = owner_tag.get('id', None) + owner_id = owner_tag.get("id", None) tags = None - tags_elem = workbook_xml.find('.//t:tags', namespaces=ns) + tags_elem = workbook_xml.find(".//t:tags", namespaces=ns) if tags_elem is not None: all_tags = TagItem.from_xml_element(tags_elem, ns) tags = all_tags views = None - views_elem = workbook_xml.find('.//t:views', namespaces=ns) + views_elem = workbook_xml.find(".//t:views", namespaces=ns) if views_elem is not None: views = ViewItem.from_xml_element(views_elem, ns) - data_acceleration_config = {'acceleration_enabled': None, 'accelerate_now': None, - 'last_updated_at': None, 'acceleration_status': None} - data_acceleration_elem = workbook_xml.find('.//t:dataAccelerationConfig', namespaces=ns) + data_acceleration_config = { + "acceleration_enabled": None, + "accelerate_now": None, + "last_updated_at": None, + "acceleration_status": None, + } + data_acceleration_elem = workbook_xml.find(".//t:dataAccelerationConfig", namespaces=ns) if data_acceleration_elem is not None: data_acceleration_config = parse_data_acceleration_config(data_acceleration_elem) - return id, name, content_url, webpage_url, created_at, description, updated_at, size, show_tabs, \ - project_id, project_name, owner_id, tags, views, data_acceleration_config + return ( + id, + name, + content_url, + webpage_url, + created_at, + description, + updated_at, + size, + show_tabs, + project_id, + project_name, + owner_id, + tags, + views, + data_acceleration_config, + ) def parse_data_acceleration_config(data_acceleration_elem): data_acceleration_config = dict() - acceleration_enabled = data_acceleration_elem.get('accelerationEnabled', None) + acceleration_enabled = data_acceleration_elem.get("accelerationEnabled", None) if acceleration_enabled is not None: acceleration_enabled = string_to_bool(acceleration_enabled) - accelerate_now = data_acceleration_elem.get('accelerateNow', None) + accelerate_now = data_acceleration_elem.get("accelerateNow", None) if accelerate_now is not None: accelerate_now = string_to_bool(accelerate_now) - last_updated_at = data_acceleration_elem.get('lastUpdatedAt', None) + last_updated_at = data_acceleration_elem.get("lastUpdatedAt", None) if last_updated_at is not None: last_updated_at = parse_datetime(last_updated_at) - acceleration_status = data_acceleration_elem.get('accelerationStatus', None) + acceleration_status = data_acceleration_elem.get("accelerationStatus", None) - data_acceleration_config['acceleration_enabled'] = acceleration_enabled - data_acceleration_config['accelerate_now'] = accelerate_now - data_acceleration_config['last_updated_at'] = last_updated_at - data_acceleration_config['acceleration_status'] = acceleration_status + data_acceleration_config["acceleration_enabled"] = acceleration_enabled + data_acceleration_config["accelerate_now"] = accelerate_now + data_acceleration_config["last_updated_at"] = last_updated_at + data_acceleration_config["acceleration_status"] = acceleration_status return data_acceleration_config # Used to convert string represented boolean to a boolean type def string_to_bool(s): - return s.lower() == 'true' + return s.lower() == "true" diff --git a/tableauserverclient/namespace.py b/tableauserverclient/namespace.py index 43717dce2..986a02fb3 100644 --- a/tableauserverclient/namespace.py +++ b/tableauserverclient/namespace.py @@ -1,9 +1,9 @@ from xml.etree import ElementTree as ET import re -OLD_NAMESPACE = 'http://tableausoftware.com/api' -NEW_NAMESPACE = 'http://tableau.com/api' -NAMESPACE_RE = re.compile(r'\{(.*?)\}') +OLD_NAMESPACE = "http://tableausoftware.com/api" +NEW_NAMESPACE = "http://tableau.com/api" +NAMESPACE_RE = re.compile(r"\{(.*?)\}") class UnknownNamespaceError(Exception): @@ -12,7 +12,7 @@ class UnknownNamespaceError(Exception): class Namespace(object): def __init__(self): - self._namespace = {'t': NEW_NAMESPACE} + self._namespace = {"t": NEW_NAMESPACE} self._detected = False def __call__(self): @@ -22,7 +22,7 @@ def detect(self, xml): if self._detected: return - if not xml.startswith(b'= FILESIZE_LIMIT: - logger.info('Publishing {0} to server with chunking method (datasource over 64MB)'.format(filename)) + logger.info("Publishing {0} to server with chunking method (datasource over 64MB)".format(filename)) upload_session_id = Fileuploads.upload_chunks(self.parent_srv, file) url = "{0}&uploadSessionId={1}".format(url, upload_session_id) - xml_request, content_type = RequestFactory.Datasource.publish_req_chunked(datasource_item, - connection_credentials, - connections) + xml_request, content_type = RequestFactory.Datasource.publish_req_chunked( + datasource_item, connection_credentials, connections + ) else: - logger.info('Publishing {0} to server'.format(filename)) + logger.info("Publishing {0} to server".format(filename)) try: - with open(file, 'rb') as f: + with open(file, "rb") as f: file_contents = f.read() except TypeError: file_contents = file.read() - xml_request, content_type = RequestFactory.Datasource.publish_req(datasource_item, - filename, - file_contents, - connection_credentials, - connections) + xml_request, content_type = RequestFactory.Datasource.publish_req( + datasource_item, filename, file_contents, connection_credentials, connections + ) # Send the publishing request to server try: @@ -255,33 +254,36 @@ def publish(self, datasource_item, file, mode, connection_credentials=None, conn if as_job: new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (JOB_ID: {1}'.format(filename, new_job.id)) + logger.info("Published {0} (JOB_ID: {1}".format(filename, new_job.id)) return new_job else: new_datasource = DatasourceItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (ID: {1})'.format(filename, new_datasource.id)) + logger.info("Published {0} (ID: {1})".format(filename, new_datasource.id)) return new_datasource server_response = self.post_request(url, xml_request, content_type) new_datasource = DatasourceItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (ID: {1})'.format(filename, new_datasource.id)) + logger.info("Published {0} (ID: {1})".format(filename, new_datasource.id)) return new_datasource - @api(version='2.0') + @api(version="2.0") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='2.0') + @api(version="2.0") def update_permission(self, item, permission_item): import warnings - warnings.warn('Server.datasources.update_permission is deprecated, ' - 'please use Server.datasources.update_permissions instead.', - DeprecationWarning) + + warnings.warn( + "Server.datasources.update_permission is deprecated, " + "please use Server.datasources.update_permissions instead.", + DeprecationWarning, + ) self._permissions.update(item, permission_item) - @api(version='2.0') + @api(version="2.0") def update_permissions(self, item, permission_item): self._permissions.update(item, permission_item) - @api(version='2.0') + @api(version="2.0") def delete_permission(self, item, capability_item): self._permissions.delete(item, capability_item) diff --git a/tableauserverclient/server/endpoint/default_permissions_endpoint.py b/tableauserverclient/server/endpoint/default_permissions_endpoint.py index d435a03d6..1cfa41733 100644 --- a/tableauserverclient/server/endpoint/default_permissions_endpoint.py +++ b/tableauserverclient/server/endpoint/default_permissions_endpoint.py @@ -11,7 +11,7 @@ class _DefaultPermissionsEndpoint(Endpoint): - """ Adds default-permission model to another endpoint + """Adds default-permission model to another endpoint Tableau default-permissions model applies only to databases and projects and then takes an object type in the uri to set the defaults. @@ -28,38 +28,37 @@ def __init__(self, parent_srv, owner_baseurl): self.owner_baseurl = owner_baseurl def update_default_permissions(self, resource, permissions, content_type): - url = '{0}/{1}/default-permissions/{2}'.format(self.owner_baseurl(), resource.id, content_type + 's') + url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), resource.id, content_type + "s") update_req = RequestFactory.Permission.add_req(permissions) response = self.put_request(url, update_req) - permissions = PermissionsRule.from_response(response.content, - self.parent_srv.namespace) - logger.info('Updated permissions for resource {0}'.format(resource.id)) + permissions = PermissionsRule.from_response(response.content, self.parent_srv.namespace) + logger.info("Updated permissions for resource {0}".format(resource.id)) return permissions def delete_default_permission(self, resource, rule, content_type): for capability, mode in rule.capabilities.items(): # Made readability better but line is too long, will make this look better - url = '{baseurl}/{content_id}/default-permissions/' \ - '{content_type}/{grantee_type}/{grantee_id}/{cap}/{mode}' \ - .format( + url = ( + "{baseurl}/{content_id}/default-permissions/" + "{content_type}/{grantee_type}/{grantee_id}/{cap}/{mode}".format( baseurl=self.owner_baseurl(), content_id=resource.id, - content_type=content_type + 's', - grantee_type=rule.grantee.tag_name + 's', + content_type=content_type + "s", + grantee_type=rule.grantee.tag_name + "s", grantee_id=rule.grantee.id, cap=capability, - mode=mode) + mode=mode, + ) + ) - logger.debug('Removing {0} permission for capabilty {1}'.format( - mode, capability)) + logger.debug("Removing {0} permission for capabilty {1}".format(mode, capability)) self.delete_request(url) - logger.info('Deleted permission for {0} {1} item {2}'.format( - rule.grantee.tag_name, - rule.grantee.id, - resource.id)) + logger.info( + "Deleted permission for {0} {1} item {2}".format(rule.grantee.tag_name, rule.grantee.id, resource.id) + ) def populate_default_permissions(self, item, content_type): if not item.id: @@ -70,12 +69,11 @@ def permission_fetcher(): return self._get_default_permissions(item, content_type) item._set_default_permissions(permission_fetcher, content_type) - logger.info('Populated {0} permissions for item (ID: {1})'.format(item.id, content_type)) + logger.info("Populated {0} permissions for item (ID: {1})".format(item.id, content_type)) def _get_default_permissions(self, item, content_type, req_options=None): url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), item.id, content_type + "s") server_response = self.get_request(url, req_options) - permissions = PermissionsRule.from_response(server_response.content, - self.parent_srv.namespace) + permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace) return permissions diff --git a/tableauserverclient/server/endpoint/endpoint.py b/tableauserverclient/server/endpoint/endpoint.py index dc504242a..92a20b21a 100644 --- a/tableauserverclient/server/endpoint/endpoint.py +++ b/tableauserverclient/server/endpoint/endpoint.py @@ -9,7 +9,7 @@ except ImportError: from distutils.version import LooseVersion as Version -logger = logging.getLogger('tableau.endpoint') +logger = logging.getLogger("tableau.endpoint") Success_codes = [200, 201, 202, 204] @@ -22,9 +22,9 @@ def __init__(self, parent_srv): def _make_common_headers(auth_token, content_type): headers = {} if auth_token is not None: - headers['x-tableau-auth'] = auth_token + headers["x-tableau-auth"] = auth_token if content_type is not None: - headers['content-type'] = content_type + headers["content-type"] = content_type return headers @@ -33,24 +33,23 @@ def _safe_to_log(server_response): """Checks if the server_response content is not xml (eg binary image or zip) and replaces it with a constant """ - ALLOWED_CONTENT_TYPES = ('application/xml', 'application/xml;charset=utf-8') - if server_response.headers.get('Content-Type', None) not in ALLOWED_CONTENT_TYPES: - return '[Truncated File Contents]' + ALLOWED_CONTENT_TYPES = ("application/xml", "application/xml;charset=utf-8") + if server_response.headers.get("Content-Type", None) not in ALLOWED_CONTENT_TYPES: + return "[Truncated File Contents]" else: return server_response.content - def _make_request(self, method, url, content=None, auth_token=None, - content_type=None, parameters=None): + def _make_request(self, method, url, content=None, auth_token=None, content_type=None, parameters=None): parameters = parameters or {} parameters.update(self.parent_srv.http_options) - parameters['headers'] = Endpoint._make_common_headers(auth_token, content_type) + parameters["headers"] = Endpoint._make_common_headers(auth_token, content_type) if content is not None: - parameters['data'] = content + parameters["data"] = content - logger.debug(u'request {}, url: {}'.format(method.__name__, url)) + logger.debug(u"request {}, url: {}".format(method.__name__, url)) if content: - logger.debug(u'request content: {}'.format(content[:1000])) + logger.debug(u"request content: {}".format(content[:1000])) server_response = method(url, **parameters) self.parent_srv._namespace.detect(server_response.content) @@ -59,8 +58,11 @@ def _make_request(self, method, url, content=None, auth_token=None, # This check is to determine if the response is a text response (xml or otherwise) # so that we do not attempt to log bytes and other binary data. if len(server_response.content) > 0 and server_response.encoding: - logger.debug(u'Server response from {0}:\n\t{1}'.format( - url, server_response.content.decode(server_response.encoding))) + logger.debug( + u"Server response from {0}:\n\t{1}".format( + url, server_response.content.decode(server_response.encoding) + ) + ) return server_response def _check_status(self, server_response): @@ -92,25 +94,31 @@ def get_request(self, url, request_object=None, parameters=None): except EndpointUnavailableError: url = request_object.apply_query_params(url) - return self._make_request(self.parent_srv.session.get, url, - auth_token=self.parent_srv.auth_token, - parameters=parameters) + return self._make_request( + self.parent_srv.session.get, url, auth_token=self.parent_srv.auth_token, parameters=parameters + ) def delete_request(self, url): # We don't return anything for a delete self._make_request(self.parent_srv.session.delete, url, auth_token=self.parent_srv.auth_token) - def put_request(self, url, xml_request=None, content_type='text/xml'): - return self._make_request(self.parent_srv.session.put, url, - content=xml_request, - auth_token=self.parent_srv.auth_token, - content_type=content_type) - - def post_request(self, url, xml_request, content_type='text/xml'): - return self._make_request(self.parent_srv.session.post, url, - content=xml_request, - auth_token=self.parent_srv.auth_token, - content_type=content_type) + def put_request(self, url, xml_request=None, content_type="text/xml"): + return self._make_request( + self.parent_srv.session.put, + url, + content=xml_request, + auth_token=self.parent_srv.auth_token, + content_type=content_type, + ) + + def post_request(self, url, xml_request, content_type="text/xml"): + return self._make_request( + self.parent_srv.session.post, + url, + content=xml_request, + auth_token=self.parent_srv.auth_token, + content_type=content_type, + ) def api(version): @@ -131,12 +139,15 @@ def api(version): >>> def get(self, req_options=None): >>> ... """ + def _decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): self.parent_srv.assert_at_least_version(version) return func(self, *args, **kwargs) + return wrapper + return _decorator @@ -162,10 +173,12 @@ def parameter_added_in(**params): >>> def download(self, workbook_id, filepath=None, extract_only=False): >>> ... """ + def _decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): import warnings + server_ver = Version(self.parent_srv.version or "0.0") params_to_check = set(params) & set(kwargs) for p in params_to_check: @@ -174,7 +187,9 @@ def wrapper(self, *args, **kwargs): error = "{!r} not available in {}, it will be ignored. Added in {}".format(p, server_ver, min_ver) warnings.warn(error) return func(self, *args, **kwargs) + return wrapper + return _decorator diff --git a/tableauserverclient/server/endpoint/exceptions.py b/tableauserverclient/server/endpoint/exceptions.py index 3c9226f0f..9a9a81d77 100644 --- a/tableauserverclient/server/endpoint/exceptions.py +++ b/tableauserverclient/server/endpoint/exceptions.py @@ -15,9 +15,11 @@ def __str__(self): def from_response(cls, resp, ns): # Check elements exist before .text parsed_response = ET.fromstring(resp) - error_response = cls(parsed_response.find('t:error', namespaces=ns).get('code', ''), - parsed_response.find('.//t:summary', namespaces=ns).text, - parsed_response.find('.//t:detail', namespaces=ns).text) + error_response = cls( + parsed_response.find("t:error", namespaces=ns).get("code", ""), + parsed_response.find(".//t:summary", namespaces=ns).text, + parsed_response.find(".//t:detail", namespaces=ns).text, + ) return error_response @@ -60,4 +62,5 @@ def __init__(self, error_payload): def __str__(self): from pprint import pformat + return pformat(self.error) diff --git a/tableauserverclient/server/endpoint/favorites_endpoint.py b/tableauserverclient/server/endpoint/favorites_endpoint.py index b1a90ba00..459d852e6 100644 --- a/tableauserverclient/server/endpoint/favorites_endpoint.py +++ b/tableauserverclient/server/endpoint/favorites_endpoint.py @@ -7,7 +7,7 @@ import logging import copy -logger = logging.getLogger('tableau.endpoint.favorites') +logger = logging.getLogger("tableau.endpoint.favorites") class Favorites(Endpoint): @@ -18,60 +18,60 @@ def baseurl(self): # Gets all favorites @api(version="2.5") def get(self, user_item, req_options=None): - logger.info('Querying all favorites for user {0}'.format(user_item.name)) - url = '{0}/{1}'.format(self.baseurl, user_item.id) + logger.info("Querying all favorites for user {0}".format(user_item.name)) + url = "{0}/{1}".format(self.baseurl, user_item.id) server_response = self.get_request(url, req_options) user_item._favorites = FavoriteItem.from_response(server_response.content, self.parent_srv.namespace) @api(version="2.0") def add_favorite_workbook(self, user_item, workbook_item): - url = '{0}/{1}'.format(self.baseurl, user_item.id) + url = "{0}/{1}".format(self.baseurl, user_item.id) add_req = RequestFactory.Favorite.add_workbook_req(workbook_item.id, workbook_item.name) server_response = self.put_request(url, add_req) - logger.info('Favorited {0} for user (ID: {1})'.format(workbook_item.name, user_item.id)) + logger.info("Favorited {0} for user (ID: {1})".format(workbook_item.name, user_item.id)) @api(version="2.0") def add_favorite_view(self, user_item, view_item): - url = '{0}/{1}'.format(self.baseurl, user_item.id) + url = "{0}/{1}".format(self.baseurl, user_item.id) add_req = RequestFactory.Favorite.add_view_req(view_item.id, view_item.name) server_response = self.put_request(url, add_req) - logger.info('Favorited {0} for user (ID: {1})'.format(view_item.name, user_item.id)) + logger.info("Favorited {0} for user (ID: {1})".format(view_item.name, user_item.id)) @api(version="2.3") def add_favorite_datasource(self, user_item, datasource_item): - url = '{0}/{1}'.format(self.baseurl, user_item.id) + url = "{0}/{1}".format(self.baseurl, user_item.id) add_req = RequestFactory.Favorite.add_datasource_req(datasource_item.id, datasource_item.name) server_response = self.put_request(url, add_req) - logger.info('Favorited {0} for user (ID: {1})'.format(datasource_item.name, user_item.id)) + logger.info("Favorited {0} for user (ID: {1})".format(datasource_item.name, user_item.id)) @api(version="3.1") def add_favorite_project(self, user_item, project_item): - url = '{0}/{1}'.format(self.baseurl, user_item.id) + url = "{0}/{1}".format(self.baseurl, user_item.id) add_req = RequestFactory.Favorite.add_project_req(project_item.id, project_item.name) server_response = self.put_request(url, add_req) - logger.info('Favorited {0} for user (ID: {1})'.format(project_item.name, user_item.id)) + logger.info("Favorited {0} for user (ID: {1})".format(project_item.name, user_item.id)) @api(version="2.0") def delete_favorite_workbook(self, user_item, workbook_item): - url = '{0}/{1}/workbooks/{2}'.format(self.baseurl, user_item.id, workbook_item.id) - logger.info('Removing favorite {0} for user (ID: {1})'.format(workbook_item.id, user_item.id)) + url = "{0}/{1}/workbooks/{2}".format(self.baseurl, user_item.id, workbook_item.id) + logger.info("Removing favorite {0} for user (ID: {1})".format(workbook_item.id, user_item.id)) self.delete_request(url) @api(version="2.0") def delete_favorite_view(self, user_item, view_item): - url = '{0}/{1}/views/{2}'.format(self.baseurl, user_item.id, view_item.id) - logger.info('Removing favorite {0} for user (ID: {1})'.format(view_item.id, user_item.id)) + url = "{0}/{1}/views/{2}".format(self.baseurl, user_item.id, view_item.id) + logger.info("Removing favorite {0} for user (ID: {1})".format(view_item.id, user_item.id)) self.delete_request(url) @api(version="2.3") def delete_favorite_datasource(self, user_item, datasource_item): - url = '{0}/{1}/datasources/{2}'.format(self.baseurl, user_item.id, datasource_item.id) - logger.info('Removing favorite {0} for user (ID: {1})'.format(datasource_item.id, user_item.id)) + url = "{0}/{1}/datasources/{2}".format(self.baseurl, user_item.id, datasource_item.id) + logger.info("Removing favorite {0} for user (ID: {1})".format(datasource_item.id, user_item.id)) self.delete_request(url) @api(version="3.1") def delete_favorite_project(self, user_item, project_item): - url = '{0}/{1}/projects/{2}'.format(self.baseurl, user_item.id, project_item.id) - logger.info('Removing favorite {0} for user (ID: {1})'.format(project_item.id, user_item.id)) + url = "{0}/{1}/projects/{2}".format(self.baseurl, user_item.id, project_item.id) + logger.info("Removing favorite {0} for user (ID: {1})".format(project_item.id, user_item.id)) self.delete_request(url) diff --git a/tableauserverclient/server/endpoint/fileuploads_endpoint.py b/tableauserverclient/server/endpoint/fileuploads_endpoint.py index c89a595d4..05a3ce17c 100644 --- a/tableauserverclient/server/endpoint/fileuploads_endpoint.py +++ b/tableauserverclient/server/endpoint/fileuploads_endpoint.py @@ -8,13 +8,13 @@ # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks CHUNK_SIZE = 1024 * 1024 * 5 # 5MB -logger = logging.getLogger('tableau.endpoint.fileuploads') +logger = logging.getLogger("tableau.endpoint.fileuploads") class Fileuploads(Endpoint): def __init__(self, parent_srv): super(Fileuploads, self).__init__(parent_srv) - self.upload_id = '' + self.upload_id = "" @property def baseurl(self): @@ -23,10 +23,10 @@ def baseurl(self): @api(version="2.0") def initiate(self): url = self.baseurl - server_response = self.post_request(url, '') + server_response = self.post_request(url, "") fileupload_item = FileuploadItem.from_response(server_response.content, self.parent_srv.namespace) self.upload_id = fileupload_item.upload_session_id - logger.info('Initiated file upload session (ID: {0})'.format(self.upload_id)) + logger.info("Initiated file upload session (ID: {0})".format(self.upload_id)) return self.upload_id @api(version="2.0") @@ -36,13 +36,13 @@ def append(self, xml_request, content_type): raise MissingRequiredFieldError(error) url = "{0}/{1}".format(self.baseurl, self.upload_id) server_response = self.put_request(url, xml_request, content_type) - logger.info('Uploading a chunk to session (ID: {0})'.format(self.upload_id)) + logger.info("Uploading a chunk to session (ID: {0})".format(self.upload_id)) return FileuploadItem.from_response(server_response.content, self.parent_srv.namespace) def read_chunks(self, file): file_opened = False try: - file_content = open(file, 'rb') + file_content = open(file, "rb") file_opened = True except TypeError: file_content = file diff --git a/tableauserverclient/server/endpoint/flows_endpoint.py b/tableauserverclient/server/endpoint/flows_endpoint.py index dfe16f904..41cbe19cd 100644 --- a/tableauserverclient/server/endpoint/flows_endpoint.py +++ b/tableauserverclient/server/endpoint/flows_endpoint.py @@ -14,11 +14,11 @@ from contextlib import closing # The maximum size of a file that can be published in a single request is 64MB -FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB +FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB -ALLOWED_FILE_EXTENSIONS = ['tfl', 'tflx'] +ALLOWED_FILE_EXTENSIONS = ["tfl", "tflx"] -logger = logging.getLogger('tableau.endpoint.flows') +logger = logging.getLogger("tableau.endpoint.flows") class Flows(Endpoint): @@ -34,7 +34,7 @@ def baseurl(self): # Get all flows @api(version="3.3") def get(self, req_options=None): - logger.info('Querying all flows on site') + logger.info("Querying all flows on site") url = self.baseurl server_response = self.get_request(url, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) @@ -47,7 +47,7 @@ def get_by_id(self, flow_id): if not flow_id: error = "Flow ID undefined." raise ValueError(error) - logger.info('Querying single flow (ID: {0})'.format(flow_id)) + logger.info("Querying single flow (ID: {0})".format(flow_id)) url = "{0}/{1}".format(self.baseurl, flow_id) server_response = self.get_request(url) return FlowItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -56,17 +56,17 @@ def get_by_id(self, flow_id): @api(version="3.3") def populate_connections(self, flow_item): if not flow_item.id: - error = 'Flow item missing ID. Flow must be retrieved from server first.' + error = "Flow item missing ID. Flow must be retrieved from server first." raise MissingRequiredFieldError(error) def connections_fetcher(): return self._get_flow_connections(flow_item) flow_item._set_connections(connections_fetcher) - logger.info('Populated connections for flow (ID: {0})'.format(flow_item.id)) + logger.info("Populated connections for flow (ID: {0})".format(flow_item.id)) def _get_flow_connections(self, flow_item, req_options=None): - url = '{0}/{1}/connections'.format(self.baseurl, flow_item.id) + url = "{0}/{1}/connections".format(self.baseurl, flow_item.id) server_response = self.get_request(url, req_options) connections = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace) return connections @@ -79,7 +79,7 @@ def delete(self, flow_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, flow_id) self.delete_request(url) - logger.info('Deleted single flow (ID: {0})'.format(flow_id)) + logger.info("Deleted single flow (ID: {0})".format(flow_id)) # Download 1 flow by id @api(version="3.3") @@ -89,24 +89,24 @@ def download(self, flow_id, filepath=None): raise ValueError(error) url = "{0}/{1}/content".format(self.baseurl, flow_id) - with closing(self.get_request(url, parameters={'stream': True})) as server_response: - _, params = cgi.parse_header(server_response.headers['Content-Disposition']) - filename = to_filename(os.path.basename(params['filename'])) + with closing(self.get_request(url, parameters={"stream": True})) as server_response: + _, params = cgi.parse_header(server_response.headers["Content-Disposition"]) + filename = to_filename(os.path.basename(params["filename"])) download_path = make_download_path(filepath, filename) - with open(download_path, 'wb') as f: + with open(download_path, "wb") as f: for chunk in server_response.iter_content(1024): # 1KB f.write(chunk) - logger.info('Downloaded flow to {0} (ID: {1})'.format(download_path, flow_id)) + logger.info("Downloaded flow to {0} (ID: {1})".format(download_path, flow_id)) return os.path.abspath(download_path) # Update flow @api(version="3.3") def update(self, flow_item): if not flow_item.id: - error = 'Flow item missing ID. Flow must be retrieved from server first.' + error = "Flow item missing ID. Flow must be retrieved from server first." raise MissingRequiredFieldError(error) self._resource_tagger.update_tags(self.baseurl, flow_item) @@ -115,7 +115,7 @@ def update(self, flow_item): url = "{0}/{1}".format(self.baseurl, flow_item.id) update_req = RequestFactory.Flow.update_req(flow_item) server_response = self.put_request(url, update_req) - logger.info('Updated flow item (ID: {0})'.format(flow_item.id)) + logger.info("Updated flow item (ID: {0})".format(flow_item.id)) updated_flow = copy.copy(flow_item) return updated_flow._parse_common_elements(server_response.content, self.parent_srv.namespace) @@ -128,8 +128,7 @@ def update_connection(self, flow_item, connection_item): server_response = self.put_request(url, update_req) connection = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Updated flow item (ID: {0} & connection item {1}'.format(flow_item.id, - connection_item.id)) + logger.info("Updated flow item (ID: {0} & connection item {1}".format(flow_item.id, connection_item.id)) return connection @api(version="3.3") @@ -147,7 +146,7 @@ def publish(self, flow_item, file_path, mode, connections=None): error = "File path does not lead to an existing file." raise IOError(error) if not mode or not hasattr(self.parent_srv.PublishMode, mode): - error = 'Invalid mode defined.' + error = "Invalid mode defined." raise ValueError(error) filename = os.path.basename(file_path) @@ -157,29 +156,25 @@ def publish(self, flow_item, file_path, mode, connections=None): if not flow_item.name: flow_item.name = os.path.splitext(filename)[0] if file_extension not in ALLOWED_FILE_EXTENSIONS: - error = "Only {} files can be published as flows.".format(', '.join(ALLOWED_FILE_EXTENSIONS)) + error = "Only {} files can be published as flows.".format(", ".join(ALLOWED_FILE_EXTENSIONS)) raise ValueError(error) # Construct the url with the defined mode url = "{0}?flowType={1}".format(self.baseurl, file_extension) if mode == self.parent_srv.PublishMode.Overwrite or mode == self.parent_srv.PublishMode.Append: - url += '&{0}=true'.format(mode.lower()) + url += "&{0}=true".format(mode.lower()) # Determine if chunking is required (64MB is the limit for single upload method) if os.path.getsize(file_path) >= FILESIZE_LIMIT: - logger.info('Publishing {0} to server with chunking method (flow over 64MB)'.format(filename)) + logger.info("Publishing {0} to server with chunking method (flow over 64MB)".format(filename)) upload_session_id = Fileuploads.upload_chunks(self.parent_srv, file_path) url = "{0}&uploadSessionId={1}".format(url, upload_session_id) - xml_request, content_type = RequestFactory.Flow.publish_req_chunked(flow_item, - connections) + xml_request, content_type = RequestFactory.Flow.publish_req_chunked(flow_item, connections) else: - logger.info('Publishing {0} to server'.format(filename)) - with open(file_path, 'rb') as f: + logger.info("Publishing {0} to server".format(filename)) + with open(file_path, "rb") as f: file_contents = f.read() - xml_request, content_type = RequestFactory.Flow.publish_req(flow_item, - filename, - file_contents, - connections) + xml_request, content_type = RequestFactory.Flow.publish_req(flow_item, filename, file_contents, connections) # Send the publishing request to server try: @@ -190,30 +185,32 @@ def publish(self, flow_item, file_path, mode, connections=None): raise err else: new_flow = FlowItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (ID: {1})'.format(filename, new_flow.id)) + logger.info("Published {0} (ID: {1})".format(filename, new_flow.id)) return new_flow server_response = self.post_request(url, xml_request, content_type) new_flow = FlowItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (ID: {1})'.format(filename, new_flow.id)) + logger.info("Published {0} (ID: {1})".format(filename, new_flow.id)) return new_flow - @api(version='3.3') + @api(version="3.3") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='3.3') + @api(version="3.3") def update_permission(self, item, permission_item): import warnings - warnings.warn('Server.flows.update_permission is deprecated, ' - 'please use Server.flows.update_permissions instead.', - DeprecationWarning) + + warnings.warn( + "Server.flows.update_permission is deprecated, " "please use Server.flows.update_permissions instead.", + DeprecationWarning, + ) self._permissions.update(item, permission_item) - @api(version='3.3') + @api(version="3.3") def update_permissions(self, item, permission_item): self._permissions.update(item, permission_item) - @api(version='3.3') + @api(version="3.3") def delete_permission(self, item, capability_item): self._permissions.delete(item, capability_item) diff --git a/tableauserverclient/server/endpoint/groups_endpoint.py b/tableauserverclient/server/endpoint/groups_endpoint.py index 6a9b81afd..4a09872cb 100644 --- a/tableauserverclient/server/endpoint/groups_endpoint.py +++ b/tableauserverclient/server/endpoint/groups_endpoint.py @@ -5,7 +5,7 @@ import logging -logger = logging.getLogger('tableau.endpoint.groups') +logger = logging.getLogger("tableau.endpoint.groups") class Groups(Endpoint): @@ -16,7 +16,7 @@ def baseurl(self): # Gets all groups @api(version="2.0") def get(self, req_options=None): - logger.info('Querying all groups on site') + logger.info("Querying all groups on site") url = self.baseurl server_response = self.get_request(url, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) @@ -42,7 +42,7 @@ def _get_users_for_group(self, group_item, req_options=None): server_response = self.get_request(url, req_options) user_item = UserItem.from_response(server_response.content, self.parent_srv.namespace) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) - logger.info('Populated users for group (ID: {0})'.format(group_item.id)) + logger.info("Populated users for group (ID: {0})".format(group_item.id)) return user_item, pagination_item # Deletes 1 group by id @@ -53,30 +53,33 @@ def delete(self, group_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, group_id) self.delete_request(url) - logger.info('Deleted single group (ID: {0})'.format(group_id)) + logger.info("Deleted single group (ID: {0})".format(group_id)) @api(version="2.0") def update(self, group_item, default_site_role=None, as_job=False): # (1/8/2021): Deprecated starting v0.15 if default_site_role is not None: import warnings - warnings.simplefilter('always', DeprecationWarning) - warnings.warn('Groups.update(...default_site_role=""...) is deprecated, ' - 'please set the minimum_site_role field of GroupItem', - DeprecationWarning) + + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + 'Groups.update(...default_site_role=""...) is deprecated, ' + "please set the minimum_site_role field of GroupItem", + DeprecationWarning, + ) group_item.minimum_site_role = default_site_role if not group_item.id: error = "Group item missing ID." raise MissingRequiredFieldError(error) - if as_job and (group_item.domain_name is None or group_item.domain_name == 'local'): + if as_job and (group_item.domain_name is None or group_item.domain_name == "local"): error = "Local groups cannot be updated asynchronously." raise ValueError(error) url = "{0}/{1}".format(self.baseurl, group_item.id) update_req = RequestFactory.Group.update_req(group_item, None) server_response = self.put_request(url, update_req) - logger.info('Updated group item (ID: {0})'.format(group_item.id)) + logger.info("Updated group item (ID: {0})".format(group_item.id)) if as_job: return JobItem.from_response(server_response.content, self.parent_srv.namespace)[0] else: @@ -97,7 +100,7 @@ def create_AD_group(self, group_item, asJob=False): url = self.baseurl + asJobparameter create_req = RequestFactory.Group.create_ad_req(group_item) server_response = self.post_request(url, create_req) - if (asJob): + if asJob: return JobItem.from_response(server_response.content, self.parent_srv.namespace)[0] else: return GroupItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -113,7 +116,7 @@ def remove_user(self, group_item, user_id): raise ValueError(error) url = "{0}/{1}/users/{2}".format(self.baseurl, group_item.id, user_id) self.delete_request(url) - logger.info('Removed user (id: {0}) from group (ID: {1})'.format(user_id, group_item.id)) + logger.info("Removed user (id: {0}) from group (ID: {1})".format(user_id, group_item.id)) # Adds 1 user to 1 group @api(version="2.0") @@ -128,5 +131,5 @@ def add_user(self, group_item, user_id): add_req = RequestFactory.Group.add_user_req(user_id) server_response = self.post_request(url, add_req) user = UserItem.from_response(server_response.content, self.parent_srv.namespace).pop() - logger.info('Added user (id: {0}) to group (ID: {1})'.format(user_id, group_item.id)) + logger.info("Added user (id: {0}) to group (ID: {1})".format(user_id, group_item.id)) return user diff --git a/tableauserverclient/server/endpoint/jobs_endpoint.py b/tableauserverclient/server/endpoint/jobs_endpoint.py index d8bbe39c7..6079ca788 100644 --- a/tableauserverclient/server/endpoint/jobs_endpoint.py +++ b/tableauserverclient/server/endpoint/jobs_endpoint.py @@ -10,7 +10,7 @@ # In case we are in python 3 the string check is different basestring = str -logger = logging.getLogger('tableau.endpoint.jobs') +logger = logging.getLogger("tableau.endpoint.jobs") class Jobs(Endpoint): @@ -18,31 +18,32 @@ class Jobs(Endpoint): def baseurl(self): return "{0}/sites/{1}/jobs".format(self.parent_srv.baseurl, self.parent_srv.site_id) - @api(version='2.6') + @api(version="2.6") def get(self, job_id=None, req_options=None): # Backwards Compatibility fix until we rev the major version if job_id is not None and isinstance(job_id, basestring): import warnings + warnings.warn("Jobs.get(job_id) is deprecated, update code to use Jobs.get_by_id(job_id)") return self.get_by_id(job_id) if isinstance(job_id, RequestOptionsBase): req_options = job_id - self.parent_srv.assert_at_least_version('3.1') + self.parent_srv.assert_at_least_version("3.1") server_response = self.get_request(self.baseurl, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) jobs = BackgroundJobItem.from_response(server_response.content, self.parent_srv.namespace) return jobs, pagination_item - @api(version='3.1') + @api(version="3.1") def cancel(self, job_id): - id_ = getattr(job_id, 'id', job_id) - url = '{0}/{1}'.format(self.baseurl, id_) + id_ = getattr(job_id, "id", job_id) + url = "{0}/{1}".format(self.baseurl, id_) return self.put_request(url) - @api(version='2.6') + @api(version="2.6") def get_by_id(self, job_id): - logger.info('Query for information about job ' + job_id) + logger.info("Query for information about job " + job_id) url = "{0}/{1}".format(self.baseurl, job_id) server_response = self.get_request(url) new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0] diff --git a/tableauserverclient/server/endpoint/metadata_endpoint.py b/tableauserverclient/server/endpoint/metadata_endpoint.py index ac111d6ef..368a92a97 100644 --- a/tableauserverclient/server/endpoint/metadata_endpoint.py +++ b/tableauserverclient/server/endpoint/metadata_endpoint.py @@ -4,7 +4,7 @@ import json -logger = logging.getLogger('tableau.endpoint.metadata') +logger = logging.getLogger("tableau.endpoint.metadata") def is_valid_paged_query(parsed_query): @@ -12,9 +12,11 @@ def is_valid_paged_query(parsed_query): Also check that we are asking for the pageInfo object, so we get the endCursor. There is no way to do this relilably without writing a GraphQL parser, so simply check that that the string contains 'hasNextPage' and 'endCursor'""" - return all(k in parsed_query['variables'] for k in ('first', 'afterToken')) and \ - 'hasNextPage' in parsed_query['query'] and \ - 'endCursor' in parsed_query['query'] + return ( + all(k in parsed_query["variables"] for k in ("first", "afterToken")) + and "hasNextPage" in parsed_query["query"] + and "endCursor" in parsed_query["query"] + ) def extract_values(obj, key): @@ -40,8 +42,8 @@ def extract(obj, arr, key): def get_page_info(result): - next_page = extract_values(result, 'hasNextPage').pop() - cursor = extract_values(result, 'endCursor').pop() + next_page = extract_values(result, "hasNextPage").pop() + cursor = extract_values(result, "endCursor").pop() return next_page, cursor @@ -56,20 +58,20 @@ def control_baseurl(self): @api("3.5") def query(self, query, variables=None, abort_on_error=False): - logger.info('Querying Metadata API') + logger.info("Querying Metadata API") url = self.baseurl try: - graphql_query = json.dumps({'query': query, 'variables': variables}) + graphql_query = json.dumps({"query": query, "variables": variables}) except Exception as e: - raise InvalidGraphQLQuery('Must provide a string') + raise InvalidGraphQLQuery("Must provide a string") # Setting content type because post_reuqest defaults to text/xml - server_response = self.post_request(url, graphql_query, content_type='text/json') + server_response = self.post_request(url, graphql_query, content_type="text/json") results = server_response.json() - if abort_on_error and results.get('errors', None): - raise GraphQLError(results['errors']) + if abort_on_error and results.get("errors", None): + raise GraphQLError(results["errors"]) return results @@ -87,32 +89,34 @@ def eventing_status(self): @api("3.5") def paginated_query(self, query, variables=None, abort_on_error=False): - logger.info('Querying Metadata API using a Paged Query') + logger.info("Querying Metadata API using a Paged Query") url = self.baseurl if variables is None: # default paramaters - variables = {'first': 100, 'afterToken': None} - elif (('first' in variables) and ('afterToken' not in variables)): + variables = {"first": 100, "afterToken": None} + elif ("first" in variables) and ("afterToken" not in variables): # they passed a page size but not a token, probably because they're starting at `null` token - variables.update({'afterToken': None}) + variables.update({"afterToken": None}) - graphql_query = json.dumps({'query': query, 'variables': variables}) + graphql_query = json.dumps({"query": query, "variables": variables}) parsed_query = json.loads(graphql_query) if not is_valid_paged_query(parsed_query): - raise InvalidGraphQLQuery('Paged queries must have a `$first` and `$afterToken` variables as well as ' - 'a pageInfo object with `endCursor` and `hasNextPage`') + raise InvalidGraphQLQuery( + "Paged queries must have a `$first` and `$afterToken` variables as well as " + "a pageInfo object with `endCursor` and `hasNextPage`" + ) - results_dict = {'pages': []} - paginated_results = results_dict['pages'] + results_dict = {"pages": []} + paginated_results = results_dict["pages"] # get first page - server_response = self.post_request(url, graphql_query, content_type='text/json') + server_response = self.post_request(url, graphql_query, content_type="text/json") results = server_response.json() - if abort_on_error and results.get('errors', None): - raise GraphQLError(results['errors']) + if abort_on_error and results.get("errors", None): + raise GraphQLError(results["errors"]) paginated_results.append(results) @@ -121,18 +125,18 @@ def paginated_query(self, query, variables=None, abort_on_error=False): while has_another_page: # Update the page - variables.update({'afterToken': cursor}) + variables.update({"afterToken": cursor}) # make the call logger.debug("Calling Token: " + cursor) - graphql_query = json.dumps({'query': query, 'variables': variables}) - server_response = self.post_request(url, graphql_query, content_type='text/json') + graphql_query = json.dumps({"query": query, "variables": variables}) + server_response = self.post_request(url, graphql_query, content_type="text/json") results = server_response.json() # verify response - if abort_on_error and results.get('errors', None): - raise GraphQLError(results['errors']) + if abort_on_error and results.get("errors", None): + raise GraphQLError(results["errors"]) # save results and repeat paginated_results.append(results) has_another_page, cursor = get_page_info(results) - logger.info('Sucessfully got all results for paged query') + logger.info("Sucessfully got all results for paged query") return results_dict diff --git a/tableauserverclient/server/endpoint/permissions_endpoint.py b/tableauserverclient/server/endpoint/permissions_endpoint.py index 585fd0052..0992f5ca9 100644 --- a/tableauserverclient/server/endpoint/permissions_endpoint.py +++ b/tableauserverclient/server/endpoint/permissions_endpoint.py @@ -10,7 +10,7 @@ class _PermissionsEndpoint(Endpoint): - """ Adds permission model to another endpoint + """Adds permission model to another endpoint Tableau permissions model is identical between objects but they are nested under the parent object endpoint (i.e. permissions for workbooks are under @@ -27,12 +27,11 @@ def __init__(self, parent_srv, owner_baseurl): self.owner_baseurl = owner_baseurl def update(self, resource, permissions): - url = '{0}/{1}/permissions'.format(self.owner_baseurl(), resource.id) + url = "{0}/{1}/permissions".format(self.owner_baseurl(), resource.id) update_req = RequestFactory.Permission.add_req(permissions) response = self.put_request(url, update_req) - permissions = PermissionsRule.from_response(response.content, - self.parent_srv.namespace) - logger.info('Updated permissions for resource {0}'.format(resource.id)) + permissions = PermissionsRule.from_response(response.content, self.parent_srv.namespace) + logger.info("Updated permissions for resource {0}".format(resource.id)) return permissions @@ -46,23 +45,17 @@ def delete(self, resource, rules): for rule in rules: for capability, mode in rule.capabilities.items(): " /permissions/groups/group-id/capability-name/capability-mode" - url = '{0}/{1}/permissions/{2}/{3}/{4}/{5}'.format( - self.owner_baseurl(), - resource.id, - rule.grantee.tag_name + 's', - rule.grantee.id, - capability, - mode) + url = "{0}/{1}/permissions/{2}/{3}/{4}/{5}".format( + self.owner_baseurl(), resource.id, rule.grantee.tag_name + "s", rule.grantee.id, capability, mode + ) - logger.debug('Removing {0} permission for capabilty {1}'.format( - mode, capability)) + logger.debug("Removing {0} permission for capabilty {1}".format(mode, capability)) self.delete_request(url) - logger.info('Deleted permission for {0} {1} item {2}'.format( - rule.grantee.tag_name, - rule.grantee.id, - resource.id)) + logger.info( + "Deleted permission for {0} {1} item {2}".format(rule.grantee.tag_name, rule.grantee.id, resource.id) + ) def populate(self, item): if not item.id: @@ -73,12 +66,11 @@ def permission_fetcher(): return self._get_permissions(item) item._set_permissions(permission_fetcher) - logger.info('Populated permissions for item (ID: {0})'.format(item.id)) + logger.info("Populated permissions for item (ID: {0})".format(item.id)) def _get_permissions(self, item, req_options=None): url = "{0}/{1}/permissions".format(self.owner_baseurl(), item.id) server_response = self.get_request(url, req_options) - permissions = PermissionsRule.from_response(server_response.content, - self.parent_srv.namespace) + permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace) return permissions diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index 170425eab..72286e570 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -7,7 +7,7 @@ import logging -logger = logging.getLogger('tableau.endpoint.projects') +logger = logging.getLogger("tableau.endpoint.projects") class Projects(Endpoint): @@ -23,7 +23,7 @@ def baseurl(self): @api(version="2.0") def get(self, req_options=None): - logger.info('Querying all projects on site') + logger.info("Querying all projects on site") url = self.baseurl server_response = self.get_request(url, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) @@ -37,7 +37,7 @@ def delete(self, project_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, project_id) self.delete_request(url) - logger.info('Deleted single project (ID: {0})'.format(project_id)) + logger.info("Deleted single project (ID: {0})".format(project_id)) @api(version="2.0") def update(self, project_item): @@ -48,7 +48,7 @@ def update(self, project_item): url = "{0}/{1}".format(self.baseurl, project_item.id) update_req = RequestFactory.Project.update_req(project_item) server_response = self.put_request(url, update_req) - logger.info('Updated project item (ID: {0})'.format(project_item.id)) + logger.info("Updated project item (ID: {0})".format(project_item.id)) updated_project = ProjectItem.from_response(server_response.content, self.parent_srv.namespace)[0] return updated_project @@ -58,61 +58,64 @@ def create(self, project_item): create_req = RequestFactory.Project.create_req(project_item) server_response = self.post_request(url, create_req) new_project = ProjectItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Created new project (ID: {0})'.format(new_project.id)) + logger.info("Created new project (ID: {0})".format(new_project.id)) return new_project - @api(version='2.0') + @api(version="2.0") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='2.0') + @api(version="2.0") def update_permission(self, item, rules): import warnings - warnings.warn('Server.projects.update_permission is deprecated, ' - 'please use Server.projects.update_permissions instead.', - DeprecationWarning) + + warnings.warn( + "Server.projects.update_permission is deprecated, " + "please use Server.projects.update_permissions instead.", + DeprecationWarning, + ) return self._permissions.update(item, rules) - @api(version='2.0') + @api(version="2.0") def update_permissions(self, item, rules): return self._permissions.update(item, rules) - @api(version='2.0') + @api(version="2.0") def delete_permission(self, item, rules): self._permissions.delete(item, rules) - @api(version='2.1') + @api(version="2.1") def populate_workbook_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Workbook) - @api(version='2.1') + @api(version="2.1") def populate_datasource_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Datasource) - @api(version='3.4') + @api(version="3.4") def populate_flow_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Flow) - @api(version='2.1') + @api(version="2.1") def update_workbook_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Workbook) - @api(version='2.1') + @api(version="2.1") def update_datasource_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Datasource) - @api(version='3.4') + @api(version="3.4") def update_flow_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Flow) - @api(version='2.1') + @api(version="2.1") def delete_workbook_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Workbook) - @api(version='2.1') + @api(version="2.1") def delete_datasource_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Datasource) - @api(version='3.4') + @api(version="3.4") def delete_flow_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Flow) diff --git a/tableauserverclient/server/endpoint/resource_tagger.py b/tableauserverclient/server/endpoint/resource_tagger.py index ccee9fa10..a38c66ebe 100644 --- a/tableauserverclient/server/endpoint/resource_tagger.py +++ b/tableauserverclient/server/endpoint/resource_tagger.py @@ -6,7 +6,7 @@ import copy import urllib.parse -logger = logging.getLogger('tableau.endpoint.resource_tagger') +logger = logging.getLogger("tableau.endpoint.resource_tagger") class _ResourceTagger(Endpoint): @@ -47,4 +47,4 @@ def update_tags(self, baseurl, resource_item): if add_set: resource_item.tags = self._add_tags(baseurl, resource_item.id, add_set) resource_item._initial_tags = copy.copy(resource_item.tags) - logger.info('Updated tags to {0}'.format(resource_item.tags)) + logger.info("Updated tags to {0}".format(resource_item.tags)) diff --git a/tableauserverclient/server/endpoint/schedules_endpoint.py b/tableauserverclient/server/endpoint/schedules_endpoint.py index 3fd164b49..3a5e665fa 100644 --- a/tableauserverclient/server/endpoint/schedules_endpoint.py +++ b/tableauserverclient/server/endpoint/schedules_endpoint.py @@ -5,9 +5,9 @@ import copy from collections import namedtuple -logger = logging.getLogger('tableau.endpoint.schedules') +logger = logging.getLogger("tableau.endpoint.schedules") # Oh to have a first class Result concept in Python... -AddResponse = namedtuple('AddResponse', ('result', 'error', 'warnings', 'task_created')) +AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created")) OK = AddResponse(result=True, error=None, warnings=None, task_created=None) @@ -65,8 +65,7 @@ def create(self, schedule_item): return new_schedule @api(version="2.8") - def add_to_schedule(self, schedule_id, workbook=None, datasource=None, - task_type=TaskItem.Type.ExtractRefresh): + def add_to_schedule(self, schedule_id, workbook=None, datasource=None, task_type=TaskItem.Type.ExtractRefresh): def add_to(resource, type_, req_factory): id_ = resource.id url = "{0}/{1}/{2}s".format(self.siteurl, schedule_id, type_) @@ -74,7 +73,8 @@ def add_to(resource, type_, req_factory): response = self.put_request(url, add_req) error, warnings, task_created = ScheduleItem.parse_add_to_schedule_response( - response, self.parent_srv.namespace) + response, self.parent_srv.namespace + ) if task_created: logger.info("Added {} to {} to schedule {}".format(type_, id_, schedule_id)) diff --git a/tableauserverclient/server/endpoint/server_info_endpoint.py b/tableauserverclient/server/endpoint/server_info_endpoint.py index 0a6b9ec89..98d996b52 100644 --- a/tableauserverclient/server/endpoint/server_info_endpoint.py +++ b/tableauserverclient/server/endpoint/server_info_endpoint.py @@ -3,7 +3,7 @@ from ...models import ServerInfoItem import logging -logger = logging.getLogger('tableau.endpoint.server_info') +logger = logging.getLogger("tableau.endpoint.server_info") class ServerInfo(Endpoint): diff --git a/tableauserverclient/server/endpoint/sites_endpoint.py b/tableauserverclient/server/endpoint/sites_endpoint.py index c57cb3d4f..9446a01a8 100644 --- a/tableauserverclient/server/endpoint/sites_endpoint.py +++ b/tableauserverclient/server/endpoint/sites_endpoint.py @@ -5,7 +5,7 @@ import copy import logging -logger = logging.getLogger('tableau.endpoint.sites') +logger = logging.getLogger("tableau.endpoint.sites") class Sites(Endpoint): @@ -16,7 +16,7 @@ def baseurl(self): # Gets all sites @api(version="2.0") def get(self, req_options=None): - logger.info('Querying all sites on site') + logger.info("Querying all sites on site") url = self.baseurl server_response = self.get_request(url, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) @@ -29,7 +29,7 @@ def get_by_id(self, site_id): if not site_id: error = "Site ID undefined." raise ValueError(error) - logger.info('Querying single site (ID: {0})'.format(site_id)) + logger.info("Querying single site (ID: {0})".format(site_id)) url = "{0}/{1}".format(self.baseurl, site_id) server_response = self.get_request(url) return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -40,7 +40,7 @@ def get_by_name(self, site_name): if not site_name: error = "Site Name undefined." raise ValueError(error) - logger.info('Querying single site (Name: {0})'.format(site_name)) + logger.info("Querying single site (Name: {0})".format(site_name)) url = "{0}/{1}?key=name".format(self.baseurl, site_name) server_response = self.get_request(url) return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -51,7 +51,7 @@ def get_by_content_url(self, content_url): if content_url is None: error = "Content URL undefined." raise ValueError(error) - logger.info('Querying single site (Content URL: {0})'.format(content_url)) + logger.info("Querying single site (Content URL: {0})".format(content_url)) url = "{0}/{1}?key=contentUrl".format(self.baseurl, content_url) server_response = self.get_request(url) return SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -64,13 +64,13 @@ def update(self, site_item): raise MissingRequiredFieldError(error) if site_item.admin_mode: if site_item.admin_mode == SiteItem.AdminMode.ContentOnly and site_item.user_quota: - error = 'You cannot set admin_mode to ContentOnly and also set a user quota' + error = "You cannot set admin_mode to ContentOnly and also set a user quota" raise ValueError(error) url = "{0}/{1}".format(self.baseurl, site_item.id) update_req = RequestFactory.Site.update_req(site_item) server_response = self.put_request(url, update_req) - logger.info('Updated site item (ID: {0})'.format(site_item.id)) + logger.info("Updated site item (ID: {0})".format(site_item.id)) update_site = copy.copy(site_item) return update_site._parse_common_tags(server_response.content, self.parent_srv.namespace) @@ -85,23 +85,23 @@ def delete(self, site_id): # If we deleted the site we are logged into # then we are automatically logged out if site_id == self.parent_srv.site_id: - logger.info('Deleting current site and clearing auth tokens') + logger.info("Deleting current site and clearing auth tokens") self.parent_srv._clear_auth() - logger.info('Deleted single site (ID: {0}) and signed out'.format(site_id)) + logger.info("Deleted single site (ID: {0}) and signed out".format(site_id)) # Create new site @api(version="2.0") def create(self, site_item): if site_item.admin_mode: if site_item.admin_mode == SiteItem.AdminMode.ContentOnly and site_item.user_quota: - error = 'You cannot set admin_mode to ContentOnly and also set a user quota' + error = "You cannot set admin_mode to ContentOnly and also set a user quota" raise ValueError(error) url = self.baseurl create_req = RequestFactory.Site.create_req(site_item) server_response = self.post_request(url, create_req) new_site = SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Created new site (ID: {0})'.format(new_site.id)) + logger.info("Created new site (ID: {0})".format(new_site.id)) return new_site @api(version="3.5") diff --git a/tableauserverclient/server/endpoint/subscriptions_endpoint.py b/tableauserverclient/server/endpoint/subscriptions_endpoint.py index 120a2a17b..1a66e8ac5 100644 --- a/tableauserverclient/server/endpoint/subscriptions_endpoint.py +++ b/tableauserverclient/server/endpoint/subscriptions_endpoint.py @@ -4,18 +4,17 @@ import logging -logger = logging.getLogger('tableau.endpoint.subscriptions') +logger = logging.getLogger("tableau.endpoint.subscriptions") class Subscriptions(Endpoint): @property def baseurl(self): - return "{0}/sites/{1}/subscriptions".format(self.parent_srv.baseurl, - self.parent_srv.site_id) + return "{0}/sites/{1}/subscriptions".format(self.parent_srv.baseurl, self.parent_srv.site_id) - @api(version='2.3') + @api(version="2.3") def get(self, req_options=None): - logger.info('Querying all subscriptions for the site') + logger.info("Querying all subscriptions for the site") url = self.baseurl server_response = self.get_request(url, req_options) @@ -23,7 +22,7 @@ def get(self, req_options=None): all_subscriptions = SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace) return all_subscriptions, pagination_item - @api(version='2.3') + @api(version="2.3") def get_by_id(self, subscription_id): if not subscription_id: error = "No Subscription ID provided" @@ -33,7 +32,7 @@ def get_by_id(self, subscription_id): server_response = self.get_request(url) return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0] - @api(version='2.3') + @api(version="2.3") def create(self, subscription_item): if not subscription_item: error = "No Susbcription provided" @@ -44,16 +43,16 @@ def create(self, subscription_item): server_response = self.post_request(url, create_req) return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0] - @api(version='2.3') + @api(version="2.3") def delete(self, subscription_id): if not subscription_id: error = "Subscription ID undefined." raise ValueError(error) url = "{0}/{1}".format(self.baseurl, subscription_id) self.delete_request(url) - logger.info('Deleted subscription (ID: {0})'.format(subscription_id)) + logger.info("Deleted subscription (ID: {0})".format(subscription_id)) - @api(version='2.3') + @api(version="2.3") def update(self, subscription_item): if not subscription_item.id: error = "Subscription item missing ID. Subscription must be retrieved from server first." @@ -61,5 +60,5 @@ def update(self, subscription_item): url = "{0}/{1}".format(self.baseurl, subscription_item.id) update_req = RequestFactory.Subscription.update_req(subscription_item) server_response = self.put_request(url, update_req) - logger.info('Updated subscription item (ID: {0})'.format(subscription_item.id)) + logger.info("Updated subscription item (ID: {0})".format(subscription_item.id)) return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0] diff --git a/tableauserverclient/server/endpoint/tables_endpoint.py b/tableauserverclient/server/endpoint/tables_endpoint.py index 3a5c2f3f4..e35535d19 100644 --- a/tableauserverclient/server/endpoint/tables_endpoint.py +++ b/tableauserverclient/server/endpoint/tables_endpoint.py @@ -7,7 +7,7 @@ import logging -logger = logging.getLogger('tableau.endpoint.tables') +logger = logging.getLogger("tableau.endpoint.tables") class Tables(Endpoint): @@ -22,7 +22,7 @@ def baseurl(self): @api(version="3.5") def get(self, req_options=None): - logger.info('Querying all tables on site') + logger.info("Querying all tables on site") url = self.baseurl server_response = self.get_request(url, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) @@ -35,7 +35,7 @@ def get_by_id(self, table_id): if not table_id: error = "table ID undefined." raise ValueError(error) - logger.info('Querying single table (ID: {0})'.format(table_id)) + logger.info("Querying single table (ID: {0})".format(table_id)) url = "{0}/{1}".format(self.baseurl, table_id) server_response = self.get_request(url) return TableItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -47,7 +47,7 @@ def delete(self, table_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, table_id) self.delete_request(url) - logger.info('Deleted single table (ID: {0})'.format(table_id)) + logger.info("Deleted single table (ID: {0})".format(table_id)) @api(version="3.5") def update(self, table_item): @@ -58,7 +58,7 @@ def update(self, table_item): url = "{0}/{1}".format(self.baseurl, table_item.id) update_req = RequestFactory.Table.update_req(table_item) server_response = self.put_request(url, update_req) - logger.info('Updated table item (ID: {0})'.format(table_item.id)) + logger.info("Updated table item (ID: {0})".format(table_item.id)) updated_table = TableItem.from_response(server_response.content, self.parent_srv.namespace)[0] return updated_table @@ -73,13 +73,12 @@ def column_fetcher(): return Pager(lambda options: self._get_columns_for_table(table_item, options), req_options) table_item._set_columns(column_fetcher) - logger.info('Populated columns for table (ID: {0}'.format(table_item.id)) + logger.info("Populated columns for table (ID: {0}".format(table_item.id)) def _get_columns_for_table(self, table_item, req_options=None): url = "{0}/{1}/columns".format(self.baseurl, table_item.id) server_response = self.get_request(url, req_options) - columns = ColumnItem.from_response(server_response.content, - self.parent_srv.namespace) + columns = ColumnItem.from_response(server_response.content, self.parent_srv.namespace) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) return columns, pagination_item @@ -90,26 +89,27 @@ def update_column(self, table_item, column_item): server_response = self.put_request(url, update_req) column = ColumnItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Updated table item (ID: {0} & column item {1}'.format(table_item.id, - column_item.id)) + logger.info("Updated table item (ID: {0} & column item {1}".format(table_item.id, column_item.id)) return column - @api(version='3.5') + @api(version="3.5") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='3.5') + @api(version="3.5") def update_permission(self, item, rules): import warnings - warnings.warn('Server.tables.update_permission is deprecated, ' - 'please use Server.tables.update_permissions instead.', - DeprecationWarning) + + warnings.warn( + "Server.tables.update_permission is deprecated, " "please use Server.tables.update_permissions instead.", + DeprecationWarning, + ) return self._permissions.update(item, rules) - @api(version='3.5') + @api(version="3.5") def update_permissions(self, item, rules): return self._permissions.update(item, rules) - @api(version='3.5') + @api(version="3.5") def delete_permission(self, item, rules): return self._permissions.delete(item, rules) diff --git a/tableauserverclient/server/endpoint/tasks_endpoint.py b/tableauserverclient/server/endpoint/tasks_endpoint.py index a3e5e7b34..abc249721 100644 --- a/tableauserverclient/server/endpoint/tasks_endpoint.py +++ b/tableauserverclient/server/endpoint/tasks_endpoint.py @@ -4,61 +4,57 @@ import logging -logger = logging.getLogger('tableau.endpoint.tasks') +logger = logging.getLogger("tableau.endpoint.tasks") class Tasks(Endpoint): @property def baseurl(self): - return "{0}/sites/{1}/tasks".format(self.parent_srv.baseurl, - self.parent_srv.site_id) + return "{0}/sites/{1}/tasks".format(self.parent_srv.baseurl, self.parent_srv.site_id) def __normalize_task_type(self, task_type): """ - The word for extract refresh used in API URL is "extractRefreshes". - It is different than the tag "extractRefresh" used in the request body. + The word for extract refresh used in API URL is "extractRefreshes". + It is different than the tag "extractRefresh" used in the request body. """ if task_type == TaskItem.Type.ExtractRefresh: - return '{}es'.format(task_type) + return "{}es".format(task_type) else: return task_type - @api(version='2.6') + @api(version="2.6") def get(self, req_options=None, task_type=TaskItem.Type.ExtractRefresh): if task_type == TaskItem.Type.DataAcceleration: self.parent_srv.assert_at_least_version("3.8") - logger.info('Querying all {} tasks for the site'.format(task_type)) + logger.info("Querying all {} tasks for the site".format(task_type)) url = "{0}/{1}".format(self.baseurl, self.__normalize_task_type(task_type)) server_response = self.get_request(url, req_options) - pagination_item = PaginationItem.from_response(server_response.content, - self.parent_srv.namespace) - all_tasks = TaskItem.from_response(server_response.content, - self.parent_srv.namespace, - task_type) + pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) + all_tasks = TaskItem.from_response(server_response.content, self.parent_srv.namespace, task_type) return all_tasks, pagination_item - @api(version='2.6') + @api(version="2.6") def get_by_id(self, task_id): if not task_id: error = "No Task ID provided" raise ValueError(error) logger.info("Querying a single task by id ({})".format(task_id)) - url = "{}/{}/{}".format(self.baseurl, - self.__normalize_task_type(TaskItem.Type.ExtractRefresh), task_id) + url = "{}/{}/{}".format(self.baseurl, self.__normalize_task_type(TaskItem.Type.ExtractRefresh), task_id) server_response = self.get_request(url) return TaskItem.from_response(server_response.content, self.parent_srv.namespace)[0] - @api(version='2.6') + @api(version="2.6") def run(self, task_item): if not task_item.id: error = "User item missing ID." raise MissingRequiredFieldError(error) - url = "{0}/{1}/{2}/runNow".format(self.baseurl, - self.__normalize_task_type(TaskItem.Type.ExtractRefresh), task_item.id) + url = "{0}/{1}/{2}/runNow".format( + self.baseurl, self.__normalize_task_type(TaskItem.Type.ExtractRefresh), task_item.id + ) run_req = RequestFactory.Task.run_req(task_item) server_response = self.post_request(url, run_req) return server_response.content @@ -72,7 +68,6 @@ def delete(self, task_id, task_type=TaskItem.Type.ExtractRefresh): if not task_id: error = "No Task ID provided" raise ValueError(error) - url = "{0}/{1}/{2}".format(self.baseurl, - self.__normalize_task_type(task_type), task_id) + url = "{0}/{1}/{2}".format(self.baseurl, self.__normalize_task_type(task_type), task_id) self.delete_request(url) - logger.info('Deleted single task (ID: {0})'.format(task_id)) + logger.info("Deleted single task (ID: {0})".format(task_id)) diff --git a/tableauserverclient/server/endpoint/users_endpoint.py b/tableauserverclient/server/endpoint/users_endpoint.py index 17e12a8b1..3318e6bb3 100644 --- a/tableauserverclient/server/endpoint/users_endpoint.py +++ b/tableauserverclient/server/endpoint/users_endpoint.py @@ -6,7 +6,7 @@ import copy import logging -logger = logging.getLogger('tableau.endpoint.users') +logger = logging.getLogger("tableau.endpoint.users") class Users(QuerysetEndpoint): @@ -17,7 +17,7 @@ def baseurl(self): # Gets all users @api(version="2.0") def get(self, req_options=None): - logger.info('Querying all users on site') + logger.info("Querying all users on site") if req_options is None: req_options = RequestOptions() @@ -35,7 +35,7 @@ def get_by_id(self, user_id): if not user_id: error = "User ID undefined." raise ValueError(error) - logger.info('Querying single user (ID: {0})'.format(user_id)) + logger.info("Querying single user (ID: {0})".format(user_id)) url = "{0}/{1}".format(self.baseurl, user_id) server_response = self.get_request(url) return UserItem.from_response(server_response.content, self.parent_srv.namespace).pop() @@ -50,7 +50,7 @@ def update(self, user_item, password=None): url = "{0}/{1}".format(self.baseurl, user_item.id) update_req = RequestFactory.User.update_req(user_item, password) server_response = self.put_request(url, update_req) - logger.info('Updated user item (ID: {0})'.format(user_item.id)) + logger.info("Updated user item (ID: {0})".format(user_item.id)) updated_item = copy.copy(user_item) return updated_item._parse_common_tags(server_response.content, self.parent_srv.namespace) @@ -62,7 +62,7 @@ def remove(self, user_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, user_id) self.delete_request(url) - logger.info('Removed single user (ID: {0})'.format(user_id)) + logger.info("Removed single user (ID: {0})".format(user_id)) # Add new user to site @api(version="2.0") @@ -71,7 +71,7 @@ def add(self, user_item): add_req = RequestFactory.User.add_req(user_item) server_response = self.post_request(url, add_req) new_user = UserItem.from_response(server_response.content, self.parent_srv.namespace).pop() - logger.info('Added new user (ID: {0})'.format(new_user.id)) + logger.info("Added new user (ID: {0})".format(new_user.id)) return new_user # Get workbooks for user @@ -89,7 +89,7 @@ def wb_pager(): def _get_wbs_for_user(self, user_item, req_options=None): url = "{0}/{1}/workbooks".format(self.baseurl, user_item.id) server_response = self.get_request(url, req_options) - logger.info('Populated workbooks for user (ID: {0})'.format(user_item.id)) + logger.info("Populated workbooks for user (ID: {0})".format(user_item.id)) workbook_item = WorkbookItem.from_response(server_response.content, self.parent_srv.namespace) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) return workbook_item, pagination_item @@ -112,7 +112,7 @@ def groups_for_user_pager(): def _get_groups_for_user(self, user_item, req_options=None): url = "{0}/{1}/groups".format(self.baseurl, user_item.id) server_response = self.get_request(url, req_options) - logger.info('Populated groups for user (ID: {0})'.format(user_item.id)) + logger.info("Populated groups for user (ID: {0})".format(user_item.id)) group_item = GroupItem.from_response(server_response.content, self.parent_srv.namespace) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) return group_item, pagination_item diff --git a/tableauserverclient/server/endpoint/views_endpoint.py b/tableauserverclient/server/endpoint/views_endpoint.py index 8c848c295..a00e7f145 100644 --- a/tableauserverclient/server/endpoint/views_endpoint.py +++ b/tableauserverclient/server/endpoint/views_endpoint.py @@ -7,7 +7,7 @@ from contextlib import closing import logging -logger = logging.getLogger('tableau.endpoint.views') +logger = logging.getLogger("tableau.endpoint.views") class Views(QuerysetEndpoint): @@ -27,7 +27,7 @@ def baseurl(self): @api(version="2.2") def get(self, req_options=None, usage=False): - logger.info('Querying all views on site') + logger.info("Querying all views on site") url = self.baseurl if usage: url += "?includeUsageStatistics=true" @@ -41,7 +41,7 @@ def get_by_id(self, view_id): if not view_id: error = "View item missing ID." raise MissingRequiredFieldError(error) - logger.info('Querying single view (ID: {0})'.format(view_id)) + logger.info("Querying single view (ID: {0})".format(view_id)) url = "{0}/{1}".format(self.baseurl, view_id) server_response = self.get_request(url) return ViewItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -56,12 +56,10 @@ def image_fetcher(): return self._get_preview_for_view(view_item) view_item._set_preview_image(image_fetcher) - logger.info('Populated preview image for view (ID: {0})'.format(view_item.id)) + logger.info("Populated preview image for view (ID: {0})".format(view_item.id)) def _get_preview_for_view(self, view_item): - url = "{0}/workbooks/{1}/views/{2}/previewImage".format(self.siteurl, - view_item.workbook_id, - view_item.id) + url = "{0}/workbooks/{1}/views/{2}/previewImage".format(self.siteurl, view_item.workbook_id, view_item.id) server_response = self.get_request(url) image = server_response.content return image @@ -121,15 +119,15 @@ def _get_view_csv(self, view_item, req_options): csv = server_response.iter_content(1024) return csv - @api(version='3.2') + @api(version="3.2") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='3.2') + @api(version="3.2") def update_permissions(self, resource, rules): return self._permissions.update(resource, rules) - @api(version='3.2') + @api(version="3.2") def delete_permission(self, item, capability_item): return self._permissions.delete(item, capability_item) diff --git a/tableauserverclient/server/endpoint/webhooks_endpoint.py b/tableauserverclient/server/endpoint/webhooks_endpoint.py index fe108a27d..6f5135ac1 100644 --- a/tableauserverclient/server/endpoint/webhooks_endpoint.py +++ b/tableauserverclient/server/endpoint/webhooks_endpoint.py @@ -4,7 +4,7 @@ import logging -logger = logging.getLogger('tableau.endpoint.webhooks') +logger = logging.getLogger("tableau.endpoint.webhooks") class Webhooks(Endpoint): @@ -17,7 +17,7 @@ def baseurl(self): @api(version="3.6") def get(self, req_options=None): - logger.info('Querying all Webhooks on site') + logger.info("Querying all Webhooks on site") url = self.baseurl server_response = self.get_request(url, req_options) all_webhook_items = WebhookItem.from_response(server_response.content, self.parent_srv.namespace) @@ -29,7 +29,7 @@ def get_by_id(self, webhook_id): if not webhook_id: error = "Webhook ID undefined." raise ValueError(error) - logger.info('Querying single webhook (ID: {0})'.format(webhook_id)) + logger.info("Querying single webhook (ID: {0})".format(webhook_id)) url = "{0}/{1}".format(self.baseurl, webhook_id) server_response = self.get_request(url) return WebhookItem.from_response(server_response.content, self.parent_srv.namespace)[0] @@ -41,7 +41,7 @@ def delete(self, webhook_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, webhook_id) self.delete_request(url) - logger.info('Deleted single webhook (ID: {0})'.format(webhook_id)) + logger.info("Deleted single webhook (ID: {0})".format(webhook_id)) @api(version="3.6") def create(self, webhook_item): @@ -50,7 +50,7 @@ def create(self, webhook_item): server_response = self.post_request(url, create_req) new_webhook = WebhookItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Created new webhook (ID: {0})'.format(new_webhook.id)) + logger.info("Created new webhook (ID: {0})".format(new_webhook.id)) return new_webhook @api(version="3.6") @@ -60,5 +60,5 @@ def test(self, webhook_id): raise ValueError(error) url = "{0}/{1}/test".format(self.baseurl, webhook_id) testOutcome = self.get_request(url) - logger.info('Testing webhook (ID: {0} returned {1})'.format(webhook_id, testOutcome)) + logger.info("Testing webhook (ID: {0} returned {1})".format(webhook_id, testOutcome)) return testOutcome diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index e40d9e1dd..aa72979dd 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -14,11 +14,11 @@ from contextlib import closing # The maximum size of a file that can be published in a single request is 64MB -FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB +FILESIZE_LIMIT = 1024 * 1024 * 64 # 64MB -ALLOWED_FILE_EXTENSIONS = ['twb', 'twbx'] +ALLOWED_FILE_EXTENSIONS = ["twb", "twbx"] -logger = logging.getLogger('tableau.endpoint.workbooks') +logger = logging.getLogger("tableau.endpoint.workbooks") class Workbooks(QuerysetEndpoint): @@ -34,13 +34,11 @@ def baseurl(self): # Get all workbooks on site @api(version="2.0") def get(self, req_options=None): - logger.info('Querying all workbooks on site') + logger.info("Querying all workbooks on site") url = self.baseurl server_response = self.get_request(url, req_options) - pagination_item = PaginationItem.from_response( - server_response.content, self.parent_srv.namespace) - all_workbook_items = WorkbookItem.from_response( - server_response.content, self.parent_srv.namespace) + pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) + all_workbook_items = WorkbookItem.from_response(server_response.content, self.parent_srv.namespace) return all_workbook_items, pagination_item # Get 1 workbook @@ -49,14 +47,14 @@ def get_by_id(self, workbook_id): if not workbook_id: error = "Workbook ID undefined." raise ValueError(error) - logger.info('Querying single workbook (ID: {0})'.format(workbook_id)) + logger.info("Querying single workbook (ID: {0})".format(workbook_id)) url = "{0}/{1}".format(self.baseurl, workbook_id) server_response = self.get_request(url) return WorkbookItem.from_response(server_response.content, self.parent_srv.namespace)[0] @api(version="2.8") def refresh(self, workbook_id): - id_ = getattr(workbook_id, 'id', workbook_id) + id_ = getattr(workbook_id, "id", workbook_id) url = "{0}/{1}/refresh".format(self.baseurl, id_) empty_req = RequestFactory.Empty.empty_req() server_response = self.post_request(url, empty_req) @@ -64,9 +62,9 @@ def refresh(self, workbook_id): return new_job # create one or more extracts on 1 workbook, optionally encrypted - @api(version='3.5') + @api(version="3.5") def create_extract(self, workbook_item, encrypt=False, includeAll=True, datasources=None): - id_ = getattr(workbook_item, 'id', workbook_item) + id_ = getattr(workbook_item, "id", workbook_item) url = "{0}/{1}/createExtract?encrypt={2}".format(self.baseurl, id_, encrypt) datasource_req = RequestFactory.Workbook.embedded_extract_req(includeAll, datasources) @@ -75,9 +73,9 @@ def create_extract(self, workbook_item, encrypt=False, includeAll=True, datasour return new_job # delete all the extracts on 1 workbook - @api(version='3.5') + @api(version="3.5") def delete_extract(self, workbook_item): - id_ = getattr(workbook_item, 'id', workbook_item) + id_ = getattr(workbook_item, "id", workbook_item) url = "{0}/{1}/deleteExtract".format(self.baseurl, id_) empty_req = RequestFactory.Empty.empty_req() server_response = self.post_request(url, empty_req) @@ -90,7 +88,7 @@ def delete(self, workbook_id): raise ValueError(error) url = "{0}/{1}".format(self.baseurl, workbook_id) self.delete_request(url) - logger.info('Deleted single workbook (ID: {0})'.format(workbook_id)) + logger.info("Deleted single workbook (ID: {0})".format(workbook_id)) # Update workbook @api(version="2.0") @@ -105,14 +103,15 @@ def update(self, workbook_item): url = "{0}/{1}".format(self.baseurl, workbook_item.id) update_req = RequestFactory.Workbook.update_req(workbook_item) server_response = self.put_request(url, update_req) - logger.info('Updated workbook item (ID: {0})'.format(workbook_item.id)) + logger.info("Updated workbook item (ID: {0})".format(workbook_item.id)) updated_workbook = copy.copy(workbook_item) return updated_workbook._parse_common_tags(server_response.content, self.parent_srv.namespace) @api(version="2.3") def update_conn(self, *args, **kwargs): import warnings - warnings.warn('update_conn is deprecated, please use update_connection instead') + + warnings.warn("update_conn is deprecated, please use update_connection instead") return self.update_connection(*args, **kwargs) # Update workbook_connection @@ -123,14 +122,15 @@ def update_connection(self, workbook_item, connection_item): server_response = self.put_request(url, update_req) connection = ConnectionItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Updated workbook item (ID: {0} & connection item {1})'.format(workbook_item.id, - connection_item.id)) + logger.info( + "Updated workbook item (ID: {0} & connection item {1})".format(workbook_item.id, connection_item.id) + ) return connection # Download workbook contents with option of passing in filepath @api(version="2.0") - @parameter_added_in(no_extract='2.5') - @parameter_added_in(include_extract='2.5') + @parameter_added_in(no_extract="2.5") + @parameter_added_in(include_extract="2.5") def download(self, workbook_id, filepath=None, include_extract=True, no_extract=None): if not workbook_id: error = "Workbook ID undefined." @@ -139,22 +139,23 @@ def download(self, workbook_id, filepath=None, include_extract=True, no_extract= if no_extract is False or no_extract is True: import warnings - warnings.warn('no_extract is deprecated, use include_extract instead.', DeprecationWarning) + + warnings.warn("no_extract is deprecated, use include_extract instead.", DeprecationWarning) include_extract = not no_extract if not include_extract: url += "?includeExtract=False" with closing(self.get_request(url, parameters={"stream": True})) as server_response: - _, params = cgi.parse_header(server_response.headers['Content-Disposition']) - filename = to_filename(os.path.basename(params['filename'])) + _, params = cgi.parse_header(server_response.headers["Content-Disposition"]) + filename = to_filename(os.path.basename(params["filename"])) download_path = make_download_path(filepath, filename) - with open(download_path, 'wb') as f: + with open(download_path, "wb") as f: for chunk in server_response.iter_content(1024): # 1KB f.write(chunk) - logger.info('Downloaded workbook to {0} (ID: {1})'.format(download_path, workbook_id)) + logger.info("Downloaded workbook to {0} (ID: {1})".format(download_path, workbook_id)) return os.path.abspath(download_path) # Get all views of workbook @@ -168,16 +169,14 @@ def view_fetcher(): return self._get_views_for_workbook(workbook_item, usage) workbook_item._set_views(view_fetcher) - logger.info('Populated views for workbook (ID: {0})'.format(workbook_item.id)) + logger.info("Populated views for workbook (ID: {0})".format(workbook_item.id)) def _get_views_for_workbook(self, workbook_item, usage): url = "{0}/{1}/views".format(self.baseurl, workbook_item.id) if usage: url += "?includeUsageStatistics=true" server_response = self.get_request(url) - views = ViewItem.from_response(server_response.content, - self.parent_srv.namespace, - workbook_id=workbook_item.id) + views = ViewItem.from_response(server_response.content, self.parent_srv.namespace, workbook_id=workbook_item.id) return views # Get all connections of workbook @@ -191,7 +190,7 @@ def connection_fetcher(): return self._get_workbook_connections(workbook_item) workbook_item._set_connections(connection_fetcher) - logger.info('Populated connections for workbook (ID: {0})'.format(workbook_item.id)) + logger.info("Populated connections for workbook (ID: {0})".format(workbook_item.id)) def _get_workbook_connections(self, workbook_item, req_options=None): url = "{0}/{1}/connections".format(self.baseurl, workbook_item.id) @@ -229,7 +228,7 @@ def image_fetcher(): return self._get_wb_preview_image(workbook_item) workbook_item._set_preview_image(image_fetcher) - logger.info('Populated preview image for workbook (ID: {0})'.format(workbook_item.id)) + logger.info("Populated preview image for workbook (ID: {0})".format(workbook_item.id)) def _get_wb_preview_image(self, workbook_item): url = "{0}/{1}/previewImage".format(self.baseurl, workbook_item.id) @@ -237,32 +236,38 @@ def _get_wb_preview_image(self, workbook_item): preview_image = server_response.content return preview_image - @api(version='2.0') + @api(version="2.0") def populate_permissions(self, item): self._permissions.populate(item) - @api(version='2.0') + @api(version="2.0") def update_permissions(self, resource, rules): return self._permissions.update(resource, rules) - @api(version='2.0') + @api(version="2.0") def delete_permission(self, item, capability_item): return self._permissions.delete(item, capability_item) # Publishes workbook. Chunking method if file over 64MB @api(version="2.0") - @parameter_added_in(as_job='3.0') - @parameter_added_in(connections='2.8') + @parameter_added_in(as_job="3.0") + @parameter_added_in(connections="2.8") def publish( - self, workbook_item, file, mode, - connection_credentials=None, connections=None, as_job=False, - hidden_views=None, skip_connection_check=False + self, + workbook_item, + file, + mode, + connection_credentials=None, + connections=None, + as_job=False, + hidden_views=None, + skip_connection_check=False, ): if connection_credentials is not None: import warnings - warnings.warn("connection_credentials is being deprecated. Use connections instead", - DeprecationWarning) + + warnings.warn("connection_credentials is being deprecated. Use connections instead", DeprecationWarning) try: # Expect file to be a filepath @@ -278,7 +283,7 @@ def publish( if not workbook_item.name: workbook_item.name = os.path.splitext(filename)[0] if file_extension not in ALLOWED_FILE_EXTENSIONS: - error = "Only {} files can be published as workbooks.".format(', '.join(ALLOWED_FILE_EXTENSIONS)) + error = "Only {} files can be published as workbooks.".format(", ".join(ALLOWED_FILE_EXTENSIONS)) raise ValueError(error) except TypeError: @@ -287,12 +292,12 @@ def publish( file_type = get_file_type(file) - if file_type == 'zip': - file_extension = 'twbx' - elif file_type == 'xml': - file_extension = 'twb' + if file_type == "zip": + file_extension = "twbx" + elif file_type == "xml": + file_extension = "twb" else: - error = 'Unsupported file type {}!'.format(file_type) + error = "Unsupported file type {}!".format(file_type) raise ValueError(error) if not workbook_item.name: @@ -304,51 +309,52 @@ def publish( filename = "{}.{}".format(workbook_item.name, file_extension) if not hasattr(self.parent_srv.PublishMode, mode): - error = 'Invalid mode defined.' + error = "Invalid mode defined." raise ValueError(error) # Construct the url with the defined mode url = "{0}?workbookType={1}".format(self.baseurl, file_extension) if mode == self.parent_srv.PublishMode.Overwrite: - url += '&{0}=true'.format(mode.lower()) + url += "&{0}=true".format(mode.lower()) elif mode == self.parent_srv.PublishMode.Append: - error = 'Workbooks cannot be appended.' + error = "Workbooks cannot be appended." raise ValueError(error) if as_job: - url += '&{0}=true'.format('asJob') + url += "&{0}=true".format("asJob") if skip_connection_check: - url += '&{0}=true'.format('skipConnectionCheck') + url += "&{0}=true".format("skipConnectionCheck") # Determine if chunking is required (64MB is the limit for single upload method) if file_size >= FILESIZE_LIMIT: - logger.info('Publishing {0} to server with chunking method (workbook over 64MB)'.format(workbook_item.name)) + logger.info("Publishing {0} to server with chunking method (workbook over 64MB)".format(workbook_item.name)) upload_session_id = Fileuploads.upload_chunks(self.parent_srv, file) url = "{0}&uploadSessionId={1}".format(url, upload_session_id) conn_creds = connection_credentials - xml_request, content_type = RequestFactory.Workbook.publish_req_chunked(workbook_item, - connection_credentials=conn_creds, - connections=connections, - hidden_views=hidden_views) + xml_request, content_type = RequestFactory.Workbook.publish_req_chunked( + workbook_item, connection_credentials=conn_creds, connections=connections, hidden_views=hidden_views + ) else: - logger.info('Publishing {0} to server'.format(filename)) + logger.info("Publishing {0} to server".format(filename)) try: - with open(file, 'rb') as f: + with open(file, "rb") as f: file_contents = f.read() except TypeError: file_contents = file.read() conn_creds = connection_credentials - xml_request, content_type = RequestFactory.Workbook.publish_req(workbook_item, - filename, - file_contents, - connection_credentials=conn_creds, - connections=connections, - hidden_views=hidden_views) - logger.debug('Request xml: {0} '.format(xml_request[:1000])) + xml_request, content_type = RequestFactory.Workbook.publish_req( + workbook_item, + filename, + file_contents, + connection_credentials=conn_creds, + connections=connections, + hidden_views=hidden_views, + ) + logger.debug("Request xml: {0} ".format(xml_request[:1000])) # Send the publishing request to server try: @@ -360,9 +366,9 @@ def publish( if as_job: new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (JOB_ID: {1}'.format(workbook_item.name, new_job.id)) + logger.info("Published {0} (JOB_ID: {1}".format(workbook_item.name, new_job.id)) return new_job else: new_workbook = WorkbookItem.from_response(server_response.content, self.parent_srv.namespace)[0] - logger.info('Published {0} (ID: {1})'.format(workbook_item.name, new_workbook.id)) + logger.info("Published {0} (ID: {1})".format(workbook_item.name, new_workbook.id)) return new_workbook diff --git a/tableauserverclient/server/filter.py b/tableauserverclient/server/filter.py index aa42a6439..8802321fd 100644 --- a/tableauserverclient/server/filter.py +++ b/tableauserverclient/server/filter.py @@ -11,8 +11,8 @@ def __init__(self, field, operator, value): def __str__(self): value_string = str(self._value) if isinstance(self._value, list): - value_string = value_string.replace(' ', '').replace('\'', '') - return '{0}:{1}:{2}'.format(self.field, self.operator, value_string) + value_string = value_string.replace(" ", "").replace("'", "") + return "{0}:{1}:{2}".format(self.field, self.operator, value_string) @property def value(self): diff --git a/tableauserverclient/server/pager.py b/tableauserverclient/server/pager.py index 0e2382fae..2de84b4d1 100644 --- a/tableauserverclient/server/pager.py +++ b/tableauserverclient/server/pager.py @@ -14,7 +14,7 @@ class Pager(object): def __init__(self, endpoint, request_opts=None, **kwargs): - if hasattr(endpoint, 'get'): + if hasattr(endpoint, "get"): # The simpliest case is to take an Endpoint and call its get endpoint = partial(endpoint.get, **kwargs) self._endpoint = endpoint @@ -30,7 +30,7 @@ def __init__(self, endpoint, request_opts=None, **kwargs): # If we have options we could be starting on any page, backfill the count if self._options: - self._count = ((self._options.pagenumber - 1) * self._options.pagesize) + self._count = (self._options.pagenumber - 1) * self._options.pagesize else: self._count = 0 self._options = RequestOptions() diff --git a/tableauserverclient/server/query.py b/tableauserverclient/server/query.py index c8ba5e6c6..3dbb830fa 100644 --- a/tableauserverclient/server/query.py +++ b/tableauserverclient/server/query.py @@ -4,11 +4,10 @@ def to_camel_case(word): - return word.split('_')[0] + ''.join(x.capitalize() or '_' for x in word.split('_')[1:]) + return word.split("_")[0] + "".join(x.capitalize() or "_" for x in word.split("_")[1:]) class QuerySet: - def __init__(self, model): self.model = model self.request_options = RequestOptions() diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index e34220188..d2e921479 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -13,13 +13,13 @@ def _add_multipart(parts): multipart_part.make_multipart(content_type=content_type) mime_multipart_parts.append(multipart_part) xml_request, content_type = encode_multipart_formdata(mime_multipart_parts) - content_type = ''.join(('multipart/mixed',) + content_type.partition(';')[1:]) + content_type = "".join(("multipart/mixed",) + content_type.partition(";")[1:]) return xml_request, content_type def _tsrequest_wrapped(func): def wrapper(self, *args, **kwargs): - xml_request = ET.Element('tsRequest') + xml_request = ET.Element("tsRequest") func(self, xml_request, *args, **kwargs) return ET.tostring(xml_request) @@ -27,182 +27,184 @@ def wrapper(self, *args, **kwargs): def _add_connections_element(connections_element, connection): - connection_element = ET.SubElement(connections_element, 'connection') - connection_element.attrib['serverAddress'] = connection.server_address + connection_element = ET.SubElement(connections_element, "connection") + connection_element.attrib["serverAddress"] = connection.server_address if connection.server_port: - connection_element.attrib['serverPort'] = connection.server_port + connection_element.attrib["serverPort"] = connection.server_port if connection.connection_credentials: connection_credentials = connection.connection_credentials _add_credentials_element(connection_element, connection_credentials) def _add_hiddenview_element(views_element, view_name): - view_element = ET.SubElement(views_element, 'view') - view_element.attrib['name'] = view_name - view_element.attrib['hidden'] = "true" + view_element = ET.SubElement(views_element, "view") + view_element.attrib["name"] = view_name + view_element.attrib["hidden"] = "true" def _add_credentials_element(parent_element, connection_credentials): - credentials_element = ET.SubElement(parent_element, 'connectionCredentials') - credentials_element.attrib['name'] = connection_credentials.name - credentials_element.attrib['password'] = connection_credentials.password - credentials_element.attrib['embed'] = 'true' if connection_credentials.embed else 'false' + credentials_element = ET.SubElement(parent_element, "connectionCredentials") + credentials_element.attrib["name"] = connection_credentials.name + credentials_element.attrib["password"] = connection_credentials.password + credentials_element.attrib["embed"] = "true" if connection_credentials.embed else "false" if connection_credentials.oauth: - credentials_element.attrib['oAuth'] = 'true' + credentials_element.attrib["oAuth"] = "true" class AuthRequest(object): def signin_req(self, auth_item): - xml_request = ET.Element('tsRequest') + xml_request = ET.Element("tsRequest") - credentials_element = ET.SubElement(xml_request, 'credentials') + credentials_element = ET.SubElement(xml_request, "credentials") for attribute_name, attribute_value in auth_item.credentials.items(): credentials_element.attrib[attribute_name] = attribute_value - site_element = ET.SubElement(credentials_element, 'site') - site_element.attrib['contentUrl'] = auth_item.site_id + site_element = ET.SubElement(credentials_element, "site") + site_element.attrib["contentUrl"] = auth_item.site_id if auth_item.user_id_to_impersonate: - user_element = ET.SubElement(credentials_element, 'user') - user_element.attrib['id'] = auth_item.user_id_to_impersonate + user_element = ET.SubElement(credentials_element, "user") + user_element.attrib["id"] = auth_item.user_id_to_impersonate return ET.tostring(xml_request) def switch_req(self, site_content_url): - xml_request = ET.Element('tsRequest') + xml_request = ET.Element("tsRequest") - site_element = ET.SubElement(xml_request, 'site') - site_element.attrib['contentUrl'] = site_content_url + site_element = ET.SubElement(xml_request, "site") + site_element.attrib["contentUrl"] = site_content_url return ET.tostring(xml_request) class ColumnRequest(object): def update_req(self, column_item): - xml_request = ET.Element('tsRequest') - column_element = ET.SubElement(xml_request, 'column') + xml_request = ET.Element("tsRequest") + column_element = ET.SubElement(xml_request, "column") if column_item.description: - column_element.attrib['description'] = str(column_item.description) + column_element.attrib["description"] = str(column_item.description) return ET.tostring(xml_request) class DataAlertRequest(object): def add_user_to_alert(self, alert_item, user_id): - xml_request = ET.Element('tsRequest') - user_element = ET.SubElement(xml_request, 'user') - user_element.attrib['id'] = user_id + xml_request = ET.Element("tsRequest") + user_element = ET.SubElement(xml_request, "user") + user_element.attrib["id"] = user_id return ET.tostring(xml_request) def update_req(self, alert_item): - xml_request = ET.Element('tsRequest') - dataAlert_element = ET.SubElement(xml_request, 'dataAlert') - dataAlert_element.attrib['subject'] = alert_item.subject - dataAlert_element.attrib['frequency'] = alert_item.frequency.lower() - dataAlert_element.attrib['public'] = alert_item.public + xml_request = ET.Element("tsRequest") + dataAlert_element = ET.SubElement(xml_request, "dataAlert") + dataAlert_element.attrib["subject"] = alert_item.subject + dataAlert_element.attrib["frequency"] = alert_item.frequency.lower() + dataAlert_element.attrib["public"] = alert_item.public - owner = ET.SubElement(dataAlert_element, 'owner') - owner.attrib['id'] = alert_item.owner_id + owner = ET.SubElement(dataAlert_element, "owner") + owner.attrib["id"] = alert_item.owner_id return ET.tostring(xml_request) class DatabaseRequest(object): def update_req(self, database_item): - xml_request = ET.Element('tsRequest') - database_element = ET.SubElement(xml_request, 'database') + xml_request = ET.Element("tsRequest") + database_element = ET.SubElement(xml_request, "database") if database_item.contact_id: - contact_element = ET.SubElement(database_element, 'contact') - contact_element.attrib['id'] = database_item.contact_id + contact_element = ET.SubElement(database_element, "contact") + contact_element.attrib["id"] = database_item.contact_id - database_element.attrib['isCertified'] = str(database_item.certified).lower() + database_element.attrib["isCertified"] = str(database_item.certified).lower() if database_item.certification_note: - database_element.attrib['certificationNote'] = str(database_item.certification_note) + database_element.attrib["certificationNote"] = str(database_item.certification_note) if database_item.description: - database_element.attrib['description'] = str(database_item.description) + database_element.attrib["description"] = str(database_item.description) return ET.tostring(xml_request) class DatasourceRequest(object): def _generate_xml(self, datasource_item, connection_credentials=None, connections=None): - xml_request = ET.Element('tsRequest') - datasource_element = ET.SubElement(xml_request, 'datasource') - datasource_element.attrib['name'] = datasource_item.name + xml_request = ET.Element("tsRequest") + datasource_element = ET.SubElement(xml_request, "datasource") + datasource_element.attrib["name"] = datasource_item.name if datasource_item.description: - datasource_element.attrib['description'] = str(datasource_item.description) + datasource_element.attrib["description"] = str(datasource_item.description) if datasource_item.use_remote_query_agent is not None: - datasource_element.attrib['useRemoteQueryAgent'] = str(datasource_item.use_remote_query_agent).lower() + datasource_element.attrib["useRemoteQueryAgent"] = str(datasource_item.use_remote_query_agent).lower() if datasource_item.ask_data_enablement: - ask_data_element = ET.SubElement(datasource_element, 'askData') - ask_data_element.attrib['enablement'] = datasource_item.ask_data_enablement + ask_data_element = ET.SubElement(datasource_element, "askData") + ask_data_element.attrib["enablement"] = datasource_item.ask_data_enablement - project_element = ET.SubElement(datasource_element, 'project') - project_element.attrib['id'] = datasource_item.project_id + project_element = ET.SubElement(datasource_element, "project") + project_element.attrib["id"] = datasource_item.project_id if connection_credentials is not None and connections is not None: - raise RuntimeError('You cannot set both `connections` and `connection_credentials`') + raise RuntimeError("You cannot set both `connections` and `connection_credentials`") if connection_credentials is not None: _add_credentials_element(datasource_element, connection_credentials) if connections is not None: - connections_element = ET.SubElement(datasource_element, 'connections') + connections_element = ET.SubElement(datasource_element, "connections") for connection in connections: _add_connections_element(connections_element, connection) return ET.tostring(xml_request) def update_req(self, datasource_item): - xml_request = ET.Element('tsRequest') - datasource_element = ET.SubElement(xml_request, 'datasource') + xml_request = ET.Element("tsRequest") + datasource_element = ET.SubElement(xml_request, "datasource") if datasource_item.ask_data_enablement: - ask_data_element = ET.SubElement(datasource_element, 'askData') - ask_data_element.attrib['enablement'] = datasource_item.ask_data_enablement + ask_data_element = ET.SubElement(datasource_element, "askData") + ask_data_element.attrib["enablement"] = datasource_item.ask_data_enablement if datasource_item.project_id: - project_element = ET.SubElement(datasource_element, 'project') - project_element.attrib['id'] = datasource_item.project_id + project_element = ET.SubElement(datasource_element, "project") + project_element.attrib["id"] = datasource_item.project_id if datasource_item.owner_id: - owner_element = ET.SubElement(datasource_element, 'owner') - owner_element.attrib['id'] = datasource_item.owner_id + owner_element = ET.SubElement(datasource_element, "owner") + owner_element.attrib["id"] = datasource_item.owner_id - datasource_element.attrib['isCertified'] = str(datasource_item.certified).lower() + datasource_element.attrib["isCertified"] = str(datasource_item.certified).lower() if datasource_item.certification_note: - datasource_element.attrib['certificationNote'] = str(datasource_item.certification_note) + datasource_element.attrib["certificationNote"] = str(datasource_item.certification_note) if datasource_item.encrypt_extracts is not None: - datasource_element.attrib['encryptExtracts'] = str(datasource_item.encrypt_extracts).lower() + datasource_element.attrib["encryptExtracts"] = str(datasource_item.encrypt_extracts).lower() return ET.tostring(xml_request) def publish_req(self, datasource_item, filename, file_contents, connection_credentials=None, connections=None): xml_request = self._generate_xml(datasource_item, connection_credentials, connections) - parts = {'request_payload': ('', xml_request, 'text/xml'), - 'tableau_datasource': (filename, file_contents, 'application/octet-stream')} + parts = { + "request_payload": ("", xml_request, "text/xml"), + "tableau_datasource": (filename, file_contents, "application/octet-stream"), + } return _add_multipart(parts) def publish_req_chunked(self, datasource_item, connection_credentials=None, connections=None): xml_request = self._generate_xml(datasource_item, connection_credentials, connections) - parts = {'request_payload': ('', xml_request, 'text/xml')} + parts = {"request_payload": ("", xml_request, "text/xml")} return _add_multipart(parts) class FavoriteRequest(object): def _add_to_req(self, id_, target_type, label): - ''' + """ - ''' - xml_request = ET.Element('tsRequest') - favorite_element = ET.SubElement(xml_request, 'favorite') + """ + xml_request = ET.Element("tsRequest") + favorite_element = ET.SubElement(xml_request, "favorite") target = ET.SubElement(favorite_element, target_type) - favorite_element.attrib['label'] = label - target.attrib['id'] = id_ + favorite_element.attrib["label"] = label + target.attrib["id"] = id_ return ET.tostring(xml_request) @@ -221,208 +223,212 @@ def add_workbook_req(self, id_, name): class FileuploadRequest(object): def chunk_req(self, chunk): - parts = {'request_payload': ('', '', 'text/xml'), - 'tableau_file': ('file', chunk, 'application/octet-stream')} + parts = {"request_payload": ("", "", "text/xml"), "tableau_file": ("file", chunk, "application/octet-stream")} return _add_multipart(parts) class FlowRequest(object): def _generate_xml(self, flow_item, connections=None): - xml_request = ET.Element('tsRequest') - flow_element = ET.SubElement(xml_request, 'flow') - flow_element.attrib['name'] = flow_item.name - project_element = ET.SubElement(flow_element, 'project') - project_element.attrib['id'] = flow_item.project_id + xml_request = ET.Element("tsRequest") + flow_element = ET.SubElement(xml_request, "flow") + flow_element.attrib["name"] = flow_item.name + project_element = ET.SubElement(flow_element, "project") + project_element.attrib["id"] = flow_item.project_id if connections is not None: - connections_element = ET.SubElement(flow_element, 'connections') + connections_element = ET.SubElement(flow_element, "connections") for connection in connections: _add_connections_element(connections_element, connection) return ET.tostring(xml_request) def update_req(self, flow_item): - xml_request = ET.Element('tsRequest') - flow_element = ET.SubElement(xml_request, 'flow') + xml_request = ET.Element("tsRequest") + flow_element = ET.SubElement(xml_request, "flow") if flow_item.project_id: - project_element = ET.SubElement(flow_element, 'project') - project_element.attrib['id'] = flow_item.project_id + project_element = ET.SubElement(flow_element, "project") + project_element.attrib["id"] = flow_item.project_id if flow_item.owner_id: - owner_element = ET.SubElement(flow_element, 'owner') - owner_element.attrib['id'] = flow_item.owner_id + owner_element = ET.SubElement(flow_element, "owner") + owner_element.attrib["id"] = flow_item.owner_id return ET.tostring(xml_request) def publish_req(self, flow_item, filename, file_contents, connections=None): xml_request = self._generate_xml(flow_item, connections) - parts = {'request_payload': ('', xml_request, 'text/xml'), - 'tableau_flow': (filename, file_contents, 'application/octet-stream')} + parts = { + "request_payload": ("", xml_request, "text/xml"), + "tableau_flow": (filename, file_contents, "application/octet-stream"), + } return _add_multipart(parts) def publish_req_chunked(self, flow_item, connections=None): xml_request = self._generate_xml(flow_item, connections) - parts = {'request_payload': ('', xml_request, 'text/xml')} + parts = {"request_payload": ("", xml_request, "text/xml")} return _add_multipart(parts) class GroupRequest(object): def add_user_req(self, user_id): - xml_request = ET.Element('tsRequest') - user_element = ET.SubElement(xml_request, 'user') - user_element.attrib['id'] = user_id + xml_request = ET.Element("tsRequest") + user_element = ET.SubElement(xml_request, "user") + user_element.attrib["id"] = user_id return ET.tostring(xml_request) def create_local_req(self, group_item): - xml_request = ET.Element('tsRequest') - group_element = ET.SubElement(xml_request, 'group') - group_element.attrib['name'] = group_item.name + xml_request = ET.Element("tsRequest") + group_element = ET.SubElement(xml_request, "group") + group_element.attrib["name"] = group_item.name if group_item.minimum_site_role is not None: - group_element.attrib['minimumSiteRole'] = group_item.minimum_site_role + group_element.attrib["minimumSiteRole"] = group_item.minimum_site_role return ET.tostring(xml_request) def create_ad_req(self, group_item): - xml_request = ET.Element('tsRequest') - group_element = ET.SubElement(xml_request, 'group') - group_element.attrib['name'] = group_item.name - import_element = ET.SubElement(group_element, 'import') - import_element.attrib['source'] = "ActiveDirectory" + xml_request = ET.Element("tsRequest") + group_element = ET.SubElement(xml_request, "group") + group_element.attrib["name"] = group_item.name + import_element = ET.SubElement(group_element, "import") + import_element.attrib["source"] = "ActiveDirectory" if group_item.domain_name is None: error = "Group Domain undefined." raise ValueError(error) - import_element.attrib['domainName'] = group_item.domain_name + import_element.attrib["domainName"] = group_item.domain_name if group_item.license_mode is not None: - import_element.attrib['grantLicenseMode'] = group_item.license_mode + import_element.attrib["grantLicenseMode"] = group_item.license_mode if group_item.minimum_site_role is not None: - import_element.attrib['siteRole'] = group_item.minimum_site_role + import_element.attrib["siteRole"] = group_item.minimum_site_role return ET.tostring(xml_request) def update_req(self, group_item, default_site_role=None): # (1/8/2021): Deprecated starting v0.15 if default_site_role is not None: import warnings - warnings.simplefilter('always', DeprecationWarning) - warnings.warn('RequestFactory.Group.update_req(...default_site_role="") is deprecated, ' - 'please set the minimum_site_role field of GroupItem', - DeprecationWarning) + + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + 'RequestFactory.Group.update_req(...default_site_role="") is deprecated, ' + "please set the minimum_site_role field of GroupItem", + DeprecationWarning, + ) group_item.minimum_site_role = default_site_role - xml_request = ET.Element('tsRequest') - group_element = ET.SubElement(xml_request, 'group') - group_element.attrib['name'] = group_item.name - if group_item.domain_name is not None and group_item.domain_name != 'local': + xml_request = ET.Element("tsRequest") + group_element = ET.SubElement(xml_request, "group") + group_element.attrib["name"] = group_item.name + if group_item.domain_name is not None and group_item.domain_name != "local": # Import element is only accepted in the request for AD groups - import_element = ET.SubElement(group_element, 'import') - import_element.attrib['source'] = "ActiveDirectory" - import_element.attrib['domainName'] = group_item.domain_name - import_element.attrib['siteRole'] = group_item.minimum_site_role + import_element = ET.SubElement(group_element, "import") + import_element.attrib["source"] = "ActiveDirectory" + import_element.attrib["domainName"] = group_item.domain_name + import_element.attrib["siteRole"] = group_item.minimum_site_role if group_item.license_mode is not None: - import_element.attrib['grantLicenseMode'] = group_item.license_mode + import_element.attrib["grantLicenseMode"] = group_item.license_mode else: # Local group request does not accept an 'import' element if group_item.minimum_site_role is not None: - group_element.attrib['minimumSiteRole'] = group_item.minimum_site_role + group_element.attrib["minimumSiteRole"] = group_item.minimum_site_role return ET.tostring(xml_request) class PermissionRequest(object): def add_req(self, rules): - xml_request = ET.Element('tsRequest') - permissions_element = ET.SubElement(xml_request, 'permissions') + xml_request = ET.Element("tsRequest") + permissions_element = ET.SubElement(xml_request, "permissions") for rule in rules: - grantee_capabilities_element = ET.SubElement(permissions_element, 'granteeCapabilities') + grantee_capabilities_element = ET.SubElement(permissions_element, "granteeCapabilities") grantee_element = ET.SubElement(grantee_capabilities_element, rule.grantee.tag_name) - grantee_element.attrib['id'] = rule.grantee.id + grantee_element.attrib["id"] = rule.grantee.id - capabilities_element = ET.SubElement(grantee_capabilities_element, 'capabilities') + capabilities_element = ET.SubElement(grantee_capabilities_element, "capabilities") self._add_all_capabilities(capabilities_element, rule.capabilities) return ET.tostring(xml_request) def _add_all_capabilities(self, capabilities_element, capabilities_map): for name, mode in capabilities_map.items(): - capability_element = ET.SubElement(capabilities_element, 'capability') - capability_element.attrib['name'] = name - capability_element.attrib['mode'] = mode + capability_element = ET.SubElement(capabilities_element, "capability") + capability_element.attrib["name"] = name + capability_element.attrib["mode"] = mode class ProjectRequest(object): def update_req(self, project_item): - xml_request = ET.Element('tsRequest') - project_element = ET.SubElement(xml_request, 'project') + xml_request = ET.Element("tsRequest") + project_element = ET.SubElement(xml_request, "project") if project_item.name: - project_element.attrib['name'] = project_item.name + project_element.attrib["name"] = project_item.name if project_item.description: - project_element.attrib['description'] = project_item.description + project_element.attrib["description"] = project_item.description if project_item.content_permissions: - project_element.attrib['contentPermissions'] = project_item.content_permissions + project_element.attrib["contentPermissions"] = project_item.content_permissions if project_item.parent_id is not None: - project_element.attrib['parentProjectId'] = project_item.parent_id + project_element.attrib["parentProjectId"] = project_item.parent_id return ET.tostring(xml_request) def create_req(self, project_item): - xml_request = ET.Element('tsRequest') - project_element = ET.SubElement(xml_request, 'project') - project_element.attrib['name'] = project_item.name + xml_request = ET.Element("tsRequest") + project_element = ET.SubElement(xml_request, "project") + project_element.attrib["name"] = project_item.name if project_item.description: - project_element.attrib['description'] = project_item.description + project_element.attrib["description"] = project_item.description if project_item.content_permissions: - project_element.attrib['contentPermissions'] = project_item.content_permissions + project_element.attrib["contentPermissions"] = project_item.content_permissions if project_item.parent_id: - project_element.attrib['parentProjectId'] = project_item.parent_id + project_element.attrib["parentProjectId"] = project_item.parent_id return ET.tostring(xml_request) class ScheduleRequest(object): def create_req(self, schedule_item): - xml_request = ET.Element('tsRequest') - schedule_element = ET.SubElement(xml_request, 'schedule') - schedule_element.attrib['name'] = schedule_item.name - schedule_element.attrib['priority'] = str(schedule_item.priority) - schedule_element.attrib['type'] = schedule_item.schedule_type - schedule_element.attrib['executionOrder'] = schedule_item.execution_order + xml_request = ET.Element("tsRequest") + schedule_element = ET.SubElement(xml_request, "schedule") + schedule_element.attrib["name"] = schedule_item.name + schedule_element.attrib["priority"] = str(schedule_item.priority) + schedule_element.attrib["type"] = schedule_item.schedule_type + schedule_element.attrib["executionOrder"] = schedule_item.execution_order interval_item = schedule_item.interval_item - schedule_element.attrib['frequency'] = interval_item._frequency - frequency_element = ET.SubElement(schedule_element, 'frequencyDetails') - frequency_element.attrib['start'] = str(interval_item.start_time) - if hasattr(interval_item, 'end_time') and interval_item.end_time is not None: - frequency_element.attrib['end'] = str(interval_item.end_time) - if hasattr(interval_item, 'interval') and interval_item.interval: - intervals_element = ET.SubElement(frequency_element, 'intervals') + schedule_element.attrib["frequency"] = interval_item._frequency + frequency_element = ET.SubElement(schedule_element, "frequencyDetails") + frequency_element.attrib["start"] = str(interval_item.start_time) + if hasattr(interval_item, "end_time") and interval_item.end_time is not None: + frequency_element.attrib["end"] = str(interval_item.end_time) + if hasattr(interval_item, "interval") and interval_item.interval: + intervals_element = ET.SubElement(frequency_element, "intervals") for interval in interval_item._interval_type_pairs(): expression, value = interval - single_interval_element = ET.SubElement(intervals_element, 'interval') + single_interval_element = ET.SubElement(intervals_element, "interval") single_interval_element.attrib[expression] = value return ET.tostring(xml_request) def update_req(self, schedule_item): - xml_request = ET.Element('tsRequest') - schedule_element = ET.SubElement(xml_request, 'schedule') + xml_request = ET.Element("tsRequest") + schedule_element = ET.SubElement(xml_request, "schedule") if schedule_item.name: - schedule_element.attrib['name'] = schedule_item.name + schedule_element.attrib["name"] = schedule_item.name if schedule_item.priority: - schedule_element.attrib['priority'] = str(schedule_item.priority) + schedule_element.attrib["priority"] = str(schedule_item.priority) if schedule_item.execution_order: - schedule_element.attrib['executionOrder'] = schedule_item.execution_order + schedule_element.attrib["executionOrder"] = schedule_item.execution_order if schedule_item.state: - schedule_element.attrib['state'] = schedule_item.state + schedule_element.attrib["state"] = schedule_item.state interval_item = schedule_item.interval_item if interval_item is not None: if interval_item._frequency: - schedule_element.attrib['frequency'] = interval_item._frequency - frequency_element = ET.SubElement(schedule_element, 'frequencyDetails') - frequency_element.attrib['start'] = str(interval_item.start_time) - if hasattr(interval_item, 'end_time') and interval_item.end_time is not None: - frequency_element.attrib['end'] = str(interval_item.end_time) - intervals_element = ET.SubElement(frequency_element, 'intervals') - if hasattr(interval_item, 'interval'): + schedule_element.attrib["frequency"] = interval_item._frequency + frequency_element = ET.SubElement(schedule_element, "frequencyDetails") + frequency_element.attrib["start"] = str(interval_item.start_time) + if hasattr(interval_item, "end_time") and interval_item.end_time is not None: + frequency_element.attrib["end"] = str(interval_item.end_time) + intervals_element = ET.SubElement(frequency_element, "intervals") + if hasattr(interval_item, "interval"): for interval in interval_item._interval_type_pairs(): (expression, value) = interval - single_interval_element = ET.SubElement(intervals_element, 'interval') + single_interval_element = ET.SubElement(intervals_element, "interval") single_interval_element.attrib[expression] = value return ET.tostring(xml_request) @@ -435,11 +441,11 @@ def _add_to_req(self, id_, target_type, task_type=TaskItem.Type.ExtractRefresh): """ - xml_request = ET.Element('tsRequest') - task_element = ET.SubElement(xml_request, 'task') + xml_request = ET.Element("tsRequest") + task_element = ET.SubElement(xml_request, "task") task = ET.SubElement(task_element, task_type) workbook = ET.SubElement(task, target_type) - workbook.attrib['id'] = id_ + workbook.attrib["id"] = id_ return ET.tostring(xml_request) @@ -452,371 +458,377 @@ def add_datasource_req(self, id_, task_type=TaskItem.Type.ExtractRefresh): class SiteRequest(object): def update_req(self, site_item): - xml_request = ET.Element('tsRequest') - site_element = ET.SubElement(xml_request, 'site') + xml_request = ET.Element("tsRequest") + site_element = ET.SubElement(xml_request, "site") if site_item.name: - site_element.attrib['name'] = site_item.name + site_element.attrib["name"] = site_item.name if site_item.content_url: - site_element.attrib['contentUrl'] = site_item.content_url + site_element.attrib["contentUrl"] = site_item.content_url if site_item.admin_mode: - site_element.attrib['adminMode'] = site_item.admin_mode + site_element.attrib["adminMode"] = site_item.admin_mode if site_item.user_quota: - site_element.attrib['userQuota'] = str(site_item.user_quota) + site_element.attrib["userQuota"] = str(site_item.user_quota) if site_item.state: - site_element.attrib['state'] = site_item.state + site_element.attrib["state"] = site_item.state if site_item.storage_quota: - site_element.attrib['storageQuota'] = str(site_item.storage_quota) + site_element.attrib["storageQuota"] = str(site_item.storage_quota) if site_item.disable_subscriptions is not None: - site_element.attrib['disableSubscriptions'] = str(site_item.disable_subscriptions).lower() + site_element.attrib["disableSubscriptions"] = str(site_item.disable_subscriptions).lower() if site_item.subscribe_others_enabled is not None: - site_element.attrib['subscribeOthersEnabled'] = str(site_item.subscribe_others_enabled).lower() + site_element.attrib["subscribeOthersEnabled"] = str(site_item.subscribe_others_enabled).lower() if site_item.revision_limit: - site_element.attrib['revisionLimit'] = str(site_item.revision_limit) + site_element.attrib["revisionLimit"] = str(site_item.revision_limit) if site_item.revision_history_enabled is not None: - site_element.attrib['revisionHistoryEnabled'] = str(site_item.revision_history_enabled).lower() + site_element.attrib["revisionHistoryEnabled"] = str(site_item.revision_history_enabled).lower() if site_item.data_acceleration_mode is not None: - site_element.attrib['dataAccelerationMode'] = str(site_item.data_acceleration_mode).lower() + site_element.attrib["dataAccelerationMode"] = str(site_item.data_acceleration_mode).lower() if site_item.flows_enabled is not None: - site_element.attrib['flowsEnabled'] = str(site_item.flows_enabled).lower() + site_element.attrib["flowsEnabled"] = str(site_item.flows_enabled).lower() if site_item.cataloging_enabled is not None: - site_element.attrib['catalogingEnabled'] = str(site_item.cataloging_enabled).lower() + site_element.attrib["catalogingEnabled"] = str(site_item.cataloging_enabled).lower() if site_item.editing_flows_enabled is not None: - site_element.attrib['editingFlowsEnabled'] = str(site_item.editing_flows_enabled).lower() + site_element.attrib["editingFlowsEnabled"] = str(site_item.editing_flows_enabled).lower() if site_item.scheduling_flows_enabled is not None: - site_element.attrib['schedulingFlowsEnabled'] = str(site_item.scheduling_flows_enabled).lower() + site_element.attrib["schedulingFlowsEnabled"] = str(site_item.scheduling_flows_enabled).lower() if site_item.allow_subscription_attachments is not None: - site_element.attrib['allowSubscriptionAttachments'] = str(site_item.allow_subscription_attachments).lower() + site_element.attrib["allowSubscriptionAttachments"] = str(site_item.allow_subscription_attachments).lower() if site_item.guest_access_enabled is not None: - site_element.attrib['guestAccessEnabled'] = str(site_item.guest_access_enabled).lower() + site_element.attrib["guestAccessEnabled"] = str(site_item.guest_access_enabled).lower() if site_item.cache_warmup_enabled is not None: - site_element.attrib['cacheWarmupEnabled'] = str(site_item.cache_warmup_enabled).lower() + site_element.attrib["cacheWarmupEnabled"] = str(site_item.cache_warmup_enabled).lower() if site_item.commenting_enabled is not None: - site_element.attrib['commentingEnabled'] = str(site_item.commenting_enabled).lower() + site_element.attrib["commentingEnabled"] = str(site_item.commenting_enabled).lower() if site_item.extract_encryption_mode is not None: - site_element.attrib['extractEncryptionMode'] = str(site_item.extract_encryption_mode).lower() + site_element.attrib["extractEncryptionMode"] = str(site_item.extract_encryption_mode).lower() if site_item.request_access_enabled is not None: - site_element.attrib['requestAccessEnabled'] = str(site_item.request_access_enabled).lower() + site_element.attrib["requestAccessEnabled"] = str(site_item.request_access_enabled).lower() if site_item.run_now_enabled is not None: - site_element.attrib['runNowEnabled'] = str(site_item.run_now_enabled).lower() + site_element.attrib["runNowEnabled"] = str(site_item.run_now_enabled).lower() if site_item.tier_creator_capacity is not None: - site_element.attrib['tierCreatorCapacity'] = str(site_item.tier_creator_capacity).lower() + site_element.attrib["tierCreatorCapacity"] = str(site_item.tier_creator_capacity).lower() if site_item.tier_explorer_capacity is not None: - site_element.attrib['tierExplorerCapacity'] = str(site_item.tier_explorer_capacity).lower() + site_element.attrib["tierExplorerCapacity"] = str(site_item.tier_explorer_capacity).lower() if site_item.tier_viewer_capacity is not None: - site_element.attrib['tierViewerCapacity'] = str(site_item.tier_viewer_capacity).lower() + site_element.attrib["tierViewerCapacity"] = str(site_item.tier_viewer_capacity).lower() if site_item.data_alerts_enabled is not None: - site_element.attrib['dataAlertsEnabled'] = str(site_item.data_alerts_enabled) + site_element.attrib["dataAlertsEnabled"] = str(site_item.data_alerts_enabled) if site_item.commenting_mentions_enabled is not None: - site_element.attrib['commentingMentionsEnabled'] = str(site_item.commenting_mentions_enabled).lower() + site_element.attrib["commentingMentionsEnabled"] = str(site_item.commenting_mentions_enabled).lower() if site_item.catalog_obfuscation_enabled is not None: - site_element.attrib['catalogObfuscationEnabled'] = str(site_item.catalog_obfuscation_enabled).lower() + site_element.attrib["catalogObfuscationEnabled"] = str(site_item.catalog_obfuscation_enabled).lower() if site_item.flow_auto_save_enabled is not None: - site_element.attrib['flowAutoSaveEnabled'] = str(site_item.flow_auto_save_enabled).lower() + site_element.attrib["flowAutoSaveEnabled"] = str(site_item.flow_auto_save_enabled).lower() if site_item.web_extraction_enabled is not None: - site_element.attrib['webExtractionEnabled'] = str(site_item.web_extraction_enabled).lower() + site_element.attrib["webExtractionEnabled"] = str(site_item.web_extraction_enabled).lower() if site_item.metrics_content_type_enabled is not None: - site_element.attrib['metricsContentTypeEnabled'] = str(site_item.metrics_content_type_enabled).lower() + site_element.attrib["metricsContentTypeEnabled"] = str(site_item.metrics_content_type_enabled).lower() if site_item.notify_site_admins_on_throttle is not None: - site_element.attrib['notifySiteAdminsOnThrottle'] = str(site_item.notify_site_admins_on_throttle).lower() + site_element.attrib["notifySiteAdminsOnThrottle"] = str(site_item.notify_site_admins_on_throttle).lower() if site_item.authoring_enabled is not None: - site_element.attrib['authoringEnabled'] = str(site_item.authoring_enabled).lower() + site_element.attrib["authoringEnabled"] = str(site_item.authoring_enabled).lower() if site_item.custom_subscription_email_enabled is not None: - site_element.attrib['customSubscriptionEmailEnabled'] = \ - str(site_item.custom_subscription_email_enabled).lower() + site_element.attrib["customSubscriptionEmailEnabled"] = str( + site_item.custom_subscription_email_enabled + ).lower() if site_item.custom_subscription_email is not None: - site_element.attrib['customSubscriptionEmail'] = str(site_item.custom_subscription_email).lower() + site_element.attrib["customSubscriptionEmail"] = str(site_item.custom_subscription_email).lower() if site_item.custom_subscription_footer_enabled is not None: - site_element.attrib['customSubscriptionFooterEnabled'] =\ - str(site_item.custom_subscription_footer_enabled).lower() + site_element.attrib["customSubscriptionFooterEnabled"] = str( + site_item.custom_subscription_footer_enabled + ).lower() if site_item.custom_subscription_footer is not None: - site_element.attrib['customSubscriptionFooter'] = str(site_item.custom_subscription_footer).lower() + site_element.attrib["customSubscriptionFooter"] = str(site_item.custom_subscription_footer).lower() if site_item.ask_data_mode is not None: - site_element.attrib['askDataMode'] = str(site_item.ask_data_mode) + site_element.attrib["askDataMode"] = str(site_item.ask_data_mode) if site_item.named_sharing_enabled is not None: - site_element.attrib['namedSharingEnabled'] = str(site_item.named_sharing_enabled).lower() + site_element.attrib["namedSharingEnabled"] = str(site_item.named_sharing_enabled).lower() if site_item.mobile_biometrics_enabled is not None: - site_element.attrib['mobileBiometricsEnabled'] = str(site_item.mobile_biometrics_enabled).lower() + site_element.attrib["mobileBiometricsEnabled"] = str(site_item.mobile_biometrics_enabled).lower() if site_item.sheet_image_enabled is not None: - site_element.attrib['sheetImageEnabled'] = str(site_item.sheet_image_enabled).lower() + site_element.attrib["sheetImageEnabled"] = str(site_item.sheet_image_enabled).lower() if site_item.derived_permissions_enabled is not None: - site_element.attrib['derivedPermissionsEnabled'] = str(site_item.derived_permissions_enabled).lower() + site_element.attrib["derivedPermissionsEnabled"] = str(site_item.derived_permissions_enabled).lower() if site_item.user_visibility_mode is not None: - site_element.attrib['userVisibilityMode'] = str(site_item.user_visibility_mode) + site_element.attrib["userVisibilityMode"] = str(site_item.user_visibility_mode) if site_item.use_default_time_zone is not None: - site_element.attrib['useDefaultTimeZone'] = str(site_item.use_default_time_zone).lower() + site_element.attrib["useDefaultTimeZone"] = str(site_item.use_default_time_zone).lower() if site_item.time_zone is not None: - site_element.attrib['timeZone'] = str(site_item.time_zone) + site_element.attrib["timeZone"] = str(site_item.time_zone) if site_item.auto_suspend_refresh_enabled is not None: - site_element.attrib['autoSuspendRefreshEnabled'] = str(site_item.auto_suspend_refresh_enabled).lower() + site_element.attrib["autoSuspendRefreshEnabled"] = str(site_item.auto_suspend_refresh_enabled).lower() if site_item.auto_suspend_refresh_inactivity_window is not None: - site_element.attrib['autoSuspendRefreshInactivityWindow'] =\ - str(site_item.auto_suspend_refresh_inactivity_window) + site_element.attrib["autoSuspendRefreshInactivityWindow"] = str( + site_item.auto_suspend_refresh_inactivity_window + ) return ET.tostring(xml_request) def create_req(self, site_item): - xml_request = ET.Element('tsRequest') - site_element = ET.SubElement(xml_request, 'site') - site_element.attrib['name'] = site_item.name - site_element.attrib['contentUrl'] = site_item.content_url + xml_request = ET.Element("tsRequest") + site_element = ET.SubElement(xml_request, "site") + site_element.attrib["name"] = site_item.name + site_element.attrib["contentUrl"] = site_item.content_url if site_item.admin_mode: - site_element.attrib['adminMode'] = site_item.admin_mode + site_element.attrib["adminMode"] = site_item.admin_mode if site_item.user_quota: - site_element.attrib['userQuota'] = str(site_item.user_quota) + site_element.attrib["userQuota"] = str(site_item.user_quota) if site_item.storage_quota: - site_element.attrib['storageQuota'] = str(site_item.storage_quota) + site_element.attrib["storageQuota"] = str(site_item.storage_quota) if site_item.disable_subscriptions is not None: - site_element.attrib['disableSubscriptions'] = str(site_item.disable_subscriptions).lower() + site_element.attrib["disableSubscriptions"] = str(site_item.disable_subscriptions).lower() if site_item.subscribe_others_enabled is not None: - site_element.attrib['subscribeOthersEnabled'] = str(site_item.subscribe_others_enabled).lower() + site_element.attrib["subscribeOthersEnabled"] = str(site_item.subscribe_others_enabled).lower() if site_item.revision_limit: - site_element.attrib['revisionLimit'] = str(site_item.revision_limit) + site_element.attrib["revisionLimit"] = str(site_item.revision_limit) if site_item.data_acceleration_mode is not None: - site_element.attrib['dataAccelerationMode'] = str(site_item.data_acceleration_mode).lower() + site_element.attrib["dataAccelerationMode"] = str(site_item.data_acceleration_mode).lower() if site_item.flows_enabled is not None: - site_element.attrib['flowsEnabled'] = str(site_item.flows_enabled).lower() + site_element.attrib["flowsEnabled"] = str(site_item.flows_enabled).lower() if site_item.editing_flows_enabled is not None: - site_element.attrib['editingFlowsEnabled'] = str(site_item.editing_flows_enabled).lower() + site_element.attrib["editingFlowsEnabled"] = str(site_item.editing_flows_enabled).lower() if site_item.scheduling_flows_enabled is not None: - site_element.attrib['schedulingFlowsEnabled'] = str(site_item.scheduling_flows_enabled).lower() + site_element.attrib["schedulingFlowsEnabled"] = str(site_item.scheduling_flows_enabled).lower() if site_item.allow_subscription_attachments is not None: - site_element.attrib['allowSubscriptionAttachments'] = str(site_item.allow_subscription_attachments).lower() + site_element.attrib["allowSubscriptionAttachments"] = str(site_item.allow_subscription_attachments).lower() if site_item.guest_access_enabled is not None: - site_element.attrib['guestAccessEnabled'] = str(site_item.guest_access_enabled).lower() + site_element.attrib["guestAccessEnabled"] = str(site_item.guest_access_enabled).lower() if site_item.cache_warmup_enabled is not None: - site_element.attrib['cacheWarmupEnabled'] = str(site_item.cache_warmup_enabled).lower() + site_element.attrib["cacheWarmupEnabled"] = str(site_item.cache_warmup_enabled).lower() if site_item.commenting_enabled is not None: - site_element.attrib['commentingEnabled'] = str(site_item.commenting_enabled).lower() + site_element.attrib["commentingEnabled"] = str(site_item.commenting_enabled).lower() if site_item.revision_history_enabled is not None: - site_element.attrib['revisionHistoryEnabled'] = str(site_item.revision_history_enabled).lower() + site_element.attrib["revisionHistoryEnabled"] = str(site_item.revision_history_enabled).lower() if site_item.extract_encryption_mode is not None: - site_element.attrib['extractEncryptionMode'] = str(site_item.extract_encryption_mode).lower() + site_element.attrib["extractEncryptionMode"] = str(site_item.extract_encryption_mode).lower() if site_item.request_access_enabled is not None: - site_element.attrib['requestAccessEnabled'] = str(site_item.request_access_enabled).lower() + site_element.attrib["requestAccessEnabled"] = str(site_item.request_access_enabled).lower() if site_item.run_now_enabled is not None: - site_element.attrib['runNowEnabled'] = str(site_item.run_now_enabled).lower() + site_element.attrib["runNowEnabled"] = str(site_item.run_now_enabled).lower() if site_item.tier_creator_capacity is not None: - site_element.attrib['tierCreatorCapacity'] = str(site_item.tier_creator_capacity).lower() + site_element.attrib["tierCreatorCapacity"] = str(site_item.tier_creator_capacity).lower() if site_item.tier_explorer_capacity is not None: - site_element.attrib['tierExplorerCapacity'] = str(site_item.tier_explorer_capacity).lower() + site_element.attrib["tierExplorerCapacity"] = str(site_item.tier_explorer_capacity).lower() if site_item.tier_viewer_capacity is not None: - site_element.attrib['tierViewerCapacity'] = str(site_item.tier_viewer_capacity).lower() + site_element.attrib["tierViewerCapacity"] = str(site_item.tier_viewer_capacity).lower() if site_item.data_alerts_enabled is not None: - site_element.attrib['dataAlertsEnabled'] = str(site_item.data_alerts_enabled).lower() + site_element.attrib["dataAlertsEnabled"] = str(site_item.data_alerts_enabled).lower() if site_item.commenting_mentions_enabled is not None: - site_element.attrib['commentingMentionsEnabled'] = str(site_item.commenting_mentions_enabled).lower() + site_element.attrib["commentingMentionsEnabled"] = str(site_item.commenting_mentions_enabled).lower() if site_item.catalog_obfuscation_enabled is not None: - site_element.attrib['catalogObfuscationEnabled'] = str(site_item.catalog_obfuscation_enabled).lower() + site_element.attrib["catalogObfuscationEnabled"] = str(site_item.catalog_obfuscation_enabled).lower() if site_item.flow_auto_save_enabled is not None: - site_element.attrib['flowAutoSaveEnabled'] = str(site_item.flow_auto_save_enabled).lower() + site_element.attrib["flowAutoSaveEnabled"] = str(site_item.flow_auto_save_enabled).lower() if site_item.web_extraction_enabled is not None: - site_element.attrib['webExtractionEnabled'] = str(site_item.web_extraction_enabled).lower() + site_element.attrib["webExtractionEnabled"] = str(site_item.web_extraction_enabled).lower() if site_item.metrics_content_type_enabled is not None: - site_element.attrib['metricsContentTypeEnabled'] = str(site_item.metrics_content_type_enabled).lower() + site_element.attrib["metricsContentTypeEnabled"] = str(site_item.metrics_content_type_enabled).lower() if site_item.notify_site_admins_on_throttle is not None: - site_element.attrib['notifySiteAdminsOnThrottle'] = str(site_item.notify_site_admins_on_throttle).lower() + site_element.attrib["notifySiteAdminsOnThrottle"] = str(site_item.notify_site_admins_on_throttle).lower() if site_item.authoring_enabled is not None: - site_element.attrib['authoringEnabled'] = str(site_item.authoring_enabled).lower() + site_element.attrib["authoringEnabled"] = str(site_item.authoring_enabled).lower() if site_item.custom_subscription_email_enabled is not None: - site_element.attrib['customSubscriptionEmailEnabled'] =\ - str(site_item.custom_subscription_email_enabled).lower() + site_element.attrib["customSubscriptionEmailEnabled"] = str( + site_item.custom_subscription_email_enabled + ).lower() if site_item.custom_subscription_email is not None: - site_element.attrib['customSubscriptionEmail'] = str(site_item.custom_subscription_email).lower() + site_element.attrib["customSubscriptionEmail"] = str(site_item.custom_subscription_email).lower() if site_item.custom_subscription_footer_enabled is not None: - site_element.attrib['customSubscriptionFooterEnabled'] =\ - str(site_item.custom_subscription_footer_enabled).lower() + site_element.attrib["customSubscriptionFooterEnabled"] = str( + site_item.custom_subscription_footer_enabled + ).lower() if site_item.custom_subscription_footer is not None: - site_element.attrib['customSubscriptionFooter'] = str(site_item.custom_subscription_footer).lower() + site_element.attrib["customSubscriptionFooter"] = str(site_item.custom_subscription_footer).lower() if site_item.ask_data_mode is not None: - site_element.attrib['askDataMode'] = str(site_item.ask_data_mode) + site_element.attrib["askDataMode"] = str(site_item.ask_data_mode) if site_item.named_sharing_enabled is not None: - site_element.attrib['namedSharingEnabled'] = str(site_item.named_sharing_enabled).lower() + site_element.attrib["namedSharingEnabled"] = str(site_item.named_sharing_enabled).lower() if site_item.mobile_biometrics_enabled is not None: - site_element.attrib['mobileBiometricsEnabled'] = str(site_item.mobile_biometrics_enabled).lower() + site_element.attrib["mobileBiometricsEnabled"] = str(site_item.mobile_biometrics_enabled).lower() if site_item.sheet_image_enabled is not None: - site_element.attrib['sheetImageEnabled'] = str(site_item.sheet_image_enabled).lower() + site_element.attrib["sheetImageEnabled"] = str(site_item.sheet_image_enabled).lower() if site_item.cataloging_enabled is not None: - site_element.attrib['catalogingEnabled'] = str(site_item.cataloging_enabled).lower() + site_element.attrib["catalogingEnabled"] = str(site_item.cataloging_enabled).lower() if site_item.derived_permissions_enabled is not None: - site_element.attrib['derivedPermissionsEnabled'] = str(site_item.derived_permissions_enabled).lower() + site_element.attrib["derivedPermissionsEnabled"] = str(site_item.derived_permissions_enabled).lower() if site_item.user_visibility_mode is not None: - site_element.attrib['userVisibilityMode'] = str(site_item.user_visibility_mode) + site_element.attrib["userVisibilityMode"] = str(site_item.user_visibility_mode) if site_item.use_default_time_zone is not None: - site_element.attrib['useDefaultTimeZone'] = str(site_item.use_default_time_zone).lower() + site_element.attrib["useDefaultTimeZone"] = str(site_item.use_default_time_zone).lower() if site_item.time_zone is not None: - site_element.attrib['timeZone'] = str(site_item.time_zone) + site_element.attrib["timeZone"] = str(site_item.time_zone) if site_item.auto_suspend_refresh_enabled is not None: - site_element.attrib['autoSuspendRefreshEnabled'] = str(site_item.auto_suspend_refresh_enabled).lower() + site_element.attrib["autoSuspendRefreshEnabled"] = str(site_item.auto_suspend_refresh_enabled).lower() if site_item.auto_suspend_refresh_inactivity_window is not None: - site_element.attrib['autoSuspendRefreshInactivityWindow'] =\ - str(site_item.auto_suspend_refresh_inactivity_window) + site_element.attrib["autoSuspendRefreshInactivityWindow"] = str( + site_item.auto_suspend_refresh_inactivity_window + ) return ET.tostring(xml_request) class TableRequest(object): def update_req(self, table_item): - xml_request = ET.Element('tsRequest') - table_element = ET.SubElement(xml_request, 'table') + xml_request = ET.Element("tsRequest") + table_element = ET.SubElement(xml_request, "table") if table_item.contact_id: - contact_element = ET.SubElement(table_element, 'contact') - contact_element.attrib['id'] = table_item.contact_id + contact_element = ET.SubElement(table_element, "contact") + contact_element.attrib["id"] = table_item.contact_id - table_element.attrib['isCertified'] = str(table_item.certified).lower() + table_element.attrib["isCertified"] = str(table_item.certified).lower() if table_item.certification_note: - table_element.attrib['certificationNote'] = str(table_item.certification_note) + table_element.attrib["certificationNote"] = str(table_item.certification_note) if table_item.description: - table_element.attrib['description'] = str(table_item.description) + table_element.attrib["description"] = str(table_item.description) return ET.tostring(xml_request) class TagRequest(object): def add_req(self, tag_set): - xml_request = ET.Element('tsRequest') - tags_element = ET.SubElement(xml_request, 'tags') + xml_request = ET.Element("tsRequest") + tags_element = ET.SubElement(xml_request, "tags") for tag in tag_set: - tag_element = ET.SubElement(tags_element, 'tag') - tag_element.attrib['label'] = tag + tag_element = ET.SubElement(tags_element, "tag") + tag_element.attrib["label"] = tag return ET.tostring(xml_request) class UserRequest(object): def update_req(self, user_item, password): - xml_request = ET.Element('tsRequest') - user_element = ET.SubElement(xml_request, 'user') + xml_request = ET.Element("tsRequest") + user_element = ET.SubElement(xml_request, "user") if user_item.fullname: - user_element.attrib['fullName'] = user_item.fullname + user_element.attrib["fullName"] = user_item.fullname if user_item.email: - user_element.attrib['email'] = user_item.email + user_element.attrib["email"] = user_item.email if user_item.site_role: - if user_item.site_role != 'ServerAdministrator': - user_element.attrib['siteRole'] = user_item.site_role + if user_item.site_role != "ServerAdministrator": + user_element.attrib["siteRole"] = user_item.site_role if user_item.auth_setting: - user_element.attrib['authSetting'] = user_item.auth_setting + user_element.attrib["authSetting"] = user_item.auth_setting if password: - user_element.attrib['password'] = password + user_element.attrib["password"] = password return ET.tostring(xml_request) def add_req(self, user_item): - xml_request = ET.Element('tsRequest') - user_element = ET.SubElement(xml_request, 'user') - user_element.attrib['name'] = user_item.name - user_element.attrib['siteRole'] = user_item.site_role + xml_request = ET.Element("tsRequest") + user_element = ET.SubElement(xml_request, "user") + user_element.attrib["name"] = user_item.name + user_element.attrib["siteRole"] = user_item.site_role if user_item.auth_setting: - user_element.attrib['authSetting'] = user_item.auth_setting + user_element.attrib["authSetting"] = user_item.auth_setting return ET.tostring(xml_request) class WorkbookRequest(object): - def _generate_xml( - self, workbook_item, - connection_credentials=None, connections=None, - hidden_views=None - ): - xml_request = ET.Element('tsRequest') - workbook_element = ET.SubElement(xml_request, 'workbook') - workbook_element.attrib['name'] = workbook_item.name + def _generate_xml(self, workbook_item, connection_credentials=None, connections=None, hidden_views=None): + xml_request = ET.Element("tsRequest") + workbook_element = ET.SubElement(xml_request, "workbook") + workbook_element.attrib["name"] = workbook_item.name if workbook_item.show_tabs: - workbook_element.attrib['showTabs'] = str(workbook_item.show_tabs).lower() - project_element = ET.SubElement(workbook_element, 'project') - project_element.attrib['id'] = str(workbook_item.project_id) + workbook_element.attrib["showTabs"] = str(workbook_item.show_tabs).lower() + project_element = ET.SubElement(workbook_element, "project") + project_element.attrib["id"] = str(workbook_item.project_id) if connection_credentials is not None and connections is not None: - raise RuntimeError('You cannot set both `connections` and `connection_credentials`') + raise RuntimeError("You cannot set both `connections` and `connection_credentials`") if connection_credentials is not None: _add_credentials_element(workbook_element, connection_credentials) if connections is not None: - connections_element = ET.SubElement(workbook_element, 'connections') + connections_element = ET.SubElement(workbook_element, "connections") for connection in connections: _add_connections_element(connections_element, connection) if hidden_views is not None: - views_element = ET.SubElement(workbook_element, 'views') + views_element = ET.SubElement(workbook_element, "views") for view_name in hidden_views: _add_hiddenview_element(views_element, view_name) return ET.tostring(xml_request) def update_req(self, workbook_item): - xml_request = ET.Element('tsRequest') - workbook_element = ET.SubElement(xml_request, 'workbook') + xml_request = ET.Element("tsRequest") + workbook_element = ET.SubElement(xml_request, "workbook") if workbook_item.name: - workbook_element.attrib['name'] = workbook_item.name + workbook_element.attrib["name"] = workbook_item.name if workbook_item.show_tabs is not None: - workbook_element.attrib['showTabs'] = str(workbook_item.show_tabs).lower() + workbook_element.attrib["showTabs"] = str(workbook_item.show_tabs).lower() if workbook_item.project_id: - project_element = ET.SubElement(workbook_element, 'project') - project_element.attrib['id'] = workbook_item.project_id + project_element = ET.SubElement(workbook_element, "project") + project_element.attrib["id"] = workbook_item.project_id if workbook_item.owner_id: - owner_element = ET.SubElement(workbook_element, 'owner') - owner_element.attrib['id'] = workbook_item.owner_id - if workbook_item.data_acceleration_config['acceleration_enabled'] is not None: + owner_element = ET.SubElement(workbook_element, "owner") + owner_element.attrib["id"] = workbook_item.owner_id + if workbook_item.data_acceleration_config["acceleration_enabled"] is not None: data_acceleration_config = workbook_item.data_acceleration_config - data_acceleration_element = ET.SubElement(workbook_element, 'dataAccelerationConfig') - data_acceleration_element.attrib['accelerationEnabled'] = str(data_acceleration_config - ["acceleration_enabled"]).lower() - if data_acceleration_config['accelerate_now'] is not None: - data_acceleration_element.attrib['accelerateNow'] = str(data_acceleration_config - ["accelerate_now"]).lower() + data_acceleration_element = ET.SubElement(workbook_element, "dataAccelerationConfig") + data_acceleration_element.attrib["accelerationEnabled"] = str( + data_acceleration_config["acceleration_enabled"] + ).lower() + if data_acceleration_config["accelerate_now"] is not None: + data_acceleration_element.attrib["accelerateNow"] = str( + data_acceleration_config["accelerate_now"] + ).lower() return ET.tostring(xml_request) def publish_req( - self, workbook_item, filename, file_contents, - connection_credentials=None, connections=None, hidden_views=None + self, workbook_item, filename, file_contents, connection_credentials=None, connections=None, hidden_views=None ): - xml_request = self._generate_xml(workbook_item, - connection_credentials=connection_credentials, - connections=connections, - hidden_views=hidden_views) - - parts = {'request_payload': ('', xml_request, 'text/xml'), - 'tableau_workbook': (filename, file_contents, 'application/octet-stream')} + xml_request = self._generate_xml( + workbook_item, + connection_credentials=connection_credentials, + connections=connections, + hidden_views=hidden_views, + ) + + parts = { + "request_payload": ("", xml_request, "text/xml"), + "tableau_workbook": (filename, file_contents, "application/octet-stream"), + } return _add_multipart(parts) - def publish_req_chunked( - self, workbook_item, connection_credentials=None, connections=None, - hidden_views=None - ): - xml_request = self._generate_xml(workbook_item, - connection_credentials=connection_credentials, - connections=connections, - hidden_views=hidden_views) + def publish_req_chunked(self, workbook_item, connection_credentials=None, connections=None, hidden_views=None): + xml_request = self._generate_xml( + workbook_item, + connection_credentials=connection_credentials, + connections=connections, + hidden_views=hidden_views, + ) - parts = {'request_payload': ('', xml_request, 'text/xml')} + parts = {"request_payload": ("", xml_request, "text/xml")} return _add_multipart(parts) @_tsrequest_wrapped def embedded_extract_req(self, xml_request, include_all=True, datasources=None): - list_element = ET.SubElement(xml_request, 'datasources') + list_element = ET.SubElement(xml_request, "datasources") if include_all: - list_element.attrib['includeAll'] = "true" + list_element.attrib["includeAll"] = "true" else: for datasource_item in datasources: - datasource_element = list_element.SubElement(xml_request, 'datasource') - datasource_element.attrib['id'] = datasource_item.id + datasource_element = list_element.SubElement(xml_request, "datasource") + datasource_element.attrib["id"] = datasource_item.id class Connection(object): @_tsrequest_wrapped def update_req(self, xml_request, connection_item): - connection_element = ET.SubElement(xml_request, 'connection') + connection_element = ET.SubElement(xml_request, "connection") if connection_item.server_address: - connection_element.attrib['serverAddress'] = connection_item.server_address.lower() + connection_element.attrib["serverAddress"] = connection_item.server_address.lower() if connection_item.server_port: - connection_element.attrib['serverPort'] = str(connection_item.server_port) + connection_element.attrib["serverPort"] = str(connection_item.server_port) if connection_item.username: - connection_element.attrib['userName'] = connection_item.username + connection_element.attrib["userName"] = connection_item.username if connection_item.password: - connection_element.attrib['password'] = connection_item.password + connection_element.attrib["password"] = connection_item.password if connection_item.embed_password is not None: - connection_element.attrib['embedPassword'] = str(connection_item.embed_password).lower() + connection_element.attrib["embedPassword"] = str(connection_item.embed_password).lower() class TaskRequest(object): @@ -829,64 +841,64 @@ def run_req(self, xml_request, task_item): class SubscriptionRequest(object): @_tsrequest_wrapped def create_req(self, xml_request, subscription_item): - subscription_element = ET.SubElement(xml_request, 'subscription') + subscription_element = ET.SubElement(xml_request, "subscription") # Main attributes - subscription_element.attrib['subject'] = subscription_item.subject + subscription_element.attrib["subject"] = subscription_item.subject if subscription_item.attach_image is not None: - subscription_element.attrib['attachImage'] = str(subscription_item.attach_image).lower() + subscription_element.attrib["attachImage"] = str(subscription_item.attach_image).lower() if subscription_item.attach_pdf is not None: - subscription_element.attrib['attachPdf'] = str(subscription_item.attach_pdf).lower() + subscription_element.attrib["attachPdf"] = str(subscription_item.attach_pdf).lower() if subscription_item.message is not None: - subscription_element.attrib['message'] = subscription_item.message + subscription_element.attrib["message"] = subscription_item.message if subscription_item.page_orientation is not None: - subscription_element.attrib['pageOrientation'] = subscription_item.page_orientation + subscription_element.attrib["pageOrientation"] = subscription_item.page_orientation if subscription_item.page_size_option is not None: - subscription_element.attrib['pageSizeOption'] = subscription_item.page_size_option + subscription_element.attrib["pageSizeOption"] = subscription_item.page_size_option # Content element - content_element = ET.SubElement(subscription_element, 'content') - content_element.attrib['id'] = subscription_item.target.id - content_element.attrib['type'] = subscription_item.target.type + content_element = ET.SubElement(subscription_element, "content") + content_element.attrib["id"] = subscription_item.target.id + content_element.attrib["type"] = subscription_item.target.type if subscription_item.send_if_view_empty is not None: - content_element.attrib['sendIfViewEmpty'] = str(subscription_item.send_if_view_empty).lower() + content_element.attrib["sendIfViewEmpty"] = str(subscription_item.send_if_view_empty).lower() # Schedule element - schedule_element = ET.SubElement(subscription_element, 'schedule') - schedule_element.attrib['id'] = subscription_item.schedule_id + schedule_element = ET.SubElement(subscription_element, "schedule") + schedule_element.attrib["id"] = subscription_item.schedule_id # User element - user_element = ET.SubElement(subscription_element, 'user') - user_element.attrib['id'] = subscription_item.user_id + user_element = ET.SubElement(subscription_element, "user") + user_element.attrib["id"] = subscription_item.user_id return ET.tostring(xml_request) @_tsrequest_wrapped def update_req(self, xml_request, subscription_item): - subscription = ET.SubElement(xml_request, 'subscription') + subscription = ET.SubElement(xml_request, "subscription") # Main attributes if subscription_item.subject is not None: - subscription.attrib['subject'] = subscription_item.subject + subscription.attrib["subject"] = subscription_item.subject if subscription_item.attach_image is not None: - subscription.attrib['attachImage'] = str(subscription_item.attach_image).lower() + subscription.attrib["attachImage"] = str(subscription_item.attach_image).lower() if subscription_item.attach_pdf is not None: - subscription.attrib['attachPdf'] = str(subscription_item.attach_pdf).lower() + subscription.attrib["attachPdf"] = str(subscription_item.attach_pdf).lower() if subscription_item.page_orientation is not None: - subscription.attrib['pageOrientation'] = subscription_item.page_orientation + subscription.attrib["pageOrientation"] = subscription_item.page_orientation if subscription_item.page_size_option is not None: - subscription.attrib['pageSizeOption'] = subscription_item.page_size_option + subscription.attrib["pageSizeOption"] = subscription_item.page_size_option if subscription_item.suspended is not None: - subscription.attrib['suspended'] = str(subscription_item.suspended).lower() + subscription.attrib["suspended"] = str(subscription_item.suspended).lower() # Schedule element - schedule = ET.SubElement(subscription, 'schedule') + schedule = ET.SubElement(subscription, "schedule") if subscription_item.schedule_id is not None: - schedule.attrib['id'] = subscription_item.schedule_id + schedule.attrib["id"] = subscription_item.schedule_id # Content element - content = ET.SubElement(subscription, 'content') + content = ET.SubElement(subscription, "content") if subscription_item.send_if_view_empty is not None: - content.attrib['sendIfViewEmpty'] = str(subscription_item.send_if_view_empty).lower() + content.attrib["sendIfViewEmpty"] = str(subscription_item.send_if_view_empty).lower() return ET.tostring(xml_request) @@ -899,16 +911,16 @@ def empty_req(self, xml_request): class WebhookRequest(object): @_tsrequest_wrapped def create_req(self, xml_request, webhook_item): - webhook = ET.SubElement(xml_request, 'webhook') - webhook.attrib['name'] = webhook_item.name + webhook = ET.SubElement(xml_request, "webhook") + webhook.attrib["name"] = webhook_item.name - source = ET.SubElement(webhook, 'webhook-source') + source = ET.SubElement(webhook, "webhook-source") ET.SubElement(source, webhook_item._event) - destination = ET.SubElement(webhook, 'webhook-destination') - post = ET.SubElement(destination, 'webhook-destination-http') - post.attrib['method'] = 'POST' - post.attrib['url'] = webhook_item.url + destination = ET.SubElement(webhook, "webhook-destination") + post = ET.SubElement(destination, "webhook-destination-http") + post.attrib["method"] = "POST" + post.attrib["url"] = webhook_item.url return ET.tostring(xml_request) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index 22d0a4ef0..23d10b3d6 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -8,11 +8,11 @@ def apply_query_params(self, url): params = self.get_query_params() params_list = ["{}={}".format(k, v) for (k, v) in params.items()] - if '?' in url: - url, existing_params = url.split('?') + if "?" in url: + url, existing_params = url.split("?") params_list.append(existing_params) - return "{0}?{1}".format(url, '&'.join(params_list)) + return "{0}?{1}".format(url, "&".join(params_list)) except NotImplementedError: raise @@ -22,44 +22,44 @@ def get_query_params(self): class RequestOptions(RequestOptionsBase): class Operator: - Equals = 'eq' - GreaterThan = 'gt' - GreaterThanOrEqual = 'gte' - LessThan = 'lt' - LessThanOrEqual = 'lte' - In = 'in' - Has = 'has' + Equals = "eq" + GreaterThan = "gt" + GreaterThanOrEqual = "gte" + LessThan = "lt" + LessThanOrEqual = "lte" + In = "in" + Has = "has" class Field: - Args = 'args' - CompletedAt = 'completedAt' - CreatedAt = 'createdAt' - DomainName = 'domainName' - DomainNickname = 'domainNickname' - HitsTotal = 'hitsTotal' - IsLocal = 'isLocal' - JobType = 'jobType' - LastLogin = 'lastLogin' - MinimumSiteRole = 'minimumSiteRole' - Name = 'name' - Notes = 'notes' - OwnerDomain = 'ownerDomain' - OwnerEmail = 'ownerEmail' - OwnerName = 'ownerName' - Progress = 'progress' - ProjectName = 'projectName' - SiteRole = 'siteRole' - Subtitle = 'subtitle' - Tags = 'tags' - Title = 'title' - TopLevelProject = 'topLevelProject' - Type = 'type' - UpdatedAt = 'updatedAt' - UserCount = 'userCount' + Args = "args" + CompletedAt = "completedAt" + CreatedAt = "createdAt" + DomainName = "domainName" + DomainNickname = "domainNickname" + HitsTotal = "hitsTotal" + IsLocal = "isLocal" + JobType = "jobType" + LastLogin = "lastLogin" + MinimumSiteRole = "minimumSiteRole" + Name = "name" + Notes = "notes" + OwnerDomain = "ownerDomain" + OwnerEmail = "ownerEmail" + OwnerName = "ownerName" + Progress = "progress" + ProjectName = "projectName" + SiteRole = "siteRole" + Subtitle = "subtitle" + Tags = "tags" + Title = "title" + TopLevelProject = "topLevelProject" + Type = "type" + UpdatedAt = "updatedAt" + UserCount = "userCount" class Direction: - Desc = 'desc' - Asc = 'asc' + Desc = "desc" + Asc = "asc" def __init__(self, pagenumber=1, pagesize=100): self.pagenumber = pagenumber @@ -81,19 +81,19 @@ def page_number(self, page_number): def get_query_params(self): params = {} if self.pagenumber: - params['pageNumber'] = self.pagenumber + params["pageNumber"] = self.pagenumber if self.pagesize: - params['pageSize'] = self.pagesize + params["pageSize"] = self.pagesize if len(self.sort) > 0: sort_options = (str(sort_item) for sort_item in self.sort) ordered_sort_options = sorted(sort_options) - params['sort'] = ','.join(ordered_sort_options) + params["sort"] = ",".join(ordered_sort_options) if len(self.filter) > 0: filter_options = (str(filter_item) for filter_item in self.filter) ordered_filter_options = sorted(filter_options) - params['filter'] = ','.join(ordered_filter_options) + params["filter"] = ",".join(ordered_filter_options) if self._all_fields: - params['fields'] = '_all_' + params["fields"] = "_all_" return params @@ -112,7 +112,7 @@ def vf(self, name, value): def _append_view_filters(self, params): for name, value in self.view_filters: - params['vf_' + name] = value + params["vf_" + name] = value class CSVRequestOptions(_FilterOptionsBase): @@ -132,7 +132,7 @@ def max_age(self, value): def get_query_params(self): params = {} if self.max_age != -1: - params['maxAge'] = self.max_age + params["maxAge"] = self.max_age self._append_view_filters(params) return params @@ -141,7 +141,7 @@ def get_query_params(self): class ImageRequestOptions(_FilterOptionsBase): # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution class Resolution: - High = 'high' + High = "high" def __init__(self, imageresolution=None, maxage=-1): super(ImageRequestOptions, self).__init__() @@ -160,9 +160,9 @@ def max_age(self, value): def get_query_params(self): params = {} if self.image_resolution: - params['resolution'] = self.image_resolution + params["resolution"] = self.image_resolution if self.max_age != -1: - params['maxAge'] = self.max_age + params["maxAge"] = self.max_age self._append_view_filters(params) return params @@ -205,13 +205,13 @@ def max_age(self, value): def get_query_params(self): params = {} if self.page_type: - params['type'] = self.page_type + params["type"] = self.page_type if self.orientation: - params['orientation'] = self.orientation + params["orientation"] = self.orientation if self.max_age != -1: - params['maxAge'] = self.max_age + params["maxAge"] = self.max_age self._append_view_filters(params) diff --git a/tableauserverclient/server/server.py b/tableauserverclient/server/server.py index 6aff0c126..b45098e8a 100644 --- a/tableauserverclient/server/server.py +++ b/tableauserverclient/server/server.py @@ -2,9 +2,29 @@ from .exceptions import NotSignedInError from ..namespace import Namespace -from .endpoint import Sites, Views, Users, Groups, Workbooks, Datasources, Projects, Auth, \ - Schedules, ServerInfo, Tasks, Subscriptions, Jobs, Metadata,\ - Databases, Tables, Flows, Webhooks, DataAccelerationReport, Favorites, DataAlerts +from .endpoint import ( + Sites, + Views, + Users, + Groups, + Workbooks, + Datasources, + Projects, + Auth, + Schedules, + ServerInfo, + Tasks, + Subscriptions, + Jobs, + Metadata, + Databases, + Tables, + Flows, + Webhooks, + DataAccelerationReport, + Favorites, + DataAlerts, +) from .endpoint.exceptions import EndpointUnavailableError, ServerInfoEndpointNotFoundError import requests @@ -14,20 +34,14 @@ except ImportError: from distutils.version import LooseVersion as Version -_PRODUCT_TO_REST_VERSION = { - '10.0': '2.3', - '9.3': '2.2', - '9.2': '2.1', - '9.1': '2.0', - '9.0': '2.0' -} +_PRODUCT_TO_REST_VERSION = {"10.0": "2.3", "9.3": "2.2", "9.2": "2.1", "9.1": "2.0", "9.0": "2.0"} class Server(object): class PublishMode: - Append = 'Append' - Overwrite = 'Overwrite' - CreateNew = 'CreateNew' + Append = "Append" + Overwrite = "Overwrite" + CreateNew = "CreateNew" def __init__(self, server_address, use_server_version=False): self._server_address = server_address @@ -84,8 +98,8 @@ def _set_auth(self, site_id, user_id, auth_token): def _get_legacy_version(self): response = self._session.get(self.server_address + "/auth?format=xml") info_xml = ET.fromstring(response.content) - prod_version = info_xml.find('.//product_version').text - version = _PRODUCT_TO_REST_VERSION.get(prod_version, '2.1') # 2.1 + prod_version = info_xml.find(".//product_version").text + version = _PRODUCT_TO_REST_VERSION.get(prod_version, "2.1") # 2.1 return version def _determine_highest_version(self): @@ -107,6 +121,7 @@ def use_server_version(self): def use_highest_version(self): self.use_server_version() import warnings + warnings.warn("use use_server_version instead", DeprecationWarning) def assert_at_least_version(self, version): @@ -114,7 +129,8 @@ def assert_at_least_version(self, version): minimum_supported = Version(version) if server_version < minimum_supported: error = "This endpoint is not available in API version {}. Requires {}".format( - server_version, minimum_supported) + server_version, minimum_supported + ) raise EndpointUnavailableError(error) @property @@ -128,21 +144,21 @@ def namespace(self): @property def auth_token(self): if self._auth_token is None: - error = 'Missing authentication token. You must sign in first.' + error = "Missing authentication token. You must sign in first." raise NotSignedInError(error) return self._auth_token @property def site_id(self): if self._site_id is None: - error = 'Missing site ID. You must sign in first.' + error = "Missing site ID. You must sign in first." raise NotSignedInError(error) return self._site_id @property def user_id(self): if self._user_id is None: - error = 'Missing user ID. You must sign in first.' + error = "Missing user ID. You must sign in first." raise NotSignedInError(error) return self._user_id diff --git a/tableauserverclient/server/sort.py b/tableauserverclient/server/sort.py index f412b8aa3..2d6bc030a 100644 --- a/tableauserverclient/server/sort.py +++ b/tableauserverclient/server/sort.py @@ -4,4 +4,4 @@ def __init__(self, field, direction): self.direction = direction def __str__(self): - return '{0}:{1}'.format(self.field, self.direction) + return "{0}:{1}".format(self.field, self.direction)