Skip to content

Commit

Permalink
Merge 2ca6461 into 5ceb6f8
Browse files Browse the repository at this point in the history
  • Loading branch information
Eldinnie committed Aug 4, 2017
2 parents 5ceb6f8 + 2ca6461 commit 90b09a2
Show file tree
Hide file tree
Showing 87 changed files with 9,376 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
files: ^telegram/.*\.py$
args:
- --errors-only
- --disable=no-name-in-module,import-error
- --disable=import-error
10 changes: 6 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ branches:
cache:
directories:
- $HOME/.cache/pip
- $HOME/.pre-commit
before_cache:
- rm -f $HOME/.cache/pip/log/debug.log
- rm -f $HOME/.pre-commit/pre-commit.log

install:
- pip install coveralls
- pip install coveralls pytest-cov
- pip install -U wheel
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
- pip install -U -r requirements.txt
- pip install -U -r requirements-dev.txt
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then pip install ujson; fi

script:
- python travis.py
- pytest -vv --cov=telegram

after_success:
coveralls
109 changes: 109 additions & 0 deletions pytest_migrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Helper for migrating to pytests
Run it like::
python pytest_migration.py test_forcereply.py
"""

import re
import sys
from pathlib import Path

header = """#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2017
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]."""

CLASS = r'class (.*)Test\(BaseTest, unittest.TestCase\):(?:\r?\n)([\s\S]*)if __name__'
JSON_DICT = r'self.json_dict = (\{[\s\S]*\})([\s\S]*?def)'
CLASS_VARS = r' def setUp\(self\):\n([\s\S]*?def)'

if __name__ == '__main__':
original = Path('tests/' + sys.argv[1]).open('r', encoding='UTF-8').read()
new_text = header
new_text += '\nimport json\n\nimport pytest\n\n'

match = re.search(CLASS, original)
if not match:
match = re.search(CLASS[:-11], original)

name = match.group(1)
test_name = 'Test' + name

new_class = 'class {}:\n{}'.format(test_name, match.group(2))

imports = {name}
for find in re.finditer('telegram\.([^().]*)', new_class):
imports.add(find.group(1))
tg_imports = ', '.join(imports)
new_text += 'from telegram import {}{}{}\n\n'.format('(' if len(tg_imports) > 77 else '',
tg_imports,
')' if len(tg_imports) > 77 else '')

new_class = re.sub(r'telegram\.', '', new_class)
new_class = re.sub(r'self\.assertTrue\(isinstance\((.*), (.*)\)\)',
r'assert isinstance(\1, \2)', new_class)
new_class = re.sub(r'self\.assertTrue\(self\.is_json\((.*)\)\)', r'json.loads(\1)', new_class)
new_class = re.sub(r'self\.assertTrue\(self\.is_dict\((.*)\)\)',
r'assert isinstance(\1, dict)', new_class)
new_class = re.sub(r'self\.assert(True|False)\((.*)\)', r'assert \2 is \1', new_class)
new_class = re.sub(r'self\.assertIsNone\((.*)\)', r'assert \1 is None', new_class)
new_class = re.sub(r'self\.assertIsInstance\((.*), (.*)\)',
r'assert isinstance(\1, \2)', new_class)
new_class = re.sub(r'self\.assert(?:Dict)?Equals?\((.*), (.*)\)',
r'assert \1 == \2', new_class)
new_class = re.sub(r'self\.assertNotEquals?\((.*), (.*)\)', r'assert \1 != \2', new_class)
new_class = re.sub(r'self\.assertIs\((.*), (.*)\)', r'assert \1 is \2', new_class)
new_class = re.sub(r'self\.assertIsNot\((.*), (.*)\)', r'assert \1 is not \2', new_class)
new_class = re.sub(r'self\._bot', r'bot', new_class)
new_class = re.sub(r'self\._chat_id,', r'chat_id,', new_class)
new_class = re.sub(r'self\._id', 'self.id', new_class)

new_class = re.sub(r'def test_.*_(de|to)_(json|dict)\(self\):',
r'def test_\1_\2(self):', new_class)

name_lower = name.lower()
proper_name_lower = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
proper_name_lower = re.sub('([a-z0-9])([A-Z])', r'\1_\2', proper_name_lower).lower()
new_class.replace(name_lower, proper_name_lower)

json_dict = re.search(JSON_DICT, new_class)
if json_dict:
new_class = re.sub(JSON_DICT, r'\2', new_class)
new_text += '@pytest.fixture(scope=\'class\')\ndef json_dict():\n return '
new_text += json_dict.group(1).replace('self.', test_name + '.')
new_text += '\n\n'
new_text += '@pytest.fixture(scope=\'class\')\ndef {}():\n'.format(proper_name_lower)
args = []
for line in json_dict.group(1).replace('self.', test_name + '.').split(','):
match = re.search(r'\'(.*)\': (.*?\.[^,\s.]*)', line)
if match:
args.append('{}={}'.format(match.group(1), match.group(2)))
new_text += ' return {}({})\n\n'.format(name, ', '.join(args))

class_vars = re.search(CLASS_VARS, new_class)
if class_vars:
class_vars = class_vars.group(1)
class_vars = class_vars.replace(' ', '')
class_vars = class_vars.replace('self.', '')
class_vars = '\n'.join([' ' + x for x in class_vars.split('\n')])
new_class = re.sub(CLASS_VARS, class_vars, new_class)

new_class = re.sub(r'self.json_dict', r'json_dict', new_class)

new_text += new_class
new_file = Path('pytests/' + sys.argv[1]).open('w', encoding='UTF-8').write(new_text)
Empty file added pytests/__init__.py
Empty file.
55 changes: 55 additions & 0 deletions pytests/bots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2017
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Provide a bot to tests"""
import os
import sys

from platform import python_implementation

# Provide some public fallbacks so it's easy for contributors to run tests on their local machine
FALLBACKS = {
'token': '133505823:AAHZFMHno3mzVLErU5b5jJvaeG--qUyLyG0',
'payment_provider_token': '284685063:TEST:ZGJlMmQxZDI3ZTc3',
'chat_id': '12173560',
'group_id': '-49740850',
'channel_id': '@pythontelegrambottests'
}


def get(name, fallback):
full_name = '{0}-{1}-{2[0]}{2[1]}'.format(name, python_implementation(),
sys.version_info).upper()
# First try fullnames such as
# TOKEN-CPYTHON-33
# CHAT_ID-PYPY-27
val = os.getenv(full_name)
if val:
return val
# Then try short names
# TOKEN
# CHAT_ID
val = os.getenv(name.upper())
if val:
return val
# Otherwise go with the fallback
return fallback


def get_bot():
return {k: get(k, v) for k, v in FALLBACKS.items()}
112 changes: 112 additions & 0 deletions pytests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2017
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 logging
import os
import sys
from collections import defaultdict
from queue import Queue
from threading import Thread, Event
from time import sleep

import pytest

from pytests.bots import get_bot
from telegram import Bot
from telegram.ext import Dispatcher, JobQueue

TRAVIS = os.getenv('TRAVIS', False)

if TRAVIS:
pytest_plugins = ['pytests.travis_fold']


@pytest.fixture(scope='session')
def bot_info():
return get_bot()


@pytest.fixture(scope='session')
def bot(bot_info):
return Bot(bot_info['token'])


@pytest.fixture(scope='session')
def chat_id(bot_info):
return bot_info['chat_id']


@pytest.fixture(scope='session')
def group_id(bot_info):
return bot_info['group_id']


@pytest.fixture(scope='session')
def channel_id(bot_info):
return bot_info['channel_id']


@pytest.fixture(scope='session')
def provider_token(bot_info):
return bot_info['payment_provider_token']


def create_dp(bot):
# Dispatcher is heavy to init (due to many threads and such) so we have a single session
# scoped one here, but before each test, reset it (dp fixture below)
dispatcher = Dispatcher(bot, Queue(), job_queue=JobQueue(bot), workers=2)
thr = Thread(target=dispatcher.start)
thr.start()
sleep(2)
yield dispatcher
sleep(1)
if dispatcher.running:
dispatcher.stop()
thr.join()


@pytest.fixture(scope='session')
def _dp(bot):
for dp in create_dp(bot):
yield dp


@pytest.fixture(scope='function')
def dp(_dp):
# Reset the dispatcher first
while not _dp.update_queue.empty():
_dp.update_queue.get(False)
_dp.chat_data = defaultdict(dict)
_dp.user_data = defaultdict(dict)
_dp.handlers = {}
_dp.groups = []
_dp.error_handlers = []
_dp.__stop_event = Event()
_dp.__exception_event = Event()
_dp.__async_queue = Queue()
_dp.__async_threads = set()
if _dp._Dispatcher__singleton_semaphore.acquire(blocking=0):
Dispatcher._set_singleton(_dp)
yield _dp
Dispatcher._Dispatcher__singleton_semaphore.release()


def pytest_configure(config):
if sys.version_info >= (3,):
config.addinivalue_line('filterwarnings', 'ignore::ResourceWarning')
# TODO: Write so good code that we don't need to ignore ResourceWarnings anymore

0 comments on commit 90b09a2

Please sign in to comment.