Skip to content

Commit 2373133

Browse files
jorwoodsjacalata
authored andcommitted
Add type hints for schedules (#969)
* Add type hints for schedules * Squashed commit of the following: commit b836f33 Author: Brian Cantoni <bcantoni@salesforce.com> Date: Thu Jan 27 19:29:50 2022 -0800 WIP: Enable Black for CI and add as dependency (#935) * Enable Black for CI and add as dependency * Bulk reformat with Black, line length 120 * Update interval_item.py fixing DailyInterval has no attribute 'interval'
1 parent 9c3efd1 commit 2373133

File tree

5 files changed

+98
-65
lines changed

5 files changed

+98
-65
lines changed

tableauserverclient/models/interval_item.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ def _interval_type_pairs(self):
8484

8585

8686
class DailyInterval(object):
87-
def __init__(self, start_time):
87+
def __init__(self, start_time, *interval_values):
8888
self.start_time = start_time
89+
self.interval = interval_values
8990

9091
@property
9192
def _frequency(self):
@@ -101,6 +102,14 @@ def start_time(self):
101102
def start_time(self, value):
102103
self._start_time = value
103104

105+
@property
106+
def interval(self):
107+
return self._interval
108+
109+
@interval.setter
110+
def interval(self, interval):
111+
self._interval = interval
112+
104113

105114
class WeeklyInterval(object):
106115
def __init__(self, start_time, *interval_values):

tableauserverclient/models/schedule_item.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import xml.etree.ElementTree as ET
22
from datetime import datetime
3+
from typing import Optional, Union
34

45
from .interval_item import (
56
IntervalItem,
@@ -15,6 +16,8 @@
1516
)
1617
from ..datetime_helpers import parse_datetime
1718

19+
Interval = Union[HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval]
20+
1821

1922
class ScheduleItem(object):
2023
class Type:
@@ -31,86 +34,86 @@ class State:
3134
Active = "Active"
3235
Suspended = "Suspended"
3336

34-
def __init__(self, name, priority, schedule_type, execution_order, interval_item):
35-
self._created_at = None
36-
self._end_schedule_at = None
37-
self._id = None
38-
self._next_run_at = None
39-
self._state = None
40-
self._updated_at = None
41-
self.interval_item = interval_item
42-
self.execution_order = execution_order
43-
self.name = name
44-
self.priority = priority
45-
self.schedule_type = schedule_type
37+
def __init__(self, name: str, priority: int, schedule_type: str, execution_order: str, interval_item: Interval):
38+
self._created_at: Optional[datetime] = None
39+
self._end_schedule_at: Optional[datetime] = None
40+
self._id: Optional[str] = None
41+
self._next_run_at: Optional[datetime] = None
42+
self._state: Optional[str] = None
43+
self._updated_at: Optional[datetime] = None
44+
self.interval_item: Interval = interval_item
45+
self.execution_order: str = execution_order
46+
self.name: str = name
47+
self.priority: int = priority
48+
self.schedule_type: str = schedule_type
4649

4750
def __repr__(self):
48-
return '<Schedule#{_id} "{_name}" {interval_item}>'.format(**self.__dict__)
51+
return '<Schedule#{_id} "{_name}" {interval_item}>'.format(**vars(self))
4952

5053
@property
51-
def created_at(self):
54+
def created_at(self) -> Optional[datetime]:
5255
return self._created_at
5356

5457
@property
55-
def end_schedule_at(self):
58+
def end_schedule_at(self) -> Optional[datetime]:
5659
return self._end_schedule_at
5760

5861
@property
59-
def execution_order(self):
62+
def execution_order(self) -> str:
6063
return self._execution_order
6164

6265
@execution_order.setter
6366
@property_is_enum(ExecutionOrder)
64-
def execution_order(self, value):
67+
def execution_order(self, value: str):
6568
self._execution_order = value
6669

6770
@property
68-
def id(self):
71+
def id(self) -> Optional[str]:
6972
return self._id
7073

7174
@property
72-
def name(self):
75+
def name(self) -> str:
7376
return self._name
7477

7578
@name.setter
7679
@property_not_nullable
77-
def name(self, value):
80+
def name(self, value: str):
7881
self._name = value
7982

8083
@property
81-
def next_run_at(self):
84+
def next_run_at(self) -> Optional[datetime]:
8285
return self._next_run_at
8386

8487
@property
85-
def priority(self):
88+
def priority(self) -> int:
8689
return self._priority
8790

8891
@priority.setter
8992
@property_is_int(range=(1, 100))
90-
def priority(self, value):
93+
def priority(self, value: int):
9194
self._priority = value
9295

9396
@property
94-
def schedule_type(self):
97+
def schedule_type(self) -> str:
9598
return self._schedule_type
9699

97100
@schedule_type.setter
98101
@property_is_enum(Type)
99102
@property_not_nullable
100-
def schedule_type(self, value):
103+
def schedule_type(self, value: str):
101104
self._schedule_type = value
102105

103106
@property
104-
def state(self):
107+
def state(self) -> Optional[str]:
105108
return self._state
106109

107110
@state.setter
108111
@property_is_enum(State)
109-
def state(self, value):
112+
def state(self, value: str):
110113
self._state = value
111114

112115
@property
113-
def updated_at(self):
116+
def updated_at(self) -> Optional[datetime]:
114117
return self._updated_at
115118

116119
@property

tableauserverclient/server/endpoint/schedules_endpoint.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,29 @@
44
import logging
55
import copy
66
from collections import namedtuple
7+
from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union
78

89
logger = logging.getLogger("tableau.endpoint.schedules")
910
# Oh to have a first class Result concept in Python...
1011
AddResponse = namedtuple("AddResponse", ("result", "error", "warnings", "task_created"))
1112
OK = AddResponse(result=True, error=None, warnings=None, task_created=None)
1213

14+
if TYPE_CHECKING:
15+
from ..request_options import RequestOptions
16+
from ...models import DatasourceItem, WorkbookItem
17+
1318

1419
class Schedules(Endpoint):
1520
@property
16-
def baseurl(self):
21+
def baseurl(self) -> str:
1722
return "{0}/schedules".format(self.parent_srv.baseurl)
1823

1924
@property
20-
def siteurl(self):
25+
def siteurl(self) -> str:
2126
return "{0}/sites/{1}/schedules".format(self.parent_srv.baseurl, self.parent_srv.site_id)
2227

2328
@api(version="2.3")
24-
def get(self, req_options=None):
29+
def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[ScheduleItem], PaginationItem]:
2530
logger.info("Querying all schedules")
2631
url = self.baseurl
2732
server_response = self.get_request(url, req_options)
@@ -30,7 +35,7 @@ def get(self, req_options=None):
3035
return all_schedule_items, pagination_item
3136

3237
@api(version="2.3")
33-
def delete(self, schedule_id):
38+
def delete(self, schedule_id: str) -> None:
3439
if not schedule_id:
3540
error = "Schedule ID undefined"
3641
raise ValueError(error)
@@ -39,7 +44,7 @@ def delete(self, schedule_id):
3944
logger.info("Deleted single schedule (ID: {0})".format(schedule_id))
4045

4146
@api(version="2.3")
42-
def update(self, schedule_item):
47+
def update(self, schedule_item: ScheduleItem) -> ScheduleItem:
4348
if not schedule_item.id:
4449
error = "Schedule item missing ID."
4550
raise MissingRequiredFieldError(error)
@@ -52,7 +57,7 @@ def update(self, schedule_item):
5257
return updated_schedule._parse_common_tags(server_response.content, self.parent_srv.namespace)
5358

5459
@api(version="2.3")
55-
def create(self, schedule_item):
60+
def create(self, schedule_item: ScheduleItem) -> ScheduleItem:
5661
if schedule_item.interval_item is None:
5762
error = "Interval item must be defined."
5863
raise MissingRequiredFieldError(error)
@@ -67,15 +72,25 @@ def create(self, schedule_item):
6772
@api(version="2.8")
6873
def add_to_schedule(
6974
self,
70-
schedule_id,
71-
workbook=None,
72-
datasource=None,
73-
task_type=TaskItem.Type.ExtractRefresh,
74-
):
75-
def add_to(resource, type_, req_factory):
75+
schedule_id: str,
76+
workbook: "WorkbookItem" = None,
77+
datasource: "DatasourceItem" = None,
78+
task_type: str = TaskItem.Type.ExtractRefresh,
79+
) -> List[AddResponse]:
80+
def add_to(
81+
resource: Union["DatasourceItem", "WorkbookItem"],
82+
type_: str,
83+
req_factory: Callable[
84+
[
85+
str,
86+
str,
87+
],
88+
bytes,
89+
],
90+
) -> AddResponse:
7691
id_ = resource.id
7792
url = "{0}/{1}/{2}s".format(self.siteurl, schedule_id, type_)
78-
add_req = req_factory(id_, task_type=task_type)
93+
add_req = req_factory(id_, task_type=task_type) # type: ignore[call-arg, arg-type]
7994
response = self.put_request(url, add_req)
8095

8196
error, warnings, task_created = ScheduleItem.parse_add_to_schedule_response(
@@ -99,8 +114,10 @@ def add_to(resource, type_, req_factory):
99114
if workbook is not None:
100115
items.append((workbook, "workbook", RequestFactory.Schedule.add_workbook_req))
101116
if datasource is not None:
102-
items.append((datasource, "datasource", RequestFactory.Schedule.add_datasource_req))
117+
items.append(
118+
(datasource, "datasource", RequestFactory.Schedule.add_datasource_req) # type:ignore[arg-type]
119+
)
103120

104121
results = (add_to(*x) for x in items)
105122
# list() is needed for python 3.x compatibility
106-
return list(filter(lambda x: not x.result, results))
123+
return list(filter(lambda x: not x.result, results)) # type:ignore[arg-type]

tableauserverclient/server/request_factory.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ def update_req(self, schedule_item):
515515
single_interval_element.attrib[expression] = value
516516
return ET.tostring(xml_request)
517517

518-
def _add_to_req(self, id_, target_type, task_type=TaskItem.Type.ExtractRefresh):
518+
def _add_to_req(self, id_: Optional[str], target_type: str, task_type: str = TaskItem.Type.ExtractRefresh) -> bytes:
519519
"""
520520
<task>
521521
<target_type>
@@ -524,6 +524,8 @@ def _add_to_req(self, id_, target_type, task_type=TaskItem.Type.ExtractRefresh):
524524
</task>
525525
526526
"""
527+
if not isinstance(id_, str):
528+
raise ValueError(f"id_ should be a string, reeceived: {type(id_)}")
527529
xml_request = ET.Element("tsRequest")
528530
task_element = ET.SubElement(xml_request, "task")
529531
task = ET.SubElement(task_element, task_type)
@@ -532,10 +534,10 @@ def _add_to_req(self, id_, target_type, task_type=TaskItem.Type.ExtractRefresh):
532534

533535
return ET.tostring(xml_request)
534536

535-
def add_workbook_req(self, id_, task_type=TaskItem.Type.ExtractRefresh):
537+
def add_workbook_req(self, id_: Optional[str], task_type: str = TaskItem.Type.ExtractRefresh) -> bytes:
536538
return self._add_to_req(id_, "workbook", task_type)
537539

538-
def add_datasource_req(self, id_, task_type=TaskItem.Type.ExtractRefresh):
540+
def add_datasource_req(self, id_: Optional[str], task_type: str = TaskItem.Type.ExtractRefresh) -> bytes:
539541
return self._add_to_req(id_, "datasource", task_type)
540542

541543

0 commit comments

Comments
 (0)