Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ docs/_build/
# PyBuilder
target/

# PyCharm stuff
.idea/

# IPython Notebook
.ipynb_checkpoints

Expand Down
8 changes: 3 additions & 5 deletions tableauserverclient/models/datasource_item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import xml.etree.ElementTree as ET
from .exceptions import UnpopulatedPropertyError
from .property_decorators import property_not_nullable
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance the code feels ok, but I think there might be a better name than "property_decorator" which both have meanings of their own.

I'll do a more detailed review in a bit

from .tag_item import TagItem
from .. import NAMESPACE

Expand Down Expand Up @@ -45,12 +46,9 @@ def project_id(self):
return self._project_id

@project_id.setter
@property_not_nullable
def project_id(self, value):
if value is None:
error = 'Project ID must be defined.'
raise ValueError(error)
else:
self._project_id = value
self._project_id = value

@property
def project_name(self):
Expand Down
8 changes: 3 additions & 5 deletions tableauserverclient/models/group_item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import xml.etree.ElementTree as ET
from .exceptions import UnpopulatedPropertyError
from .property_decorators import property_not_empty
from .. import NAMESPACE


Expand All @@ -26,12 +27,9 @@ def name(self):
return self._name

@name.setter
@property_not_empty
def name(self, value):
if not value:
error = 'Name must be defined.'
raise ValueError(error)
else:
self._name = value
self._name = value

@property
def users(self):
Expand Down
15 changes: 5 additions & 10 deletions tableauserverclient/models/project_item.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import xml.etree.ElementTree as ET
from .property_decorators import property_is_enum, property_not_empty
from .. import NAMESPACE


Expand Down Expand Up @@ -26,12 +27,9 @@ def content_permissions(self):
return self._content_permissions

@content_permissions.setter
@property_is_enum(ContentPermissions)
def content_permissions(self, value):
if value and not hasattr(ProjectItem.ContentPermissions, value):
error = 'Invalid content permission defined.'
raise ValueError(error)
else:
self._content_permissions = value
self._content_permissions = value

@property
def id(self):
Expand All @@ -42,12 +40,9 @@ def name(self):
return self._name

@name.setter
@property_not_empty
def name(self, value):
if not value:
error = 'Name must be defined.'
raise ValueError(error)
else:
self._name = value
self._name = value

def is_default(self):
return self.name.lower() == 'default'
Expand Down
48 changes: 48 additions & 0 deletions tableauserverclient/models/property_decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from functools import wraps


def property_is_enum(enum_type):
def property_type_decorator(func):
@wraps(func)
def wrapper(self, value):
if value is not None and not hasattr(enum_type, value):
error = "Invalid value: {0}. {1} must be of type {2}.".format(value, func.__name__, enum_type.__name__)
raise ValueError(error)
return func(self, value)

return wrapper

return property_type_decorator


def property_is_boolean(func):
@wraps(func)
def wrapper(self, value):
if not isinstance(value, bool):
error = "Boolean expected for {0} flag.".format(func.__name__)
raise ValueError(error)
return func(self, value)

return wrapper


def property_not_nullable(func):
@wraps(func)
def wrapper(self, value):
if value is None:
error = "{0} must be defined.".format(func.__name__)
raise ValueError(error)
return func(self, value)

return wrapper


def property_not_empty(func):
@wraps(func)
def wrapper(self, value):
if not value:
error = "{0} must not be empty.".format(func.__name__)
raise ValueError(error)
return func(self, value)

return wrapper
50 changes: 15 additions & 35 deletions tableauserverclient/models/site_item.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import xml.etree.ElementTree as ET
from .property_decorators import property_is_enum, property_is_boolean, property_not_empty, property_not_nullable
from .. import NAMESPACE


Expand Down Expand Up @@ -45,36 +46,27 @@ def admin_mode(self):
return self._admin_mode

@admin_mode.setter
@property_is_enum(AdminMode)
def admin_mode(self, value):
if value and not hasattr(SiteItem.AdminMode, value):
error = 'Invalid admin mode defined.'
raise ValueError(error)
else:
self._admin_mode = value
self._admin_mode = value

@property
def content_url(self):
return self._content_url

@content_url.setter
@property_not_nullable
def content_url(self, value):
if value is None:
error = 'Content URL must be defined.'
raise ValueError(error)
else:
self._content_url = value
self._content_url = value

@property
def disable_subscriptions(self):
return self._disable_subscriptions

@disable_subscriptions.setter
@property_is_boolean
def disable_subscriptions(self, value):
if not isinstance(value, bool):
error = 'Boolean expected for disable_subscriptions flag.'
raise ValueError(error)
else:
self._disable_subscriptions = value
self._disable_subscriptions = value

@property
def id(self):
Expand All @@ -85,12 +77,9 @@ def name(self):
return self._name

@name.setter
@property_not_empty
def name(self, value):
if not value:
error = 'Name must be defined.'
raise ValueError(error)
else:
self._name = value
self._name = value

@property
def num_users(self):
Expand All @@ -101,24 +90,18 @@ def revision_history_enabled(self):
return self._revision_history_enabled

@revision_history_enabled.setter
@property_is_boolean
def revision_history_enabled(self, value):
if not isinstance(value, bool):
error = 'Boolean expected for revision_history_enabled flag.'
raise ValueError(error)
else:
self._revision_history_enabled = value
self._revision_history_enabled = value

@property
def state(self):
return self._state

@state.setter
@property_is_enum(State)
def state(self, value):
if not hasattr(SiteItem.State, value):
error = 'Invalid state defined.'
raise ValueError(error)
else:
self._state = value
self._state = value

@property
def status_reason(self):
Expand All @@ -133,12 +116,9 @@ def subscribe_others_enabled(self):
return self._subscribe_others_enabled

@subscribe_others_enabled.setter
@property_is_boolean
def subscribe_others_enabled(self, value):
if not isinstance(value, bool):
error = 'Boolean expected for subscribe_others_enabled flag.'
raise ValueError(error)
else:
self._subscribe_others_enabled = value
self._subscribe_others_enabled = value

def is_default(self):
return self.name.lower() == 'default'
Expand Down
26 changes: 8 additions & 18 deletions tableauserverclient/models/user_item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import xml.etree.ElementTree as ET
from .exceptions import UnpopulatedPropertyError
from .property_decorators import property_is_enum, property_not_empty, property_not_nullable
from .. import NAMESPACE


Expand Down Expand Up @@ -45,12 +46,9 @@ def auth_setting(self):
return self._auth_setting

@auth_setting.setter
@property_is_enum(Auth)
def auth_setting(self, value):
if not hasattr(UserItem.Auth, value):
error = 'Invalid auth setting defined.'
raise ValueError(error)
else:
self._auth_setting = value
self._auth_setting = value

@property
def domain_name(self):
Expand All @@ -73,27 +71,19 @@ def name(self):
return self._name

@name.setter
@property_not_empty
def name(self, value):
if not value:
error = 'Name must be defined.'
raise ValueError(error)
else:
self._name = value
self._name = value

@property
def site_role(self):
return self._site_role

@site_role.setter
@property_not_nullable
@property_is_enum(Roles)
def site_role(self, value):
if not value:
error = 'Site role must be defined.'
raise ValueError(error)
elif not hasattr(UserItem.Roles, value):
error = 'Invalid site role defined.'
raise ValueError(error)
else:
self._site_role = value
self._site_role = value

@property
def workbooks(self):
Expand Down
15 changes: 5 additions & 10 deletions tableauserverclient/models/workbook_item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import xml.etree.ElementTree as ET
from .exceptions import UnpopulatedPropertyError
from .property_decorators import property_not_nullable, property_is_boolean
from .tag_item import TagItem
from .view_item import ViewItem
from .. import NAMESPACE
Expand Down Expand Up @@ -59,12 +60,9 @@ def project_id(self):
return self._project_id

@project_id.setter
@property_not_nullable
def project_id(self, value):
if value is None:
error = 'Project ID must be defined.'
raise ValueError(error)
else:
self._project_id = value
self._project_id = value

@property
def project_name(self):
Expand All @@ -75,12 +73,9 @@ def show_tabs(self):
return self._show_tabs

@show_tabs.setter
@property_is_boolean
def show_tabs(self, value):
if not isinstance(value, bool):
error = 'Boolean expected for show tabs flag.'
raise ValueError(error)
else:
self._show_tabs = value
self._show_tabs = value

@property
def size(self):
Expand Down
10 changes: 10 additions & 0 deletions test/test_datasource_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import unittest
import tableauserverclient as TSC


class DatasourceModelTests(unittest.TestCase):
def test_invalid_project_id(self):
self.assertRaises(ValueError, TSC.DatasourceItem, None)
datasource = TSC.DatasourceItem("10")
with self.assertRaises(ValueError):
datasource.project_id = None
14 changes: 14 additions & 0 deletions test/test_group_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import unittest
import tableauserverclient as TSC


class GroupModelTests(unittest.TestCase):
def test_invalid_name(self):
self.assertRaises(ValueError, TSC.GroupItem, None)
self.assertRaises(ValueError, TSC.GroupItem, "")
group = TSC.GroupItem("grp")
with self.assertRaises(ValueError):
group.name = None

with self.assertRaises(ValueError):
group.name = ""
19 changes: 19 additions & 0 deletions test/test_project_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import unittest
import tableauserverclient as TSC


class ProjectModelTests(unittest.TestCase):
def test_invalid_name(self):
self.assertRaises(ValueError, TSC.ProjectItem, None)
self.assertRaises(ValueError, TSC.ProjectItem, "")
project = TSC.ProjectItem("proj")
with self.assertRaises(ValueError):
project.name = None

with self.assertRaises(ValueError):
project.name = ""

def test_invalid_content_permissions(self):
project = TSC.ProjectItem("proj")
with self.assertRaises(ValueError):
project.content_permissions = "Hello"
Loading