mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-02-16 18:31:45 +01:00
Accept File Paths for Updater/DispatcherBuilder.private_key (#2724)
This commit is contained in:
parent
5275c45199
commit
0cb8d50aea
10 changed files with 111 additions and 24 deletions
|
@ -26,6 +26,7 @@ from typing import IO, TYPE_CHECKING, Any, Optional, Union
|
||||||
from telegram import TelegramObject
|
from telegram import TelegramObject
|
||||||
from telegram._passport.credentials import decrypt
|
from telegram._passport.credentials import decrypt
|
||||||
from telegram._utils.files import is_local_file
|
from telegram._utils.files import is_local_file
|
||||||
|
from telegram._utils.types import FilePathInput
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, FileCredentials
|
from telegram import Bot, FileCredentials
|
||||||
|
@ -96,7 +97,7 @@ class File(TelegramObject):
|
||||||
self._id_attrs = (self.file_unique_id,)
|
self._id_attrs = (self.file_unique_id,)
|
||||||
|
|
||||||
def download(
|
def download(
|
||||||
self, custom_path: Union[Path, str] = None, out: IO = None, timeout: int = None
|
self, custom_path: FilePathInput = None, out: IO = None, timeout: int = None
|
||||||
) -> Union[Path, IO]:
|
) -> Union[Path, IO]:
|
||||||
"""
|
"""
|
||||||
Download this file. By default, the file is saved in the current working directory with its
|
Download this file. By default, the file is saved in the current working directory with its
|
||||||
|
|
|
@ -31,13 +31,13 @@ Warning:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Union, Type, Any, cast, IO, TYPE_CHECKING
|
from typing import Optional, Union, Type, Any, cast, IO, TYPE_CHECKING
|
||||||
|
|
||||||
from telegram._utils.types import FileInput
|
from telegram._utils.types import FileInput, FilePathInput
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import TelegramObject, InputFile
|
from telegram import TelegramObject, InputFile
|
||||||
|
|
||||||
|
|
||||||
def is_local_file(obj: Optional[Union[str, Path]]) -> bool:
|
def is_local_file(obj: Optional[FilePathInput]) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks if a given string is a file on local system.
|
Checks if a given string is a file on local system.
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,10 @@ if TYPE_CHECKING:
|
||||||
FileLike = Union[IO, 'InputFile']
|
FileLike = Union[IO, 'InputFile']
|
||||||
"""Either an open file handler or a :class:`telegram.InputFile`."""
|
"""Either an open file handler or a :class:`telegram.InputFile`."""
|
||||||
|
|
||||||
FileInput = Union[str, bytes, FileLike, Path]
|
FilePathInput = Union[str, Path]
|
||||||
|
"""A filepath either as string or as :obj:`pathlib.Path` object."""
|
||||||
|
|
||||||
|
FileInput = Union[FilePathInput, bytes, FileLike]
|
||||||
"""Valid input for passing files to Telegram. Either a file id as string, a file like object,
|
"""Valid input for passing files to Telegram. Either a file id as string, a file like object,
|
||||||
a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`."""
|
a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`."""
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
# flake8: noqa: E501
|
# flake8: noqa: E501
|
||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
"""This module contains the Builder classes for the telegram.ext module."""
|
"""This module contains the Builder classes for the telegram.ext module."""
|
||||||
|
from pathlib import Path
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from typing import (
|
from typing import (
|
||||||
|
@ -38,7 +39,7 @@ from typing import (
|
||||||
|
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
from telegram.request import Request
|
from telegram.request import Request
|
||||||
from telegram._utils.types import ODVInput, DVInput
|
from telegram._utils.types import ODVInput, DVInput, FilePathInput
|
||||||
from telegram._utils.warnings import warn
|
from telegram._utils.warnings import warn
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue, DEFAULT_FALSE
|
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue, DEFAULT_FALSE
|
||||||
from telegram.ext import Dispatcher, JobQueue, Updater, ExtBot, ContextTypes, CallbackContext
|
from telegram.ext import Dispatcher, JobQueue, Updater, ExtBot, ContextTypes, CallbackContext
|
||||||
|
@ -349,14 +350,23 @@ class _BaseBuilder(Generic[ODT, BT, CCT, UD, CD, BD, JQ, PT]):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _set_private_key(
|
def _set_private_key(
|
||||||
self: BuilderType, private_key: bytes, password: bytes = None
|
self: BuilderType,
|
||||||
|
private_key: Union[bytes, FilePathInput],
|
||||||
|
password: Union[bytes, FilePathInput] = None,
|
||||||
) -> BuilderType:
|
) -> BuilderType:
|
||||||
if self._bot is not DEFAULT_NONE:
|
if self._bot is not DEFAULT_NONE:
|
||||||
raise RuntimeError(_TWO_ARGS_REQ.format('private_key', 'bot instance'))
|
raise RuntimeError(_TWO_ARGS_REQ.format('private_key', 'bot instance'))
|
||||||
if self._dispatcher_check:
|
if self._dispatcher_check:
|
||||||
raise RuntimeError(_TWO_ARGS_REQ.format('private_key', 'Dispatcher instance'))
|
raise RuntimeError(_TWO_ARGS_REQ.format('private_key', 'Dispatcher instance'))
|
||||||
self._private_key = private_key
|
|
||||||
self._private_key_password = password
|
self._private_key = (
|
||||||
|
private_key if isinstance(private_key, bytes) else Path(private_key).read_bytes()
|
||||||
|
)
|
||||||
|
if password is None or isinstance(password, bytes):
|
||||||
|
self._private_key_password = password
|
||||||
|
else:
|
||||||
|
self._private_key_password = Path(password).read_bytes()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _set_defaults(self: BuilderType, defaults: 'Defaults') -> BuilderType:
|
def _set_defaults(self: BuilderType, defaults: 'Defaults') -> BuilderType:
|
||||||
|
@ -608,7 +618,11 @@ class DispatcherBuilder(_BaseBuilder[ODT, BT, CCT, UD, CD, BD, JQ, PT]):
|
||||||
"""
|
"""
|
||||||
return self._set_request(request)
|
return self._set_request(request)
|
||||||
|
|
||||||
def private_key(self: BuilderType, private_key: bytes, password: bytes = None) -> BuilderType:
|
def private_key(
|
||||||
|
self: BuilderType,
|
||||||
|
private_key: Union[bytes, FilePathInput],
|
||||||
|
password: Union[bytes, FilePathInput] = None,
|
||||||
|
) -> BuilderType:
|
||||||
"""Sets the private key and corresponding password for decryption of telegram passport data
|
"""Sets the private key and corresponding password for decryption of telegram passport data
|
||||||
to be used for :attr:`telegram.ext.Dispatcher.bot`.
|
to be used for :attr:`telegram.ext.Dispatcher.bot`.
|
||||||
|
|
||||||
|
@ -616,8 +630,12 @@ class DispatcherBuilder(_BaseBuilder[ODT, BT, CCT, UD, CD, BD, JQ, PT]):
|
||||||
/tree/master/examples#passportbotpy>`_, `Telegram Passports <https://git.io/fAvYd>`_
|
/tree/master/examples#passportbotpy>`_, `Telegram Passports <https://git.io/fAvYd>`_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
private_key (:obj:`bytes`): The private key.
|
private_key (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`): The private key or the
|
||||||
password (:obj:`bytes`): Optional. The corresponding password.
|
file path of a file that contains the key. In the latter case, the file's content
|
||||||
|
will be read automatically.
|
||||||
|
password (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`, optional): The corresponding
|
||||||
|
password or the file path of a file that contains the password. In the latter case,
|
||||||
|
the file's content will be read automatically.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:class:`DispatcherBuilder`: The same builder with the updated argument.
|
:class:`DispatcherBuilder`: The same builder with the updated argument.
|
||||||
|
@ -958,7 +976,11 @@ class UpdaterBuilder(_BaseBuilder[ODT, BT, CCT, UD, CD, BD, JQ, PT]):
|
||||||
"""
|
"""
|
||||||
return self._set_request(request)
|
return self._set_request(request)
|
||||||
|
|
||||||
def private_key(self: BuilderType, private_key: bytes, password: bytes = None) -> BuilderType:
|
def private_key(
|
||||||
|
self: BuilderType,
|
||||||
|
private_key: Union[bytes, FilePathInput],
|
||||||
|
password: Union[bytes, FilePathInput] = None,
|
||||||
|
) -> BuilderType:
|
||||||
"""Sets the private key and corresponding password for decryption of telegram passport data
|
"""Sets the private key and corresponding password for decryption of telegram passport data
|
||||||
to be used for :attr:`telegram.ext.Updater.bot`.
|
to be used for :attr:`telegram.ext.Updater.bot`.
|
||||||
|
|
||||||
|
@ -966,8 +988,12 @@ class UpdaterBuilder(_BaseBuilder[ODT, BT, CCT, UD, CD, BD, JQ, PT]):
|
||||||
/tree/master/examples#passportbotpy>`_, `Telegram Passports <https://git.io/fAvYd>`_
|
/tree/master/examples#passportbotpy>`_, `Telegram Passports <https://git.io/fAvYd>`_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
private_key (:obj:`bytes`): The private key.
|
private_key (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`): The private key or the
|
||||||
password (:obj:`bytes`): Optional. The corresponding password.
|
file path of a file that contains the key. In the latter case, the file's content
|
||||||
|
will be read automatically.
|
||||||
|
password (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`, optional): The corresponding
|
||||||
|
password or the file path of a file that contains the password. In the latter case,
|
||||||
|
the file's content will be read automatically.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:class:`UpdaterBuilder`: The same builder with the updated argument.
|
:class:`UpdaterBuilder`: The same builder with the updated argument.
|
||||||
|
|
|
@ -28,9 +28,9 @@ from typing import (
|
||||||
overload,
|
overload,
|
||||||
cast,
|
cast,
|
||||||
DefaultDict,
|
DefaultDict,
|
||||||
Union,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from telegram._utils.types import FilePathInput
|
||||||
from telegram.ext import BasePersistence, PersistenceInput
|
from telegram.ext import BasePersistence, PersistenceInput
|
||||||
from telegram.ext._contexttypes import ContextTypes
|
from telegram.ext._contexttypes import ContextTypes
|
||||||
from telegram.ext._utils.types import UD, CD, BD, ConversationDict, CDCData
|
from telegram.ext._utils.types import UD, CD, BD, ConversationDict, CDCData
|
||||||
|
@ -107,7 +107,7 @@ class PicklePersistence(BasePersistence[UD, CD, BD]):
|
||||||
@overload
|
@overload
|
||||||
def __init__(
|
def __init__(
|
||||||
self: 'PicklePersistence[Dict, Dict, Dict]',
|
self: 'PicklePersistence[Dict, Dict, Dict]',
|
||||||
filepath: Union[Path, str],
|
filepath: FilePathInput,
|
||||||
store_data: PersistenceInput = None,
|
store_data: PersistenceInput = None,
|
||||||
single_file: bool = True,
|
single_file: bool = True,
|
||||||
on_flush: bool = False,
|
on_flush: bool = False,
|
||||||
|
@ -117,7 +117,7 @@ class PicklePersistence(BasePersistence[UD, CD, BD]):
|
||||||
@overload
|
@overload
|
||||||
def __init__(
|
def __init__(
|
||||||
self: 'PicklePersistence[UD, CD, BD]',
|
self: 'PicklePersistence[UD, CD, BD]',
|
||||||
filepath: Union[Path, str],
|
filepath: FilePathInput,
|
||||||
store_data: PersistenceInput = None,
|
store_data: PersistenceInput = None,
|
||||||
single_file: bool = True,
|
single_file: bool = True,
|
||||||
on_flush: bool = False,
|
on_flush: bool = False,
|
||||||
|
@ -127,7 +127,7 @@ class PicklePersistence(BasePersistence[UD, CD, BD]):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
filepath: Union[Path, str],
|
filepath: FilePathInput,
|
||||||
store_data: PersistenceInput = None,
|
store_data: PersistenceInput = None,
|
||||||
single_file: bool = True,
|
single_file: bool = True,
|
||||||
on_flush: bool = False,
|
on_flush: bool = False,
|
||||||
|
|
|
@ -39,11 +39,11 @@ from typing import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized, TelegramError
|
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized, TelegramError
|
||||||
|
from telegram._utils.warnings import warn
|
||||||
from telegram.ext import Dispatcher
|
from telegram.ext import Dispatcher
|
||||||
from telegram.ext._utils.webhookhandler import WebhookAppClass, WebhookServer
|
from telegram.ext._utils.webhookhandler import WebhookAppClass, WebhookServer
|
||||||
from telegram.ext._utils.stack import was_called_by
|
from telegram.ext._utils.stack import was_called_by
|
||||||
from telegram.ext._utils.types import BT
|
from telegram.ext._utils.types import BT
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .builders import InitUpdaterBuilder
|
from .builders import InitUpdaterBuilder
|
||||||
|
|
|
@ -73,7 +73,7 @@ from telegram.error import (
|
||||||
TimedOut,
|
TimedOut,
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
)
|
)
|
||||||
from telegram._utils.types import JSONDict
|
from telegram._utils.types import JSONDict, FilePathInput
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
@ -385,7 +385,7 @@ class Request:
|
||||||
|
|
||||||
return self._request_wrapper('GET', url, **urlopen_kwargs)
|
return self._request_wrapper('GET', url, **urlopen_kwargs)
|
||||||
|
|
||||||
def download(self, url: str, filepath: Union[Path, str], timeout: float = None) -> None:
|
def download(self, url: str, filepath: FilePathInput, timeout: float = None) -> None:
|
||||||
"""Download a file by its URL.
|
"""Download a file by its URL.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
30
tests/data/private.key
Normal file
30
tests/data/private.key
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: AES-128-CBC,C4A419CEBF7D18FB5E1D98D6DDAEAD5F
|
||||||
|
|
||||||
|
LHkVkhpWH0KU4UrdUH4DMNGqAZkRzSwO8CqEkowQrrkdRyFwJQCgsgIywkDQsqyh
|
||||||
|
bvIkRpRb2gwQ1D9utrRQ1IFsJpreulErSPxx47b1xwXhMiX0vOzWprhZ8mYYrAZH
|
||||||
|
T9o7YXgUuF7Dk8Am51rZH50mWHUEljjkIlH2RQg1QFQr4recrZxlA3Ypn/SvOf0P
|
||||||
|
gaYrBvcX0am1JSqar0BA9sQO6u1STBjUm/e4csAubutxg/k/N69zlMcr098lqGWO
|
||||||
|
ppQmFa0grg3S2lUSuh42MYGtzluemrtWiktjrHKtm33zQX4vIgnMjuDZO4maqLD/
|
||||||
|
qHvbixY2TX28gHsoIednr2C9p/rBl8uItDlVyqWengykcDYczii0Pa8PKRmseOJh
|
||||||
|
sHGum3u5WTRRv41jK7i7PBeKsKHxMxLqTroXpCfx59XzGB5kKiPhG9Zm6NY7BZ3j
|
||||||
|
JA02+RKwlmm4v64XLbTVtV+2M4pk1cOaRx8CTB1Coe0uN+o+kJwMffqKioeaB9lE
|
||||||
|
zs9At5rdSpamG1G+Eop6hqGjYip8cLDaa9yuStIo0eOt/Q6YtU9qHOyMlOywptof
|
||||||
|
hJUMPoFjO06nsME69QvzRu9CPMGIcj4GAVYn1He6LoRVj59skPAUcn1DpytL9Ghi
|
||||||
|
9r7rLCRCExX32MuIxBq+fWBd//iOTkvnSlISc2MjXSYWu0QhKUvVZgy23pA3RH6X
|
||||||
|
px/dPdw1jF4WTlJL7IEaF3eOLgKqfYebHa+i2E64ncECvsl8WFb/T+ru1qa4n3RB
|
||||||
|
HPIaBRzPSqF1nc5BIQD12GPf/A7lq1pJpcQQN7gTkpUwJ8ydPB45sadHrc3Fz1C5
|
||||||
|
XPvL3eLfCEau2Wrz4IVgMTJ61lQnzSZG9Z+R0JYpd1+SvNpbm9YdocDYam8wIFS3
|
||||||
|
9RsJOKCansvOXfuXp26gggzsAP3mXq/DV1e86ramRbMyczSd3v+EsKmsttW0oWC6
|
||||||
|
Hhuozy11w6Q+jgsiSBrOFJ0JwgHAaCGb4oFluYzTOgdrmPgQomrz16TJLjjmn56B
|
||||||
|
9msoVGH5Kk/ifVr9waFuQFhcUfoWUUPZB3GrSGpr3Rz5XCh/BuXQDW8mDu29odzD
|
||||||
|
6hDoNITsPv+y9F/BvqWOK+JeL+wP/F+AnciGMzIDnP4a4P4yj8Gf2rr1Eriok6wz
|
||||||
|
aQr6NwnKsT4UAqjlmQ+gdPE4Joxk/ixlD41TZ97rq0LUSx2bcanM8GXZUjL74EuB
|
||||||
|
TVABCeIX2ADBwHZ6v2HEkZvK7Miy23FP75JmLdNXw4GTcYmqD1bPIfsxgUkSwG63
|
||||||
|
t0ChOqi9VdT62eAs5wShwhcrjc4xztjn6kypFu55a0neNr2qKYrwFo3QgZAbKWc1
|
||||||
|
5jfS4kAq0gxyoQTCZnGhbbL095q3Sy7GV3EaW4yk78EuRwPFOqVUQ0D5tvrKsPT4
|
||||||
|
B5AlxlarcDcMQayWKLj2pWmQm3YVlx5NfoRkSbd14h6ZryzDhG8ZfooLQ5dFh1ba
|
||||||
|
f8+YbBtvFshzUDYdnr0fS0RYc/WtYmfJdb4+Fkc268BkJzg43rMSrdzaleS6jypU
|
||||||
|
vzPs8WO0xU1xCIgB92vqZ+/4OlFwjbHHoQlnFHdNPbrfc8INbtLZgLCrELw4UEga
|
||||||
|
-----END RSA PRIVATE KEY-----
|
1
tests/data/private_key.password
Normal file
1
tests/data/private_key.password
Normal file
|
@ -0,0 +1 @@
|
||||||
|
python-telegram-bot
|
|
@ -20,6 +20,7 @@
|
||||||
"""
|
"""
|
||||||
We mainly test on UpdaterBuilder because it has all methods that DispatcherBuilder already has
|
We mainly test on UpdaterBuilder because it has all methods that DispatcherBuilder already has
|
||||||
"""
|
"""
|
||||||
|
from pathlib import Path
|
||||||
from random import randint
|
from random import randint
|
||||||
from threading import Event
|
from threading import Event
|
||||||
|
|
||||||
|
@ -63,7 +64,9 @@ class TestBuilder:
|
||||||
pytest.skip(f'{builder.__class__} has no method called {method}')
|
pytest.skip(f'{builder.__class__} has no method called {method}')
|
||||||
|
|
||||||
# First that e.g. `bot` can't be set if `request` was already set
|
# First that e.g. `bot` can't be set if `request` was already set
|
||||||
getattr(builder, method)(1)
|
# We pass the private key since `private_key` is the only method that doesn't just save
|
||||||
|
# the passed value
|
||||||
|
getattr(builder, method)(Path('tests/data/private.key'))
|
||||||
with pytest.raises(RuntimeError, match=f'`bot` may only be set, if no {description}'):
|
with pytest.raises(RuntimeError, match=f'`bot` may only be set, if no {description}'):
|
||||||
builder.bot(None)
|
builder.bot(None)
|
||||||
|
|
||||||
|
@ -84,7 +87,9 @@ class TestBuilder:
|
||||||
pytest.skip(f'{builder.__class__} has no method called {method}')
|
pytest.skip(f'{builder.__class__} has no method called {method}')
|
||||||
|
|
||||||
# First that e.g. `dispatcher` can't be set if `bot` was already set
|
# First that e.g. `dispatcher` can't be set if `bot` was already set
|
||||||
getattr(builder, method)(None)
|
# We pass the private key since `private_key` is the only method that doesn't just save
|
||||||
|
# the passed value
|
||||||
|
getattr(builder, method)(Path('tests/data/private.key'))
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
RuntimeError, match=f'`dispatcher` may only be set, if no {description}'
|
RuntimeError, match=f'`dispatcher` may only be set, if no {description}'
|
||||||
):
|
):
|
||||||
|
@ -102,7 +107,9 @@ class TestBuilder:
|
||||||
builder = builder.__class__()
|
builder = builder.__class__()
|
||||||
builder.dispatcher(None)
|
builder.dispatcher(None)
|
||||||
if method != 'dispatcher_class':
|
if method != 'dispatcher_class':
|
||||||
getattr(builder, method)(None)
|
# We pass the private key since `private_key` is the only method that doesn't just save
|
||||||
|
# the passed value
|
||||||
|
getattr(builder, method)(Path('tests/data/private.key'))
|
||||||
else:
|
else:
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
RuntimeError, match=f'`{method}` may only be set, if no Dispatcher instance'
|
RuntimeError, match=f'`{method}` may only be set, if no Dispatcher instance'
|
||||||
|
@ -251,3 +258,22 @@ class TestBuilder:
|
||||||
else:
|
else:
|
||||||
assert isinstance(obj, CustomDispatcher)
|
assert isinstance(obj, CustomDispatcher)
|
||||||
assert obj.arg == 2
|
assert obj.arg == 2
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('input_type', ('bytes', 'str', 'Path'))
|
||||||
|
def test_all_private_key_input_types(self, builder, bot, input_type):
|
||||||
|
private_key = Path('tests/data/private.key')
|
||||||
|
password = Path('tests/data/private_key.password')
|
||||||
|
|
||||||
|
if input_type == 'bytes':
|
||||||
|
private_key = private_key.read_bytes()
|
||||||
|
password = password.read_bytes()
|
||||||
|
if input_type == 'str':
|
||||||
|
private_key = str(private_key)
|
||||||
|
password = str(password)
|
||||||
|
|
||||||
|
builder.token(bot.token).private_key(
|
||||||
|
private_key=private_key,
|
||||||
|
password=password,
|
||||||
|
)
|
||||||
|
bot = builder.build().bot
|
||||||
|
assert bot.private_key
|
||||||
|
|
Loading…
Add table
Reference in a new issue