Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[pylint]
good-names = id
min-public-methods = 1
min-public-methods = 0
Empty file added app/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions app/app_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from domain.event.message_received_event import MessageReceivedEvent


class AppClient():
def __init__(self, bot_client, event_bus):
self._bot_client = bot_client
self.event_bus = event_bus

self.event_bus.subscribe(self)

def start(self):
self._bot_client.run()

async def on_receive_event(self, event):
if isinstance(event, MessageReceivedEvent):
print("yolo")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an ellipsis + comment about the expected behavior.
Maybe remove the print ?


@staticmethod
def subscribed_to():
return [MessageReceivedEvent]
9 changes: 8 additions & 1 deletion app/discord_client.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import discord
from domain.event.message_received_event import MessageReceivedEvent


class DiscordClient():
def __init__(self, bot_secret_key):
def __init__(self, bot_secret_key, event_bus):
self._client = discord.Client()
self._bot_secret_key = bot_secret_key
self.event_bus = event_bus

self._client.on_message = self.on_message

def run(self):
self._client.run(self._bot_secret_key)

async def on_message(self, _message):
await self.event_bus.publish(MessageReceivedEvent())
5 changes: 5 additions & 0 deletions app/domain/event/message_received_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from shared.event.event import Event


class MessageReceivedEvent(Event):
pass
3 changes: 3 additions & 0 deletions app/shared/event/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Event():
def __init__(self, payload=None):
self.payload = payload
29 changes: 29 additions & 0 deletions app/shared/event/event_bus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class EventBus():
def __init__(self):
self._subscribers = {}

async def publish(self, event):
event_classes = [x for x in list(
map(lambda x: x.__name__, type(event).mro())) if x != 'object']
Comment on lines +6 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x is not a good variable name at all.
remove ambiguity? :

Suggested change
event_classes = [x for x in list(
map(lambda x: x.__name__, type(event).mro())) if x != 'object']
event_classes = [x for x in list(
map((lambda x: x.__name__), type(event).mro())) if x != 'object']

why map? :

Suggested change
event_classes = [x for x in list(
map(lambda x: x.__name__, type(event).mro())) if x != 'object']
event_classes = [x for x in
[x.__name__ for x in type(event).mro()]
if x != 'object']

Simpler solution:

Suggested change
event_classes = [x for x in list(
map(lambda x: x.__name__, type(event).mro())) if x != 'object']
event_classes = [x.__name__ for x in type(event).mro()
if x.__name__ != 'object']


subscribers = []
for event_class in event_classes:
if not event_class in self._subscribers.keys():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not x in y is not the "right" way.
x not in y is better.
and a key not in keys can be checked without .keys() if _subscribers is a dict:

Suggested change
if not event_class in self._subscribers.keys():
if event_class not in self._subscribers:

continue
subscribers += self._subscribers[event_class]

if not subscribers:
return

for subscriber in subscribers:
await subscriber.on_receive_event(event)

def subscribe(self, subscriber):
subscribed_events = list(
map(lambda event_class: event_class.__name__, subscriber.subscribed_to()))
Comment on lines +22 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List comprehension, create a map only to cast is into a list is not pythonic.

Suggested change
subscribed_events = list(
map(lambda event_class: event_class.__name__, subscriber.subscribed_to()))
subscribed_events = [event_class.__name__ for event_class in subscriber.subscribed_to()]


for event_class_name in subscribed_events:
if not event_class_name in self._subscribers.keys():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again here:

Suggested change
if not event_class_name in self._subscribers.keys():
if event_class_name not in self._subscribers:

self._subscribers[event_class_name] = []

self._subscribers[event_class_name].append(subscriber)
13 changes: 13 additions & 0 deletions app/shared/event/event_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from event import Event


class EventLogger():
def __init__(self):
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if __init__ will be filled with code in the future, prefer ellipsis to pass.
If not, then delete the __init__ method.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vikka connait pas ellipsis, tu peux détailler ? Quelle différence ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Et si __init__ n'est pas implémenter, autant ne pas le mettre non ? on l'ajoutera quand on en aura besoin.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ellipsis est .... Pas le caractère utf8, juste '.'*3.

Ellipsis est généralement reconnu comme préférable comme marqueur "WIP", tandis que pass comme "nothing to do here". Mais ellipsis étant très peu connu / utilisé, il n'y a pas de concensus solide ni de norme. Cette sémantique de "required, but not set yet" est quelque chose que j'ai compris à force de lire et consulter des échanges sur Python, Pythonic et le fonctionnement de python.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Et si __init__ n'est pas implémenter, autant ne pas le mettre non ? on l'ajoutera quand on en aura besoin.

C'est ce que je dis ici : "If not, then delete the init method.". Donc je plussoie.


async def on_receive_event(self, event):
print("Received event", type(event).__name__)

@staticmethod
def subscribed_to():
return [Event]
13 changes: 10 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
from os import environ, path
from dotenv import load_dotenv
from app.discord_client import DiscordClient

from app.app_client import AppClient
from app.shared.event.event_bus import EventBus
from app.shared.event.event_logger import EventLogger

if environ.get("BOT_ENV") == "development":
basedir = path.dirname(__file__)
load_dotenv(path.join(basedir, '.env.development'))

event_bus = EventBus()
event_logger = EventLogger()
event_bus.subscribe(event_logger)

client = DiscordClient(environ.get("DISCORD_BOT_SECRET_KEY"))
client.run()
discord_client = DiscordClient(
environ.get("DISCORD_BOT_SECRET_KEY"), event_bus)
app = AppClient(discord_client, event_bus)
app.start()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pylama==7.7.1
pylint==2.6.2
pyparsing==2.4.7
pytest==6.2.2
pytest-asyncio==0.14.0
pytest-mock==3.5.1
python-dateutil==2.8.1
python-dotenv==0.15.0
Expand Down
29 changes: 29 additions & 0 deletions tests/discord_app_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from app.app_client import AppClient
from stubs.discord_client_stub import DiscordClientStub
from app.shared.event.event_bus import EventBus
from app.domain.event.message_received_event import MessageReceivedEvent
from stubs.in_memory_event_logger import InMemoryEventLogger


import pytest


def test_app_run_bot_client_on_start():
event_bus = EventBus()
discord_client_stub = DiscordClientStub(event_bus)
app = AppClient(discord_client_stub, event_bus)
app.start()
assert discord_client_stub.is_start == True


@pytest.mark.asyncio
async def test_app_receive_event_from_bot_client():
event_bus = EventBus()
discord_client_stub = DiscordClientStub(event_bus)
event_logger = InMemoryEventLogger()
event_bus.subscribe(event_logger)
app = AppClient(discord_client_stub, event_bus)
app.start()

await discord_client_stub.trigger_event(MessageReceivedEvent())
assert len(event_logger.events), 1
10 changes: 10 additions & 0 deletions tests/stubs/discord_client_stub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class DiscordClientStub():
def __init__(self, event_bus):
self.is_start = False
self._event_bus = event_bus

def run(self):
self.is_start = True

async def trigger_event(self, event):
await self._event_bus.publish(event)
13 changes: 13 additions & 0 deletions tests/stubs/in_memory_event_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from app.shared.event.event import Event


class InMemoryEventLogger():
def __init__(self):
self.events = []

async def on_receive_event(self, event):
self.events.append(event)

@staticmethod
def subscribed_to():
return [Event]