diff --git a/README.md b/README.md index e7af1ab..dba858c 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,58 @@ class MyApp(App): MyApp().run(1) ``` +## Component definition + +Creating your own components is pretty easy, you just need to inherit from `limbus.Component` and implement some methods (see some examples in `examples/defining_cmps.py`). + +The `Component` class has the next main methods: +- `__init__`: where you can add class parameters to your component. +- `register_inputs`: where you need to declare the input pins of your component. +- `register_outputs`: where you need to declare the output pins of your component. +- `register_properties`: where you can declare properties that can be changed during the execution. +- `forward`: where you must define the logic of your component (mandatory). + +For a detailed list of `Component` methods and attributes, please check `limbus/core/component.py`. + +**Note** that if you want intellisense (at least in `VSCode` you will need to define the `input` and `output` types). + +Let's see a very simple example that sums 2 integers: + +```python +class Add(Component): + """Add two numbers.""" + # NOTE: type definition is optional, but it helps with the intellisense. ;) + class InputsTyping(OutputParams): + a: InputParam + b: InputParam + + class OutputsTyping(OutputParams): + out: OutputParam + + inputs: InputsTyping + outputs: OutputsTyping + + @staticmethod + def register_inputs(inputs: InputParams) -> None: + # Here you need to declare the input parameters and their default values (if they have). + inputs.declare("a", int) + inputs.declare("b", int) + + @staticmethod + def register_outputs(outputs: OutputParams) -> None: + # Here you need to declare the output parameters. + outputs.declare("out", int) + + async def forward(self) -> ComponentState: + # Here you must to define the logic of your component. + a, b = await asyncio.gather( + self.inputs.a.receive(), + self.inputs.b.receive() + ) + await self.outputs.out.send(a + b) + return ComponentState.OK +``` + ## Ecosystem Limbus is a core technology to easily build different components and create generic pipelines. In the following list, you can find different examples diff --git a/examples/defining_cmps.py b/examples/defining_cmps.py index 26b4a49..93805fa 100644 --- a/examples/defining_cmps.py +++ b/examples/defining_cmps.py @@ -2,7 +2,7 @@ from typing import List, Any import asyncio -from limbus.core import Component, Params, InputParams, OutputParams, ComponentState, VerboseMode +from limbus.core import Component, InputParams, OutputParams, ComponentState, VerboseMode, OutputParam, InputParam from limbus.core.pipeline import Pipeline @@ -10,13 +10,24 @@ # --------------------- class Add(Component): """Add two numbers.""" + # NOTE: type definition is optional, but it helps with the intellisense. ;) + class InputsTyping(OutputParams): # noqa: D106 + a: InputParam + b: InputParam + + class OutputsTyping(OutputParams): # noqa: D106 + out: OutputParam + + inputs: InputsTyping # type: ignore + outputs: OutputsTyping # type: ignore + @staticmethod - def register_inputs(inputs: Params) -> None: # noqa: D102 + def register_inputs(inputs: InputParams) -> None: # noqa: D102 inputs.declare("a", int) inputs.declare("b", int) @staticmethod - def register_outputs(outputs: Params) -> None: # noqa: D102 + def register_outputs(outputs: OutputParams) -> None: # noqa: D102 outputs.declare("out", int) async def forward(self) -> ComponentState: # noqa: D102 @@ -28,8 +39,14 @@ async def forward(self) -> ComponentState: # noqa: D102 class Printer(Component): """Prints the input to the console.""" + # NOTE: type definition is optional, but it helps with the intellisense. ;) + class InputsTyping(OutputParams): # noqa: D106 + inp: InputParam + + inputs: InputsTyping # type: ignore + @staticmethod - def register_inputs(inputs: Params) -> None: # noqa: D102 + def register_inputs(inputs: InputParams) -> None: # noqa: D102 inputs.declare("inp", Any) async def forward(self) -> ComponentState: # noqa: D102 @@ -40,6 +57,12 @@ async def forward(self) -> ComponentState: # noqa: D102 class Data(Component): """Data source of inf numbers.""" + # NOTE: type definition is optional, but it helps with the intellisense. ;) + class OutputsTyping(OutputParams): # noqa: D106 + out: OutputParam + + outputs: OutputsTyping # type: ignore + def __init__(self, name: str, initial_value: int = 0): super().__init__(name) self._initial_value: int = initial_value @@ -57,6 +80,16 @@ async def forward(self) -> ComponentState: # noqa: D102 class Acc(Component): """Accumulate data in a list.""" + # NOTE: type definition is optional, but it helps with the intellisense. ;) + class InputsTyping(OutputParams): # noqa: D106 + inp: InputParam + + class OutputsTyping(OutputParams): # noqa: D106 + out: OutputParam + + inputs: InputsTyping # type: ignore + outputs: OutputsTyping # type: ignore + def __init__(self, name: str, elements: int = 1): super().__init__(name) self._elements: int = elements diff --git a/limbus/core/__init__.py b/limbus/core/__init__.py index bf12b30..16799e0 100644 --- a/limbus/core/__init__.py +++ b/limbus/core/__init__.py @@ -1,6 +1,6 @@ from limbus.core.component import Component, iterations_manager from limbus.core.states import ComponentState, PipelineState, VerboseMode -from limbus.core.param import NoValue, Param, Reference +from limbus.core.param import NoValue, Param, Reference, InputParam, OutputParam from limbus.core.params import Params, InputParams, OutputParams from limbus.core.pipeline import Pipeline from limbus.core.app import App @@ -18,5 +18,7 @@ "Reference", "InputParams", "OutputParams", + "InputParam", + "OutputParam", "Param", "NoValue"] diff --git a/setup.py b/setup.py index eed2a9b..5387f46 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup(name='limbus', - version='0.1.3', + version='0.1.4', description='High level interface to create Pytorch Graphs.', long_description=open('README.md').read(), long_description_content_type='text/markdown',