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

health: move to mypy #1620

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
23 changes: 23 additions & 0 deletions .github/workflows/mypy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: mypy validation

on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
python-version: ["3.13"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Run mypy verification
run: |
./scripts/run_mypy.sh
31 changes: 0 additions & 31 deletions .github/workflows/pytype.yml

This file was deleted.

8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,11 @@ filterwarnings = [
"ignore:slack.* package is deprecated. Please use slack_sdk.* package instead.*:UserWarning",
]
asyncio_mode = "auto"


[tool.mypy]
files = "slack_sdk/"
exclude = ["slack_sdk/scim", "slack_sdk/rtm"]
force_union_syntax = true
warn_unused_ignores = true
enable_error_code = "ignore-without-code"
1 change: 1 addition & 0 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ psutil>=6.0.0,<7
boto3<=2
# For AWS tests
moto>=4.0.13,<6
mypy<=1.13.0
13 changes: 13 additions & 0 deletions scripts/run_mypy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
# ./scripts/run_mypy.sh

set -e

script_dir=$(dirname $0)
cd ${script_dir}/..

pip install -U pip setuptools wheel
pip install -r requirements/testing.txt \
-r requirements/optional.txt

mypy --config-file pyproject.toml
17 changes: 9 additions & 8 deletions slack_sdk/audit_logs/v1/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Refer to https://slack.dev/python-slack-sdk/audit-logs/ for details.
"""

import json
import logging
from ssl import SSLContext
Expand Down Expand Up @@ -225,7 +226,7 @@
headers: Dict[str, str],
) -> AuditLogsResponse:
if body_params is not None:
body_params = json.dumps(body_params)
body_params = json.dumps(body_params) # type: ignore[assignment]

Check warning on line 229 in slack_sdk/audit_logs/v1/async_client.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/async_client.py#L229

Added line #L229 was not covered by tests
headers["Content-Type"] = "application/json;charset=utf-8"

session: Optional[ClientSession] = None
Expand All @@ -252,7 +253,7 @@
retry_request = RetryHttpRequest(
method=http_verb,
url=url,
headers=headers,
headers=headers, # type: ignore[arg-type]
body_params=body_params,
)

Expand All @@ -278,19 +279,19 @@
)

try:
async with session.request(http_verb, url, **request_kwargs) as res:
async with session.request(http_verb, url, **request_kwargs) as res: # type: ignore[arg-type, union-attr] # noqa: E501
try:
response_body = await res.text()
retry_response = RetryHttpResponse(
status_code=res.status,
headers=res.headers,
headers=res.headers, # type: ignore[arg-type]
data=response_body.encode("utf-8") if response_body is not None else None,
)
except aiohttp.ContentTypeError:
self.logger.debug(f"No response data returned from the following API call: {url}.")
retry_response = RetryHttpResponse(
status_code=res.status,
headers=res.headers,
headers=res.headers, # type: ignore[arg-type]
)
except json.decoder.JSONDecodeError as e:
message = f"Failed to parse the response body: {str(e)}"
Expand Down Expand Up @@ -320,7 +321,7 @@
url=url,
status_code=res.status,
raw_body=response_body,
headers=res.headers,
headers=res.headers, # type: ignore[arg-type]
)
_debug_log_response(self.logger, resp)
return resp
Expand Down Expand Up @@ -351,10 +352,10 @@

if resp is not None:
return resp
raise last_error
raise last_error # type: ignore[misc]

Check warning on line 355 in slack_sdk/audit_logs/v1/async_client.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/async_client.py#L355

Added line #L355 was not covered by tests

finally:
if not use_running_session:
await session.close()
await session.close() # type: ignore[union-attr]

return resp
16 changes: 8 additions & 8 deletions slack_sdk/audit_logs/v1/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Refer to https://slack.dev/python-slack-sdk/audit-logs/ for details.
"""

import json
import logging
import urllib
Expand Down Expand Up @@ -217,7 +218,7 @@
headers: Dict[str, str],
) -> AuditLogsResponse:
if body is not None:
body = json.dumps(body)
body = json.dumps(body) # type: ignore[assignment]

Check warning on line 221 in slack_sdk/audit_logs/v1/client.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/client.py#L221

Added line #L221 was not covered by tests
headers["Content-Type"] = "application/json;charset=utf-8"

if self.logger.level <= logging.DEBUG:
Expand All @@ -229,7 +230,7 @@
req = Request(
method=http_verb,
url=url,
data=body.encode("utf-8") if body is not None else None,
data=body.encode("utf-8") if body is not None else None, # type: ignore[attr-defined]
headers=headers,
)
resp = None
Expand Down Expand Up @@ -327,7 +328,7 @@

if resp is not None:
return resp
raise last_error
raise last_error # type: ignore[misc]

Check warning on line 331 in slack_sdk/audit_logs/v1/client.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/client.py#L331

Added line #L331 was not covered by tests

def _perform_http_request_internal(self, url: str, req: Request) -> AuditLogsResponse:
opener: Optional[OpenerDirector] = None
Expand All @@ -344,19 +345,18 @@
else:
raise SlackRequestError(f"Invalid URL detected: {url}")

# NOTE: BAN-B310 is already checked above
http_resp: Optional[HTTPResponse] = None
http_resp: HTTPResponse
if opener:
http_resp = opener.open(req, timeout=self.timeout) # skipcq: BAN-B310
http_resp = opener.open(req, timeout=self.timeout)

Check warning on line 350 in slack_sdk/audit_logs/v1/client.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/client.py#L350

Added line #L350 was not covered by tests
else:
http_resp = urlopen(req, context=self.ssl, timeout=self.timeout) # skipcq: BAN-B310
http_resp = urlopen(req, context=self.ssl, timeout=self.timeout)
charset: str = http_resp.headers.get_content_charset() or "utf-8"
response_body: str = http_resp.read().decode(charset)
resp = AuditLogsResponse(
url=url,
status_code=http_resp.status,
raw_body=response_body,
headers=http_resp.headers,
headers=http_resp.headers, # type: ignore[arg-type]
)
_debug_log_response(self.logger, resp)
return resp
12 changes: 6 additions & 6 deletions slack_sdk/audit_logs/v1/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@
self.attributes = []
for a in attributes:
if isinstance(a, dict):
self.attributes.append(Attribute(**a))
self.attributes.append(Attribute(**a)) # type: ignore[arg-type]

Check warning on line 807 in slack_sdk/audit_logs/v1/logs.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/logs.py#L807

Added line #L807 was not covered by tests
else:
self.attributes.append(a)
self.channel = channel
Expand All @@ -822,11 +822,11 @@
self.rules_checked = None
if rules_checked is not None:
self.rules_checked = []
for a in rules_checked:
for a in rules_checked: # type: ignore[assignment]

Check warning on line 825 in slack_sdk/audit_logs/v1/logs.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/logs.py#L825

Added line #L825 was not covered by tests
if isinstance(a, dict):
self.rules_checked.append(AAARule(**a))
self.rules_checked.append(AAARule(**a)) # type: ignore[arg-type]

Check warning on line 827 in slack_sdk/audit_logs/v1/logs.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/logs.py#L827

Added line #L827 was not covered by tests
else:
self.rules_checked.append(a)
self.rules_checked.append(a) # type: ignore[arg-type]

Check warning on line 829 in slack_sdk/audit_logs/v1/logs.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/audit_logs/v1/logs.py#L829

Added line #L829 was not covered by tests
self.disconnecting_team = disconnecting_team
self.is_channel_canvas = is_channel_canvas
self.linked_channel_id = linked_channel_id
Expand Down Expand Up @@ -1021,7 +1021,7 @@
class WorkflowV2StepConfiguration:
name: Optional[str]
step_function_type: Optional[str]
step_function_app_id: Optional[int]
step_function_app_id: Optional[str]
unknown_fields: Dict[str, Any]

def __init__(
Expand Down Expand Up @@ -1235,7 +1235,7 @@
provided: Optional[str] = None,
**kwargs,
) -> None:
self.entries = [Entry(**e) if isinstance(e, dict) else e for e in entries]
self.entries = [Entry(**e) if isinstance(e, dict) else e for e in entries] # type: ignore[union-attr]
self.response_metadata = (
ResponseMetadata(**response_metadata) if isinstance(response_metadata, dict) else response_metadata
)
Expand Down
4 changes: 2 additions & 2 deletions slack_sdk/audit_logs/v1/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class AuditLogsResponse:
body: Optional[Dict[str, Any]]
typed_body: Optional[LogsResponse]

@property
def typed_body(self) -> Optional[LogsResponse]: # type: ignore
@property # type: ignore[no-redef]
def typed_body(self) -> Optional[LogsResponse]:
if self.body is None:
return None
return LogsResponse(**self.body)
Expand Down
6 changes: 3 additions & 3 deletions slack_sdk/http_retry/builtin_async_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
error: Optional[Exception] = None,
) -> None:
if response is None:
raise error
raise error # type: ignore[misc]

Check warning on line 71 in slack_sdk/http_retry/builtin_async_handlers.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/http_retry/builtin_async_handlers.py#L71

Added line #L71 was not covered by tests

state.next_attempt_requested = True
retry_after_header_name: Optional[str] = None
Expand All @@ -79,9 +79,9 @@
duration = 1
if retry_after_header_name is None:
# This situation usually does not arise. Just in case.
duration += random.random()
duration += random.random() # type: ignore[assignment]

Check warning on line 82 in slack_sdk/http_retry/builtin_async_handlers.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/http_retry/builtin_async_handlers.py#L82

Added line #L82 was not covered by tests
else:
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random()
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random() # type: ignore[assignment, index] # noqa: E501
await asyncio.sleep(duration)
state.increment_current_attempt()

Expand Down
6 changes: 3 additions & 3 deletions slack_sdk/http_retry/builtin_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
error: Optional[Exception] = None,
) -> None:
if response is None:
raise error
raise error # type: ignore[misc]

Check warning on line 74 in slack_sdk/http_retry/builtin_handlers.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/http_retry/builtin_handlers.py#L74

Added line #L74 was not covered by tests

state.next_attempt_requested = True
retry_after_header_name: Optional[str] = None
Expand All @@ -82,9 +82,9 @@
duration = 1
if retry_after_header_name is None:
# This situation usually does not arise. Just in case.
duration += random.random()
duration += random.random() # type: ignore[assignment]

Check warning on line 85 in slack_sdk/http_retry/builtin_handlers.py

View check run for this annotation

Codecov / codecov/patch

slack_sdk/http_retry/builtin_handlers.py#L85

Added line #L85 was not covered by tests
else:
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random()
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random() # type: ignore[index, assignment] # noqa: E501
time.sleep(duration)
state.increment_current_attempt()

Expand Down
4 changes: 2 additions & 2 deletions slack_sdk/http_retry/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def __init__(
@classmethod
def from_urllib_http_request(cls, req: Request) -> "HttpRequest":
return HttpRequest(
method=req.method,
method=req.method, # type: ignore[arg-type]
url=req.full_url,
headers={k: v if isinstance(v, list) else [v] for k, v in req.headers.items()},
data=req.data,
data=req.data, # type: ignore[arg-type]
)
2 changes: 1 addition & 1 deletion slack_sdk/http_retry/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class HttpResponse:
"""HTTP response representation"""

status_code: int
headers: Dict[str, List[str]]
headers: Dict[str, Union[List[str], str]]
body: Optional[Dict[str, Any]]
data: Optional[bytes]

Expand Down
11 changes: 5 additions & 6 deletions slack_sdk/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# NOTE: used only for legacy components - don't use this for Block Kit
def extract_json(
item_or_items: Union[JsonObject, Sequence[JsonObject]], *format_args
) -> Union[Dict[Any, Any], List[Dict[Any, Any]]]: # type: ignore
) -> Union[Dict[Any, Any], List[Dict[Any, Any]], Sequence[JsonObject]]:
"""
Given a sequence (or single item), attempt to call the to_dict() method on each
item and return a plain list. If item is not the expected type, return it
Expand All @@ -24,13 +24,12 @@ def extract_json(
method
"""
try:
return [ # type: ignore
elem.to_dict(*format_args) if isinstance(elem, JsonObject) else elem for elem in item_or_items
return [
elem.to_dict(*format_args) if isinstance(elem, JsonObject) else elem
for elem in item_or_items # type: ignore[union-attr]
]
except TypeError: # not iterable, so try returning it as a single item
return ( # type: ignore
item_or_items.to_dict(*format_args) if isinstance(item_or_items, JsonObject) else item_or_items
)
return item_or_items.to_dict(*format_args) if isinstance(item_or_items, JsonObject) else item_or_items


def show_unknown_key_warning(name: Union[str, object], others: dict):
Expand Down
8 changes: 4 additions & 4 deletions slack_sdk/models/attachments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(
def name_or_url_present(self):
return self.name is not None or self.url is not None

def to_dict(self) -> dict: # skipcq: PYL-W0221
def to_dict(self) -> dict:
json = super().to_dict()
json["type"] = self.subtype
return json
Expand Down Expand Up @@ -212,7 +212,7 @@ class ActionExternalSelector(AbstractActionSelector):
data_source = "external"

@property
def attributes(self) -> Set[str]:
def attributes(self) -> Set[str]: # type: ignore[override]
return super().attributes.union({"min_query_length"})

def __init__(
Expand Down Expand Up @@ -417,7 +417,7 @@ def author_link_without_author_name(self) -> bool:
def author_link_without_author_icon(self) -> bool:
return self.author_link is None or self.author_icon is not None

def to_dict(self) -> dict: # skipcq: PYL-W0221
def to_dict(self) -> dict:
json = super().to_dict()
if self.fields is not None:
json["fields"] = extract_json(self.fields)
Expand Down Expand Up @@ -469,7 +469,7 @@ def to_dict(self) -> dict:

class InteractiveAttachment(Attachment):
@property
def attributes(self) -> Set[str]:
def attributes(self) -> Set[str]: # type: ignore[override]
return super().attributes.union({"callback_id"})

actions_max_length = 5
Expand Down
Loading
Loading