8000 Add support for all types of monthly repeating schedules by bcantoni · Pull Request #1462 · tableau/server-client-python · GitHub
[go: up one dir, main page]

Skip to content

Add support for all types of monthly repeating schedules #1462

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

Merged
merged 4 commits into from
Sep 17, 2024
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
41 changes: 27 additions & 14 deletions tableauserverclient/models/interval_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,21 +246,34 @@ def interval(self):

@interval.setter
def interval(self, interval_values):
# This is weird because the value could be a str or an int
# The only valid str is 'LastDay' so we check that first. If that's not it
# try to convert it to an int, if that fails because it's an incorrect string
# like 'badstring' we catch and re-raise. Otherwise we convert to int and check
# that it's in range 1-31
# Valid monthly intervals strings can contain any of the following
# day numbers (1-31) (integer or string)
# relative day within the month (First, Second, ... Last)
# week days (Sunday, Monday, ... LastDay)
VALID_INTERVALS = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"LastDay",
"First",
"Second",
"Third",
"Fourth",
"Fifth",
"Last",
]
for value in range(1, 32):
VALID_INTERVALS.append(str(value))
VALID_INTERVALS.append(value)

for interval_value in interval_values:
error = "Invalid interval value for a monthly frequency: {}.".format(interval_value)

if interval_value != "LastDay":
try:
if not (1 <= int(interval_value) <= 31):
raise ValueError(error)
except ValueError:
if interval_value != "LastDay":
raise ValueError(error)
if interval_value not in VALID_INTERVALS:
error = f"Invalid monthly interval: {interval_value}"
raise ValueError(error)

self._interval = interval_values

Expand Down
4 changes: 3 additions & 1 deletion tableauserverclient/server/endpoint/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ def _make_request(

loggable_response = self.log_response_safely(server_response)
logger.debug("Server response from {0}".format(url))
# logger.debug("\n\t{1}".format(loggable_response))
# uncomment the following to log full responses in debug mode
# BE CAREFUL WHEN SHARING THESE RESULTS - MAY CONTAIN YOUR SENSITIVE DATA
# logger.debug(loggable_response)

if content_type == "application/xml":
self.parent_srv._namespace.detect(server_response.content)
Expand Down
12 changes: 12 additions & 0 deletions test/assets/schedule_get_monthly_id_2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<tsResponse
xmlns="http://tableau.com/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api https://help.tableau.com/samples/en-us/rest_api/ts-api_3_25.xsd">
<schedule id="8c5caf33-6223-4724-83c3-ccdc1e730a07" name="Monthly First Monday!" state="Active" priority="50" createdAt="2024-09-12T01:22:07Z" updatedAt="2024-09-12T01:22:48Z" type="Extract" frequency="Monthly" nextRunAt="2024-10-07T08:00:00Z" executionOrder="Parallel">
<frequencyDetails start="08:00:00">
<intervals>
<interval weekDay="Monday" monthDay="First" />
</intervals>
</frequencyDetails>
</schedule>
</tsResponse>
16 changes: 16 additions & 0 deletions test/test_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
GET_HOURLY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_hourly_id.xml")
GET_DAILY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_daily_id.xml")
GET_MONTHLY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_monthly_id.xml")
GET_MONTHLY_ID_2_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_monthly_id_2.xml")
GET_EMPTY_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_empty.xml")
CREATE_HOURLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_hourly.xml")
CREATE_DAILY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_daily.xml")
Expand Down Expand Up @@ -158,6 +159,21 @@ def test_get_monthly_by_id(self) -> None:
self.assertEqual("Active", schedule.state)
self.assertEqual(("1", "2"), schedule.interval_item.interval)

def test_get_monthly_by_id_2(self) -> None:
self.server.version = "3.15"
with open(GET_MONTHLY_ID_2_XML, "rb") as f:
response_xml = f.read().decode("utf-8")
with requests_mock.mock() as m:
schedule_id = "8c5caf33-6223-4724-83c3-ccdc1e730a07"
baseurl = "{}/schedules/{}".format(self.server.baseurl, schedule_id)
m.get(baseurl, text=response_xml)
schedule = self.server.schedules.get_by_id(schedule_id)
self.assertIsNotNone(schedule)
self.assertEqual(schedule_id, schedule.id)
self.assertEqual("Monthly First Monday!", schedule.name)
self.assertEqual("Active", schedule.state)
self.assertEqual(("Monday", "First"), schedule.interval_item.interval)

def test_delete(self) -> None:
with requests_mock.mock() as m:
m.delete(self.baseurl + "/c9cff7f9-309c-4361-99ff-d4ba8c9f5467", status_code=204)
Expand Down
Loading
0