# Write a class app

!!! abstract “”

    How to inherit from `scinexus` app base classes, or using the `define_app` decorator, specifying input/output type hints.

## Using inheritance from a base class

```python linenums=“1” from collections.abc import Callable from citeable import Software from scinexus import ComposableApp

my_cite = Software( author=[“Doe, J”, “Smith, A”], title=“My Sequence Filter”, year=2025, url=“https://example.com/my-filter”, version=“0.1.0”, )

class my_app( # (1)! ComposableApp[str, str], # (2)! cite=my_cite, # (3)! ): def init(self, convert: Callable[[str], str]): self.convert = convert

    def main(self, val: str) -> str:  # (4)!
        return self.convert(val)

    1. We suggest naming your apps using the PEP8 naming style for functions (lowercase separated by underscores) because the instances will be used like functions.
    2. We type hint the input / output types with the base class.
    3. We assign the citation in the class definition.
    4. Your class **must** have a `main()` method with type hints specified for its first argument and its return type.

    ## Using the `define_app` decorator

    How to use `@define_app` on a class with a `main()` method, configure it via `__init__` parameters, and control behaviour with the `app_type` parameter.

    ```python { linenums="1" notest }
    from collections.abc import Callable
    from citeable import Software
    from scinexus import ComposableApp

    my_cite = Software(
        author=["Doe, J", "Smith, A"],
        title="My Sequence Filter",
        year=2025,
        url="https://example.com/my-filter",
        version="0.1.0",
    )

    @define_app(cite=my_cite)  # (1)!
    class my_app:
        def __init__(self, convert: Callable[[str], str]):
            self.convert = convert

        def main(self, val: str) -> str:  # (2)!
            return self.convert(val)

1. The `define_app` decorator is used. You can specify the `app_type` here, which we don’t in this case, and assign your citation.
2. Your class must have a `main()` method with type hints specified for its first argument and its return type.

### Specifying the app type

The `define_app` decorator has a default `app_type` of `"generic"`. This means the app does data transformation and does not load or write data. The supported app types are indicated by the `AppType` enum:

```python { linenums=“1” notest } from scinexus.composable import AppType

print(list(AppType))

# [<AppType.LOADER: ‘loader’>, <AppType.WRITER: ‘writer’>, <AppType.GENERIC:

# ‘generic’>, <AppType.NON_COMPOSABLE: ‘non_composable’>]

    <!-- [[[end]]] -->

    If your app is not intended to be composed sequentially with other apps, set it to non-composable:

    ```python
    from scinexus import define_app, AppType

    @define_app(app_type=AppType.NON_COMPOSABLE)
    class my_standalone_app:
        def main(self, val: str) -> str:
            return val.upper()

## Handling `NotCompleted` values

By default, apps skip `NotCompleted` inputs — they propagate through the pipeline without calling `main()`. If your app needs access to `NotCompleted` instances (e.g. you are developing a writer that records failures), set `skip_not_completed=False`:

    from scinexus import define_app, NotCompleted

    @define_app(skip_not_completed=False)
    class my_writer:
        def main(self, val: str) -> str:
            if isinstance(val, NotCompleted):
                # handle the failure
                ...
            return val