Skip to content
New issue

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

Adding Schedules Support Round 2 #48

Merged
merged 17 commits into from Oct 7, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 67 additions & 0 deletions samples/create_schedules.py
@@ -0,0 +1,67 @@
####
# This script demonstrates how to create schedules using the Tableau
# Server Client.
#
# To run the script, you must have installed Python 2.7.9 or later.
####


import argparse
import getpass
import logging

from datetime import time

import tableauserverclient as TSC


def main():

parser = argparse.ArgumentParser(description='Creates sample schedules for each type of frequency.')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
help='desired logging level (set to error by default)')
args = parser.parse_args()

password = getpass.getpass("Password: ")

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
logging.basicConfig(level=logging_level)

tableau_auth = TSC.TableauAuth(args.username, password)
server = TSC.Server(args.server)
with server.auth.sign_in(tableau_auth):
# Hourly Schedule
hourly_interval = TSC.IntervalItem.create_hourly(time(2, 30), time(23, 0), TSC.IntervalItem.Occurrence.Hours, 2)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yikes, I need to update these now :)

(I wonder if we can find a way to run these, either in a local task, or in travis somehow)

hourly_schedule = TSC.ScheduleItem("Hourly-Schedule", 50, TSC.ScheduleItem.Type.Extract,
TSC.ScheduleItem.ExecutionOrder.Parallel, hourly_interval)
hourly_schedule = server.schedules.create(hourly_schedule)
print("Hourly schedule created (ID: {}).".format(hourly_schedule.id))

# Daily Schedule
daily_interval = TSC.IntervalItem.create_daily(time(5))
daily_schedule = TSC.ScheduleItem("Daily-Schedule", 60, TSC.ScheduleItem.Type.Subscription,
TSC.ScheduleItem.ExecutionOrder.Serial, daily_interval)
daily_schedule = server.schedules.create(daily_schedule)
print("Daily schedule created (ID: {}).".format(daily_schedule.id))

# Weekly Schedule
weekly_interval = TSC.IntervalItem.create_weekly(time(19, 15), TSC.IntervalItem.Day.Monday,
TSC.IntervalItem.Day.Wednesday, TSC.IntervalItem.Day.Friday)
weekly_schedule = TSC.ScheduleItem("Weekly-Schedule", 70, TSC.ScheduleItem.Type.Extract,
TSC.ScheduleItem.ExecutionOrder.Serial, weekly_interval)
weekly_schedule = server.schedules.create(weekly_schedule)
print("Weekly schedule created (ID: {}).".format(weekly_schedule.id))

# Monthly Schedule
monthly_interval = TSC.IntervalItem.create_monthly(time(23, 30), 15)
monthly_schedule = TSC.ScheduleItem("Monthly-Schedule", 80, TSC.ScheduleItem.Type.Subscription,
TSC.ScheduleItem.ExecutionOrder.Parallel, monthly_interval)
monthly_schedule = server.schedules.create(monthly_schedule)
print("Monthly schedule created (ID: {}).".format(monthly_schedule.id))


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion tableauserverclient/__init__.py
@@ -1,6 +1,6 @@
from .namespace import NAMESPACE
from .models import ConnectionItem, DatasourceItem,\
GroupItem, PaginationItem, ProjectItem, \
GroupItem, IntervalItem, PaginationItem, ProjectItem, ScheduleItem, \
SiteItem, TableauAuth, UserItem, ViewItem, WorkbookItem, UnpopulatedPropertyError
from .server import RequestOptions, Filter, Sort, Server, ServerResponseError,\
MissingRequiredFieldError, NotSignedInError
Expand Down
2 changes: 2 additions & 0 deletions tableauserverclient/models/__init__.py
Expand Up @@ -2,8 +2,10 @@
from .datasource_item import DatasourceItem
from .exceptions import UnpopulatedPropertyError
from .group_item import GroupItem
from .interval_item import IntervalItem
from .pagination_item import PaginationItem
from .project_item import ProjectItem
from .schedule_item import ScheduleItem
from .site_item import SiteItem
from .tableau_auth import TableauAuth
from .user_item import UserItem
Expand Down
101 changes: 101 additions & 0 deletions tableauserverclient/models/interval_item.py
@@ -0,0 +1,101 @@
import xml.etree.ElementTree as ET
from datetime import datetime
from .. import NAMESPACE


class IntervalItem(object):
class Frequency:
Hourly = "Hourly"
Daily = "Daily"
Weekly = "Weekly"
Monthly = "Monthly"

class Occurrence:
Hours = "Hours"
Minutes = "Minutes"
WeekDay = "weekDay"
MonthDay = "monthDay"

class Day:
Sunday = "Sunday"
Monday = "Monday"
Tuesday = "Tuesday"
Wednesday = "Wednesday"
Thursday = "Thursday"
Friday = "Friday"
Saturday = "Saturday"
LastDay = "LastDay"

def __init__(self, frequency, interval, start_time, end_time=None):
self.end_time = end_time
self.frequency = frequency
self.interval = interval
self.start_time = start_time

@staticmethod
def _validate_time(t):
units_of_time = {"hour", "minute", "second"}

if not any(hasattr(t, unit) for unit in units_of_time):
error = "Invalid time object defined."
raise ValueError(error)

@classmethod
def create_hourly(cls, start_time, end_time, interval_occurrence, interval_value):
if interval_occurrence != IntervalItem.Occurrence.Hours and \
interval_occurrence != IntervalItem.Occurrence.Minutes:
error = "Invalid interval type defined: {}.".format(interval_occurrence)
raise ValueError(error)
elif interval_occurrence == IntervalItem.Occurrence.Hours and interval_value not in [1, 2, 4, 6, 8, 12]:
error = "Invalid hour value defined: {}.".format(interval_value)
raise ValueError(error)
elif interval_occurrence == IntervalItem.Occurrence.Minutes and interval_value not in [15, 30]:
error = "Invalid minute value defined: {}".format(interval_value)
raise ValueError(error)

cls._validate_time(start_time)
cls._validate_time(end_time)
interval = [(interval_occurrence.lower(), str(interval_value))]
return cls(IntervalItem.Frequency.Hourly, interval, start_time, end_time)

@classmethod
def create_daily(cls, start_time):
cls._validate_time(start_time)
return cls(IntervalItem.Frequency.Daily, None, start_time)

@classmethod
def create_weekly(cls, start_time, *interval_value):
interval = []
for day in interval_value:
if not hasattr(IntervalItem.Day, day):
error = "Invalid week day defined: {}.".format(day)
raise ValueError(error)
interval.append((IntervalItem.Occurrence.WeekDay, day))
cls._validate_time(start_time)
return cls(IntervalItem.Frequency.Weekly, interval, start_time)

@classmethod
def create_monthly(cls, start_time, interval_value):
if (interval_value < 1 or interval_value > 31) and interval_value != IntervalItem.Day.LastDay:
error = "Invalid interval value defined for a monthly frequency: {}.".format(interval_value)
raise ValueError(error)
interval = [(IntervalItem.Occurrence.MonthDay, str(interval_value))]
cls._validate_time(start_time)
return cls(IntervalItem.Frequency.Monthly, interval, start_time)

@classmethod
def from_response(cls, resp, frequency):
cls.from_xml_element(ET.fromstring(resp), frequency)

@classmethod
def from_xml_element(cls, parsed_response, frequency):
start_time = parsed_response.get("start", None)
start_time = datetime.strptime(start_time, "%H:%M:%S").time()
end_time = parsed_response.get("end", None)
if end_time is not None:
end_time = datetime.strptime(end_time, "%H:%M:%S").time()
interval_elems = parsed_response.findall(".//t:intervals/t:interval", namespaces=NAMESPACE)
interval = []
for interval_elem in interval_elems:
interval.extend(interval_elem.attrib.items())
return cls(frequency, interval, start_time, end_time)