diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 127a43f..4be529a 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -3,5 +3,5 @@ Fixes #__.
To do:
- [ ] ...
-Cuurent changes in PR:
+Current changes in PR:
- ...
diff --git a/README.md b/README.md
index c2204d8..e4e4357 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
collegamento v0.1.1
+collegamento v0.2.0
A tool that makes it much easier to make offload work when asyncio isn't an option.
diff --git a/collegamento/__init__.py b/collegamento/__init__.py
index 2731795..fdc6461 100644
--- a/collegamento/__init__.py
+++ b/collegamento/__init__.py
@@ -6,7 +6,6 @@
from .simple_client_server import ( # noqa: F401, E402
USER_FUNCTION,
CollegamentoError,
- Notification,
Request,
Response,
SimpleClient,
diff --git a/collegamento/files_variant.py b/collegamento/files_variant.py
index 44cf72a..5e81417 100644
--- a/collegamento/files_variant.py
+++ b/collegamento/files_variant.py
@@ -5,7 +5,6 @@
from .simple_client_server import (
USER_FUNCTION,
CollegamentoError,
- Notification,
Request,
SimpleClient,
SimpleServer,
@@ -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):
@@ -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"""
@@ -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"""
@@ -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):
@@ -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]
diff --git a/collegamento/simple_client_server/__init__.py b/collegamento/simple_client_server/__init__.py
index 1ae4f93..e49df62 100644
--- a/collegamento/simple_client_server/__init__.py
+++ b/collegamento/simple_client_server/__init__.py
@@ -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
diff --git a/collegamento/simple_client_server/client.py b/collegamento/simple_client_server/client.py
index 3cf7208..e336f42 100644
--- a/collegamento/simple_client_server/client.py
+++ b/collegamento/simple_client_server/client.py
@@ -5,7 +5,6 @@
from .misc import (
USER_FUNCTION,
CollegamentoError,
- Notification,
Request,
RequestQueueType,
Response,
@@ -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()
@@ -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,
diff --git a/collegamento/simple_client_server/misc.py b/collegamento/simple_client_server/misc.py
index 8b7a86b..6f5e7d4 100644
--- a/collegamento/simple_client_server/misc.py
+++ b/collegamento/simple_client_server/misc.py
@@ -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"""
@@ -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:
diff --git a/collegamento/simple_client_server/server.py b/collegamento/simple_client_server/server.py
index e4e1acd..718df1a 100644
--- a/collegamento/simple_client_server/server.py
+++ b/collegamento/simple_client_server/server.py
@@ -5,7 +5,6 @@
from .misc import (
USER_FUNCTION,
- Notification,
Request,
RequestQueueType,
Response,
@@ -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")
@@ -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:
@@ -54,11 +55,11 @@ 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"
)
@@ -66,14 +67,6 @@ def parse_line(self, message: Request | Notification) -> None:
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
@@ -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:
@@ -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)
@@ -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"]
diff --git a/docs/source/classes.rst b/docs/source/classes.rst
index c353fd4..40bde22 100644
--- a/docs/source/classes.rst
+++ b/docs/source/classes.rst
@@ -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``
@@ -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 ;).
diff --git a/docs/source/conf.py b/docs/source/conf.py
index e253d96..42b4788 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -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
diff --git a/docs/source/example-usage.rst b/docs/source/example-usage.rst
index 7864c5c..a3096ff 100644
--- a/docs/source/example-usage.rst
+++ b/docs/source/example-usage.rst
@@ -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
@@ -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()
diff --git a/docs/source/examples/class_example.rst b/docs/source/examples/class_example.rst
index c35833f..b4798bc 100644
--- a/docs/source/examples/class_example.rst
+++ b/docs/source/examples/class_example.rst
@@ -6,7 +6,7 @@ Class Example
from time import sleep
- from collegamento import FileClient, Request
+ from collegamento import FileClient, FileServer, Request
class MyClient:
@@ -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(" ")
diff --git a/docs/source/examples/file_example.rst b/docs/source/examples/file_example.rst
index 33c3fee..17f2720 100644
--- a/docs/source/examples/file_example.rst
+++ b/docs/source/examples/file_example.rst
@@ -6,10 +6,16 @@ File Example
from time import sleep
- from collegamento import USER_FUNCTION, FileClient, Request, Response
+ from collegamento import (
+ USER_FUNCTION,
+ FileClient,
+ FileServer,
+ Request,
+ Response,
+ )
- def split_str(arg: Request) -> list[str]:
+ def split_str(server: "FileServer", arg: Request) -> list[str]:
file = arg["file"] # type: ignore
return file.split(" ")
@@ -19,6 +25,7 @@ File Example
context = FileClient(commands)
context.update_file("test", "test contents")
+ sleep(1)
context.request({"command": "test", "file": "test"})
sleep(1)
diff --git a/docs/source/examples/simple_example.rst b/docs/source/examples/simple_example.rst
index e58ff13..6451b6e 100644
--- a/docs/source/examples/simple_example.rst
+++ b/docs/source/examples/simple_example.rst
@@ -4,12 +4,16 @@ Simple Example
.. code-block:: python
- from time import sleep
+ from collegamento import (
+ USER_FUNCTION,
+ Request,
+ Response,
+ SimpleClient,
+ SimpleServer,
+ )
- from collegamento import USER_FUNCTION, Request, Response, SimpleClient
-
- def foo(bar: Request) -> bool:
+ def foo(server: "SimpleServer", bar: Request) -> bool:
if bar["command"] == "test":
return True
return False
@@ -21,8 +25,6 @@ Simple Example
context.request({"command": "test"})
- sleep(1)
-
output: Response | None = context.get_response("test")
if output is not None and output["result"]: # type: ignore
print("Yippee! It worked!")
diff --git a/docs/source/variables.rst b/docs/source/variables.rst
index 7161d8f..8718369 100644
--- a/docs/source/variables.rst
+++ b/docs/source/variables.rst
@@ -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.
diff --git a/examples/class_example.py b/examples/class_example.py
index 02d55b9..f0143ca 100644
--- a/examples/class_example.py
+++ b/examples/class_example.py
@@ -1,6 +1,6 @@
from time import sleep
-from collegamento import FileClient, Request
+from collegamento import FileClient, FileServer, Request
class MyClient:
@@ -21,7 +21,7 @@ def check_split(self) -> list[str] | None:
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(" ")
diff --git a/examples/file_example.py b/examples/file_example.py
index a60e993..edf71b4 100644
--- a/examples/file_example.py
+++ b/examples/file_example.py
@@ -1,9 +1,15 @@
from time import sleep
-from collegamento import USER_FUNCTION, FileClient, Request, Response
+from collegamento import (
+ USER_FUNCTION,
+ FileClient,
+ FileServer,
+ Request,
+ Response,
+)
-def split_str(arg: Request) -> list[str]:
+def split_str(server: "FileServer", arg: Request) -> list[str]:
file = arg["file"] # type: ignore
return file.split(" ")
@@ -13,6 +19,7 @@ def main():
context = FileClient(commands)
context.update_file("test", "test contents")
+ sleep(1)
context.request({"command": "test", "file": "test"})
sleep(1)
diff --git a/examples/simple_example.py b/examples/simple_example.py
index 1b5441e..9cb46e2 100644
--- a/examples/simple_example.py
+++ b/examples/simple_example.py
@@ -1,9 +1,13 @@
-from time import sleep
+from collegamento import (
+ USER_FUNCTION,
+ Request,
+ Response,
+ SimpleClient,
+ SimpleServer,
+)
-from collegamento import USER_FUNCTION, Request, Response, SimpleClient
-
-def foo(bar: Request) -> bool:
+def foo(server: "SimpleServer", bar: Request) -> bool:
if bar["command"] == "test":
return True
return False
@@ -15,8 +19,6 @@ def main():
context.request({"command": "test"})
- sleep(1)
-
output: Response | None = context.get_response("test")
if output is not None and output["result"]: # type: ignore
print("Yippee! It worked!")
diff --git a/setup.py b/setup.py
index fb62ca3..f8a140c 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@
setup(
name="collegamento",
- version="0.1.1",
+ version="0.2.0",
description="Collegamento provides an easy to use Client/Server IPC backend",
author="Moosems",
author_email="moosems.j@gmail.com",
diff --git a/tests/test_file_variant.py b/tests/test_file_variant.py
index 025890e..df0a126 100644
--- a/tests/test_file_variant.py
+++ b/tests/test_file_variant.py
@@ -1,13 +1,19 @@
from time import sleep
-from collegamento import USER_FUNCTION, FileClient, Request, Response
+from collegamento import (
+ USER_FUNCTION,
+ FileClient,
+ FileServer,
+ Request,
+ Response,
+)
-def func(test_arg: Request) -> bool:
+def func(server: FileServer, request: Request) -> bool:
return True
-def split_str(arg: Request) -> list[str]:
+def split_str(server: FileServer, arg: Request) -> list[str]:
file = arg["file"] # type: ignore
return file.split(" ")
diff --git a/tests/test_simple.py b/tests/test_simple.py
index b4c623b..fcafcb4 100644
--- a/tests/test_simple.py
+++ b/tests/test_simple.py
@@ -1,9 +1,15 @@
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
@@ -14,9 +20,6 @@ def test_Client_Server():
context = SimpleClient(commands)
context.request({"command": "test"})
-
- sleep(1)
-
context.add_command("test1", foo)
sleep(1)