Skip to content

Commit

Permalink
Update PTB to v13.3 (#106)
Browse files Browse the repository at this point in the history
* Upgrade PTB version and make adjustments for Persistence

* Update PTB to v13.3

* Use auto_pagination

* Fix orchestra scores

* Artificially up coverage

* coverage
  • Loading branch information
Bibo-Joshi committed Feb 21, 2021
1 parent 06822ec commit 92483af
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 136 deletions.
4 changes: 2 additions & 2 deletions bot/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ def back_up(context: CallbackContext) -> None:

def schedule_daily_job(dispatcher: Dispatcher) -> None:
"""
Schedules a job running daily at 2AM UTC which run :meth:`check_users`.
Schedules a job running daily at 2AM which runs :meth:`back_up`.
Args:
dispatcher: The :class:`telegram.ext.Dispatcher`.
"""
dispatcher.job_queue.run_daily(back_up, dtm.time(0, 0))
dispatcher.job_queue.run_daily(back_up, dtm.time(2, 0))
4 changes: 2 additions & 2 deletions bot/check_user_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def check_users(context: CallbackContext) -> None:

def schedule_daily_job(dispatcher: Dispatcher) -> None:
"""
Schedules a job running daily at 2AM UTC which run :meth:`check_users`.
Schedules a job running daily at 2AM which runs :meth:`check_users`.
Args:
dispatcher: The :class:`telegram.ext.Dispatcher`.
"""
dispatcher.job_queue.run_daily(check_users, datetime.time(0, 0))
dispatcher.job_queue.run_daily(check_users, datetime.time(2, 0))
31 changes: 8 additions & 23 deletions bot/editing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import datetime as dtm
import warnings
from copy import deepcopy
from typing import Dict, Callable, List, Union
from typing import Dict, Callable, List

from telegram import (
Update,
Expand All @@ -30,7 +30,6 @@
InlineQueryHandler,
BaseFilter,
)
from telegram.constants import MAX_INLINE_QUERY_RESULTS

from bot import (
ORCHESTRA_KEY,
Expand Down Expand Up @@ -371,34 +370,17 @@ def choose_member(update: Update, context: CallbackContext) -> str:
inline_query = update.inline_query
orchestra = context.bot_data[ORCHESTRA_KEY]

if inline_query.offset:
offset = int(inline_query.offset)
else:
offset = 0
next_offset: Union[str, int] = ''

members = sorted(list(orchestra.members.values()), key=lambda member: member.full_name)

# Telegram only likes up to 50 results
if len(members) > (offset + 1) * MAX_INLINE_QUERY_RESULTS:
next_offset = offset + 1
members = members[
offset * MAX_INLINE_QUERY_RESULTS : offset * MAX_INLINE_QUERY_RESULTS # noqa: E203
+ MAX_INLINE_QUERY_RESULTS
]
else:
members = members[offset * MAX_INLINE_QUERY_RESULTS :] # noqa: E203

results = [
InlineQueryResultArticle(
id=m.user_id,
id=f'edit {m.user_id}',
title=m.full_name,
input_message_content=InputTextMessageContent(m.user_id),
)
for m in members
]

inline_query.answer(results=results, next_offset=next_offset)
inline_query.answer(results=results, auto_pagination=True)

return CHOOSING_MEMBER

Expand Down Expand Up @@ -967,9 +949,12 @@ def build_editing_handler(admin: int) -> ConversationHandler:
MessageHandler((Filters.text & ~Filters.command), date_of_birth),
CallbackQueryHandler(date_of_birth),
],
ADDRESS: [MessageHandler(ADDRESS_FILTER, address), CallbackQueryHandler(address)],
ADDRESS: [
MessageHandler(ADDRESS_FILTER, address, run_async=True),
CallbackQueryHandler(address),
],
ADDRESS_CONFIRMATION: [
MessageHandler(ADDRESS_FILTER, address),
MessageHandler(ADDRESS_FILTER, address, run_async=True),
CallbackQueryHandler(address),
],
PHOTO: [
Expand Down
6 changes: 3 additions & 3 deletions bot/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
logger = logging.getLogger(__name__)


def handle_error(update: Update, context: CallbackContext) -> None:
def handle_error(update: object, context: CallbackContext) -> None:
"""
Informs the originator of the update that an error occurred and forwards the traceback to the
admin.
Expand All @@ -29,7 +29,7 @@ def handle_error(update: Update, context: CallbackContext) -> None:
logger.error(msg="Exception while handling an update:", exc_info=context.error)

# Inform sender of update, that something went wrong
if update and update.effective_message:
if isinstance(update, Update) and update.effective_message:
text = emojize(
'Huch, da ist etwas schief gelaufen :worried:. Ich melde es dem Hirsch :nerd_face:.',
use_aliases=True,
Expand All @@ -42,7 +42,7 @@ def handle_error(update: Update, context: CallbackContext) -> None:

# Gather information from the update
payload = ''
if update:
if isinstance(update, Update):
if update.effective_user:
payload += ' with the user {}'.format(
mention_html(update.effective_user.id, update.effective_user.first_name)
Expand Down
18 changes: 1 addition & 17 deletions bot/inline.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""This module contains functions for the inline mode."""
from typing import Union

from telegram import (
Update,
Expand Down Expand Up @@ -42,12 +41,6 @@ def search_users(update: Update, context: CallbackContext) -> None:
admin_id = context.bot_data[ADMIN_KEY]
user_id = update.effective_user.id

if inline_query.offset:
offset = int(inline_query.offset)
else:
offset = 0
next_offset: Union[str, int] = ''

members = [
m
for uid, m in orchestra.members.items()
Expand All @@ -59,15 +52,6 @@ def search_users(update: Update, context: CallbackContext) -> None:
else:
sorted_members = sorted(members, key=lambda m: m.compare_full_name_to(query), reverse=True)

# Telegram only likes up to 50 results
if len(sorted_members) > (offset + 1) * MEMBERS_PER_PAGE:
next_offset = offset + 1
sorted_members = sorted_members[
offset * MEMBERS_PER_PAGE : offset * MEMBERS_PER_PAGE + MEMBERS_PER_PAGE # noqa: E203
]
else:
sorted_members = sorted_members[offset * MEMBERS_PER_PAGE :] # noqa: E203

results = [
InlineQueryResultArticle(
id=m.user_id,
Expand All @@ -84,9 +68,9 @@ def search_users(update: Update, context: CallbackContext) -> None:

inline_query.answer(
results=results,
next_offset=next_offset,
switch_pm_text='Hilfe',
switch_pm_parameter=INLINE_HELP,
auto_pagination=True,
)


Expand Down
14 changes: 13 additions & 1 deletion bot/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
"""This module contains functions for setting up to bot at start up."""
import re
import warnings
from typing import List, Union, Dict

from telegram import BotCommand, Update
Expand Down Expand Up @@ -57,6 +58,10 @@
]
"""List[:class:`telegram.BotCommand`]: A list of commands of the bot."""

warnings.filterwarnings(
'ignore', message="BasePersistence.", module='telegram.ext.basepersistence'
)


def setup( # pylint: disable=R0913,R0914,R0915
dispatcher: Dispatcher,
Expand Down Expand Up @@ -198,7 +203,9 @@ def clear_conversation_status(update: Update, context: CallbackContext) -> None:
CommandHandler('start', registration.start, filters=Filters.text('/start'))
)
dispatcher.add_handler(
CallbackQueryHandler(registration.request_registration, pattern=REGISTRATION_PATTERN)
CallbackQueryHandler(
registration.request_registration, pattern=REGISTRATION_PATTERN, run_async=True
)
)
dispatcher.add_handler(registration.ACCEPT_REGISTRATION_HANDLER)
dispatcher.add_handler(registration.DENY_REGISTRATION_HANDLER)
Expand Down Expand Up @@ -257,6 +264,11 @@ def clear_conversation_status(update: Update, context: CallbackContext) -> None:
bot_data = dispatcher.bot_data
if not bot_data.get(ORCHESTRA_KEY):
bot_data[ORCHESTRA_KEY] = Orchestra()
else:
# We rebuild the orchestra on start up to make sure code changes are applied
old_orchestra = bot_data.pop(ORCHESTRA_KEY)
new_orchestra = old_orchestra.copy()
bot_data[ORCHESTRA_KEY] = new_orchestra
if not bot_data.get(PENDING_REGISTRATIONS_KEY):
bot_data[PENDING_REGISTRATIONS_KEY] = dict()
if not bot_data.get(DENIED_USERS_KEY):
Expand Down
15 changes: 11 additions & 4 deletions components/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def __init__(
self.date_of_birth = date_of_birth
self.photo_file_id = photo_file_id
self.allow_contact_sharing = allow_contact_sharing
self.user_score = UserScore(self)
self.user_score = UserScore()

# See https://github.com/python/mypy/issues/3004
self._instruments: List[Instrument] = []
Expand Down Expand Up @@ -638,15 +638,22 @@ def copy(self) -> 'Member':
"""
Returns: A (deep) copy of this member.
"""
# for backwards compatibility
if not hasattr(self, '_functions'):
self._functions = [] # pylint: disable=W0212 # type: ignore
if hasattr(self.user_score, 'member'):
del self.user_score.member # type: ignore # pylint: disable=E1101 # pragma: no cover
for score in self.user_score._high_score.values(): # pylint: disable=W0212 # type: ignore
if hasattr(score, 'member'): # pragma: no cover
del score.member # pragma: no cover

new_member = copy.deepcopy(self)
# for backwards compatibility@
if not hasattr(new_member, '_functions'):
new_member._functions = [] # pylint: disable=W0212 # type: ignore
if not hasattr(new_member, 'joined'):
new_member.joined = None
new_member.instruments = [
i for i in new_member.instruments if i in self.ALLOWED_INSTRUMENTS
]

return new_member

@classmethod
Expand Down
31 changes: 22 additions & 9 deletions components/orchestra.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,16 @@ def _score(self, attr: str) -> List[Score]:
else:
attr = f'{attr}s_score'

return sorted(
[
getattr(m.user_score, attr)
for m in self.members.values()
if getattr(m.user_score, attr).answers > 0
],
reverse=True,
) # noqa: E126
scores = {
member: getattr(member.user_score, attr)
for member in self.members.values()
if getattr(member.user_score, attr).answers > 0
}
membered_scores = []
for member, score in scores.items():
score.member = member
membered_scores.append(score)
return sorted(membered_scores, reverse=True)

def _score_text(self, attr: str, length: int = None, html: Optional[bool] = False) -> str:
sorted_scores = self._score(attr)
Expand Down Expand Up @@ -342,6 +344,17 @@ def overall_score_text(self, length: int = None, html: Optional[bool] = False) -
"""
return self._score_text('overall', length=length, html=html)

def copy(self) -> 'Orchestra':
"""
Returns a (deep) copy of this orchestra.
"""
new_orchestra = self.__class__()

for member in self.members.values():
new_orchestra.register_member(member.copy())

return new_orchestra

def __eq__(self, other: object) -> bool:
return False

Expand All @@ -364,7 +377,7 @@ def __eq__(self, other: object) -> bool:
'birthdays': 'Geburtstag',
'birthday': 'Geburtstag',
'photo_file_ids': 'Foto',
'photo_file_id': 'Photo',
'photo_file_id': 'Foto',
}
"""Dict[:obj:`str`, :obj:`str`]: A map from the names of the different properties of this
class to the human readable strings."""
Expand Down
26 changes: 8 additions & 18 deletions components/userscore.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,29 @@

import datetime as dt
from threading import Lock
from typing import Dict, TYPE_CHECKING
from typing import Dict
from collections import defaultdict

from components import PicklableBase
from components import Score

# We don't like circular imports
if TYPE_CHECKING:
from components import Member


class UserScore(PicklableBase):
"""
The high score of a single user. Keeps track of their game stats. :class:`components.UserScore`
instances are subscriptable: For each date ``day``, ``score[day]`` is a
:class:`components.Score` instance with the number of answers and correct answers given by the
user on that day. To add values, :meth:`add_to_score` should be the preferred method.
Attributes:
member (:class:`components.Member`): The member, this high score is associated with.
Args:
member: The member, this high score is associated with.
"""

def __init__(self, member: 'Member') -> None:
self.member = member

def __init__(self) -> None:
self._high_score_lock = Lock()
self._high_score: Dict[dt.date, Score] = defaultdict(self._default_factory)
self._high_score: Dict[dt.date, Score] = defaultdict(Score)

def _default_factory(self: 'UserScore') -> Score:
return Score(member=self.member)
@staticmethod
def _default_factory() -> Score:
# needed for backwards compatibility only. Can be dropped in future versions
return Score() # pragma: no cover

def __getitem__(self, date: dt.date) -> Score:
with self._high_score_lock:
Expand Down Expand Up @@ -72,7 +62,7 @@ def todays_score(self) -> Score:
return self[dt.date.today()]

def _cumulative_score(self, start: dt.date = None) -> Score:
c_score = Score(member=self.member)
c_score = Score()

with self._high_score_lock:
for date, score in self._high_score.items():
Expand Down
8 changes: 7 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"""The script that runs the bot."""
import logging
from configparser import ConfigParser

import pytz
from telegram import ParseMode
from telegram.ext import Updater, PicklePersistence, Defaults

Expand Down Expand Up @@ -37,7 +39,11 @@ def main() -> None:
# Create the Updater and pass it your bot's token.
# Make sure to set use_context=True to use the new context based callbacks
# Post version 12 this will no longer be necessary
defaults = Defaults(parse_mode=ParseMode.HTML, disable_notification=True)
defaults = Defaults(
parse_mode=ParseMode.HTML,
disable_notification=True,
tzinfo=pytz.timezone('Europe/Berlin')
)
persistence = PicklePersistence('akanamen_db', single_file=False)
updater = Updater(token, use_context=True, persistence=persistence, defaults=defaults)

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
python-telegram-bot[json]==12.8
python-telegram-bot[json]==13.3
emoji
geopy==1.21.0
vobject==0.9.6.1
Expand All @@ -7,6 +7,6 @@ python-dateutil==2.8.1
camelot-py[cv]
numpy
pandas
git+https://gitlab.com/HirschHeissIch/ptbstats.git@v1.2
git+https://gitlab.com/HirschHeissIch/ptbstats.git@v1.3
pyocclient==0.6
git+https://github.com/Bibo-Joshi/yourls-python.git@extensions
2 changes: 1 addition & 1 deletion tests/orchestra.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def date_of_birth():
def instrument():
number = random.randint(1, 3)
instruments_ = random.sample(
[i() for i in instruments.__dict__.values() if isinstance(i, type)], number
[i() for i in list(instruments.__dict__.values()) if isinstance(i, type)], number
)
return value_or_none(instruments_)

Expand Down
Loading

0 comments on commit 92483af

Please sign in to comment.