| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,3 @@ | ||
| ############################################################################### | ||
| # | ||
| # Datasource - A class for writing datasources to Tableau files | ||
| # | ||
| ############################################################################### | ||
| import collections | ||
| import itertools | ||
| import xml.etree.ElementTree as ET | ||
| Expand All | @@ -16,7 +11,7 @@ | |
|
|
||
| ######## | ||
| # This is needed in order to determine if something is a string or not. It is necessary because | ||
| # of differences between python2 (basestring) and python3 (str). If python2 support is every | ||
| # of differences between python2 (basestring) and python3 (str). If python2 support is ever | ||
| # dropped, remove this and change the basestring references below to str | ||
| try: | ||
| basestring | ||
| Expand All | @@ -35,7 +30,7 @@ def _get_metadata_xml_for_field(root_xml, field_name): | |
|
|
||
|
|
||
| def _is_used_by_worksheet(names, field): | ||
| return any((y for y in names if y in field.worksheets)) | ||
| return any(y for y in names if y in field.worksheets) | ||
|
|
||
|
|
||
| class FieldDictionary(MultiLookupDict): | ||
| Expand Down Expand Up | @@ -87,27 +82,32 @@ def base36encode(number): | |
| return sign + base36 | ||
|
|
||
|
|
||
| def make_unique_name(dbclass): | ||
| def _make_unique_name(dbclass): | ||
| rand_part = base36encode(uuid4().int) | ||
| name = dbclass + '.' + rand_part | ||
| return name | ||
|
|
||
|
|
||
| class ConnectionParser(object): | ||
| """Parser for detecting and extracting connections from differing Tableau file formats.""" | ||
|
|
||
| def __init__(self, datasource_xml, version): | ||
| self._dsxml = datasource_xml | ||
| self._dsversion = version | ||
|
|
||
| def _extract_federated_connections(self): | ||
| connections = list(map(Connection, self._dsxml.findall('.//named-connections/named-connection/*'))) | ||
| # 'sqlproxy' connections (Tableau Server Connections) are not embedded into named-connection elements | ||
| # extract them manually for now | ||
| connections.extend(map(Connection, self._dsxml.findall("./connection[@class='sqlproxy']"))) | ||
| return connections | ||
|
|
||
| def _extract_legacy_connection(self): | ||
| return list(map(Connection, self._dsxml.findall('connection'))) | ||
|
|
||
| def get_connections(self): | ||
| """Find and return all connections based on file format version.""" | ||
|
|
||
| if float(self._dsversion) < 10: | ||
| connections = self._extract_legacy_connection() | ||
| else: | ||
| Expand All | @@ -116,16 +116,11 @@ def get_connections(self): | |
|
|
||
|
|
||
| class Datasource(object): | ||
| """ | ||
| A class for writing datasources to Tableau files. | ||
| """A class representing Tableau Data Sources, embedded in workbook files or | ||
| in TDS files. | ||
|
|
||
| """ | ||
|
|
||
| ########################################################################### | ||
| # | ||
| # Public API. | ||
| # | ||
| ########################################################################### | ||
| def __init__(self, dsxml, filename=None): | ||
| """ | ||
| Constructor. Default is to create datasource from xml. | ||
| Expand All | @@ -145,21 +140,23 @@ def __init__(self, dsxml, filename=None): | |
|
|
||
| @classmethod | ||
| def from_file(cls, filename): | ||
| """Initialize datasource from file (.tds)""" | ||
| """Initialize datasource from file (.tds ot .tdsx)""" | ||
|
|
||
| dsxml = xml_open(filename, cls.__name__.lower()).getroot() | ||
| dsxml = xml_open(filename, 'datasource').getroot() | ||
|
Comment thread
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI realized that this was actually less readable than just making it a literal string, which removed the need for the comment "#Gets the name of the class and normalizes it so it can verify the file it opens"
Sorry, something went wrong.
All reactions
|
||
| return cls(dsxml, filename) | ||
|
|
||
| @classmethod | ||
| def from_connections(cls, caption, connections): | ||
| """Create a new Data Source give a list of Connections.""" | ||
|
|
||
| root = ET.Element('datasource', caption=caption, version='10.0', inline='true') | ||
| outer_connection = ET.SubElement(root, 'connection') | ||
| outer_connection.set('class', 'federated') | ||
| named_conns = ET.SubElement(outer_connection, 'named-connections') | ||
| for conn in connections: | ||
| nc = ET.SubElement(named_conns, | ||
| 'named-connection', | ||
| name=make_unique_name(conn.dbclass), | ||
| name=_make_unique_name(conn.dbclass), | ||
| caption=conn.server) | ||
| nc.append(conn._connectionXML) | ||
| return cls(root) | ||
| Expand Down Expand Up | @@ -194,16 +191,10 @@ def save_as(self, new_filename): | |
|
|
||
| xfile._save_file(self._filename, self._datasourceTree, new_filename) | ||
|
|
||
| ########### | ||
| # name | ||
| ########### | ||
| @property | ||
| def name(self): | ||
| return self._name | ||
|
|
||
| ########### | ||
| # version | ||
| ########### | ||
| @property | ||
| def version(self): | ||
| return self._version | ||
| Expand All | @@ -222,9 +213,6 @@ def caption(self): | |
| del self._datasourceXML.attrib['caption'] | ||
| self._caption = '' | ||
|
|
||
| ########### | ||
| # connections | ||
| ########### | ||
| @property | ||
| def connections(self): | ||
| return self._connections | ||
| Expand All | @@ -234,16 +222,15 @@ def clear_repository_location(self): | |
| if tag is not None: | ||
| self._datasourceXML.remove(tag) | ||
|
|
||
| ########### | ||
| # fields | ||
| ########### | ||
| @property | ||
| def fields(self): | ||
| if not self._fields: | ||
| self._fields = self._get_all_fields() | ||
| return self._fields | ||
|
|
||
| def _get_all_fields(self): | ||
| # Some columns are represented by `column` tags and others as `metadata-record` tags | ||
| # Find them all and chain them into one dictionary | ||
| column_field_objects = self._get_column_objects() | ||
| existing_column_fields = [x.id for x in column_field_objects] | ||
| metadata_only_field_objects = (x for x in self._get_metadata_objects() if x.id not in existing_column_fields) | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis shouldn't ever be called outside of the class so I made it private.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.