Skip to content

Commit

Permalink
Remove Notification
Browse files Browse the repository at this point in the history
  • Loading branch information
Moosems committed Aug 7, 2024
1 parent 614e3d1 commit f43c704
Show file tree
Hide file tree
Showing 17 changed files with 70 additions and 103 deletions.
1 change: 0 additions & 1 deletion collegamento/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from .simple_client_server import ( # noqa: F401, E402
USER_FUNCTION,
CollegamentoError,
Notification,
Request,
Response,
SimpleClient,
Expand Down
58 changes: 22 additions & 36 deletions collegamento/files_variant.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from logging import Logger
from multiprocessing.queues import Queue as GenericQueueClass
from typing import NotRequired
from typing import Mapping, NotRequired

from .simple_client_server import (
USER_FUNCTION,
CollegamentoError,
Notification,
Request,
SimpleClient,
SimpleServer,
Expand All @@ -16,11 +15,19 @@ class FileRequest(Request):
# There may be commands that don't require a file but some might
file: NotRequired[str]

def update_files(server: "FileServer", request: Request) -> None:
file: str = request["file"] # type: ignore

class FileNotification(Notification):
file: str
remove: bool
contents: NotRequired[str]
if request["remove"]: # type: ignore
server.logger.info(f"File {file} was requested for removal")
server.files.pop(file)
server.logger.info(f"File {file} has been removed")
else:
contents: str = request["contents"] # type: ignore
server.files[file] = contents
server.logger.info(
f"File {file} has been updated with new contents"
)


class FileClient(SimpleClient):
Expand All @@ -34,6 +41,8 @@ def __init__(
) -> None:
self.files: dict[str, str] = {}

commands["FileNotification"] = update_files

super().__init__(commands, id_max, FileServer)

def create_server(self) -> None:
Expand Down Expand Up @@ -71,14 +80,15 @@ def update_file(self, file: str, current_state: str) -> None:
self.files[file] = current_state

self.logger.debug("Creating notification dict")
notification: dict = {
file_notification: dict = {
"command": "FileNotification",
"file": file,
"remove": False,
"contents": self.files[file],
}

self.logger.debug("Notifying server of file update")
super().notify_server(notification)
self.request(file_notification)

def remove_file(self, file: str) -> None:
"""Removes a file from the main_server - external API"""
Expand All @@ -91,12 +101,13 @@ def remove_file(self, file: str) -> None:
)

self.logger.info("Notifying server of file deletion")
notification: dict = {
file_notification: dict = {
"command": "FileNotification",
"file": file,
"remove": True,
}
self.logger.debug("Notifying server of file removal")
super().notify_server(notification)
self.request(file_notification)


class FileServer(SimpleServer):
Expand All @@ -113,33 +124,8 @@ def __init__(

super().__init__(commands, response_queue, requests_queue, logger)

def parse_line(self, message: Request | Notification) -> None:
self.logger.debug("Parsing Message from user - pre-super")
id: int = message["id"]

if message["type"] == "notification":
self.logger.debug("Mesage is of type notification")

file: str = message["file"] # type: ignore

if message["remove"]: # type: ignore
self.logger.info(f"File {file} was requested for removal")
self.files.pop(file)
self.logger.info(f"File {file} has been removed")
else:
contents: str = message["contents"] # type: ignore
self.files[file] = contents
self.logger.info(
f"File {file} has been updated with new contents"
)

self.simple_id_response(id, False)
return

super().parse_line(message)

def handle_request(self, request: Request) -> None:
if "file" in request:
if "file" in request and request["command"] != "FileNotification":
file = request["file"]
request["file"] = self.files[file]

Expand Down
4 changes: 1 addition & 3 deletions collegamento/simple_client_server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from .client import SimpleClient # noqa: F401, E402
from .client import SimpleClient, SimpleServer # noqa: F401, E402
from .misc import ( # noqa: F401, E402
USER_FUNCTION,
CollegamentoError,
Notification,
Request,
RequestQueueType,
Response,
ResponseQueueType,
)
from .server import SimpleServer # noqa: F401, E402
18 changes: 0 additions & 18 deletions collegamento/simple_client_server/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from .misc import (
USER_FUNCTION,
CollegamentoError,
Notification,
Request,
RequestQueueType,
Response,
Expand All @@ -16,7 +15,6 @@

class SimpleClient:
"""The IPC class is used to talk to the server and run commands. The public API includes the following methods:
- SimpleClient.notify_server()
- SimpleClient.request()
- SimpleClient.add_command()
- SimpleClient.kill_IPC()
Expand Down Expand Up @@ -83,22 +81,6 @@ def create_message_id(self) -> int:

return id

def notify_server(
self,
notification_dict: dict,
) -> None:
self.logger.info("Creating notification for server")

id: int = self.create_message_id()
final_notification: Notification = {
"id": id,
"type": "notification",
}
final_notification.update(notification_dict)
self.logger.debug(f"Notification created: {final_notification}")
self.requests_queue.put(final_notification)
self.logger.info("Message sent")

def request(
self,
request_details: dict,
Expand Down
12 changes: 3 additions & 9 deletions collegamento/simple_client_server/misc.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Any
from multiprocessing.queues import Queue as GenericQueueClass
from typing import TYPE_CHECKING, Any, NotRequired, TypedDict

Expand All @@ -16,13 +17,6 @@ class Request(Message):

command: str


class Notification(Message):
"""Notifies the server to store or update its storage of something"""

contents: NotRequired[Any]


class Response(Message):
"""Server responses to requests and notifications"""

Expand All @@ -31,11 +25,11 @@ class Response(Message):
result: NotRequired[Any]


USER_FUNCTION = Callable[[Request], Any]
USER_FUNCTION = Callable[["SimpleServer", Request], Any] # type: ignore

if TYPE_CHECKING:
ResponseQueueType = GenericQueueClass[Response]
RequestQueueType = GenericQueueClass[Request | Notification]
RequestQueueType = GenericQueueClass[Request]
# Else, this is CPython < 3.12. We are now in the No Man's Land
# of Typing. In this case, avoid subscripting "GenericQueue". Ugh.
else:
Expand Down
17 changes: 4 additions & 13 deletions collegamento/simple_client_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from .misc import (
USER_FUNCTION,
Notification,
Request,
RequestQueueType,
Response,
Expand Down Expand Up @@ -54,26 +53,18 @@ def simple_id_response(self, id: int, cancelled: bool = True) -> None:
self.response_queue.put(response)
self.logger.info(f"Simple response for id {id} sent")

def parse_line(self, message: Request | Notification) -> None:
def parse_line(self, message: Request) -> None:
self.logger.debug("Parsing Message from user")
id: int = message["id"]

if message["type"] not in {"notification", "request"}:
if message["type"] != "request":
self.logger.warning(
f"Unknown type {type}. Sending simple response"
)
self.simple_id_response(id)
self.logger.debug(f"Simple response for id {id} sent")
return

if message["type"] == "notification":
self.logger.debug("Mesage is of type notification")
self.simple_id_response(id, False)
self.logger.debug(
f"Notification response for id {id} has been sent"
)
return

self.logger.info(f"Mesage with id {id} is of type request")
self.all_ids.append(id)
command: str = message["command"] # type: ignore
Expand All @@ -84,7 +75,7 @@ def parse_line(self, message: Request | Notification) -> None:
def cancel_all_ids_except_newest(self) -> None:
self.logger.info("Cancelling all old id's")

# NOTE: Used to be list comprehension but thats ugly
# NOTE: It used to be list comprehension but that was ugly
ids = []
for request in list(self.newest_requests.values()):
if request is not None:
Expand Down Expand Up @@ -132,7 +123,7 @@ def handle_request(self, request: Request) -> None:
response["cancelled"] = True
else:
self.logger.debug(f"Running user function for command {command}")
response["result"] = self.commands[command](request)
response["result"] = self.commands[command](self, request)

self.logger.debug("Response created")
self.response_queue.put(response)
Expand Down
15 changes: 14 additions & 1 deletion docs/source/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ The ``Response`` class is what is returned by the "ref:`SimpleClient Overview` o

The ``SimpleClient`` class can do:

- ``SimpleClient.notify_server(notification_dict: dict)`` (as a base class, this has no use case, but it will likely be used by any given subclass)
- ``SimpleClient.request(request_details: dict)`` (all details in request_details are specific to the command in the request_details)
- ``SimpleClient.add_command(name: str, command: USER_FUNCTION)`` (adds the function with the name provided that takes input of :ref:`Request Overview` and returns anything``
- ``SimpleClient.kill_IPC()`` (kills the IPC server)

.. _SimpleServer Overview:

``SimpleServer``
****************

The SimpleServer is a backend piece of code made visible for commands that can be given to a ``SimpleClient``. If you want to know more about it, check out the source code ;).

.. _FileClient Overview:

``FileClient``
Expand All @@ -46,3 +52,10 @@ The ``SimpleClient`` class can do:
- ``FileClient.remove_file(file: str)`` (removes the file specified from the system and notifies the server to fo the same)

This class also has some changed functionality. When you make a ``.request()`` and add a file to the request, it chnages the request's name to its contents for the function to use.

.. _FileServer Overview:

``FileServer``
**************

The ``FileServer`` is a backend piece of code made visible for commands that can be given to a ``FileClient``. If you want to know more about it, check out the source code ;).
7 changes: 4 additions & 3 deletions docs/source/example-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ Now that you have ``Collegamento`` installed, let's try running a simple example
from time import sleep
from collegamento import USER_FUNCTION, Request, Response, SimpleClient
from collegamento import USER_FUNCTION, Request, Response, SimpleClient, SimpleServer
def foo(bar: Request) -> bool:
def foo(server: "SimpleServer", bar: Request) -> bool:
if bar["command"] == "test":
return True
return False
Expand All @@ -26,12 +26,13 @@ Now that you have ``Collegamento`` installed, let's try running a simple example
sleep(1)
output: Response | None = context.get_response("test")
if output is not None and output["result"] == True: # type: ignore
if output is not None and output["result"]: # type: ignore
print("Yippee! It worked!")
else:
print("Aww, maybe your compute is just a little slow?")
context.kill_IPC()
if __name__ == "__main__":
main()
5 changes: 3 additions & 2 deletions docs/source/examples/class_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Class Example
from time import sleep
from collegamento import FileClient, Request
from collegamento import FileClient, Request, FileServer
class MyClient:
Expand All @@ -27,14 +27,15 @@ Class Example
return output["result"] # type: ignore
return output
def split_str(self, arg: Request) -> list[str]:
def split_str(self, server: FileServer, arg: Request) -> list[str]:
file = arg["file"] # type: ignore
return file.split(" ")
def main():
mc = MyClient()
mc.change_file("Test File")
sleep(1)
mc.request_split()
sleep(1)
Expand Down
5 changes: 3 additions & 2 deletions docs/source/examples/file_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ File Example
from time import sleep
from collegamento import USER_FUNCTION, FileClient, Request, Response
from collegamento import USER_FUNCTION, FileClient, Request, Response, FileServer
def split_str(arg: Request) -> list[str]:
def split_str(server: "FileServer", arg: Request) -> list[str]:
file = arg["file"] # type: ignore
return file.split(" ")
Expand All @@ -19,6 +19,7 @@ File Example
context = FileClient(commands)
context.update_file("test", "test contents")
sleep(1)
context.request({"command": "test", "file": "test"})
sleep(1)
Expand Down
4 changes: 2 additions & 2 deletions docs/source/examples/simple_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Simple Example
from time import sleep
from collegamento import USER_FUNCTION, Request, Response, SimpleClient
from collegamento import USER_FUNCTION, Request, Response, SimpleClient, SimpleServer
def foo(bar: Request) -> bool:
def foo(server: "SimpleServer", bar: Request) -> bool:
if bar["command"] == "test":
return True
return False
Expand Down
2 changes: 1 addition & 1 deletion docs/source/variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ Variables
``USER_FUNCTION``
*****************

``USER_FUNCTION`` is a type variable that simply states that any function that matches this type takes in a :ref:`Request Overview` class and returns anything or even nothing.
``USER_FUNCTION`` is a type variable that simply states that any function that matches this type takes in a :ref:`SimpleServer Overview` and :ref:`Request Overview` class (positionally) and returns anything or even nothing.
Loading

0 comments on commit f43c704

Please sign in to comment.