85 lines
2.8 KiB
Python
85 lines
2.8 KiB
Python
|
|
import nbformat
|
|
import threading
|
|
|
|
from multiprocessing import Pipe
|
|
from typing import Any
|
|
|
|
from core.correctness.validation import check_type, valid_string, \
|
|
valid_dict, valid_path, valid_list
|
|
from core.correctness.vars import VALID_VARIABLE_NAME_CHARS, VALID_CHANNELS
|
|
from core.functionality import wait
|
|
from core.meow import BaseRecipe, BaseHandler
|
|
|
|
class JupyterNotebookRecipe(BaseRecipe):
|
|
source:str
|
|
def __init__(self, name:str, recipe:Any, parameters:dict[str,Any]={},
|
|
requirements:dict[str,Any]={}, source:str=""):
|
|
super().__init__(name, recipe, parameters, requirements)
|
|
self._is_valid_source(source)
|
|
self.source = source
|
|
|
|
def _is_valid_source(self, source:str)->None:
|
|
if source:
|
|
valid_path(source, extension=".ipynb", min_length=0)
|
|
|
|
def _is_valid_recipe(self, recipe:dict[str,Any])->None:
|
|
check_type(recipe, dict)
|
|
nbformat.validate(recipe)
|
|
|
|
def _is_valid_parameters(self, parameters:dict[str,Any])->None:
|
|
valid_dict(parameters, str, Any, strict=False, min_length=0)
|
|
for k in parameters.keys():
|
|
valid_string(k, VALID_VARIABLE_NAME_CHARS)
|
|
|
|
def _is_valid_requirements(self, requirements:dict[str,Any])->None:
|
|
valid_dict(requirements, str, Any, strict=False, min_length=0)
|
|
for k in requirements.keys():
|
|
valid_string(k, VALID_VARIABLE_NAME_CHARS)
|
|
|
|
class PapermillHandler(BaseHandler):
|
|
_worker:threading.Thread
|
|
_stop_pipe:Pipe
|
|
def __init__(self, inputs:list[VALID_CHANNELS])->None:
|
|
super().__init__(inputs)
|
|
self._worker = None
|
|
self._stop_pipe = Pipe()
|
|
|
|
def run(self)->None:
|
|
all_inputs = self.inputs + [self._stop_pipe[0]]
|
|
while True:
|
|
ready = wait(all_inputs)
|
|
|
|
if self._stop_pipe[0] in ready:
|
|
return
|
|
else:
|
|
for input in self.inputs:
|
|
if input in ready:
|
|
message = input.recv()
|
|
event, rule = message
|
|
self.handle(event, rule)
|
|
|
|
def start(self)->None:
|
|
if self._worker is None:
|
|
self._worker = threading.Thread(
|
|
target=self.run,
|
|
args=[])
|
|
self._worker.daemon = True
|
|
self._worker.start()
|
|
else:
|
|
raise RuntimeWarning("Repeated calls to start have no effect.")
|
|
|
|
def stop(self)->None:
|
|
if self._worker is None:
|
|
raise RuntimeWarning("Cannot stop thread that is not started.")
|
|
else:
|
|
self._stop_pipe[1].send(1)
|
|
self._worker.join()
|
|
|
|
def handle(self, event, rule)->None:
|
|
# TODO finish implementation and test
|
|
pass
|
|
|
|
def _is_valid_inputs(self, inputs:list[VALID_CHANNELS])->None:
|
|
valid_list(inputs, VALID_CHANNELS)
|