Skip to content

Commit

Permalink
chore: move to mypy
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamBergamin committed Dec 20, 2024
1 parent c7710f0 commit 1474b81
Show file tree
Hide file tree
Showing 48 changed files with 217 additions and 189 deletions.
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ files = "slack_sdk/"
exclude = ["slack_sdk/scim", "slack_sdk/rtm"]
force_union_syntax = true
warn_unused_ignores = true
enable_error_code = "ignore-without-code"
13 changes: 9 additions & 4 deletions scripts/run_mypy.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#!/bin/bash
# ./scripts/run_mypy.sh

set -e

script_dir=$(dirname $0)
cd ${script_dir}/.. && \
pip install .
pip install -r requirements/testing.txt && \
mypy --config-file pyproject.toml
cd ${script_dir}/..

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

mypy --config-file pyproject.toml
2 changes: 1 addition & 1 deletion slack_sdk/audit_logs/v1/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ async def _perform_http_request(
)

try:
async with session.request(http_verb, url, **request_kwargs) as res: # type: ignore[arg-type, union-attr]
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(
Expand Down
2 changes: 1 addition & 1 deletion slack_sdk/audit_logs/v1/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class AuditLogsResponse:
body: Optional[Dict[str, Any]]
typed_body: Optional[LogsResponse]

@property # type:ignore[no-redef]
@property # type: ignore[no-redef]
def typed_body(self) -> Optional[LogsResponse]:
if self.body is None:
return None
Expand Down
2 changes: 1 addition & 1 deletion slack_sdk/http_retry/builtin_async_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ async def prepare_for_next_attempt_async(
# This situation usually does not arise. Just in case.
duration += random.random() # type: ignore[assignment]
else:
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random() # type: ignore[assignment, index]
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
2 changes: 1 addition & 1 deletion slack_sdk/http_retry/builtin_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def prepare_for_next_attempt(
# This situation usually does not arise. Just in case.
duration += random.random() # type: ignore[assignment]
else:
duration = int(response.headers.get(retry_after_header_name)[0]) + random.random() # type: ignore[index, assignment]
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/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 @@ -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
8 changes: 4 additions & 4 deletions slack_sdk/models/basic_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ def get_non_null_attributes(self) -> dict:
"""

def to_dict_compatible(value: Union[dict, list, object, tuple]) -> Union[dict, list, Any]:
if isinstance(value, (list, tuple)): # skipcq: PYL-R1705
if isinstance(value, (list, tuple)):
return [to_dict_compatible(v) for v in value]
else:
to_dict = getattr(value, "to_dict", None)
if to_dict and callable(to_dict): # skipcq: PYL-R1705
if to_dict and callable(to_dict):
return {k: to_dict_compatible(v) for k, v in value.to_dict().items()} # type: ignore[attr-defined]
else:
return value
Expand All @@ -69,7 +69,7 @@ def is_not_empty(self, key: str) -> bool:
return True

has_len = getattr(value, "__len__", None) is not None
if has_len: # skipcq: PYL-R1705
if has_len:
return len(value) > 0
else:
return value is not None
Expand All @@ -93,7 +93,7 @@ def to_dict(self, *args) -> dict:

def __repr__(self):
dict_value = self.get_non_null_attributes()
if dict_value: # skipcq: PYL-R1705
if dict_value:
return f"<slack_sdk.{self.__class__.__name__}: {dict_value}>"
else:
return self.__str__()
Expand Down
36 changes: 18 additions & 18 deletions slack_sdk/models/blocks/basic_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class TextObject(JsonObject):
attributes = {"text", "type", "emoji"}
logger = logging.getLogger(__name__)

def _subtype_warning(self): # skipcq: PYL-R0201
def _subtype_warning(self):
warnings.warn(
"subtype is deprecated since slackclient 2.6.0, use type instead",
DeprecationWarning,
Expand All @@ -36,17 +36,17 @@ def parse(
text: Union[str, Dict[str, Any], "TextObject"],
default_type: str = "mrkdwn",
) -> Optional["TextObject"]:
if not text: # skipcq: PYL-R1705
if not text:
return None
elif isinstance(text, str):
if default_type == PlainTextObject.type: # skipcq: PYL-R1705
if default_type == PlainTextObject.type:
return PlainTextObject.from_str(text)
else:
return MarkdownTextObject.from_str(text)
elif isinstance(text, dict):
d = copy.copy(text)
t = d.pop("type")
if t == PlainTextObject.type: # skipcq: PYL-R1705
if t == PlainTextObject.type:
return PlainTextObject(**d)
else:
return MarkdownTextObject(**d)
Expand All @@ -59,7 +59,7 @@ def parse(
def __init__(
self,
text: str,
type: Optional[str] = None, # skipcq: PYL-W0622
type: Optional[str] = None,
subtype: Optional[str] = None,
emoji: Optional[bool] = None,
**kwargs,
Expand Down Expand Up @@ -273,14 +273,14 @@ def parse_all(cls, options: Optional[Sequence[Union[Dict[str, Any], "Option"]]])
cls.logger.warning(f"Unknown option object detected and skipped ({o})")
return option_objects

def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self, option_type: str = "block") -> Dict[str, Any]:
"""
Different parent classes must call this with a valid value from OptionTypes -
either "dialog", "action", or "block", so that JSON is returned in the
correct shape.
"""
self.validate_json()
if option_type == "dialog": # skipcq: PYL-R1705
if option_type == "dialog":
return {"label": self.label, "value": self.value}
elif option_type == "action" or option_type == "attachment":
# "action" can be confusing but it means a legacy message action in attachments
Expand Down Expand Up @@ -343,7 +343,7 @@ def __init__(
options: A list of no more than 100 Option objects.
""" # noqa prevent flake8 blowing up on the long URL
# default_type=PlainTextObject.type is for backward-compatibility
self._label: Optional[TextObject] = TextObject.parse(label, default_type=PlainTextObject.type) # type: ignore[arg-type]
self._label: Optional[TextObject] = TextObject.parse(label, default_type=PlainTextObject.type) # type: ignore[arg-type] # noqa: E501
self.label: Optional[str] = self._label.text if self._label else None
self.options = Option.parse_all(options) # compatible with version 2.5
show_unknown_key_warning(self, others)
Expand Down Expand Up @@ -373,10 +373,10 @@ def parse_all(
cls.logger.warning(f"Unknown option group object detected and skipped ({o})")
return option_group_objects

def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self, option_type: str = "block") -> Dict[str, Any]:
self.validate_json()
dict_options = [o.to_dict(option_type) for o in self.options] # type: ignore[union-attr]
if option_type == "dialog": # skipcq: PYL-R1705
if option_type == "dialog":
return {
"label": self.label,
"options": dict_options,
Expand Down Expand Up @@ -405,7 +405,7 @@ class ConfirmObject(JsonObject):
@classmethod
def parse(cls, confirm: Union["ConfirmObject", Dict[str, Any]]):
if confirm:
if isinstance(confirm, ConfirmObject): # skipcq: PYL-R1705
if isinstance(confirm, ConfirmObject):
return confirm
elif isinstance(confirm, dict):
return ConfirmObject(**confirm)
Expand Down Expand Up @@ -462,8 +462,8 @@ def deny_length(self) -> bool:
def _validate_confirm_style(self) -> bool:
return self._style is None or self._style in ["primary", "danger"]

def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
if option_type == "action": # skipcq: PYL-R1705
def to_dict(self, option_type: str = "block") -> Dict[str, Any]:
if option_type == "action":
# deliberately skipping JSON validators here - can't find documentation
# on actual limits here
json: Dict[str, Union[str, dict]] = {
Expand Down Expand Up @@ -498,7 +498,7 @@ class DispatchActionConfig(JsonObject):
@classmethod
def parse(cls, config: Union["DispatchActionConfig", Dict[str, Any]]):
if config:
if isinstance(config, DispatchActionConfig): # skipcq: PYL-R1705
if isinstance(config, DispatchActionConfig):
return config
elif isinstance(config, dict):
return DispatchActionConfig(**config)
Expand All @@ -518,7 +518,7 @@ def __init__(
"""
self._trigger_actions_on = trigger_actions_on or []

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json = {}
if self._trigger_actions_on:
Expand All @@ -533,7 +533,7 @@ def __init__(self, *, url: str, customizable_input_parameters: Optional[List[Dic
self._url = url
self._customizable_input_parameters = customizable_input_parameters

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json = {"url": self._url}
if self._customizable_input_parameters is not None:
Expand All @@ -551,7 +551,7 @@ def __init__(
):
self._trigger = trigger

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json = {}
if isinstance(self._trigger, WorkflowTrigger):
Expand Down Expand Up @@ -580,7 +580,7 @@ def __init__(
self._id = id
self._url = url

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json = {}
if self._id is not None:
Expand Down
22 changes: 11 additions & 11 deletions slack_sdk/models/blocks/block_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class BlockElement(JsonObject, metaclass=ABCMeta):
attributes = {"type"}
logger = logging.getLogger(__name__)

def _subtype_warning(self): # skipcq: PYL-R0201
def _subtype_warning(self):
warnings.warn(
"subtype is deprecated since slackclient 2.6.0, use type instead",
DeprecationWarning,
Expand All @@ -47,7 +47,7 @@ def subtype(self) -> Optional[str]:
def __init__(
self,
*,
type: Optional[str] = None, # skipcq: PYL-W0622
type: Optional[str] = None,
subtype: Optional[str] = None,
**others: dict,
):
Expand All @@ -58,7 +58,7 @@ def __init__(

@classmethod
def parse(cls, block_element: Union[dict, "BlockElement"]) -> Optional[Union["BlockElement", TextObject]]:
if block_element is None: # skipcq: PYL-R1705
if block_element is None:
return None
elif isinstance(block_element, dict):
if "type" in block_element:
Expand All @@ -67,7 +67,7 @@ def parse(cls, block_element: Union[dict, "BlockElement"]) -> Optional[Union["Bl
for subclass in cls._get_sub_block_elements():
if t == subclass.type:
return subclass(**d)
if t == PlainTextObject.type: # skipcq: PYL-R1705
if t == PlainTextObject.type:
return PlainTextObject(**d)
elif t == MarkdownTextObject.type:
return MarkdownTextObject(**d)
Expand All @@ -80,7 +80,7 @@ def parse(cls, block_element: Union[dict, "BlockElement"]) -> Optional[Union["Bl
def parse_all(
cls, block_elements: Sequence[Union[dict, "BlockElement", TextObject]]
) -> List[Union["BlockElement", TextObject]]:
return [cls.parse(e) for e in block_elements or []] # type: ignore
return [cls.parse(e) for e in block_elements or []] # type: ignore[arg-type, misc]

@classmethod
def _get_sub_block_elements(cls: Type["BlockElement"]) -> Iterator[Type["BlockElement"]]:
Expand All @@ -107,7 +107,7 @@ def __init__(
self,
*,
action_id: Optional[str] = None,
type: Optional[str] = None, # skipcq: PYL-W0622
type: Optional[str] = None,
subtype: Optional[str] = None,
**others: dict,
):
Expand Down Expand Up @@ -145,7 +145,7 @@ def __init__(
*,
action_id: Optional[str] = None,
placeholder: Optional[Union[str, TextObject]] = None,
type: Optional[str] = None, # skipcq: PYL-W0622
type: Optional[str] = None,
subtype: Optional[str] = None,
confirm: Optional[Union[dict, ConfirmObject]] = None,
focus_on_load: Optional[bool] = None,
Expand Down Expand Up @@ -1077,8 +1077,8 @@ def __init__(
self.exclude_external_shared_channels = exclude_external_shared_channels

@classmethod
def parse(cls, filter: Union[dict, "ConversationFilter"]): # skipcq: PYL-W0622
if filter is None: # skipcq: PYL-R1705
def parse(cls, filter: Union[dict, "ConversationFilter"]):
if filter is None:
return None
elif isinstance(filter, ConversationFilter):
return filter
Expand Down Expand Up @@ -1113,7 +1113,7 @@ def __init__(
confirm: Optional[Union[dict, ConfirmObject]] = None,
response_url_enabled: Optional[bool] = None,
default_to_current_conversation: Optional[bool] = None,
filter: Optional[ConversationFilter] = None, # skipcq: PYL-W0622
filter: Optional[ConversationFilter] = None,
focus_on_load: Optional[bool] = None,
**others: dict,
):
Expand Down Expand Up @@ -1181,7 +1181,7 @@ def __init__(
confirm: Optional[Union[dict, ConfirmObject]] = None,
max_selected_items: Optional[int] = None,
default_to_current_conversation: Optional[bool] = None,
filter: Optional[Union[dict, ConversationFilter]] = None, # skipcq: PYL-W0622
filter: Optional[Union[dict, ConversationFilter]] = None,
focus_on_load: Optional[bool] = None,
**others: dict,
):
Expand Down
Loading

0 comments on commit 1474b81

Please sign in to comment.