mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
Refactor and Overhaul the Test Suite (#3426)
This commit is contained in:
parent
43c3c8f568
commit
963edbf191
129 changed files with 6046 additions and 5962 deletions
30
.github/CONTRIBUTING.rst
vendored
30
.github/CONTRIBUTING.rst
vendored
|
@ -84,35 +84,13 @@ Here's how to make a one-off code change.
|
|||
|
||||
- In addition, PTB uses some formatting/styling and linting tools in the pre-commit setup. Some of those tools also have command line tools that can help to run these tools outside of the pre-commit step. If you'd like to leverage that, please have a look at the `pre-commit config file`_ for an overview of which tools (and which versions of them) are used. For example, we use `Black`_ for code formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
|
||||
|
||||
- Please ensure that the code you write is well-tested.
|
||||
- Please ensure that the code you write is well-tested and that all automated tests still pass. We
|
||||
have dedicated an `testing page`_ to help you with that.
|
||||
|
||||
- In addition to that, we provide the `dev` marker for pytest. If you write one or multiple tests and want to run only those, you can decorate them via `@pytest.mark.dev` and then run it with minimal overhead with `pytest ./path/to/test_file.py -m dev`.
|
||||
|
||||
- Don’t break backward compatibility.
|
||||
- Don't break backward compatibility.
|
||||
|
||||
- Add yourself to the AUTHORS.rst_ file in an alphabetical fashion.
|
||||
|
||||
- Before making a commit ensure that all automated tests still pass:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -v
|
||||
|
||||
Since the tests can take a while to run, you can speed things up by running them in parallel
|
||||
using `pytest-xdist`_ (note that this may effect the result of the test in some rare cases):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -v -n auto --dist=loadfile
|
||||
|
||||
To run ``test_official`` (particularly useful if you made API changes), run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
prior to running the tests.
|
||||
|
||||
- If you want run style & type checks before committing run
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -287,4 +265,4 @@ break the API classes. For example:
|
|||
.. _`RTD build`: https://docs.python-telegram-bot.org/en/doc-fixes
|
||||
.. _`CSI`: https://standards.mousepawmedia.com/en/stable/csi.html
|
||||
.. _`section`: #documenting
|
||||
.. _`pytest-xdist`: https://github.com/pytest-dev/pytest-xdist
|
||||
.. _`testing page`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/tests/README.rst
|
||||
|
|
41
.github/workflows/test.yml
vendored
41
.github/workflows/test.yml
vendored
|
@ -44,42 +44,23 @@ jobs:
|
|||
# The first & second one are achieved by mocking the corresponding import
|
||||
# See test_helpers.py & test_no_passport.py for details
|
||||
run: |
|
||||
# Test without passport
|
||||
pytest -v --cov -k test_no_passport.py
|
||||
# We test without optional dependencies first. This includes:
|
||||
# - without pytz
|
||||
# - without jobqueue
|
||||
# - without ratelimiter
|
||||
# - without webhooks
|
||||
# - without arbitrary callback data
|
||||
# - without socks suppport
|
||||
TO_TEST="test_no_passport.py or test_datetime.py or test_defaults.py or test_jobqueue.py or test_applicationbuilder.py or test_ratelimiter.py or test_updater.py or test_callbackdatacache.py or test_request.py"
|
||||
pytest -v --cov -k "${TO_TEST}"
|
||||
status=$?
|
||||
|
||||
# test without pytz
|
||||
pytest -v --cov --cov-append -k test_datetime.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
pytest -v --cov --cov-append -k test_defaults.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# test without pytz & jobqueue
|
||||
pytest -v --cov --cov-append -k test_jobqueue.py
|
||||
pytest -v --cov --cov-append -k test_applicationbuilder.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# Test without ratelimiter
|
||||
pytest -v --cov --cov-append -k test_ratelimiter.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# Test without webhooks
|
||||
pytest -v --cov --cov-append -k test_updater.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# Test without callback-data
|
||||
pytest -v --cov --cov-append -k test_callbackdatacache.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# Test without socks
|
||||
pytest -v --cov --cov-append -k test_request.py
|
||||
status=$(( $? > status ? $? : status))
|
||||
|
||||
# Test the rest
|
||||
export TEST_WITH_OPT_DEPS='true'
|
||||
pip install -r requirements-opts.txt
|
||||
# `-n auto --dist loadfile` uses pytest-xdist to run each test file on a different CPU
|
||||
# worker
|
||||
# worker. Increasing number of workers has little effect on test duration, but it seems
|
||||
# to increase flakyness, specially on python 3.7 with --dist=loadgroup.
|
||||
pytest -v --cov --cov-append -n auto --dist loadfile
|
||||
status=$(( $? > status ? $? : status))
|
||||
exit ${status}
|
||||
|
|
2
.github/workflows/type_completeness.yml
vendored
2
.github/workflows/type_completeness.yml
vendored
|
@ -37,7 +37,7 @@ jobs:
|
|||
- name: Compare Completeness
|
||||
uses: jannekem/run-python-script-action@v1
|
||||
with:
|
||||
script: |
|
||||
script: |
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
GitHub Repository <https://github.com/python-telegram-bot/python-telegram-bot/>
|
||||
Telegram Channel <https://t.me/pythontelegrambotchannel/>
|
||||
Telegram User Group <https://t.me/pythontelegrambotgroup/>
|
||||
contributing
|
||||
coc
|
||||
|
||||
|
||||
contributing
|
||||
testing
|
||||
|
|
1
docs/source/testing.rst
Normal file
1
docs/source/testing.rst
Normal file
|
@ -0,0 +1 @@
|
|||
.. include:: ../../tests/README.rst
|
|
@ -1,10 +1,10 @@
|
|||
pre-commit
|
||||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
pytest==7.2.1
|
||||
pytest-asyncio==0.20.3
|
||||
pytest-timeout==2.1.0 # used to timeout tests
|
||||
pytest-asyncio==0.20.3 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.1.0 # xdist runs tests in parallel
|
||||
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
wheel # required for building the wheels for releases
|
||||
|
|
|
@ -36,7 +36,10 @@ filterwarnings =
|
|||
; Unfortunately due to https://github.com/pytest-dev/pytest/issues/8343 we can't have this here
|
||||
; and instead do a trick directly in tests/conftest.py
|
||||
; ignore::telegram.utils.deprecate.TelegramDeprecationWarning
|
||||
markers = dev: If you want to test a specific test, use this
|
||||
markers =
|
||||
dev: If you want to test a specific test, use this
|
||||
no_req
|
||||
req
|
||||
asyncio_mode = auto
|
||||
|
||||
[coverage:run]
|
||||
|
|
101
tests/README.rst
Normal file
101
tests/README.rst
Normal file
|
@ -0,0 +1,101 @@
|
|||
==============
|
||||
Testing in PTB
|
||||
==============
|
||||
|
||||
PTB uses `pytest`_ for testing. To run the tests, you need to
|
||||
have pytest installed along with a few other dependencies. You can find the list of dependencies
|
||||
in the ``requirements-dev.txt`` file in the root of the repository.
|
||||
|
||||
Running tests
|
||||
=============
|
||||
|
||||
To run the entire test suite, you can use the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest
|
||||
|
||||
This will run all the tests, including the ones which make a request to the Telegram servers, which
|
||||
may take a long time (total > 13 mins). To run only the tests that don't require a connection, you
|
||||
can run the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -m no_req
|
||||
|
||||
Or alternatively, you can run the following command to run only the tests that require a connection:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -m req
|
||||
|
||||
To further speed up the tests, you can run them in parallel using the ``-n`` flag (requires `pytest-xdist`_). But beware that
|
||||
this will use multiple CPU cores on your machine. The ``--dist`` flag is used to specify how the
|
||||
tests will be distributed across the cores. The ``loadgroup`` option is used to distribute the tests
|
||||
such that tests marked with ``@pytest.mark.xdist_group("name")`` are run on the same core — important if you want avoid race conditions in some tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -n auto --dist=loadgroup
|
||||
|
||||
This will result in a significant speedup, but may cause some tests to fail. If you want to run
|
||||
the failed tests in isolation, you can use the ``--lf`` flag:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --lf
|
||||
|
||||
|
||||
Writing tests
|
||||
=============
|
||||
|
||||
PTB has a separate test file for every file in the ``telegram.*`` namespace. Further, the tests for
|
||||
the ``telegram`` module are split into two classes, based on whether the test methods in them make a
|
||||
request or not. When writing tests, make sure to split them into these two classes, and make sure
|
||||
to name the test class as: ``TestXXXWithoutRequest`` for tests that don't make a request, and ``TestXXXWithRequest`` for tests that do.
|
||||
|
||||
Writing tests is a creative process; allowing you to design your test however you'd like, but there
|
||||
are a few conventions that you should follow:
|
||||
|
||||
- Each new test class needs a ``test_slot_behaviour``, ``test_to_dict``, ``test_de_json`` and
|
||||
``test_equality`` (in most cases).
|
||||
|
||||
- Make use of pytest's fixtures and parametrize wherever possible. Having knowledge of pytest's
|
||||
tooling can help you as well. You can look at the existing tests for examples and inspiration.
|
||||
|
||||
If you have made some API changes, you may want to run ``test_official`` to validate that the changes are
|
||||
complete and correct. To run it, export an environment variable first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
and then run ``pytest tests/test_official.py``.
|
||||
|
||||
We also have another marker, ``@pytest.mark.dev``, which you can add to tests that you want to run selectively.
|
||||
Use as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest -m dev
|
||||
|
||||
|
||||
Bots used in tests
|
||||
==================
|
||||
|
||||
If you run the tests locally, the test setup will use one of the two public bots available. Which
|
||||
bot of the two gets chosen for the test session is random. Whereas when the tests on the
|
||||
Github Actions CI are run, the test setup allocates a different, but same bot for every combination of Python version and
|
||||
OS.
|
||||
|
||||
Thus, number of bots used for testing locally is 2 (called as fallback bots), and on the CI,
|
||||
its [3.7, 3.8, 3.9, 3.10, 3.11] x [ubuntu-latest, macos-latest, windows-latest] = 15. Bringing the
|
||||
total number of bots used for testing to 17.
|
||||
|
||||
|
||||
That's it! If you have any questions, feel free to ask them in the `PTB dev
|
||||
group`_.
|
||||
|
||||
.. _pytest: https://docs.pytest.org/en/stable/
|
||||
.. _pytest-xdist: https://pypi.org/project/pytest-xdist/
|
||||
.. _PTB dev group: https://t.me/pythontelegrambotgroup
|
|
@ -45,26 +45,27 @@ if GITHUB_ACTION is not None and BOTS is not None and JOB_INDEX is not None:
|
|||
BOTS = json.loads(base64.b64decode(BOTS).decode("utf-8"))
|
||||
JOB_INDEX = int(JOB_INDEX)
|
||||
|
||||
FALLBACKS = json.loads(base64.b64decode(FALLBACKS).decode("utf-8"))
|
||||
FALLBACKS = json.loads(base64.b64decode(FALLBACKS).decode("utf-8")) # type: list[dict[str, str]]
|
||||
|
||||
|
||||
def get(name, fallback):
|
||||
# If we have TOKEN, PAYMENT_PROVIDER_TOKEN, CHAT_ID, SUPER_GROUP_ID,
|
||||
# CHANNEL_ID, BOT_NAME, or BOT_USERNAME in the environment, then use that
|
||||
val = os.getenv(name.upper())
|
||||
if val:
|
||||
return val
|
||||
class BotInfoProvider:
|
||||
def __init__(self):
|
||||
self._cached = {}
|
||||
|
||||
def get_info(self):
|
||||
if self._cached:
|
||||
return self._cached
|
||||
self._cached = {k: get(k, v) for k, v in random.choice(FALLBACKS).items()}
|
||||
return self._cached
|
||||
|
||||
|
||||
def get(key, fallback):
|
||||
# If we're running as a github action then fetch bots from the repo secrets
|
||||
if GITHUB_ACTION is not None and BOTS is not None and JOB_INDEX is not None:
|
||||
try:
|
||||
return BOTS[JOB_INDEX][name]
|
||||
except (KeyError, IndexError):
|
||||
return BOTS[JOB_INDEX][key]
|
||||
except (IndexError, KeyError):
|
||||
pass
|
||||
|
||||
# Otherwise go with the fallback
|
||||
return fallback
|
||||
|
||||
|
||||
def get_bot():
|
||||
return {k: get(k, v) for k, v in random.choice(FALLBACKS).items()}
|
||||
|
|
|
@ -22,7 +22,7 @@ import os
|
|||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
from httpx import AsyncClient, Response
|
||||
|
@ -48,16 +48,49 @@ from telegram.ext.filters import MessageFilter, UpdateFilter
|
|||
from telegram.request import RequestData
|
||||
from telegram.request._httpxrequest import HTTPXRequest
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
from tests.bots import get_bot
|
||||
from tests.bots import BotInfoProvider
|
||||
|
||||
BOT_INFO = BotInfoProvider()
|
||||
|
||||
|
||||
# This is here instead of in setup.cfg due to https://github.com/pytest-dev/pytest/issues/8343
|
||||
def pytest_runtestloop(session):
|
||||
def pytest_runtestloop(session: pytest.Session):
|
||||
session.add_marker(
|
||||
pytest.mark.filterwarnings("ignore::telegram.warnings.PTBDeprecationWarning")
|
||||
)
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items: List[pytest.Item]):
|
||||
"""Here we add a flaky marker to all request making tests and a (no_)req marker to the rest."""
|
||||
for item in items: # items are the test methods
|
||||
parent = item.parent # Get the parent of the item (class, or module if defined outside)
|
||||
if parent is None: # should never happen, but just in case
|
||||
return
|
||||
if ( # Check if the class name ends with 'WithRequest' and if it has no flaky marker
|
||||
parent.name.endswith("WithRequest")
|
||||
and not parent.get_closest_marker( # get_closest_marker gets pytest.marks with `name`
|
||||
name="flaky"
|
||||
) # don't add/override any previously set markers
|
||||
and not parent.get_closest_marker(name="req")
|
||||
): # Add the flaky marker with a rerun filter to the class
|
||||
parent.add_marker(pytest.mark.flaky(3, 1, rerun_filter=no_rerun_after_xfail_or_flood))
|
||||
parent.add_marker(pytest.mark.req)
|
||||
# Add the no_req marker to all classes that end with 'WithoutRequest' and don't have it
|
||||
elif parent.name.endswith("WithoutRequest") and not parent.get_closest_marker(
|
||||
name="no_req"
|
||||
):
|
||||
parent.add_marker(pytest.mark.no_req)
|
||||
|
||||
|
||||
def no_rerun_after_xfail_or_flood(error, name, test: pytest.Function, plugin):
|
||||
"""Don't rerun tests that have xfailed when marked with xfail, or when we hit a flood limit."""
|
||||
xfail_present = test.get_closest_marker(name="xfail")
|
||||
did_we_flood = "flood" in getattr(error[1], "msg", "") # _pytest.outcomes.XFailed has 'msg'
|
||||
if xfail_present or did_we_flood:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
GITHUB_ACTION = os.getenv("GITHUB_ACTION", False)
|
||||
|
||||
if GITHUB_ACTION:
|
||||
|
@ -86,19 +119,12 @@ def event_loop(request):
|
|||
# loop.close() # instead of closing here, do that at the every end of the test session
|
||||
|
||||
|
||||
# Related to the above, see https://stackoverflow.com/a/67307042/10606962
|
||||
def pytest_sessionfinish(session, exitstatus):
|
||||
asyncio.get_event_loop().close()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def bot_info():
|
||||
return get_bot()
|
||||
def bot_info() -> Dict[str, str]:
|
||||
return BOT_INFO.get_info()
|
||||
|
||||
|
||||
# Below classes are used to monkeypatch attributes since parent classes don't have __dict__
|
||||
|
||||
|
||||
class TestHttpxRequest(HTTPXRequest):
|
||||
async def _request_wrapper(
|
||||
self,
|
||||
|
@ -132,6 +158,10 @@ class DictExtBot(ExtBot):
|
|||
# Makes it easier to work with the bot in tests
|
||||
self._unfreeze()
|
||||
|
||||
# Here we override get_me for caching because we don't want to call the API repeatedly in tests
|
||||
async def get_me(self, *args, **kwargs):
|
||||
return await mocked_get_me(self)
|
||||
|
||||
|
||||
class DictBot(Bot):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -139,11 +169,42 @@ class DictBot(Bot):
|
|||
# Makes it easier to work with the bot in tests
|
||||
self._unfreeze()
|
||||
|
||||
# Here we override get_me for caching because we don't want to call the API repeatedly in tests
|
||||
async def get_me(self, *args, **kwargs):
|
||||
return await mocked_get_me(self)
|
||||
|
||||
|
||||
class DictApplication(Application):
|
||||
pass
|
||||
|
||||
|
||||
async def mocked_get_me(bot: Bot):
|
||||
if bot._bot_user is None:
|
||||
bot._bot_user = get_bot_user(bot.token)
|
||||
return bot._bot_user
|
||||
|
||||
|
||||
def get_bot_user(token: str) -> User:
|
||||
"""Used to return a mock user in bot.get_me(). This saves API calls on every init."""
|
||||
bot_info = BOT_INFO.get_info()
|
||||
# We don't take token from bot_info, because we need to make a bot with a specific ID. So we
|
||||
# generate the correct user_id from the token (token from bot_info is random each test run).
|
||||
# This is important in e.g. bot equality tests. The other parameters like first_name don't
|
||||
# matter as much. In the future we may provide a way to get all the correct info from the token
|
||||
user_id = int(token.split(":")[0])
|
||||
first_name = bot_info.get("name")
|
||||
username = bot_info.get("username").strip("@")
|
||||
return User(
|
||||
user_id,
|
||||
first_name,
|
||||
is_bot=True,
|
||||
username=username,
|
||||
can_join_groups=True,
|
||||
can_read_all_group_messages=False,
|
||||
supports_inline_queries=True,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
async def bot(bot_info):
|
||||
"""Makes an ExtBot instance with the given bot_info"""
|
||||
|
@ -151,6 +212,12 @@ async def bot(bot_info):
|
|||
yield _bot
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def one_time_bot(bot_info):
|
||||
"""A function scoped bot since the session bot would shutdown when `async with app` finishes"""
|
||||
return make_bot(bot_info)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
async def cdc_bot(bot_info):
|
||||
"""Makes an ExtBot instance with the given bot_info that uses arbitrary callback_data"""
|
||||
|
@ -170,20 +237,36 @@ async def raw_bot(bot_info):
|
|||
yield _bot
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
# Here we store the default bots so that we don't have to create them again and again.
|
||||
# They are initialized but not shutdown on pytest_sessionfinish because it is causing
|
||||
# problems with the event loop (Event loop is closed).
|
||||
default_bots = {}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
async def default_bot(request, bot_info):
|
||||
param = request.param if hasattr(request, "param") else {}
|
||||
defaults = Defaults(**param)
|
||||
|
||||
default_bot = make_bot(bot_info, defaults=Defaults(**param))
|
||||
async with default_bot:
|
||||
yield default_bot
|
||||
# If the bot is already created, return it. Else make a new one.
|
||||
default_bot = default_bots.get(defaults, None)
|
||||
if default_bot is None:
|
||||
default_bot = make_bot(bot_info, defaults=defaults)
|
||||
await default_bot.initialize()
|
||||
default_bots[defaults] = default_bot # Defaults object is hashable
|
||||
return default_bot
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture(scope="session")
|
||||
async def tz_bot(timezone, bot_info):
|
||||
default_bot = make_bot(bot_info, defaults=Defaults(tzinfo=timezone))
|
||||
async with default_bot:
|
||||
yield default_bot
|
||||
defaults = Defaults(tzinfo=timezone)
|
||||
try: # If the bot is already created, return it. Saves time since get_me is not called again.
|
||||
return default_bots[defaults]
|
||||
except KeyError:
|
||||
default_bot = make_bot(bot_info, defaults=defaults)
|
||||
await default_bot.initialize()
|
||||
default_bots[defaults] = default_bot
|
||||
return default_bot
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
|
@ -243,16 +326,14 @@ def data_file(filename: str) -> Path:
|
|||
|
||||
@pytest.fixture(scope="function")
|
||||
def thumb_file():
|
||||
f = data_file("thumb.jpg").open("rb")
|
||||
yield f
|
||||
f.close()
|
||||
with data_file("thumb.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def class_thumb_file():
|
||||
f = data_file("thumb.jpg").open("rb")
|
||||
yield f
|
||||
f.close()
|
||||
with data_file("thumb.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
def make_bot(bot_info=None, **kwargs):
|
||||
|
@ -285,7 +366,7 @@ def make_message(text, **kwargs):
|
|||
"""
|
||||
bot = kwargs.pop("bot", None)
|
||||
if bot is None:
|
||||
bot = make_bot(get_bot())
|
||||
bot = make_bot(BOT_INFO.get_info())
|
||||
message = Message(
|
||||
message_id=1,
|
||||
from_user=kwargs.pop("user", User(id=1, first_name="", is_bot=False)),
|
||||
|
@ -401,7 +482,7 @@ class BasicTimezone(datetime.tzinfo):
|
|||
return datetime.timedelta(0)
|
||||
|
||||
|
||||
@pytest.fixture(params=["Europe/Berlin", "Asia/Singapore", "UTC"])
|
||||
@pytest.fixture(scope="session", params=["Europe/Berlin", "Asia/Singapore", "UTC"])
|
||||
def tzinfo(request):
|
||||
if TEST_WITH_OPT_DEPS:
|
||||
return pytz.timezone(request.param)
|
||||
|
@ -410,7 +491,7 @@ def tzinfo(request):
|
|||
return BasicTimezone(offset=datetime.timedelta(hours=hours_offset), name=request.param)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture(scope="session")
|
||||
def timezone(tzinfo):
|
||||
return tzinfo
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
@ -35,21 +36,19 @@ from tests.conftest import data_file
|
|||
|
||||
@pytest.fixture(scope="function")
|
||||
def animation_file():
|
||||
f = data_file("game.gif").open("rb")
|
||||
yield f
|
||||
f.close()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
async def animation(bot, chat_id):
|
||||
with data_file("game.gif").open("rb") as f:
|
||||
thumb = data_file("thumb.jpg")
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
async def animation(bot, chat_id):
|
||||
with data_file("game.gif").open("rb") as f, data_file("thumb.jpg").open("rb") as thumb:
|
||||
return (
|
||||
await bot.send_animation(chat_id, animation=f, read_timeout=50, thumb=thumb.open("rb"))
|
||||
await bot.send_animation(chat_id, animation=f, read_timeout=50, thumb=thumb)
|
||||
).animation
|
||||
|
||||
|
||||
class TestAnimation:
|
||||
class TestAnimationBase:
|
||||
animation_file_id = "CgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
animation_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
width = 320
|
||||
|
@ -63,6 +62,8 @@ class TestAnimation:
|
|||
file_size = 5859
|
||||
caption = "Test *animation*"
|
||||
|
||||
|
||||
class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
def test_slot_behaviour(self, animation, mro_slots):
|
||||
for attr in animation.__slots__:
|
||||
assert getattr(animation, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -80,215 +81,6 @@ class TestAnimation:
|
|||
assert animation.file_name.startswith("game.gif") == self.file_name.startswith("game.gif")
|
||||
assert isinstance(animation.thumb, PhotoSize)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_all_args(self, bot, chat_id, animation_file, animation, thumb_file):
|
||||
message = await bot.send_animation(
|
||||
chat_id,
|
||||
animation_file,
|
||||
duration=self.duration,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
caption=self.caption,
|
||||
parse_mode="Markdown",
|
||||
disable_notification=False,
|
||||
protect_content=True,
|
||||
thumb=thumb_file,
|
||||
has_spoiler=True,
|
||||
)
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
assert message.animation.file_name == animation.file_name
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
assert message.animation.file_size == animation.file_size
|
||||
assert message.animation.thumb.width == self.width
|
||||
assert message.animation.thumb.height == self.height
|
||||
assert message.has_protected_content
|
||||
try:
|
||||
assert message.has_media_spoiler
|
||||
except AssertionError:
|
||||
pytest.xfail("This is a bug on Telegram's end")
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_animation_custom_filename(self, bot, chat_id, animation_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return list(request_data.multipart_data.values())[0][0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
assert await bot.send_animation(chat_id, animation_file, filename="custom_filename")
|
||||
monkeypatch.delattr(bot.request, "post")
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_get_and_download(self, bot, animation):
|
||||
path = Path("game.gif")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(animation.file_id)
|
||||
|
||||
assert new_file.file_id == animation.file_id
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
new_filepath = await new_file.download_to_drive("game.gif")
|
||||
|
||||
assert new_filepath.is_file()
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_animation_url_file(self, bot, chat_id, animation):
|
||||
message = await bot.send_animation(
|
||||
chat_id=chat_id, animation=self.animation_file_url, caption=self.caption
|
||||
)
|
||||
|
||||
assert message.caption == self.caption
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
|
||||
assert message.animation.duration == animation.duration
|
||||
assert message.animation.file_name.startswith(
|
||||
"game.gif"
|
||||
) == animation.file_name.startswith("game.gif")
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_animation_caption_entities(self, bot, chat_id, animation):
|
||||
test_string = "Italic Bold Code"
|
||||
entities = [
|
||||
MessageEntity(MessageEntity.ITALIC, 0, 6),
|
||||
MessageEntity(MessageEntity.ITALIC, 7, 4),
|
||||
MessageEntity(MessageEntity.ITALIC, 12, 4),
|
||||
]
|
||||
message = await bot.send_animation(
|
||||
chat_id, animation, caption=test_string, caption_entities=entities
|
||||
)
|
||||
|
||||
assert message.caption == test_string
|
||||
assert message.caption_entities == tuple(entities)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_1(self, default_bot, chat_id, animation_file):
|
||||
test_string = "Italic Bold Code"
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string
|
||||
)
|
||||
assert message.caption_markdown == test_markdown_string
|
||||
assert message.caption == test_string
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_2(self, default_bot, chat_id, animation_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string, parse_mode=None
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_3(self, default_bot, chat_id, animation_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string, parse_mode="HTML"
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_animation_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("animation") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("animation"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_animation(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
monkeypatch.delattr(bot, "_post")
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
({"allow_sending_without_reply": False}, True),
|
||||
],
|
||||
indirect=["default_bot"],
|
||||
)
|
||||
async def test_send_animation_default_allow_sending_without_reply(
|
||||
self, default_bot, chat_id, animation, custom
|
||||
):
|
||||
reply_to_message = await default_bot.send_message(chat_id, "test")
|
||||
await reply_to_message.delete()
|
||||
if custom is not None:
|
||||
message = await default_bot.send_animation(
|
||||
chat_id,
|
||||
animation,
|
||||
allow_sending_without_reply=custom,
|
||||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
elif default_bot.defaults.allow_sending_without_reply:
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
else:
|
||||
with pytest.raises(BadRequest, match="message not found"):
|
||||
await default_bot.send_animation(
|
||||
chat_id, animation, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_animation_default_protect_content(self, default_bot, chat_id, animation):
|
||||
animation_protected = await default_bot.send_animation(chat_id, animation)
|
||||
assert animation_protected.has_protected_content
|
||||
ani_unprotected = await default_bot.send_animation(
|
||||
chat_id, animation, protect_content=False
|
||||
)
|
||||
assert not ani_unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_resend(self, bot, chat_id, animation):
|
||||
message = await bot.send_animation(chat_id, animation.file_id)
|
||||
|
||||
assert message.animation == animation
|
||||
|
||||
async def test_send_with_animation(self, monkeypatch, bot, chat_id, animation):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["animation"] == animation.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.send_animation(animation=animation, chat_id=chat_id)
|
||||
assert message
|
||||
|
||||
def test_de_json(self, bot, animation):
|
||||
json_dict = {
|
||||
"file_id": self.animation_file_id,
|
||||
|
@ -323,33 +115,6 @@ class TestAnimation:
|
|||
assert animation_dict["mime_type"] == animation.mime_type
|
||||
assert animation_dict["file_size"] == animation.file_size
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
animation_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_animation(chat_id=chat_id, animation=animation_file)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_animation(chat_id=chat_id, animation="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_animation(chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, animation):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == animation.file_id
|
||||
|
||||
assert check_shortcut_signature(Animation.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(animation.get_file, animation.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(animation.get_file, animation.get_bot())
|
||||
|
||||
monkeypatch.setattr(animation.get_bot(), "get_file", make_assertion)
|
||||
assert await animation.get_file()
|
||||
|
||||
def test_equality(self):
|
||||
a = Animation(
|
||||
self.animation_file_id,
|
||||
|
@ -371,3 +136,222 @@ class TestAnimation:
|
|||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_animation_custom_filename(self, bot, chat_id, animation_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return list(request_data.multipart_data.values())[0][0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_animation(chat_id, animation_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_animation_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("animation") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("animation"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_animation(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
async def test_send_with_animation(self, monkeypatch, bot, chat_id, animation):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["animation"] == animation.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_animation(animation=animation, chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, animation):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == animation.file_id
|
||||
|
||||
assert check_shortcut_signature(Animation.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(animation.get_file, animation.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(animation.get_file, animation.get_bot())
|
||||
|
||||
monkeypatch.setattr(animation.get_bot(), "get_file", make_assertion)
|
||||
assert await animation.get_file()
|
||||
|
||||
|
||||
class TestAnimationWithRequest(TestAnimationBase):
|
||||
async def test_send_all_args(self, bot, chat_id, animation_file, animation, thumb_file):
|
||||
message = await bot.send_animation(
|
||||
chat_id,
|
||||
animation_file,
|
||||
duration=self.duration,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
caption=self.caption,
|
||||
parse_mode="Markdown",
|
||||
disable_notification=False,
|
||||
protect_content=True,
|
||||
thumb=thumb_file,
|
||||
has_spoiler=True,
|
||||
)
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
assert message.animation.file_name == animation.file_name
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
assert message.animation.file_size == animation.file_size
|
||||
assert message.animation.thumb.width == self.width
|
||||
assert message.animation.thumb.height == self.height
|
||||
assert message.has_protected_content
|
||||
try:
|
||||
assert message.has_media_spoiler
|
||||
except AssertionError:
|
||||
pytest.xfail("This is a bug on Telegram's end")
|
||||
|
||||
async def test_get_and_download(self, bot, animation):
|
||||
path = Path("game.gif")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(animation.file_id)
|
||||
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
new_filepath = await new_file.download_to_drive("game.gif")
|
||||
assert new_filepath.is_file()
|
||||
|
||||
async def test_send_animation_url_file(self, bot, chat_id, animation):
|
||||
message = await bot.send_animation(
|
||||
chat_id=chat_id, animation=self.animation_file_url, caption=self.caption
|
||||
)
|
||||
|
||||
assert message.caption == self.caption
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
|
||||
assert message.animation.duration == animation.duration
|
||||
assert message.animation.file_name.startswith(
|
||||
"game.gif"
|
||||
) == animation.file_name.startswith("game.gif")
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
|
||||
async def test_send_animation_caption_entities(self, bot, chat_id, animation):
|
||||
test_string = "Italic Bold Code"
|
||||
entities = [
|
||||
MessageEntity(MessageEntity.ITALIC, 0, 6),
|
||||
MessageEntity(MessageEntity.ITALIC, 7, 4),
|
||||
MessageEntity(MessageEntity.ITALIC, 12, 4),
|
||||
]
|
||||
message = await bot.send_animation(
|
||||
chat_id, animation, caption=test_string, caption_entities=entities
|
||||
)
|
||||
|
||||
assert message.caption == test_string
|
||||
assert message.caption_entities == tuple(entities)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_1(self, default_bot, chat_id, animation_file):
|
||||
test_string = "Italic Bold Code"
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string
|
||||
)
|
||||
assert message.caption_markdown == test_markdown_string
|
||||
assert message.caption == test_string
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_2(self, default_bot, chat_id, animation_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string, parse_mode=None
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_animation_default_parse_mode_3(self, default_bot, chat_id, animation_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation_file, caption=test_markdown_string, parse_mode="HTML"
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
({"allow_sending_without_reply": False}, True),
|
||||
],
|
||||
indirect=["default_bot"],
|
||||
)
|
||||
async def test_send_animation_default_allow_sending_without_reply(
|
||||
self, default_bot, chat_id, animation, custom
|
||||
):
|
||||
reply_to_message = await default_bot.send_message(chat_id, "test")
|
||||
await reply_to_message.delete()
|
||||
if custom is not None:
|
||||
message = await default_bot.send_animation(
|
||||
chat_id,
|
||||
animation,
|
||||
allow_sending_without_reply=custom,
|
||||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
elif default_bot.defaults.allow_sending_without_reply:
|
||||
message = await default_bot.send_animation(
|
||||
chat_id, animation, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
else:
|
||||
with pytest.raises(BadRequest, match="message not found"):
|
||||
await default_bot.send_animation(
|
||||
chat_id, animation, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_animation_default_protect_content(self, default_bot, chat_id, animation):
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_animation(chat_id, animation),
|
||||
default_bot.send_animation(chat_id, animation, protect_content=False),
|
||||
)
|
||||
anim_protected, anim_unprotected = await tasks
|
||||
assert anim_protected.has_protected_content
|
||||
assert not anim_unprotected.has_protected_content
|
||||
|
||||
async def test_resend(self, bot, chat_id, animation):
|
||||
message = await bot.send_animation(chat_id, animation.file_id)
|
||||
assert message.animation == animation
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
animation_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_animation(chat_id=chat_id, animation=animation_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_animation(chat_id=chat_id, animation="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_animation(chat_id=chat_id)
|
||||
|
|
|
@ -53,7 +53,13 @@ from telegram.ext import (
|
|||
filters,
|
||||
)
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from tests.conftest import PROJECT_ROOT_PATH, call_after, make_message_update, send_webhook_message
|
||||
from tests.conftest import (
|
||||
PROJECT_ROOT_PATH,
|
||||
call_after,
|
||||
make_bot,
|
||||
make_message_update,
|
||||
send_webhook_message,
|
||||
)
|
||||
|
||||
|
||||
class CustomContext(CallbackContext):
|
||||
|
@ -113,8 +119,8 @@ class TestApplication:
|
|||
):
|
||||
self.received = context.error.message
|
||||
|
||||
async def test_slot_behaviour(self, bot, mro_slots):
|
||||
async with ApplicationBuilder().token(bot.token).build() as app:
|
||||
async def test_slot_behaviour(self, one_time_bot, mro_slots):
|
||||
async with ApplicationBuilder().bot(one_time_bot).build() as app:
|
||||
for at in app.__slots__:
|
||||
at = f"_Application{at}" if at.startswith("__") and not at.endswith("__") else at
|
||||
assert getattr(app, at, "err") != "err", f"got extra slot '{at}'"
|
||||
|
@ -144,12 +150,12 @@ class TestApplication:
|
|||
"concurrent_updates, expected", [(0, 0), (4, 4), (False, 0), (True, 256)]
|
||||
)
|
||||
@pytest.mark.filterwarnings("ignore: `Application` instances should")
|
||||
def test_init(self, bot, concurrent_updates, expected):
|
||||
def test_init(self, one_time_bot, concurrent_updates, expected):
|
||||
update_queue = asyncio.Queue()
|
||||
job_queue = JobQueue()
|
||||
persistence = PicklePersistence("file_path")
|
||||
context_types = ContextTypes()
|
||||
updater = Updater(bot=bot, update_queue=update_queue)
|
||||
updater = Updater(bot=one_time_bot, update_queue=update_queue)
|
||||
|
||||
async def post_init(application: Application) -> None:
|
||||
pass
|
||||
|
@ -161,7 +167,7 @@ class TestApplication:
|
|||
pass
|
||||
|
||||
app = Application(
|
||||
bot=bot,
|
||||
bot=one_time_bot,
|
||||
update_queue=update_queue,
|
||||
job_queue=job_queue,
|
||||
persistence=persistence,
|
||||
|
@ -172,7 +178,7 @@ class TestApplication:
|
|||
post_shutdown=post_shutdown,
|
||||
post_stop=post_stop,
|
||||
)
|
||||
assert app.bot is bot
|
||||
assert app.bot is one_time_bot
|
||||
assert app.update_queue is update_queue
|
||||
assert app.job_queue is job_queue
|
||||
assert app.persistence is persistence
|
||||
|
@ -196,7 +202,7 @@ class TestApplication:
|
|||
|
||||
with pytest.raises(ValueError, match="must be a non-negative"):
|
||||
Application(
|
||||
bot=bot,
|
||||
bot=one_time_bot,
|
||||
update_queue=update_queue,
|
||||
job_queue=job_queue,
|
||||
persistence=persistence,
|
||||
|
@ -208,19 +214,19 @@ class TestApplication:
|
|||
post_stop=None,
|
||||
)
|
||||
|
||||
def test_job_queue(self, bot, app, recwarn):
|
||||
def test_job_queue(self, one_time_bot, app, recwarn):
|
||||
expected_warning = (
|
||||
"No `JobQueue` set up. To use `JobQueue`, you must install PTB via "
|
||||
"`pip install python-telegram-bot[job-queue]`."
|
||||
)
|
||||
assert app.job_queue is app._job_queue
|
||||
application = ApplicationBuilder().token(bot.token).job_queue(None).build()
|
||||
application = ApplicationBuilder().bot(one_time_bot).job_queue(None).build()
|
||||
assert application.job_queue is None
|
||||
assert len(recwarn) == 1
|
||||
assert str(recwarn[0].message) == expected_warning
|
||||
assert recwarn[0].filename == __file__, "wrong stacklevel"
|
||||
|
||||
def test_custom_context_init(self, bot):
|
||||
def test_custom_context_init(self, one_time_bot):
|
||||
cc = ContextTypes(
|
||||
context=CustomContext,
|
||||
user_data=int,
|
||||
|
@ -228,14 +234,14 @@ class TestApplication:
|
|||
bot_data=complex,
|
||||
)
|
||||
|
||||
application = ApplicationBuilder().token(bot.token).context_types(cc).build()
|
||||
application = ApplicationBuilder().bot(one_time_bot).context_types(cc).build()
|
||||
|
||||
assert isinstance(application.user_data[1], int)
|
||||
assert isinstance(application.chat_data[1], float)
|
||||
assert isinstance(application.bot_data, complex)
|
||||
|
||||
@pytest.mark.parametrize("updater", (True, False))
|
||||
async def test_initialize(self, bot, monkeypatch, updater):
|
||||
async def test_initialize(self, one_time_bot, monkeypatch, updater):
|
||||
"""Initialization of persistence is tested test_basepersistence"""
|
||||
self.test_flag = set()
|
||||
|
||||
|
@ -251,18 +257,18 @@ class TestApplication:
|
|||
)
|
||||
|
||||
if updater:
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
await app.initialize()
|
||||
assert self.test_flag == {"bot", "updater"}
|
||||
await app.shutdown()
|
||||
else:
|
||||
app = ApplicationBuilder().token(bot.token).updater(None).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).updater(None).build()
|
||||
await app.initialize()
|
||||
assert self.test_flag == {"bot"}
|
||||
await app.shutdown()
|
||||
|
||||
@pytest.mark.parametrize("updater", (True, False))
|
||||
async def test_shutdown(self, bot, monkeypatch, updater):
|
||||
async def test_shutdown(self, one_time_bot, monkeypatch, updater):
|
||||
"""Shutdown of persistence is tested in test_basepersistence"""
|
||||
self.test_flag = set()
|
||||
|
||||
|
@ -278,11 +284,11 @@ class TestApplication:
|
|||
)
|
||||
|
||||
if updater:
|
||||
async with ApplicationBuilder().token(bot.token).build():
|
||||
async with ApplicationBuilder().bot(one_time_bot).build():
|
||||
pass
|
||||
assert self.test_flag == {"bot", "updater"}
|
||||
else:
|
||||
async with ApplicationBuilder().token(bot.token).updater(None).build():
|
||||
async with ApplicationBuilder().bot(one_time_bot).updater(None).build():
|
||||
pass
|
||||
assert self.test_flag == {"bot"}
|
||||
|
||||
|
@ -329,12 +335,12 @@ class TestApplication:
|
|||
await app.shutdown()
|
||||
await app.stop()
|
||||
|
||||
async def test_start_not_running_after_failure(self, bot, monkeypatch):
|
||||
async def test_start_not_running_after_failure(self, one_time_bot, monkeypatch):
|
||||
def start(_):
|
||||
raise Exception("Test Exception")
|
||||
|
||||
monkeypatch.setattr(JobQueue, "start", start)
|
||||
app = ApplicationBuilder().token(bot.token).job_queue(JobQueue()).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).job_queue(JobQueue()).build()
|
||||
|
||||
async with app:
|
||||
with pytest.raises(Exception, match="Test Exception"):
|
||||
|
@ -405,12 +411,12 @@ class TestApplication:
|
|||
|
||||
@pytest.mark.parametrize("job_queue", (True, False))
|
||||
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
|
||||
async def test_start_stop_processing_updates(self, bot, job_queue):
|
||||
async def test_start_stop_processing_updates(self, one_time_bot, job_queue):
|
||||
# TODO: repeat a similar test for create_task, persistence processing and job queue
|
||||
if job_queue:
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
else:
|
||||
app = ApplicationBuilder().token(bot.token).job_queue(None).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).job_queue(None).build()
|
||||
|
||||
async def callback(u, c):
|
||||
self.received = u
|
||||
|
@ -440,9 +446,12 @@ class TestApplication:
|
|||
await asyncio.sleep(0.05)
|
||||
assert app.update_queue.empty()
|
||||
assert self.received == 1
|
||||
|
||||
await app.updater.start_polling()
|
||||
await app.stop()
|
||||
try: # just in case start_polling times out
|
||||
await app.updater.start_polling()
|
||||
except TelegramError:
|
||||
pytest.xfail("start_polling timed out")
|
||||
else:
|
||||
await app.stop()
|
||||
assert not app.running
|
||||
# app.stop() should not stop the updater!
|
||||
assert app.updater.running
|
||||
|
@ -476,7 +485,7 @@ class TestApplication:
|
|||
async def one(update, context):
|
||||
self.received = context
|
||||
|
||||
def two(update, context):
|
||||
async def two(update, context):
|
||||
if update.message.text == "test":
|
||||
if context is not self.received:
|
||||
pytest.fail("Expected same context object, got different")
|
||||
|
@ -643,7 +652,7 @@ class TestApplication:
|
|||
await asyncio.sleep(0.05)
|
||||
await app.stop()
|
||||
|
||||
async def test_flow_stop(self, app, bot):
|
||||
async def test_flow_stop(self, app, one_time_bot):
|
||||
passed = []
|
||||
|
||||
async def start1(b, u):
|
||||
|
@ -668,7 +677,8 @@ class TestApplication:
|
|||
],
|
||||
),
|
||||
)
|
||||
update.message.set_bot(bot)
|
||||
await one_time_bot.initialize()
|
||||
update.message.set_bot(one_time_bot)
|
||||
|
||||
async with app:
|
||||
# If ApplicationHandlerStop raised handlers in other groups should not be called.
|
||||
|
@ -679,18 +689,18 @@ class TestApplication:
|
|||
await app.process_update(update)
|
||||
assert passed == ["start1"]
|
||||
|
||||
async def test_flow_stop_by_error_handler(self, app, bot):
|
||||
async def test_flow_stop_by_error_handler(self, app):
|
||||
passed = []
|
||||
exception = Exception("General excepition")
|
||||
exception = Exception("General exception")
|
||||
|
||||
async def start1(b, u):
|
||||
async def start1(u, c):
|
||||
passed.append("start1")
|
||||
raise exception
|
||||
|
||||
async def start2(b, u):
|
||||
async def start2(u, c):
|
||||
passed.append("start2")
|
||||
|
||||
async def start3(b, u):
|
||||
async def start3(u, c):
|
||||
passed.append("start3")
|
||||
|
||||
async def error(u, c):
|
||||
|
@ -728,7 +738,7 @@ class TestApplication:
|
|||
# Higher groups should still be called
|
||||
assert self.count == 42
|
||||
|
||||
async def test_error_in_handler_part_2(self, app, bot):
|
||||
async def test_error_in_handler_part_2(self, app, one_time_bot):
|
||||
passed = []
|
||||
err = Exception("General exception")
|
||||
|
||||
|
@ -758,7 +768,8 @@ class TestApplication:
|
|||
],
|
||||
),
|
||||
)
|
||||
update.message.set_bot(bot)
|
||||
await one_time_bot.initialize()
|
||||
update.message.set_bot(one_time_bot)
|
||||
|
||||
async with app:
|
||||
# If an unhandled exception was caught, no further handlers from the same group should
|
||||
|
@ -837,7 +848,7 @@ class TestApplication:
|
|||
|
||||
await app.stop()
|
||||
|
||||
async def test_custom_context_error_handler(self, bot):
|
||||
async def test_custom_context_error_handler(self, one_time_bot):
|
||||
async def error_handler(_, context):
|
||||
self.received = (
|
||||
type(context),
|
||||
|
@ -848,7 +859,7 @@ class TestApplication:
|
|||
|
||||
application = (
|
||||
ApplicationBuilder()
|
||||
.token(bot.token)
|
||||
.bot(one_time_bot)
|
||||
.context_types(
|
||||
ContextTypes(
|
||||
context=CustomContext, bot_data=int, user_data=float, chat_data=complex
|
||||
|
@ -866,8 +877,8 @@ class TestApplication:
|
|||
await asyncio.sleep(0.05)
|
||||
assert self.received == (CustomContext, float, complex, int)
|
||||
|
||||
async def test_custom_context_handler_callback(self, bot):
|
||||
def callback(_, context):
|
||||
async def test_custom_context_handler_callback(self, one_time_bot):
|
||||
async def callback(_, context):
|
||||
self.received = (
|
||||
type(context),
|
||||
type(context.user_data),
|
||||
|
@ -877,7 +888,7 @@ class TestApplication:
|
|||
|
||||
application = (
|
||||
ApplicationBuilder()
|
||||
.token(bot.token)
|
||||
.bot(one_time_bot)
|
||||
.context_types(
|
||||
ContextTypes(
|
||||
context=CustomContext, bot_data=int, user_data=float, chat_data=complex
|
||||
|
@ -971,7 +982,7 @@ class TestApplication:
|
|||
), "incorrect stacklevel!"
|
||||
|
||||
async def test_non_blocking_no_error_handler(self, app, caplog):
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error, block=False))
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error("Test error"), block=False))
|
||||
|
||||
with caplog.at_level(logging.ERROR):
|
||||
async with app:
|
||||
|
@ -997,7 +1008,7 @@ class TestApplication:
|
|||
|
||||
app.add_error_handler(async_error_handler, block=False)
|
||||
app.add_error_handler(normal_error_handler)
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error, block=handler_block))
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error("err"), block=handler_block))
|
||||
|
||||
async with app:
|
||||
await app.start()
|
||||
|
@ -1041,14 +1052,15 @@ class TestApplication:
|
|||
), "incorrect stacklevel!"
|
||||
|
||||
@pytest.mark.parametrize(["block", "expected_output"], [(False, 0), (True, 5)])
|
||||
async def test_default_block_error_handler(self, bot, block, expected_output):
|
||||
async def test_default_block_error_handler(self, bot_info, block, expected_output):
|
||||
async def error_handler(*args, **kwargs):
|
||||
await asyncio.sleep(0.1)
|
||||
self.count = 5
|
||||
|
||||
app = Application.builder().token(bot.token).defaults(Defaults(block=block)).build()
|
||||
bot = make_bot(bot_info, defaults=Defaults(block=block))
|
||||
app = Application.builder().bot(bot).build()
|
||||
async with app:
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error))
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error("error")))
|
||||
app.add_error_handler(error_handler)
|
||||
await app.process_update(1)
|
||||
await asyncio.sleep(0.05)
|
||||
|
@ -1057,8 +1069,9 @@ class TestApplication:
|
|||
assert self.count == 5
|
||||
|
||||
@pytest.mark.parametrize(["block", "expected_output"], [(False, 0), (True, 5)])
|
||||
async def test_default_block_handler(self, bot, block, expected_output):
|
||||
app = Application.builder().token(bot.token).defaults(Defaults(block=block)).build()
|
||||
async def test_default_block_handler(self, bot_info, block, expected_output):
|
||||
bot = make_bot(bot_info, defaults=Defaults(block=block))
|
||||
app = Application.builder().bot(bot).build()
|
||||
async with app:
|
||||
app.add_handler(TypeHandler(object, self.callback_set_count(5, sleep=0.1)))
|
||||
await app.process_update(1)
|
||||
|
@ -1072,7 +1085,7 @@ class TestApplication:
|
|||
async def test_nonblocking_handler_raises_and_non_blocking_error_handler_raises(
|
||||
self, app, caplog, handler_block, error_handler_block
|
||||
):
|
||||
handler = TypeHandler(object, self.callback_raise_error, block=handler_block)
|
||||
handler = TypeHandler(object, self.callback_raise_error("error"), block=handler_block)
|
||||
app.add_handler(handler)
|
||||
app.add_error_handler(self.error_handler_raise_error, block=error_handler_block)
|
||||
|
||||
|
@ -1303,10 +1316,12 @@ class TestApplication:
|
|||
await app.stop()
|
||||
|
||||
@pytest.mark.parametrize("concurrent_updates", (15, 50, 100))
|
||||
async def test_concurrent_updates(self, bot, concurrent_updates):
|
||||
async def test_concurrent_updates(self, one_time_bot, concurrent_updates):
|
||||
# We don't test with `True` since the large number of parallel coroutines quickly leads
|
||||
# to test instabilities
|
||||
app = Application.builder().token(bot.token).concurrent_updates(concurrent_updates).build()
|
||||
app = (
|
||||
Application.builder().bot(one_time_bot).concurrent_updates(concurrent_updates).build()
|
||||
)
|
||||
events = {i: asyncio.Event() for i in range(app.concurrent_updates + 10)}
|
||||
queue = asyncio.Queue()
|
||||
for event in events.values():
|
||||
|
@ -1337,8 +1352,8 @@ class TestApplication:
|
|||
|
||||
await app.stop()
|
||||
|
||||
async def test_concurrent_updates_done_on_shutdown(self, bot):
|
||||
app = Application.builder().token(bot.token).concurrent_updates(True).build()
|
||||
async def test_concurrent_updates_done_on_shutdown(self, one_time_bot):
|
||||
app = Application.builder().bot(one_time_bot).concurrent_updates(True).build()
|
||||
event = asyncio.Event()
|
||||
|
||||
async def callback(update, context):
|
||||
|
@ -1422,7 +1437,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_polling_post_init(self, bot, monkeypatch):
|
||||
def test_run_polling_post_init(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def get_updates(*args, **kwargs):
|
||||
|
@ -1443,7 +1458,7 @@ class TestApplication:
|
|||
async def post_init(app: Application) -> None:
|
||||
events.append("post_init")
|
||||
|
||||
app = Application.builder().token(bot.token).post_init(post_init).build()
|
||||
app = Application.builder().bot(one_time_bot).post_init(post_init).build()
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(
|
||||
|
@ -1465,7 +1480,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_polling_post_shutdown(self, bot, monkeypatch):
|
||||
def test_run_polling_post_shutdown(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def get_updates(*args, **kwargs):
|
||||
|
@ -1486,7 +1501,7 @@ class TestApplication:
|
|||
async def post_shutdown(app: Application) -> None:
|
||||
events.append("post_shutdown")
|
||||
|
||||
app = Application.builder().token(bot.token).post_shutdown(post_shutdown).build()
|
||||
app = Application.builder().bot(one_time_bot).post_shutdown(post_shutdown).build()
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(
|
||||
|
@ -1691,7 +1706,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_webhook_post_init(self, bot, monkeypatch):
|
||||
def test_run_webhook_post_init(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def delete_webhook(*args, **kwargs):
|
||||
|
@ -1718,7 +1733,7 @@ class TestApplication:
|
|||
async def post_init(app: Application) -> None:
|
||||
events.append("post_init")
|
||||
|
||||
app = Application.builder().token(bot.token).post_init(post_init).build()
|
||||
app = Application.builder().bot(one_time_bot).post_init(post_init).build()
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
@ -1751,7 +1766,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_webhook_post_shutdown(self, bot, monkeypatch):
|
||||
def test_run_webhook_post_shutdown(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def delete_webhook(*args, **kwargs):
|
||||
|
@ -1778,7 +1793,7 @@ class TestApplication:
|
|||
async def post_shutdown(app: Application) -> None:
|
||||
events.append("post_shutdown")
|
||||
|
||||
app = Application.builder().token(bot.token).post_shutdown(post_shutdown).build()
|
||||
app = Application.builder().bot(one_time_bot).post_shutdown(post_shutdown).build()
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
@ -1883,7 +1898,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_webhook_parameters_passing(self, bot, monkeypatch):
|
||||
def test_run_webhook_parameters_passing(self, one_time_bot, monkeypatch):
|
||||
# Check that we pass them correctly
|
||||
|
||||
async def start_webhook(_, **kwargs):
|
||||
|
@ -1898,7 +1913,7 @@ class TestApplication:
|
|||
|
||||
monkeypatch.setattr(Updater, "start_webhook", start_webhook)
|
||||
monkeypatch.setattr(Updater, "stop", stop)
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
app_signature = inspect.signature(app.run_webhook)
|
||||
|
||||
for name, param in updater_signature.parameters.items():
|
||||
|
@ -1939,8 +1954,8 @@ class TestApplication:
|
|||
assert set(self.received.keys()) == set(expected.keys())
|
||||
assert self.received == expected
|
||||
|
||||
def test_run_without_updater(self, bot):
|
||||
app = ApplicationBuilder().token(bot.token).updater(None).build()
|
||||
def test_run_without_updater(self, one_time_bot):
|
||||
app = ApplicationBuilder().bot(one_time_bot).updater(None).build()
|
||||
|
||||
with pytest.raises(RuntimeError, match="only available if the application has an Updater"):
|
||||
app.run_webhook()
|
||||
|
@ -1950,7 +1965,7 @@ class TestApplication:
|
|||
|
||||
@pytest.mark.parametrize("method", ["start", "initialize"])
|
||||
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
|
||||
def test_run_error_in_application(self, bot, monkeypatch, method):
|
||||
def test_run_error_in_application(self, one_time_bot, monkeypatch, method):
|
||||
shutdowns = []
|
||||
|
||||
async def raise_method(*args, **kwargs):
|
||||
|
@ -1971,7 +1986,7 @@ class TestApplication:
|
|||
monkeypatch.setattr(
|
||||
Updater, "shutdown", call_after(Updater.shutdown, after_shutdown("updater"))
|
||||
)
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
with pytest.raises(RuntimeError, match="Test Exception"):
|
||||
app.run_polling(close_loop=False)
|
||||
|
||||
|
@ -1986,7 +2001,7 @@ class TestApplication:
|
|||
|
||||
@pytest.mark.parametrize("method", ["start_polling", "start_webhook"])
|
||||
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
|
||||
def test_run_error_in_updater(self, bot, monkeypatch, method):
|
||||
def test_run_error_in_updater(self, one_time_bot, monkeypatch, method):
|
||||
shutdowns = []
|
||||
|
||||
async def raise_method(*args, **kwargs):
|
||||
|
@ -2007,7 +2022,7 @@ class TestApplication:
|
|||
monkeypatch.setattr(
|
||||
Updater, "shutdown", call_after(Updater.shutdown, after_shutdown("updater"))
|
||||
)
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
with pytest.raises(RuntimeError, match="Test Exception"):
|
||||
if "polling" in method:
|
||||
app.run_polling(close_loop=False)
|
||||
|
@ -2023,12 +2038,12 @@ class TestApplication:
|
|||
reason="Only really relevant on windows",
|
||||
)
|
||||
@pytest.mark.parametrize("method", ["start_polling", "start_webhook"])
|
||||
def test_run_stop_signal_warning_windows(self, bot, method, recwarn, monkeypatch):
|
||||
def test_run_stop_signal_warning_windows(self, one_time_bot, method, recwarn, monkeypatch):
|
||||
async def raise_method(*args, **kwargs):
|
||||
raise RuntimeError("Prevent Actually Running")
|
||||
|
||||
monkeypatch.setattr(Application, "initialize", raise_method)
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
|
||||
with pytest.raises(RuntimeError, match="Prevent Actually Running"):
|
||||
if "polling" in method:
|
||||
|
@ -2054,7 +2069,7 @@ class TestApplication:
|
|||
|
||||
assert len(recwarn) == 0
|
||||
|
||||
@pytest.mark.timeout(6)
|
||||
@pytest.mark.flaky(3, 1) # loop.call_later will error the test when a flood error is received
|
||||
def test_signal_handlers(self, app, monkeypatch):
|
||||
# this test should make sure that signal handlers are set by default on Linux + Mac,
|
||||
# and not on Windows.
|
||||
|
@ -2068,11 +2083,10 @@ class TestApplication:
|
|||
loop = asyncio.get_event_loop()
|
||||
monkeypatch.setattr(loop, "add_signal_handler", signal_handler_test)
|
||||
|
||||
async def abort_app():
|
||||
await asyncio.sleep(2)
|
||||
def abort_app():
|
||||
raise SystemExit
|
||||
|
||||
loop.create_task(abort_app())
|
||||
loop.call_later(0.6, abort_app)
|
||||
|
||||
app.run_polling(close_loop=False)
|
||||
|
||||
|
@ -2082,7 +2096,7 @@ class TestApplication:
|
|||
assert received_signals == [signal.SIGINT, signal.SIGTERM, signal.SIGABRT]
|
||||
|
||||
received_signals.clear()
|
||||
loop.create_task(abort_app())
|
||||
loop.call_later(0.6, abort_app)
|
||||
app.run_webhook(port=49152, webhook_url="example.com", close_loop=False)
|
||||
|
||||
if platform.system() == "Windows":
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
|
||||
import httpx
|
||||
|
@ -38,10 +37,7 @@ from telegram.ext import (
|
|||
from telegram.ext._applicationbuilder import _BOT_CHECKS
|
||||
from telegram.request import HTTPXRequest
|
||||
|
||||
from .auxil.object_conversions import env_var_2_bool
|
||||
from .conftest import PRIVATE_KEY, data_file
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
from .conftest import PRIVATE_KEY, TEST_WITH_OPT_DEPS, data_file
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
@ -35,20 +36,17 @@ from tests.conftest import data_file
|
|||
|
||||
@pytest.fixture(scope="function")
|
||||
def audio_file():
|
||||
with open(data_file("telegram.mp3"), "rb") as f:
|
||||
with data_file("telegram.mp3").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
async def audio(bot, chat_id):
|
||||
with data_file("telegram.mp3").open("rb") as f:
|
||||
thumb = data_file("thumb.jpg")
|
||||
return (
|
||||
await bot.send_audio(chat_id, audio=f, read_timeout=50, thumb=thumb.open("rb"))
|
||||
).audio
|
||||
with data_file("telegram.mp3").open("rb") as f, data_file("thumb.jpg").open("rb") as thumb:
|
||||
return (await bot.send_audio(chat_id, audio=f, read_timeout=50, thumb=thumb)).audio
|
||||
|
||||
|
||||
class TestAudio:
|
||||
class TestAudioBase:
|
||||
caption = "Test *audio*"
|
||||
performer = "Leandro Toledo"
|
||||
title = "Teste"
|
||||
|
@ -65,6 +63,8 @@ class TestAudio:
|
|||
audio_file_id = "5a3128a4d2a04750b5b58397f3b5e812"
|
||||
audio_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestAudioWithoutRequest(TestAudioBase):
|
||||
def test_slot_behaviour(self, audio, mro_slots):
|
||||
for attr in audio.__slots__:
|
||||
assert getattr(audio, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -88,176 +88,6 @@ class TestAudio:
|
|||
assert audio.thumb.width == self.thumb_width
|
||||
assert audio.thumb.height == self.thumb_height
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_all_args(self, bot, chat_id, audio_file, thumb_file):
|
||||
message = await bot.send_audio(
|
||||
chat_id,
|
||||
audio=audio_file,
|
||||
caption=self.caption,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title,
|
||||
disable_notification=False,
|
||||
protect_content=True,
|
||||
parse_mode="Markdown",
|
||||
thumb=thumb_file,
|
||||
)
|
||||
|
||||
assert message.caption == self.caption.replace("*", "")
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == self.duration
|
||||
assert message.audio.performer == self.performer
|
||||
assert message.audio.title == self.title
|
||||
assert message.audio.file_name == self.file_name
|
||||
assert message.audio.mime_type == self.mime_type
|
||||
assert message.audio.file_size == self.file_size
|
||||
assert message.audio.thumb.file_size == self.thumb_file_size
|
||||
assert message.audio.thumb.width == self.thumb_width
|
||||
assert message.audio.thumb.height == self.thumb_height
|
||||
assert message.has_protected_content
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_audio_custom_filename(self, bot, chat_id, audio_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return list(request_data.multipart_data.values())[0][0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
assert await bot.send_audio(chat_id, audio_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_get_and_download(self, bot, audio):
|
||||
path = Path("telegram.mp3")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(audio.file_id)
|
||||
|
||||
assert new_file.file_size == self.file_size
|
||||
assert new_file.file_id == audio.file_id
|
||||
assert new_file.file_unique_id == audio.file_unique_id
|
||||
assert str(new_file.file_path).startswith("https://")
|
||||
|
||||
await new_file.download_to_drive("telegram.mp3")
|
||||
|
||||
assert path.is_file()
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_mp3_url_file(self, bot, chat_id, audio):
|
||||
message = await bot.send_audio(
|
||||
chat_id=chat_id, audio=self.audio_file_url, caption=self.caption
|
||||
)
|
||||
|
||||
assert message.caption == self.caption
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == audio.duration
|
||||
assert message.audio.mime_type == audio.mime_type
|
||||
assert message.audio.file_size == audio.file_size
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_resend(self, bot, chat_id, audio):
|
||||
message = await bot.send_audio(chat_id=chat_id, audio=audio.file_id)
|
||||
|
||||
assert message.audio == audio
|
||||
|
||||
async def test_send_with_audio(self, monkeypatch, bot, chat_id, audio):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["audio"] == audio.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.send_audio(audio=audio, chat_id=chat_id)
|
||||
assert message
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_audio_caption_entities(self, bot, chat_id, audio):
|
||||
test_string = "Italic Bold Code"
|
||||
entities = [
|
||||
MessageEntity(MessageEntity.ITALIC, 0, 6),
|
||||
MessageEntity(MessageEntity.ITALIC, 7, 4),
|
||||
MessageEntity(MessageEntity.ITALIC, 12, 4),
|
||||
]
|
||||
message = await bot.send_audio(
|
||||
chat_id, audio, caption=test_string, caption_entities=entities
|
||||
)
|
||||
|
||||
assert message.caption == test_string
|
||||
assert message.caption_entities == tuple(entities)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_1(self, default_bot, chat_id, audio_file):
|
||||
test_string = "Italic Bold Code"
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(chat_id, audio_file, caption=test_markdown_string)
|
||||
assert message.caption_markdown == test_markdown_string
|
||||
assert message.caption == test_string
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_2(self, default_bot, chat_id, audio_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(
|
||||
chat_id, audio_file, caption=test_markdown_string, parse_mode=None
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_3(self, default_bot, chat_id, audio_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(
|
||||
chat_id, audio_file, caption=test_markdown_string, parse_mode="HTML"
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_audio_default_protect_content(self, default_bot, chat_id, audio):
|
||||
protected_audio = await default_bot.send_audio(chat_id, audio)
|
||||
assert protected_audio.has_protected_content
|
||||
unprotected = await default_bot.send_audio(chat_id, audio, protect_content=False)
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_audio_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("audio") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("audio"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_audio(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
monkeypatch.delattr(bot, "_post")
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
def test_de_json(self, bot, audio):
|
||||
json_dict = {
|
||||
"file_id": self.audio_file_id,
|
||||
|
@ -294,33 +124,6 @@ class TestAudio:
|
|||
assert audio_dict["file_size"] == audio.file_size
|
||||
assert audio_dict["file_name"] == audio.file_name
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
audio_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_audio(chat_id=chat_id, audio=audio_file)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_audio(chat_id=chat_id, audio="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_audio(chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, audio):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == audio.file_id
|
||||
|
||||
assert check_shortcut_signature(Audio.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(audio.get_file, audio.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(audio.get_file, audio.get_bot())
|
||||
|
||||
monkeypatch.setattr(audio._bot, "get_file", make_assertion)
|
||||
assert await audio.get_file()
|
||||
|
||||
def test_equality(self, audio):
|
||||
a = Audio(audio.file_id, audio.file_unique_id, audio.duration)
|
||||
b = Audio("", audio.file_unique_id, audio.duration)
|
||||
|
@ -340,3 +143,187 @@ class TestAudio:
|
|||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_with_audio(self, monkeypatch, bot, chat_id, audio):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["audio"] == audio.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_audio(audio=audio, chat_id=chat_id)
|
||||
|
||||
async def test_send_audio_custom_filename(self, bot, chat_id, audio_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return list(request_data.multipart_data.values())[0][0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_audio(chat_id, audio_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_audio_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("audio") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("audio"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_audio(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, audio):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == audio.file_id
|
||||
|
||||
assert check_shortcut_signature(Audio.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(audio.get_file, audio.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(audio.get_file, audio.get_bot())
|
||||
|
||||
monkeypatch.setattr(audio._bot, "get_file", make_assertion)
|
||||
assert await audio.get_file()
|
||||
|
||||
|
||||
class TestAudioWithRequest(TestAudioBase):
|
||||
async def test_send_all_args(self, bot, chat_id, audio_file, thumb_file):
|
||||
message = await bot.send_audio(
|
||||
chat_id,
|
||||
audio=audio_file,
|
||||
caption=self.caption,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title,
|
||||
disable_notification=False,
|
||||
protect_content=True,
|
||||
parse_mode="Markdown",
|
||||
thumb=thumb_file,
|
||||
)
|
||||
|
||||
assert message.caption == self.caption.replace("*", "")
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == self.duration
|
||||
assert message.audio.performer == self.performer
|
||||
assert message.audio.title == self.title
|
||||
assert message.audio.file_name == self.file_name
|
||||
assert message.audio.mime_type == self.mime_type
|
||||
assert message.audio.file_size == self.file_size
|
||||
assert message.audio.thumb.file_size == self.thumb_file_size
|
||||
assert message.audio.thumb.width == self.thumb_width
|
||||
assert message.audio.thumb.height == self.thumb_height
|
||||
assert message.has_protected_content
|
||||
|
||||
async def test_get_and_download(self, bot, chat_id, audio):
|
||||
path = Path("telegram.mp3")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(audio.file_id)
|
||||
|
||||
assert new_file.file_size == self.file_size
|
||||
assert new_file.file_unique_id == audio.file_unique_id
|
||||
assert str(new_file.file_path).startswith("https://")
|
||||
|
||||
await new_file.download_to_drive("telegram.mp3")
|
||||
assert path.is_file()
|
||||
|
||||
async def test_send_mp3_url_file(self, bot, chat_id, audio):
|
||||
message = await bot.send_audio(
|
||||
chat_id=chat_id, audio=self.audio_file_url, caption=self.caption
|
||||
)
|
||||
|
||||
assert message.caption == self.caption
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == audio.duration
|
||||
assert message.audio.mime_type == audio.mime_type
|
||||
assert message.audio.file_size == audio.file_size
|
||||
|
||||
async def test_send_audio_caption_entities(self, bot, chat_id, audio):
|
||||
test_string = "Italic Bold Code"
|
||||
entities = [
|
||||
MessageEntity(MessageEntity.ITALIC, 0, 6),
|
||||
MessageEntity(MessageEntity.ITALIC, 7, 4),
|
||||
MessageEntity(MessageEntity.ITALIC, 12, 4),
|
||||
]
|
||||
message = await bot.send_audio(
|
||||
chat_id, audio, caption=test_string, caption_entities=entities
|
||||
)
|
||||
|
||||
assert message.caption == test_string
|
||||
assert message.caption_entities == tuple(entities)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_1(self, default_bot, chat_id, audio_file):
|
||||
test_string = "Italic Bold Code"
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(chat_id, audio_file, caption=test_markdown_string)
|
||||
assert message.caption_markdown == test_markdown_string
|
||||
assert message.caption == test_string
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_2(self, default_bot, chat_id, audio_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(
|
||||
chat_id, audio_file, caption=test_markdown_string, parse_mode=None
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_audio_default_parse_mode_3(self, default_bot, chat_id, audio_file):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
||||
message = await default_bot.send_audio(
|
||||
chat_id, audio_file, caption=test_markdown_string, parse_mode="HTML"
|
||||
)
|
||||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_audio_default_protect_content(self, default_bot, chat_id, audio):
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_audio(chat_id, audio),
|
||||
default_bot.send_audio(chat_id, audio, protect_content=False),
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
async def test_resend(self, bot, chat_id, audio):
|
||||
message = await bot.send_audio(chat_id=chat_id, audio=audio.file_id)
|
||||
assert message.audio == audio
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
audio_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_audio(chat_id=chat_id, audio=audio_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_audio(chat_id=chat_id, audio="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_audio(chat_id=chat_id)
|
||||
|
|
|
@ -43,7 +43,7 @@ from telegram.ext import (
|
|||
filters,
|
||||
)
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from tests.conftest import DictApplication, make_message_update
|
||||
from tests.conftest import DictApplication, make_bot, make_message_update
|
||||
|
||||
|
||||
class HandlerStates(int, enum.Enum):
|
||||
|
@ -227,7 +227,11 @@ class PappInput(NamedTuple):
|
|||
|
||||
|
||||
def build_papp(
|
||||
token: str, store_data: dict = None, update_interval: float = None, fill_data: bool = False
|
||||
bot_info: dict = None,
|
||||
token: str = None,
|
||||
store_data: dict = None,
|
||||
update_interval: float = None,
|
||||
fill_data: bool = False,
|
||||
) -> Application:
|
||||
store_data = PersistenceInput(**(store_data or {}))
|
||||
if update_interval is not None:
|
||||
|
@ -237,12 +241,15 @@ def build_papp(
|
|||
else:
|
||||
persistence = TrackingPersistence(store_data=store_data, fill_data=fill_data)
|
||||
|
||||
if bot_info is not None:
|
||||
bot = make_bot(bot_info, arbitrary_callback_data=True)
|
||||
else:
|
||||
bot = make_bot(token=token, arbitrary_callback_data=True)
|
||||
return (
|
||||
ApplicationBuilder()
|
||||
.token(token)
|
||||
.bot(bot)
|
||||
.persistence(persistence)
|
||||
.application_class(DictApplication)
|
||||
.arbitrary_callback_data(True)
|
||||
.build()
|
||||
)
|
||||
|
||||
|
@ -252,7 +259,7 @@ def build_conversation_handler(name: str, persistent: bool = True) -> BaseHandle
|
|||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def papp(request, bot) -> Application:
|
||||
def papp(request, bot_info) -> Application:
|
||||
papp_input = request.param
|
||||
store_data = {}
|
||||
if papp_input.bot_data is not None:
|
||||
|
@ -265,7 +272,7 @@ def papp(request, bot) -> Application:
|
|||
store_data["callback_data"] = papp_input.callback_data
|
||||
|
||||
app = build_papp(
|
||||
bot.token,
|
||||
bot_info=bot_info,
|
||||
store_data=store_data,
|
||||
update_interval=papp_input.update_interval,
|
||||
fill_data=papp_input.fill_data,
|
||||
|
@ -998,7 +1005,7 @@ class TestBasePersistence:
|
|||
assert papp.persistence.dropped_chat_ids == {1: 1}
|
||||
assert papp.persistence.updated_chat_ids == {2: 1}
|
||||
|
||||
async def test_errors_while_persisting(self, bot, caplog):
|
||||
async def test_errors_while_persisting(self, bot_info, caplog):
|
||||
class ErrorPersistence(TrackingPersistence):
|
||||
def raise_error(self):
|
||||
raise Exception("PersistenceError")
|
||||
|
@ -1032,8 +1039,7 @@ class TestBasePersistence:
|
|||
|
||||
app = (
|
||||
ApplicationBuilder()
|
||||
.token(bot.token)
|
||||
.arbitrary_callback_data(True)
|
||||
.bot(make_bot(bot_info, arbitrary_callback_data=True))
|
||||
.persistence(ErrorPersistence())
|
||||
.build()
|
||||
)
|
||||
|
|
3024
tests/test_bot.py
3024
tests/test_bot.py
File diff suppressed because it is too large
Load diff
|
@ -22,12 +22,12 @@ import pytest
|
|||
from telegram import BotCommand, Dice
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def bot_command():
|
||||
return BotCommand(command="start", description="A command")
|
||||
|
||||
|
||||
class TestBotCommand:
|
||||
class TestBotCommandWithoutRequest:
|
||||
command = "start"
|
||||
description = "A command"
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", params=["str", "int"])
|
||||
@pytest.fixture(scope="module", params=["str", "int"])
|
||||
def chat_id(request):
|
||||
if request.param == "str":
|
||||
return "@supergroupusername"
|
||||
|
@ -57,7 +57,7 @@ def scope_type(request):
|
|||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="class",
|
||||
scope="module",
|
||||
params=[
|
||||
BotCommandScopeDefault,
|
||||
BotCommandScopeAllPrivateChats,
|
||||
|
@ -82,7 +82,7 @@ def scope_class(request):
|
|||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="class",
|
||||
scope="module",
|
||||
params=[
|
||||
(BotCommandScopeDefault, BotCommandScope.DEFAULT),
|
||||
(BotCommandScopeAllPrivateChats, BotCommandScope.ALL_PRIVATE_CHATS),
|
||||
|
@ -106,7 +106,7 @@ def scope_class_and_type(request):
|
|||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def bot_command_scope(scope_class_and_type, chat_id):
|
||||
# we use de_json here so that we don't have to worry about which class needs which arguments
|
||||
return scope_class_and_type[0].de_json(
|
||||
|
@ -115,7 +115,7 @@ def bot_command_scope(scope_class_and_type, chat_id):
|
|||
|
||||
|
||||
# All the scope types are very similar, so we test everything via parametrization
|
||||
class TestBotCommandScope:
|
||||
class TestBotCommandScopeWithoutRequest:
|
||||
def test_slot_behaviour(self, bot_command_scope, mro_slots):
|
||||
for attr in bot_command_scope.__slots__:
|
||||
assert getattr(bot_command_scope, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import os
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
|
@ -28,7 +27,7 @@ from telegram import CallbackQuery, Chat, InlineKeyboardButton, InlineKeyboardMa
|
|||
from telegram._utils.datetime import UTC
|
||||
from telegram.ext import ExtBot
|
||||
from telegram.ext._callbackdatacache import CallbackDataCache, InvalidCallbackData, _KeyboardData
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
from tests.conftest import TEST_WITH_OPT_DEPS
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
|
@ -36,9 +35,6 @@ def callback_data_cache(bot):
|
|||
return CallbackDataCache(bot)
|
||||
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
TEST_WITH_OPT_DEPS,
|
||||
reason="Only relevant if the optional dependency is not installed",
|
||||
|
|
|
@ -32,23 +32,23 @@ from tests.auxil.bot_method_checks import (
|
|||
@pytest.fixture(scope="function", params=["message", "inline"])
|
||||
def callback_query(bot, request):
|
||||
cbq = CallbackQuery(
|
||||
TestCallbackQuery.id_,
|
||||
TestCallbackQuery.from_user,
|
||||
TestCallbackQuery.chat_instance,
|
||||
data=TestCallbackQuery.data,
|
||||
game_short_name=TestCallbackQuery.game_short_name,
|
||||
TestCallbackQueryBase.id_,
|
||||
TestCallbackQueryBase.from_user,
|
||||
TestCallbackQueryBase.chat_instance,
|
||||
data=TestCallbackQueryBase.data,
|
||||
game_short_name=TestCallbackQueryBase.game_short_name,
|
||||
)
|
||||
cbq.set_bot(bot)
|
||||
cbq._unfreeze()
|
||||
if request.param == "message":
|
||||
cbq.message = TestCallbackQuery.message
|
||||
cbq.message = TestCallbackQueryBase.message
|
||||
cbq.message.set_bot(bot)
|
||||
else:
|
||||
cbq.inline_message_id = TestCallbackQuery.inline_message_id
|
||||
cbq.inline_message_id = TestCallbackQueryBase.inline_message_id
|
||||
return cbq
|
||||
|
||||
|
||||
class TestCallbackQuery:
|
||||
class TestCallbackQueryBase:
|
||||
id_ = "id"
|
||||
from_user = User(1, "test_user", False)
|
||||
chat_instance = "chat_instance"
|
||||
|
@ -57,6 +57,8 @@ class TestCallbackQuery:
|
|||
inline_message_id = "inline_message_id"
|
||||
game_short_name = "the_game"
|
||||
|
||||
|
||||
class TestCallbackQueryWithoutRequest(TestCallbackQueryBase):
|
||||
@staticmethod
|
||||
def skip_params(callback_query: CallbackQuery):
|
||||
if callback_query.inline_message_id:
|
||||
|
@ -121,6 +123,26 @@ class TestCallbackQuery:
|
|||
assert callback_query_dict["data"] == callback_query.data
|
||||
assert callback_query_dict["game_short_name"] == callback_query.game_short_name
|
||||
|
||||
def test_equality(self):
|
||||
a = CallbackQuery(self.id_, self.from_user, "chat")
|
||||
b = CallbackQuery(self.id_, self.from_user, "chat")
|
||||
c = CallbackQuery(self.id_, None, "")
|
||||
d = CallbackQuery("", None, "chat")
|
||||
e = Audio(self.id_, "unique_id", 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_answer(self, monkeypatch, callback_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["callback_query_id"] == callback_query.id
|
||||
|
@ -447,23 +469,3 @@ class TestCallbackQuery:
|
|||
|
||||
monkeypatch.setattr(callback_query.get_bot(), "copy_message", make_assertion)
|
||||
assert await callback_query.copy_message(1)
|
||||
|
||||
def test_equality(self):
|
||||
a = CallbackQuery(self.id_, self.from_user, "chat")
|
||||
b = CallbackQuery(self.id_, self.from_user, "chat")
|
||||
c = CallbackQuery(self.id_, None, "")
|
||||
d = CallbackQuery("", None, "chat")
|
||||
e = Audio(self.id_, "unique_id", 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -29,37 +29,37 @@ from tests.auxil.bot_method_checks import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat(bot):
|
||||
chat = Chat(
|
||||
TestChat.id_,
|
||||
title=TestChat.title,
|
||||
type=TestChat.type_,
|
||||
username=TestChat.username,
|
||||
sticker_set_name=TestChat.sticker_set_name,
|
||||
can_set_sticker_set=TestChat.can_set_sticker_set,
|
||||
permissions=TestChat.permissions,
|
||||
slow_mode_delay=TestChat.slow_mode_delay,
|
||||
bio=TestChat.bio,
|
||||
linked_chat_id=TestChat.linked_chat_id,
|
||||
location=TestChat.location,
|
||||
TestChatBase.id_,
|
||||
title=TestChatBase.title,
|
||||
type=TestChatBase.type_,
|
||||
username=TestChatBase.username,
|
||||
sticker_set_name=TestChatBase.sticker_set_name,
|
||||
can_set_sticker_set=TestChatBase.can_set_sticker_set,
|
||||
permissions=TestChatBase.permissions,
|
||||
slow_mode_delay=TestChatBase.slow_mode_delay,
|
||||
bio=TestChatBase.bio,
|
||||
linked_chat_id=TestChatBase.linked_chat_id,
|
||||
location=TestChatBase.location,
|
||||
has_private_forwards=True,
|
||||
has_protected_content=True,
|
||||
join_to_send_messages=True,
|
||||
join_by_request=True,
|
||||
has_restricted_voice_and_video_messages=True,
|
||||
is_forum=True,
|
||||
active_usernames=TestChat.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChat.emoji_status_custom_emoji_id,
|
||||
has_aggressive_anti_spam_enabled=TestChat.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChat.has_hidden_members,
|
||||
active_usernames=TestChatBase.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChatBase.emoji_status_custom_emoji_id,
|
||||
has_aggressive_anti_spam_enabled=TestChatBase.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChatBase.has_hidden_members,
|
||||
)
|
||||
chat.set_bot(bot)
|
||||
chat._unfreeze()
|
||||
return chat
|
||||
|
||||
|
||||
class TestChat:
|
||||
class TestChatBase:
|
||||
id_ = -28767330
|
||||
title = "ToledosPalaceBot - Group"
|
||||
type_ = "group"
|
||||
|
@ -87,6 +87,8 @@ class TestChat:
|
|||
has_aggressive_anti_spam_enabled = True
|
||||
has_hidden_members = True
|
||||
|
||||
|
||||
class TestChatWithoutRequest(TestChatBase):
|
||||
def test_slot_behaviour(self, chat, mro_slots):
|
||||
for attr in chat.__slots__:
|
||||
assert getattr(chat, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -194,6 +196,26 @@ class TestChat:
|
|||
chat = Chat(id=1, type="private")
|
||||
assert chat.type is ChatType.PRIVATE
|
||||
|
||||
def test_equality(self):
|
||||
a = Chat(self.id_, self.title, self.type_)
|
||||
b = Chat(self.id_, self.title, self.type_)
|
||||
c = Chat(self.id_, "", "")
|
||||
d = Chat(0, self.title, self.type_)
|
||||
e = User(self.id_, "", False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
def test_link(self, chat):
|
||||
assert chat.link == f"https://t.me/{chat.username}"
|
||||
chat.username = None
|
||||
|
@ -234,7 +256,6 @@ class TestChat:
|
|||
|
||||
monkeypatch.setattr(chat.get_bot(), "send_chat_action", make_assertion)
|
||||
assert await chat.send_action(action=ChatAction.TYPING)
|
||||
assert await chat.send_action(action=ChatAction.TYPING)
|
||||
|
||||
async def test_leave(self, monkeypatch, chat):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
@ -1251,23 +1272,3 @@ class TestChat:
|
|||
):
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
chat.mention_markdown_v2()
|
||||
|
||||
def test_equality(self):
|
||||
a = Chat(self.id_, self.title, self.type_)
|
||||
b = Chat(self.id_, self.title, self.type_)
|
||||
c = Chat(self.id_, "", "")
|
||||
d = Chat(0, self.title, self.type_)
|
||||
e = User(self.id_, "", False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -21,7 +21,7 @@ import pytest
|
|||
from telegram import ChatAdministratorRights
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_admin_rights():
|
||||
return ChatAdministratorRights(
|
||||
can_change_info=True,
|
||||
|
@ -39,7 +39,7 @@ def chat_admin_rights():
|
|||
)
|
||||
|
||||
|
||||
class TestChatAdministratorRights:
|
||||
class TestChatAdministratorRightsWithoutRequest:
|
||||
def test_slot_behaviour(self, chat_admin_rights, mro_slots):
|
||||
inst = chat_admin_rights
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -24,27 +24,27 @@ from telegram import ChatInviteLink, User
|
|||
from telegram._utils.datetime import to_timestamp
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def creator():
|
||||
return User(1, "First name", False)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def invite_link(creator):
|
||||
return ChatInviteLink(
|
||||
TestChatInviteLink.link,
|
||||
TestChatInviteLinkBase.link,
|
||||
creator,
|
||||
TestChatInviteLink.creates_join_request,
|
||||
TestChatInviteLink.primary,
|
||||
TestChatInviteLink.revoked,
|
||||
expire_date=TestChatInviteLink.expire_date,
|
||||
member_limit=TestChatInviteLink.member_limit,
|
||||
name=TestChatInviteLink.name,
|
||||
pending_join_request_count=TestChatInviteLink.pending_join_request_count,
|
||||
TestChatInviteLinkBase.creates_join_request,
|
||||
TestChatInviteLinkBase.primary,
|
||||
TestChatInviteLinkBase.revoked,
|
||||
expire_date=TestChatInviteLinkBase.expire_date,
|
||||
member_limit=TestChatInviteLinkBase.member_limit,
|
||||
name=TestChatInviteLinkBase.name,
|
||||
pending_join_request_count=TestChatInviteLinkBase.pending_join_request_count,
|
||||
)
|
||||
|
||||
|
||||
class TestChatInviteLink:
|
||||
class TestChatInviteLinkBase:
|
||||
link = "thisialink"
|
||||
creates_join_request = False
|
||||
primary = True
|
||||
|
@ -54,6 +54,8 @@ class TestChatInviteLink:
|
|||
name = "LinkName"
|
||||
pending_join_request_count = 42
|
||||
|
||||
|
||||
class TestChatInviteLinkWithoutRequest(TestChatInviteLinkBase):
|
||||
def test_slot_behaviour(self, mro_slots, invite_link):
|
||||
for attr in invite_link.__slots__:
|
||||
assert getattr(invite_link, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -29,26 +29,26 @@ from tests.auxil.bot_method_checks import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def time():
|
||||
return datetime.datetime.now(tz=UTC)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_join_request(bot, time):
|
||||
cjr = ChatJoinRequest(
|
||||
chat=TestChatJoinRequest.chat,
|
||||
from_user=TestChatJoinRequest.from_user,
|
||||
chat=TestChatJoinRequestBase.chat,
|
||||
from_user=TestChatJoinRequestBase.from_user,
|
||||
date=time,
|
||||
bio=TestChatJoinRequest.bio,
|
||||
invite_link=TestChatJoinRequest.invite_link,
|
||||
user_chat_id=TestChatJoinRequest.from_user.id,
|
||||
bio=TestChatJoinRequestBase.bio,
|
||||
invite_link=TestChatJoinRequestBase.invite_link,
|
||||
user_chat_id=TestChatJoinRequestBase.from_user.id,
|
||||
)
|
||||
cjr.set_bot(bot)
|
||||
return cjr
|
||||
|
||||
|
||||
class TestChatJoinRequest:
|
||||
class TestChatJoinRequestBase:
|
||||
chat = Chat(1, Chat.SUPERGROUP)
|
||||
from_user = User(2, "first_name", False)
|
||||
bio = "bio"
|
||||
|
@ -61,6 +61,8 @@ class TestChatJoinRequest:
|
|||
is_primary=False,
|
||||
)
|
||||
|
||||
|
||||
class TestChatJoinRequestWithoutRequest(TestChatJoinRequestBase):
|
||||
def test_slot_behaviour(self, chat_join_request, mro_slots):
|
||||
inst = chat_join_request
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -22,15 +22,17 @@ import pytest
|
|||
from telegram import ChatLocation, Location, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def chat_location(bot):
|
||||
return ChatLocation(TestChatLocation.location, TestChatLocation.address)
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_location():
|
||||
return ChatLocation(TestChatLocationBase.location, TestChatLocationBase.address)
|
||||
|
||||
|
||||
class TestChatLocation:
|
||||
class TestChatLocationBase:
|
||||
location = Location(123, 456)
|
||||
address = "The Shire"
|
||||
|
||||
|
||||
class TestChatLocationWithoutRequest(TestChatLocationBase):
|
||||
def test_slot_behaviour(self, chat_location, mro_slots):
|
||||
inst = chat_location
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -187,7 +187,7 @@ def chat_member_type(request):
|
|||
],
|
||||
indirect=True,
|
||||
)
|
||||
class TestChatMemberTypes:
|
||||
class TestChatMemberTypesWithoutRequest:
|
||||
def test_slot_behaviour(self, chat_member_type, mro_slots):
|
||||
inst = chat_member_type
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -34,26 +34,26 @@ from telegram import (
|
|||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def user():
|
||||
return User(1, "First name", False)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat():
|
||||
return Chat(1, Chat.SUPERGROUP, "Chat")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def old_chat_member(user):
|
||||
return ChatMember(user, TestChatMemberUpdated.old_status)
|
||||
return ChatMember(user, TestChatMemberUpdatedBase.old_status)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def new_chat_member(user):
|
||||
return ChatMemberAdministrator(
|
||||
user,
|
||||
TestChatMemberUpdated.new_status,
|
||||
TestChatMemberUpdatedBase.new_status,
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
|
@ -66,25 +66,27 @@ def new_chat_member(user):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def time():
|
||||
return datetime.datetime.now(tz=UTC)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def invite_link(user):
|
||||
return ChatInviteLink("link", user, False, True, True)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_member_updated(user, chat, old_chat_member, new_chat_member, invite_link, time):
|
||||
return ChatMemberUpdated(chat, user, time, old_chat_member, new_chat_member, invite_link)
|
||||
|
||||
|
||||
class TestChatMemberUpdated:
|
||||
class TestChatMemberUpdatedBase:
|
||||
old_status = ChatMember.MEMBER
|
||||
new_status = ChatMember.ADMINISTRATOR
|
||||
|
||||
|
||||
class TestChatMemberUpdatedWithoutRequest(TestChatMemberUpdatedBase):
|
||||
def test_slot_behaviour(self, mro_slots, chat_member_updated):
|
||||
action = chat_member_updated
|
||||
for attr in action.__slots__:
|
||||
|
|
|
@ -22,7 +22,7 @@ import pytest
|
|||
from telegram import ChatPermissions, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_permissions():
|
||||
return ChatPermissions(
|
||||
can_send_messages=True,
|
||||
|
@ -43,7 +43,7 @@ def chat_permissions():
|
|||
)
|
||||
|
||||
|
||||
class TestChatPermissions:
|
||||
class TestChatPermissionsBase:
|
||||
can_send_messages = True
|
||||
can_send_media_messages = True
|
||||
can_send_polls = True
|
||||
|
@ -60,6 +60,8 @@ class TestChatPermissions:
|
|||
can_send_video_notes = False
|
||||
can_send_voice_notes = None
|
||||
|
||||
|
||||
class TestChatPermissionsWithoutRequest(TestChatPermissionsBase):
|
||||
def test_slot_behaviour(self, chat_permissions, mro_slots):
|
||||
inst = chat_permissions
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
@ -35,12 +36,11 @@ from tests.conftest import data_file, expect_bad_request
|
|||
|
||||
@pytest.fixture(scope="function")
|
||||
def chatphoto_file():
|
||||
f = data_file("telegram.jpg").open("rb")
|
||||
yield f
|
||||
f.close()
|
||||
with data_file("telegram.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture(scope="module")
|
||||
async def chat_photo(bot, super_group_id):
|
||||
async def func():
|
||||
return (await bot.get_chat(super_group_id, read_timeout=50)).photo
|
||||
|
@ -50,61 +50,20 @@ async def chat_photo(bot, super_group_id):
|
|||
)
|
||||
|
||||
|
||||
class TestChatPhoto:
|
||||
class TestChatPhotoBase:
|
||||
chatphoto_small_file_id = "smallCgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
chatphoto_big_file_id = "bigCgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
chatphoto_small_file_unique_id = "smalladc3145fd2e84d95b64d68eaa22aa33e"
|
||||
chatphoto_big_file_unique_id = "bigadc3145fd2e84d95b64d68eaa22aa33e"
|
||||
chatphoto_file_url = "https://python-telegram-bot.org/static/testfiles/telegram.jpg"
|
||||
|
||||
|
||||
class TestChatPhotoWithoutRequest(TestChatPhotoBase):
|
||||
def test_slot_behaviour(self, chat_photo, mro_slots):
|
||||
for attr in chat_photo.__slots__:
|
||||
assert getattr(chat_photo, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(chat_photo)) == len(set(mro_slots(chat_photo))), "duplicate slot"
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_all_args(
|
||||
self, bot, super_group_id, chatphoto_file, chat_photo, thumb_file
|
||||
):
|
||||
async def func():
|
||||
assert await bot.set_chat_photo(super_group_id, chatphoto_file)
|
||||
|
||||
await expect_bad_request(
|
||||
func, "Type of file mismatch", "Telegram did not accept the file."
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_get_and_download(self, bot, chat_photo):
|
||||
jpg_file = Path("telegram.jpg")
|
||||
if jpg_file.is_file():
|
||||
jpg_file.unlink()
|
||||
|
||||
new_file = await bot.get_file(chat_photo.small_file_id)
|
||||
|
||||
assert new_file.file_unique_id == chat_photo.small_file_unique_id
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
await new_file.download_to_drive(jpg_file)
|
||||
|
||||
assert jpg_file.is_file()
|
||||
|
||||
new_file = await bot.get_file(chat_photo.big_file_id)
|
||||
|
||||
assert new_file.file_unique_id == chat_photo.big_file_unique_id
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
await new_file.download_to_drive(jpg_file)
|
||||
|
||||
assert jpg_file.is_file()
|
||||
|
||||
async def test_send_with_chat_photo(self, monkeypatch, bot, super_group_id, chat_photo):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters["photo"] == chat_photo.to_dict()
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.set_chat_photo(photo=chat_photo, chat_id=super_group_id)
|
||||
assert message
|
||||
|
||||
def test_de_json(self, bot, chat_photo):
|
||||
json_dict = {
|
||||
"small_file_id": self.chatphoto_small_file_id,
|
||||
|
@ -128,46 +87,6 @@ class TestChatPhoto:
|
|||
assert chat_photo_dict["small_file_unique_id"] == chat_photo.small_file_unique_id
|
||||
assert chat_photo_dict["big_file_unique_id"] == chat_photo.big_file_unique_id
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file(self, bot, super_group_id):
|
||||
chatphoto_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id, photo=chatphoto_file)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file_id(self, bot, super_group_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id, photo="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, super_group_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id)
|
||||
|
||||
async def test_get_small_file_instance_method(self, monkeypatch, chat_photo):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == chat_photo.small_file_id
|
||||
|
||||
assert check_shortcut_signature(ChatPhoto.get_small_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(
|
||||
chat_photo.get_small_file, chat_photo.get_bot(), "get_file"
|
||||
)
|
||||
assert await check_defaults_handling(chat_photo.get_small_file, chat_photo.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat_photo.get_bot(), "get_file", make_assertion)
|
||||
assert await chat_photo.get_small_file()
|
||||
|
||||
async def test_get_big_file_instance_method(self, monkeypatch, chat_photo):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == chat_photo.big_file_id
|
||||
|
||||
assert check_shortcut_signature(ChatPhoto.get_big_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(chat_photo.get_big_file, chat_photo.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(chat_photo.get_big_file, chat_photo.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat_photo.get_bot(), "get_file", make_assertion)
|
||||
assert await chat_photo.get_big_file()
|
||||
|
||||
def test_equality(self):
|
||||
a = ChatPhoto(
|
||||
self.chatphoto_small_file_id,
|
||||
|
@ -199,3 +118,80 @@ class TestChatPhoto:
|
|||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_with_chat_photo(self, monkeypatch, bot, super_group_id, chat_photo):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters["photo"] == chat_photo.to_dict()
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.set_chat_photo(photo=chat_photo, chat_id=super_group_id)
|
||||
assert message
|
||||
|
||||
async def test_get_small_file_instance_method(self, monkeypatch, chat_photo):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == chat_photo.small_file_id
|
||||
|
||||
assert check_shortcut_signature(ChatPhoto.get_small_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(
|
||||
chat_photo.get_small_file, chat_photo.get_bot(), "get_file"
|
||||
)
|
||||
assert await check_defaults_handling(chat_photo.get_small_file, chat_photo.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat_photo.get_bot(), "get_file", make_assertion)
|
||||
assert await chat_photo.get_small_file()
|
||||
|
||||
async def test_get_big_file_instance_method(self, monkeypatch, chat_photo):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == chat_photo.big_file_id
|
||||
|
||||
assert check_shortcut_signature(ChatPhoto.get_big_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(chat_photo.get_big_file, chat_photo.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(chat_photo.get_big_file, chat_photo.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat_photo.get_bot(), "get_file", make_assertion)
|
||||
assert await chat_photo.get_big_file()
|
||||
|
||||
|
||||
class TestChatPhotoWithRequest:
|
||||
async def test_get_and_download(self, bot, chat_photo):
|
||||
jpg_file = Path("telegram.jpg")
|
||||
if jpg_file.is_file():
|
||||
jpg_file.unlink()
|
||||
|
||||
tasks = {bot.get_file(chat_photo.small_file_id), bot.get_file(chat_photo.big_file_id)}
|
||||
asserts = []
|
||||
|
||||
for task in asyncio.as_completed(tasks):
|
||||
file = await task
|
||||
if file.file_unique_id == chat_photo.small_file_unique_id:
|
||||
asserts.append("small")
|
||||
elif file.file_unique_id == chat_photo.big_file_unique_id:
|
||||
asserts.append("big")
|
||||
assert file.file_path.startswith("https://")
|
||||
|
||||
await file.download_to_drive(jpg_file)
|
||||
assert jpg_file.is_file()
|
||||
|
||||
assert "small" in asserts and "big" in asserts
|
||||
|
||||
async def test_send_all_args(self, bot, super_group_id, chatphoto_file):
|
||||
async def func():
|
||||
assert await bot.set_chat_photo(super_group_id, chatphoto_file)
|
||||
|
||||
await expect_bad_request(
|
||||
func, "Type of file mismatch", "Telegram did not accept the file."
|
||||
)
|
||||
|
||||
async def test_error_send_empty_file(self, bot, super_group_id):
|
||||
chatphoto_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id, photo=chatphoto_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, super_group_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id, photo="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, super_group_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id)
|
||||
|
|
|
@ -22,22 +22,26 @@ import pytest
|
|||
from telegram import ChosenInlineResult, Location, User, Voice
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def user():
|
||||
user = User(1, "First name", False)
|
||||
user._unfreeze()
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def chosen_inline_result(user):
|
||||
return ChosenInlineResult(TestChosenInlineResult.result_id, user, TestChosenInlineResult.query)
|
||||
return ChosenInlineResult(
|
||||
TestChosenInlineResultBase.result_id, user, TestChosenInlineResultBase.query
|
||||
)
|
||||
|
||||
|
||||
class TestChosenInlineResult:
|
||||
class TestChosenInlineResultBase:
|
||||
result_id = "result id"
|
||||
query = "query text"
|
||||
|
||||
|
||||
class TestChosenInlineResultWithoutRequest(TestChosenInlineResultBase):
|
||||
def test_slot_behaviour(self, chosen_inline_result, mro_slots):
|
||||
inst = chosen_inline_result
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import constants
|
||||
from telegram._utils.enum import IntEnum, StringEnum
|
||||
from telegram.error import BadRequest
|
||||
|
@ -36,7 +35,7 @@ class IntEnumTest(IntEnum):
|
|||
BAR = 2
|
||||
|
||||
|
||||
class TestConstants:
|
||||
class TestConstantsWithoutRequest:
|
||||
"""Also test _utils.enum.StringEnum on the fly because tg.constants is currently the only
|
||||
place where that class is used."""
|
||||
|
||||
|
@ -110,30 +109,6 @@ class TestConstants:
|
|||
|
||||
assert hash(IntEnumTest.FOO) == hash(1)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_max_message_length(self, bot, chat_id):
|
||||
await bot.send_message(chat_id=chat_id, text="a" * constants.MessageLimit.MAX_TEXT_LENGTH)
|
||||
|
||||
with pytest.raises(
|
||||
BadRequest,
|
||||
match="Message is too long",
|
||||
):
|
||||
await bot.send_message(
|
||||
chat_id=chat_id, text="a" * (constants.MessageLimit.MAX_TEXT_LENGTH + 1)
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_max_caption_length(self, bot, chat_id):
|
||||
good_caption = "a" * constants.MessageLimit.CAPTION_LENGTH
|
||||
with data_file("telegram.png").open("rb") as f:
|
||||
good_msg = await bot.send_photo(photo=f, caption=good_caption, chat_id=chat_id)
|
||||
assert good_msg.caption == good_caption
|
||||
|
||||
bad_caption = good_caption + "Z"
|
||||
match = "Message caption is too long"
|
||||
with pytest.raises(BadRequest, match=match), data_file("telegram.png").open("rb") as f:
|
||||
await bot.send_photo(photo=f, caption=bad_caption, chat_id=chat_id)
|
||||
|
||||
def test_bot_api_version_and_info(self):
|
||||
assert constants.BOT_API_VERSION == str(constants.BOT_API_VERSION_INFO)
|
||||
assert constants.BOT_API_VERSION_INFO == tuple(
|
||||
|
@ -151,3 +126,29 @@ class TestConstants:
|
|||
assert vi < (vi[0] + 1, vi[1] + 1)
|
||||
assert vi[0] == vi.major
|
||||
assert vi[1] == vi.minor
|
||||
|
||||
|
||||
class TestConstantsWithRequest:
|
||||
async def test_max_message_length(self, bot, chat_id):
|
||||
good_text = "a" * constants.MessageLimit.MAX_TEXT_LENGTH
|
||||
bad_text = good_text + "Z"
|
||||
tasks = asyncio.gather(
|
||||
bot.send_message(chat_id, text=good_text),
|
||||
bot.send_message(chat_id, text=bad_text),
|
||||
return_exceptions=True,
|
||||
)
|
||||
good_msg, bad_msg = await tasks
|
||||
assert good_msg.text == good_text
|
||||
assert isinstance(bad_msg, BadRequest) and "Message is too long" in str(bad_msg)
|
||||
|
||||
async def test_max_caption_length(self, bot, chat_id):
|
||||
good_caption = "a" * constants.MessageLimit.CAPTION_LENGTH
|
||||
bad_caption = good_caption + "Z"
|
||||
tasks = asyncio.gather(
|
||||
bot.send_photo(chat_id, data_file("telegram.png").read_bytes(), good_caption),
|
||||
bot.send_photo(chat_id, data_file("telegram.png").read_bytes(), bad_caption),
|
||||
return_exceptions=True,
|
||||
)
|
||||
good_msg, bad_msg = await tasks
|
||||
assert good_msg.caption == good_caption
|
||||
assert isinstance(bad_msg, BadRequest) and "Message caption is too long" in str(bad_msg)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Contact, Voice
|
||||
|
@ -24,22 +26,24 @@ from telegram.error import BadRequest
|
|||
from telegram.request import RequestData
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def contact():
|
||||
return Contact(
|
||||
TestContact.phone_number,
|
||||
TestContact.first_name,
|
||||
TestContact.last_name,
|
||||
TestContact.user_id,
|
||||
TestContactBase.phone_number,
|
||||
TestContactBase.first_name,
|
||||
TestContactBase.last_name,
|
||||
TestContactBase.user_id,
|
||||
)
|
||||
|
||||
|
||||
class TestContact:
|
||||
class TestContactBase:
|
||||
phone_number = "+11234567890"
|
||||
first_name = "Leandro"
|
||||
last_name = "Toledo"
|
||||
user_id = 23
|
||||
|
||||
|
||||
class TestContactWithoutRequest(TestContactBase):
|
||||
def test_slot_behaviour(self, contact, mro_slots):
|
||||
for attr in contact.__slots__:
|
||||
assert getattr(contact, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -68,6 +72,48 @@ class TestContact:
|
|||
assert contact.last_name == self.last_name
|
||||
assert contact.user_id == self.user_id
|
||||
|
||||
def test_to_dict(self, contact):
|
||||
contact_dict = contact.to_dict()
|
||||
|
||||
assert isinstance(contact_dict, dict)
|
||||
assert contact_dict["phone_number"] == contact.phone_number
|
||||
assert contact_dict["first_name"] == contact.first_name
|
||||
assert contact_dict["last_name"] == contact.last_name
|
||||
assert contact_dict["user_id"] == contact.user_id
|
||||
|
||||
def test_equality(self):
|
||||
a = Contact(self.phone_number, self.first_name)
|
||||
b = Contact(self.phone_number, self.first_name)
|
||||
c = Contact(self.phone_number, "")
|
||||
d = Contact("", self.first_name)
|
||||
e = Voice("", "unique_id", 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_contact_without_required(self, bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either contact or phone_number and first_name"):
|
||||
await bot.send_contact(chat_id=chat_id)
|
||||
|
||||
async def test_send_mutually_exclusive(self, bot, chat_id, contact):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_contact(
|
||||
chat_id=chat_id,
|
||||
contact=contact,
|
||||
phone_number=contact.phone_number,
|
||||
first_name=contact.first_name,
|
||||
)
|
||||
|
||||
async def test_send_with_contact(self, monkeypatch, bot, chat_id, contact):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
|
@ -77,10 +123,10 @@ class TestContact:
|
|||
return phone and first and last
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.send_contact(contact=contact, chat_id=chat_id)
|
||||
assert message
|
||||
assert await bot.send_contact(contact=contact, chat_id=chat_id)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
|
||||
class TestContactWithRequest(TestContactBase):
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
|
@ -114,54 +160,12 @@ class TestContact:
|
|||
chat_id, contact=contact, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_contact_default_protect_content(self, chat_id, default_bot, contact):
|
||||
protected = await default_bot.send_contact(chat_id, contact=contact)
|
||||
assert protected.has_protected_content
|
||||
unprotected = await default_bot.send_contact(
|
||||
chat_id, contact=contact, protect_content=False
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_contact(chat_id, contact=contact),
|
||||
default_bot.send_contact(chat_id, contact=contact, protect_content=False),
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
async def test_send_contact_without_required(self, bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either contact or phone_number and first_name"):
|
||||
await bot.send_contact(chat_id=chat_id)
|
||||
|
||||
async def test_send_mutually_exclusive(self, bot, chat_id, contact):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_contact(
|
||||
chat_id=chat_id,
|
||||
contact=contact,
|
||||
phone_number=contact.phone_number,
|
||||
first_name=contact.first_name,
|
||||
)
|
||||
|
||||
def test_to_dict(self, contact):
|
||||
contact_dict = contact.to_dict()
|
||||
|
||||
assert isinstance(contact_dict, dict)
|
||||
assert contact_dict["phone_number"] == contact.phone_number
|
||||
assert contact_dict["first_name"] == contact.first_name
|
||||
assert contact_dict["last_name"] == contact.last_name
|
||||
assert contact_dict["user_id"] == contact.user_id
|
||||
|
||||
def test_equality(self):
|
||||
a = Contact(self.phone_number, self.first_name)
|
||||
b = Contact(self.phone_number, self.first_name)
|
||||
c = Contact(self.phone_number, "")
|
||||
d = Contact("", self.first_name)
|
||||
e = Voice("", "unique_id", 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -24,7 +24,6 @@ from warnings import filterwarnings
|
|||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Bot,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChosenInlineResult,
|
||||
|
@ -45,7 +44,6 @@ from telegram.ext import (
|
|||
CommandHandler,
|
||||
ConversationHandler,
|
||||
Defaults,
|
||||
ExtBot,
|
||||
InlineQueryHandler,
|
||||
JobQueue,
|
||||
MessageHandler,
|
||||
|
@ -59,7 +57,7 @@ from telegram.ext import (
|
|||
filters,
|
||||
)
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from tests.conftest import make_command_message
|
||||
from tests.conftest import DictBot, make_bot, make_command_message
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
|
@ -1255,7 +1253,7 @@ class TestConversationHandler:
|
|||
await app.process_update(Update(update_id=2, message=brew_message))
|
||||
assert handler.check_update(Update(0, message=pour_coffee_message))
|
||||
# assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
||||
await asyncio.sleep(0.7)
|
||||
await asyncio.sleep(0.75)
|
||||
assert handler.check_update(Update(0, message=start_message))
|
||||
# assert handler.conversations.get((self.group.id, user1.id)) is None
|
||||
|
||||
|
@ -2113,7 +2111,7 @@ class TestConversationHandler:
|
|||
@pytest.mark.parametrize("handler_block", [True, False, None])
|
||||
@pytest.mark.parametrize("ext_bot", [True, False], ids=["ExtBot", "Bot"])
|
||||
async def test_blocking_resolution_order(
|
||||
self, bot, default_block, ch_block, handler_block, ext_bot
|
||||
self, bot_info, default_block, ch_block, handler_block, ext_bot
|
||||
):
|
||||
event = asyncio.Event()
|
||||
|
||||
|
@ -2149,7 +2147,7 @@ class TestConversationHandler:
|
|||
fallbacks=[fallback],
|
||||
)
|
||||
|
||||
bot = ExtBot(bot.token, defaults=defaults) if ext_bot else Bot(bot.token)
|
||||
bot = make_bot(bot_info, defaults=defaults) if ext_bot else DictBot(bot_info["token"])
|
||||
app = ApplicationBuilder().bot(bot).build()
|
||||
app.add_handler(conv_handler)
|
||||
|
||||
|
@ -2160,7 +2158,7 @@ class TestConversationHandler:
|
|||
fallback_message.set_bot(bot)
|
||||
|
||||
# This loop makes sure that we test all of entry points, states handler & fallbacks
|
||||
for message in [start_message, start_message, fallback_message]:
|
||||
for message in [start_message, fallback_message]:
|
||||
process_update_task = asyncio.create_task(
|
||||
app.process_update(Update(0, message=message))
|
||||
)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import datetime as dtm
|
||||
import os
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
@ -26,18 +25,22 @@ from telegram._utils import datetime as tg_dtm
|
|||
from telegram.ext import Defaults
|
||||
|
||||
# sample time specification values categorised into absolute / delta / time-of-day
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
from tests.conftest import TEST_WITH_OPT_DEPS
|
||||
|
||||
ABSOLUTE_TIME_SPECS = [
|
||||
dtm.datetime.now(tz=dtm.timezone(dtm.timedelta(hours=-7))).replace(second=0, microsecond=0),
|
||||
dtm.datetime.utcnow().replace(second=0, microsecond=0),
|
||||
]
|
||||
# We do not parametrize tests with these variables, since there's a tiny chance that there is an
|
||||
# error while collecting the tests (happens when time goes from HH:59:00 -> HH+1:00:00) when we
|
||||
# run the test suite with multiple workers
|
||||
DELTA_TIME_SPECS = [dtm.timedelta(hours=3, seconds=42, milliseconds=2), 30, 7.5]
|
||||
TIME_OF_DAY_TIME_SPECS = [
|
||||
dtm.time(12, 42, tzinfo=dtm.timezone(dtm.timedelta(hours=-7))),
|
||||
dtm.time(12, 42),
|
||||
]
|
||||
RELATIVE_TIME_SPECS = DELTA_TIME_SPECS + TIME_OF_DAY_TIME_SPECS
|
||||
|
||||
ABSOLUTE_TIME_SPECS = [
|
||||
dtm.datetime.now(tz=dtm.timezone(dtm.timedelta(hours=-7))),
|
||||
dtm.datetime.utcnow(),
|
||||
]
|
||||
TIME_SPECS = ABSOLUTE_TIME_SPECS + RELATIVE_TIME_SPECS
|
||||
|
||||
"""
|
||||
|
@ -49,7 +52,6 @@ Because imports in pytest are intricate, we just run
|
|||
|
||||
with the TEST_WITH_OPT_DEPS=False environment variable in addition to the regular test suite.
|
||||
"""
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
|
||||
|
||||
class TestDatetime:
|
||||
|
@ -97,12 +99,15 @@ class TestDatetime:
|
|||
with pytest.raises(ValueError):
|
||||
tg_dtm.to_float_timestamp(dtm.datetime(2019, 11, 11), reference_timestamp=123)
|
||||
|
||||
@pytest.mark.parametrize("time_spec", DELTA_TIME_SPECS, ids=str)
|
||||
def test_to_float_timestamp_delta(self, time_spec):
|
||||
# see note on parametrization at the top of this file
|
||||
def test_to_float_timestamp_delta(self):
|
||||
"""Conversion from a 'delta' time specification to timestamp"""
|
||||
reference_t = 0
|
||||
delta = time_spec.total_seconds() if hasattr(time_spec, "total_seconds") else time_spec
|
||||
assert tg_dtm.to_float_timestamp(time_spec, reference_t) == reference_t + delta
|
||||
for i in DELTA_TIME_SPECS:
|
||||
delta = i.total_seconds() if hasattr(i, "total_seconds") else i
|
||||
assert (
|
||||
tg_dtm.to_float_timestamp(i, reference_t) == reference_t + delta
|
||||
), f"failed for {i}"
|
||||
|
||||
def test_to_float_timestamp_time_of_day(self):
|
||||
"""Conversion from time-of-day specification to timestamp"""
|
||||
|
@ -130,22 +135,24 @@ class TestDatetime:
|
|||
ref_t + (-utc_offset.total_seconds() % (24 * 60 * 60))
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("time_spec", RELATIVE_TIME_SPECS, ids=str)
|
||||
def test_to_float_timestamp_default_reference(self, time_spec):
|
||||
# see note on parametrization at the top of this file
|
||||
def test_to_float_timestamp_default_reference(self):
|
||||
"""The reference timestamp for relative time specifications should default to now"""
|
||||
now = time.time()
|
||||
assert tg_dtm.to_float_timestamp(time_spec) == pytest.approx(
|
||||
tg_dtm.to_float_timestamp(time_spec, reference_timestamp=now)
|
||||
)
|
||||
for i in RELATIVE_TIME_SPECS:
|
||||
now = time.time()
|
||||
assert tg_dtm.to_float_timestamp(i) == pytest.approx(
|
||||
tg_dtm.to_float_timestamp(i, reference_timestamp=now)
|
||||
), f"Failed for {i}"
|
||||
|
||||
def test_to_float_timestamp_error(self):
|
||||
with pytest.raises(TypeError, match="Defaults"):
|
||||
tg_dtm.to_float_timestamp(Defaults())
|
||||
|
||||
@pytest.mark.parametrize("time_spec", TIME_SPECS, ids=str)
|
||||
def test_to_timestamp(self, time_spec):
|
||||
# see note on parametrization at the top of this file
|
||||
def test_to_timestamp(self):
|
||||
# delegate tests to `to_float_timestamp`
|
||||
assert tg_dtm.to_timestamp(time_spec) == int(tg_dtm.to_float_timestamp(time_spec))
|
||||
for i in TIME_SPECS:
|
||||
assert tg_dtm.to_timestamp(i) == int(tg_dtm.to_float_timestamp(i)), f"Failed for {i}"
|
||||
|
||||
def test_to_timestamp_none(self):
|
||||
# this 'convenience' behaviour has been left left for backwards compatibility
|
||||
|
|
|
@ -19,15 +19,12 @@
|
|||
|
||||
import datetime as dtm
|
||||
import inspect
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import User
|
||||
from telegram.ext import Defaults
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
from tests.conftest import TEST_WITH_OPT_DEPS
|
||||
|
||||
|
||||
class TestDefault:
|
||||
|
|
|
@ -22,14 +22,16 @@ import pytest
|
|||
from telegram import BotCommand, Dice
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", params=Dice.ALL_EMOJI)
|
||||
@pytest.fixture(scope="module", params=Dice.ALL_EMOJI)
|
||||
def dice(request):
|
||||
return Dice(value=5, emoji=request.param)
|
||||
|
||||
|
||||
class TestDice:
|
||||
class TestDiceBase:
|
||||
value = 4
|
||||
|
||||
|
||||
class TestDiceWithoutRequest(TestDiceBase):
|
||||
def test_slot_behaviour(self, dice, mro_slots):
|
||||
for attr in dice.__slots__:
|
||||
assert getattr(dice, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
@ -35,18 +36,17 @@ from tests.conftest import data_file
|
|||
|
||||
@pytest.fixture(scope="function")
|
||||
def document_file():
|
||||
f = data_file("telegram.png").open("rb")
|
||||
yield f
|
||||
f.close()
|
||||
with data_file("telegram.png").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
async def document(bot, chat_id):
|
||||
with data_file("telegram.png").open("rb") as f:
|
||||
return (await bot.send_document(chat_id, document=f, read_timeout=50)).document
|
||||
|
||||
|
||||
class TestDocument:
|
||||
class TestDocumentBase:
|
||||
caption = "DocumentTest - *Caption*"
|
||||
document_file_url = "https://python-telegram-bot.org/static/testfiles/telegram.gif"
|
||||
file_size = 12948
|
||||
|
@ -58,6 +58,8 @@ class TestDocument:
|
|||
document_file_id = "5a3128a4d2a04750b5b58397f3b5e812"
|
||||
document_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
def test_slot_behaviour(self, document, mro_slots):
|
||||
for attr in document.__slots__:
|
||||
assert getattr(document, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -78,7 +80,141 @@ class TestDocument:
|
|||
assert document.thumb.width == self.thumb_width
|
||||
assert document.thumb.height == self.thumb_height
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
def test_de_json(self, bot, document):
|
||||
json_dict = {
|
||||
"file_id": self.document_file_id,
|
||||
"file_unique_id": self.document_file_unique_id,
|
||||
"thumb": document.thumb.to_dict(),
|
||||
"file_name": self.file_name,
|
||||
"mime_type": self.mime_type,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
test_document = Document.de_json(json_dict, bot)
|
||||
assert test_document.api_kwargs == {}
|
||||
|
||||
assert test_document.file_id == self.document_file_id
|
||||
assert test_document.file_unique_id == self.document_file_unique_id
|
||||
assert test_document.thumb == document.thumb
|
||||
assert test_document.file_name == self.file_name
|
||||
assert test_document.mime_type == self.mime_type
|
||||
assert test_document.file_size == self.file_size
|
||||
|
||||
def test_to_dict(self, document):
|
||||
document_dict = document.to_dict()
|
||||
|
||||
assert isinstance(document_dict, dict)
|
||||
assert document_dict["file_id"] == document.file_id
|
||||
assert document_dict["file_unique_id"] == document.file_unique_id
|
||||
assert document_dict["file_name"] == document.file_name
|
||||
assert document_dict["mime_type"] == document.mime_type
|
||||
assert document_dict["file_size"] == document.file_size
|
||||
|
||||
def test_equality(self, document):
|
||||
a = Document(document.file_id, document.file_unique_id)
|
||||
b = Document("", document.file_unique_id)
|
||||
d = Document("", "")
|
||||
e = Voice(document.file_id, document.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_document(chat_id=chat_id)
|
||||
|
||||
@pytest.mark.parametrize("disable_content_type_detection", [True, False, None])
|
||||
async def test_send_with_document(
|
||||
self, monkeypatch, bot, chat_id, document, disable_content_type_detection
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.parameters
|
||||
type_detection = (
|
||||
data.get("disable_content_type_detection") == disable_content_type_detection
|
||||
)
|
||||
return data["document"] == document.file_id and type_detection
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
message = await bot.send_document(
|
||||
document=document,
|
||||
chat_id=chat_id,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
)
|
||||
|
||||
assert message
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_document_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("document") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("document"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_document(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, document):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == document.file_id
|
||||
|
||||
assert check_shortcut_signature(Document.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(document.get_file, document.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(document.get_file, document.get_bot())
|
||||
|
||||
monkeypatch.setattr(document.get_bot(), "get_file", make_assertion)
|
||||
assert await document.get_file()
|
||||
|
||||
|
||||
class TestDocumentWithRequest(TestDocumentBase):
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with open(os.devnull, "rb") as f:
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document=f)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document="")
|
||||
|
||||
async def test_get_and_download(self, bot, document, chat_id):
|
||||
path = Path("telegram.png")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(document.file_id)
|
||||
|
||||
assert new_file.file_size == document.file_size
|
||||
assert new_file.file_unique_id == document.file_unique_id
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
await new_file.download_to_drive("telegram.png")
|
||||
|
||||
assert path.is_file()
|
||||
|
||||
async def test_send_resend(self, bot, chat_id, document):
|
||||
message = await bot.send_document(chat_id=chat_id, document=document.file_id)
|
||||
assert message.document == document
|
||||
|
||||
async def test_send_all_args(self, bot, chat_id, document_file, document, thumb_file):
|
||||
message = await bot.send_document(
|
||||
chat_id,
|
||||
|
@ -105,24 +241,6 @@ class TestDocument:
|
|||
assert message.document.thumb.height == self.thumb_height
|
||||
assert message.has_protected_content
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_get_and_download(self, bot, document):
|
||||
path = Path("telegram.png")
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
|
||||
new_file = await bot.get_file(document.file_id)
|
||||
|
||||
assert new_file.file_size == document.file_size
|
||||
assert new_file.file_id == document.file_id
|
||||
assert new_file.file_unique_id == document.file_unique_id
|
||||
assert new_file.file_path.startswith("https://")
|
||||
|
||||
await new_file.download_to_drive("telegram.png")
|
||||
|
||||
assert path.is_file()
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_url_gif_file(self, bot, chat_id):
|
||||
message = await bot.send_document(chat_id, self.document_file_url)
|
||||
|
||||
|
@ -138,34 +256,16 @@ class TestDocument:
|
|||
assert document.mime_type == "image/gif"
|
||||
assert document.file_size == 3878
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_resend(self, bot, chat_id, document):
|
||||
message = await bot.send_document(chat_id=chat_id, document=document.file_id)
|
||||
|
||||
assert message.document == document
|
||||
|
||||
@pytest.mark.parametrize("disable_content_type_detection", [True, False, None])
|
||||
async def test_send_with_document(
|
||||
self, monkeypatch, bot, chat_id, document, disable_content_type_detection
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.parameters
|
||||
type_detection = (
|
||||
data.get("disable_content_type_detection") == disable_content_type_detection
|
||||
)
|
||||
return data["document"] == document.file_id and type_detection
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
message = await bot.send_document(
|
||||
document=document,
|
||||
chat_id=chat_id,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_document_default_protect_content(self, chat_id, default_bot, document):
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_document(chat_id, document),
|
||||
default_bot.send_document(chat_id, document, protect_content=False),
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
assert message
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_document_caption_entities(self, bot, chat_id, document):
|
||||
test_string = "Italic Bold Code"
|
||||
entities = [
|
||||
|
@ -180,7 +280,6 @@ class TestDocument:
|
|||
assert message.caption == test_string
|
||||
assert message.caption_entities == tuple(entities)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_document_default_parse_mode_1(self, default_bot, chat_id, document):
|
||||
test_string = "Italic Bold Code"
|
||||
|
@ -190,7 +289,6 @@ class TestDocument:
|
|||
assert message.caption_markdown == test_markdown_string
|
||||
assert message.caption == test_string
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_document_default_parse_mode_2(self, default_bot, chat_id, document):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
@ -201,7 +299,6 @@ class TestDocument:
|
|||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||
async def test_send_document_default_parse_mode_3(self, default_bot, chat_id, document):
|
||||
test_markdown_string = "_Italic_ *Bold* `Code`"
|
||||
|
@ -212,7 +309,6 @@ class TestDocument:
|
|||
assert message.caption == test_markdown_string
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
|
@ -245,106 +341,3 @@ class TestDocument:
|
|||
await default_bot.send_document(
|
||||
chat_id, document, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_document_default_protect_content(self, chat_id, default_bot, document):
|
||||
protected = await default_bot.send_document(chat_id, document)
|
||||
assert protected.has_protected_content
|
||||
unprotected = await default_bot.send_document(chat_id, document, protect_content=False)
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_document_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
nonlocal test_flag
|
||||
if local_mode:
|
||||
test_flag = data.get("document") == expected and data.get("thumb") == expected
|
||||
else:
|
||||
test_flag = isinstance(data.get("document"), InputFile) and isinstance(
|
||||
data.get("thumb"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_document(chat_id, file, thumb=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
||||
def test_de_json(self, bot, document):
|
||||
json_dict = {
|
||||
"file_id": self.document_file_id,
|
||||
"file_unique_id": self.document_file_unique_id,
|
||||
"thumb": document.thumb.to_dict(),
|
||||
"file_name": self.file_name,
|
||||
"mime_type": self.mime_type,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
test_document = Document.de_json(json_dict, bot)
|
||||
assert test_document.api_kwargs == {}
|
||||
|
||||
assert test_document.file_id == self.document_file_id
|
||||
assert test_document.file_unique_id == self.document_file_unique_id
|
||||
assert test_document.thumb == document.thumb
|
||||
assert test_document.file_name == self.file_name
|
||||
assert test_document.mime_type == self.mime_type
|
||||
assert test_document.file_size == self.file_size
|
||||
|
||||
def test_to_dict(self, document):
|
||||
document_dict = document.to_dict()
|
||||
|
||||
assert isinstance(document_dict, dict)
|
||||
assert document_dict["file_id"] == document.file_id
|
||||
assert document_dict["file_unique_id"] == document.file_unique_id
|
||||
assert document_dict["file_name"] == document.file_name
|
||||
assert document_dict["mime_type"] == document.mime_type
|
||||
assert document_dict["file_size"] == document.file_size
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with open(os.devnull, "rb") as f:
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document=f)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document="")
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_document(chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, document):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["file_id"] == document.file_id
|
||||
|
||||
assert check_shortcut_signature(Document.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(document.get_file, document.get_bot(), "get_file")
|
||||
assert await check_defaults_handling(document.get_file, document.get_bot())
|
||||
|
||||
monkeypatch.setattr(document.get_bot(), "get_file", make_assertion)
|
||||
assert await document.get_file()
|
||||
|
||||
def test_equality(self, document):
|
||||
a = Document(document.file_id, document.file_unique_id)
|
||||
b = Document("", document.file_unique_id)
|
||||
d = Document("", "")
|
||||
e = Voice(document.file_id, document.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -22,20 +22,22 @@ import pytest
|
|||
from telegram import EncryptedCredentials, PassportElementError
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_credentials():
|
||||
return EncryptedCredentials(
|
||||
TestEncryptedCredentials.data,
|
||||
TestEncryptedCredentials.hash,
|
||||
TestEncryptedCredentials.secret,
|
||||
TestEncryptedCredentialsBase.data,
|
||||
TestEncryptedCredentialsBase.hash,
|
||||
TestEncryptedCredentialsBase.secret,
|
||||
)
|
||||
|
||||
|
||||
class TestEncryptedCredentials:
|
||||
class TestEncryptedCredentialsBase:
|
||||
data = "data"
|
||||
hash = "hash"
|
||||
secret = "secret"
|
||||
|
||||
|
||||
class TestEncryptedCredentialsWithoutRequest(TestEncryptedCredentialsBase):
|
||||
def test_slot_behaviour(self, encrypted_credentials, mro_slots):
|
||||
inst = encrypted_credentials
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -22,22 +22,22 @@ import pytest
|
|||
from telegram import EncryptedPassportElement, PassportElementError, PassportFile
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_passport_element():
|
||||
return EncryptedPassportElement(
|
||||
TestEncryptedPassportElement.type_,
|
||||
TestEncryptedPassportElementBase.type_,
|
||||
"this is a hash",
|
||||
data=TestEncryptedPassportElement.data,
|
||||
phone_number=TestEncryptedPassportElement.phone_number,
|
||||
email=TestEncryptedPassportElement.email,
|
||||
files=TestEncryptedPassportElement.files,
|
||||
front_side=TestEncryptedPassportElement.front_side,
|
||||
reverse_side=TestEncryptedPassportElement.reverse_side,
|
||||
selfie=TestEncryptedPassportElement.selfie,
|
||||
data=TestEncryptedPassportElementBase.data,
|
||||
phone_number=TestEncryptedPassportElementBase.phone_number,
|
||||
email=TestEncryptedPassportElementBase.email,
|
||||
files=TestEncryptedPassportElementBase.files,
|
||||
front_side=TestEncryptedPassportElementBase.front_side,
|
||||
reverse_side=TestEncryptedPassportElementBase.reverse_side,
|
||||
selfie=TestEncryptedPassportElementBase.selfie,
|
||||
)
|
||||
|
||||
|
||||
class TestEncryptedPassportElement:
|
||||
class TestEncryptedPassportElementBase:
|
||||
type_ = "type"
|
||||
hash = "this is a hash"
|
||||
data = "data"
|
||||
|
@ -48,6 +48,8 @@ class TestEncryptedPassportElement:
|
|||
reverse_side = PassportFile("file_id", 50, 0, 25)
|
||||
selfie = PassportFile("file_id", 50, 0, 25)
|
||||
|
||||
|
||||
class TestEncryptedPassportElementWithoutRequest(TestEncryptedPassportElementBase):
|
||||
def test_slot_behaviour(self, encrypted_passport_element, mro_slots):
|
||||
inst = encrypted_passport_element
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -27,20 +27,20 @@ from telegram.error import TelegramError
|
|||
from tests.conftest import data_file
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def file(bot):
|
||||
file = File(
|
||||
TestFile.file_id,
|
||||
TestFile.file_unique_id,
|
||||
file_path=TestFile.file_path,
|
||||
file_size=TestFile.file_size,
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
file_path=TestFileBase.file_path,
|
||||
file_size=TestFileBase.file_size,
|
||||
)
|
||||
file.set_bot(bot)
|
||||
file._unfreeze()
|
||||
return file
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_file(bot):
|
||||
# check https://github.com/python-telegram-bot/python-telegram-bot/wiki/\
|
||||
# PTB-test-writing-knowledge-base#how-to-generate-encrypted-passport-files
|
||||
|
@ -49,13 +49,18 @@ def encrypted_file(bot):
|
|||
"Oq3G4sX+bKZthoyms1YlPqvWou9esb+z0Bi/KqQUG8s=",
|
||||
"Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=",
|
||||
)
|
||||
ef = File(TestFile.file_id, TestFile.file_unique_id, TestFile.file_size, TestFile.file_path)
|
||||
ef = File(
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
TestFileBase.file_size,
|
||||
TestFileBase.file_path,
|
||||
)
|
||||
ef.set_bot(bot)
|
||||
ef.set_credentials(fc)
|
||||
return ef
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_local_file(bot):
|
||||
# check encrypted_file() for the source of the fc values
|
||||
fc = FileCredentials(
|
||||
|
@ -63,9 +68,9 @@ def encrypted_local_file(bot):
|
|||
"Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=",
|
||||
)
|
||||
ef = File(
|
||||
TestFile.file_id,
|
||||
TestFile.file_unique_id,
|
||||
TestFile.file_size,
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
TestFileBase.file_size,
|
||||
file_path=str(data_file("image_encrypted.jpg")),
|
||||
)
|
||||
ef.set_bot(bot)
|
||||
|
@ -73,19 +78,19 @@ def encrypted_local_file(bot):
|
|||
return ef
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def local_file(bot):
|
||||
file = File(
|
||||
TestFile.file_id,
|
||||
TestFile.file_unique_id,
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
file_path=str(data_file("local_file.txt")),
|
||||
file_size=TestFile.file_size,
|
||||
file_size=TestFileBase.file_size,
|
||||
)
|
||||
file.set_bot(bot)
|
||||
return file
|
||||
|
||||
|
||||
class TestFile:
|
||||
class TestFileBase:
|
||||
file_id = "NOTVALIDDOESNOTMATTER"
|
||||
file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
file_path = (
|
||||
|
@ -94,6 +99,8 @@ class TestFile:
|
|||
file_size = 28232
|
||||
file_content = "Saint-Saëns".encode() # Intentionally contains unicode chars.
|
||||
|
||||
|
||||
class TestFileWithoutRequest(TestFileBase):
|
||||
def test_slot_behaviour(self, file, mro_slots):
|
||||
for attr in file.__slots__:
|
||||
assert getattr(file, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -123,10 +130,25 @@ class TestFile:
|
|||
assert file_dict["file_path"] == file.file_path
|
||||
assert file_dict["file_size"] == file.file_size
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_error_get_empty_file_id(self, bot):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.get_file(file_id="")
|
||||
def test_equality(self, bot):
|
||||
a = File(self.file_id, self.file_unique_id, bot)
|
||||
b = File("", self.file_unique_id, bot)
|
||||
c = File(self.file_id, self.file_unique_id, None)
|
||||
d = File("", "", bot)
|
||||
e = Voice(self.file_id, self.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_download(self, monkeypatch, file):
|
||||
async def test(*args, **kwargs):
|
||||
|
@ -140,9 +162,6 @@ class TestFile:
|
|||
finally:
|
||||
out_file.unlink()
|
||||
|
||||
async def test_download_local_file(self, local_file):
|
||||
assert await local_file.download_to_drive() == Path(local_file.file_path)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"]
|
||||
)
|
||||
|
@ -161,20 +180,6 @@ class TestFile:
|
|||
os.close(file_handle)
|
||||
custom_path.unlink()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"]
|
||||
)
|
||||
async def test_download_custom_path_local_file(self, local_file, custom_path_type):
|
||||
file_handle, custom_path = mkstemp()
|
||||
custom_path = Path(custom_path)
|
||||
try:
|
||||
out_file = await local_file.download_to_drive(custom_path_type(custom_path))
|
||||
assert out_file == custom_path
|
||||
assert out_file.read_bytes() == self.file_content
|
||||
finally:
|
||||
os.close(file_handle)
|
||||
custom_path.unlink()
|
||||
|
||||
async def test_download_no_filename(self, monkeypatch, file):
|
||||
async def test(*args, **kwargs):
|
||||
return self.file_content
|
||||
|
@ -200,12 +205,6 @@ class TestFile:
|
|||
custom_fobj.seek(0)
|
||||
assert custom_fobj.read() == self.file_content
|
||||
|
||||
async def test_download_file_obj_local_file(self, local_file):
|
||||
with TemporaryFile() as custom_fobj:
|
||||
await local_file.download_to_memory(out=custom_fobj)
|
||||
custom_fobj.seek(0)
|
||||
assert custom_fobj.read() == self.file_content
|
||||
|
||||
async def test_download_bytearray(self, monkeypatch, file):
|
||||
async def test(*args, **kwargs):
|
||||
return self.file_content
|
||||
|
@ -223,18 +222,6 @@ class TestFile:
|
|||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
async def test_download_bytearray_local_file(self, local_file):
|
||||
# Check that a download to a newly allocated bytearray works.
|
||||
buf = await local_file.download_as_bytearray()
|
||||
assert buf == bytearray(self.file_content)
|
||||
|
||||
# Check that a download to a given bytearray works (extends the bytearray).
|
||||
buf2 = buf[:]
|
||||
buf3 = await local_file.download_as_bytearray(buf=buf2)
|
||||
assert buf3 is buf2
|
||||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
async def test_download_encrypted(self, monkeypatch, bot, encrypted_file):
|
||||
async def test(*args, **kwargs):
|
||||
return data_file("image_encrypted.jpg").read_bytes()
|
||||
|
@ -257,29 +244,6 @@ class TestFile:
|
|||
custom_fobj.seek(0)
|
||||
assert custom_fobj.read() == data_file("image_decrypted.jpg").read_bytes()
|
||||
|
||||
async def test_download_local_file_encrypted(self, encrypted_local_file):
|
||||
out_file = await encrypted_local_file.download_to_drive()
|
||||
try:
|
||||
assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes()
|
||||
finally:
|
||||
out_file.unlink()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"]
|
||||
)
|
||||
async def test_download_custom_path_local_file_encrypted(
|
||||
self, encrypted_local_file, custom_path_type
|
||||
):
|
||||
file_handle, custom_path = mkstemp()
|
||||
custom_path = Path(custom_path)
|
||||
try:
|
||||
out_file = await encrypted_local_file.download_to_drive(custom_path_type(custom_path))
|
||||
assert out_file == custom_path
|
||||
assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes()
|
||||
finally:
|
||||
os.close(file_handle)
|
||||
custom_path.unlink()
|
||||
|
||||
async def test_download_file_obj_local_file_encrypted(self, monkeypatch, encrypted_local_file):
|
||||
async def test(*args, **kwargs):
|
||||
return data_file("image_encrypted.jpg").read_bytes()
|
||||
|
@ -307,6 +271,70 @@ class TestFile:
|
|||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
|
||||
class TestFileWithRequest(TestFileBase):
|
||||
async def test_error_get_empty_file_id(self, bot):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.get_file(file_id="")
|
||||
|
||||
async def test_download_local_file(self, local_file):
|
||||
assert await local_file.download_to_drive() == Path(local_file.file_path)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"]
|
||||
)
|
||||
async def test_download_custom_path_local_file(self, local_file, custom_path_type):
|
||||
file_handle, custom_path = mkstemp()
|
||||
custom_path = Path(custom_path)
|
||||
try:
|
||||
out_file = await local_file.download_to_drive(custom_path_type(custom_path))
|
||||
assert out_file == custom_path
|
||||
assert out_file.read_bytes() == self.file_content
|
||||
finally:
|
||||
os.close(file_handle)
|
||||
custom_path.unlink()
|
||||
|
||||
async def test_download_file_obj_local_file(self, local_file):
|
||||
with TemporaryFile() as custom_fobj:
|
||||
await local_file.download_to_memory(out=custom_fobj)
|
||||
custom_fobj.seek(0)
|
||||
assert custom_fobj.read() == self.file_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"]
|
||||
)
|
||||
async def test_download_custom_path_local_file_encrypted(
|
||||
self, encrypted_local_file, custom_path_type
|
||||
):
|
||||
file_handle, custom_path = mkstemp()
|
||||
custom_path = Path(custom_path)
|
||||
try:
|
||||
out_file = await encrypted_local_file.download_to_drive(custom_path_type(custom_path))
|
||||
assert out_file == custom_path
|
||||
assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes()
|
||||
finally:
|
||||
os.close(file_handle)
|
||||
custom_path.unlink()
|
||||
|
||||
async def test_download_local_file_encrypted(self, encrypted_local_file):
|
||||
out_file = await encrypted_local_file.download_to_drive()
|
||||
try:
|
||||
assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes()
|
||||
finally:
|
||||
out_file.unlink()
|
||||
|
||||
async def test_download_bytearray_local_file(self, local_file):
|
||||
# Check that a download to a newly allocated bytearray works.
|
||||
buf = await local_file.download_as_bytearray()
|
||||
assert buf == bytearray(self.file_content)
|
||||
|
||||
# Check that a download to a given bytearray works (extends the bytearray).
|
||||
buf2 = buf[:]
|
||||
buf3 = await local_file.download_as_bytearray(buf=buf2)
|
||||
assert buf3 is buf2
|
||||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
async def test_download_bytearray_local_file_encrypted(self, encrypted_local_file):
|
||||
# Check that a download to a newly allocated bytearray works.
|
||||
buf = await encrypted_local_file.download_as_bytearray()
|
||||
|
@ -318,23 +346,3 @@ class TestFile:
|
|||
assert buf3 is buf2
|
||||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
def test_equality(self, bot):
|
||||
a = File(self.file_id, self.file_unique_id, bot)
|
||||
b = File("", self.file_unique_id, bot)
|
||||
c = File(self.file_id, self.file_unique_id, None)
|
||||
d = File("", "", bot)
|
||||
e = Voice(self.file_id, self.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -22,30 +22,23 @@ import pytest
|
|||
from telegram import ForceReply, ReplyKeyboardRemove
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def force_reply():
|
||||
return ForceReply(
|
||||
TestForceReply.selective,
|
||||
TestForceReply.input_field_placeholder,
|
||||
)
|
||||
return ForceReply(TestForceReplyBase.selective, TestForceReplyBase.input_field_placeholder)
|
||||
|
||||
|
||||
class TestForceReply:
|
||||
class TestForceReplyBase:
|
||||
force_reply = True
|
||||
selective = True
|
||||
input_field_placeholder = "force replies can be annoying if not used properly"
|
||||
|
||||
|
||||
class TestForceReplyWithoutRequest(TestForceReplyBase):
|
||||
def test_slot_behaviour(self, force_reply, mro_slots):
|
||||
for attr in force_reply.__slots__:
|
||||
assert getattr(force_reply, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(force_reply)) == len(set(mro_slots(force_reply))), "duplicate slot"
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_message_with_force_reply(self, bot, chat_id, force_reply):
|
||||
message = await bot.send_message(chat_id, "text", reply_markup=force_reply)
|
||||
|
||||
assert message.text == "text"
|
||||
|
||||
def test_expected(self, force_reply):
|
||||
assert force_reply.force_reply == self.force_reply
|
||||
assert force_reply.selective == self.selective
|
||||
|
@ -73,3 +66,9 @@ class TestForceReply:
|
|||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
|
||||
class TestForceReplyWithRequest(TestForceReplyBase):
|
||||
async def test_send_message_with_force_reply(self, bot, chat_id, force_reply):
|
||||
message = await bot.send_message(chat_id, "text", reply_markup=force_reply)
|
||||
assert message.text == "text"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
@ -44,7 +45,7 @@ async def emoji_id(bot):
|
|||
return first_sticker.custom_emoji_id
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture(scope="module")
|
||||
async def forum_topic_object(forum_group_id, emoji_id):
|
||||
return ForumTopic(
|
||||
message_thread_id=forum_group_id,
|
||||
|
@ -54,7 +55,7 @@ async def forum_topic_object(forum_group_id, emoji_id):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture(scope="function")
|
||||
async def real_topic(bot, emoji_id, forum_group_id):
|
||||
result = await bot.create_forum_topic(
|
||||
chat_id=forum_group_id,
|
||||
|
@ -71,13 +72,12 @@ async def real_topic(bot, emoji_id, forum_group_id):
|
|||
assert result is True, "Topic was not deleted"
|
||||
|
||||
|
||||
class TestForumTopic:
|
||||
class TestForumTopicWithoutRequest:
|
||||
def test_slot_behaviour(self, mro_slots, forum_topic_object):
|
||||
for attr in forum_topic_object.__slots__:
|
||||
assert getattr(forum_topic_object, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(forum_topic_object)) == len(
|
||||
set(mro_slots(forum_topic_object))
|
||||
), "duplicate slot"
|
||||
inst = forum_topic_object
|
||||
for attr in inst.__slots__:
|
||||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
async def test_expected_values(self, emoji_id, forum_group_id, forum_topic_object):
|
||||
assert forum_topic_object.message_thread_id == forum_group_id
|
||||
|
@ -152,8 +152,7 @@ class TestForumTopic:
|
|||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
class TestForumMethods:
|
||||
class TestForumMethodsWithRequest:
|
||||
async def test_create_forum_topic(self, real_topic):
|
||||
result = real_topic
|
||||
assert isinstance(result, ForumTopic)
|
||||
|
@ -237,22 +236,20 @@ class TestForumMethods:
|
|||
|
||||
async def test_unpin_all_forum_topic_messages(self, bot, forum_group_id, real_topic):
|
||||
message_thread_id = real_topic.message_thread_id
|
||||
pin_msg_tasks = set()
|
||||
|
||||
msgs = [
|
||||
await (
|
||||
await bot.send_message(
|
||||
chat_id=forum_group_id, text=TEST_MSG_TEXT, message_thread_id=message_thread_id
|
||||
)
|
||||
).pin()
|
||||
awaitables = {
|
||||
bot.send_message(forum_group_id, TEST_MSG_TEXT, message_thread_id=message_thread_id)
|
||||
for _ in range(2)
|
||||
]
|
||||
}
|
||||
for coro in asyncio.as_completed(awaitables):
|
||||
msg = await coro
|
||||
pin_msg_tasks.add(asyncio.create_task(msg.pin()))
|
||||
|
||||
assert all(msgs) is True, "Message(s) were not pinned"
|
||||
assert all([await task for task in pin_msg_tasks]) is True, "Message(s) were not pinned"
|
||||
|
||||
# We need 2 or more pinned msgs for this to work, else we get Chat_not_modified error
|
||||
result = await bot.unpin_all_forum_topic_messages(
|
||||
chat_id=forum_group_id, message_thread_id=message_thread_id
|
||||
)
|
||||
result = await bot.unpin_all_forum_topic_messages(forum_group_id, message_thread_id)
|
||||
assert result is True, "Failed to unpin all the messages in forum topic"
|
||||
|
||||
async def test_edit_general_forum_topic(self, bot, forum_group_id):
|
||||
|
@ -304,12 +301,12 @@ class TestForumMethods:
|
|||
assert result is True, "Failed to reopen general forum topic"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture(scope="module")
|
||||
def topic_created():
|
||||
return ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=TEST_TOPIC_ICON_COLOR)
|
||||
|
||||
|
||||
class TestForumTopicCreated:
|
||||
class TestForumTopicCreatedWithoutRequest:
|
||||
def test_slot_behaviour(self, topic_created, mro_slots):
|
||||
for attr in topic_created.__slots__:
|
||||
assert getattr(topic_created, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -358,7 +355,7 @@ class TestForumTopicCreated:
|
|||
assert hash(a) != hash(d)
|
||||
|
||||
|
||||
class TestForumTopicClosed:
|
||||
class TestForumTopicClosedWithoutRequest:
|
||||
def test_slot_behaviour(self, mro_slots):
|
||||
action = ForumTopicClosed()
|
||||
for attr in action.__slots__:
|
||||
|
@ -376,7 +373,7 @@ class TestForumTopicClosed:
|
|||
assert action_dict == {}
|
||||
|
||||
|
||||
class TestForumTopicReopened:
|
||||
class TestForumTopicReopenedWithoutRequest:
|
||||
def test_slot_behaviour(self, mro_slots):
|
||||
action = ForumTopicReopened()
|
||||
for attr in action.__slots__:
|
||||
|
|
|
@ -22,21 +22,21 @@ import pytest
|
|||
from telegram import Animation, Game, MessageEntity, PhotoSize
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture(scope="module")
|
||||
def game():
|
||||
game = Game(
|
||||
TestGame.title,
|
||||
TestGame.description,
|
||||
TestGame.photo,
|
||||
text=TestGame.text,
|
||||
text_entities=TestGame.text_entities,
|
||||
animation=TestGame.animation,
|
||||
TestGameBase.title,
|
||||
TestGameBase.description,
|
||||
TestGameBase.photo,
|
||||
text=TestGameBase.text,
|
||||
text_entities=TestGameBase.text_entities,
|
||||
animation=TestGameBase.animation,
|
||||
)
|
||||
game._unfreeze()
|
||||
return game
|
||||
|
||||
|
||||
class TestGame:
|
||||
class TestGameBase:
|
||||
title = "Python-telegram-bot Test Game"
|
||||
description = "description"
|
||||
photo = [PhotoSize("Blah", "ElseBlah", 640, 360, file_size=0)]
|
||||
|
@ -47,6 +47,8 @@ class TestGame:
|
|||
text_entities = [MessageEntity(13, 17, MessageEntity.URL)]
|
||||
animation = Animation("blah", "unique_id", 320, 180, 1)
|
||||
|
||||
|
||||
class TestGameWithoutRequest(TestGameBase):
|
||||
def test_slot_behaviour(self, game, mro_slots):
|
||||
for attr in game.__slots__:
|
||||
assert getattr(game, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -95,20 +97,6 @@ class TestGame:
|
|||
assert game_dict["text_entities"] == [game.text_entities[0].to_dict()]
|
||||
assert game_dict["animation"] == game.animation.to_dict()
|
||||
|
||||
def test_parse_entity(self, game):
|
||||
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||
game.text_entities = [entity]
|
||||
|
||||
assert game.parse_text_entity(entity) == "http://google.com"
|
||||
|
||||
def test_parse_entities(self, game):
|
||||
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||
entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1)
|
||||
game.text_entities = [entity_2, entity]
|
||||
|
||||
assert game.parse_text_entities(MessageEntity.URL) == {entity: "http://google.com"}
|
||||
assert game.parse_text_entities() == {entity: "http://google.com", entity_2: "h"}
|
||||
|
||||
def test_equality(self):
|
||||
a = Game("title", "description", [PhotoSize("Blah", "unique_id", 640, 360, file_size=0)])
|
||||
b = Game(
|
||||
|
@ -133,3 +121,17 @@ class TestGame:
|
|||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
def test_parse_entity(self, game):
|
||||
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||
game.text_entities = [entity]
|
||||
|
||||
assert game.parse_text_entity(entity) == "http://google.com"
|
||||
|
||||
def test_parse_entities(self, game):
|
||||
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||
entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1)
|
||||
game.text_entities = [entity_2, entity]
|
||||
|
||||
assert game.parse_text_entities(MessageEntity.URL) == {entity: "http://google.com"}
|
||||
assert game.parse_text_entities() == {entity: "http://google.com", entity_2: "h"}
|
||||
|
|
|
@ -22,25 +22,31 @@ import pytest
|
|||
from telegram import GameHighScore, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def game_highscore():
|
||||
return GameHighScore(
|
||||
TestGameHighScore.position, TestGameHighScore.user, TestGameHighScore.score
|
||||
TestGameHighScoreBase.position, TestGameHighScoreBase.user, TestGameHighScoreBase.score
|
||||
)
|
||||
|
||||
|
||||
class TestGameHighScore:
|
||||
class TestGameHighScoreBase:
|
||||
position = 12
|
||||
user = User(2, "test user", False)
|
||||
score = 42
|
||||
|
||||
|
||||
class TestGameHighScoreWithoutRequest(TestGameHighScoreBase):
|
||||
def test_slot_behaviour(self, game_highscore, mro_slots):
|
||||
for attr in game_highscore.__slots__:
|
||||
assert getattr(game_highscore, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(game_highscore)) == len(set(mro_slots(game_highscore))), "same slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {"position": self.position, "user": self.user.to_dict(), "score": self.score}
|
||||
json_dict = {
|
||||
"position": self.position,
|
||||
"user": self.user.to_dict(),
|
||||
"score": self.score,
|
||||
}
|
||||
highscore = GameHighScore.de_json(json_dict, bot)
|
||||
assert highscore.api_kwargs == {}
|
||||
|
||||
|
|
|
@ -22,22 +22,22 @@ import pytest
|
|||
from telegram import CallbackGame, InlineKeyboardButton, LoginUrl, WebAppInfo
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_keyboard_button():
|
||||
return InlineKeyboardButton(
|
||||
TestInlineKeyboardButton.text,
|
||||
url=TestInlineKeyboardButton.url,
|
||||
callback_data=TestInlineKeyboardButton.callback_data,
|
||||
switch_inline_query=TestInlineKeyboardButton.switch_inline_query,
|
||||
switch_inline_query_current_chat=TestInlineKeyboardButton.switch_inline_query_current_chat,
|
||||
callback_game=TestInlineKeyboardButton.callback_game,
|
||||
pay=TestInlineKeyboardButton.pay,
|
||||
login_url=TestInlineKeyboardButton.login_url,
|
||||
web_app=TestInlineKeyboardButton.web_app,
|
||||
TestInlineKeyboardButtonBase.text,
|
||||
url=TestInlineKeyboardButtonBase.url,
|
||||
callback_data=TestInlineKeyboardButtonBase.callback_data,
|
||||
switch_inline_query=TestInlineKeyboardButtonBase.switch_inline_query,
|
||||
switch_inline_query_current_chat=TestInlineKeyboardButtonBase.switch_inline_query_current_chat, # noqa: E501
|
||||
callback_game=TestInlineKeyboardButtonBase.callback_game,
|
||||
pay=TestInlineKeyboardButtonBase.pay,
|
||||
login_url=TestInlineKeyboardButtonBase.login_url,
|
||||
web_app=TestInlineKeyboardButtonBase.web_app,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineKeyboardButton:
|
||||
class TestInlineKeyboardButtonBase:
|
||||
text = "text"
|
||||
url = "url"
|
||||
callback_data = "callback data"
|
||||
|
@ -48,6 +48,8 @@ class TestInlineKeyboardButton:
|
|||
login_url = LoginUrl("http://google.com")
|
||||
web_app = WebAppInfo(url="https://example.com")
|
||||
|
||||
|
||||
class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
||||
def test_slot_behaviour(self, inline_keyboard_button, mro_slots):
|
||||
inst = inline_keyboard_button
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,12 +28,12 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_keyboard_markup():
|
||||
return InlineKeyboardMarkup(TestInlineKeyboardMarkup.inline_keyboard)
|
||||
return InlineKeyboardMarkup(TestInlineKeyboardMarkupBase.inline_keyboard)
|
||||
|
||||
|
||||
class TestInlineKeyboardMarkup:
|
||||
class TestInlineKeyboardMarkupBase:
|
||||
inline_keyboard = [
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
|
@ -41,104 +41,14 @@ class TestInlineKeyboardMarkup:
|
|||
]
|
||||
]
|
||||
|
||||
|
||||
class TestInlineKeyboardMarkupWithoutRequest(TestInlineKeyboardMarkupBase):
|
||||
def test_slot_behaviour(self, inline_keyboard_markup, mro_slots):
|
||||
inst = inline_keyboard_markup
|
||||
for attr in inst.__slots__:
|
||||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_message_with_inline_keyboard_markup(
|
||||
self, bot, chat_id, inline_keyboard_markup
|
||||
):
|
||||
message = await bot.send_message(
|
||||
chat_id, "Testing InlineKeyboardMarkup", reply_markup=inline_keyboard_markup
|
||||
)
|
||||
|
||||
assert message.text == "Testing InlineKeyboardMarkup"
|
||||
|
||||
def test_from_button(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_button(
|
||||
InlineKeyboardButton(text="button1", callback_data="data1")
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 1
|
||||
assert len(inline_keyboard_markup[0]) == 1
|
||||
|
||||
def test_from_row(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_row(
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
]
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 1
|
||||
assert len(inline_keyboard_markup[0]) == 2
|
||||
|
||||
def test_from_column(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_column(
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
]
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 2
|
||||
assert len(inline_keyboard_markup[0]) == 1
|
||||
assert len(inline_keyboard_markup[1]) == 1
|
||||
|
||||
def test_expected_values(self, inline_keyboard_markup):
|
||||
assert inline_keyboard_markup.inline_keyboard == tuple(
|
||||
tuple(row) for row in self.inline_keyboard
|
||||
)
|
||||
|
||||
def test_wrong_keyboard_inputs(self):
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton("b1", "1")], InlineKeyboardButton("b2", "2")]
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup("strings_are_not_allowed")
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(["strings_are_not_allowed_in_the_rows_either"])
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(InlineKeyboardButton("b1", "1"))
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup([[[InlineKeyboardButton("only_2d_array_is_allowed", "1")]]])
|
||||
|
||||
async def test_expected_values_empty_switch(self, inline_keyboard_markup, bot, monkeypatch):
|
||||
async def make_assertion(
|
||||
url,
|
||||
data,
|
||||
reply_to_message_id=None,
|
||||
disable_notification=None,
|
||||
reply_markup=None,
|
||||
timeout=None,
|
||||
**kwargs,
|
||||
):
|
||||
if reply_markup is not None:
|
||||
markups = (
|
||||
InlineKeyboardMarkup,
|
||||
ReplyKeyboardMarkup,
|
||||
ForceReply,
|
||||
ReplyKeyboardRemove,
|
||||
)
|
||||
if isinstance(reply_markup, markups):
|
||||
data["reply_markup"] = reply_markup.to_dict()
|
||||
else:
|
||||
data["reply_markup"] = reply_markup
|
||||
|
||||
assert bool("'switch_inline_query': ''" in str(data["reply_markup"]))
|
||||
assert bool("'switch_inline_query_current_chat': ''" in str(data["reply_markup"]))
|
||||
|
||||
inline_keyboard_markup.inline_keyboard[0][0]._unfreeze()
|
||||
inline_keyboard_markup.inline_keyboard[0][0].callback_data = None
|
||||
inline_keyboard_markup.inline_keyboard[0][0].switch_inline_query = ""
|
||||
inline_keyboard_markup.inline_keyboard[0][1]._unfreeze()
|
||||
inline_keyboard_markup.inline_keyboard[0][1].callback_data = None
|
||||
inline_keyboard_markup.inline_keyboard[0][1].switch_inline_query_current_chat = ""
|
||||
|
||||
monkeypatch.setattr(bot, "_send_message", make_assertion)
|
||||
await bot.send_message(123, "test", reply_markup=inline_keyboard_markup)
|
||||
|
||||
def test_to_dict(self, inline_keyboard_markup):
|
||||
inline_keyboard_markup_dict = inline_keyboard_markup.to_dict()
|
||||
|
||||
|
@ -233,3 +143,96 @@ class TestInlineKeyboardMarkup:
|
|||
|
||||
assert a != g
|
||||
assert hash(a) != hash(g)
|
||||
|
||||
def test_from_button(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_button(
|
||||
InlineKeyboardButton(text="button1", callback_data="data1")
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 1
|
||||
assert len(inline_keyboard_markup[0]) == 1
|
||||
|
||||
def test_from_row(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_row(
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
]
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 1
|
||||
assert len(inline_keyboard_markup[0]) == 2
|
||||
|
||||
def test_from_column(self):
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.from_column(
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
]
|
||||
).inline_keyboard
|
||||
assert len(inline_keyboard_markup) == 2
|
||||
assert len(inline_keyboard_markup[0]) == 1
|
||||
assert len(inline_keyboard_markup[1]) == 1
|
||||
|
||||
def test_expected_values(self, inline_keyboard_markup):
|
||||
assert inline_keyboard_markup.inline_keyboard == tuple(
|
||||
tuple(row) for row in self.inline_keyboard
|
||||
)
|
||||
|
||||
def test_wrong_keyboard_inputs(self):
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton("b1", "1")], InlineKeyboardButton("b2", "2")]
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup("strings_are_not_allowed")
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(["strings_are_not_allowed_in_the_rows_either"])
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup(InlineKeyboardButton("b1", "1"))
|
||||
with pytest.raises(ValueError):
|
||||
InlineKeyboardMarkup([[[InlineKeyboardButton("only_2d_array_is_allowed", "1")]]])
|
||||
|
||||
async def test_expected_values_empty_switch(self, inline_keyboard_markup, bot, monkeypatch):
|
||||
async def make_assertion(
|
||||
url,
|
||||
data,
|
||||
reply_to_message_id=None,
|
||||
disable_notification=None,
|
||||
reply_markup=None,
|
||||
timeout=None,
|
||||
**kwargs,
|
||||
):
|
||||
if reply_markup is not None:
|
||||
markups = (
|
||||
InlineKeyboardMarkup,
|
||||
ReplyKeyboardMarkup,
|
||||
ForceReply,
|
||||
ReplyKeyboardRemove,
|
||||
)
|
||||
if isinstance(reply_markup, markups):
|
||||
data["reply_markup"] = reply_markup.to_dict()
|
||||
else:
|
||||
data["reply_markup"] = reply_markup
|
||||
|
||||
assert bool("'switch_inline_query': ''" in str(data["reply_markup"]))
|
||||
assert bool("'switch_inline_query_current_chat': ''" in str(data["reply_markup"]))
|
||||
|
||||
inline_keyboard_markup.inline_keyboard[0][0]._unfreeze()
|
||||
inline_keyboard_markup.inline_keyboard[0][0].callback_data = None
|
||||
inline_keyboard_markup.inline_keyboard[0][0].switch_inline_query = ""
|
||||
inline_keyboard_markup.inline_keyboard[0][1]._unfreeze()
|
||||
inline_keyboard_markup.inline_keyboard[0][1].callback_data = None
|
||||
inline_keyboard_markup.inline_keyboard[0][1].switch_inline_query_current_chat = ""
|
||||
|
||||
monkeypatch.setattr(bot, "_send_message", make_assertion)
|
||||
await bot.send_message(123, "test", reply_markup=inline_keyboard_markup)
|
||||
|
||||
|
||||
class TestInlineKeyborardMarkupWithRequest(TestInlineKeyboardMarkupBase):
|
||||
async def test_send_message_with_inline_keyboard_markup(
|
||||
self, bot, chat_id, inline_keyboard_markup
|
||||
):
|
||||
message = await bot.send_message(
|
||||
chat_id, "Testing InlineKeyboardMarkup", reply_markup=inline_keyboard_markup
|
||||
)
|
||||
|
||||
assert message.text == "Testing InlineKeyboardMarkup"
|
||||
|
|
|
@ -27,26 +27,28 @@ from tests.auxil.bot_method_checks import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query(bot):
|
||||
ilq = InlineQuery(
|
||||
TestInlineQuery.id_,
|
||||
TestInlineQuery.from_user,
|
||||
TestInlineQuery.query,
|
||||
TestInlineQuery.offset,
|
||||
location=TestInlineQuery.location,
|
||||
TestInlineQueryBase.id_,
|
||||
TestInlineQueryBase.from_user,
|
||||
TestInlineQueryBase.query,
|
||||
TestInlineQueryBase.offset,
|
||||
location=TestInlineQueryBase.location,
|
||||
)
|
||||
ilq.set_bot(bot)
|
||||
return ilq
|
||||
|
||||
|
||||
class TestInlineQuery:
|
||||
class TestInlineQueryBase:
|
||||
id_ = 1234
|
||||
from_user = User(1, "First name", False)
|
||||
query = "query text"
|
||||
offset = "offset"
|
||||
location = Location(8.8, 53.1)
|
||||
|
||||
|
||||
class TestInlineQueryWithoutRequest(TestInlineQueryBase):
|
||||
def test_slot_behaviour(self, inline_query, mro_slots):
|
||||
for attr in inline_query.__slots__:
|
||||
assert getattr(inline_query, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -79,34 +81,6 @@ class TestInlineQuery:
|
|||
assert inline_query_dict["query"] == inline_query.query
|
||||
assert inline_query_dict["offset"] == inline_query.offset
|
||||
|
||||
async def test_answer(self, monkeypatch, inline_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["inline_query_id"] == inline_query.id
|
||||
|
||||
assert check_shortcut_signature(
|
||||
InlineQuery.answer, Bot.answer_inline_query, ["inline_query_id"], ["auto_pagination"]
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
inline_query.answer, inline_query.get_bot(), "answer_inline_query"
|
||||
)
|
||||
assert await check_defaults_handling(inline_query.answer, inline_query.get_bot())
|
||||
|
||||
monkeypatch.setattr(inline_query.get_bot(), "answer_inline_query", make_assertion)
|
||||
assert await inline_query.answer(results=[])
|
||||
|
||||
async def test_answer_error(self, inline_query):
|
||||
with pytest.raises(ValueError, match="mutually exclusive"):
|
||||
await inline_query.answer(results=[], auto_pagination=True, current_offset="foobar")
|
||||
|
||||
async def test_answer_auto_pagination(self, monkeypatch, inline_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
inline_query_id_matches = kwargs["inline_query_id"] == inline_query.id
|
||||
offset_matches = kwargs.get("current_offset") == inline_query.offset
|
||||
return offset_matches and inline_query_id_matches
|
||||
|
||||
monkeypatch.setattr(inline_query.get_bot(), "answer_inline_query", make_assertion)
|
||||
assert await inline_query.answer(results=[], auto_pagination=True)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQuery(self.id_, User(1, "", False), "", "")
|
||||
b = InlineQuery(self.id_, User(1, "", False), "", "")
|
||||
|
@ -126,3 +100,31 @@ class TestInlineQuery:
|
|||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_answer_error(self, inline_query):
|
||||
with pytest.raises(ValueError, match="mutually exclusive"):
|
||||
await inline_query.answer(results=[], auto_pagination=True, current_offset="foobar")
|
||||
|
||||
async def test_answer(self, monkeypatch, inline_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["inline_query_id"] == inline_query.id
|
||||
|
||||
assert check_shortcut_signature(
|
||||
InlineQuery.answer, Bot.answer_inline_query, ["inline_query_id"], ["auto_pagination"]
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
inline_query.answer, inline_query.get_bot(), "answer_inline_query"
|
||||
)
|
||||
assert await check_defaults_handling(inline_query.answer, inline_query.get_bot())
|
||||
|
||||
monkeypatch.setattr(inline_query.get_bot(), "answer_inline_query", make_assertion)
|
||||
assert await inline_query.answer(results=[])
|
||||
|
||||
async def test_answer_auto_pagination(self, monkeypatch, inline_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
inline_query_id_matches = kwargs["inline_query_id"] == inline_query.id
|
||||
offset_matches = kwargs.get("current_offset") == inline_query.offset
|
||||
return offset_matches and inline_query_id_matches
|
||||
|
||||
monkeypatch.setattr(inline_query.get_bot(), "answer_inline_query", make_assertion)
|
||||
assert await inline_query.answer(results=[], auto_pagination=True)
|
||||
|
|
|
@ -28,23 +28,23 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_article():
|
||||
return InlineQueryResultArticle(
|
||||
TestInlineQueryResultArticle.id_,
|
||||
TestInlineQueryResultArticle.title,
|
||||
input_message_content=TestInlineQueryResultArticle.input_message_content,
|
||||
reply_markup=TestInlineQueryResultArticle.reply_markup,
|
||||
url=TestInlineQueryResultArticle.url,
|
||||
hide_url=TestInlineQueryResultArticle.hide_url,
|
||||
description=TestInlineQueryResultArticle.description,
|
||||
thumb_url=TestInlineQueryResultArticle.thumb_url,
|
||||
thumb_height=TestInlineQueryResultArticle.thumb_height,
|
||||
thumb_width=TestInlineQueryResultArticle.thumb_width,
|
||||
TestInlineQueryResultArticleBase.id_,
|
||||
TestInlineQueryResultArticleBase.title,
|
||||
input_message_content=TestInlineQueryResultArticleBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultArticleBase.reply_markup,
|
||||
url=TestInlineQueryResultArticleBase.url,
|
||||
hide_url=TestInlineQueryResultArticleBase.hide_url,
|
||||
description=TestInlineQueryResultArticleBase.description,
|
||||
thumb_url=TestInlineQueryResultArticleBase.thumb_url,
|
||||
thumb_height=TestInlineQueryResultArticleBase.thumb_height,
|
||||
thumb_width=TestInlineQueryResultArticleBase.thumb_width,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultArticle:
|
||||
class TestInlineQueryResultArticleBase:
|
||||
id_ = "id"
|
||||
type_ = "article"
|
||||
title = "title"
|
||||
|
@ -57,6 +57,8 @@ class TestInlineQueryResultArticle:
|
|||
thumb_height = 10
|
||||
thumb_width = 15
|
||||
|
||||
|
||||
class TestInlineQueryResultArticleWithoutRequest(TestInlineQueryResultArticleBase):
|
||||
def test_slot_behaviour(self, inline_query_result_article, mro_slots, recwarn):
|
||||
inst = inline_query_result_article
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -29,23 +29,23 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_audio():
|
||||
return InlineQueryResultAudio(
|
||||
TestInlineQueryResultAudio.id_,
|
||||
TestInlineQueryResultAudio.audio_url,
|
||||
TestInlineQueryResultAudio.title,
|
||||
performer=TestInlineQueryResultAudio.performer,
|
||||
audio_duration=TestInlineQueryResultAudio.audio_duration,
|
||||
caption=TestInlineQueryResultAudio.caption,
|
||||
parse_mode=TestInlineQueryResultAudio.parse_mode,
|
||||
caption_entities=TestInlineQueryResultAudio.caption_entities,
|
||||
input_message_content=TestInlineQueryResultAudio.input_message_content,
|
||||
reply_markup=TestInlineQueryResultAudio.reply_markup,
|
||||
TestInlineQueryResultAudioBase.id_,
|
||||
TestInlineQueryResultAudioBase.audio_url,
|
||||
TestInlineQueryResultAudioBase.title,
|
||||
performer=TestInlineQueryResultAudioBase.performer,
|
||||
audio_duration=TestInlineQueryResultAudioBase.audio_duration,
|
||||
caption=TestInlineQueryResultAudioBase.caption,
|
||||
parse_mode=TestInlineQueryResultAudioBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultAudioBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultAudioBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultAudioBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultAudio:
|
||||
class TestInlineQueryResultAudioBase:
|
||||
id_ = "id"
|
||||
type_ = "audio"
|
||||
audio_url = "audio url"
|
||||
|
@ -58,6 +58,8 @@ class TestInlineQueryResultAudio:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultAudioWithoutRequest(TestInlineQueryResultAudioBase):
|
||||
def test_slot_behaviour(self, inline_query_result_audio, mro_slots):
|
||||
inst = inline_query_result_audio
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -29,20 +29,20 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_audio():
|
||||
return InlineQueryResultCachedAudio(
|
||||
TestInlineQueryResultCachedAudio.id_,
|
||||
TestInlineQueryResultCachedAudio.audio_file_id,
|
||||
caption=TestInlineQueryResultCachedAudio.caption,
|
||||
parse_mode=TestInlineQueryResultCachedAudio.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedAudio.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedAudio.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedAudio.reply_markup,
|
||||
TestInlineQueryResultCachedAudioBase.id_,
|
||||
TestInlineQueryResultCachedAudioBase.audio_file_id,
|
||||
caption=TestInlineQueryResultCachedAudioBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedAudioBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedAudioBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedAudioBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedAudioBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedAudio:
|
||||
class TestInlineQueryResultCachedAudioBase:
|
||||
id_ = "id"
|
||||
type_ = "audio"
|
||||
audio_file_id = "audio file id"
|
||||
|
@ -52,6 +52,8 @@ class TestInlineQueryResultCachedAudio:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedAudioWithoutRequest(TestInlineQueryResultCachedAudioBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_audio, mro_slots):
|
||||
inst = inline_query_result_cached_audio
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -29,22 +29,22 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_document():
|
||||
return InlineQueryResultCachedDocument(
|
||||
TestInlineQueryResultCachedDocument.id_,
|
||||
TestInlineQueryResultCachedDocument.title,
|
||||
TestInlineQueryResultCachedDocument.document_file_id,
|
||||
caption=TestInlineQueryResultCachedDocument.caption,
|
||||
parse_mode=TestInlineQueryResultCachedDocument.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedDocument.caption_entities,
|
||||
description=TestInlineQueryResultCachedDocument.description,
|
||||
input_message_content=TestInlineQueryResultCachedDocument.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedDocument.reply_markup,
|
||||
TestInlineQueryResultCachedDocumentBase.id_,
|
||||
TestInlineQueryResultCachedDocumentBase.title,
|
||||
TestInlineQueryResultCachedDocumentBase.document_file_id,
|
||||
caption=TestInlineQueryResultCachedDocumentBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedDocumentBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedDocumentBase.caption_entities,
|
||||
description=TestInlineQueryResultCachedDocumentBase.description,
|
||||
input_message_content=TestInlineQueryResultCachedDocumentBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedDocumentBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedDocument:
|
||||
class TestInlineQueryResultCachedDocumentBase:
|
||||
id_ = "id"
|
||||
type_ = "document"
|
||||
document_file_id = "document file id"
|
||||
|
@ -56,6 +56,8 @@ class TestInlineQueryResultCachedDocument:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedDocumentWithoutRequest(TestInlineQueryResultCachedDocumentBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_document, mro_slots):
|
||||
inst = inline_query_result_cached_document
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,21 +28,21 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_gif():
|
||||
return InlineQueryResultCachedGif(
|
||||
TestInlineQueryResultCachedGif.id_,
|
||||
TestInlineQueryResultCachedGif.gif_file_id,
|
||||
title=TestInlineQueryResultCachedGif.title,
|
||||
caption=TestInlineQueryResultCachedGif.caption,
|
||||
parse_mode=TestInlineQueryResultCachedGif.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedGif.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedGif.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedGif.reply_markup,
|
||||
TestInlineQueryResultCachedGifBase.id_,
|
||||
TestInlineQueryResultCachedGifBase.gif_file_id,
|
||||
title=TestInlineQueryResultCachedGifBase.title,
|
||||
caption=TestInlineQueryResultCachedGifBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedGifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedGifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedGifBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGif:
|
||||
class TestInlineQueryResultCachedGifBase:
|
||||
id_ = "id"
|
||||
type_ = "gif"
|
||||
gif_file_id = "gif file id"
|
||||
|
@ -53,6 +53,8 @@ class TestInlineQueryResultCachedGif:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGifWithoutRequest(TestInlineQueryResultCachedGifBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_gif, mro_slots):
|
||||
inst = inline_query_result_cached_gif
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,21 +28,21 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_mpeg4_gif():
|
||||
return InlineQueryResultCachedMpeg4Gif(
|
||||
TestInlineQueryResultCachedMpeg4Gif.id_,
|
||||
TestInlineQueryResultCachedMpeg4Gif.mpeg4_file_id,
|
||||
title=TestInlineQueryResultCachedMpeg4Gif.title,
|
||||
caption=TestInlineQueryResultCachedMpeg4Gif.caption,
|
||||
parse_mode=TestInlineQueryResultCachedMpeg4Gif.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedMpeg4Gif.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedMpeg4Gif.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedMpeg4Gif.reply_markup,
|
||||
TestInlineQueryResultCachedMpeg4GifBase.id_,
|
||||
TestInlineQueryResultCachedMpeg4GifBase.mpeg4_file_id,
|
||||
title=TestInlineQueryResultCachedMpeg4GifBase.title,
|
||||
caption=TestInlineQueryResultCachedMpeg4GifBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedMpeg4GifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedMpeg4GifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedMpeg4GifBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4Gif:
|
||||
class TestInlineQueryResultCachedMpeg4GifBase:
|
||||
id_ = "id"
|
||||
type_ = "mpeg4_gif"
|
||||
mpeg4_file_id = "mpeg4 file id"
|
||||
|
@ -53,6 +53,8 @@ class TestInlineQueryResultCachedMpeg4Gif:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4GifWithoutRequest(TestInlineQueryResultCachedMpeg4GifBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_mpeg4_gif, mro_slots):
|
||||
inst = inline_query_result_cached_mpeg4_gif
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,22 +28,22 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_photo():
|
||||
return InlineQueryResultCachedPhoto(
|
||||
TestInlineQueryResultCachedPhoto.id_,
|
||||
TestInlineQueryResultCachedPhoto.photo_file_id,
|
||||
title=TestInlineQueryResultCachedPhoto.title,
|
||||
description=TestInlineQueryResultCachedPhoto.description,
|
||||
caption=TestInlineQueryResultCachedPhoto.caption,
|
||||
parse_mode=TestInlineQueryResultCachedPhoto.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedPhoto.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedPhoto.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedPhoto.reply_markup,
|
||||
TestInlineQueryResultCachedPhotoBase.id_,
|
||||
TestInlineQueryResultCachedPhotoBase.photo_file_id,
|
||||
title=TestInlineQueryResultCachedPhotoBase.title,
|
||||
description=TestInlineQueryResultCachedPhotoBase.description,
|
||||
caption=TestInlineQueryResultCachedPhotoBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedPhotoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedPhotoBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhoto:
|
||||
class TestInlineQueryResultCachedPhotoBase:
|
||||
id_ = "id"
|
||||
type_ = "photo"
|
||||
photo_file_id = "photo file id"
|
||||
|
@ -55,6 +55,8 @@ class TestInlineQueryResultCachedPhoto:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhotoWithoutRequest(TestInlineQueryResultCachedPhotoBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_photo, mro_slots):
|
||||
inst = inline_query_result_cached_photo
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -27,23 +27,25 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_sticker():
|
||||
return InlineQueryResultCachedSticker(
|
||||
TestInlineQueryResultCachedSticker.id_,
|
||||
TestInlineQueryResultCachedSticker.sticker_file_id,
|
||||
input_message_content=TestInlineQueryResultCachedSticker.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedSticker.reply_markup,
|
||||
TestInlineQueryResultCachedStickerBase.id_,
|
||||
TestInlineQueryResultCachedStickerBase.sticker_file_id,
|
||||
input_message_content=TestInlineQueryResultCachedStickerBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedStickerBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedSticker:
|
||||
class TestInlineQueryResultCachedStickerBase:
|
||||
id_ = "id"
|
||||
type_ = "sticker"
|
||||
sticker_file_id = "sticker file id"
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedStickerWithoutRequest(TestInlineQueryResultCachedStickerBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_sticker, mro_slots):
|
||||
inst = inline_query_result_cached_sticker
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,22 +28,22 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_video():
|
||||
return InlineQueryResultCachedVideo(
|
||||
TestInlineQueryResultCachedVideo.id_,
|
||||
TestInlineQueryResultCachedVideo.video_file_id,
|
||||
TestInlineQueryResultCachedVideo.title,
|
||||
caption=TestInlineQueryResultCachedVideo.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVideo.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVideo.caption_entities,
|
||||
description=TestInlineQueryResultCachedVideo.description,
|
||||
input_message_content=TestInlineQueryResultCachedVideo.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVideo.reply_markup,
|
||||
TestInlineQueryResultCachedVideoBase.id_,
|
||||
TestInlineQueryResultCachedVideoBase.video_file_id,
|
||||
TestInlineQueryResultCachedVideoBase.title,
|
||||
caption=TestInlineQueryResultCachedVideoBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVideoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVideoBase.caption_entities,
|
||||
description=TestInlineQueryResultCachedVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultCachedVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVideoBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideo:
|
||||
class TestInlineQueryResultCachedVideoBase:
|
||||
id_ = "id"
|
||||
type_ = "video"
|
||||
video_file_id = "video file id"
|
||||
|
@ -55,6 +55,8 @@ class TestInlineQueryResultCachedVideo:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideoWithoutRequest(TestInlineQueryResultCachedVideoBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_video, mro_slots):
|
||||
inst = inline_query_result_cached_video
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,21 +28,21 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_voice():
|
||||
return InlineQueryResultCachedVoice(
|
||||
TestInlineQueryResultCachedVoice.id_,
|
||||
TestInlineQueryResultCachedVoice.voice_file_id,
|
||||
TestInlineQueryResultCachedVoice.title,
|
||||
caption=TestInlineQueryResultCachedVoice.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVoice.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVoice.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedVoice.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVoice.reply_markup,
|
||||
TestInlineQueryResultCachedVoiceBase.id_,
|
||||
TestInlineQueryResultCachedVoiceBase.voice_file_id,
|
||||
TestInlineQueryResultCachedVoiceBase.title,
|
||||
caption=TestInlineQueryResultCachedVoiceBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVoiceBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVoiceBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedVoiceBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVoiceBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVoice:
|
||||
class TestInlineQueryResultCachedVoiceBase:
|
||||
id_ = "id"
|
||||
type_ = "voice"
|
||||
voice_file_id = "voice file id"
|
||||
|
@ -53,6 +53,8 @@ class TestInlineQueryResultCachedVoice:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVoiceWithoutRequest(TestInlineQueryResultCachedVoiceBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_voice, mro_slots):
|
||||
inst = inline_query_result_cached_voice
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -27,22 +27,22 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_contact():
|
||||
return InlineQueryResultContact(
|
||||
TestInlineQueryResultContact.id_,
|
||||
TestInlineQueryResultContact.phone_number,
|
||||
TestInlineQueryResultContact.first_name,
|
||||
last_name=TestInlineQueryResultContact.last_name,
|
||||
thumb_url=TestInlineQueryResultContact.thumb_url,
|
||||
thumb_width=TestInlineQueryResultContact.thumb_width,
|
||||
thumb_height=TestInlineQueryResultContact.thumb_height,
|
||||
input_message_content=TestInlineQueryResultContact.input_message_content,
|
||||
reply_markup=TestInlineQueryResultContact.reply_markup,
|
||||
TestInlineQueryResultContactBase.id_,
|
||||
TestInlineQueryResultContactBase.phone_number,
|
||||
TestInlineQueryResultContactBase.first_name,
|
||||
last_name=TestInlineQueryResultContactBase.last_name,
|
||||
thumb_url=TestInlineQueryResultContactBase.thumb_url,
|
||||
thumb_width=TestInlineQueryResultContactBase.thumb_width,
|
||||
thumb_height=TestInlineQueryResultContactBase.thumb_height,
|
||||
input_message_content=TestInlineQueryResultContactBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultContactBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultContact:
|
||||
class TestInlineQueryResultContactBase:
|
||||
id_ = "id"
|
||||
type_ = "contact"
|
||||
phone_number = "phone_number"
|
||||
|
@ -54,6 +54,8 @@ class TestInlineQueryResultContact:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultContactWithoutRequest(TestInlineQueryResultContactBase):
|
||||
def test_slot_behaviour(self, inline_query_result_contact, mro_slots):
|
||||
inst = inline_query_result_contact
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,26 +28,26 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_document():
|
||||
return InlineQueryResultDocument(
|
||||
TestInlineQueryResultDocument.id_,
|
||||
TestInlineQueryResultDocument.document_url,
|
||||
TestInlineQueryResultDocument.title,
|
||||
TestInlineQueryResultDocument.mime_type,
|
||||
caption=TestInlineQueryResultDocument.caption,
|
||||
parse_mode=TestInlineQueryResultDocument.parse_mode,
|
||||
caption_entities=TestInlineQueryResultDocument.caption_entities,
|
||||
description=TestInlineQueryResultDocument.description,
|
||||
thumb_url=TestInlineQueryResultDocument.thumb_url,
|
||||
thumb_width=TestInlineQueryResultDocument.thumb_width,
|
||||
thumb_height=TestInlineQueryResultDocument.thumb_height,
|
||||
input_message_content=TestInlineQueryResultDocument.input_message_content,
|
||||
reply_markup=TestInlineQueryResultDocument.reply_markup,
|
||||
TestInlineQueryResultDocumentBase.id_,
|
||||
TestInlineQueryResultDocumentBase.document_url,
|
||||
TestInlineQueryResultDocumentBase.title,
|
||||
TestInlineQueryResultDocumentBase.mime_type,
|
||||
caption=TestInlineQueryResultDocumentBase.caption,
|
||||
parse_mode=TestInlineQueryResultDocumentBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultDocumentBase.caption_entities,
|
||||
description=TestInlineQueryResultDocumentBase.description,
|
||||
thumb_url=TestInlineQueryResultDocumentBase.thumb_url,
|
||||
thumb_width=TestInlineQueryResultDocumentBase.thumb_width,
|
||||
thumb_height=TestInlineQueryResultDocumentBase.thumb_height,
|
||||
input_message_content=TestInlineQueryResultDocumentBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultDocumentBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultDocument:
|
||||
class TestInlineQueryResultDocumentBase:
|
||||
id_ = "id"
|
||||
type_ = "document"
|
||||
document_url = "document url"
|
||||
|
@ -63,6 +63,8 @@ class TestInlineQueryResultDocument:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultDocumentWithoutRequest(TestInlineQueryResultDocumentBase):
|
||||
def test_slot_behaviour(self, inline_query_result_document, mro_slots):
|
||||
inst = inline_query_result_document
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -26,21 +26,23 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_game():
|
||||
return InlineQueryResultGame(
|
||||
TestInlineQueryResultGame.id_,
|
||||
TestInlineQueryResultGame.game_short_name,
|
||||
reply_markup=TestInlineQueryResultGame.reply_markup,
|
||||
TestInlineQueryResultGameBase.id_,
|
||||
TestInlineQueryResultGameBase.game_short_name,
|
||||
reply_markup=TestInlineQueryResultGameBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultGame:
|
||||
class TestInlineQueryResultGameBase:
|
||||
id_ = "id"
|
||||
type_ = "game"
|
||||
game_short_name = "game short name"
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultGameWithoutRequest(TestInlineQueryResultGameBase):
|
||||
def test_slot_behaviour(self, inline_query_result_game, mro_slots):
|
||||
inst = inline_query_result_game
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,26 +28,26 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_gif():
|
||||
return InlineQueryResultGif(
|
||||
TestInlineQueryResultGif.id_,
|
||||
TestInlineQueryResultGif.gif_url,
|
||||
TestInlineQueryResultGif.thumb_url,
|
||||
gif_width=TestInlineQueryResultGif.gif_width,
|
||||
gif_height=TestInlineQueryResultGif.gif_height,
|
||||
gif_duration=TestInlineQueryResultGif.gif_duration,
|
||||
title=TestInlineQueryResultGif.title,
|
||||
caption=TestInlineQueryResultGif.caption,
|
||||
parse_mode=TestInlineQueryResultGif.parse_mode,
|
||||
caption_entities=TestInlineQueryResultGif.caption_entities,
|
||||
input_message_content=TestInlineQueryResultGif.input_message_content,
|
||||
reply_markup=TestInlineQueryResultGif.reply_markup,
|
||||
thumb_mime_type=TestInlineQueryResultGif.thumb_mime_type,
|
||||
TestInlineQueryResultGifBase.id_,
|
||||
TestInlineQueryResultGifBase.gif_url,
|
||||
TestInlineQueryResultGifBase.thumb_url,
|
||||
gif_width=TestInlineQueryResultGifBase.gif_width,
|
||||
gif_height=TestInlineQueryResultGifBase.gif_height,
|
||||
gif_duration=TestInlineQueryResultGifBase.gif_duration,
|
||||
title=TestInlineQueryResultGifBase.title,
|
||||
caption=TestInlineQueryResultGifBase.caption,
|
||||
parse_mode=TestInlineQueryResultGifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultGifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultGifBase.reply_markup,
|
||||
thumb_mime_type=TestInlineQueryResultGifBase.thumb_mime_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultGif:
|
||||
class TestInlineQueryResultGifBase:
|
||||
id_ = "id"
|
||||
type_ = "gif"
|
||||
gif_url = "gif url"
|
||||
|
@ -63,6 +63,8 @@ class TestInlineQueryResultGif:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultGifWithoutRequest(TestInlineQueryResultGifBase):
|
||||
def test_slot_behaviour(self, inline_query_result_gif, mro_slots):
|
||||
inst = inline_query_result_gif
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -27,26 +27,26 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_location():
|
||||
return InlineQueryResultLocation(
|
||||
TestInlineQueryResultLocation.id_,
|
||||
TestInlineQueryResultLocation.latitude,
|
||||
TestInlineQueryResultLocation.longitude,
|
||||
TestInlineQueryResultLocation.title,
|
||||
live_period=TestInlineQueryResultLocation.live_period,
|
||||
thumb_url=TestInlineQueryResultLocation.thumb_url,
|
||||
thumb_width=TestInlineQueryResultLocation.thumb_width,
|
||||
thumb_height=TestInlineQueryResultLocation.thumb_height,
|
||||
input_message_content=TestInlineQueryResultLocation.input_message_content,
|
||||
reply_markup=TestInlineQueryResultLocation.reply_markup,
|
||||
horizontal_accuracy=TestInlineQueryResultLocation.horizontal_accuracy,
|
||||
heading=TestInlineQueryResultLocation.heading,
|
||||
proximity_alert_radius=TestInlineQueryResultLocation.proximity_alert_radius,
|
||||
TestInlineQueryResultLocationBase.id_,
|
||||
TestInlineQueryResultLocationBase.latitude,
|
||||
TestInlineQueryResultLocationBase.longitude,
|
||||
TestInlineQueryResultLocationBase.title,
|
||||
live_period=TestInlineQueryResultLocationBase.live_period,
|
||||
thumb_url=TestInlineQueryResultLocationBase.thumb_url,
|
||||
thumb_width=TestInlineQueryResultLocationBase.thumb_width,
|
||||
thumb_height=TestInlineQueryResultLocationBase.thumb_height,
|
||||
input_message_content=TestInlineQueryResultLocationBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultLocationBase.reply_markup,
|
||||
horizontal_accuracy=TestInlineQueryResultLocationBase.horizontal_accuracy,
|
||||
heading=TestInlineQueryResultLocationBase.heading,
|
||||
proximity_alert_radius=TestInlineQueryResultLocationBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultLocation:
|
||||
class TestInlineQueryResultLocationBase:
|
||||
id_ = "id"
|
||||
type_ = "location"
|
||||
latitude = 0.0
|
||||
|
@ -62,6 +62,8 @@ class TestInlineQueryResultLocation:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultLocationWithoutRequest(TestInlineQueryResultLocationBase):
|
||||
def test_slot_behaviour(self, inline_query_result_location, mro_slots):
|
||||
inst = inline_query_result_location
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,26 +28,26 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_mpeg4_gif():
|
||||
return InlineQueryResultMpeg4Gif(
|
||||
TestInlineQueryResultMpeg4Gif.id_,
|
||||
TestInlineQueryResultMpeg4Gif.mpeg4_url,
|
||||
TestInlineQueryResultMpeg4Gif.thumb_url,
|
||||
mpeg4_width=TestInlineQueryResultMpeg4Gif.mpeg4_width,
|
||||
mpeg4_height=TestInlineQueryResultMpeg4Gif.mpeg4_height,
|
||||
mpeg4_duration=TestInlineQueryResultMpeg4Gif.mpeg4_duration,
|
||||
title=TestInlineQueryResultMpeg4Gif.title,
|
||||
caption=TestInlineQueryResultMpeg4Gif.caption,
|
||||
parse_mode=TestInlineQueryResultMpeg4Gif.parse_mode,
|
||||
caption_entities=TestInlineQueryResultMpeg4Gif.caption_entities,
|
||||
input_message_content=TestInlineQueryResultMpeg4Gif.input_message_content,
|
||||
reply_markup=TestInlineQueryResultMpeg4Gif.reply_markup,
|
||||
thumb_mime_type=TestInlineQueryResultMpeg4Gif.thumb_mime_type,
|
||||
TestInlineQueryResultMpeg4GifBase.id_,
|
||||
TestInlineQueryResultMpeg4GifBase.mpeg4_url,
|
||||
TestInlineQueryResultMpeg4GifBase.thumb_url,
|
||||
mpeg4_width=TestInlineQueryResultMpeg4GifBase.mpeg4_width,
|
||||
mpeg4_height=TestInlineQueryResultMpeg4GifBase.mpeg4_height,
|
||||
mpeg4_duration=TestInlineQueryResultMpeg4GifBase.mpeg4_duration,
|
||||
title=TestInlineQueryResultMpeg4GifBase.title,
|
||||
caption=TestInlineQueryResultMpeg4GifBase.caption,
|
||||
parse_mode=TestInlineQueryResultMpeg4GifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultMpeg4GifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultMpeg4GifBase.reply_markup,
|
||||
thumb_mime_type=TestInlineQueryResultMpeg4GifBase.thumb_mime_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4Gif:
|
||||
class TestInlineQueryResultMpeg4GifBase:
|
||||
id_ = "id"
|
||||
type_ = "mpeg4_gif"
|
||||
mpeg4_url = "mpeg4 url"
|
||||
|
@ -63,6 +63,8 @@ class TestInlineQueryResultMpeg4Gif:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4GifWithoutRequest(TestInlineQueryResultMpeg4GifBase):
|
||||
def test_slot_behaviour(self, inline_query_result_mpeg4_gif, mro_slots):
|
||||
inst = inline_query_result_mpeg4_gif
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,25 +28,25 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_photo():
|
||||
return InlineQueryResultPhoto(
|
||||
TestInlineQueryResultPhoto.id_,
|
||||
TestInlineQueryResultPhoto.photo_url,
|
||||
TestInlineQueryResultPhoto.thumb_url,
|
||||
photo_width=TestInlineQueryResultPhoto.photo_width,
|
||||
photo_height=TestInlineQueryResultPhoto.photo_height,
|
||||
title=TestInlineQueryResultPhoto.title,
|
||||
description=TestInlineQueryResultPhoto.description,
|
||||
caption=TestInlineQueryResultPhoto.caption,
|
||||
parse_mode=TestInlineQueryResultPhoto.parse_mode,
|
||||
caption_entities=TestInlineQueryResultPhoto.caption_entities,
|
||||
input_message_content=TestInlineQueryResultPhoto.input_message_content,
|
||||
reply_markup=TestInlineQueryResultPhoto.reply_markup,
|
||||
TestInlineQueryResultPhotoBase.id_,
|
||||
TestInlineQueryResultPhotoBase.photo_url,
|
||||
TestInlineQueryResultPhotoBase.thumb_url,
|
||||
photo_width=TestInlineQueryResultPhotoBase.photo_width,
|
||||
photo_height=TestInlineQueryResultPhotoBase.photo_height,
|
||||
title=TestInlineQueryResultPhotoBase.title,
|
||||
description=TestInlineQueryResultPhotoBase.description,
|
||||
caption=TestInlineQueryResultPhotoBase.caption,
|
||||
parse_mode=TestInlineQueryResultPhotoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultPhotoBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultPhoto:
|
||||
class TestInlineQueryResultPhotoBase:
|
||||
id_ = "id"
|
||||
type_ = "photo"
|
||||
photo_url = "photo url"
|
||||
|
@ -62,6 +62,8 @@ class TestInlineQueryResultPhoto:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultPhotoWithoutRequest(TestInlineQueryResultPhotoBase):
|
||||
def test_slot_behaviour(self, inline_query_result_photo, mro_slots):
|
||||
inst = inline_query_result_photo
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -27,27 +27,27 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_venue():
|
||||
return InlineQueryResultVenue(
|
||||
TestInlineQueryResultVenue.id_,
|
||||
TestInlineQueryResultVenue.latitude,
|
||||
TestInlineQueryResultVenue.longitude,
|
||||
TestInlineQueryResultVenue.title,
|
||||
TestInlineQueryResultVenue.address,
|
||||
foursquare_id=TestInlineQueryResultVenue.foursquare_id,
|
||||
foursquare_type=TestInlineQueryResultVenue.foursquare_type,
|
||||
thumb_url=TestInlineQueryResultVenue.thumb_url,
|
||||
thumb_width=TestInlineQueryResultVenue.thumb_width,
|
||||
thumb_height=TestInlineQueryResultVenue.thumb_height,
|
||||
input_message_content=TestInlineQueryResultVenue.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVenue.reply_markup,
|
||||
google_place_id=TestInlineQueryResultVenue.google_place_id,
|
||||
google_place_type=TestInlineQueryResultVenue.google_place_type,
|
||||
TestInlineQueryResultVenueBase.id_,
|
||||
TestInlineQueryResultVenueBase.latitude,
|
||||
TestInlineQueryResultVenueBase.longitude,
|
||||
TestInlineQueryResultVenueBase.title,
|
||||
TestInlineQueryResultVenueBase.address,
|
||||
foursquare_id=TestInlineQueryResultVenueBase.foursquare_id,
|
||||
foursquare_type=TestInlineQueryResultVenueBase.foursquare_type,
|
||||
thumb_url=TestInlineQueryResultVenueBase.thumb_url,
|
||||
thumb_width=TestInlineQueryResultVenueBase.thumb_width,
|
||||
thumb_height=TestInlineQueryResultVenueBase.thumb_height,
|
||||
input_message_content=TestInlineQueryResultVenueBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVenueBase.reply_markup,
|
||||
google_place_id=TestInlineQueryResultVenueBase.google_place_id,
|
||||
google_place_type=TestInlineQueryResultVenueBase.google_place_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVenue:
|
||||
class TestInlineQueryResultVenueBase:
|
||||
id_ = "id"
|
||||
type_ = "venue"
|
||||
latitude = "latitude"
|
||||
|
@ -64,6 +64,8 @@ class TestInlineQueryResultVenue:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultVenueWithoutRequest(TestInlineQueryResultVenueBase):
|
||||
def test_slot_behaviour(self, inline_query_result_venue, mro_slots):
|
||||
inst = inline_query_result_venue
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,27 +28,27 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_video():
|
||||
return InlineQueryResultVideo(
|
||||
TestInlineQueryResultVideo.id_,
|
||||
TestInlineQueryResultVideo.video_url,
|
||||
TestInlineQueryResultVideo.mime_type,
|
||||
TestInlineQueryResultVideo.thumb_url,
|
||||
TestInlineQueryResultVideo.title,
|
||||
video_width=TestInlineQueryResultVideo.video_width,
|
||||
video_height=TestInlineQueryResultVideo.video_height,
|
||||
video_duration=TestInlineQueryResultVideo.video_duration,
|
||||
caption=TestInlineQueryResultVideo.caption,
|
||||
parse_mode=TestInlineQueryResultVideo.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVideo.caption_entities,
|
||||
description=TestInlineQueryResultVideo.description,
|
||||
input_message_content=TestInlineQueryResultVideo.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVideo.reply_markup,
|
||||
TestInlineQueryResultVideoBase.id_,
|
||||
TestInlineQueryResultVideoBase.video_url,
|
||||
TestInlineQueryResultVideoBase.mime_type,
|
||||
TestInlineQueryResultVideoBase.thumb_url,
|
||||
TestInlineQueryResultVideoBase.title,
|
||||
video_width=TestInlineQueryResultVideoBase.video_width,
|
||||
video_height=TestInlineQueryResultVideoBase.video_height,
|
||||
video_duration=TestInlineQueryResultVideoBase.video_duration,
|
||||
caption=TestInlineQueryResultVideoBase.caption,
|
||||
parse_mode=TestInlineQueryResultVideoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVideoBase.caption_entities,
|
||||
description=TestInlineQueryResultVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVideoBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVideo:
|
||||
class TestInlineQueryResultVideoBase:
|
||||
id_ = "id"
|
||||
type_ = "video"
|
||||
video_url = "video url"
|
||||
|
@ -65,6 +65,8 @@ class TestInlineQueryResultVideo:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultVideoWithoutRequest(TestInlineQueryResultVideoBase):
|
||||
def test_slot_behaviour(self, inline_query_result_video, mro_slots):
|
||||
inst = inline_query_result_video
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -28,22 +28,22 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_voice():
|
||||
return InlineQueryResultVoice(
|
||||
id=TestInlineQueryResultVoice.id_,
|
||||
voice_url=TestInlineQueryResultVoice.voice_url,
|
||||
title=TestInlineQueryResultVoice.title,
|
||||
voice_duration=TestInlineQueryResultVoice.voice_duration,
|
||||
caption=TestInlineQueryResultVoice.caption,
|
||||
parse_mode=TestInlineQueryResultVoice.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVoice.caption_entities,
|
||||
input_message_content=TestInlineQueryResultVoice.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVoice.reply_markup,
|
||||
id=TestInlineQueryResultVoiceBase.id_,
|
||||
voice_url=TestInlineQueryResultVoiceBase.voice_url,
|
||||
title=TestInlineQueryResultVoiceBase.title,
|
||||
voice_duration=TestInlineQueryResultVoiceBase.voice_duration,
|
||||
caption=TestInlineQueryResultVoiceBase.caption,
|
||||
parse_mode=TestInlineQueryResultVoiceBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVoiceBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultVoiceBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVoiceBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVoice:
|
||||
class TestInlineQueryResultVoiceBase:
|
||||
id_ = "id"
|
||||
type_ = "voice"
|
||||
voice_url = "voice url"
|
||||
|
@ -55,6 +55,8 @@ class TestInlineQueryResultVoice:
|
|||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultVoiceWithoutRequest(TestInlineQueryResultVoiceBase):
|
||||
def test_slot_behaviour(self, inline_query_result_voice, mro_slots):
|
||||
inst = inline_query_result_voice
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,20 +21,22 @@ import pytest
|
|||
from telegram import InputContactMessageContent, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_contact_message_content():
|
||||
return InputContactMessageContent(
|
||||
TestInputContactMessageContent.phone_number,
|
||||
TestInputContactMessageContent.first_name,
|
||||
last_name=TestInputContactMessageContent.last_name,
|
||||
TestInputContactMessageContentBase.phone_number,
|
||||
TestInputContactMessageContentBase.first_name,
|
||||
TestInputContactMessageContentBase.last_name,
|
||||
)
|
||||
|
||||
|
||||
class TestInputContactMessageContent:
|
||||
class TestInputContactMessageContentBase:
|
||||
phone_number = "phone number"
|
||||
first_name = "first name"
|
||||
last_name = "last name"
|
||||
|
||||
|
||||
class TestInputContactMessageContentWithoutRequest(TestInputContactMessageContentBase):
|
||||
def test_slot_behaviour(self, input_contact_message_content, mro_slots):
|
||||
inst = input_contact_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -26,12 +26,12 @@ from telegram import InputFile
|
|||
from tests.conftest import data_file
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def png_file():
|
||||
return data_file("game.png")
|
||||
|
||||
|
||||
class TestInputFile:
|
||||
class TestInputFileWithoutRequest:
|
||||
def test_slot_behaviour(self, mro_slots):
|
||||
inst = InputFile(BytesIO(b"blah"), filename="tg.jpg")
|
||||
for attr in inst.__slots__:
|
||||
|
@ -65,7 +65,7 @@ class TestInputFile:
|
|||
assert input_file.attach_name is None
|
||||
assert input_file.attach_uri is None
|
||||
|
||||
def test_mimetypes(self, caplog):
|
||||
def test_mimetypes(self):
|
||||
# Only test a few to make sure logic works okay
|
||||
assert InputFile(data_file("telegram.jpg").open("rb")).mimetype == "image/jpeg"
|
||||
# For some reason python can guess the type on macOS
|
||||
|
@ -139,6 +139,8 @@ class TestInputFile:
|
|||
== "blah.jpg"
|
||||
)
|
||||
|
||||
|
||||
class TestInputFileWithRequest:
|
||||
async def test_send_bytes(self, bot, chat_id):
|
||||
# We test this here and not at the respective test modules because it's not worth
|
||||
# duplicating the test for the different methods
|
||||
|
|
|
@ -22,33 +22,33 @@ import pytest
|
|||
from telegram import InputInvoiceMessageContent, InputTextMessageContent, LabeledPrice
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_invoice_message_content():
|
||||
return InputInvoiceMessageContent(
|
||||
title=TestInputInvoiceMessageContent.title,
|
||||
description=TestInputInvoiceMessageContent.description,
|
||||
payload=TestInputInvoiceMessageContent.payload,
|
||||
provider_token=TestInputInvoiceMessageContent.provider_token,
|
||||
currency=TestInputInvoiceMessageContent.currency,
|
||||
prices=TestInputInvoiceMessageContent.prices,
|
||||
max_tip_amount=TestInputInvoiceMessageContent.max_tip_amount,
|
||||
suggested_tip_amounts=TestInputInvoiceMessageContent.suggested_tip_amounts,
|
||||
provider_data=TestInputInvoiceMessageContent.provider_data,
|
||||
photo_url=TestInputInvoiceMessageContent.photo_url,
|
||||
photo_size=TestInputInvoiceMessageContent.photo_size,
|
||||
photo_width=TestInputInvoiceMessageContent.photo_width,
|
||||
photo_height=TestInputInvoiceMessageContent.photo_height,
|
||||
need_name=TestInputInvoiceMessageContent.need_name,
|
||||
need_phone_number=TestInputInvoiceMessageContent.need_phone_number,
|
||||
need_email=TestInputInvoiceMessageContent.need_email,
|
||||
need_shipping_address=TestInputInvoiceMessageContent.need_shipping_address,
|
||||
send_phone_number_to_provider=TestInputInvoiceMessageContent.send_phone_number_to_provider,
|
||||
send_email_to_provider=TestInputInvoiceMessageContent.send_email_to_provider,
|
||||
is_flexible=TestInputInvoiceMessageContent.is_flexible,
|
||||
title=TestInputInvoiceMessageContentBase.title,
|
||||
description=TestInputInvoiceMessageContentBase.description,
|
||||
payload=TestInputInvoiceMessageContentBase.payload,
|
||||
provider_token=TestInputInvoiceMessageContentBase.provider_token,
|
||||
currency=TestInputInvoiceMessageContentBase.currency,
|
||||
prices=TestInputInvoiceMessageContentBase.prices,
|
||||
max_tip_amount=TestInputInvoiceMessageContentBase.max_tip_amount,
|
||||
suggested_tip_amounts=TestInputInvoiceMessageContentBase.suggested_tip_amounts,
|
||||
provider_data=TestInputInvoiceMessageContentBase.provider_data,
|
||||
photo_url=TestInputInvoiceMessageContentBase.photo_url,
|
||||
photo_size=TestInputInvoiceMessageContentBase.photo_size,
|
||||
photo_width=TestInputInvoiceMessageContentBase.photo_width,
|
||||
photo_height=TestInputInvoiceMessageContentBase.photo_height,
|
||||
need_name=TestInputInvoiceMessageContentBase.need_name,
|
||||
need_phone_number=TestInputInvoiceMessageContentBase.need_phone_number,
|
||||
need_email=TestInputInvoiceMessageContentBase.need_email,
|
||||
need_shipping_address=TestInputInvoiceMessageContentBase.need_shipping_address,
|
||||
send_phone_number_to_provider=TestInputInvoiceMessageContentBase.send_phone_number_to_provider, # noqa: E501
|
||||
send_email_to_provider=TestInputInvoiceMessageContentBase.send_email_to_provider,
|
||||
is_flexible=TestInputInvoiceMessageContentBase.is_flexible,
|
||||
)
|
||||
|
||||
|
||||
class TestInputInvoiceMessageContent:
|
||||
class TestInputInvoiceMessageContentBase:
|
||||
title = "invoice title"
|
||||
description = "invoice description"
|
||||
payload = "invoice payload"
|
||||
|
@ -70,6 +70,8 @@ class TestInputInvoiceMessageContent:
|
|||
send_email_to_provider = True
|
||||
is_flexible = True
|
||||
|
||||
|
||||
class TestInputInvoiceMessageContentWithoutRequest(TestInputInvoiceMessageContentBase):
|
||||
def test_slot_behaviour(self, input_invoice_message_content, mro_slots):
|
||||
inst = input_invoice_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
@ -103,29 +105,7 @@ class TestInputInvoiceMessageContent:
|
|||
assert input_invoice_message_content.send_email_to_provider == self.send_email_to_provider
|
||||
assert input_invoice_message_content.is_flexible == self.is_flexible
|
||||
|
||||
def test_suggested_tip_amonuts_always_tuple(self):
|
||||
input_invoice_message_content = InputInvoiceMessageContent(
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
payload=self.payload,
|
||||
provider_token=self.provider_token,
|
||||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
max_tip_amount=self.max_tip_amount,
|
||||
suggested_tip_amounts=self.suggested_tip_amounts,
|
||||
provider_data=self.provider_data,
|
||||
photo_url=self.photo_url,
|
||||
photo_size=self.photo_size,
|
||||
photo_width=self.photo_width,
|
||||
photo_height=self.photo_height,
|
||||
need_name=self.need_name,
|
||||
need_phone_number=self.need_phone_number,
|
||||
need_email=self.need_email,
|
||||
need_shipping_address=self.need_shipping_address,
|
||||
send_phone_number_to_provider=self.send_phone_number_to_provider,
|
||||
send_email_to_provider=self.send_email_to_provider,
|
||||
is_flexible=self.is_flexible,
|
||||
)
|
||||
def test_suggested_tip_amonuts_always_tuple(self, input_invoice_message_content):
|
||||
assert isinstance(input_invoice_message_content.suggested_tip_amounts, tuple)
|
||||
assert input_invoice_message_content.suggested_tip_amounts == tuple(
|
||||
int(amount) for amount in self.suggested_tip_amounts
|
||||
|
|
|
@ -21,19 +21,19 @@ import pytest
|
|||
from telegram import InputLocationMessageContent, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_location_message_content():
|
||||
return InputLocationMessageContent(
|
||||
TestInputLocationMessageContent.latitude,
|
||||
TestInputLocationMessageContent.longitude,
|
||||
live_period=TestInputLocationMessageContent.live_period,
|
||||
horizontal_accuracy=TestInputLocationMessageContent.horizontal_accuracy,
|
||||
heading=TestInputLocationMessageContent.heading,
|
||||
proximity_alert_radius=TestInputLocationMessageContent.proximity_alert_radius,
|
||||
TestInputLocationMessageContentBase.latitude,
|
||||
TestInputLocationMessageContentBase.longitude,
|
||||
live_period=TestInputLocationMessageContentBase.live_period,
|
||||
horizontal_accuracy=TestInputLocationMessageContentBase.horizontal_accuracy,
|
||||
heading=TestInputLocationMessageContentBase.heading,
|
||||
proximity_alert_radius=TestInputLocationMessageContentBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestInputLocationMessageContent:
|
||||
class TestInputLocationMessageContentBase:
|
||||
latitude = -23.691288
|
||||
longitude = -46.788279
|
||||
live_period = 80
|
||||
|
@ -41,6 +41,8 @@ class TestInputLocationMessageContent:
|
|||
heading = 90
|
||||
proximity_alert_radius = 999
|
||||
|
||||
|
||||
class TestInputLocationMessageContentWithoutRequest(TestInputLocationMessageContentBase):
|
||||
def test_slot_behaviour(self, input_location_message_content, mro_slots):
|
||||
inst = input_location_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import copy
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
@ -56,86 +57,75 @@ from .test_photo import _photo, photo, photo_file, thumb # noqa: F401
|
|||
from .test_video import video, video_file # noqa: F401
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_video(class_thumb_file):
|
||||
return InputMediaVideo(
|
||||
media=TestInputMediaVideo.media,
|
||||
caption=TestInputMediaVideo.caption,
|
||||
width=TestInputMediaVideo.width,
|
||||
height=TestInputMediaVideo.height,
|
||||
duration=TestInputMediaVideo.duration,
|
||||
parse_mode=TestInputMediaVideo.parse_mode,
|
||||
caption_entities=TestInputMediaVideo.caption_entities,
|
||||
media=TestInputMediaVideoBase.media,
|
||||
caption=TestInputMediaVideoBase.caption,
|
||||
width=TestInputMediaVideoBase.width,
|
||||
height=TestInputMediaVideoBase.height,
|
||||
duration=TestInputMediaVideoBase.duration,
|
||||
parse_mode=TestInputMediaVideoBase.parse_mode,
|
||||
caption_entities=TestInputMediaVideoBase.caption_entities,
|
||||
thumb=class_thumb_file,
|
||||
supports_streaming=TestInputMediaVideo.supports_streaming,
|
||||
has_spoiler=TestInputMediaVideo.has_spoiler,
|
||||
supports_streaming=TestInputMediaVideoBase.supports_streaming,
|
||||
has_spoiler=TestInputMediaVideoBase.has_spoiler,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def input_media_photo(class_thumb_file):
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_photo():
|
||||
return InputMediaPhoto(
|
||||
media=TestInputMediaPhoto.media,
|
||||
caption=TestInputMediaPhoto.caption,
|
||||
parse_mode=TestInputMediaPhoto.parse_mode,
|
||||
caption_entities=TestInputMediaPhoto.caption_entities,
|
||||
has_spoiler=TestInputMediaPhoto.has_spoiler,
|
||||
media=TestInputMediaPhotoBase.media,
|
||||
caption=TestInputMediaPhotoBase.caption,
|
||||
parse_mode=TestInputMediaPhotoBase.parse_mode,
|
||||
caption_entities=TestInputMediaPhotoBase.caption_entities,
|
||||
has_spoiler=TestInputMediaPhotoBase.has_spoiler,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_animation(class_thumb_file):
|
||||
return InputMediaAnimation(
|
||||
media=TestInputMediaAnimation.media,
|
||||
caption=TestInputMediaAnimation.caption,
|
||||
parse_mode=TestInputMediaAnimation.parse_mode,
|
||||
caption_entities=TestInputMediaAnimation.caption_entities,
|
||||
width=TestInputMediaAnimation.width,
|
||||
height=TestInputMediaAnimation.height,
|
||||
media=TestInputMediaAnimationBase.media,
|
||||
caption=TestInputMediaAnimationBase.caption,
|
||||
parse_mode=TestInputMediaAnimationBase.parse_mode,
|
||||
caption_entities=TestInputMediaAnimationBase.caption_entities,
|
||||
width=TestInputMediaAnimationBase.width,
|
||||
height=TestInputMediaAnimationBase.height,
|
||||
thumb=class_thumb_file,
|
||||
duration=TestInputMediaAnimation.duration,
|
||||
has_spoiler=TestInputMediaAnimation.has_spoiler,
|
||||
duration=TestInputMediaAnimationBase.duration,
|
||||
has_spoiler=TestInputMediaAnimationBase.has_spoiler,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_audio(class_thumb_file):
|
||||
return InputMediaAudio(
|
||||
media=TestInputMediaAudio.media,
|
||||
caption=TestInputMediaAudio.caption,
|
||||
duration=TestInputMediaAudio.duration,
|
||||
performer=TestInputMediaAudio.performer,
|
||||
title=TestInputMediaAudio.title,
|
||||
media=TestInputMediaAudioBase.media,
|
||||
caption=TestInputMediaAudioBase.caption,
|
||||
duration=TestInputMediaAudioBase.duration,
|
||||
performer=TestInputMediaAudioBase.performer,
|
||||
title=TestInputMediaAudioBase.title,
|
||||
thumb=class_thumb_file,
|
||||
parse_mode=TestInputMediaAudio.parse_mode,
|
||||
caption_entities=TestInputMediaAudio.caption_entities,
|
||||
parse_mode=TestInputMediaAudioBase.parse_mode,
|
||||
caption_entities=TestInputMediaAudioBase.caption_entities,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_document(class_thumb_file):
|
||||
return InputMediaDocument(
|
||||
media=TestInputMediaDocument.media,
|
||||
caption=TestInputMediaDocument.caption,
|
||||
media=TestInputMediaDocumentBase.media,
|
||||
caption=TestInputMediaDocumentBase.caption,
|
||||
thumb=class_thumb_file,
|
||||
parse_mode=TestInputMediaDocument.parse_mode,
|
||||
caption_entities=TestInputMediaDocument.caption_entities,
|
||||
disable_content_type_detection=TestInputMediaDocument.disable_content_type_detection,
|
||||
parse_mode=TestInputMediaDocumentBase.parse_mode,
|
||||
caption_entities=TestInputMediaDocumentBase.caption_entities,
|
||||
disable_content_type_detection=TestInputMediaDocumentBase.disable_content_type_detection,
|
||||
)
|
||||
|
||||
|
||||
class CustomSequence(Sequence):
|
||||
def __init__(self, items):
|
||||
self.items = items
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.items[index]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.items)
|
||||
|
||||
|
||||
class TestInputMediaVideo:
|
||||
class TestInputMediaVideoBase:
|
||||
type_ = "video"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
@ -147,6 +137,8 @@ class TestInputMediaVideo:
|
|||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
has_spoiler = True
|
||||
|
||||
|
||||
class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||
def test_slot_behaviour(self, input_media_video, mro_slots):
|
||||
inst = input_media_video
|
||||
for attr in inst.__slots__:
|
||||
|
@ -210,7 +202,7 @@ class TestInputMediaVideo:
|
|||
assert input_media_video.thumb == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaPhoto:
|
||||
class TestInputMediaPhotoBase:
|
||||
type_ = "photo"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
@ -218,6 +210,8 @@ class TestInputMediaPhoto:
|
|||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
has_spoiler = True
|
||||
|
||||
|
||||
class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
def test_slot_behaviour(self, input_media_photo, mro_slots):
|
||||
inst = input_media_photo
|
||||
for attr in inst.__slots__:
|
||||
|
@ -266,7 +260,7 @@ class TestInputMediaPhoto:
|
|||
assert input_media_photo.media == data_file("telegram.mp4").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaAnimation:
|
||||
class TestInputMediaAnimationBase:
|
||||
type_ = "animation"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
@ -277,6 +271,8 @@ class TestInputMediaAnimation:
|
|||
duration = 1
|
||||
has_spoiler = True
|
||||
|
||||
|
||||
class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
||||
def test_slot_behaviour(self, input_media_animation, mro_slots):
|
||||
inst = input_media_animation
|
||||
for attr in inst.__slots__:
|
||||
|
@ -332,7 +328,7 @@ class TestInputMediaAnimation:
|
|||
assert input_media_animation.thumb == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaAudio:
|
||||
class TestInputMediaAudioBase:
|
||||
type_ = "audio"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
@ -342,6 +338,8 @@ class TestInputMediaAudio:
|
|||
parse_mode = "HTML"
|
||||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
|
||||
|
||||
class TestInputMediaAudioWithoutRequest(TestInputMediaAudioBase):
|
||||
def test_slot_behaviour(self, input_media_audio, mro_slots):
|
||||
inst = input_media_audio
|
||||
for attr in inst.__slots__:
|
||||
|
@ -401,7 +399,7 @@ class TestInputMediaAudio:
|
|||
assert input_media_audio.thumb == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaDocument:
|
||||
class TestInputMediaDocumentBase:
|
||||
type_ = "document"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
@ -409,6 +407,8 @@ class TestInputMediaDocument:
|
|||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
disable_content_type_detection = True
|
||||
|
||||
|
||||
class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
||||
def test_slot_behaviour(self, input_media_document, mro_slots):
|
||||
inst = input_media_document
|
||||
for attr in inst.__slots__:
|
||||
|
@ -467,7 +467,7 @@ class TestInputMediaDocument:
|
|||
assert input_media_document.thumb == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function") # noqa: F811
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
def media_group(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, caption="*photo* 1", parse_mode="Markdown"),
|
||||
|
@ -478,12 +478,12 @@ def media_group(photo, thumb): # noqa: F811
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function") # noqa: F811
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
def media_group_no_caption_args(photo, thumb): # noqa: F811
|
||||
return [InputMediaPhoto(photo), InputMediaPhoto(thumb), InputMediaPhoto(photo)]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function") # noqa: F811
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
def media_group_no_caption_only_caption_entities(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, caption_entities=[MessageEntity(MessageEntity.BOLD, 0, 5)]),
|
||||
|
@ -491,7 +491,7 @@ def media_group_no_caption_only_caption_entities(photo, thumb): # noqa: F811
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function") # noqa: F811
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
def media_group_no_caption_only_parse_mode(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, parse_mode="Markdown"),
|
||||
|
@ -499,32 +499,7 @@ def media_group_no_caption_only_parse_mode(photo, thumb): # noqa: F811
|
|||
]
|
||||
|
||||
|
||||
class TestSendMediaGroup:
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_media_group_photo(self, bot, chat_id, media_group):
|
||||
messages = await bot.send_media_group(chat_id, media_group)
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
assert all(mes.caption == f"photo {idx+1}" for idx, mes in enumerate(messages))
|
||||
assert all(
|
||||
mes.caption_entities == (MessageEntity(MessageEntity.BOLD, 0, 5),) for mes in messages
|
||||
)
|
||||
|
||||
async def test_send_media_group_with_message_thread_id(
|
||||
self, bot, real_topic, forum_group_id, media_group # noqa: F811
|
||||
):
|
||||
messages = await bot.send_media_group(
|
||||
forum_group_id,
|
||||
media_group,
|
||||
message_thread_id=real_topic.message_thread_id,
|
||||
)
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(i.message_thread_id == real_topic.message_thread_id for i in messages)
|
||||
|
||||
class TestSendMediaGroupWithoutRequest:
|
||||
async def test_send_media_group_throws_error_with_group_caption_and_individual_captions(
|
||||
self,
|
||||
bot,
|
||||
|
@ -544,6 +519,143 @@ class TestSendMediaGroup:
|
|||
):
|
||||
await bot.send_media_group(chat_id, group, caption="foo")
|
||||
|
||||
async def test_send_media_group_custom_filename(
|
||||
self,
|
||||
bot,
|
||||
chat_id,
|
||||
photo_file, # noqa: F811
|
||||
animation_file, # noqa: F811
|
||||
audio_file, # noqa: F811
|
||||
video_file, # noqa: F811
|
||||
monkeypatch,
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
result = all(
|
||||
field_tuple[0] == "custom_filename"
|
||||
for field_tuple in request_data.multipart_data.values()
|
||||
)
|
||||
if result is True:
|
||||
raise Exception("Test was successful")
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
media = [
|
||||
InputMediaAnimation(animation_file, filename="custom_filename"),
|
||||
InputMediaAudio(audio_file, filename="custom_filename"),
|
||||
InputMediaPhoto(photo_file, filename="custom_filename"),
|
||||
InputMediaVideo(video_file, filename="custom_filename"),
|
||||
]
|
||||
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, media)
|
||||
|
||||
async def test_send_media_group_with_thumbs(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(method, url, request_data: RequestData, *args, **kwargs):
|
||||
nonlocal input_video
|
||||
files = request_data.multipart_data
|
||||
video_check = files[input_video.media.attach_name] == input_video.media.field_tuple
|
||||
thumb_check = files[input_video.thumb.attach_name] == input_video.thumb.field_tuple
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumb=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, [input_video, input_video])
|
||||
|
||||
async def test_edit_message_media_with_thumb(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(
|
||||
method: str, url: str, request_data: RequestData = None, *args, **kwargs
|
||||
):
|
||||
files = request_data.multipart_data
|
||||
video_check = files[input_video.media.attach_name] == input_video.media.field_tuple
|
||||
thumb_check = files[input_video.thumb.attach_name] == input_video.thumb.field_tuple
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumb=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.edit_message_media(chat_id=chat_id, message_id=123, media=input_video)
|
||||
|
||||
|
||||
class CustomSequence(Sequence):
|
||||
def __init__(self, items):
|
||||
self.items = items
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.items[index]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.items)
|
||||
|
||||
|
||||
class TestSendMediaGroupWithRequest:
|
||||
async def test_send_media_group_photo(self, bot, chat_id, media_group):
|
||||
messages = await bot.send_media_group(chat_id, media_group)
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
assert all(mes.caption == f"photo {idx+1}" for idx, mes in enumerate(messages))
|
||||
assert all(
|
||||
mes.caption_entities == (MessageEntity(MessageEntity.BOLD, 0, 5),) for mes in messages
|
||||
)
|
||||
|
||||
async def test_send_media_group_new_files(
|
||||
self, bot, chat_id, video_file, photo_file # noqa: F811
|
||||
):
|
||||
async def func():
|
||||
return await bot.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaVideo(video_file),
|
||||
InputMediaPhoto(photo_file),
|
||||
InputMediaPhoto(data_file("telegram.jpg").read_bytes()),
|
||||
],
|
||||
)
|
||||
|
||||
messages = await expect_bad_request(
|
||||
func, "Type of file mismatch", "Telegram did not accept the file."
|
||||
)
|
||||
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
|
||||
@pytest.mark.parametrize("sequence_type", [list, tuple, CustomSequence])
|
||||
@pytest.mark.parametrize("bot_class", ["raw_bot", "ext_bot"])
|
||||
async def test_send_media_group_different_sequences(
|
||||
self, bot, chat_id, media_group, sequence_type, bot_class, raw_bot
|
||||
):
|
||||
"""Test that send_media_group accepts different sequence types. This test ensures that
|
||||
Bot._insert_defaults works for arbitrary sequence types."""
|
||||
bot = bot if bot_class == "ext_bot" else raw_bot
|
||||
|
||||
messages = await bot.send_media_group(chat_id, sequence_type(media_group))
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
|
||||
async def test_send_media_group_with_message_thread_id(
|
||||
self, bot, real_topic, forum_group_id, media_group # noqa: F811
|
||||
):
|
||||
messages = await bot.send_media_group(
|
||||
forum_group_id,
|
||||
media_group,
|
||||
message_thread_id=real_topic.message_thread_id,
|
||||
)
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(i.message_thread_id == real_topic.message_thread_id for i in messages)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"caption, parse_mode, caption_entities",
|
||||
[
|
||||
|
@ -553,7 +665,6 @@ class TestSendMediaGroup:
|
|||
("photo 1", None, [MessageEntity(MessageEntity.BOLD, 0, 5)]),
|
||||
],
|
||||
)
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_media_group_with_group_caption(
|
||||
self,
|
||||
bot,
|
||||
|
@ -598,16 +709,15 @@ class TestSendMediaGroup:
|
|||
assert all(mes.caption is None for mes in other_messages)
|
||||
assert not any(mes.caption_entities for mes in other_messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_media_group_all_args(self, bot, raw_bot, chat_id, media_group):
|
||||
ext_bot = bot
|
||||
for bot in (ext_bot, raw_bot):
|
||||
# We need to test 1) below both the bot and raw_bot and setting this up with
|
||||
# pytest.parametrize appears to be difficult ...
|
||||
|
||||
m1 = await bot.send_message(chat_id, text="test")
|
||||
# We need to test 1) below both the bot and raw_bot and setting this up with
|
||||
# pytest.parametrize appears to be difficult ...
|
||||
aws = {b.send_message(chat_id, text="test") for b in (ext_bot, raw_bot)}
|
||||
for msg_task in asyncio.as_completed(aws):
|
||||
m1 = await msg_task
|
||||
copied_media_group = copy.copy(media_group)
|
||||
messages = await bot.send_media_group(
|
||||
messages = await m1.get_bot().send_media_group(
|
||||
chat_id,
|
||||
media_group,
|
||||
disable_notification=True,
|
||||
|
@ -633,7 +743,6 @@ class TestSendMediaGroup:
|
|||
)
|
||||
assert all(mes.has_protected_content for mes in messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_media_group_with_spoiler(
|
||||
self, bot, chat_id, photo_file, video_file # noqa: F811
|
||||
):
|
||||
|
@ -649,97 +758,36 @@ class TestSendMediaGroup:
|
|||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
assert all(mes.has_media_spoiler for mes in messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_media_group_custom_filename(
|
||||
self,
|
||||
bot,
|
||||
chat_id,
|
||||
photo_file, # noqa: F811
|
||||
animation_file, # noqa: F811
|
||||
audio_file, # noqa: F811
|
||||
video_file, # noqa: F811
|
||||
monkeypatch,
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
result = all(
|
||||
field_tuple[0] == "custom_filename"
|
||||
for field_tuple in request_data.multipart_data.values()
|
||||
async def test_edit_message_media(self, bot, raw_bot, chat_id, media_group):
|
||||
ext_bot = bot
|
||||
# We need to test 1) below both the bot and raw_bot and setting this up with
|
||||
# pytest.parametrize appears to be difficult ...
|
||||
aws = {b.send_media_group(chat_id, media_group) for b in (ext_bot, raw_bot)}
|
||||
for msg_task in asyncio.as_completed(aws):
|
||||
messages = await msg_task
|
||||
cid = messages[-1].chat.id
|
||||
mid = messages[-1].message_id
|
||||
copied_media = copy.copy(media_group[0])
|
||||
new_message = (
|
||||
await messages[-1]
|
||||
.get_bot()
|
||||
.edit_message_media(chat_id=cid, message_id=mid, media=media_group[0])
|
||||
)
|
||||
if result is True:
|
||||
raise Exception("Test was successful")
|
||||
assert isinstance(new_message, Message)
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
# 1)
|
||||
# make sure that the media was not modified
|
||||
assert media_group[0].parse_mode == copied_media.parse_mode
|
||||
|
||||
media = [
|
||||
InputMediaAnimation(animation_file, filename="custom_filename"),
|
||||
InputMediaAudio(audio_file, filename="custom_filename"),
|
||||
InputMediaPhoto(photo_file, filename="custom_filename"),
|
||||
InputMediaVideo(video_file, filename="custom_filename"),
|
||||
]
|
||||
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, media)
|
||||
|
||||
async def test_send_media_group_with_thumbs(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(method, url, request_data: RequestData, *args, **kwargs):
|
||||
files = request_data.multipart_data
|
||||
video_check = files[input_video.media.attach_name] == input_video.media.field_tuple
|
||||
thumb_check = files[input_video.thumb.attach_name] == input_video.thumb.field_tuple
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumb=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, [input_video, input_video])
|
||||
|
||||
@pytest.mark.flaky(3, 1) # noqa: F811
|
||||
async def test_send_media_group_new_files(
|
||||
self,
|
||||
bot,
|
||||
chat_id,
|
||||
video_file, # noqa: F811
|
||||
photo_file, # noqa: F811
|
||||
animation_file, # noqa: F811
|
||||
):
|
||||
async def func():
|
||||
return await bot.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaVideo(video_file),
|
||||
InputMediaPhoto(photo_file),
|
||||
InputMediaPhoto(data_file("telegram.jpg").read_bytes()),
|
||||
],
|
||||
)
|
||||
|
||||
messages = await expect_bad_request(
|
||||
func, "Type of file mismatch", "Telegram did not accept the file."
|
||||
async def test_edit_message_media_new_file(self, bot, chat_id, media_group, thumb_file):
|
||||
messages = await bot.send_media_group(chat_id, media_group)
|
||||
cid = messages[-1].chat.id
|
||||
mid = messages[-1].message_id
|
||||
new_message = await bot.edit_message_media(
|
||||
chat_id=cid, message_id=mid, media=InputMediaPhoto(thumb_file)
|
||||
)
|
||||
assert isinstance(new_message, Message)
|
||||
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("sequence_type", [list, tuple, CustomSequence])
|
||||
@pytest.mark.parametrize("bot_class", ["raw_bot", "ext_bot"])
|
||||
async def test_send_media_group_different_sequences(
|
||||
self, bot, chat_id, media_group, sequence_type, bot_class, raw_bot
|
||||
):
|
||||
"""Test that send_media_group accepts different sequence types. This test ensures that
|
||||
Bot._insert_defaults works for arbitrary sequence types."""
|
||||
bot = bot if bot_class == "ext_bot" else raw_bot
|
||||
|
||||
messages = await bot.send_media_group(chat_id, sequence_type(media_group))
|
||||
assert isinstance(messages, tuple)
|
||||
assert len(messages) == 3
|
||||
assert all(isinstance(mes, Message) for mes in messages)
|
||||
assert all(mes.media_group_id == messages[0].media_group_id for mes in messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
|
@ -773,19 +821,18 @@ class TestSendMediaGroup:
|
|||
chat_id, media_group, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_media_group_default_protect_content(
|
||||
self, chat_id, media_group, default_bot
|
||||
):
|
||||
protected = await default_bot.send_media_group(chat_id, media_group)
|
||||
assert all(msg.has_protected_content for msg in protected)
|
||||
unprotected = await default_bot.send_media_group(
|
||||
chat_id, media_group, protect_content=False
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_media_group(chat_id, media_group),
|
||||
default_bot.send_media_group(chat_id, media_group, protect_content=False),
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert all(msg.has_protected_content for msg in protected)
|
||||
assert not all(msg.has_protected_content for msg in unprotected)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"parse_mode": ParseMode.HTML}], indirect=True)
|
||||
async def test_send_media_group_default_parse_mode(
|
||||
self, chat_id, media_group_no_caption_args, default_bot
|
||||
|
@ -797,19 +844,21 @@ class TestSendMediaGroup:
|
|||
# make sure no parse_mode was set as a side effect
|
||||
assert not any(item.parse_mode for item in media_group_no_caption_args)
|
||||
|
||||
overridden_markdown_v2 = await default_bot.send_media_group(
|
||||
chat_id,
|
||||
media_group_no_caption_args.copy(),
|
||||
caption="*photo* 1",
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
)
|
||||
|
||||
overridden_none = await default_bot.send_media_group(
|
||||
chat_id,
|
||||
media_group_no_caption_args.copy(),
|
||||
caption="<b>photo</b> 1",
|
||||
parse_mode=None,
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_media_group(
|
||||
chat_id,
|
||||
media_group_no_caption_args.copy(),
|
||||
caption="*photo* 1",
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
),
|
||||
default_bot.send_media_group(
|
||||
chat_id,
|
||||
media_group_no_caption_args.copy(),
|
||||
caption="<b>photo</b> 1",
|
||||
parse_mode=None,
|
||||
),
|
||||
)
|
||||
overridden_markdown_v2, overridden_none = await tasks
|
||||
|
||||
# Make sure first message got the caption, which will lead to Telegram
|
||||
# displaying its caption as group caption
|
||||
|
@ -830,53 +879,6 @@ class TestSendMediaGroup:
|
|||
assert all(mes.caption is None for mes in other_messages)
|
||||
assert not any(mes.caption_entities for mes in other_messages)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_edit_message_media(self, bot, raw_bot, chat_id, media_group):
|
||||
ext_bot = bot
|
||||
for bot in (ext_bot, raw_bot):
|
||||
# We need to test 1) below both the bot and raw_bot and setting this up with
|
||||
# pytest.parametrize appears to be difficult ...
|
||||
messages = await bot.send_media_group(chat_id, media_group)
|
||||
cid = messages[-1].chat.id
|
||||
mid = messages[-1].message_id
|
||||
copied_media = copy.copy(media_group[0])
|
||||
new_message = await bot.edit_message_media(
|
||||
chat_id=cid, message_id=mid, media=media_group[0]
|
||||
)
|
||||
assert isinstance(new_message, Message)
|
||||
|
||||
# 1)
|
||||
# make sure that the media was not modified
|
||||
assert media_group[0].parse_mode == copied_media.parse_mode
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_edit_message_media_new_file(self, bot, chat_id, media_group, thumb_file):
|
||||
messages = await bot.send_media_group(chat_id, media_group)
|
||||
cid = messages[-1].chat.id
|
||||
mid = messages[-1].message_id
|
||||
new_message = await bot.edit_message_media(
|
||||
chat_id=cid, message_id=mid, media=InputMediaPhoto(thumb_file)
|
||||
)
|
||||
assert isinstance(new_message, Message)
|
||||
|
||||
async def test_edit_message_media_with_thumb(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(
|
||||
method: str, url: str, request_data: RequestData = None, *args, **kwargs
|
||||
):
|
||||
files = request_data.multipart_data
|
||||
video_check = files[input_video.media.attach_name] == input_video.media.field_tuple
|
||||
thumb_check = files[input_video.thumb.attach_name] == input_video.thumb.field_tuple
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumb=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.edit_message_media(chat_id=chat_id, message_id=123, media=input_video)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot", [{"parse_mode": ParseMode.HTML}], indirect=True, ids=["HTML-Bot"]
|
||||
)
|
||||
|
|
|
@ -22,22 +22,24 @@ from telegram import InputTextMessageContent, MessageEntity
|
|||
from telegram.constants import ParseMode
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_text_message_content():
|
||||
return InputTextMessageContent(
|
||||
TestInputTextMessageContent.message_text,
|
||||
parse_mode=TestInputTextMessageContent.parse_mode,
|
||||
entities=TestInputTextMessageContent.entities,
|
||||
disable_web_page_preview=TestInputTextMessageContent.disable_web_page_preview,
|
||||
TestInputTextMessageContentBase.message_text,
|
||||
parse_mode=TestInputTextMessageContentBase.parse_mode,
|
||||
entities=TestInputTextMessageContentBase.entities,
|
||||
disable_web_page_preview=TestInputTextMessageContentBase.disable_web_page_preview,
|
||||
)
|
||||
|
||||
|
||||
class TestInputTextMessageContent:
|
||||
class TestInputTextMessageContentBase:
|
||||
message_text = "*message text*"
|
||||
parse_mode = ParseMode.MARKDOWN
|
||||
entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
disable_web_page_preview = True
|
||||
|
||||
|
||||
class TestInputTextMessageContentWithoutRequest(TestInputTextMessageContentBase):
|
||||
def test_slot_behaviour(self, input_text_message_content, mro_slots):
|
||||
inst = input_text_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,21 @@ import pytest
|
|||
from telegram import InputVenueMessageContent, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def input_venue_message_content():
|
||||
return InputVenueMessageContent(
|
||||
TestInputVenueMessageContent.latitude,
|
||||
TestInputVenueMessageContent.longitude,
|
||||
TestInputVenueMessageContent.title,
|
||||
TestInputVenueMessageContent.address,
|
||||
foursquare_id=TestInputVenueMessageContent.foursquare_id,
|
||||
foursquare_type=TestInputVenueMessageContent.foursquare_type,
|
||||
google_place_id=TestInputVenueMessageContent.google_place_id,
|
||||
google_place_type=TestInputVenueMessageContent.google_place_type,
|
||||
TestInputVenueMessageContentBase.latitude,
|
||||
TestInputVenueMessageContentBase.longitude,
|
||||
TestInputVenueMessageContentBase.title,
|
||||
TestInputVenueMessageContentBase.address,
|
||||
foursquare_id=TestInputVenueMessageContentBase.foursquare_id,
|
||||
foursquare_type=TestInputVenueMessageContentBase.foursquare_type,
|
||||
google_place_id=TestInputVenueMessageContentBase.google_place_id,
|
||||
google_place_type=TestInputVenueMessageContentBase.google_place_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInputVenueMessageContent:
|
||||
class TestInputVenueMessageContentBase:
|
||||
latitude = 1.0
|
||||
longitude = 2.0
|
||||
title = "title"
|
||||
|
@ -45,6 +45,8 @@ class TestInputVenueMessageContent:
|
|||
google_place_id = "google place id"
|
||||
google_place_type = "google place type"
|
||||
|
||||
|
||||
class TestInputVenueMessageContentWithoutRequest(TestInputVenueMessageContentBase):
|
||||
def test_slot_behaviour(self, input_venue_message_content, mro_slots):
|
||||
inst = input_venue_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Invoice, LabeledPrice
|
||||
|
@ -23,18 +25,18 @@ from telegram.error import BadRequest
|
|||
from telegram.request import RequestData
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def invoice():
|
||||
return Invoice(
|
||||
TestInvoice.title,
|
||||
TestInvoice.description,
|
||||
TestInvoice.start_parameter,
|
||||
TestInvoice.currency,
|
||||
TestInvoice.total_amount,
|
||||
TestInvoiceBase.title,
|
||||
TestInvoiceBase.description,
|
||||
TestInvoiceBase.start_parameter,
|
||||
TestInvoiceBase.currency,
|
||||
TestInvoiceBase.total_amount,
|
||||
)
|
||||
|
||||
|
||||
class TestInvoice:
|
||||
class TestInvoiceBase:
|
||||
payload = "payload"
|
||||
prices = [LabeledPrice("Fish", 100), LabeledPrice("Fish Tax", 1000)]
|
||||
provider_data = """{"test":"test"}"""
|
||||
|
@ -46,6 +48,8 @@ class TestInvoice:
|
|||
max_tip_amount = 42
|
||||
suggested_tip_amounts = [13, 42]
|
||||
|
||||
|
||||
class TestInvoiceWithoutRequest(TestInvoiceBase):
|
||||
def test_slot_behaviour(self, invoice, mro_slots):
|
||||
for attr in invoice.__slots__:
|
||||
assert getattr(invoice, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -54,11 +58,11 @@ class TestInvoice:
|
|||
def test_de_json(self, bot):
|
||||
invoice_json = Invoice.de_json(
|
||||
{
|
||||
"title": TestInvoice.title,
|
||||
"description": TestInvoice.description,
|
||||
"start_parameter": TestInvoice.start_parameter,
|
||||
"currency": TestInvoice.currency,
|
||||
"total_amount": TestInvoice.total_amount,
|
||||
"title": self.title,
|
||||
"description": self.description,
|
||||
"start_parameter": self.start_parameter,
|
||||
"currency": self.currency,
|
||||
"total_amount": self.total_amount,
|
||||
},
|
||||
bot,
|
||||
)
|
||||
|
@ -80,100 +84,12 @@ class TestInvoice:
|
|||
assert invoice_dict["currency"] == invoice.currency
|
||||
assert invoice_dict["total_amount"] == invoice.total_amount
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
async def test_send_required_args_only(self, bot, chat_id, provider_token):
|
||||
message = await bot.send_invoice(
|
||||
chat_id=chat_id,
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
payload=self.payload,
|
||||
provider_token=provider_token,
|
||||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
)
|
||||
|
||||
assert message.invoice.currency == self.currency
|
||||
assert message.invoice.start_parameter == ""
|
||||
assert message.invoice.description == self.description
|
||||
assert message.invoice.title == self.title
|
||||
assert message.invoice.total_amount == self.total_amount
|
||||
|
||||
link = await bot.create_invoice_link(
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
payload=self.payload,
|
||||
provider_token=provider_token,
|
||||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
)
|
||||
assert isinstance(link, str)
|
||||
assert link != ""
|
||||
|
||||
async def test_send_all_args_send_invoice(self, bot, chat_id, provider_token, monkeypatch):
|
||||
message = await bot.send_invoice(
|
||||
chat_id,
|
||||
self.title,
|
||||
self.description,
|
||||
self.payload,
|
||||
provider_token,
|
||||
self.currency,
|
||||
self.prices,
|
||||
max_tip_amount=self.max_tip_amount,
|
||||
suggested_tip_amounts=self.suggested_tip_amounts,
|
||||
start_parameter=self.start_parameter,
|
||||
provider_data=self.provider_data,
|
||||
photo_url="https://raw.githubusercontent.com/"
|
||||
"python-telegram-bot/logos/master/"
|
||||
"logo/png/ptb-logo_240.png",
|
||||
photo_size=240,
|
||||
photo_width=240,
|
||||
photo_height=240,
|
||||
need_name=True,
|
||||
need_phone_number=True,
|
||||
need_email=True,
|
||||
need_shipping_address=True,
|
||||
send_phone_number_to_provider=True,
|
||||
send_email_to_provider=True,
|
||||
is_flexible=True,
|
||||
disable_notification=True,
|
||||
protect_content=True,
|
||||
)
|
||||
|
||||
assert message.invoice.currency == self.currency
|
||||
assert message.invoice.start_parameter == self.start_parameter
|
||||
assert message.invoice.description == self.description
|
||||
assert message.invoice.title == self.title
|
||||
assert message.invoice.total_amount == self.total_amount
|
||||
assert message.has_protected_content
|
||||
|
||||
# We do this next one as safety guard to make sure that we pass all of the optional
|
||||
async def test_send_invoice_all_args_mock(self, bot, monkeypatch):
|
||||
# We do this one as safety guard to make sure that we pass all of the optional
|
||||
# parameters correctly because #2526 went unnoticed for 3 years …
|
||||
async def make_assertion(*args, **_):
|
||||
kwargs = args[1]
|
||||
return (
|
||||
kwargs["chat_id"] == "chat_id"
|
||||
and kwargs["title"] == "title"
|
||||
and kwargs["description"] == "description"
|
||||
and kwargs["payload"] == "payload"
|
||||
and kwargs["provider_token"] == "provider_token"
|
||||
and kwargs["currency"] == "currency"
|
||||
and kwargs["prices"] == self.prices
|
||||
and kwargs["max_tip_amount"] == "max_tip_amount"
|
||||
and kwargs["suggested_tip_amounts"] == "suggested_tip_amounts"
|
||||
and kwargs["start_parameter"] == "start_parameter"
|
||||
and kwargs["provider_data"] == "provider_data"
|
||||
and kwargs["photo_url"] == "photo_url"
|
||||
and kwargs["photo_size"] == "photo_size"
|
||||
and kwargs["photo_width"] == "photo_width"
|
||||
and kwargs["photo_height"] == "photo_height"
|
||||
and kwargs["need_name"] == "need_name"
|
||||
and kwargs["need_phone_number"] == "need_phone_number"
|
||||
and kwargs["need_email"] == "need_email"
|
||||
and kwargs["need_shipping_address"] == "need_shipping_address"
|
||||
and kwargs["send_phone_number_to_provider"] == "send_phone_number_to_provider"
|
||||
and kwargs["send_email_to_provider"] == "send_email_to_provider"
|
||||
and kwargs["is_flexible"] == "is_flexible"
|
||||
)
|
||||
return all([kwargs[key] == key for key in kwargs])
|
||||
|
||||
monkeypatch.setattr(bot, "_send_message", make_assertion)
|
||||
assert await bot.send_invoice(
|
||||
|
@ -183,7 +99,7 @@ class TestInvoice:
|
|||
payload="payload",
|
||||
provider_token="provider_token",
|
||||
currency="currency",
|
||||
prices=self.prices,
|
||||
prices="prices",
|
||||
max_tip_amount="max_tip_amount",
|
||||
suggested_tip_amounts="suggested_tip_amounts",
|
||||
start_parameter="start_parameter",
|
||||
|
@ -203,33 +119,10 @@ class TestInvoice:
|
|||
protect_content=True,
|
||||
)
|
||||
|
||||
async def test_send_all_args_create_invoice_link(
|
||||
self, bot, chat_id, provider_token, monkeypatch
|
||||
):
|
||||
async def test_send_all_args_create_invoice_link(self, bot, monkeypatch):
|
||||
async def make_assertion(*args, **_):
|
||||
kwargs = args[1]
|
||||
return (
|
||||
kwargs["title"] == "title"
|
||||
and kwargs["description"] == "description"
|
||||
and kwargs["payload"] == "payload"
|
||||
and kwargs["provider_token"] == "provider_token"
|
||||
and kwargs["currency"] == "currency"
|
||||
and kwargs["prices"] == self.prices
|
||||
and kwargs["max_tip_amount"] == "max_tip_amount"
|
||||
and kwargs["suggested_tip_amounts"] == "suggested_tip_amounts"
|
||||
and kwargs["provider_data"] == "provider_data"
|
||||
and kwargs["photo_url"] == "photo_url"
|
||||
and kwargs["photo_size"] == "photo_size"
|
||||
and kwargs["photo_width"] == "photo_width"
|
||||
and kwargs["photo_height"] == "photo_height"
|
||||
and kwargs["need_name"] == "need_name"
|
||||
and kwargs["need_phone_number"] == "need_phone_number"
|
||||
and kwargs["need_email"] == "need_email"
|
||||
and kwargs["need_shipping_address"] == "need_shipping_address"
|
||||
and kwargs["send_phone_number_to_provider"] == "send_phone_number_to_provider"
|
||||
and kwargs["send_email_to_provider"] == "send_email_to_provider"
|
||||
and kwargs["is_flexible"] == "is_flexible"
|
||||
)
|
||||
return all([kwargs[i] == i for i in kwargs])
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
assert await bot.create_invoice_link(
|
||||
|
@ -238,7 +131,7 @@ class TestInvoice:
|
|||
payload="payload",
|
||||
provider_token="provider_token",
|
||||
currency="currency",
|
||||
prices=self.prices,
|
||||
prices="prices",
|
||||
max_tip_amount="max_tip_amount",
|
||||
suggested_tip_amounts="suggested_tip_amounts",
|
||||
provider_data="provider_data",
|
||||
|
@ -273,7 +166,75 @@ class TestInvoice:
|
|||
start_parameter=self.start_parameter,
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
def test_equality(self):
|
||||
a = Invoice("invoice", "desc", "start", "EUR", 7)
|
||||
b = Invoice("invoice", "desc", "start", "EUR", 7)
|
||||
c = Invoice("invoices", "description", "stop", "USD", 8)
|
||||
d = LabeledPrice("label", 5)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
|
||||
class TestInvoiceWithRequest(TestInvoiceBase):
|
||||
async def test_send_required_args_only(self, bot, chat_id, provider_token):
|
||||
message = await bot.send_invoice(
|
||||
chat_id=chat_id,
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
payload=self.payload,
|
||||
provider_token=provider_token,
|
||||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
)
|
||||
|
||||
assert message.invoice.currency == self.currency
|
||||
assert message.invoice.start_parameter == ""
|
||||
assert message.invoice.description == self.description
|
||||
assert message.invoice.title == self.title
|
||||
assert message.invoice.total_amount == self.total_amount
|
||||
|
||||
link = await bot.create_invoice_link(
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
payload=self.payload,
|
||||
provider_token=provider_token,
|
||||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
)
|
||||
|
||||
assert isinstance(link, str)
|
||||
assert link != ""
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_invoice_default_protect_content(
|
||||
self, chat_id, default_bot, provider_token
|
||||
):
|
||||
tasks = asyncio.gather(
|
||||
*(
|
||||
default_bot.send_invoice(
|
||||
chat_id,
|
||||
self.title,
|
||||
self.description,
|
||||
self.payload,
|
||||
provider_token,
|
||||
self.currency,
|
||||
self.prices,
|
||||
**kwargs,
|
||||
)
|
||||
for kwargs in ({}, {"protect_content": False})
|
||||
)
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
|
@ -326,12 +287,8 @@ class TestInvoice:
|
|||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_invoice_default_protect_content(
|
||||
self, chat_id, default_bot, provider_token
|
||||
):
|
||||
protected = await default_bot.send_invoice(
|
||||
async def test_send_all_args_send_invoice(self, bot, chat_id, provider_token):
|
||||
message = await bot.send_invoice(
|
||||
chat_id,
|
||||
self.title,
|
||||
self.description,
|
||||
|
@ -339,31 +296,26 @@ class TestInvoice:
|
|||
provider_token,
|
||||
self.currency,
|
||||
self.prices,
|
||||
max_tip_amount=self.max_tip_amount,
|
||||
suggested_tip_amounts=self.suggested_tip_amounts,
|
||||
start_parameter=self.start_parameter,
|
||||
provider_data=self.provider_data,
|
||||
photo_url="https://raw.githubusercontent.com/"
|
||||
"python-telegram-bot/logos/master/logo/png/ptb-logo_240.png",
|
||||
photo_size=240,
|
||||
photo_width=240,
|
||||
photo_height=240,
|
||||
need_name=True,
|
||||
need_phone_number=True,
|
||||
need_email=True,
|
||||
need_shipping_address=True,
|
||||
send_phone_number_to_provider=True,
|
||||
send_email_to_provider=True,
|
||||
is_flexible=True,
|
||||
disable_notification=True,
|
||||
protect_content=True,
|
||||
)
|
||||
assert protected.has_protected_content
|
||||
unprotected = await default_bot.send_invoice(
|
||||
chat_id,
|
||||
self.title,
|
||||
self.description,
|
||||
self.payload,
|
||||
provider_token,
|
||||
self.currency,
|
||||
self.prices,
|
||||
protect_content=False,
|
||||
)
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
def test_equality(self):
|
||||
a = Invoice("invoice", "desc", "start", "EUR", 7)
|
||||
b = Invoice("invoice", "desc", "start", "EUR", 7)
|
||||
c = Invoice("invoices", "description", "stop", "USD", 8)
|
||||
d = LabeledPrice("label", 5)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
for attr in message.invoice.__slots__:
|
||||
assert getattr(message.invoice, attr) == getattr(self, attr)
|
||||
assert message.has_protected_content
|
||||
|
|
|
@ -27,9 +27,7 @@ import time
|
|||
import pytest
|
||||
|
||||
from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Job, JobQueue
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
from tests.conftest import TEST_WITH_OPT_DEPS, make_bot
|
||||
|
||||
if TEST_WITH_OPT_DEPS:
|
||||
import pytz
|
||||
|
@ -46,7 +44,7 @@ class CustomContext(CallbackContext):
|
|||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def job_queue(bot, app):
|
||||
async def job_queue(app):
|
||||
jq = JobQueue()
|
||||
jq.set_application(app)
|
||||
await jq.start()
|
||||
|
@ -179,9 +177,9 @@ class TestJobQueue:
|
|||
job_queue.run_repeating(
|
||||
self.job_run_once, 0.5, first=dtm.datetime.now(timezone) + dtm.timedelta(seconds=0.2)
|
||||
)
|
||||
await asyncio.sleep(0.15)
|
||||
await asyncio.sleep(0.05)
|
||||
assert self.result == 0
|
||||
await asyncio.sleep(0.2)
|
||||
await asyncio.sleep(0.25)
|
||||
assert self.result == 1
|
||||
|
||||
async def test_run_repeating_last(self, job_queue):
|
||||
|
@ -192,7 +190,7 @@ class TestJobQueue:
|
|||
assert self.result == 1
|
||||
|
||||
async def test_run_repeating_last_timezone(self, job_queue, timezone):
|
||||
"""Test correct scheduling of job when passing a timezone-aware datetime as ``first``"""
|
||||
"""Test correct scheduling of job when passing a timezone-aware datetime as ``last``"""
|
||||
job_queue.run_repeating(
|
||||
self.job_run_once, 0.25, last=dtm.datetime.now(timezone) + dtm.timedelta(seconds=0.4)
|
||||
)
|
||||
|
@ -244,6 +242,7 @@ class TestJobQueue:
|
|||
j2 = job_queue.run_repeating(self.job_run_once, 0.2)
|
||||
|
||||
await asyncio.sleep(0.25)
|
||||
assert self.result == 1
|
||||
|
||||
j1.schedule_removal()
|
||||
j2.schedule_removal()
|
||||
|
@ -273,8 +272,8 @@ class TestJobQueue:
|
|||
await asyncio.sleep(0.3)
|
||||
assert self.result == 1
|
||||
|
||||
async def test_in_application(self, bot):
|
||||
app = ApplicationBuilder().token(bot.token).build()
|
||||
async def test_in_application(self, bot_info):
|
||||
app = ApplicationBuilder().bot(make_bot(bot_info)).build()
|
||||
async with app:
|
||||
assert not app.job_queue.scheduler.running
|
||||
await app.start()
|
||||
|
@ -311,7 +310,7 @@ class TestJobQueue:
|
|||
# Testing running at a specific datetime
|
||||
delta, now = dtm.timedelta(seconds=0.5), dtm.datetime.now(UTC)
|
||||
when = now + delta
|
||||
expected_time = (now + delta).timestamp()
|
||||
expected_time = when.timestamp()
|
||||
|
||||
job_queue.run_once(self.job_datetime_tests, when)
|
||||
await asyncio.sleep(0.6)
|
||||
|
@ -444,8 +443,11 @@ class TestJobQueue:
|
|||
callback = self.job_run_once
|
||||
|
||||
job1 = job_queue.run_once(callback, 10, name="name1")
|
||||
await asyncio.sleep(0.03) # To stablize tests on windows
|
||||
job2 = job_queue.run_once(callback, 10, name="name1")
|
||||
await asyncio.sleep(0.03)
|
||||
job3 = job_queue.run_once(callback, 10, name="name2")
|
||||
await asyncio.sleep(0.03)
|
||||
|
||||
assert job_queue.jobs() == (job1, job2, job3)
|
||||
assert job_queue.get_jobs_by_name("name1") == (job1, job2)
|
||||
|
@ -453,9 +455,9 @@ class TestJobQueue:
|
|||
|
||||
async def test_job_run(self, app):
|
||||
job = app.job_queue.run_repeating(self.job_run_once, 0.02)
|
||||
await asyncio.sleep(0.05)
|
||||
assert self.result == 0
|
||||
await job.run(app)
|
||||
await asyncio.sleep(0.05) # the job queue has not started yet
|
||||
assert self.result == 0 # so the job will not run
|
||||
await job.run(app) # but this will force it to run
|
||||
assert self.result == 1
|
||||
|
||||
async def test_enable_disable_job(self, job_queue):
|
||||
|
@ -569,7 +571,7 @@ class TestJobQueue:
|
|||
)
|
||||
job_queue.set_application(application)
|
||||
|
||||
def callback(context):
|
||||
async def callback(context):
|
||||
self.result = (
|
||||
type(context),
|
||||
context.user_data,
|
||||
|
@ -603,8 +605,8 @@ class TestJobQueue:
|
|||
if wait:
|
||||
assert not task.done()
|
||||
ready_event.set()
|
||||
await asyncio.sleep(0.1)
|
||||
await asyncio.sleep(0.1) # no CancelledError (see source of JobQueue.stop for details)
|
||||
assert task.done()
|
||||
else:
|
||||
await asyncio.sleep(0.1)
|
||||
await asyncio.sleep(0.1) # unfortunately we will get a CancelledError here
|
||||
assert task.done()
|
||||
|
|
|
@ -28,20 +28,20 @@ from telegram import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def keyboard_button():
|
||||
return KeyboardButton(
|
||||
TestKeyboardButton.text,
|
||||
request_location=TestKeyboardButton.request_location,
|
||||
request_contact=TestKeyboardButton.request_contact,
|
||||
request_poll=TestKeyboardButton.request_poll,
|
||||
web_app=TestKeyboardButton.web_app,
|
||||
request_chat=TestKeyboardButton.request_chat,
|
||||
request_user=TestKeyboardButton.request_user,
|
||||
TestKeyboardButtonBase.text,
|
||||
request_location=TestKeyboardButtonBase.request_location,
|
||||
request_contact=TestKeyboardButtonBase.request_contact,
|
||||
request_poll=TestKeyboardButtonBase.request_poll,
|
||||
web_app=TestKeyboardButtonBase.web_app,
|
||||
request_chat=TestKeyboardButtonBase.request_chat,
|
||||
request_user=TestKeyboardButtonBase.request_user,
|
||||
)
|
||||
|
||||
|
||||
class TestKeyboardButton:
|
||||
class TestKeyboardButtonBase:
|
||||
text = "text"
|
||||
request_location = True
|
||||
request_contact = True
|
||||
|
@ -50,6 +50,8 @@ class TestKeyboardButton:
|
|||
request_chat = KeyboardButtonRequestChat(1, True)
|
||||
request_user = KeyboardButtonRequestUser(2)
|
||||
|
||||
|
||||
class TestKeyboardButtonWithoutRequest(TestKeyboardButtonBase):
|
||||
def test_slot_behaviour(self, keyboard_button, mro_slots):
|
||||
inst = keyboard_button
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,14 +21,16 @@ import pytest
|
|||
from telegram import KeyboardButtonPollType, Poll
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def keyboard_button_poll_type():
|
||||
return KeyboardButtonPollType(TestKeyboardButtonPollType.type)
|
||||
return KeyboardButtonPollType(TestKeyboardButtonPollTypeBase.type)
|
||||
|
||||
|
||||
class TestKeyboardButtonPollType:
|
||||
class TestKeyboardButtonPollTypeBase:
|
||||
type = Poll.QUIZ
|
||||
|
||||
|
||||
class TestKeyboardButtonPollTypeWithoutRequest(TestKeyboardButtonPollTypeBase):
|
||||
def test_slot_behaviour(self, keyboard_button_poll_type, mro_slots):
|
||||
inst = keyboard_button_poll_type
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -25,17 +25,19 @@ from telegram import ChatAdministratorRights, KeyboardButtonRequestChat, Keyboar
|
|||
@pytest.fixture(scope="class")
|
||||
def request_user():
|
||||
return KeyboardButtonRequestUser(
|
||||
TestKeyboardButtonRequestUser.request_id,
|
||||
TestKeyboardButtonRequestUser.user_is_bot,
|
||||
TestKeyboardButtonRequestUser.user_is_premium,
|
||||
TestKeyboardButtonRequestUserBase.request_id,
|
||||
TestKeyboardButtonRequestUserBase.user_is_bot,
|
||||
TestKeyboardButtonRequestUserBase.user_is_premium,
|
||||
)
|
||||
|
||||
|
||||
class TestKeyboardButtonRequestUser:
|
||||
class TestKeyboardButtonRequestUserBase:
|
||||
request_id = 123
|
||||
user_is_bot = True
|
||||
user_is_premium = False
|
||||
|
||||
|
||||
class TestKeyboardButtonRequestUserWithoutRequest(TestKeyboardButtonRequestUserBase):
|
||||
def test_slot_behaviour(self, request_user, mro_slots):
|
||||
for attr in request_user.__slots__:
|
||||
assert getattr(request_user, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -78,18 +80,18 @@ class TestKeyboardButtonRequestUser:
|
|||
@pytest.fixture(scope="class")
|
||||
def request_chat():
|
||||
return KeyboardButtonRequestChat(
|
||||
TestKeyboardButtonRequestChat.request_id,
|
||||
TestKeyboardButtonRequestChat.chat_is_channel,
|
||||
TestKeyboardButtonRequestChat.chat_is_forum,
|
||||
TestKeyboardButtonRequestChat.chat_has_username,
|
||||
TestKeyboardButtonRequestChat.chat_is_created,
|
||||
TestKeyboardButtonRequestChat.user_administrator_rights,
|
||||
TestKeyboardButtonRequestChat.bot_administrator_rights,
|
||||
TestKeyboardButtonRequestChat.bot_is_member,
|
||||
TestKeyboardButtonRequestChatBase.request_id,
|
||||
TestKeyboardButtonRequestChatBase.chat_is_channel,
|
||||
TestKeyboardButtonRequestChatBase.chat_is_forum,
|
||||
TestKeyboardButtonRequestChatBase.chat_has_username,
|
||||
TestKeyboardButtonRequestChatBase.chat_is_created,
|
||||
TestKeyboardButtonRequestChatBase.user_administrator_rights,
|
||||
TestKeyboardButtonRequestChatBase.bot_administrator_rights,
|
||||
TestKeyboardButtonRequestChatBase.bot_is_member,
|
||||
)
|
||||
|
||||
|
||||
class TestKeyboardButtonRequestChat:
|
||||
class TestKeyboardButtonRequestChatBase:
|
||||
request_id = 456
|
||||
chat_is_channel = True
|
||||
chat_is_forum = False
|
||||
|
@ -103,6 +105,8 @@ class TestKeyboardButtonRequestChat:
|
|||
)
|
||||
bot_is_member = True
|
||||
|
||||
|
||||
class TestKeyboardButtonRequestChatWithoutRequest(TestKeyboardButtonRequestChatBase):
|
||||
def test_slot_behaviour(self, request_chat, mro_slots):
|
||||
for attr in request_chat.__slots__:
|
||||
assert getattr(request_chat, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -21,15 +21,17 @@ import pytest
|
|||
from telegram import LabeledPrice, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def labeled_price():
|
||||
return LabeledPrice(TestLabeledPrice.label, TestLabeledPrice.amount)
|
||||
return LabeledPrice(TestLabeledPriceBase.label, TestLabeledPriceBase.amount)
|
||||
|
||||
|
||||
class TestLabeledPrice:
|
||||
class TestLabeledPriceBase:
|
||||
label = "label"
|
||||
amount = 100
|
||||
|
||||
|
||||
class TestLabeledPriceWithoutRequest(TestLabeledPriceBase):
|
||||
def test_slot_behaviour(self, labeled_price, mro_slots):
|
||||
inst = labeled_price
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Location
|
||||
|
@ -23,19 +25,19 @@ from telegram.error import BadRequest
|
|||
from telegram.request import RequestData
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def location():
|
||||
return Location(
|
||||
latitude=TestLocation.latitude,
|
||||
longitude=TestLocation.longitude,
|
||||
horizontal_accuracy=TestLocation.horizontal_accuracy,
|
||||
live_period=TestLocation.live_period,
|
||||
heading=TestLocation.live_period,
|
||||
proximity_alert_radius=TestLocation.proximity_alert_radius,
|
||||
latitude=TestLocationBase.latitude,
|
||||
longitude=TestLocationBase.longitude,
|
||||
horizontal_accuracy=TestLocationBase.horizontal_accuracy,
|
||||
live_period=TestLocationBase.live_period,
|
||||
heading=TestLocationBase.live_period,
|
||||
proximity_alert_radius=TestLocationBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestLocation:
|
||||
class TestLocationBase:
|
||||
latitude = -23.691288
|
||||
longitude = -46.788279
|
||||
horizontal_accuracy = 999
|
||||
|
@ -43,6 +45,8 @@ class TestLocation:
|
|||
heading = 90
|
||||
proximity_alert_radius = 50
|
||||
|
||||
|
||||
class TestLocationWithoutRequest(TestLocationBase):
|
||||
def test_slot_behaviour(self, location, mro_slots):
|
||||
for attr in location.__slots__:
|
||||
assert getattr(location, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -50,12 +54,12 @@ class TestLocation:
|
|||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
"latitude": TestLocation.latitude,
|
||||
"longitude": TestLocation.longitude,
|
||||
"horizontal_accuracy": TestLocation.horizontal_accuracy,
|
||||
"live_period": TestLocation.live_period,
|
||||
"heading": TestLocation.heading,
|
||||
"proximity_alert_radius": TestLocation.proximity_alert_radius,
|
||||
"latitude": self.latitude,
|
||||
"longitude": self.longitude,
|
||||
"horizontal_accuracy": self.horizontal_accuracy,
|
||||
"live_period": self.live_period,
|
||||
"heading": self.heading,
|
||||
"proximity_alert_radius": self.proximity_alert_radius,
|
||||
}
|
||||
location = Location.de_json(json_dict, bot)
|
||||
assert location.api_kwargs == {}
|
||||
|
@ -67,7 +71,139 @@ class TestLocation:
|
|||
assert location.heading == self.heading
|
||||
assert location.proximity_alert_radius == self.proximity_alert_radius
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
def test_to_dict(self, location):
|
||||
location_dict = location.to_dict()
|
||||
|
||||
assert location_dict["latitude"] == location.latitude
|
||||
assert location_dict["longitude"] == location.longitude
|
||||
assert location_dict["horizontal_accuracy"] == location.horizontal_accuracy
|
||||
assert location_dict["live_period"] == location.live_period
|
||||
assert location["heading"] == location.heading
|
||||
assert location["proximity_alert_radius"] == location.proximity_alert_radius
|
||||
|
||||
def test_equality(self):
|
||||
a = Location(self.longitude, self.latitude)
|
||||
b = Location(self.longitude, self.latitude)
|
||||
d = Location(0, self.latitude)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
async def test_send_location_without_required(self, bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.send_location(chat_id=chat_id)
|
||||
|
||||
async def test_edit_location_without_required(self, bot):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.edit_message_live_location(chat_id=2, message_id=3)
|
||||
|
||||
async def test_send_location_with_all_args(self, bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_location(chat_id=1, latitude=2.5, longitude=4.6, location=location)
|
||||
|
||||
async def test_edit_location_with_all_args(self, bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.edit_message_live_location(
|
||||
chat_id=1, message_id=7, latitude=2.5, longitude=4.6, location=location
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_edit_live_inline_message(self, monkeypatch, bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
lat = data["latitude"] == str(location.latitude)
|
||||
lon = data["longitude"] == str(location.longitude)
|
||||
id_ = data["inline_message_id"] == "1234"
|
||||
ha = data["horizontal_accuracy"] == "50"
|
||||
heading = data["heading"] == "90"
|
||||
prox_alert = data["proximity_alert_radius"] == "1000"
|
||||
return lat and lon and id_ and ha and heading and prox_alert
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(
|
||||
inline_message_id=1234,
|
||||
location=location,
|
||||
horizontal_accuracy=50,
|
||||
heading=90,
|
||||
proximity_alert_radius=1000,
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_stop_live_inline_message(self, monkeypatch, bot):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
id_ = request_data.json_parameters["inline_message_id"] == "1234"
|
||||
return id_
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.stop_message_live_location(inline_message_id=1234)
|
||||
|
||||
async def test_send_with_location(self, monkeypatch, bot, chat_id, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_location(location=location, chat_id=chat_id)
|
||||
|
||||
async def test_edit_live_location_with_location(self, monkeypatch, bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(None, None, location=location)
|
||||
|
||||
|
||||
class TestLocationWithRequest:
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
({"allow_sending_without_reply": False}, True),
|
||||
],
|
||||
indirect=["default_bot"],
|
||||
)
|
||||
async def test_send_location_default_allow_sending_without_reply(
|
||||
self, default_bot, chat_id, location, custom
|
||||
):
|
||||
reply_to_message = await default_bot.send_message(chat_id, "test")
|
||||
await reply_to_message.delete()
|
||||
if custom is not None:
|
||||
message = await default_bot.send_location(
|
||||
chat_id,
|
||||
location=location,
|
||||
allow_sending_without_reply=custom,
|
||||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
elif default_bot.defaults.allow_sending_without_reply:
|
||||
message = await default_bot.send_location(
|
||||
chat_id, location=location, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
else:
|
||||
with pytest.raises(BadRequest, match="message not found"):
|
||||
await default_bot.send_location(
|
||||
chat_id, location=location, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_location_default_protect_content(self, chat_id, default_bot, location):
|
||||
tasks = asyncio.gather(
|
||||
default_bot.send_location(chat_id, location=location),
|
||||
default_bot.send_location(chat_id, location=location, protect_content=False),
|
||||
)
|
||||
protected, unprotected = await tasks
|
||||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.xfail
|
||||
async def test_send_live_location(self, bot, chat_id):
|
||||
message = await bot.send_location(
|
||||
|
@ -110,135 +246,3 @@ class TestLocation:
|
|||
await bot.edit_message_live_location(
|
||||
message.chat_id, message.message_id, latitude=52.223880, longitude=5.164306
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_edit_live_inline_message(self, monkeypatch, bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
lat = data["latitude"] == str(location.latitude)
|
||||
lon = data["longitude"] == str(location.longitude)
|
||||
id_ = data["inline_message_id"] == "1234"
|
||||
ha = data["horizontal_accuracy"] == "50"
|
||||
heading = data["heading"] == "90"
|
||||
prox_alert = data["proximity_alert_radius"] == "1000"
|
||||
return lat and lon and id_ and ha and heading and prox_alert
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(
|
||||
inline_message_id=1234,
|
||||
location=location,
|
||||
horizontal_accuracy=50,
|
||||
heading=90,
|
||||
proximity_alert_radius=1000,
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_stop_live_inline_message(self, monkeypatch, bot):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
id_ = request_data.json_parameters["inline_message_id"] == "1234"
|
||||
return id_
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.stop_message_live_location(inline_message_id=1234)
|
||||
|
||||
async def test_send_with_location(self, monkeypatch, bot, chat_id, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_location(location=location, chat_id=chat_id)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
({"allow_sending_without_reply": False}, True),
|
||||
],
|
||||
indirect=["default_bot"],
|
||||
)
|
||||
async def test_send_location_default_allow_sending_without_reply(
|
||||
self, default_bot, chat_id, location, custom
|
||||
):
|
||||
reply_to_message = await default_bot.send_message(chat_id, "test")
|
||||
await reply_to_message.delete()
|
||||
if custom is not None:
|
||||
message = await default_bot.send_location(
|
||||
chat_id,
|
||||
location=location,
|
||||
allow_sending_without_reply=custom,
|
||||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
elif default_bot.defaults.allow_sending_without_reply:
|
||||
message = await default_bot.send_location(
|
||||
chat_id, location=location, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
else:
|
||||
with pytest.raises(BadRequest, match="message not found"):
|
||||
await default_bot.send_location(
|
||||
chat_id, location=location, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
@pytest.mark.flaky(3, 1)
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_location_default_protect_content(self, chat_id, default_bot, location):
|
||||
protected = await default_bot.send_location(chat_id, location=location)
|
||||
assert protected.has_protected_content
|
||||
unprotected = await default_bot.send_location(
|
||||
chat_id, location=location, protect_content=False
|
||||
)
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
async def test_edit_live_location_with_location(self, monkeypatch, bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(None, None, location=location)
|
||||
|
||||
async def test_send_location_without_required(self, bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.send_location(chat_id=chat_id)
|
||||
|
||||
async def test_edit_location_without_required(self, bot):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.edit_message_live_location(chat_id=2, message_id=3)
|
||||
|
||||
async def test_send_location_with_all_args(self, bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_location(chat_id=1, latitude=2.5, longitude=4.6, location=location)
|
||||
|
||||
async def test_edit_location_with_all_args(self, bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.edit_message_live_location(
|
||||
chat_id=1, message_id=7, latitude=2.5, longitude=4.6, location=location
|
||||
)
|
||||
|
||||
def test_to_dict(self, location):
|
||||
location_dict = location.to_dict()
|
||||
|
||||
assert location_dict["latitude"] == location.latitude
|
||||
assert location_dict["longitude"] == location.longitude
|
||||
assert location_dict["horizontal_accuracy"] == location.horizontal_accuracy
|
||||
assert location_dict["live_period"] == location.live_period
|
||||
assert location["heading"] == location.heading
|
||||
assert location["proximity_alert_radius"] == location.proximity_alert_radius
|
||||
|
||||
def test_equality(self):
|
||||
a = Location(self.longitude, self.latitude)
|
||||
b = Location(self.longitude, self.latitude)
|
||||
d = Location(0, self.latitude)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -21,22 +21,24 @@ import pytest
|
|||
from telegram import LoginUrl
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def login_url():
|
||||
return LoginUrl(
|
||||
url=TestLoginUrl.url,
|
||||
forward_text=TestLoginUrl.forward_text,
|
||||
bot_username=TestLoginUrl.bot_username,
|
||||
request_write_access=TestLoginUrl.request_write_access,
|
||||
url=TestLoginUrlBase.url,
|
||||
forward_text=TestLoginUrlBase.forward_text,
|
||||
bot_username=TestLoginUrlBase.bot_username,
|
||||
request_write_access=TestLoginUrlBase.request_write_access,
|
||||
)
|
||||
|
||||
|
||||
class TestLoginUrl:
|
||||
class TestLoginUrlBase:
|
||||
url = "http://www.google.com"
|
||||
forward_text = "Send me forward!"
|
||||
bot_username = "botname"
|
||||
request_write_access = True
|
||||
|
||||
|
||||
class TestLoginUrlWithoutRequest(TestLoginUrlBase):
|
||||
def test_slot_behaviour(self, login_url, mro_slots):
|
||||
for attr in login_url.__slots__:
|
||||
assert getattr(login_url, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -31,7 +31,7 @@ from telegram import (
|
|||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="class",
|
||||
scope="module",
|
||||
params=[
|
||||
MenuButton.DEFAULT,
|
||||
MenuButton.WEB_APP,
|
||||
|
@ -43,7 +43,7 @@ def scope_type(request):
|
|||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="class",
|
||||
scope="module",
|
||||
params=[
|
||||
MenuButtonDefault,
|
||||
MenuButtonCommands,
|
||||
|
@ -60,7 +60,7 @@ def scope_class(request):
|
|||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="class",
|
||||
scope="module",
|
||||
params=[
|
||||
(MenuButtonDefault, MenuButton.DEFAULT),
|
||||
(MenuButtonCommands, MenuButton.COMMANDS),
|
||||
|
@ -76,24 +76,26 @@ def scope_class_and_type(request):
|
|||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def menu_button(scope_class_and_type):
|
||||
# We use de_json here so that we don't have to worry about which class gets which arguments
|
||||
return scope_class_and_type[0].de_json(
|
||||
dict(
|
||||
type=scope_class_and_type[1],
|
||||
text=TestMenuButton.text,
|
||||
web_app=TestMenuButton.web_app.to_dict(),
|
||||
text=TestMenuButtonselfBase.text,
|
||||
web_app=TestMenuButtonselfBase.web_app.to_dict(),
|
||||
),
|
||||
bot=None,
|
||||
)
|
||||
|
||||
|
||||
# All the scope types are very similar, so we test everything via parametrization
|
||||
class TestMenuButton:
|
||||
class TestMenuButtonselfBase:
|
||||
text = "button_text"
|
||||
web_app = WebAppInfo(url="https://python-telegram-bot.org/web_app")
|
||||
|
||||
|
||||
# All the scope types are very similar, so we test everything via parametrization
|
||||
class TestMenuButtonWithoutRequest(TestMenuButtonselfBase):
|
||||
def test_slot_behaviour(self, menu_button, mro_slots):
|
||||
for attr in menu_button.__slots__:
|
||||
assert getattr(menu_button, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
|
|
@ -66,13 +66,13 @@ from tests.auxil.bot_method_checks import (
|
|||
from tests.test_passport import RAW_PASSPORT_DATA
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def message(bot):
|
||||
message = Message(
|
||||
message_id=TestMessage.id_,
|
||||
date=TestMessage.date,
|
||||
chat=copy(TestMessage.chat),
|
||||
from_user=copy(TestMessage.from_user),
|
||||
message_id=TestMessageBase.id_,
|
||||
date=TestMessageBase.date,
|
||||
chat=copy(TestMessageBase.chat),
|
||||
from_user=copy(TestMessageBase.from_user),
|
||||
)
|
||||
message.set_bot(bot)
|
||||
message._unfreeze()
|
||||
|
@ -271,17 +271,17 @@ def message(bot):
|
|||
)
|
||||
def message_params(bot, request):
|
||||
message = Message(
|
||||
message_id=TestMessage.id_,
|
||||
from_user=TestMessage.from_user,
|
||||
date=TestMessage.date,
|
||||
chat=TestMessage.chat,
|
||||
message_id=TestMessageBase.id_,
|
||||
from_user=TestMessageBase.from_user,
|
||||
date=TestMessageBase.date,
|
||||
chat=TestMessageBase.chat,
|
||||
**request.param,
|
||||
)
|
||||
message.set_bot(bot)
|
||||
return message
|
||||
|
||||
|
||||
class TestMessage:
|
||||
class TestMessageBase:
|
||||
id_ = 1
|
||||
from_user = User(2, "testuser", False)
|
||||
date = datetime.utcnow()
|
||||
|
@ -347,6 +347,13 @@ class TestMessage:
|
|||
caption_entities=[MessageEntity(**e) for e in test_entities_v2],
|
||||
)
|
||||
|
||||
|
||||
class TestMessageWithoutRequest(TestMessageBase):
|
||||
def test_slot_behaviour(self, message, mro_slots):
|
||||
for attr in message.__slots__:
|
||||
assert getattr(message, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(message)) == len(set(mro_slots(message))), "duplicate slot"
|
||||
|
||||
def test_all_possibilities_de_json_and_to_dict(self, bot, message_params):
|
||||
new = Message.de_json(message_params.to_dict(), bot)
|
||||
assert new.api_kwargs == {}
|
||||
|
@ -358,10 +365,26 @@ class TestMessage:
|
|||
for slot in new.__slots__:
|
||||
assert not isinstance(new[slot], dict)
|
||||
|
||||
def test_slot_behaviour(self, message, mro_slots):
|
||||
for attr in message.__slots__:
|
||||
assert getattr(message, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(message)) == len(set(mro_slots(message))), "duplicate slot"
|
||||
def test_equality(self):
|
||||
id_ = 1
|
||||
a = Message(id_, self.date, self.chat, from_user=self.from_user)
|
||||
b = Message(id_, self.date, self.chat, from_user=self.from_user)
|
||||
c = Message(id_, self.date, Chat(123, Chat.GROUP), from_user=User(0, "", False))
|
||||
d = Message(0, self.date, self.chat, from_user=self.from_user)
|
||||
e = Update(id_)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_parse_entity(self):
|
||||
text = (
|
||||
|
@ -563,7 +586,7 @@ class TestMessage:
|
|||
expected = b"\\U0001f469\\u200d\\U0001f469\\u200d *ABC*".decode("unicode-escape")
|
||||
bold_entity = MessageEntity(type=MessageEntity.BOLD, offset=7, length=3)
|
||||
message = Message(
|
||||
1, self.from_user, self.date, self.chat, text=text, entities=[bold_entity]
|
||||
1, self.date, self.chat, self.from_user, text=text, entities=[bold_entity]
|
||||
)
|
||||
assert expected == message.text_markdown
|
||||
|
||||
|
@ -1826,34 +1849,3 @@ class TestMessage:
|
|||
|
||||
monkeypatch.setattr(message.get_bot(), "unpin_all_forum_topic_messages", make_assertion)
|
||||
assert await message.unpin_all_forum_topic_messages()
|
||||
|
||||
def test_equality(self):
|
||||
id_ = 1
|
||||
a = Message(
|
||||
id_,
|
||||
self.date,
|
||||
self.chat,
|
||||
from_user=self.from_user,
|
||||
)
|
||||
b = Message(
|
||||
id_,
|
||||
self.date,
|
||||
self.chat,
|
||||
from_user=self.from_user,
|
||||
)
|
||||
c = Message(id_, self.date, Chat(123, Chat.GROUP), from_user=User(0, "", False))
|
||||
d = Message(0, self.date, self.chat, from_user=self.from_user)
|
||||
e = Update(id_)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
from telegram import MessageAutoDeleteTimerChanged, VideoChatEnded
|
||||
|
||||
|
||||
class TestMessageAutoDeleteTimerChanged:
|
||||
class TestMessageAutoDeleteTimerChangedWithoutRequest:
|
||||
message_auto_delete_time = 100
|
||||
|
||||
def test_slot_behaviour(self, mro_slots):
|
||||
|
|
|
@ -22,7 +22,7 @@ from telegram import MessageEntity, User
|
|||
from telegram.constants import MessageEntityType
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", params=MessageEntity.ALL_TYPES)
|
||||
@pytest.fixture(scope="module", params=MessageEntity.ALL_TYPES)
|
||||
def message_entity(request):
|
||||
type_ = request.param
|
||||
url = None
|
||||
|
@ -37,12 +37,14 @@ def message_entity(request):
|
|||
return MessageEntity(type_, 1, 3, url=url, user=user, language=language)
|
||||
|
||||
|
||||
class TestMessageEntity:
|
||||
class TestMessageEntityBase:
|
||||
type_ = "url"
|
||||
offset = 1
|
||||
length = 2
|
||||
url = "url"
|
||||
|
||||
|
||||
class TestMessageEntityWithoutRequest(TestMessageEntityBase):
|
||||
def test_slot_behaviour(self, message_entity, mro_slots):
|
||||
inst = message_entity
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -20,12 +20,12 @@ import pytest
|
|||
from telegram import MessageId, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def message_id():
|
||||
return MessageId(message_id=TestMessageId.m_id)
|
||||
return MessageId(message_id=TestMessageIdWithoutRequest.m_id)
|
||||
|
||||
|
||||
class TestMessageId:
|
||||
class TestMessageIdWithoutRequest:
|
||||
m_id = 1234
|
||||
|
||||
def test_slot_behaviour(self, message_id, mro_slots):
|
||||
|
|
|
@ -26,30 +26,26 @@ Because imports in pytest are intricate, we just run
|
|||
|
||||
with the TEST_WITH_OPT_DEPS environment variable set to False in addition to the regular test suite
|
||||
"""
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import _bot as bot
|
||||
from telegram._passport import credentials as credentials
|
||||
from tests.auxil.object_conversions import env_var_2_bool
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
from tests.conftest import TEST_WITH_OPT_DEPS
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
TEST_WITH_OPT_DEPS, reason="Only relevant if the optional dependency is not installed"
|
||||
)
|
||||
class TestNoPassport:
|
||||
def test_bot_init(self, bot_info, monkeypatch):
|
||||
class TestNoPassportWithoutRequest:
|
||||
def test_bot_init(self, bot_info):
|
||||
with pytest.raises(RuntimeError, match="passport"):
|
||||
bot.Bot(bot_info["token"], private_key=1, private_key_password=2)
|
||||
|
||||
def test_credentials_decrypt(self, monkeypatch):
|
||||
def test_credentials_decrypt(self):
|
||||
with pytest.raises(RuntimeError, match="passport"):
|
||||
credentials.decrypt(1, 1, 1)
|
||||
|
||||
def test_encrypted_credentials_decrypted_secret(self, monkeypatch):
|
||||
def test_encrypted_credentials_decrypted_secret(self):
|
||||
ec = credentials.EncryptedCredentials("data", "hash", "secret")
|
||||
with pytest.raises(RuntimeError, match="passport"):
|
||||
ec.decrypted_secret
|
||||
|
|
|
@ -21,22 +21,24 @@ import pytest
|
|||
from telegram import OrderInfo, ShippingAddress
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def order_info():
|
||||
return OrderInfo(
|
||||
TestOrderInfo.name,
|
||||
TestOrderInfo.phone_number,
|
||||
TestOrderInfo.email,
|
||||
TestOrderInfo.shipping_address,
|
||||
TestOrderInfoBase.name,
|
||||
TestOrderInfoBase.phone_number,
|
||||
TestOrderInfoBase.email,
|
||||
TestOrderInfoBase.shipping_address,
|
||||
)
|
||||
|
||||
|
||||
class TestOrderInfo:
|
||||
class TestOrderInfoBase:
|
||||
name = "name"
|
||||
phone_number = "phone_number"
|
||||
email = "email"
|
||||
shipping_address = ShippingAddress("GB", "", "London", "12 Grimmauld Place", "", "WC1")
|
||||
|
||||
|
||||
class TestOrderInfoWithoutRequest(TestOrderInfoBase):
|
||||
def test_slot_behaviour(self, order_info, mro_slots):
|
||||
for attr in order_info.__slots__:
|
||||
assert getattr(order_info, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
@ -44,10 +46,10 @@ class TestOrderInfo:
|
|||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
"name": TestOrderInfo.name,
|
||||
"phone_number": TestOrderInfo.phone_number,
|
||||
"email": TestOrderInfo.email,
|
||||
"shipping_address": TestOrderInfo.shipping_address.to_dict(),
|
||||
"name": self.name,
|
||||
"phone_number": self.phone_number,
|
||||
"email": self.email,
|
||||
"shipping_address": self.shipping_address.to_dict(),
|
||||
}
|
||||
order_info = OrderInfo.de_json(json_dict, bot)
|
||||
assert order_info.api_kwargs == {}
|
||||
|
|
|
@ -128,7 +128,7 @@ RAW_PASSPORT_DATA = {
|
|||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture(scope="module")
|
||||
def all_passport_data():
|
||||
return [
|
||||
{
|
||||
|
@ -214,12 +214,12 @@ def all_passport_data():
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_data(bot):
|
||||
return PassportData.de_json(RAW_PASSPORT_DATA, bot=bot)
|
||||
|
||||
|
||||
class TestPassport:
|
||||
class TestPassportBase:
|
||||
driver_license_selfie_file_id = "DgADBAADEQQAAkopgFNr6oi-wISRtAI"
|
||||
driver_license_selfie_file_unique_id = "d4e390cca57b4da5a65322b304762a12"
|
||||
driver_license_front_side_file_id = "DgADBAADxwMAApnQgVPK2-ckL2eXVAI"
|
||||
|
@ -241,6 +241,8 @@ class TestPassport:
|
|||
driver_license_selfie_credentials_file_hash = "Cila/qLXSBH7DpZFbb5bRZIRxeFW2uv/ulL0u0JNsYI="
|
||||
driver_license_selfie_credentials_secret = "tivdId6RNYNsvXYPppdzrbxOBuBOr9wXRPDcCvnXU7E="
|
||||
|
||||
|
||||
class TestPassportWithoutRequest(TestPassportBase):
|
||||
def test_slot_behaviour(self, passport_data, mro_slots):
|
||||
inst = passport_data
|
||||
for attr in inst.__slots__:
|
||||
|
@ -387,6 +389,37 @@ class TestPassport:
|
|||
assert email.type == "email"
|
||||
assert email.email == "fb3e3i47zt@dispostable.com"
|
||||
|
||||
def test_de_json_and_to_dict(self, bot):
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, bot)
|
||||
assert passport_data.api_kwargs == {}
|
||||
assert passport_data.to_dict() == RAW_PASSPORT_DATA
|
||||
|
||||
assert passport_data.decrypted_data
|
||||
assert passport_data.to_dict() == RAW_PASSPORT_DATA
|
||||
|
||||
def test_equality(self, passport_data):
|
||||
a = PassportData(passport_data.data, passport_data.credentials)
|
||||
b = PassportData(passport_data.data, passport_data.credentials)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
new_pp_data = deepcopy(passport_data)
|
||||
new_pp_data.credentials._unfreeze()
|
||||
new_pp_data.credentials.hash = "NOTAPROPERHASH"
|
||||
c = PassportData(new_pp_data.data, new_pp_data.credentials)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
def test_bot_init_invalid_key(self, bot):
|
||||
with pytest.raises(TypeError):
|
||||
Bot(bot.token, private_key="Invalid key!")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Bot(bot.token, private_key=b"Invalid key!")
|
||||
|
||||
def test_all_types(self, passport_data, bot, all_passport_data):
|
||||
credentials = passport_data.decrypted_credentials.to_dict()
|
||||
|
||||
|
@ -422,13 +455,6 @@ class TestPassport:
|
|||
assert isinstance(new, PassportData)
|
||||
assert new.decrypted_data
|
||||
|
||||
def test_bot_init_invalid_key(self, bot):
|
||||
with pytest.raises(TypeError):
|
||||
Bot(bot.token, private_key="Invalid key!")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Bot(bot.token, private_key=b"Invalid key!")
|
||||
|
||||
async def test_passport_data_okay_with_non_crypto_bot(self, bot):
|
||||
async with make_bot(token=bot.token) as b:
|
||||
assert PassportData.de_json(RAW_PASSPORT_DATA, bot=b)
|
||||
|
@ -506,26 +532,3 @@ class TestPassport:
|
|||
],
|
||||
)
|
||||
assert message
|
||||
|
||||
def test_de_json_and_to_dict(self, bot):
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, bot)
|
||||
assert passport_data.api_kwargs == {}
|
||||
assert passport_data.to_dict() == RAW_PASSPORT_DATA
|
||||
|
||||
assert passport_data.decrypted_data
|
||||
assert passport_data.to_dict() == RAW_PASSPORT_DATA
|
||||
|
||||
def test_equality(self, passport_data):
|
||||
a = PassportData(passport_data.data, passport_data.credentials)
|
||||
b = PassportData(passport_data.data, passport_data.credentials)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
passport_data.credentials._unfreeze()
|
||||
passport_data.credentials.hash = "NOTAPROPERHASH"
|
||||
c = PassportData(passport_data.data, passport_data.credentials)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
|
|
@ -21,23 +21,25 @@ import pytest
|
|||
from telegram import PassportElementErrorDataField, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_data_field():
|
||||
return PassportElementErrorDataField(
|
||||
TestPassportElementErrorDataField.type_,
|
||||
TestPassportElementErrorDataField.field_name,
|
||||
TestPassportElementErrorDataField.data_hash,
|
||||
TestPassportElementErrorDataField.message,
|
||||
TestPassportElementErrorDataFieldBase.type_,
|
||||
TestPassportElementErrorDataFieldBase.field_name,
|
||||
TestPassportElementErrorDataFieldBase.data_hash,
|
||||
TestPassportElementErrorDataFieldBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorDataField:
|
||||
class TestPassportElementErrorDataFieldBase:
|
||||
source = "data"
|
||||
type_ = "test_type"
|
||||
field_name = "test_field"
|
||||
data_hash = "data_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorDataFieldWithoutRequest(TestPassportElementErrorDataFieldBase):
|
||||
def test_slot_behaviour(self, passport_element_error_data_field, mro_slots):
|
||||
inst = passport_element_error_data_field
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorFile, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_file():
|
||||
return PassportElementErrorFile(
|
||||
TestPassportElementErrorFile.type_,
|
||||
TestPassportElementErrorFile.file_hash,
|
||||
TestPassportElementErrorFile.message,
|
||||
TestPassportElementErrorFileBase.type_,
|
||||
TestPassportElementErrorFileBase.file_hash,
|
||||
TestPassportElementErrorFileBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorFile:
|
||||
class TestPassportElementErrorFileBase:
|
||||
source = "file"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorFileWithoutRequest(TestPassportElementErrorFileBase):
|
||||
def test_slot_behaviour(self, passport_element_error_file, mro_slots):
|
||||
inst = passport_element_error_file
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorFiles, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_files():
|
||||
return PassportElementErrorFiles(
|
||||
TestPassportElementErrorFiles.type_,
|
||||
TestPassportElementErrorFiles.file_hashes,
|
||||
TestPassportElementErrorFiles.message,
|
||||
TestPassportElementErrorFilesBase.type_,
|
||||
TestPassportElementErrorFilesBase.file_hashes,
|
||||
TestPassportElementErrorFilesBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorFiles:
|
||||
class TestPassportElementErrorFilesBase:
|
||||
source = "files"
|
||||
type_ = "test_type"
|
||||
file_hashes = ["hash1", "hash2"]
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorFilesWithoutRequest(TestPassportElementErrorFilesBase):
|
||||
def test_slot_behaviour(self, passport_element_error_files, mro_slots):
|
||||
inst = passport_element_error_files
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorFrontSide, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_front_side():
|
||||
return PassportElementErrorFrontSide(
|
||||
TestPassportElementErrorFrontSide.type_,
|
||||
TestPassportElementErrorFrontSide.file_hash,
|
||||
TestPassportElementErrorFrontSide.message,
|
||||
TestPassportElementErrorFrontSideBase.type_,
|
||||
TestPassportElementErrorFrontSideBase.file_hash,
|
||||
TestPassportElementErrorFrontSideBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorFrontSide:
|
||||
class TestPassportElementErrorFrontSideBase:
|
||||
source = "front_side"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorFrontSideWithoutRequest(TestPassportElementErrorFrontSideBase):
|
||||
def test_slot_behaviour(self, passport_element_error_front_side, mro_slots):
|
||||
inst = passport_element_error_front_side
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorReverseSide, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_reverse_side():
|
||||
return PassportElementErrorReverseSide(
|
||||
TestPassportElementErrorReverseSide.type_,
|
||||
TestPassportElementErrorReverseSide.file_hash,
|
||||
TestPassportElementErrorReverseSide.message,
|
||||
TestPassportElementErrorReverseSideBase.type_,
|
||||
TestPassportElementErrorReverseSideBase.file_hash,
|
||||
TestPassportElementErrorReverseSideBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorReverseSide:
|
||||
class TestPassportElementErrorReverseSideBase:
|
||||
source = "reverse_side"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorReverseSideWithoutRequest(TestPassportElementErrorReverseSideBase):
|
||||
def test_slot_behaviour(self, passport_element_error_reverse_side, mro_slots):
|
||||
inst = passport_element_error_reverse_side
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorDataField, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_selfie():
|
||||
return PassportElementErrorSelfie(
|
||||
TestPassportElementErrorSelfie.type_,
|
||||
TestPassportElementErrorSelfie.file_hash,
|
||||
TestPassportElementErrorSelfie.message,
|
||||
TestPassportElementErrorSelfieBase.type_,
|
||||
TestPassportElementErrorSelfieBase.file_hash,
|
||||
TestPassportElementErrorSelfieBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorSelfie:
|
||||
class TestPassportElementErrorSelfieBase:
|
||||
source = "selfie"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorSelfieWithoutRequest(TestPassportElementErrorSelfieBase):
|
||||
def test_slot_behaviour(self, passport_element_error_selfie, mro_slots):
|
||||
inst = passport_element_error_selfie
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,25 @@ import pytest
|
|||
from telegram import PassportElementErrorDataField, PassportElementErrorTranslationFile
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_translation_file():
|
||||
return PassportElementErrorTranslationFile(
|
||||
TestPassportElementErrorTranslationFile.type_,
|
||||
TestPassportElementErrorTranslationFile.file_hash,
|
||||
TestPassportElementErrorTranslationFile.message,
|
||||
TestPassportElementErrorTranslationFileBase.type_,
|
||||
TestPassportElementErrorTranslationFileBase.file_hash,
|
||||
TestPassportElementErrorTranslationFileBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFile:
|
||||
class TestPassportElementErrorTranslationFileBase:
|
||||
source = "translation_file"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFileWithoutRequest(
|
||||
TestPassportElementErrorTranslationFileBase
|
||||
):
|
||||
def test_slot_behaviour(self, passport_element_error_translation_file, mro_slots):
|
||||
inst = passport_element_error_translation_file
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,25 @@ import pytest
|
|||
from telegram import PassportElementErrorSelfie, PassportElementErrorTranslationFiles
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_translation_files():
|
||||
return PassportElementErrorTranslationFiles(
|
||||
TestPassportElementErrorTranslationFiles.type_,
|
||||
TestPassportElementErrorTranslationFiles.file_hashes,
|
||||
TestPassportElementErrorTranslationFiles.message,
|
||||
TestPassportElementErrorTranslationFilesBase.type_,
|
||||
TestPassportElementErrorTranslationFilesBase.file_hashes,
|
||||
TestPassportElementErrorTranslationFilesBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFiles:
|
||||
class TestPassportElementErrorTranslationFilesBase:
|
||||
source = "translation_files"
|
||||
type_ = "test_type"
|
||||
file_hashes = ["hash1", "hash2"]
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFilesWithoutRequest(
|
||||
TestPassportElementErrorTranslationFilesBase
|
||||
):
|
||||
def test_slot_behaviour(self, passport_element_error_translation_files, mro_slots):
|
||||
inst = passport_element_error_translation_files
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -21,21 +21,23 @@ import pytest
|
|||
from telegram import PassportElementErrorDataField, PassportElementErrorUnspecified
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_unspecified():
|
||||
return PassportElementErrorUnspecified(
|
||||
TestPassportElementErrorUnspecified.type_,
|
||||
TestPassportElementErrorUnspecified.element_hash,
|
||||
TestPassportElementErrorUnspecified.message,
|
||||
TestPassportElementErrorUnspecifiedBase.type_,
|
||||
TestPassportElementErrorUnspecifiedBase.element_hash,
|
||||
TestPassportElementErrorUnspecifiedBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorUnspecified:
|
||||
class TestPassportElementErrorUnspecifiedBase:
|
||||
source = "unspecified"
|
||||
type_ = "test_type"
|
||||
element_hash = "element_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorUnspecifiedWithoutRequest(TestPassportElementErrorUnspecifiedBase):
|
||||
def test_slot_behaviour(self, passport_element_error_unspecified, mro_slots):
|
||||
inst = passport_element_error_unspecified
|
||||
for attr in inst.__slots__:
|
||||
|
|
|
@ -29,21 +29,23 @@ from tests.auxil.bot_method_checks import (
|
|||
@pytest.fixture(scope="class")
|
||||
def passport_file(bot):
|
||||
pf = PassportFile(
|
||||
file_id=TestPassportFile.file_id,
|
||||
file_unique_id=TestPassportFile.file_unique_id,
|
||||
file_size=TestPassportFile.file_size,
|
||||
file_date=TestPassportFile.file_date,
|
||||
file_id=TestPassportFileBase.file_id,
|
||||
file_unique_id=TestPassportFileBase.file_unique_id,
|
||||
file_size=TestPassportFileBase.file_size,
|
||||
file_date=TestPassportFileBase.file_date,
|
||||
)
|
||||
pf.set_bot(bot)
|
||||
return pf
|
||||
|
||||
|
||||
class TestPassportFile:
|
||||
class TestPassportFileBase:
|
||||
file_id = "data"
|
||||
file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
file_size = 50
|
||||
file_date = 1532879128
|
||||
|
||||
|
||||
class TestPassportFileWithoutRequest(TestPassportFileBase):
|
||||
def test_slot_behaviour(self, passport_file, mro_slots):
|
||||
inst = passport_file
|
||||
for attr in inst.__slots__:
|
||||
|
@ -65,21 +67,6 @@ class TestPassportFile:
|
|||
assert passport_file_dict["file_size"] == passport_file.file_size
|
||||
assert passport_file_dict["file_date"] == passport_file.file_date
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, passport_file):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
result = kwargs["file_id"] == passport_file.file_id
|
||||
# we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File
|
||||
return File(file_id=result, file_unique_id=result)
|
||||
|
||||
assert check_shortcut_signature(PassportFile.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(
|
||||
passport_file.get_file, passport_file.get_bot(), "get_file"
|
||||
)
|
||||
assert await check_defaults_handling(passport_file.get_file, passport_file.get_bot())
|
||||
|
||||
monkeypatch.setattr(passport_file.get_bot(), "get_file", make_assertion)
|
||||
assert (await passport_file.get_file()).file_id == "True"
|
||||
|
||||
def test_equality(self):
|
||||
a = PassportFile(self.file_id, self.file_unique_id, self.file_size, self.file_date)
|
||||
b = PassportFile("", self.file_unique_id, self.file_size, self.file_date)
|
||||
|
@ -99,3 +86,18 @@ class TestPassportFile:
|
|||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, passport_file):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
result = kwargs["file_id"] == passport_file.file_id
|
||||
# we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File
|
||||
return File(file_id=result, file_unique_id=result)
|
||||
|
||||
assert check_shortcut_signature(PassportFile.get_file, Bot.get_file, ["file_id"], [])
|
||||
assert await check_shortcut_call(
|
||||
passport_file.get_file, passport_file.get_bot(), "get_file"
|
||||
)
|
||||
assert await check_defaults_handling(passport_file.get_file, passport_file.get_bot())
|
||||
|
||||
monkeypatch.setattr(passport_file.get_bot(), "get_file", make_assertion)
|
||||
assert (await passport_file.get_file()).file_id == "True"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue