Skip to content

Commit

Permalink
Release 0.6 (#126)
Browse files Browse the repository at this point in the history
* Fix #117 by only attempting files with the right extension inside the archive (#118)

* Commenting and Docstring cleanup. A few very small code cleanups (#120)

Add docstrings and remove clutter. I also made some very tiny tweaks to some code for clarity.

* Small cleanups for various editors. Play nice with built in test-runners (#121)

* Add Py36, update travis to use pycodestyle (#124)

* Add `initial sql` and `query band` support (#123)

Addresses #109 and #110

* Prep for release of 0.6 (#125)

* Prep for release of 0.6

* wordsmithing the changelog
  • Loading branch information
Russell Hay authored Jan 11, 2017
1 parent 8029b4f commit 65fbc80
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 109 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,11 @@ target/
.DS_Store
.idea

#Editor things
*.sublime-project
*.sublime-workspace
settings.json
tasks.json

#Jekyll
docs/_site
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ python:
- "3.3"
- "3.4"
- "3.5"
- "3.6"
- "pypy"
# command to install dependencies
install:
- "pip install -e ."
- "pip install pep8"
- "pip install pycodestyle"
# command to run tests
script:
# Tests
- python setup.py test
# pep8
- pep8 .
# pycodestyle
- pycodestyle tableaudocumentapi test samples
# Examples
- (cd "samples/replicate-workbook" && python replicate_workbook.py)
- (cd "samples/list-tds-info" && python list_tds_info.py)
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 06 (11 January 2017)

* Initial SQL and query banding support (#123)
* Fixed bug in xfiles to allow opening workbooks with external file caches (#117, #118)
* Code Cleanup (#120, #121)
* Added Py36 support (#124)
* Switched to pycodestyle from pip8 on travis runs (#124)

## 05 (01 November 2016)

* Added ability to set the port for connections (#97)
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The following people have contributed to this project to make it possible, and w

* [Charley Peng](https://github.com/chid)
* [Miguel Sánchez](https://github.com/MiguelSR)
* [Ryan Richmond](https://github.com/r-richmond)

## Core Team

Expand Down
24 changes: 24 additions & 0 deletions docs/docs/api-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ class Datasource(dsxml, filename=None)
class Connection(connxml)
```

The Connection class represents a tableau data connection. It can be from any type of connection found in `dbclass.py` via `is_valid_dbclass`

**Params:**

**Raises:**

**Methods:**

**Properities:**

`self.server:` Returns a string containing the server.

`self.dbname:` Returns a string containing the database name.

`self.username:` Returns a string containing the username.

`self.dbclass:` Returns a string containing the database class.

`self.port:` Returns a string containing the port.

`self.query_band:` Returns a string containing the query band.

`self.initial_sql:` Returns a string containing the initial sql.

## Fields
```python
class Workbook(column_xml=None, metadata_xml=None)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name='tableaudocumentapi',
version='0.5',
version='0.6',
author='Tableau',
author_email='[email protected]',
url='https://github.com/tableau/document-api-python',
Expand Down
124 changes: 88 additions & 36 deletions tableaudocumentapi/connection.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
###############################################################################
#
# Connection - A class for writing connections to Tableau files
#
###############################################################################
import xml.etree.ElementTree as ET
from tableaudocumentapi.dbclass import is_valid_dbclass


class Connection(object):
"""
A class for writing connections to Tableau files.
"""

###########################################################################
#
# Public API.
#
###########################################################################
"""A class representing connections inside Data Sources."""

def __init__(self, connxml):
"""
Constructor.
"""Connection is usually instantiated by passing in connection elements
in a Data Source. If creating a connection from scratch you can call
`from_attributes` passing in the connection attributes.
"""
self._connectionXML = connxml
Expand All @@ -31,27 +18,33 @@ def __init__(self, connxml):
self._authentication = connxml.get('authentication')
self._class = connxml.get('class')
self._port = connxml.get('port', None)
self._query_band = connxml.get('query-band-spec', None)
self._initial_sql = connxml.get('one-time-sql', None)

def __repr__(self):
return "'<Connection server='{}' dbname='{}' @ {}>'".format(self._server, self._dbname, hex(id(self)))

@classmethod
def from_attributes(cls, server, dbname, username, dbclass, port=None, authentication=''):
def from_attributes(cls, server, dbname, username, dbclass, port=None, query_band=None,
initial_sql=None, authentication=''):
"""Creates a new connection that can be added into a Data Source.
defaults to `''` which will be treated as 'prompt' by Tableau."""

root = ET.Element('connection', authentication=authentication)
xml = cls(root)
xml.server = server
xml.dbname = dbname
xml.username = username
xml.dbclass = dbclass
xml.port = port
xml.query_band = query_band
xml.initial_sql = initial_sql

return xml

###########
# dbname
###########
@property
def dbname(self):
"""Database name for the connection. Not the table name."""
return self._dbname

@dbname.setter
Expand All @@ -69,11 +62,9 @@ def dbname(self, value):
self._dbname = value
self._connectionXML.set('dbname', value)

###########
# server
###########
@property
def server(self):
"""Hostname or IP address of the database server. May also be a URL in some connection types."""
return self._server

@server.setter
Expand All @@ -91,11 +82,9 @@ def server(self, value):
self._server = value
self._connectionXML.set('server', value)

###########
# username
###########
@property
def username(self):
"""Username used to authenticate to the database."""
return self._username

@username.setter
Expand All @@ -113,38 +102,49 @@ def username(self, value):
self._username = value
self._connectionXML.set('username', value)

###########
# authentication
###########
@property
def authentication(self):
return self._authentication

###########
# dbclass
###########
@property
def dbclass(self):
"""The type of connection (e.g. 'MySQL', 'Postgresql'). A complete list
can be found in dbclass.py"""
return self._class

@dbclass.setter
def dbclass(self, value):
"""Set the connection's dbclass property.
Args:
value: New dbclass value. String.
Returns:
Nothing.
"""

if not is_valid_dbclass(value):
raise AttributeError("'{}' is not a valid database type".format(value))

self._class = value
self._connectionXML.set('class', value)

###########
# port
###########
@property
def port(self):
"""Port used to connect to the database."""
return self._port

@port.setter
def port(self, value):
"""Set the connection's port property.
Args:
value: New port value. String.
Returns:
Nothing.
"""

self._port = value
# If port is None we remove the element and don't write it to XML
if value is None:
Expand All @@ -154,3 +154,55 @@ def port(self, value):
pass
else:
self._connectionXML.set('port', value)

@property
def query_band(self):
"""Query band passed on connection to database."""
return self._query_band

@query_band.setter
def query_band(self, value):
"""Set the connection's query_band property.
Args:
value: New query_band value. String.
Returns:
Nothing.
"""

self._query_band = value
# If query band is None we remove the element and don't write it to XML
if value is None:
try:
del self._connectionXML.attrib['query-band-spec']
except KeyError:
pass
else:
self._connectionXML.set('query-band-spec', value)

@property
def initial_sql(self):
"""Initial SQL to be run."""
return self._initial_sql

@initial_sql.setter
def initial_sql(self, value):
"""Set the connection's initial_sql property.
Args:
value: New initial_sql value. String.
Returns:
Nothing.
"""

self._initial_sql = value
# If initial_sql is None we remove the element and don't write it to XML
if value is None:
try:
del self._connectionXML.attrib['one-time-sql']
except KeyError:
pass
else:
self._connectionXML.set('one-time-sql', value)
Loading

0 comments on commit 65fbc80

Please sign in to comment.