Skip to content

Commit

Permalink
Update to python 3.12 (#58)
Browse files Browse the repository at this point in the history
* Upgrade PythonTelegramBot
* Update to Python 3.12 in CI/CD
  • Loading branch information
juanitodread authored Feb 12, 2024
1 parent 5cebe5d commit 6159d69
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10.12
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.10.12
python-version: 3.12

- name: Install dependencies
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.10.12
- name: Set up Python 3.12
uses: actions/setup-python@v2
with:
python-version: 3.10.12
python-version: 3.12
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
flake8==5.0.4
pytest==7.4.0
python-telegram-bot==13.5
flake8==7.0.0
pytest==8.0.0
python-telegram-bot==20.7
requests==2.31.0
tweepy==4.14.0
1 change: 0 additions & 1 deletion src/clients/twitter/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def __init__(self, config: TwitterConfig) -> None:

print('Twitter Client v2 created')


def post(self, tweet: str) -> PublishedTweet:
status = self._client.create_tweet(text=tweet)

Expand Down
166 changes: 166 additions & 0 deletions src/telegram_bot_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import json
import asyncio
from telegram import Update
from telegram.ext import (
ApplicationBuilder,
Application,
ContextTypes,
CommandHandler,
MessageHandler,
filters,
)

from src.gorrion import Gorrion
from src.config import Config
from src.clients.spotify import Spotify, NotPlayingError
from src.clients.twitter import Twitter, TwitterLocal
from src.clients.musixmatch import Musixmatch


application = ApplicationBuilder().token(Config.TELEGRAM_TOKEN).build()


def _new_gorrion(local_mode: bool, delay_mode: bool) -> Gorrion:
spotify = Spotify(Config.get_spotify_config())
musixmatch = Musixmatch(Config.get_musixmatch_config())

twitter_config = Config.get_twitter_config()
twitter_config.retweet_delay = delay_mode
twitter = (TwitterLocal(twitter_config)
if local_mode else Twitter(twitter_config))

return Gorrion(spotify, twitter, musixmatch)


class TelegramBot:
def __init__(self, gorrion: Gorrion) -> None:
self._gorrion = gorrion
self._commands = ['/start', '/playing', '/lyric', '/album', '/tracks', '/about']

async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await self._send_message(update, context, 'Welcome to Gorrion Bot 🐦🤖')
await self._send_message(update, context, f'Supported commands are: \n\n{"\n".join(self._commands)}')

async def playing(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
song = self._gorrion.playing()

await self._send_message(update, context, song.tweet)

async def playing_with_lyrics(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
tweets = self._gorrion.playing_with_lyrics()
song, *lyrics = tweets

await self._send_message(update, context, song.tweet)

if lyrics:
for lyric in lyrics:
await self._send_message(update, context, lyric.tweet)

async def playing_album(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
song = self._gorrion.playing_album()

await self._send_message(update, context, song.tweet)

async def playing_album_with_tracks(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
tweets = self._gorrion.playing_album_with_tracks()
album, *tracks = tweets

await self._send_message(update, context, album.tweet)

if tracks:
for track in tracks:
await self._send_message(update, context, track.tweet)

async def about(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await self._send_message(update, context, 'Made with ❤️ by @juanitodread')

async def any_other_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await self._send_message(update, context, f'I can only reply to you based on the commands: \n\n{"\n".join(self._commands)}')

async def _send_message(self, update: Update | object, context: ContextTypes.DEFAULT_TYPE, message: str) -> None:
if not self._is_bot_owner(update.effective_chat.username):
await context.bot.send_message(
chat_id=update.effective_chat.id,
text='Sorry 💔. I can only chat with my creator 🧙🏼.'
)
return

await context.bot.send_message(chat_id=update.effective_chat.id, text=message)

async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
print(f'Error ({type(context.error)}): {context.error}')

match context.error:
case NotPlayingError():
await self._send_message(update, context, str(context.error))
case _:
await self._send_message(update, context, 'Service not available')

def _is_bot_owner(self, username: str | None) -> bool:
if not Config.TELEGRAM_OWNER_USERNAME or len(Config.TELEGRAM_OWNER_USERNAME) == 0:
raise Exception('TELEGRAM_OWNER_USERNAME variable is wrong')

return Config.TELEGRAM_OWNER_USERNAME == username


def _setup_app(app: Application, bot: TelegramBot) -> Application:
start_handler = CommandHandler('start', bot.start)
application.add_handler(start_handler)

playing_handler = CommandHandler('playing', bot.playing)
application.add_handler(playing_handler)

lyric_handler = CommandHandler('lyric', bot.playing_with_lyrics)
application.add_handler(lyric_handler)

album_handler = CommandHandler('album', bot.playing_album)
application.add_handler(album_handler)

tracks_handler = CommandHandler('tracks', bot.playing_album_with_tracks)
application.add_handler(tracks_handler)

about_handler = CommandHandler('about', bot.about)
application.add_handler(about_handler)

any_other_message_handler = MessageHandler(filters.TEXT & (~filters.COMMAND), bot.any_other_message)
application.add_handler(any_other_message_handler)

application.add_error_handler(bot._on_error)

return app


def _do_work_local(event, context) -> None:
gorrion = _new_gorrion(local_mode=True, delay_mode=False)
bot = TelegramBot(gorrion)

app = _setup_app(application, bot)
app.run_polling(allowed_updates=Update.ALL_TYPES)


async def _do_work_lambda(event, context) -> dict:
gorrion = _new_gorrion(local_mode=False, delay_mode=False)
bot = TelegramBot(gorrion)

app = _setup_app(application, bot)

try:
await app.initialize()
await app.process_update(Update.de_json(json.loads(event['body']), app.bot))
except Exception as error:
print(f'Error: {error}')

return {
'status_code': 200,
'body': {}
}


def do_work(event, context):
print(f'Event: {event}')

# run in lambda
return asyncio.get_event_loop().run_until_complete(_do_work_lambda(event, context))

# run in local
# _do_work_local(event, context)
76 changes: 29 additions & 47 deletions src/templates/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,86 +3,68 @@

@dataclass
class TweetBodyConfig:
with_track: bool
with_album: bool
with_artists: bool
with_tracks: bool
with_release_date: bool
with_track: bool = False
with_album: bool = False
with_artists: bool = False
with_tracks: bool = False
with_release_date: bool = False


@dataclass
class TweetFooterConfig:
with_gorrion_hashtags: bool
with_album_hashtag: bool
with_artists_hashtag: bool
with_song_media_link: bool
with_album_media_link: bool
with_gorrion_hashtags: bool = False
with_album_hashtag: bool = False
with_artists_hashtag: bool = False
with_song_media_link: bool = False
with_album_media_link: bool = False


@dataclass
class TweetConfig:
with_header: bool = field(init=False, default=False)
with_body: bool = field(init=False, default=False)
with_footer: bool = field(init=False, default=False)
body_config: TweetBodyConfig = field(
init=False,
default=TweetBodyConfig(
with_track=False,
with_album=False,
with_artists=False,
with_tracks=False,
with_release_date=False,
)
)
footer_config: TweetFooterConfig = field(
init=False,
default=TweetFooterConfig(
with_gorrion_hashtags=False,
with_album_hashtag=False,
with_artists_hashtag=False,
with_song_media_link=False,
with_album_media_link=False,
)
)
with_header: bool = False
with_body: bool = False
with_footer: bool = False
body_config: TweetBodyConfig = field(default_factory=TweetBodyConfig)
footer_config: TweetFooterConfig = field(default_factory=TweetFooterConfig)


@dataclass
class TweetSongConfig(TweetConfig):
with_header = True
with_body = True
with_footer = True
body_config = TweetBodyConfig(
with_header: bool = True
with_body: bool = True
with_footer: bool = True
body_config: TweetBodyConfig = field(default_factory=lambda: TweetBodyConfig(
with_track=True,
with_album=True,
with_artists=True,
with_tracks=False,
with_release_date=False,
)
footer_config = TweetFooterConfig(
))
footer_config: TweetFooterConfig = field(default_factory=lambda: TweetFooterConfig(
with_gorrion_hashtags=True,
with_album_hashtag=False,
with_artists_hashtag=True,
with_song_media_link=True,
with_album_media_link=False,
)
))


@dataclass
class TweetAlbumConfig(TweetConfig):
with_header = True
with_body = True
with_footer = True
body_config = TweetBodyConfig(
with_header: bool = True
with_body: bool = True
with_footer: bool = True
body_config: TweetBodyConfig = field(default_factory=lambda: TweetBodyConfig(
with_track=False,
with_album=True,
with_artists=True,
with_tracks=True,
with_release_date=True,
)
footer_config = TweetFooterConfig(
))
footer_config: TweetFooterConfig = field(default_factory=lambda: TweetFooterConfig(
with_gorrion_hashtags=True,
with_album_hashtag=True,
with_artists_hashtag=True,
with_song_media_link=False,
with_album_media_link=True,
)
))
4 changes: 2 additions & 2 deletions tests/templates/test_twitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_to_tweet_with_footer_only(self, album_fixture, song_config_fixture):
song_config_fixture.with_footer = True
template = TweetTemplate(album_fixture, song_config_fixture)

assert template.to_tweet() == ('#gorrion #NowPlaying\n\n'
assert template.to_tweet() == ('#gorrion #NowPlaying #ElyGuerra\n\n'
'http://spotify.com/track/1')

def test_to_tweet_default_config(self, album_fixture, config_fixture):
Expand Down Expand Up @@ -115,7 +115,7 @@ def test_footer_with_footer_true(self, album_fixture, song_config_fixture):
song_config_fixture.with_footer = True
template = TweetTemplate(album_fixture, song_config_fixture)

assert template.footer() == ('#gorrion #NowPlaying\n\n'
assert template.footer() == ('#gorrion #NowPlaying #ElyGuerra\n\n'
'http://spotify.com/track/1')

def test_footer_with_footer_false(self, album_fixture, song_config_fixture):
Expand Down

0 comments on commit 6159d69

Please sign in to comment.