Repository: slackapi/python-slack-sdk (python)

Issue:
Incorrect type hint for WebClient#files_upload file argument
After #771 was merged, the `files_upload` function signature still does not accept a `bytes` type object: https://github.com/slackapi/python-slack-sdk/blob/main/slack_sdk/web/client.py#L1458-L1460

```
    def files_upload(
        self, *, file: Union[str, IOBase] = None, content: str = None, **kwargs
    ) -> SlackResponse:
```
So the OP example produces a mypy error: `Argument "file" to "files_upload" of "WebClient" has incompatible type "bytes"; expected "Union[str, IOBase, None]"`

_Originally posted by @gburek-fastly in https://github.com/slackapi/python-slack-sdk/issues/770#issuecomment-749221824_

Pull request:
Fix #901 by correcting type hints for files_upload method args
## Summary

This pull request fixes #901 by correcting the `file` arg's type hint.

### Category (place an `x` in each of the `[ ]`)

- [x] **slack_sdk.web.WebClient** (Web API client)
- [ ] **slack_sdk.webhook.WebhookClient** (Incoming Webhook, response_url sender)
- [ ] **slack_sdk.models** (UI component builders)
- [ ] **slack_sdk.oauth** (OAuth Flow Utilities)
- [ ] **slack_sdk.rtm.RTMClient** (RTM client)
- [ ] **slack_sdk.signature** (Request Signature Verifier)
- [ ] `/docs-src` (Documents, have you run `./docs.sh`?)
- [ ] `/docs-src-v2` (Documents, have you run `./docs-v2.sh`?)

## Requirements (place an `x` in each `[ ]`)

- [x] I've read and understood the [Contributing Guidelines](https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md) and have done my best effort to follow them.
- [x] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
- [x] I've run `python setup.py validate` after making the changes.


Patch:
diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py
index 4295e22..ecc7834 100644
--- a/slack_sdk/web/async_client.py
+++ b/slack_sdk/web/async_client.py
@@ -1549,7 +1549,7 @@ class AsyncWebClient(AsyncBaseClient):
         return await self.api_call("files.sharedPublicURL", json=kwargs)
 
     async def files_upload(
-        self, *, file: Union[str, IOBase] = None, content: str = None, **kwargs
+        self, *, file: Union[str, bytes, IOBase] = None, content: str = None, **kwargs
     ) -> AsyncSlackResponse:
         """Uploads or creates a file.
 
diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py
index e5477bc..b748f51 100644
--- a/slack_sdk/web/client.py
+++ b/slack_sdk/web/client.py
@@ -1456,7 +1456,7 @@ class WebClient(BaseClient):
         return self.api_call("files.sharedPublicURL", json=kwargs)
 
     def files_upload(
-        self, *, file: Union[str, IOBase] = None, content: str = None, **kwargs
+        self, *, file: Union[str, bytes, IOBase] = None, content: str = None, **kwargs
     ) -> SlackResponse:
         """Uploads or creates a file.
 
diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py
index db77427..36d44bd 100644
--- a/slack_sdk/web/internal_utils.py
+++ b/slack_sdk/web/internal_utils.py
@@ -141,7 +141,9 @@ def _build_req_args(
         _set_default_params(data, default_params)
     if files is not None and isinstance(files, dict):
         files = {k: v for k, v in files.items() if v is not None}
-        _set_default_params(files, default_params)
+        # NOTE: We do not need to all #_set_default_params here
+        # because other parameters in binary data requests can exist
+        # only in either data or params, not in files.
     if params is not None and isinstance(params, dict):
         params = {k: v for k, v in params.items() if v is not None}
         _set_default_params(params, default_params)
diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py
index e966f1f..22884a4 100644
--- a/slack_sdk/web/legacy_client.py
+++ b/slack_sdk/web/legacy_client.py
@@ -1549,7 +1549,7 @@ class LegacyWebClient(LegacyBaseClient):
         return self.api_call("files.sharedPublicURL", json=kwargs)
 
     def files_upload(
-        self, *, file: Union[str, IOBase] = None, content: str = None, **kwargs
+        self, *, file: Union[str, bytes, IOBase] = None, content: str = None, **kwargs
     ) -> Union[Future, SlackResponse]:
         """Uploads or creates a file.
 


Test patch:
diff --git a/tests/slack_sdk/web/test_web_client_issue_900.py b/tests/slack_sdk/web/test_web_client_issue_900.py
new file mode 100644
index 0000000..32ce13f
--- /dev/null
+++ b/tests/slack_sdk/web/test_web_client_issue_900.py
@@ -0,0 +1,22 @@
+import unittest
+from os.path import dirname
+
+from slack_sdk.web import WebClient
+from tests.slack_sdk.web.mock_web_api_server import (
+    setup_mock_web_api_server,
+    cleanup_mock_web_api_server,
+)
+
+
+class TestWebClient_Issue_900(unittest.TestCase):
+    def setUp(self):
+        setup_mock_web_api_server(self)
+
+    def tearDown(self):
+        cleanup_mock_web_api_server(self)
+
+    def test_if_it_works_with_default_params(self):
+        client = WebClient(
+            base_url="http://localhost:8888", token="xoxb-api_test", team_id="T111"
+        )
+        client.files_upload(file=f"{dirname(__file__)}/test_web_client_issue_900.py")