Skip to content

Commit

Permalink
Initial restructuring
Browse files Browse the repository at this point in the history
  • Loading branch information
Garulf committed Feb 27, 2024
1 parent 390b759 commit 6ce3345
Show file tree
Hide file tree
Showing 14 changed files with 105 additions and 314 deletions.
18 changes: 0 additions & 18 deletions pyflowlauncher/__init__.py

This file was deleted.

16 changes: 16 additions & 0 deletions pyflowlauncher/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from abc import ABC
import logging


_logger = logging.getLogger(__name__)


class Base(ABC):

_LOGGER = _logger.getChild("Base")

def __init__(self) -> None:
self._logger = logging.getLogger(__name__).getChild(self.__class__.__name__)

def __del__(self):
self._logger.debug(f"Destroying {self.__class__.__name__} instance")
56 changes: 0 additions & 56 deletions pyflowlauncher/event.py

This file was deleted.

28 changes: 0 additions & 28 deletions pyflowlauncher/jsonrpc.py

This file was deleted.

File renamed without changes.
33 changes: 33 additions & 0 deletions pyflowlauncher/jsonrpc/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import asyncio
import logging

from ..base import Base
from .models import JsonRPCRequest


_logger = logging.getLogger(__name__)


class Dispatcher(Base):

def __init__(self):
self._methods = {}

def add_method(self, func):
self._methods[func.__name__] = func
_logger.debug(f"Adding method {func.__name__} to dispatcher")
return func

def remove_method(self, func):
del self._methods[func.__name__]

async def await_maybe(self, func):
if asyncio.iscoroutine(func):
return await func
return func

async def dispatch(self, request: JsonRPCRequest):
method = self._methods.get(request['method'])
if method is None:
return {'error': 'method not found'}
return await self.await_maybe(method(*request['parameters']))
19 changes: 19 additions & 0 deletions pyflowlauncher/jsonrpc/ids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from itertools import count


class ID:

def __init__(self, start=1, step=1):
self._counter = count(start, step)
self._current = start

def __next__(self):
self._current = next(self._counter)
return self._current

def __iter__(self):
return self

@property
def current(self):
return self._current
14 changes: 14 additions & 0 deletions pyflowlauncher/jsonrpc/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import TypedDict


class JsonRPCRequest(TypedDict):
id: int
jsonrpc: str
method: str
parameters: list


class JsonRPCResponse(TypedDict):
id: int
jsonrpc: str
result: list
8 changes: 8 additions & 0 deletions pyflowlauncher/jsonrpc/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from ..base import Base
from ids import ID


class Server(Base):

def __init__(self, id: ID):
self.id = id
24 changes: 0 additions & 24 deletions pyflowlauncher/method.py

This file was deleted.

108 changes: 15 additions & 93 deletions pyflowlauncher/plugin.py
Original file line number Diff line number Diff line change
@@ -1,102 +1,24 @@
from __future__ import annotations

import sys
from functools import wraps
from typing import Any, Callable, Iterable, Optional, Type, Union
from pathlib import Path
import json
import asyncio

from pyflowlauncher.shared import logger

from .event import EventHandler
from .jsonrpc import JsonRPCClient
from .result import JsonRPCAction, ResultResponse
from .manifest import PluginManifestSchema, MANIFEST_FILE

Method = Callable[..., Union[ResultResponse, JsonRPCAction, None]]
from jsonrpcserver import method, async_dispatch as dispatch


class Plugin:

def __init__(self, methods: list[Method] | None = None) -> None:
self._logger = logger(self)
self._client = JsonRPCClient()
self._event_handler = EventHandler()
self._settings: dict[str, Any] = {}
if methods:
self.add_methods(methods)

def add_method(self, method: Method) -> str:
"""Add a method to the event handler."""
return self._event_handler.add_event(method)

def add_methods(self, methods: Iterable[Method]) -> None:
self._event_handler.add_events(methods)

def on_method(self, method: Method) -> Method:
@wraps(method)
def wrapper(*args, **kwargs):
return method(*args, **kwargs)
self._event_handler.add_event(wrapper)
return wrapper

def method(self, method: Method) -> Method:
"""Register a method to be called when the plugin is run."""
return self.on_method(method)

def add_exception_handler(self, exception: Type[Exception], handler: Callable[..., Any]) -> None:
"""Add exception handler to be called when an exception is raised in a method."""
self._event_handler.add_exception_handler(exception, handler)

def on_except(self, exception: Type[Exception]) -> Callable[..., Any]:
@wraps(exception)
def wrapper(handler: Callable[..., Any]) -> Callable[..., Any]:
self.add_exception_handler(exception, handler)
return handler
return wrapper

def action(self, method: Method, parameters: Optional[Iterable] = None) -> JsonRPCAction:
"""Register a method and return a JsonRPCAction that calls it."""
method_name = self.add_method(method)
return {"method": method_name, "parameters": parameters or []}
def __init__(self):
self.methods = {}

@property
def settings(self) -> dict:
if self._settings is None:
self._settings = {}
self._settings = self._client.recieve().get('settings', {})
return self._settings
def on_method(self, func):
self.methods[func.__name__] = func
return func

def run(self) -> None:
request = self._client.recieve()
method = request["method"]
parameters = request.get('parameters', [])
if sys.version_info >= (3, 10, 0):
feedback = asyncio.run(self._event_handler.trigger_event(method, *parameters))
else:
loop = asyncio.get_event_loop()
feedback = loop.run_until_complete(self._event_handler.trigger_event(method, *parameters))
if not feedback:
return
self._client.send(feedback)
async def run(self):
while True:
request = await self.receive_request()
response = await dispatch(request, methods=self.methods)
await self.send_response(response)

@property
def run_dir(self) -> Path:
"""Return the run directory of the plugin."""
return Path(sys.argv[0]).parent
async def receive_request(self):
pass

def root_dir(self) -> Path:
"""Return the root directory of the plugin."""
current_dir = self.run_dir
for part in current_dir.parts:
if current_dir.joinpath(MANIFEST_FILE).exists():
return current_dir
current_dir = current_dir.parent
raise FileNotFoundError(f"Could not find {MANIFEST_FILE} in {self.run_dir} or any parent directory.")
async def send_response(self, response):
pass

def manifest(self) -> PluginManifestSchema:
"""Return the plugin manifest."""
with open(self.root_dir() / MANIFEST_FILE, 'r', encoding='utf-8') as f:
manifest = json.load(f)
return manifest
Loading

0 comments on commit 6ce3345

Please sign in to comment.