Skip to content

Commit

Permalink
improved installing services, added cleancontract, added string utils…
Browse files Browse the repository at this point in the history
…, added processes
  • Loading branch information
douwevandermeij committed Apr 7, 2021
1 parent d67cc6e commit 7dc3f78
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 1 deletion.
9 changes: 9 additions & 0 deletions fractal/core/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ class Contract(Model):
pass


@dataclass
class CleanContract(Contract):
@classmethod
def clean(cls, **kwargs):
if "$type" in kwargs:
kwargs["type"] = kwargs["$type"]
return super(CleanContract, cls).clean(**kwargs)


class EnumModel(str, Enum):
@staticmethod
def values_dict():
Expand Down
Empty file.
8 changes: 8 additions & 0 deletions fractal/core/process/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from abc import ABC

from fractal.core.process.process_scope import ProcessScope


class Action(ABC):
def execute(self, scope: ProcessScope) -> ProcessScope:
pass
66 changes: 66 additions & 0 deletions fractal/core/process/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from dataclasses import asdict

from fractal.core.process.action import Action
from fractal.core.process.process_scope import ProcessScope
from fractal.core.specifications.generic.specification import Specification


class SetValueAction(Action):
def __init__(self, **kwargs):
self.kwargs = kwargs

def execute(self, scope: ProcessScope) -> ProcessScope:
return scope.update(ProcessScope(self.kwargs))


class IncreaseValueAction(Action):
def __init__(self, name, value):
self.name = name
self.value = value

def execute(self, scope: ProcessScope) -> ProcessScope:
scope[self.name] += self.value
return scope


class PrintAction(Action):
def __init__(self, text):
self.text = text

def execute(self, scope: ProcessScope) -> ProcessScope:
print(self.text)
return scope


class PrintValueAction(Action):
def __init__(self, name):
self.name = name

def execute(self, scope: ProcessScope) -> ProcessScope:
print(scope[self.name])
return scope


class AddEntityAction(Action):
def __init__(self, repository_key: str = "repository", **entity_defaults):
self.repository_key = repository_key
self.entity_defaults = entity_defaults

def execute(self, scope: ProcessScope) -> ProcessScope:
entity_class = scope[self.repository_key].entity
data = self.entity_defaults
if hasattr(scope, "contract"):
data.update(scope["contract"])
entity = entity_class(**data)
scope["entity"] = scope[self.repository_key].add(entity)
return scope


class FetchEntityAction(Action):
def __init__(self, specification: Specification, repository_key: str = "repository"):
self.specification = specification
self.repository_key = repository_key

def execute(self, scope: ProcessScope) -> ProcessScope:
scope["entity"] = scope[self.repository_key].find_one(self.specification)
return scope
43 changes: 43 additions & 0 deletions fractal/core/process/actions/control_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import Iterable, Optional

from fractal.core.process.action import Action
from fractal.core.process.process import Process
from fractal.core.process.process_scope import ProcessScope
from fractal.core.specifications.generic.specification import Specification


class IfElseAction(Action):
def __init__(self, specification: Specification, process_true: Process, process_false: Optional[Process] = None):
self.specification = specification
self.process_true = process_true
self.process_false = process_false

def execute(self, scope: ProcessScope) -> ProcessScope:
if self.specification.is_satisfied_by(scope):
scope.update(self.process_true.run(scope))
elif self.process_false:
scope.update(self.process_false.run(scope))
return scope


class WhileAction(Action):
def __init__(self, specification: Specification, process: Process):
self.specification = specification
self.process = process

def execute(self, scope: ProcessScope) -> ProcessScope:
while self.specification.is_satisfied_by(scope):
scope.update(self.process.run(scope))
return scope


class ForEachAction(Action):
def __init__(self, iterable: Iterable, process: Process):
self.iterable = iterable
self.process = process

def execute(self, scope: ProcessScope) -> ProcessScope:
for item in self.iterable:
scope["item"] = item
scope.update(self.process.run(scope))
return scope
16 changes: 16 additions & 0 deletions fractal/core/process/process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from typing import Optional, List

from fractal.core.process.action import Action
from fractal.core.process.process_scope import ProcessScope


class Process:
def __init__(self, actions: List[Action]):
self.actions = actions

def run(self, scope: Optional[ProcessScope] = None) -> ProcessScope:
if not scope:
scope = ProcessScope()
for action in self.actions:
scope.update(action.execute(scope))
return scope
25 changes: 25 additions & 0 deletions fractal/core/process/process_scope.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from typing import Optional, Dict


class ProcessScope:
def __init__(self, data: Optional[Dict] = None):
self.data = data or {}

def __getattr__(self, item):
return self.data.get(item)

def __getitem__(self, item):
return self.data.get(item)

def __setitem__(self, key, value):
self.data[key] = value

def __repr__(self):
return self.data.__repr__()

def update(self, scope: 'ProcessScope') -> 'ProcessScope':
self.data.update(scope.data)
return self

def get(self, key, default=None):
return self.data.get(key, default)
10 changes: 9 additions & 1 deletion fractal/core/utils/application_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from fractal.core.repositories import Repository
from fractal.core.services import Service
from fractal.core.utils.loggers import init_logging
from fractal.core.utils.string import camel_to_snake


class ApplicationContext(object):
Expand Down Expand Up @@ -72,7 +73,14 @@ def install_repository(self, repository):
self.repositories.append(repository)
return repository

def install_generator(self, generator_name, generator):
def install_service(self, service, *, name=""):
if not name:
name = camel_to_snake(service.__name__)
setattr(ApplicationContext, name, property(
lambda self: next(service.install(self))
))

def install_generator(self, generator_name, generator): # TODO deprecated
setattr(self, f"_{generator_name}", generator)

def get_service():
Expand Down
10 changes: 10 additions & 0 deletions fractal/core/utils/string.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import re


def camel_to_snake(name):
name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()


def snake_to_camel(name):
return ''.join(word.title() for word in name.split('_'))

0 comments on commit 7dc3f78

Please sign in to comment.