8000 Type hint webhooks by jorwoods · Pull Request #945 · tableau/server-client-python · GitHub
[go: up one dir, main page]

Skip to content

Type hint webhooks #945

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 74 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
a481299
Silence property decorator warnings
jorwoods Feb 2, 2021
5209c1f
Remove refs to distutils2
jorwoods Feb 2, 2021
2028935
Ignore problem variable in _version.py
jorwoods Feb 2, 2021
ddd84f6
Linting changes
jorwoods Feb 3, 2021
3a8faeb
Mypy checking in pipeline
jorwoods Feb 3, 2021
43c8dd7
Mypy ignore imports
jorwoods Feb 3, 2021
db1de41
Install mypy in pipeline
jorwoods Feb 3, 2021
ac9b06b
Fix mypy errors in datasource_item
jorwoods Feb 3, 2021
9a17beb
Add pre-commit config
jorwoods Feb 3, 2021
9be8bd7
Add pre-commit config
jorwoods Feb 3, 2021
13bde24
Type hint on datasources_endpoint
jorwoods Feb 3, 2021
5ea3e17
update_permissions takes a list of rules
jorwoods Feb 3, 2021
d4315de
Run mypy on tests as well
jorwoods Feb 3, 2021
0acf44c
Add mypy test and samples to travis
jorwoods Feb 3, 2021
45df4ff
Make type hint imports conditional
jorwoods Feb 4, 2021
bac2811
Annotate workbookitem init
jorwoods Feb 4, 2021
e19b28d
Continue typing workbookitem
jorwoods Feb 4, 2021
2a77b28
Begin annotations on workbook endpoint
jorwoods Feb 4, 2021
7efb7a6
Squashed commit of the following:
jorwoods Feb 18, 2021
0bf6fd9
Ignore property decorator warnings
jorwoods Feb 18, 2021
a8b42e1
Continue annotations on wb endpoint
jorwoods Feb 18, 2021
973237d
More workbook endpoint
jorwoods Feb 18, 2021
9a81506
Type hinting. Hinting error in publish
jorwoods Feb 18, 2021
cd3342d
Formatting
jorwoods Feb 18, 2021
cc5e9dc
Stop testing 3.5
jorwoods Feb 18, 2021
8870a07
Remove failing typecheck
jorwoods Feb 21, 2021
a8e182f
Python 3.5 is deprecated
jorwoods Feb 21, 2021
ee29429
Resolve development conflicts
jorwoods Feb 21, 2021
7ff1ad4
Remove misc check from pre-commit
jorwoods Feb 24, 2021
505f0e2
Remove ignore comments
jorwoods Feb 25, 2021
24574cb
Clean up function signatures
jorwoods Feb 25, 2021
4fa4c54
Fix PathLike call
jorwoods Feb 25, 2021
662145b
Explicitly return None
jorwoods Feb 25, 2021
f2e5a72
Move mode to separate line
jorwoods Feb 25, 2021
b146fdd
Remove bad TypeVar
jorwoods Mar 10, 2021
afa05ef
Merge branch 'development' into jorwoods/mypy
Apr 30, 2021
6041ce1
Run black formatter
Apr 30, 2021
e54f7fe
Fix mypy errors
Apr 30, 2021
059af6d
Add mypy into test install
Apr 30, 2021
dcd1fb6
Remove redundant mypy install
Apr 30, 2021
eb9649b
Type hint publish file
jorwoods Apr 30, 2021
4441377
Type hint datasource publish
jorwoods Apr 30, 2021
0ce6636
Split Union return type into overloads
jorwoods Oct 18, 2021
83327c4
Type hinting on datasource item
jorwoods Oct 19, 2021
4d88b6c
Merge remote-tracking branch 'upstream/development' into jorwoods/mypy
jorwoods Oct 19, 2021
eade29d
Fix type checking errors
jorwoods Oct 19, 2021
48517c6
Merge remote-tracking branch 'upstream/development' into jorwoods/mypy
jorwoods Oct 19, 2021
d70b27b
Make code compatible with 3.6 and 3.7
jorwoods Oct 19, 2021
f1fb183
Fix mypy errors
jorwoods Oct 19, 2021
742b1c9
Enable mypy
jorwoods Oct 19, 2021
bc7d63e
Ignore mypy import errors
jorwoods Oct 19, 2021
0d4dc2c
Remove pre-commit
jorwoods Oct 19, 2021
a6ab0b5
Formatting
jorwoods Oct 19, 2021
1f01be2
Fix black formatting oddities
jorwoods Oct 19, 2021
511f676
Add context to TypeErrors
jorwoods Oct 19, 2021
077c273
Add workbook test for TypeError
jorwoods Oct 19, 2021
4eeab5d
Type hint update_hyper_data
jorwoods Oct 19, 2021
27b4c61
Formatting
jorwoods Oct 19, 2021
1e41a91
Pin mypy version
jorwoods Oct 19, 2021
814430b
Better TypeError message
jorwoods Oct 19, 2021
bfccfb4
Use os.PathLike abstract class in isinstance
jorwoods Oct 19, 2021
a5997ec
Add test for publishing a Path object
jorwoods Oct 19, 2021
ee73215
Add str into PathOrFile
jorwoods Oct 19, 2021
56e8a93
Add type hints to tests
jorwoods Oct 19, 2021
9853fa1
Add pull request trigger to github actions
jorwoods Oct 20, 2021
de7037e
Add str to update_hyper_data type hints
jorwoods Oct 20, 2021
13da99d
Remove unused imports
jorwoods Oct 20, 2021
477e679
Fix actions type hint
jorwoods Oct 20, 2021
ab49a56
Change actions type to Sequence[Mapping]
jorwoods Oct 21, 2021
a0f4dd2
Fix tag type hints
jorwoods Oct 21, 2021
c56edf7
Type hint webhooks
jorwoods Oct 26, 2021
f634580
Squashed commit of the following:
jorwoods Jan 28, 2022
e5d82a9
Merge branch 'development' into jorwoods/type_hint_webhooks
jacalata Jan 28, 2022
69663ab
Update request_factory.py
jacalata Jan 28, 2022
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
8000
< 10000 button type="button" class="btn-octicon js-details-target" aria-label="Toggle diff contents" aria-expanded="true" style="width: 22px;">
23 changes: 12 additions & 11 deletions tableauserverclient/models/webhook_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import re

from typing import List, Optional, TYPE_CHECKING, Tuple, Type

NAMESPACE_RE = re.compile(r"^{.*}")

Expand All @@ -14,11 +15,11 @@ def _parse_event(events):

class WebhookItem(object):
def __init__(self):
self._id = None
self.name = None
self.url = None
self._event = None
self.owner_id = None
self._id: Optional[str] = None
self.name: Optional[str] = None
self.url: Optional[str] = None
self._event: Optional[str] = None
self.owner_id: Optional[str] = None

def _set_values(self, id, name, url, event, owner_id):
if id is not None:
Expand All @@ -33,21 +34,21 @@ def _set_values(self, id, name, url, event, owner_id):
self.owner_id = owner_id

@property
def id(self):
def id(self) -> Optional[str]:
return self._id

@property
def event(self):
def event(self) -> Optional[str]:
if self._event:
return self._event.replace("webhook-source-event-", "")
return None

@event.setter
def event(self, value):
def event(self, value: str) -> None:
self._event = "webhook-source-event-{}".format(value)

@classmethod
def from_response(cls, resp, ns):
def from_response(cls: Type["WebhookItem"], resp: bytes, ns) -> List["WebhookItem"]:
all_webhooks_items = list()
parsed_response = ET.fromstring(resp)
all_webhooks_xml = parsed_response.findall(".//t:webhook", namespaces=ns)
Expand All @@ -60,7 +61,7 @@ def from_response(cls, resp, ns):
return all_webhooks_items

@staticmethod
def _parse_element(webhook_xml, ns):
def _parse_element(webhook_xml: ET.Element, ns) -> Tuple:
id = webhook_xml.get("id", None)
name = webhook_xml.get("name", None)

Expand All @@ -80,5 +81,5 @@ def _parse_element(webhook_xml, ns):

return id, name, url, event, owner_id

def __repr__(self):
def __repr__(self) -> str:
return "<Webhook id={} name={} url={} event={}>".format(self.id, self.name, self.url, self.event)
20 changes: 13 additions & 7 deletions tableauserverclient/server/endpoint/webhooks_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@

logger = logging.getLogger("tableau.endpoint.webhooks")

from typing import List, Optional, TYPE_CHECKING, Tuple

if TYPE_CHECKING:
from ..server import Server
from ..request_options import RequestOptions


class Webhooks(Endpoint):
def __init__(self, parent_srv):
def __init__(self, parent_srv: "Server") -> None:
super(Webhooks, self).__init__(parent_srv)

@property
def baseurl(self):
def baseurl(self) -> str:
return "{0}/sites/{1}/webhooks".format(self.parent_srv.baseurl, self.parent_srv.site_id)

@api(version="3.6")
def get(self, req_options=None):
def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[WebhookItem], PaginationItem]:
logger.info("Querying all Webhooks on site")
url = self.baseurl
server_response = self.get_request(url, req_options)
Expand All @@ -25,7 +31,7 @@ def get(self, req_options=None):
return all_webhook_items, pagination_item

@api(version="3.6")
def get_by_id(self, webhook_id):
def get_by_id(self, webhook_id: str) -> WebhookItem:
if not webhook_id:
error = "Webhook ID undefined."
raise ValueError(error)
Expand All @@ -35,7 +41,7 @@ def get_by_id(self, webhook_id):
return WebhookItem.from_response(server_response.content, self.parent_srv.namespace)[0]

@api(version="3.6")
def delete(self, webhook_id):
def delete(self, webhook_id: str) -> None:
if not webhook_id:
error = "Webhook ID undefined."
raise ValueError(error)
Expand All @@ -44,7 +50,7 @@ def delete(self, webhook_id):
logger.info("Deleted single webhook (ID: {0})".format(webhook_id))

@api(version="3.6")
def create(self, webhook_item):
def create(self, webhook_item: WebhookItem) -> WebhookItem:
url = self.baseurl
create_req = RequestFactory.Webhook.create_req(webhook_item)
server_response = self.post_request(url, create_req)
Expand All @@ -54,7 +60,7 @@ def create(self, webhook_item):
return new_webhook

@api(version="3.6")
def test(self, webhook_id):
def test(self, webhook_id: str):
if not webhook_id:
error = "Webhook ID undefined."
raise ValueError(error)
Expand Down
1 change: 1 addition & 0 deletions tableauserverclient/server/endpoint/workbooks_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ def publish(
connection_credentials: Optional["ConnectionCredentials"] = None,
connections: Optional[Sequence[ConnectionItem]] = None,
as_job: bool = False,
hidden_views: Optional[Sequence[str]] = None,
skip_connection_check: bool = False,
):

Expand Down
34 changes: 21 additions & 13 deletions tableauserverclient/server/request_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@

from requests.packages.urllib3.fields import RequestField
from requests.packages.urllib3.filepost import encode_multipart_formdata
from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Iterable

from ..models import TaskItem, UserItem, GroupItem, PermissionsRule, FavoriteItem

from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Iterable

if TYPE_CHECKING:
from ..models import SubscriptionItem
from ..models import DataAlertItem
from ..models import FlowItem
from ..models import ConnectionItem
from ..models import SiteItem
from ..models import ProjectItem
from ..models import SubscriptionItem
from ..models import DataAlertItem
from ..models import FlowItem
from ..models import ConnectionItem
from ..models import SiteItem
from ..models import ProjectItem
from ..models import WebhookItem


def _add_multipart(parts: Dict) -> Tuple[Any, str]:
Expand Down Expand Up @@ -1031,17 +1030,26 @@ def empty_req(self, xml_request):

class WebhookRequest(object):
@_tsrequest_wrapped
def create_req(self, xml_request, webhook_item):
def create_req(self, xml_request: ET.Element, webhook_item: "WebhookItem") -> bytes:
webhook = ET.SubElement(xml_request, "webhook")
webhook.attrib["name"] = webhook_item.name
if isinstance(webhook_item.name, str):
webhook.attrib["name"] = webhook_item.name
else:
raise ValueError(f"Name must be provided for {webhook_item}")

source = ET.SubElement(webhook, "webhook-source")
ET.SubElement(source, webhook_item._event)
if isinstance(webhook_item._event, str):
ET.SubElement(source, webhook_item._event)
else:
raise ValueError(f"_event for Webhook must be provided. {webhook_item}")

destination = ET.SubElement(webhook, "webhook-destination")
post = ET.SubElement(destination, "webhook-destination-http")
post.attrib["method"] = "POST"
post.attrib["url"] = webhook_item.url
if isinstance(webhook_item.url, str):
post.attrib["url"] = webhook_item.url
else:
raise ValueError(f"URL must be provided on {webhook_item}")

return ET.tostring(xml_request)

Expand Down
4 changes: 1 addition & 3 deletions test/test_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,7 @@ def test_create_weekly(self) -> None:
self.assertEqual("2016-09-16T16:15:00Z", format_datetime(new_schedule.next_run_at))
self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Parallel, new_schedule.execution_order)
self.assertEqual(time(9, 15), new_schedule.interval_item.start_time)
self.assertEqual(
("Monday", "Wednesday", "Friday"), new_schedule.interval_item.interval
) # type: ignore[union-attr]
self.assertEqual(("Monday", "Wednesday", "Friday"), new_schedule.interval_item.interval)
self.assertEqual(2, len(new_schedule.warnings))
self.assertEqual("warning 1", new_schedule.warnings[0])
self.assertEqual("warning 2", new_schedule.warnings[1])
Expand Down
14 changes: 7 additions & 7 deletions test/test_webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


class WebhookTests(unittest.TestCase):
def setUp(self):
def setUp(self) -> None:
self.server = TSC.Server("http://test")
self.server.version = "3.6"

Expand All @@ -24,7 +24,7 @@ def setUp(self):

self.baseurl = self.server.webhooks.baseurl

def test_get(self):
def test_get(self) -> None:
with open(GET_XML, "rb") as f:
response_xml = f.read().decode("utf-8")
with requests_mock.mock() as m:
Expand All @@ -39,24 +39,24 @@ def test_get(self):
self.assertEqual(webhook.name, "webhook-name")
self.assertEqual(webhook.id, "webhook-id")

def test_get_before_signin(self):
def test_get_before_signin(self) -> None:
self.server._auth_token = None
self.assertRaises(TSC.NotSignedInError, self.server.webhooks.get)

def test_delete(self):
def test_delete(self) -> None:
with requests_mock.mock() as m:
m.delete(self.baseurl + "/ee8c6e70-43b6-11e6-af4f-f7b0d8e20760", status_code=204)
self.server.webhooks.delete("ee8c6e70-43b6-11e6-af4f-f7b0d8e20760")

def test_delete_missing_id(self):
def test_delete_missing_id(self) -> None:
self.assertRaises(ValueError, self.server.webhooks.delete, "")

def test_test(self):
def test_test(self) -> None:
with requests_mock.mock() as m:
m.get(self.baseurl + "/ee8c6e70-43b6-11e6-af4f-f7b0d8e20760/test", status_code=200)
self.server.webhooks.test("ee8c6e70-43b6-11e6-af4f-f7b0d8e20760")

def test_create(self):
def test_create(self) -> None:
with open(CREATE_XML, "rb") as f:
response_xml = f.read().decode("utf-8")
with requests_mock.mock() as m:
Expand Down
0