diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml new file mode 100644 index 000000000..c368d1015 --- /dev/null +++ b/.github/workflows/mypy.yml @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 66b5e193a..65b4ae7fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" diff --git a/scripts/run_mypy.sh b/scripts/run_mypy.sh index 693501a1e..e7ffb7970 100755 --- a/scripts/run_mypy.sh +++ b/scripts/run_mypy.sh @@ -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 diff --git a/slack_sdk/audit_logs/v1/async_client.py b/slack_sdk/audit_logs/v1/async_client.py index 4a1c33705..24e22ec6a 100644 --- a/slack_sdk/audit_logs/v1/async_client.py +++ b/slack_sdk/audit_logs/v1/async_client.py @@ -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( diff --git a/slack_sdk/audit_logs/v1/response.py b/slack_sdk/audit_logs/v1/response.py index 08ff0b0dd..a2e0705d5 100644 --- a/slack_sdk/audit_logs/v1/response.py +++ b/slack_sdk/audit_logs/v1/response.py @@ -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 diff --git a/slack_sdk/http_retry/builtin_async_handlers.py b/slack_sdk/http_retry/builtin_async_handlers.py index 491619b55..0d99d67a7 100644 --- a/slack_sdk/http_retry/builtin_async_handlers.py +++ b/slack_sdk/http_retry/builtin_async_handlers.py @@ -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() diff --git a/slack_sdk/http_retry/builtin_handlers.py b/slack_sdk/http_retry/builtin_handlers.py index d6f50a25f..8755d7c89 100644 --- a/slack_sdk/http_retry/builtin_handlers.py +++ b/slack_sdk/http_retry/builtin_handlers.py @@ -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() diff --git a/slack_sdk/models/attachments/__init__.py b/slack_sdk/models/attachments/__init__.py index ce1cd4635..e516ad35b 100644 --- a/slack_sdk/models/attachments/__init__.py +++ b/slack_sdk/models/attachments/__init__.py @@ -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 @@ -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) diff --git a/slack_sdk/models/basic_objects.py b/slack_sdk/models/basic_objects.py index f20754ec0..339358790 100644 --- a/slack_sdk/models/basic_objects.py +++ b/slack_sdk/models/basic_objects.py @@ -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 @@ -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 @@ -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"" else: return self.__str__() diff --git a/slack_sdk/models/blocks/basic_components.py b/slack_sdk/models/blocks/basic_components.py index dbe242ece..143d18e32 100644 --- a/slack_sdk/models/blocks/basic_components.py +++ b/slack_sdk/models/blocks/basic_components.py @@ -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, @@ -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) @@ -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, @@ -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 @@ -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) @@ -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, @@ -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) @@ -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]] = { @@ -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) @@ -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: @@ -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: @@ -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): @@ -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: diff --git a/slack_sdk/models/blocks/block_elements.py b/slack_sdk/models/blocks/block_elements.py index 7bdecce4f..4f0fc6d2d 100644 --- a/slack_sdk/models/blocks/block_elements.py +++ b/slack_sdk/models/blocks/block_elements.py @@ -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, @@ -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, ): @@ -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: @@ -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) @@ -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"]]: @@ -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, ): @@ -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, @@ -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 @@ -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, ): @@ -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, ): diff --git a/slack_sdk/models/blocks/blocks.py b/slack_sdk/models/blocks/blocks.py index 34fd9eb10..59ebac676 100644 --- a/slack_sdk/models/blocks/blocks.py +++ b/slack_sdk/models/blocks/blocks.py @@ -33,7 +33,7 @@ class Block(JsonObject): block_id_max_length = 255 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, @@ -46,7 +46,7 @@ def subtype(self) -> Optional[str]: def __init__( self, *, - type: Optional[str] = None, # skipcq: PYL-W0622 + type: Optional[str] = None, subtype: Optional[str] = None, # deprecated block_id: Optional[str] = None, ): @@ -62,14 +62,14 @@ def _validate_block_id_length(self): @classmethod def parse(cls, block: Union[dict, "Block"]) -> Optional["Block"]: - if block is None: # skipcq: PYL-R1705 + if block is None: return None elif isinstance(block, Block): return block else: if "type" in block: - type = block["type"] # skipcq: PYL-W0622 - if type == SectionBlock.type: # skipcq: PYL-R1705 + type = block["type"] + if type == SectionBlock.type: return SectionBlock(**block) elif type == DividerBlock.type: return DividerBlock(**block) @@ -100,7 +100,7 @@ def parse(cls, block: Union[dict, "Block"]) -> Optional["Block"]: @classmethod def parse_all(cls, blocks: Optional[Sequence[Union[dict, "Block"]]]) -> List["Block"]: - return [cls.parse(b) for b in blocks or []] # type: ignore + return [cls.parse(b) for b in blocks or []] # type: ignore[misc] # ------------------------------------------------- diff --git a/slack_sdk/models/dialogs/__init__.py b/slack_sdk/models/dialogs/__init__.py index e020e85c9..f59a7f856 100644 --- a/slack_sdk/models/dialogs/__init__.py +++ b/slack_sdk/models/dialogs/__init__.py @@ -178,7 +178,7 @@ def placeholder_length(self) -> bool: def data_source_valid(self) -> bool: return self.data_source in self.DataSourceTypes - def to_dict(self) -> dict: # skipcq: PYL-W0221 + def to_dict(self) -> dict: json = super().to_dict() if self.data_source == "external": if isinstance(self.value, Option): @@ -262,7 +262,7 @@ def to_dict(self) -> dict: class DialogUserSelector(AbstractDialogSelector): data_source = "users" - def __init__( # skipcq: PYL-W0235 + def __init__( self, *, name: str, @@ -300,7 +300,7 @@ def __init__( # skipcq: PYL-W0235 class DialogChannelSelector(AbstractDialogSelector): data_source = "channels" - def __init__( # skipcq: PYL-W0235 + def __init__( self, *, name: str, @@ -336,7 +336,7 @@ def __init__( # skipcq: PYL-W0235 class DialogConversationSelector(AbstractDialogSelector): data_source = "conversations" - def __init__( # skipcq: PYL-W0235 + def __init__( self, *, name: str, @@ -421,7 +421,7 @@ def __init__( class DialogBuilder(JsonObject): - attributes = Set() # no attributes because to_dict has unique implementation + attributes = set() # no attributes because to_dict has unique implementation _callback_id: Optional[str] _elements: List[Union[DialogTextComponent, AbstractDialogSelector]] @@ -837,7 +837,7 @@ def submit_label_valid(self) -> bool: def state_length(self) -> bool: return not self._state or len(self._state) <= self.state_max_length - def to_dict(self) -> dict: # skipcq: PYL-W0221 + def to_dict(self) -> dict: self.validate_json() json = { "title": self._title, diff --git a/slack_sdk/models/messages/message.py b/slack_sdk/models/messages/message.py index 6d92ebe3d..355e3befa 100644 --- a/slack_sdk/models/messages/message.py +++ b/slack_sdk/models/messages/message.py @@ -57,7 +57,7 @@ def __init__( def attachments_length(self): return self.attachments is None or len(self.attachments) <= self.attachments_max_length - def to_dict(self) -> dict: # skipcq: PYL-W0221 + def to_dict(self) -> dict: json = super().to_dict() if len(self.text) > 40000: LOGGER.error("Messages over 40,000 characters are automatically truncated by Slack") diff --git a/slack_sdk/models/views/__init__.py b/slack_sdk/models/views/__init__.py index 800a5acb0..5bcc5a691 100644 --- a/slack_sdk/models/views/__init__.py +++ b/slack_sdk/models/views/__init__.py @@ -38,8 +38,8 @@ class View(JsonObject): def __init__( self, # "modal", "home", and "workflow_step" - type: str, # skipcq: PYL-W0622 - id: Optional[str] = None, # skipcq: PYL-W0622 + type: str, + id: Optional[str] = None, callback_id: Optional[str] = None, external_id: Optional[str] = None, team_id: Optional[str] = None, @@ -53,7 +53,7 @@ def __init__( blocks: Optional[Sequence[Union[dict, Block]]] = None, private_metadata: Optional[str] = None, state: Optional[Union[dict, "ViewState"]] = None, - hash: Optional[str] = None, # skipcq: PYL-W0622 + hash: Optional[str] = None, clear_on_close: Optional[bool] = None, notify_on_close: Optional[bool] = None, **kwargs, @@ -145,7 +145,7 @@ def __init__( new_state_values = copy.copy(values) if isinstance(new_state_values, dict): # just in case for block_id, actions in new_state_values.items(): - if actions is None: # skipcq: PYL-R1724 + if actions is None: continue elif isinstance(actions, dict): new_actions: Dict[str, Union[ViewStateValue, dict]] = copy.copy(actions) @@ -196,7 +196,7 @@ class ViewStateValue(JsonObject): def __init__( self, *, - type: Optional[str] = None, # skipcq: PYL-W0622 + type: Optional[str] = None, value: Optional[str] = None, selected_date: Optional[str] = None, selected_time: Optional[str] = None, diff --git a/slack_sdk/oauth/installation_store/amazon_s3/__init__.py b/slack_sdk/oauth/installation_store/amazon_s3/__init__.py index 15d36d097..c5c420f12 100644 --- a/slack_sdk/oauth/installation_store/amazon_s3/__init__.py +++ b/slack_sdk/oauth/installation_store/amazon_s3/__init__.py @@ -174,7 +174,7 @@ def find_bot( body = fetch_response["Body"].read().decode("utf-8") data = json.loads(body) return Bot(**data) - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" self.logger.warning(message) return None @@ -243,7 +243,7 @@ def find_installation( return installation - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find an installation data for enterprise: {e_id}, team: {t_id}: {e}" self.logger.warning(message) return None @@ -272,7 +272,7 @@ def delete_bot(self, *, enterprise_id: Optional[str], team_id: Optional[str]) -> Bucket=self.bucket_name, Key=content.get("Key"), ) - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" raise SlackClientConfigurationError(message) @@ -315,7 +315,7 @@ def delete_installation( Key=key, ) deleted_keys.append(key) - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" raise SlackClientConfigurationError(message) @@ -327,7 +327,7 @@ def delete_installation( Key=no_user_id_key, ) deleted_keys.append(no_user_id_key) - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" raise SlackClientConfigurationError(message) @@ -346,6 +346,6 @@ def delete_installation( Bucket=self.bucket_name, Key=content.get("Key"), ) - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" raise SlackClientConfigurationError(message) diff --git a/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py b/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py index d7b128245..6c2cccdfe 100644 --- a/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py +++ b/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py @@ -26,7 +26,7 @@ def __init__(self, installation_store: AsyncInstallationStore): def logger(self) -> Logger: return self.underlying.logger - async def async_save(self, installation: Installation): # type: ignore + async def async_save(self, installation: Installation): # type: ignore[explicit-override] # Invalidate cache data for update operations key = f"{installation.enterprise_id or ''}-{installation.team_id or ''}" if key in self.cached_bots: @@ -36,14 +36,14 @@ async def async_save(self, installation: Installation): # type: ignore self.cached_installations.pop(key) return await self.underlying.async_save(installation) - async def async_save_bot(self, bot: Bot): # type: ignore + async def async_save_bot(self, bot: Bot): # type: ignore[explicit-override] # Invalidate cache data for update operations key = f"{bot.enterprise_id or ''}-{bot.team_id or ''}" if key in self.cached_bots: self.cached_bots.pop(key) return await self.underlying.async_save_bot(bot) - async def async_find_bot( # type: ignore + async def async_find_bot( # type: ignore[explicit-override] self, *, enterprise_id: Optional[str], @@ -64,7 +64,7 @@ async def async_find_bot( # type: ignore self.cached_bots[key] = bot return bot - async def async_find_installation( # type: ignore + async def async_find_installation( # type: ignore[explicit-override] self, *, enterprise_id: Optional[str], diff --git a/slack_sdk/oauth/installation_store/cacheable_installation_store.py b/slack_sdk/oauth/installation_store/cacheable_installation_store.py index 9a33bd29a..506aa2d0b 100644 --- a/slack_sdk/oauth/installation_store/cacheable_installation_store.py +++ b/slack_sdk/oauth/installation_store/cacheable_installation_store.py @@ -24,7 +24,7 @@ def __init__(self, installation_store: InstallationStore): def logger(self) -> Logger: return self.underlying.logger - def save(self, installation: Installation): # type: ignore + def save(self, installation: Installation): # type: ignore[explicit-override] # Invalidate cache data for update operations key = f"{installation.enterprise_id or ''}-{installation.team_id or ''}" if key in self.cached_bots: @@ -35,14 +35,14 @@ def save(self, installation: Installation): # type: ignore return self.underlying.save(installation) - def save_bot(self, bot: Bot): # type: ignore + def save_bot(self, bot: Bot): # type: ignore[explicit-override] # Invalidate cache data for update operations key = f"{bot.enterprise_id or ''}-{bot.team_id or ''}" if key in self.cached_bots: self.cached_bots.pop(key) return self.underlying.save_bot(bot) - def find_bot( # type: ignore + def find_bot( # type: ignore[explicit-override] self, *, enterprise_id: Optional[str], @@ -63,7 +63,7 @@ def find_bot( # type: ignore self.cached_bots[key] = bot return bot - def find_installation( # type: ignore + def find_installation( # type: ignore[explicit-override] self, *, enterprise_id: Optional[str], diff --git a/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py b/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py index 04dcf956d..10cb73c0c 100644 --- a/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py +++ b/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py @@ -218,7 +218,7 @@ def find_bot( with self.engine.connect() as conn: result: object = conn.execute(query) - for row in result.mappings(): # type: ignore + for row in result.mappings(): # type: ignore[attr-defined] return Bot( app_id=row["app_id"], enterprise_id=row["enterprise_id"], @@ -266,7 +266,7 @@ def find_installation( installation: Optional[Installation] = None with self.engine.connect() as conn: result: object = conn.execute(query) - for row in result.mappings(): # type: ignore + for row in result.mappings(): # type: ignore[attr-defined] installation = Installation( app_id=row["app_id"], enterprise_id=row["enterprise_id"], diff --git a/slack_sdk/oauth/installation_store/sqlite3/__init__.py b/slack_sdk/oauth/installation_store/sqlite3/__init__.py index 0ac56226a..12acd05c7 100644 --- a/slack_sdk/oauth/installation_store/sqlite3/__init__.py +++ b/slack_sdk/oauth/installation_store/sqlite3/__init__.py @@ -37,7 +37,7 @@ def init(self): cur = conn.execute("select count(1) from slack_installations;") row_num = cur.fetchone()[0] self.logger.debug(f"{row_num} installations are stored in {self.database}") - except Exception: # skipcq: PYL-W0703 + except Exception: self.create_tables() self.init_called = True @@ -357,7 +357,7 @@ def find_bot( return bot return None - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find bot installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" if self.logger.level <= logging.DEBUG: self.logger.exception(message) @@ -532,7 +532,7 @@ def find_installation( return installation return None - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find an installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" if self.logger.level <= logging.DEBUG: self.logger.exception(message) @@ -558,7 +558,7 @@ def delete_bot(self, *, enterprise_id: Optional[str], team_id: Optional[str]) -> [self.client_id, enterprise_id or "", team_id or ""], ) conn.commit() - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to delete bot installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" if self.logger.level <= logging.DEBUG: self.logger.exception(message) @@ -607,7 +607,7 @@ def delete_installation( [self.client_id, enterprise_id or "", team_id, user_id], ) conn.commit() - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to delete installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" if self.logger.level <= logging.DEBUG: self.logger.exception(message) diff --git a/slack_sdk/oauth/state_store/amazon_s3/__init__.py b/slack_sdk/oauth/state_store/amazon_s3/__init__.py index 6d6afcee4..1ad590838 100644 --- a/slack_sdk/oauth/state_store/amazon_s3/__init__.py +++ b/slack_sdk/oauth/state_store/amazon_s3/__init__.py @@ -3,7 +3,7 @@ from logging import Logger from uuid import uuid4 -from botocore.client import BaseClient # type:ignore[import-untyped] +from botocore.client import BaseClient # type: ignore[import-untyped] from ..async_state_store import AsyncOAuthStateStore from ..state_store import OAuthStateStore @@ -63,7 +63,7 @@ def consume(self, state: str) -> bool: ) self.logger.debug(f"S3 delete_object response: {deletion_response}") return still_valid - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find any persistent data for state: {state} - {e}" self.logger.warning(message) return False diff --git a/slack_sdk/oauth/state_store/sqlalchemy/__init__.py b/slack_sdk/oauth/state_store/sqlalchemy/__init__.py index 50e8c4f97..74fa551d2 100644 --- a/slack_sdk/oauth/state_store/sqlalchemy/__init__.py +++ b/slack_sdk/oauth/state_store/sqlalchemy/__init__.py @@ -72,7 +72,7 @@ def consume(self, state: str) -> bool: conn.execute(self.oauth_states.delete().where(c.id == row["id"])) return True return False - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find any persistent data for state: {state} - {e}" self.logger.warning(message) return False diff --git a/slack_sdk/oauth/state_store/sqlite3/__init__.py b/slack_sdk/oauth/state_store/sqlite3/__init__.py index 8775c6e5f..8a82e333f 100644 --- a/slack_sdk/oauth/state_store/sqlite3/__init__.py +++ b/slack_sdk/oauth/state_store/sqlite3/__init__.py @@ -34,7 +34,7 @@ def init(self): cur = conn.execute("select count(1) from oauth_states;") row_num = cur.fetchone()[0] self.logger.debug(f"{row_num} oauth states are stored in {self.database}") - except Exception: # skipcq: PYL-W0703 + except Exception: self.create_tables() self.init_called = True @@ -85,12 +85,12 @@ def consume(self, state: str) -> bool: row = cur.fetchone() self.logger.debug(f"consume's query result: {row} (database: {self.database})") if row and len(row) > 0: - id = row[0] # skipcq: PYL-W0622 + id = row[0] conn.execute("delete from oauth_states where id = ?;", [id]) conn.commit() return True return False - except Exception as e: # skipcq: PYL-W0703 + except Exception as e: message = f"Failed to find any persistent data for state: {state} - {e}" self.logger.warning(message) return False diff --git a/slack_sdk/oauth/token_rotation/async_rotator.py b/slack_sdk/oauth/token_rotation/async_rotator.py index 9106064fe..1b4047bf1 100644 --- a/slack_sdk/oauth/token_rotation/async_rotator.py +++ b/slack_sdk/oauth/token_rotation/async_rotator.py @@ -135,7 +135,7 @@ async def perform_user_token_rotation( refreshed_installation = Installation(**installation.to_dict()) refreshed_installation.user_token = refresh_response.get("access_token") refreshed_installation.user_refresh_token = refresh_response.get("refresh_token") - refreshed_installation.user_token_expires_at = int(time()) + int(refresh_response.get("expires_in")) # type: ignore[arg-type] + refreshed_installation.user_token_expires_at = int(time()) + int(refresh_response.get("expires_in")) # type: ignore[arg-type] # noqa: E501 return refreshed_installation except SlackApiError as e: diff --git a/slack_sdk/rtm/__init__.py b/slack_sdk/rtm/__init__.py index dfcd75aed..5849cde52 100644 --- a/slack_sdk/rtm/__init__.py +++ b/slack_sdk/rtm/__init__.py @@ -23,7 +23,7 @@ validate_aiohttp_version(aiohttp.__version__) -class RTMClient(object): # skipcq: PYL-R0205 +class RTMClient(object): """An RTMClient allows apps to communicate with the Slack Platform's RTM API. The event-driven architecture of this client allows you to simply @@ -412,7 +412,7 @@ async def _read_messages(self): payload = message.json() event = payload.pop("type", "Unknown") await self._dispatch_event(event, data=payload) - except Exception as err: # skipcq: PYL-W0703 + except Exception as err: data = message.data if message else message self._logger.info(f"Caught a raised exception ({err}) while dispatching a TEXT message ({data})") # Raised exceptions here happen in users' code and were just unhandled. @@ -562,9 +562,7 @@ def _close_websocket(self) -> Sequence[Future]: futures = [] close_method = getattr(self._websocket, "close", None) if callable(close_method): - future = asyncio.ensure_future( # skipcq: PYL-E1102 - close_method(), loop=self._event_loop # skipcq: PYL-E1102 - ) # skipcq: PYL-E1102 + future = asyncio.ensure_future(close_method(), loop=self._event_loop) futures.append(future) self._websocket = None event_f = asyncio.ensure_future(self._dispatch_event(event="close"), loop=self._event_loop) diff --git a/slack_sdk/scim/v1/client.py b/slack_sdk/scim/v1/client.py index 450c02d81..d9a4c062d 100644 --- a/slack_sdk/scim/v1/client.py +++ b/slack_sdk/scim/v1/client.py @@ -4,6 +4,7 @@ Refer to https://slack.dev/python-slack-sdk/scim/ for details. """ + import json import logging import urllib @@ -145,9 +146,9 @@ def patch_user(self, id: str, partial_user: Union[Dict[str, Any], User]) -> User self.api_call( http_verb="PATCH", path=f"Users/{quote(id)}", - body_params=partial_user.to_dict() - if isinstance(partial_user, User) - else _to_dict_without_not_given(partial_user), + body_params=( + partial_user.to_dict() if isinstance(partial_user, User) else _to_dict_without_not_given(partial_user) + ), ) ) @@ -210,9 +211,11 @@ def patch_group(self, id: str, partial_group: Union[Dict[str, Any], Group]) -> G self.api_call( http_verb="PATCH", path=f"Groups/{quote(id)}", - body_params=partial_group.to_dict() - if isinstance(partial_group, Group) - else _to_dict_without_not_given(partial_group), + body_params=( + partial_group.to_dict() + if isinstance(partial_group, Group) + else _to_dict_without_not_given(partial_group) + ), ) ) @@ -403,9 +406,9 @@ def _perform_http_request_internal(self, url: str, req: Request) -> SCIMResponse # NOTE: BAN-B310 is already checked above http_resp: Optional[HTTPResponse] = None if opener: - http_resp = opener.open(req, timeout=self.timeout) # skipcq: BAN-B310 + http_resp = opener.open(req, timeout=self.timeout) 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 = SCIMResponse( diff --git a/slack_sdk/scim/v1/response.py b/slack_sdk/scim/v1/response.py index b9fb377b8..5f1495b21 100644 --- a/slack_sdk/scim/v1/response.py +++ b/slack_sdk/scim/v1/response.py @@ -61,7 +61,7 @@ def __repr__(self): for key, value in vars(self).items(): dict_value[key] = value.to_dict() if hasattr(value, "to_dict") else value - if dict_value: # skipcq: PYL-R1705 + if dict_value: return f"" else: return self.__str__() diff --git a/slack_sdk/signature/__init__.py b/slack_sdk/signature/__init__.py index 8a1b87a68..b9e97953f 100644 --- a/slack_sdk/signature/__init__.py +++ b/slack_sdk/signature/__init__.py @@ -7,7 +7,7 @@ class Clock: - def now(self) -> float: # skipcq: PYL-R0201 + def now(self) -> float: return time() diff --git a/slack_sdk/socket_mode/aiohttp/__init__.py b/slack_sdk/socket_mode/aiohttp/__init__.py index 839bfc76a..3582a2ed3 100644 --- a/slack_sdk/socket_mode/aiohttp/__init__.py +++ b/slack_sdk/socket_mode/aiohttp/__init__.py @@ -419,7 +419,7 @@ async def send_message(self, message: str): if self.logger.level <= logging.DEBUG: self.logger.debug(f"Sending a message: {message} from session: {session_id}") try: - await self.current_session.send_str(message) # type:ignore[union-attr] + await self.current_session.send_str(message) # type: ignore[union-attr] except ConnectionError as e: # We rarely get this exception while replacing the underlying WebSocket connections. # We can do one more try here as the self.current_session should be ready now. diff --git a/slack_sdk/socket_mode/async_listeners.py b/slack_sdk/socket_mode/async_listeners.py index beb98abd9..9b3ac86c3 100644 --- a/slack_sdk/socket_mode/async_listeners.py +++ b/slack_sdk/socket_mode/async_listeners.py @@ -3,18 +3,18 @@ from slack_sdk.socket_mode.request import SocketModeRequest -class AsyncWebSocketMessageListener(Callable): # type:ignore[misc] +class AsyncWebSocketMessageListener(Callable): # type: ignore[misc] async def __call__( - client: "AsyncBaseSocketModeClient", # type:ignore[name-defined] # noqa: F821 + client: "AsyncBaseSocketModeClient", # type: ignore[name-defined] # noqa: F821 message: dict, raw_message: Optional[str] = None, ): # noqa: F821 raise NotImplementedError() -class AsyncSocketModeRequestListener(Callable): # type:ignore[misc] +class AsyncSocketModeRequestListener(Callable): # type: ignore[misc] async def __call__( - client: "AsyncBaseSocketModeClient", # type:ignore[name-defined] # noqa: F821 + client: "AsyncBaseSocketModeClient", # type: ignore[name-defined] # noqa: F821 request: SocketModeRequest, ): # noqa: F821 raise NotImplementedError() diff --git a/slack_sdk/socket_mode/builtin/internals.py b/slack_sdk/socket_mode/builtin/internals.py index d958a9165..c4c84e500 100644 --- a/slack_sdk/socket_mode/builtin/internals.py +++ b/slack_sdk/socket_mode/builtin/internals.py @@ -241,7 +241,7 @@ def _fetch_messages( ) -> List[Tuple[Optional[FrameHeader], bytes]]: if remaining_bytes is None: # Fetch more to complete the current message - remaining_bytes = receive() # type: ignore + remaining_bytes = receive() # type: ignore[call-arg] if remaining_bytes is None or len(remaining_bytes) == 0: # no more bytes @@ -252,7 +252,7 @@ def _fetch_messages( if current_header is None: # new message if len(remaining_bytes) <= 2: - remaining_bytes += receive() # type: ignore + remaining_bytes += receive() # type: ignore[call-arg] if remaining_bytes[0] == 10: # \n if current_data is not None and len(current_data) >= 0: diff --git a/slack_sdk/socket_mode/client.py b/slack_sdk/socket_mode/client.py index 229900fcd..ab1147baa 100644 --- a/slack_sdk/socket_mode/client.py +++ b/slack_sdk/socket_mode/client.py @@ -131,16 +131,16 @@ def run_message_listeners(self, message: dict, raw_message: str) -> None: for listener in self.message_listeners: try: - listener(self, message, raw_message) # type:ignore[call-arg, arg-type] + listener(self, message, raw_message) # type: ignore[call-arg, arg-type] except Exception as e: self.logger.exception(f"Failed to run a message listener: {e}") if len(self.socket_mode_request_listeners) > 0: request = SocketModeRequest.from_dict(message) if request is not None: - for listener in self.socket_mode_request_listeners: # type:ignore[assignment] + for listener in self.socket_mode_request_listeners: # type: ignore[assignment] try: - listener(self, request) # type:ignore[call-arg, arg-type] + listener(self, request) # type: ignore[call-arg, arg-type] except Exception as e: self.logger.exception(f"Failed to run a request listener: {e}") except Exception as e: diff --git a/slack_sdk/socket_mode/listeners.py b/slack_sdk/socket_mode/listeners.py index db0e3572b..37203fc35 100644 --- a/slack_sdk/socket_mode/listeners.py +++ b/slack_sdk/socket_mode/listeners.py @@ -5,7 +5,7 @@ class WebSocketMessageListener: def __call__( - client: "BaseSocketModeClient", # type:ignore[name-defined] # noqa: F821 + client: "BaseSocketModeClient", # type: ignore[name-defined] # noqa: F821 message: dict, raw_message: Optional[str] = None, ): # noqa: F821 @@ -13,5 +13,5 @@ def __call__( class SocketModeRequestListener: - def __call__(client: "BaseSocketModeClient", request: SocketModeRequest): # type: ignore # noqa: F821 # noqa: F821 + def __call__(client: "BaseSocketModeClient", request: SocketModeRequest): # type: ignore[name-defined] # noqa: F821, F821, E501 raise NotImplementedError() diff --git a/slack_sdk/socket_mode/request.py b/slack_sdk/socket_mode/request.py index 654d4e72d..4610e8ba7 100644 --- a/slack_sdk/socket_mode/request.py +++ b/slack_sdk/socket_mode/request.py @@ -50,7 +50,7 @@ def from_dict(cls, message: dict) -> Optional["SocketModeRequest"]: ) return None - def to_dict(self) -> dict: # skipcq: PYL-W0221 + def to_dict(self) -> dict: d = {"envelope_id": self.envelope_id} if self.payload is not None: d["payload"] = self.payload # type: ignore[assignment] diff --git a/slack_sdk/socket_mode/response.py b/slack_sdk/socket_mode/response.py index ee2a93d5b..7abcc14ac 100644 --- a/slack_sdk/socket_mode/response.py +++ b/slack_sdk/socket_mode/response.py @@ -21,7 +21,7 @@ def __init__(self, envelope_id: str, payload: Optional[Union[dict, JsonObject, s else: raise ValueError(f"Unsupported payload data type ({type(payload)})") - def to_dict(self) -> dict: # skipcq: PYL-W0221 + def to_dict(self) -> dict: d = {"envelope_id": self.envelope_id} if self.payload is not None: d["payload"] = self.payload # type: ignore[assignment] diff --git a/slack_sdk/socket_mode/websocket_client/__init__.py b/slack_sdk/socket_mode/websocket_client/__init__.py index 9cd8d899c..f004a94b1 100644 --- a/slack_sdk/socket_mode/websocket_client/__init__.py +++ b/slack_sdk/socket_mode/websocket_client/__init__.py @@ -220,12 +220,12 @@ def send_message(self, message: str) -> None: self.current_session.send(message) # type: ignore[union-attr] else: self.logger.warning( - f"The current session (session id: {self.session_id()}) is no longer active. " + f"The current session (session id: {self.session_id()}) is no longer active. " # type: ignore[attr-defined] # noqa: E501 "Failed to send a message" ) raise e - def close(self) -> None: # type: ignore + def close(self) -> None: # type: ignore[explicit-override, no-redef] self.closed = True self.auto_reconnect_enabled = False self.disconnect() diff --git a/slack_sdk/web/async_base_client.py b/slack_sdk/web/async_base_client.py index 04fea3027..22f93f518 100644 --- a/slack_sdk/web/async_base_client.py +++ b/slack_sdk/web/async_base_client.py @@ -88,7 +88,7 @@ def __init__( if env_variable is not None: self.proxy = env_variable - async def api_call( # skipcq: PYL-R1710 + async def api_call( self, api_method: str, *, @@ -96,7 +96,7 @@ async def api_call( # skipcq: PYL-R1710 files: Optional[dict] = None, data: Optional[Union[dict, FormData]] = None, params: Optional[dict] = None, - json: Optional[dict] = None, # skipcq: PYL-W0621 + json: Optional[dict] = None, headers: Optional[dict] = None, auth: Optional[dict] = None, ) -> AsyncSlackResponse: diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 105f2ccaf..9a6e144cf 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2209,10 +2209,10 @@ async def calls_add( "title": title, } ) - _update_call_participants( # skipcq: PTC-W0039 + _update_call_participants( kwargs, users if users is not None else kwargs.get("users"), # type: ignore[arg-type] - ) # skipcq: PTC-W0039 + ) return await self.api_call("calls.add", http_verb="POST", params=kwargs) async def calls_end( @@ -2221,7 +2221,7 @@ async def calls_end( id: str, duration: Optional[int] = None, **kwargs, - ) -> AsyncSlackResponse: # skipcq: PYL-W0622 + ) -> AsyncSlackResponse: """Ends a Call. https://api.slack.com/methods/calls.end """ @@ -2233,7 +2233,7 @@ async def calls_info( *, id: str, **kwargs, - ) -> AsyncSlackResponse: # skipcq: PYL-W0622 + ) -> AsyncSlackResponse: """Returns information about a Call. https://api.slack.com/methods/calls.info """ @@ -2243,7 +2243,7 @@ async def calls_info( async def calls_participants_add( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> AsyncSlackResponse: @@ -2257,7 +2257,7 @@ async def calls_participants_add( async def calls_participants_remove( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> AsyncSlackResponse: @@ -2276,7 +2276,7 @@ async def calls_update( join_url: Optional[str] = None, title: Optional[str] = None, **kwargs, - ) -> AsyncSlackResponse: # skipcq: PYL-W0622 + ) -> AsyncSlackResponse: """Updates information about a Call. https://api.slack.com/methods/calls.update """ @@ -3446,7 +3446,7 @@ async def files_comments_delete( *, file: str, id: str, - **kwargs, # skipcq: PYL-W0622 + **kwargs, ) -> AsyncSlackResponse: """Deletes an existing comment on a file. https://api.slack.com/methods/files.comments.delete @@ -3821,8 +3821,8 @@ async def files_upload_v2( token=kwargs.get("token"), ) _validate_for_legacy_client(url_response) - f["file_id"] = url_response.get("file_id") - f["upload_url"] = url_response.get("upload_url") + f["file_id"] = url_response.get("file_id") # type: ignore[union-attr, unused-ignore] + f["upload_url"] = url_response.get("upload_url") # type: ignore[union-attr, unused-ignore] # step2: "https://files.slack.com/upload/v1/..." per file for f in files: @@ -3857,8 +3857,8 @@ async def files_upload_v2( thread_ts=thread_ts, **kwargs, ) - if len(completion.get("files")) == 1: # type: ignore - completion.data["file"] = completion.get("files")[0] # type: ignore + if len(completion.get("files")) == 1: # type: ignore[arg-type] + completion.data["file"] = completion.get("files")[0] # type: ignore[index] return completion async def files_getUploadURLExternal( diff --git a/slack_sdk/web/async_slack_response.py b/slack_sdk/web/async_slack_response.py index 73466f9d1..2d2cbc680 100644 --- a/slack_sdk/web/async_slack_response.py +++ b/slack_sdk/web/async_slack_response.py @@ -141,7 +141,7 @@ async def __anext__(self): self._iteration += 1 if self._iteration == 1: return self - if _next_cursor_is_present(self.data): # skipcq: PYL-R1705 + if _next_cursor_is_present(self.data): params = self.req_args.get("params", {}) if params is None: params = {} @@ -149,7 +149,7 @@ async def __anext__(self): params.update({"cursor": next_cursor}) self.req_args.update({"params": params}) - response = await self._client._request( # skipcq: PYL-W0212 + response = await self._client._request( http_verb=self.http_verb, api_url=self.api_url, req_args=self.req_args, diff --git a/slack_sdk/web/base_client.py b/slack_sdk/web/base_client.py index 5f5e63289..f3c8f936c 100644 --- a/slack_sdk/web/base_client.py +++ b/slack_sdk/web/base_client.py @@ -92,7 +92,7 @@ def __init__( if env_variable is not None: self.proxy = env_variable - def api_call( # skipcq: PYL-R1710 + def api_call( self, api_method: str, *, @@ -100,7 +100,7 @@ def api_call( # skipcq: PYL-R1710 files: Optional[dict] = None, data: Optional[dict] = None, params: Optional[dict] = None, - json: Optional[dict] = None, # skipcq: PYL-W0621 + json: Optional[dict] = None, headers: Optional[dict] = None, auth: Optional[dict] = None, ) -> SlackResponse: @@ -294,7 +294,7 @@ def convert_params(values: dict) -> dict: url = f"{url}&{q}" if "?" in url else f"{url}?{q}" response = self._perform_urllib_http_request(url=url, args=request_args) # type: ignore[arg-type] - response_body = response.get("body", None) # skipcq: PTC-W0039 + response_body = response.get("body", None) response_body_data: Optional[Union[dict, bytes]] = response_body if response_body is not None and not isinstance(response_body, bytes): try: diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index f3afd284a..800e69e5b 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2200,10 +2200,10 @@ def calls_add( "title": title, } ) - _update_call_participants( # skipcq: PTC-W0039 + _update_call_participants( kwargs, users if users is not None else kwargs.get("users"), # type: ignore[arg-type] - ) # skipcq: PTC-W0039 + ) return self.api_call("calls.add", http_verb="POST", params=kwargs) def calls_end( @@ -2212,7 +2212,7 @@ def calls_end( id: str, duration: Optional[int] = None, **kwargs, - ) -> SlackResponse: # skipcq: PYL-W0622 + ) -> SlackResponse: """Ends a Call. https://api.slack.com/methods/calls.end """ @@ -2224,7 +2224,7 @@ def calls_info( *, id: str, **kwargs, - ) -> SlackResponse: # skipcq: PYL-W0622 + ) -> SlackResponse: """Returns information about a Call. https://api.slack.com/methods/calls.info """ @@ -2234,7 +2234,7 @@ def calls_info( def calls_participants_add( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> SlackResponse: @@ -2248,7 +2248,7 @@ def calls_participants_add( def calls_participants_remove( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> SlackResponse: @@ -2267,7 +2267,7 @@ def calls_update( join_url: Optional[str] = None, title: Optional[str] = None, **kwargs, - ) -> SlackResponse: # skipcq: PYL-W0622 + ) -> SlackResponse: """Updates information about a Call. https://api.slack.com/methods/calls.update """ @@ -3437,7 +3437,7 @@ def files_comments_delete( *, file: str, id: str, - **kwargs, # skipcq: PYL-W0622 + **kwargs, ) -> SlackResponse: """Deletes an existing comment on a file. https://api.slack.com/methods/files.comments.delete @@ -3812,8 +3812,8 @@ def files_upload_v2( token=kwargs.get("token"), ) _validate_for_legacy_client(url_response) - f["file_id"] = url_response.get("file_id") - f["upload_url"] = url_response.get("upload_url") + f["file_id"] = url_response.get("file_id") # type: ignore[union-attr, unused-ignore] + f["upload_url"] = url_response.get("upload_url") # type: ignore[union-attr, unused-ignore] # step2: "https://files.slack.com/upload/v1/..." per file for f in files: @@ -3848,8 +3848,8 @@ def files_upload_v2( thread_ts=thread_ts, **kwargs, ) - if len(completion.get("files")) == 1: # type: ignore - completion.data["file"] = completion.get("files")[0] # type: ignore + if len(completion.get("files")) == 1: # type: ignore[arg-type] + completion.data["file"] = completion.get("files")[0] # type: ignore[index] return completion def files_getUploadURLExternal( diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index bcab73a30..6a87b914e 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -136,7 +136,7 @@ def _build_req_args( data: dict, default_params: dict, params: dict, - json: dict, # skipcq: PYL-W0621 + json: dict, headers: dict, auth: dict, ssl: Optional[SSLContext], @@ -387,25 +387,25 @@ def _upload_file_via_v2_url( if opener: resp = opener.open(req, timeout=timeout) else: - resp = urlopen(req, context=ssl, timeout=timeout) # skipcq: BAN-B310 + resp = urlopen(req, context=ssl, timeout=timeout) - charset = resp.headers.get_content_charset() or "utf-8" # type:ignore[union-attr] + charset = resp.headers.get_content_charset() or "utf-8" # type: ignore[union-attr] # read the response body here - body: str = resp.read().decode(charset) # type:ignore[union-attr] + body: str = resp.read().decode(charset) # type: ignore[union-attr] if logger.level <= logging.DEBUG: message = ( "Received the following response - " - f"status: {resp.status}, " # type:ignore[union-attr] - f"headers: {dict(resp.headers)}, " # type:ignore[union-attr] + f"status: {resp.status}, " # type: ignore[union-attr] + f"headers: {dict(resp.headers)}, " # type: ignore[union-attr] f"body: {body}" ) logger.debug(message) - return {"status": resp.status, "headers": resp.headers, "body": body} # type:ignore[union-attr] + return {"status": resp.status, "headers": resp.headers, "body": body} # type: ignore[union-attr] def _validate_for_legacy_client( - response: Union["SlackResponse", Future], # type:ignore[name-defined] # noqa: F821 + response: Union["SlackResponse", Future], # type: ignore[name-defined] # noqa: F821 ) -> None: # Only LegacyWebClient can return this union type if isinstance(response, Future): diff --git a/slack_sdk/web/legacy_base_client.py b/slack_sdk/web/legacy_base_client.py index ae666ff22..0d5c2ac2d 100644 --- a/slack_sdk/web/legacy_base_client.py +++ b/slack_sdk/web/legacy_base_client.py @@ -1,4 +1,5 @@ """A Python module for interacting with Slack's Web API.""" + # mypy: ignore-errors import asyncio @@ -99,7 +100,7 @@ def __init__( self._event_loop = loop - def api_call( # skipcq: PYL-R1710 + def api_call( self, api_method: str, *, @@ -107,7 +108,7 @@ def api_call( # skipcq: PYL-R1710 files: Optional[dict] = None, data: Union[dict, FormData] = None, params: Optional[dict] = None, - json: Optional[dict] = None, # skipcq: PYL-W0621 + json: Optional[dict] = None, headers: Optional[dict] = None, auth: Optional[dict] = None, ) -> Union[asyncio.Future, SlackResponse]: @@ -159,7 +160,7 @@ def api_call( # skipcq: PYL-R1710 data=data, default_params=self.default_params, params=params, - json=json, # skipcq: PYL-W0621 + json=json, headers=headers, auth=auth, ssl=self.ssl, @@ -370,7 +371,7 @@ def convert_params(values: dict) -> dict: url = f"{url}&{q}" if "?" in url else f"{url}?{q}" response = self._perform_urllib_http_request(url=url, args=request_args) - body = response.get("body", None) # skipcq: PTC-W0039 + body = response.get("body", None) response_body_data: Optional[Union[dict, bytes]] = body if body is not None and not isinstance(body, bytes): try: @@ -481,9 +482,9 @@ def _perform_urllib_http_request(self, *, url: str, args: Dict[str, Dict[str, An # NOTE: BAN-B310 is already checked above resp: Optional[HTTPResponse] = None if opener: - resp = opener.open(req, timeout=self.timeout) # skipcq: BAN-B310 + resp = opener.open(req, timeout=self.timeout) else: - resp = urlopen(req, context=self.ssl, timeout=self.timeout) # skipcq: BAN-B310 + resp = urlopen(req, context=self.ssl, timeout=self.timeout) if resp.headers.get_content_type() == "application/gzip": # admin.analytics.getFile body: bytes = resp.read() diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 1580cfef3..fb6ae7fb0 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2211,10 +2211,10 @@ def calls_add( "title": title, } ) - _update_call_participants( # skipcq: PTC-W0039 + _update_call_participants( kwargs, users if users is not None else kwargs.get("users"), # type: ignore[arg-type] - ) # skipcq: PTC-W0039 + ) return self.api_call("calls.add", http_verb="POST", params=kwargs) def calls_end( @@ -2223,7 +2223,7 @@ def calls_end( id: str, duration: Optional[int] = None, **kwargs, - ) -> Union[Future, SlackResponse]: # skipcq: PYL-W0622 + ) -> Union[Future, SlackResponse]: """Ends a Call. https://api.slack.com/methods/calls.end """ @@ -2235,7 +2235,7 @@ def calls_info( *, id: str, **kwargs, - ) -> Union[Future, SlackResponse]: # skipcq: PYL-W0622 + ) -> Union[Future, SlackResponse]: """Returns information about a Call. https://api.slack.com/methods/calls.info """ @@ -2245,7 +2245,7 @@ def calls_info( def calls_participants_add( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> Union[Future, SlackResponse]: @@ -2259,7 +2259,7 @@ def calls_participants_add( def calls_participants_remove( self, *, - id: str, # skipcq: PYL-W0622 + id: str, users: Union[str, Sequence[Dict[str, str]]], **kwargs, ) -> Union[Future, SlackResponse]: @@ -2278,7 +2278,7 @@ def calls_update( join_url: Optional[str] = None, title: Optional[str] = None, **kwargs, - ) -> Union[Future, SlackResponse]: # skipcq: PYL-W0622 + ) -> Union[Future, SlackResponse]: """Updates information about a Call. https://api.slack.com/methods/calls.update """ @@ -3448,7 +3448,7 @@ def files_comments_delete( *, file: str, id: str, - **kwargs, # skipcq: PYL-W0622 + **kwargs, ) -> Union[Future, SlackResponse]: """Deletes an existing comment on a file. https://api.slack.com/methods/files.comments.delete @@ -3823,8 +3823,8 @@ def files_upload_v2( token=kwargs.get("token"), ) _validate_for_legacy_client(url_response) - f["file_id"] = url_response.get("file_id") - f["upload_url"] = url_response.get("upload_url") + f["file_id"] = url_response.get("file_id") # type: ignore[union-attr, unused-ignore] + f["upload_url"] = url_response.get("upload_url") # type: ignore[union-attr, unused-ignore] # step2: "https://files.slack.com/upload/v1/..." per file for f in files: @@ -3859,8 +3859,8 @@ def files_upload_v2( thread_ts=thread_ts, **kwargs, ) - if len(completion.get("files")) == 1: # type: ignore - completion.data["file"] = completion.get("files")[0] # type: ignore + if len(completion.get("files")) == 1: # type: ignore[arg-type] + completion.data["file"] = completion.get("files")[0] # type: ignore[index] return completion def files_getUploadURLExternal( diff --git a/slack_sdk/web/legacy_slack_response.py b/slack_sdk/web/legacy_slack_response.py index a9ca462e4..d665a5050 100644 --- a/slack_sdk/web/legacy_slack_response.py +++ b/slack_sdk/web/legacy_slack_response.py @@ -11,7 +11,7 @@ import slack_sdk.errors as e -class LegacySlackResponse(object): # skipcq: PYL-R0205 +class LegacySlackResponse(object): """An iterable container of response data. Attributes: @@ -112,7 +112,7 @@ def __iter__(self): """ if isinstance(self.data, bytes): raise ValueError("As the response.data is binary data, this operation is unsupported") - self._iteration = 0 # skipcq: PYL-W0201 + self._iteration = 0 self.data = self._initial_data return self @@ -140,7 +140,7 @@ def __next__(self): self._iteration += 1 if self._iteration == 1: return self - if self._next_cursor_is_present(self.data): # skipcq: PYL-R1705 + if self._next_cursor_is_present(self.data): params = self.req_args.get("params", {}) if params is None: params = {} @@ -150,7 +150,7 @@ def __next__(self): if self._use_sync_aiohttp: # We no longer recommend going with this way response = asyncio.get_event_loop().run_until_complete( - self._client._request( # skipcq: PYL-W0212 + self._client._request( http_verb=self.http_verb, api_url=self.api_url, req_args=self.req_args, @@ -158,9 +158,7 @@ def __next__(self): ) else: # This method sends a request in a synchronous way - response = self._client._request_for_pagination( # skipcq: PYL-W0212 - api_url=self.api_url, req_args=self.req_args - ) + response = self._client._request_for_pagination(api_url=self.api_url, req_args=self.req_args) self.data = response["data"] self.headers = response["headers"] diff --git a/slack_sdk/web/slack_response.py b/slack_sdk/web/slack_response.py index 1f1544580..37fb266f5 100644 --- a/slack_sdk/web/slack_response.py +++ b/slack_sdk/web/slack_response.py @@ -139,7 +139,7 @@ def __next__(self): self._iteration += 1 if self._iteration == 1: return self - if _next_cursor_is_present(self.data): # skipcq: PYL-R1705 + if _next_cursor_is_present(self.data): params = self.req_args.get("params", {}) if params is None: params = {} @@ -148,9 +148,7 @@ def __next__(self): self.req_args.update({"params": params}) # This method sends a request in a synchronous way - response = self._client._request_for_pagination( # skipcq: PYL-W0212 - api_url=self.api_url, req_args=self.req_args - ) + response = self._client._request_for_pagination(api_url=self.api_url, req_args=self.req_args) self.data = response["data"] self.headers = response["headers"] self.status_code = response["status_code"] diff --git a/slack_sdk/webhook/async_client.py b/slack_sdk/webhook/async_client.py index 9285f14cd..a737b4e31 100644 --- a/slack_sdk/webhook/async_client.py +++ b/slack_sdk/webhook/async_client.py @@ -192,7 +192,7 @@ async def _perform_http_request(self, *, body: Dict[str, Any], headers: Dict[str self.logger.debug(f"Sending a request - url: {self.url}, body: {str_body}, headers: {headers}") try: - async with session.request("POST", self.url, **request_kwargs) as res: # type: ignore[arg-type, union-attr] + async with session.request("POST", self.url, **request_kwargs) as res: # type: ignore[arg-type, union-attr] # noqa: E501 try: response_body = await res.text() retry_response = RetryHttpResponse( diff --git a/tests/web/classes/test_dialogs.py b/tests/web/classes/test_dialogs.py index 0c3a3226b..2f40a71bd 100644 --- a/tests/web/classes/test_dialogs.py +++ b/tests/web/classes/test_dialogs.py @@ -11,6 +11,7 @@ DialogTextField, DialogUserSelector, ) + from slack.web.classes.dialogs import DialogBuilder from slack.web.classes.objects import Option from . import STRING_3001_CHARS, STRING_301_CHARS, STRING_51_CHARS