@@ -27,13 +27,18 @@ <h1 class="title">Module <code>slack_sdk.web.internal_utils</code></h1>
2727< span > Expand source code</ span >
2828</ summary >
2929< pre > < code class ="python "> import json
30+ import logging
3031import os
3132import platform
3233import sys
34+ import urllib
3335import warnings
36+ from asyncio import Future
37+ from http.client import HTTPResponse
3438from ssl import SSLContext
3539from typing import Any, Dict, Optional, Sequence, Union
3640from urllib.parse import urljoin
41+ from urllib.request import OpenerDirector, ProxyHandler, HTTPSHandler, Request, urlopen
3742
3843from slack_sdk import version
3944from slack_sdk.errors import SlackRequestError
@@ -326,7 +331,139 @@ <h1 class="title">Module <code>slack_sdk.web.internal_utils</code></h1>
326331 # >>> json.dumps(d)
327332 # '{"a": null, "b": 123}'
328333 #
329- return {k: v for k, v in d.items() if v is not None}</ code > </ pre >
334+ return {k: v for k, v in d.items() if v is not None}
335+
336+
337+ def _to_v2_file_upload_item(upload_file: Dict[str, Any]) -> Dict[str, Optional[Any]]:
338+ file = upload_file.get("file")
339+ content = upload_file.get("content")
340+ data: Optional[bytes] = None
341+ if file is not None:
342+ if isinstance(file, str): # filepath
343+ with open(file.encode("utf-8", "ignore"), "rb") as readable:
344+ data = readable.read()
345+ else:
346+ data = file
347+ elif content is not None:
348+ if isinstance(content, str): # filepath
349+ data = content.encode("utf-8")
350+ elif isinstance(content, bytes):
351+ data = content
352+ else:
353+ raise SlackRequestError("The given content must be either filepath as str or data as bytes")
354+
355+ filename = upload_file.get("filename")
356+ if upload_file.get("filename") is None and isinstance(file, str):
357+ # use the local filename if filename is missing
358+ if upload_file.get("filename") is None:
359+ filename = file.split(os.path.sep)[-1]
360+ else:
361+ filename = "Uploaded file"
362+
363+ title = upload_file.get("title", "Uploaded file")
364+ if data is None:
365+ raise SlackRequestError(f"File content not found for filename: {filename}, title: {title}")
366+
367+ return {
368+ "filename": filename,
369+ "data": data,
370+ "length": len(data),
371+ "title": title,
372+ "alt_txt": upload_file.get("alt_txt"),
373+ "snippet_type": upload_file.get("snippet_type"),
374+ }
375+
376+
377+ def _upload_file_via_v2_url(
378+ url: str,
379+ data: bytes,
380+ timeout: int,
381+ logger: logging.Logger,
382+ proxy: Optional[str] = None,
383+ ssl: Optional[SSLContext] = None,
384+ ) -> Dict[str, Any]:
385+ opener: Optional[OpenerDirector] = None
386+ if proxy is not None:
387+ if isinstance(proxy, str):
388+ opener = urllib.request.build_opener(
389+ ProxyHandler({"http": proxy, "https": proxy}),
390+ HTTPSHandler(context=ssl),
391+ )
392+ else:
393+ raise SlackRequestError(f"Invalid proxy detected: {proxy} must be a str value")
394+
395+ resp: Optional[HTTPResponse] = None
396+ req: Request = Request(method="POST", url=url, data=data, headers={})
397+ if opener:
398+ resp = opener.open(req, timeout=timeout)
399+ else:
400+ resp = urlopen(req, context=ssl, timeout=timeout) # skipcq: BAN-B310
401+
402+ charset = resp.headers.get_content_charset() or "utf-8"
403+ body: str = resp.read().decode(charset) # read the response body here
404+ if logger.level <= logging.DEBUG:
405+ message = (
406+ "Received the following response - ",
407+ f"status: {resp.status}, " f"headers: {dict(resp.headers)}, " f"body: {body}",
408+ )
409+ logger.debug(message)
410+
411+ return {"status": resp.status, "headers": resp.headers, "body": body}
412+
413+
414+ def _validate_for_legacy_client(
415+ response: Union["SlackResponse", Future], # noqa: F821
416+ ) -> None: # type: ignore
417+ # Only LegacyWebClient can return this union type
418+ if isinstance(response, Future):
419+ message = (
420+ "Sorry! This SDK does not support run_async=True option for this API calls. "
421+ "Please migrate to AsyncWebClient, which is a new and stable way to go."
422+ )
423+ raise SlackRequestError(message)
424+
425+
426+ def _attach_full_file_metadata(
427+ client, # type: ignore
428+ token_as_arg: Optional[str],
429+ completion: Union["SlackResponse", Future], # noqa: F821
430+ ) -> None:
431+ _validate_for_legacy_client(completion)
432+ _completion: Any = completion # just for satisfying pytype
433+ # fetch all the file metadata for backward-compatibility
434+ for f in _completion.get("files"):
435+ full_info = client.files_info(
436+ file=f.get("id"),
437+ token=token_as_arg,
438+ )
439+ f.update(full_info["file"])
440+ if len(_completion.get("files")) == 1:
441+ _completion.data["file"] = _completion.get("files")[0]
442+
443+
444+ async def _attach_full_file_metadata_async(
445+ client, # type: ignore
446+ token_as_arg: Optional[str],
447+ completion: "SlackResponse", # noqa: F821
448+ ) -> None:
449+ # fetch all the file metadata for backward-compatibility
450+ for f in completion.get("files"):
451+ full_info = await client.files_info(
452+ file=f.get("id"),
453+ token=token_as_arg,
454+ )
455+ f.update(full_info["file"])
456+ if len(completion.get("files")) == 1:
457+ completion.data["file"] = completion.get("files")[0]
458+
459+
460+ def _print_files_upload_v2_suggestion():
461+ message = (
462+ "client.files_upload() may cause some issues like timeouts for relatively large files. "
463+ "Our latest recommendation is to use client.files_upload_v2(), "
464+ "which is mostly compatible and much stabler, instead."
465+ )
466+ warnings.warn(message)</ code > </ pre >
330467</ details >
331468</ section >
332469< section >
0 commit comments