Define Ports¶
Ports are the typed connection points on a component node. Output ports produce
values; input ports consume them. The dataflow engine uses port types for
compile-time validation and param.watch for runtime propagation.
Port declarations in @register¶
String shorthand¶
The simplest form uses plain strings as port names (untyped):
@register(
component=True,
provides=["ticker", "date_range"],
requires=["market"],
)
def app(config):
...
Dict form with types¶
For typed ports, use dictionaries with key and type:
@register(
component=True,
provides=[
{"key": "filtered_data", "type": "DataFrame", "label": "Filtered Data"},
],
requires=[
{"key": "ticker", "type": "str", "label": "Ticker Symbol"},
{"key": "start_date", "type": "Date", "required": True, "blocking": True},
],
)
def app(config):
...
Output port fields¶
| Field | Type | Description |
|---|---|---|
key |
str |
Port identifier (used in wiring). |
type |
str |
Type name for compatibility checking. |
label |
str |
Display label in the UI. |
Input port fields¶
| Field | Type | Default | Description |
|---|---|---|---|
key |
str |
Port identifier (used in wiring). | |
type |
str |
None |
Expected type (case-insensitive match). |
label |
str |
None |
Display label. |
required |
bool |
True |
Whether the port must be connected. |
blocking |
bool |
True |
Whether missing input blocks execution. |
fallback |
any |
None |
Default value when disconnected. |
Automatic introspection from Viewer classes¶
When using a Viewer subclass without explicit provides/requires, FlowDash
introspects ports from param:
Outputs from @param.output¶
class MyComponent(pn.viewable.Viewer):
@param.output(param.Number)
def score(self):
return self._compute_score()
@param.output(param.DataFrame)
def table(self):
return self._data
Each @param.output becomes an OutputPort with its type derived from the
param type class name (e.g. "Number", "DataFrame").
Outputs from Parameters¶
A Viewer that already holds the value on a Parameter does not need a method to
publish it. Name the Parameter in provides:
@register(component=True, provides=["selection"])
class Picker(pn.viewable.Viewer):
selection = param.List(default=[])
def __panel__(self):
return self._table
Whatever the component assigns to self.selection flows to every connected
input. The port is typed after the Parameter ("List" here) unless provides
gives a type; a plain param.Parameter leaves the port untyped so it can
connect to any input.
A Parameter published this way is an output only, so it is left out of the
component's input ports. provides replaces the outputs introspected from
@param.output, so list those methods in it too if the component has both.
Inputs from param declarations¶
class MyComponent(pn.viewable.Viewer):
threshold = param.Number(default=0.5)
category = param.Selector(objects=["A", "B", "C"])
Each user-defined param (excluding base class params like name, loading,
etc.) becomes an InputPort. The type is the param class name (e.g. "Number",
"Selector").
Config params are not ports
Params named in the config argument (or covered by a config_schema) are
treated as design-time configuration and excluded from the input ports. See
Configure nodes.
Type compatibility rules¶
When connecting an output to an input, the dataflow engine checks type compatibility:
- If either port is untyped (
type=None), the connection is allowed. - Types are compared case-insensitively:
"dataframe"matches"DataFrame". - Mismatched types produce an error message explaining the incompatibility.
# This works: both typed as "str"
provides=[{"key": "ticker", "type": "str"}]
requires=[{"key": "symbol", "type": "str"}]
# This works: source is untyped
provides=["value"]
requires=[{"key": "input", "type": "str"}]
# This fails: "int" != "str"
provides=[{"key": "count", "type": "int"}]
requires=[{"key": "name", "type": "str"}]
The ComponentSpec dataclass¶
Internally, FlowDash converts registry entries into ComponentSpec objects:
from panel_flowdash import ComponentSpec, OutputPort, InputPort
spec = ComponentSpec(
component_id="Analytics/filter",
title="Data Filter",
description="Filters data by criteria",
icon="filter",
tags=["data"],
outputs=[OutputPort(name="filtered", type="DataFrame")],
inputs=[InputPort(name="source", type="DataFrame", required=True)],
default_size={"w": 4, "h": 3},
)
You rarely need to construct these manually. build_component_spec() and
build_component_specs() handle this from the registry.