Skip to content

Commit

Permalink
V0.2.0 (#3)
Browse files Browse the repository at this point in the history
* Remove Notification class (#2)

* Remove Notification

* Format

* Bump version

* Fix spelling error

* Add priority to certain commands

* Get priority commands actually working

* Fix examples
  • Loading branch information
Moosems authored Aug 7, 2024
1 parent 614e3d1 commit c1bf89b
Show file tree
Hide file tree
Showing 21 changed files with 129 additions and 117 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ Fixes #__.
To do:
- [ ] ...

Cuurent changes in PR:
Current changes in PR:
- ...
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1 align="center">collegamento v0.1.1</h1>
<h1 align="center">collegamento v0.2.0</h1>

A tool that makes it much easier to make offload work when asyncio isn't an option.

Expand Down
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
65 changes: 29 additions & 36 deletions collegamento/files_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from .simple_client_server import (
USER_FUNCTION,
CollegamentoError,
Notification,
Request,
SimpleClient,
SimpleServer,
Expand All @@ -17,10 +16,17 @@ class FileRequest(Request):
file: NotRequired[str]


class FileNotification(Notification):
file: str
remove: bool
contents: NotRequired[str]
def update_files(server: "FileServer", request: Request) -> None:
file: str = request["file"] # type: ignore

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,8 +40,12 @@ def __init__(
) -> None:
self.files: dict[str, str] = {}

commands["FileNotification"] = update_files

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

self.priority_commands = ["FileNotification"]

def create_server(self) -> None:
"""Creates the main_server through a subprocess - internal API"""

Expand Down Expand Up @@ -71,14 +81,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)
super().request(file_notification)

def remove_file(self, file: str) -> None:
"""Removes a file from the main_server - external API"""
Expand All @@ -91,12 +102,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)
super().request(file_notification)


class FileServer(SimpleServer):
Expand All @@ -111,35 +123,16 @@ def __init__(
) -> None:
self.files: dict[str, str] = {}

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)
super().__init__(
commands,
response_queue,
requests_queue,
logger,
["FileNotification"],
)

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
10 changes: 2 additions & 8 deletions collegamento/simple_client_server/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +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
33 changes: 19 additions & 14 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 All @@ -22,6 +21,7 @@ def __init__(
response_queue: GenericQueueClass,
requests_queue: GenericQueueClass,
logger: Logger,
priority_commands: list[str] = [],
) -> None:
self.logger: Logger = logger
self.logger.info("Starting server setup")
Expand All @@ -31,6 +31,7 @@ def __init__(
self.all_ids: list[int] = []
self.newest_ids: dict[str, int] = {}
self.newest_requests: dict[str, Request | None] = {}
self.priority_commands: list[str] = priority_commands

self.commands: dict[str, USER_FUNCTION] = commands
for command in self.commands:
Expand All @@ -54,26 +55,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 +77,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 +125,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 All @@ -155,7 +148,19 @@ def run_tasks(self) -> None:
self.cancel_all_ids_except_newest()

# Actual work
for request in list(self.newest_requests.values()):
requests_list: list[Request] = [
request
for request in self.newest_requests.values()
if request is not None
]
requests_list = sorted(
requests_list,
key=lambda request: (
request["command"] not in self.priority_commands,
),
)

for request in requests_list:
if request is None:
continue
command: str = request["command"]
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 ;).
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
project = "collegamento"
copyright = "2024, Moosems"
author = "Moosems"
release = "v0.1.1"
release = "v0.2.0"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
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()
4 changes: 2 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, FileServer, Request
class MyClient:
Expand All @@ -27,7 +27,7 @@ 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(" ")
Expand Down
Loading

0 comments on commit c1bf89b

Please sign in to comment.