Skip to content

Commit a1c0d3e

Browse files
authored
Fix #1496 Async client uses blocking call when uploading file with v2 (#1498)
1 parent 694ec2f commit a1c0d3e

File tree

10 files changed

+122
-21
lines changed

10 files changed

+122
-21
lines changed

setup.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ def run(self):
7878
" await self.files_getUploadURLExternal(",
7979
async_source,
8080
)
81+
async_source = re.sub(
82+
r" self._upload_file\(",
83+
" await self._upload_file(",
84+
async_source,
85+
)
8186
async_source = re.sub(
8287
r" self.files_completeUploadExternal\(",
8388
" await self.files_completeUploadExternal(",

slack_sdk/web/async_base_client.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
) # type: ignore
1212
from .async_slack_response import AsyncSlackResponse
1313
from .deprecation import show_deprecation_warning_if_any
14+
from .file_upload_v2_result import FileUploadV2Result
1415
from .internal_utils import (
1516
convert_bool_to_0_or_1,
1617
_build_req_args,
@@ -214,3 +215,28 @@ async def _request(self, *, http_verb, api_url, req_args) -> Dict[str, Any]:
214215
req_args=req_args,
215216
retry_handlers=self.retry_handlers,
216217
)
218+
219+
async def _upload_file(
220+
self,
221+
*,
222+
url: str,
223+
data: bytes,
224+
logger: logging.Logger,
225+
timeout: int,
226+
proxy: Optional[str],
227+
ssl: Optional[SSLContext],
228+
) -> FileUploadV2Result:
229+
"""Upload a file using the issued upload URL"""
230+
result = await _request_with_session(
231+
current_session=self.session,
232+
timeout=timeout,
233+
logger=logger,
234+
http_verb="POST",
235+
api_url=url,
236+
req_args={"data": data, "proxy": proxy, "ssl": ssl},
237+
retry_handlers=self.retry_handlers,
238+
)
239+
return FileUploadV2Result(
240+
status=result.get("status_code"),
241+
body=result.get("body"),
242+
)

slack_sdk/web/async_client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
_warn_if_text_or_attachment_fallback_is_missing,
2424
_remove_none_values,
2525
_to_v2_file_upload_item,
26-
_upload_file_via_v2_url,
2726
_validate_for_legacy_client,
2827
_print_files_upload_v2_suggestion,
2928
)
@@ -3584,17 +3583,17 @@ async def files_upload_v2(
35843583

35853584
# step2: "https://files.slack.com/upload/v1/..." per file
35863585
for f in files:
3587-
upload_result = _upload_file_via_v2_url(
3586+
upload_result = await self._upload_file(
35883587
url=f["upload_url"],
35893588
data=f["data"],
35903589
logger=self._logger,
35913590
timeout=self.timeout,
35923591
proxy=self.proxy,
35933592
ssl=self.ssl,
35943593
)
3595-
if upload_result.get("status") != 200:
3596-
status = upload_result.get("status")
3597-
body = upload_result.get("body")
3594+
if upload_result.status != 200:
3595+
status = upload_result.status
3596+
body = upload_result.body
35983597
message = (
35993598
"Failed to upload a file "
36003599
f"(status: {status}, body: {body}, filename: {f.get('filename')}, title: {f.get('title')})"

slack_sdk/web/async_internal_utils.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def convert_params(values: dict) -> dict:
108108

109109
try:
110110
async with session.request(http_verb, api_url, **req_args) as res:
111-
data: Union[dict, bytes] = {}
111+
data: Union[dict, bytes, str] = {}
112112
if res.content_type == "application/gzip":
113113
# admin.analytics.getFile
114114
data = await res.read()
@@ -117,6 +117,14 @@ def convert_params(values: dict) -> dict:
117117
headers=res.headers,
118118
data=data,
119119
)
120+
elif res.content_type == "text/plain":
121+
# https://files.slack.com/upload/v1/...
122+
data = await res.text()
123+
retry_response = RetryHttpResponse(
124+
status_code=res.status,
125+
headers=res.headers,
126+
data=data,
127+
)
120128
else:
121129
try:
122130
data = await res.json()
@@ -143,7 +151,9 @@ def convert_params(values: dict) -> dict:
143151
)
144152

145153
if logger.level <= logging.DEBUG:
146-
body = data if isinstance(data, dict) else "(binary)"
154+
body = "(binary)"
155+
if isinstance(data, dict) or isinstance(data, str):
156+
body = data
147157
logger.debug(
148158
"Received the following response - "
149159
f"status: {res.status}, "

slack_sdk/web/base_client.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121

2222
from slack_sdk.errors import SlackRequestError
2323
from .deprecation import show_deprecation_warning_if_any
24+
from .file_upload_v2_result import FileUploadV2Result
2425
from .internal_utils import (
2526
convert_bool_to_0_or_1,
2627
get_user_agent,
2728
_get_url,
2829
_build_req_args,
2930
_build_unexpected_body_error_message,
31+
_upload_file_via_v2_url,
3032
)
3133
from .slack_response import SlackResponse
3234
from slack_sdk.http_retry import default_retry_handlers
@@ -560,10 +562,34 @@ def _build_urllib_request_headers(
560562
if has_json:
561563
headers.update({"Content-Type": "application/json;charset=utf-8"})
562564
if has_files:
563-
# will be set afterwards
565+
# will be set afterward
564566
headers.pop("Content-Type", None)
565567
return headers
566568

569+
def _upload_file(
570+
self,
571+
*,
572+
url: str,
573+
data: bytes,
574+
logger: logging.Logger,
575+
timeout: int,
576+
proxy: Optional[str],
577+
ssl: Optional[SSLContext],
578+
) -> FileUploadV2Result:
579+
"""Upload a file using the issued upload URL"""
580+
result = _upload_file_via_v2_url(
581+
url=url,
582+
data=data,
583+
logger=logger,
584+
timeout=timeout,
585+
proxy=proxy,
586+
ssl=ssl,
587+
)
588+
return FileUploadV2Result(
589+
status=result.get("status"),
590+
body=result.get("body"),
591+
)
592+
567593
# =================================================================
568594

569595
@staticmethod

slack_sdk/web/client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
_warn_if_text_or_attachment_fallback_is_missing,
1515
_remove_none_values,
1616
_to_v2_file_upload_item,
17-
_upload_file_via_v2_url,
1817
_validate_for_legacy_client,
1918
_print_files_upload_v2_suggestion,
2019
)
@@ -3575,17 +3574,17 @@ def files_upload_v2(
35753574

35763575
# step2: "https://files.slack.com/upload/v1/..." per file
35773576
for f in files:
3578-
upload_result = _upload_file_via_v2_url(
3577+
upload_result = self._upload_file(
35793578
url=f["upload_url"],
35803579
data=f["data"],
35813580
logger=self._logger,
35823581
timeout=self.timeout,
35833582
proxy=self.proxy,
35843583
ssl=self.ssl,
35853584
)
3586-
if upload_result.get("status") != 200:
3587-
status = upload_result.get("status")
3588-
body = upload_result.get("body")
3585+
if upload_result.status != 200:
3586+
status = upload_result.status
3587+
body = upload_result.body
35893588
message = (
35903589
"Failed to upload a file "
35913590
f"(status: {status}, body: {body}, filename: {f.get('filename')}, title: {f.get('title')})"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class FileUploadV2Result:
2+
status: int
3+
body: str
4+
5+
def __init__(self, status: int, body: str):
6+
self.status = status
7+
self.body = body

slack_sdk/web/internal_utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,9 @@ def _upload_file_via_v2_url(
377377
else:
378378
raise SlackRequestError(f"Invalid proxy detected: {proxy} must be a str value")
379379

380+
if logger.level <= logging.DEBUG:
381+
logger.debug(f"Sending a request: POST {url}")
382+
380383
resp: Optional[HTTPResponse] = None
381384
req: Request = Request(method="POST", url=url, data=data, headers={})
382385
if opener:
@@ -388,8 +391,10 @@ def _upload_file_via_v2_url(
388391
body: str = resp.read().decode(charset) # read the response body here
389392
if logger.level <= logging.DEBUG:
390393
message = (
391-
"Received the following response - ",
392-
f"status: {resp.status}, " f"headers: {dict(resp.headers)}, " f"body: {body}",
394+
"Received the following response - "
395+
f"status: {resp.status}, "
396+
f"headers: {dict(resp.headers)}, "
397+
f"body: {body}"
393398
)
394399
logger.debug(message)
395400

slack_sdk/web/legacy_base_client.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626
from slack_sdk.errors import SlackRequestError
2727
from .async_internal_utils import _files_to_data, _get_event_loop, _request_with_session
2828
from .deprecation import show_deprecation_warning_if_any
29+
from .file_upload_v2_result import FileUploadV2Result
2930
from .internal_utils import (
3031
convert_bool_to_0_or_1,
3132
get_user_agent,
3233
_get_url,
3334
_build_req_args,
3435
_build_unexpected_body_error_message,
36+
_upload_file_via_v2_url,
3537
)
3638
from .legacy_slack_response import LegacySlackResponse as SlackResponse
3739
from ..proxy_env_variable_loader import load_http_proxy_from_env
@@ -521,10 +523,33 @@ def _build_urllib_request_headers(
521523
if has_json:
522524
headers.update({"Content-Type": "application/json;charset=utf-8"})
523525
if has_files:
524-
# will be set afterwards
526+
# will be set afterward
525527
headers.pop("Content-Type", None)
526528
return headers
527529

530+
def _upload_file(
531+
self,
532+
*,
533+
url: str,
534+
data: bytes,
535+
logger: logging.Logger,
536+
timeout: int,
537+
proxy: Optional[str],
538+
ssl: Optional[SSLContext],
539+
) -> FileUploadV2Result:
540+
result = _upload_file_via_v2_url(
541+
url=url,
542+
data=data,
543+
logger=logger,
544+
timeout=timeout,
545+
proxy=proxy,
546+
ssl=ssl,
547+
)
548+
return FileUploadV2Result(
549+
status=result.get("status"),
550+
body=result.get("body"),
551+
)
552+
528553
# =================================================================
529554

530555
@staticmethod

slack_sdk/web/legacy_client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
_warn_if_text_or_attachment_fallback_is_missing,
2626
_remove_none_values,
2727
_to_v2_file_upload_item,
28-
_upload_file_via_v2_url,
2928
_validate_for_legacy_client,
3029
_print_files_upload_v2_suggestion,
3130
)
@@ -3586,17 +3585,17 @@ def files_upload_v2(
35863585

35873586
# step2: "https://files.slack.com/upload/v1/..." per file
35883587
for f in files:
3589-
upload_result = _upload_file_via_v2_url(
3588+
upload_result = self._upload_file(
35903589
url=f["upload_url"],
35913590
data=f["data"],
35923591
logger=self._logger,
35933592
timeout=self.timeout,
35943593
proxy=self.proxy,
35953594
ssl=self.ssl,
35963595
)
3597-
if upload_result.get("status") != 200:
3598-
status = upload_result.get("status")
3599-
body = upload_result.get("body")
3596+
if upload_result.status != 200:
3597+
status = upload_result.status
3598+
body = upload_result.body
36003599
message = (
36013600
"Failed to upload a file "
36023601
f"(status: {status}, body: {body}, filename: {f.get('filename')}, title: {f.get('title')})"

0 commit comments

Comments
 (0)