Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 63 additions & 38 deletions .osparc/demo_func/metadata.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name: ofs-demo_func
thumbnail: https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Test.svg/315px-Test.svg.png
description: ''
description: ""
key: simcore/services/comp/ofs-demo_func
version: 1.0.0
integration-version: 1.0.0
type: computational
authors:
- name: Pedro Crespo-Valero
email: [email protected]
affiliation: IT'IS Foundation
- name: Pedro Crespo-Valero
email: [email protected]
affiliation: IT'IS Foundation
contact: [email protected]
inputs:
index:
Expand All @@ -17,66 +17,91 @@ inputs:
type: ref_contentSchema
contentSchema:
title: Index
minimum: 1
type: integer
real_value:
label: real_value
description: Real value
type: ref_contentSchema
contentSchema:
title: Real_value
multipleOf: 2
type: number
string_value:
label: string_value
description: String value
type: ref_contentSchema
contentSchema:
title: String_value
minLength: 3
type: string
list_of_numbers:
label: list_of_numbers
description: List of numbers
type: ref_contentSchema
contentSchema:
title: List_of_numbers
type: array
items:
type: number
minimum: 0
flag:
label: flag
description: Flag
type: ref_contentSchema
contentSchema:
title: Flag
type: boolean
defaultValue: false
answer:
label: answer
description: Answer
type: ref_contentSchema
contentSchema:
title: Answers
description: An enumeration.
enum:
- "YES"
- "NO"
type: string
defaultValue: "NO"
complex_value:
label: complex_value
description: Complex value
type: ref_contentSchema
contentSchema:
title: Complex_value
$ref: '#/definitions/Complex'
definitions:
Complex:
title: Complex
type: object
properties:
real:
title: Real
default: 0.0
type: number
imag:
title: Imag
default: 0.0
type: number
title: Complex
type: object
properties:
real:
title: Real
description: This is the real part
default: 0.0
type: number
imag:
title: Imag
default: 0.0
minimum: 0.0
type: number
outputs:
out_1:
label: Out1 integer
description: ''
description: ""
type: ref_contentSchema
contentSchema:
title: Out1 integer
type: integer
out_2:
label: Out2 number
description: ''
description: ""
type: ref_contentSchema
contentSchema:
title: Out2 number
type: number
out_3:
label: Out3 <class 'osparc_function_services.demo_services.Complex'>
description: ''
label: Out3 integer
description: ""
type: ref_contentSchema
contentSchema:
title: Out3 <class 'osparc_function_services.demo_services.Complex'>
$ref: '#/definitions/Complex'
definitions:
Complex:
title: Complex
type: object
properties:
real:
title: Real
default: 0.0
type: number
imag:
title: Imag
default: 0.0
type: number
title: Out3 integer
type: boolean
14 changes: 13 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
{
"python.formatting.provider": "black"
"python.formatting.provider": "black",
"files.associations": {
".*rc": "ini",
".env*": "ini",
"*.logs*": "log",
"*.make": "makefile",
"**/requirements/*.in": "pip-requirements",
"**/requirements/*.txt": "pip-requirements",
"*logs.txt": "log",
"*Makefile": "makefile",
"docker-compose*.yml": "dockercompose",
"Dockerfile*": "dockerfile"
},
}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ clean: ## cleans all unversioned files in project and temp files create by this



include ./scripts/integration.make
include ./scripts/docker.make
include ./scripts/registry.make
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ services:
io.simcore.type: '{"type": "computational"}'
io.simcore.authors: '{"authors": [{"name": "Pedro Crespo-Valero", "email": "[email protected]", "affiliation": "IT''IS Foundation"}]}'
io.simcore.contact: '{"contact": "[email protected]"}'
io.simcore.inputs: '{"inputs": {"index": {"label": "index", "description": "Index", "type": "ref_contentSchema", "contentSchema": {"title": "Index", "type": "integer"}}, "real_value": {"label": "real_value", "description": "Real value", "type": "ref_contentSchema", "contentSchema": {"title": "Real_value", "type": "number"}}, "complex_value": {"label": "complex_value", "description": "Complex value", "type": "ref_contentSchema", "contentSchema": {"title": "Complex_value", "$ref": "#/definitions/Complex", "definitions": {"Complex": {"title": "Complex", "type": "object", "properties": {"real": {"title": "Real", "default": 0.0, "type": "number"}, "imag": {"title": "Imag", "default": 0.0, "type": "number"}}}}}}}}'
io.simcore.outputs: '{"outputs": {"out_1": {"label": "Out1 integer", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out1 integer", "type": "integer"}}, "out_2": {"label": "Out2 number", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out2 number", "type": "number"}}, "out_3": {"label": "Out3 <class ''osparc_function_services.demo_services.Complex''>", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out3 <class ''osparc_function_services.demo_services.Complex''>", "$ref": "#/definitions/Complex", "definitions": {"Complex": {"title": "Complex", "type": "object", "properties": {"real": {"title": "Real", "default": 0.0, "type": "number"}, "imag": {"title": "Imag", "default": 0.0, "type": "number"}}}}}}}}'
io.simcore.inputs: '{"inputs": {"index": {"label": "index", "description": "Index", "type": "ref_contentSchema", "contentSchema": {"title": "Index", "minimum": 1, "type": "integer"}}, "real_value": {"label": "real_value", "description": "Real value", "type": "ref_contentSchema", "contentSchema": {"title": "Real_value", "multipleOf": 2, "type": "number"}}, "string_value": {"label": "string_value", "description": "String value", "type": "ref_contentSchema", "contentSchema": {"title": "String_value", "minLength": 3, "type": "string"}}, "list_of_numbers": {"label": "list_of_numbers", "description": "List of numbers", "type": "ref_contentSchema", "contentSchema": {"title": "List_of_numbers", "type": "array", "items": {"type": "number", "minimum": 0}}}, "flag": {"label": "flag", "description": "Flag", "type": "ref_contentSchema", "contentSchema": {"title": "Flag", "type": "boolean"}, "defaultValue": false}}}'
io.simcore.outputs: '{"outputs": {"out_1": {"label": "Out1 integer", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out1 integer", "type": "integer"}}, "out_2": {"label": "Out2 number", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out2 number", "type": "number"}}, "out_3": {"label": "Out3 integer", "description": "", "type": "ref_contentSchema", "contentSchema": {"title": "Out3 integer", "type": "boolean"}}}}'
simcore.service.settings: '[{"name": "ContainerSpec", "type": "ContainerSpec", "value": {"Command": ["ofs", "demo"]}}]'
image: registry:5000/simcore/services/comp/ofs-demo_func:1.0.0
ofs-sensitivity_ua_test_func:
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.8.10-slim as base
FROM python:3.9.12-slim as base

ARG VERSION

Expand Down
4 changes: 2 additions & 2 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ else
usermod --uid "$HOST_USERID" --gid "$HOST_GROUPID" "$SC_USER_NAME"

echo "$INFO" " Changing group properties of files around from $SC_USER_ID to group $CONTAINER_GROUP"
find / -path /proc -prune -o -group "$SC_USER_ID" -exec chgrp --no-dereference "$CONTAINER_GROUP" {} \;
find / -path /proc -prune -o -path /sys -prune -o -group "$SC_USER_ID" -exec chgrp --no-dereference "$CONTAINER_GROUP" {} \;
# change user property of files already around
echo "$INFO" " Changing ownership properties of files around from $SC_USER_ID to group $CONTAINER_GROUP"
find / -path /proc -prune -o -user "$SC_USER_ID" -exec chown --no-dereference "$SC_USER_NAME" {} \;
find / -path /proc -prune -o -path /sys -prune -o -user "$SC_USER_ID" -exec chown --no-dereference "$SC_USER_NAME" {} \;
fi

echo "$INFO" " Starting $* ..."
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ authors = [{name = "Pedro Crespo-Valero (pcrespov)"}]
classifiers = ["License :: OSI Approved :: MIT License"]
dependencies = [
"numpy",
"pint",
"pydantic",
"pyyaml",
"scipy",
Expand Down
3 changes: 3 additions & 0 deletions scripts/integration.make → scripts/docker.make
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ shell: ## docker-compose run ... bash

push: ## docker-compose push (to registry:5000)
docker-compose push

inspect-image: ## inspects image .Config [requires yq and jq installed]
for i in $(shell cat docker-compose.yml| yq '.services.*.image'); do echo $$i; docker image inspect $$i | jq '.[0].Config'; done
69 changes: 63 additions & 6 deletions src/osparc_function_services/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Dict,
Final,
Mapping,
Optional,
Tuple,
get_args,
get_origin,
Expand Down Expand Up @@ -61,6 +62,40 @@ def _name_type(parameter_annotation):
return name


def _replace_value_in_dict(item: Any, original_schema: dict[str, Any]):
#
# Taken and adapted from https://github.com/samuelcolvin/pydantic/issues/889#issuecomment-850312496
# TODO: check https://github.com/gazpachoking/jsonref

if isinstance(item, list):
return [_replace_value_in_dict(i, original_schema) for i in item]
elif isinstance(item, dict):
if "$ref" in item.keys():
# Limited to something like "$ref": "#/definitions/Engine"
definitions = item["$ref"][2:].split("/")
res = original_schema.copy()
for definition in definitions:
res = res[definition]
return res
else:
return {
key: _replace_value_in_dict(i, original_schema)
for key, i in item.items()
}
else:
return item


def _resolve_refs(schema: dict[str, Any]) -> dict[str, Any]:
if "$ref" in str(schema):
# NOTE: this is a minimal solution that cannot cope e.g. with
# the most generic $ref with might be URLs. For that we will be using
# directly jsonschema python package's resolver in the near future.
# In the meantime we can live with this
return _replace_value_in_dict(deepcopy(schema), deepcopy(schema.copy()))
return schema


def validate_inputs(parameters: Mapping[str, Parameter]) -> Dict[str, Any]:
inputs = {}
for parameter in parameters.values():
Expand All @@ -76,7 +111,6 @@ def validate_inputs(parameters: Mapping[str, Parameter]) -> Dict[str, Any]:
)

# FIXME: files are represented differently!

content_schema = schema_of(
parameter.annotation,
title=parameter.name.capitalize(),
Expand All @@ -86,7 +120,7 @@ def validate_inputs(parameters: Mapping[str, Parameter]) -> Dict[str, Any]:
"label": parameter.name,
"description": description,
"type": "ref_contentSchema",
"contentSchema": content_schema,
"contentSchema": _resolve_refs(content_schema),
}

if parameter.default != Parameter.empty:
Expand Down Expand Up @@ -121,14 +155,12 @@ def validate_outputs(return_annotation: Any) -> Dict[str, Any]:
name = f"out_{index}"

display_name = f"Out{index} {_name_type(return_type)}"
content_schema = schema_of(return_type, title=display_name)
data = {
"label": display_name,
"description": "",
"type": "ref_contentSchema",
"contentSchema": schema_of(
return_type,
title=display_name,
),
"contentSchema": _resolve_refs(content_schema),
}
outputs[name] = data
return outputs
Expand All @@ -153,3 +185,28 @@ def create_meta(func: Callable, service_version: str) -> MetaDict:
meta["outputs"] = outputs

return meta


def define_service(
version: str,
outputs: dict[str, Any],
name: Optional[str] = None,
description: Optional[str] = None,
authors: Optional[list] = None,
contact: Optional[str] = None,
thumbnail: Optional[str] = None,
):
# TODO: sync with create_meta
def _decorator(func: Callable):
service_name = f"{_PACKAGE_NAME}-{name or func.__name__}"

meta = deepcopy(_TEMPLATE_META)
meta["name"] = service_name
meta["key"] = f"simcore/services/comp/ofs-{func.__name__}"
meta["version"] = version

meta["outputs"] = outputs
func.__meta__ = meta
return func

return _decorator
38 changes: 31 additions & 7 deletions src/osparc_function_services/demo_services.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
import time
from enum import Enum
from numbers import Complex
from pydantic import BaseModel
from typing import Tuple
import time

from pydantic import BaseModel, Field, confloat, conint, constr


class Complex(BaseModel):
real: float = 0.0
imag: float = 0.0
real: float = Field(0.0, description="This is the real part")
imag: float = Field(0.0, ge=0.0)


class Answers(str, Enum):
YES = "YES"
NO = "NO"


def demo_func(
*,
index: conint(ge=1),
real_value: confloat(multiple_of=2),
string_value: constr(min_length=3),
list_of_numbers: list[confloat(ge=0)],
flag: bool = False,
answer: Answers = "NO",
complex_value: Complex,
) -> Tuple[int, float, bool]:

# Some fake implementation
print("Inputs")
print(f"{index=}")
print(f"{real_value=}")
print(f"{string_value=}")
print(f"{list_of_numbers=}")
print(f"{flag=}")

def demo_func(*, index: int, real_value: float, complex_value: Complex) -> Tuple[int, float, Complex]:
print("Sleeping 1.0")
print("sleep 1.0")
time.sleep(secs=1.0)
print("Done")

return (index, real_value, complex_value)
return (index, real_value, flag)
Loading