Skip to content

Commit

Permalink
updated after review
Browse files Browse the repository at this point in the history
  • Loading branch information
bazarnov committed Mar 19, 2022
1 parent 6d3e3e4 commit b3bf785
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ def str2unixtime(str_dt: str) -> Optional[int]:
dt = datetime.strptime(str_dt, DATETIME_FORMAT)
return calendar.timegm(dt.utctimetuple())

@staticmethod
def _parse_next_page_number(response: requests.Response) -> Optional[int]:
"""Parses a response and tries to find next page number"""
next_page = response.json().get("next_page")
return dict(parse_qsl(urlparse(next_page).query)).get("page") if next_page else None

def parse_response(self, response: requests.Response, stream_state: Mapping[str, Any], **kwargs) -> Iterable[Mapping]:
"""try to select relevant data only"""

Expand Down Expand Up @@ -150,6 +156,16 @@ def __init__(self, authenticator: Union[AuthBase, HttpAuthenticator] = None, **k
self._session.auth = authenticator
self.future_requests = deque()

@property
def url_base(self) -> str:
return f"https://{self._subdomain}.zendesk.com/api/v2/"

def path(self, **kwargs):
return self.name

def next_page_token(self, *args, **kwargs):
return None

def get_updated_state(self, current_stream_state: MutableMapping[str, Any], latest_record: Mapping[str, Any]) -> Mapping[str, Any]:
latest_benchmark = latest_record[self.cursor_field]
if current_stream_state.get(self.cursor_field):
Expand Down Expand Up @@ -271,24 +287,6 @@ def read_records(
else:
yield from self.parse_response(response, stream_state=stream_state, stream_slice=stream_slice)

@property
def url_base(self) -> str:
return f"https://{self._subdomain}.zendesk.com/api/v2/"

@staticmethod
def _parse_next_page_number(response: requests.Response) -> Optional[int]:
"""Parses a response and tries to find next page number"""
next_page = response.json().get("next_page")
if next_page:
return dict(parse_qsl(urlparse(next_page).query)).get("page")
return None

def path(self, **kwargs):
return self.name

def next_page_token(self, *args, **kwargs):
return None


class SourceZendeskSupportFullRefreshStream(BaseSourceZendeskSupportStream):
"""
Expand All @@ -306,14 +304,6 @@ def url_base(self) -> str:
def path(self, **kwargs):
return self.name

@staticmethod
def _parse_next_page_number(response: requests.Response) -> Optional[int]:
"""Parses a response and tries to find next page number"""
next_page = response.json().get("next_page")
if next_page:
return dict(parse_qsl(urlparse(next_page).query)).get("page")
return None

def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
next_page = self._parse_next_page_number(response)
if not next_page:
Expand Down Expand Up @@ -369,54 +359,55 @@ def request_params(
return params


class ZendeskSupportTicektEventsExportStream(SourceZendeskSupportCursorPaginationStream):
class ZendeskSupportTicketEventsExportStream(SourceZendeskSupportCursorPaginationStream):
"""Incremental Export from TicketEvents stream:
https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/#incremental-ticket-event-export
@ param response_list_name: the main nested entity to look at inside of response, defualt = "ticket_events"
@ param responce_target_entity: nested property inside of `response_list_name`, default = "child_events"
@ param response_target_entity: nested property inside of `response_list_name`, default = "child_events"
@ param list_entities_from_event : the list of nested child_events entities to include from parent record
@ param sideload_param : parameter variable to include various information to child_events property
more info: https://developer.zendesk.com/documentation/ticketing/using-the-zendesk-api/side_loading/#supported-endpoints
@ param event_type : specific event_type to check ["Audit", "Change", "Comment", etc]
"""

response_list_name: str = "ticket_events"
responce_target_entity: str = "child_events"
response_target_entity: str = "child_events"
list_entities_from_event: List[str] = None
sideload_param: str = None
event_type: str = None


@property
def update_event_from_record(self) -> bool:
"""Returns True/False based on list_entities_from_event property"""
return True if len(self.list_entities_from_event) > 0 else False

def path(self, **kwargs) -> str:
return "incremental/ticket_events"

def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
"""
Returns next_page_token based on `end_of_stream` parameter inside of response
"""
next_page_token = super().next_page_token(response)
end_of_stream = response.json().get(END_OF_STREAM_KEY, False)
return None if end_of_stream else next_page_token

return None if response.json().get(END_OF_STREAM_KEY, False) else next_page_token

def request_params(
self, stream_state: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None, **kwargs
) -> MutableMapping[str, Any]:
params = super().request_params(stream_state, next_page_token, **kwargs)
if self.sideload_param:
params["include"] = self.sideload_param
return params

def update_event_props(self, record: dict = None, event: dict = None, props: list = None) -> MutableMapping[str, Any]:
"""Update the event mapping with the specified fields from record entity"""
if self.list_entities_from_event and len(self.list_entities_from_event) > 0:
for prop in props:
target_prop = record.get(prop)
event[prop] = target_prop if target_prop else None
return event

def parse_response(self, response: requests.Response, stream_state: Mapping[str, Any], **kwargs) -> Iterable[Mapping]:
records = response.json().get(self.response_list_name) or []
for record in records:
for event in record.get(self.responce_target_entity):

def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]:
for record in response.json().get(self.response_list_name, []):
for event in record.get(self.response_target_entity, []):
if event.get("event_type") == self.event_type:
yield self.update_event_props(record, event, self.list_entities_from_event)
if self.update_event_from_record:
for prop in self.list_entities_from_event:
event[prop] = record.get(prop)
yield event


class Users(SourceZendeskSupportStream):
Expand All @@ -442,7 +433,7 @@ def request_params(self, **kwargs) -> MutableMapping[str, Any]:
return params


class TicketComments(ZendeskSupportTicektEventsExportStream):
class TicketComments(ZendeskSupportTicketEventsExportStream):
"""
Fetch the TicketComments incrementaly from TicketEvents Export stream
"""
Expand All @@ -452,9 +443,6 @@ class TicketComments(ZendeskSupportTicektEventsExportStream):
sideload_param = "comment_events"
event_type = "Comment"

def path(self, **kwargs) -> str:
return "incremental/ticket_events"


class Groups(SourceZendeskSupportStream):
"""Groups stream: https://developer.zendesk.com/api-reference/ticketing/groups/groups/"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#
# Copyright (c) 2021 Airbyte, Inc., all rights reserved.
#

import calendar
from datetime import datetime
from urllib.parse import parse_qsl, urlparse

import pytz
import requests
from source_zendesk_support.streams import DATETIME_FORMAT, BaseSourceZendeskSupportStream

DATETIME_STR = "2021-07-22T06:55:55Z"
DATETIME_FROM_STR = datetime.strptime(DATETIME_STR, DATETIME_FORMAT)
STREAM_URL = "https://subdomain.zendesk.com/api/v2/stream.json?&start_time=1647532987&page=1"
STREAM_RESPONSE: dict = {
"data": [],
"next_page": "https://subdomain.zendesk.com/api/v2/stream.json?&start_time=1647532987&page=2",
"count": 215,
"end_of_stream": True,
"end_time": 1647532987,
}


def test_str2datetime():
expected = datetime.strptime(DATETIME_STR, DATETIME_FORMAT)
output = BaseSourceZendeskSupportStream.str2datetime(DATETIME_STR)
assert output == expected


def test_datetime2str():
expected = datetime.strftime(DATETIME_FROM_STR.replace(tzinfo=pytz.UTC), DATETIME_FORMAT)
output = BaseSourceZendeskSupportStream.datetime2str(DATETIME_FROM_STR)
assert output == expected


def test_str2unixtime():
expected = calendar.timegm(DATETIME_FROM_STR.utctimetuple())
output = BaseSourceZendeskSupportStream.str2unixtime(DATETIME_STR)
assert output == expected


def test_parse_next_page_number(requests_mock):
expected = dict(parse_qsl(urlparse(STREAM_RESPONSE.get("next_page")).query)).get("page")
requests_mock.get(STREAM_URL, json=STREAM_RESPONSE)
test_response = requests.get(STREAM_URL)
output = BaseSourceZendeskSupportStream._parse_next_page_number(test_response)
assert output == expected
29 changes: 14 additions & 15 deletions docs/integrations/sources/zendesk-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,26 @@ This source can sync data for the [Zendesk Support API](https://developer.zendes

This Source is capable of syncing the following core Streams:

* [Tickets](https://developer.zendesk.com/rest_api/docs/support/tickets)
* [Brands](https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#list-brands)
* [Custom Roles](https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#list-custom-roles)
* [Groups](https://developer.zendesk.com/rest_api/docs/support/groups)
* [Users](https://developer.zendesk.com/rest_api/docs/support/users)
* [Group Memberships](https://developer.zendesk.com/rest_api/docs/support/group_memberships)
* [Macros](https://developer.zendesk.com/rest_api/docs/support/macros)
* [Organizations](https://developer.zendesk.com/rest_api/docs/support/organizations)
* [Satisfaction Ratings](https://developer.zendesk.com/rest_api/docs/support/satisfaction_ratings)
* [Schedules](https://developer.zendesk.com/api-reference/ticketing/ticket-management/schedules/#list-schedules)
* [SLA Policies](https://developer.zendesk.com/rest_api/docs/support/sla_policies)
* [Tags](https://developer.zendesk.com/rest_api/docs/support/tags)
* [Tickets](https://developer.zendesk.com/rest_api/docs/support/tickets)
* [Ticket Audits](https://developer.zendesk.com/rest_api/docs/support/ticket_audits)
* [Ticket Comments](https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/#incremental-ticket-event-export)
* [Ticket Fields](https://developer.zendesk.com/rest_api/docs/support/ticket_fields)
* [Ticket Forms](https://developer.zendesk.com/rest_api/docs/support/ticket_forms)
* [Ticket Metrics](https://developer.zendesk.com/rest_api/docs/support/ticket_metrics)
* [Ticket Metric Events](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metric_events/)
* [Group Memberships](https://developer.zendesk.com/rest_api/docs/support/group_memberships)
* [Macros](https://developer.zendesk.com/rest_api/docs/support/macros)
* [Satisfaction Ratings](https://developer.zendesk.com/rest_api/docs/support/satisfaction_ratings)
* [Tags](https://developer.zendesk.com/rest_api/docs/support/tags)
* [SLA Policies](https://developer.zendesk.com/rest_api/docs/support/sla_policies)
* [Brands](https://developer.zendesk.com/api-reference/ticketing/account-configuration/brands/#list-brands)
* [Custom Roles](https://developer.zendesk.com/api-reference/ticketing/account-configuration/custom_roles/#list-custom-roles)
* [Schedules](https://developer.zendesk.com/api-reference/ticketing/ticket-management/schedules/#list-schedules)

* [Users](https://developer.zendesk.com/rest_api/docs/support/users)

There are a lot of space for future work, the next streams could be added in the future:
The streams below are not implemented. Please open a Github issue or request it through Airbyte Cloud's support box if you are interested in them.

**Tickets**

Expand Down Expand Up @@ -67,10 +66,10 @@ There are a lot of space for future work, the next streams could be added in the

| Feature | Supported?\(Yes/No\) | Notes |
| :--- | :--- | :--- |
| Full Refresh Sync | Yes | ... |
| Incremental - Append Sync | Yes | ... |
| Full Refresh Sync | Yes | |
| Incremental - Append Sync | Yes | |
| Incremental - Debuped + History Sync | Yes | Enabled according to type of destination |
| Namespaces | No | ... |
| Namespaces | No | |

### Performance considerations

Expand Down

1 comment on commit b3bf785

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

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

SonarQube Report

SonarQube report for Airbyte Connectors Source Zendesk Support(#11237)

Measures

Name Value Name Value Name Value
Coverage 61.0 Quality Gate Status ERROR Bugs 0
Reliability Rating A Vulnerabilities 0 Duplicated Lines (%) 0.0
Duplicated Blocks 0 Lines to Cover 41 Lines of Code 432
Security Rating A Code Smells 8 Blocker Issues 0
Critical Issues 0 Major Issues 14 Minor Issues 48

Detected Issues

Rule File Description Message
python:mypy_return_value (MINOR) source_zendesk_support/streams.py:122 Check that return value is compatible with signature Incompatible return value type (got "Optional[str]", expected "Optional[int]") . Code line: return dict(parse_qsl(urlparse(next_page).query)).get("page") ...
python:mypy_override (MINOR) source_zendesk_support/streams.py:403 Check that method override is compatible with base class Signature of "parse_response" incompatible with supertype "BaseSourceZendeskSupportStream" . Code line: def parse_response(self, response: requests.Response, **kwargs) ->...
python:S5890 (MAJOR) source_zendesk_support/streams.py:376 Values assigned to variables should match their type annotations Assign to "list_entities_from_event" a value of type "list[str]" instead of "NoneType" or update its type hint.
python:S5890 (MAJOR) source_zendesk_support/streams.py:377 Values assigned to variables should match their type annotations Assign to "sideload_param" a value of type "str" instead of "NoneType" or update its type hint.
python:S5890 (MAJOR) source_zendesk_support/streams.py:378 Values assigned to variables should match their type annotations Assign to "event_type" a value of type "str" instead of "NoneType" or update its type hint.
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
python:black_need_format (MINOR) source_zendesk_support/streams.py Please run one of the commands: "black --config ./pyproject.toml <path_to_updated_folder>" or "./gradlew format" 1 code part(s) should be updated.
python:mypy_union_attr (MINOR) source_zendesk_support/streams.py Check that attribute exists in each item of a union Item "None" of "Optional[Dict[Any, Any]]" has no attribute "get" . Code line: current_state = stream_state.get(self.cursor_field, {})
python:mypy_union_attr (MINOR) source_zendesk_support/streams.py Check that attribute exists in each item of a union Item "None" of "Optional[Dict[Any, Any]]" has no attribute "get" . Code line: updated_state = event.get(self.cursor_field, {})
python:mypy_misc (MINOR) source_zendesk_support/streams.py Miscellaneous other checks Incompatible types in "yield" (actual type "Optional[Dict[Any, Any]]", expected type "Mapping[Any, Any]") . Code line: yield event
python:mypy_arg_type (MINOR) source_zendesk_support/streams.py Check argument types in calls Argument 2 to "filter_by_state" of "ZendeskSupportTicektEventsExportStream" has incompatible type "Mapping[str, Any]"; expected "Optional[Dict[Any, Any]]" . Code line: ... yield from self.filter_by_state(event, stream_state)
flake8:W293 (MAJOR) source_zendesk_support/streams.py blank line contains whitespace blank line contains whitespace
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:376 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "List[str]") . Code line: list_entities_from_event: List[str] = None
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:377 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "str") . Code line: sideload_param: str = None
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:378 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "str") . Code line: event_type: str = None
python:mypy_override (MINOR) source_zendesk_support/streams.py:345 Check that method override is compatible with base class Signature of "request_params" incompatible with supertype "SourceZendeskSupportFullRefreshStream" . Code line: def request_params(
python:mypy_override (MINOR) source_zendesk_support/streams.py:395 Check that method override is compatible with base class Signature of "request_params" incompatible with supertype "SourceZendeskSupportFullRefreshStream" . Code line: def request_params(
python:mypy_union_attr (MINOR) source_zendesk_support/streams.py Check that attribute exists in each item of a union Item "None" of "Optional[List[Any]]" has no attribute "iter" (not iterable) . Code line: for prop in props:
python:mypy_union_attr (MINOR) source_zendesk_support/streams.py Check that attribute exists in each item of a union Item "None" of "Optional[Dict[Any, Any]]" has no attribute "get" . Code line: target_prop = record.get(prop)
python:mypy_index (MINOR) source_zendesk_support/streams.py Check indexing operations Unsupported target for indexed assignment ("Optional[Dict[Any, Any]]") . Code line: event[prop] = target_prop if target_prop else None
python:mypy_return_value (MINOR) source_zendesk_support/streams.py Check that return value is compatible with signature Incompatible return value type (got "Optional[Dict[Any, Any]]", expected "MutableMapping[str, Any]") . Code line: return event
python:mypy_attr_defined (MINOR) source_zendesk_support/streams.py:351 Check that attribute exists Module has no attribute "parse" . Code line: parsed_state = calendar.timegm(pendulum.parse(stream_state...
python:mypy_attr_defined (MINOR) source_zendesk_support/streams.py:354 Check that attribute exists Module has no attribute "parse" . Code line: parsed_state = calendar.timegm(pendulum.parse(self.start...
python:S1066 (MAJOR) source_zendesk_support/source.py:58 Collapsible "if" statements should be merged Merge this if statement with the enclosing one.
python:mypy_no_any_return (MINOR) source_zendesk_support/source.py:64 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "BasicApiTokenAuthenticator" . Code line: return TokenAuthenticator(token=config["credentials"][...
python:mypy_arg_type (MINOR) source_zendesk_support/source.py:81 Check argument types in calls Argument "start_date" to "UserSettingsStream" has incompatible type "None"; expected "str" . Code line: ...nfig["subdomain"], authenticator=auth, start_date=None).get_settings()
python:mypy_return_value (MINOR) source_zendesk_support/streams.py Check that return value is compatible with signature Incompatible return value type (got "Optional[str]", expected "Optional[int]") . Code line: return dict(parse_qsl(urlparse(next_page).query)).get("pag...
python:mypy_return_value (MINOR) source_zendesk_support/streams.py Check that return value is compatible with signature Incompatible return value type (got "Optional[str]", expected "Optional[int]") . Code line: return dict(parse_qsl(urlparse(next_page).query)).get("pag...
python:mypy_import (MINOR) source_zendesk_support/streams.py:25 Require that imported module can be found or has stubs Library stubs not installed for "requests.auth" (or incompatible with Python 3.7) . Code line: from requests.auth import AuthBase
python:mypy_no_any_return (MINOR) source_zendesk_support/streams.py:62 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "Future[Any]" . Code line: return self.executor.submit(func, request, **kwargs)
python:S5890 (MAJOR) source_zendesk_support/streams.py:146 Values assigned to variables should match their type annotations Assign to "response_list_name" a value of type "str" instead of "NoneType" or update its type hint.
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:146 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "str") . Code line: response_list_name: str = None
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:147 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "SourceZendeskSupportStream") . Code line: parent: "SourceZendeskSupportStream" = None
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:148 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "deque[Any]") . Code line: future_requests: deque = None
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:186 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str") . Code line: start_date = stream_state.get(self.cursor_field)
python:mypy_attr_defined (MINOR) source_zendesk_support/streams.py:245 Check that attribute exists Module has no attribute "parse" . Code line: ... start_time = current_state or calendar.timegm(pendulum.parse(self._...
python:mypy_arg_type (MINOR) source_zendesk_support/streams.py:288 Check argument types in calls Argument "stream_state" to "parse_response" of "BaseSourceZendeskSupportStream" has incompatible type "Optional[Mapping[str, Any]]"; expected "Mapping[str, Any]" . Code line: ... from self.parse_response(response, stream_state=stream_state, stream_...
python:S5890 (MAJOR) source_zendesk_support/streams.py:298 Values assigned to variables should match their type annotations Assign to "response_list_name" a value of type "str" instead of "NoneType" or update its type hint.
python:mypy_assignment (MINOR) source_zendesk_support/streams.py:298 Check that assigned value is compatible with target Incompatible types in assignment (expression has type "None", variable has type "str") . Code line: response_list_name: str = None
python:mypy_return (MINOR) source_zendesk_support/streams.py:339 Check that function always returns a value Missing return statement . Code line: def next_page_token(self, response: requests.Response) -> Optional...
python:mypy_attr_defined (MINOR) source_zendesk_support/streams.py:358 Check that attribute exists Module has no attribute "parse" . Code line: ... params = {"start_time": calendar.timegm(pendulum.parse(self._...
python:mypy_override (MINOR) source_zendesk_support/streams.py:569 Check that method override is compatible with base class Signature of "parse_response" incompatible with supertype "BaseSourceZendeskSupportStream" . Code line: def parse_response(self, response: requests.Response, **kwargs) ->...
python:mypy_no_any_return (MINOR) source_zendesk_support/streams.py:577 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "Mapping[str, Any]" . Code line: return resp
python:mypy_override (MINOR) source_zendesk_support/streams.py:519 Check that method override is compatible with base class Signature of "request_params" incompatible with supertype "SourceZendeskSupportCursorPaginationStream" . Code line: def request_params(self, next_page_token: Mapping[str, Any] = None...
python:mypy_no_any_return (MINOR) source_zendesk_support/streams.py:527 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "Optional[Mapping[str, Any]]" . Code line: return response.json().get("before_cursor")
python:mypy_arg_type (MINOR) source_zendesk_support/streams.py:468 Check argument types in calls Argument 1 to "str2unixtime" of "BaseSourceZendeskSupportStream" has incompatible type "Optional[Any]"; expected "str" . Code line: start_time = self.str2unixtime((stream_state or {}).get(self.c...
python:mypy_no_any_return (MINOR) source_zendesk_support/streams.py:89 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "Union[int, float]" . Code line: return super().backoff_time(response)
python:mypy_import (MINOR) source_zendesk_support/source.py:8 Require that imported module can be found or has stubs Library stubs not installed for "requests" (or incompatible with Python 3.7) . Code line: import requests
python:mypy_return (MINOR) source_zendesk_support/source.py:53 Check that function always returns a value Missing return statement . Code line: def get_authenticator(cls, config: Mapping[str, Any]) -> BasicApiT...
python:mypy_valid_type (MINOR) source_zendesk_support/source.py:70 Check that type (annotation) is valid Function "builtins.any" is not valid as a type . Code line: def check_connection(self, logger, config) -> Tuple[bool, any]:
python:mypy_import (MINOR) source_zendesk_support/streams.py:18 Require that imported module can be found or has stubs Library stubs not installed for "pytz" (or incompatible with Python 3.7) . Code line: import pytz
python:mypy_import (MINOR) source_zendesk_support/streams.py:19 Require that imported module can be found or has stubs Library stubs not installed for "requests" (or incompatible with Python 3.7) . Code line: import requests
python:S5886 (MAJOR) source_zendesk_support/streams.py:97 Function return types should be consistent with their type hint Return a value of type "datetime" instead of "NoneType" or update function "str2datetime" type hint.
python:mypy_return_value (MINOR) source_zendesk_support/streams.py:97 Check that return value is compatible with signature Incompatible return value type (got "None", expected "datetime") . Code line: return None
python:mypy_return_value (MINOR) source_zendesk_support/streams.py:312 Check that return value is compatible with signature Incompatible return value type (got "int", expected "Optional[Mapping[str, Any]]") . Code line: return next_page
python:mypy_no_any_return (MINOR) source_zendesk_support/streams.py:322 Reject returning value with "Any" type if return type is not "Any" Returning Any from function declared to return "MutableMapping[str, Any]" . Code line: return params
python:mypy_override (MINOR) source_zendesk_support/streams.py:429 Check that method override is compatible with base class Signature of "request_params" incompatible with supertype "SourceZendeskSupportStream" . Code line: def request_params(self, **kwargs) -> MutableMapping[str, Any]:

Coverage (61.0%)

File Coverage File Coverage
source_zendesk_support/init.py 100.0 source_zendesk_support/source.py 44.4
source_zendesk_support/streams.py 71.5

Please sign in to comment.