nonoha-core is a Python package that provides the core functionality for nonoha - a lightweight node-based data processing framework where data flows seamlessly from node to node and integrates naturally with the Python ecosystem.
Install from the repository:
pip install git+https://github.com/viestyle-dev/nonoha-core.gitOr clone and install locally:
git clone https://github.com/viestyle-dev/nonoha-core
cd nonoha-core
pip install .Requires Python 3.11+. The only runtime dependency is NumPy.
nonoha-core is the foundation layer of the nonoha stack. Applications
are usually built on the systems that sit on top of it — the nonoha
engine and its visual editor — which manage graph files, persistence,
and I/O for you. Using the core API directly, as below, is recommended
for understanding the data model and for implementing your own nodes.
Nodes expose typed ports; raw NumPy arrays flow through them:
import numpy as np
from nonoha_core.node import BaseNodeGraph
from nonoha_core.nodes.arithmetic_operation_nodes import AddNode, NegativeNode
graph = BaseNodeGraph("demo", {})
add = AddNode("add") # two Float32 input slots by default
neg = NegativeNode("neg")
graph.add_node(add)
graph.add_node(neg)
graph.connect_nodes("add", "value", "neg", "values")
neg.outputs["values"].subscribe("printer", lambda values: print(values[0]))
add.inputs["values"].dispatch([
np.array([1.0, 2.0, 3.0], dtype=np.float32),
np.array([10.0, 20.0, 30.0], dtype=np.float32),
])
# -> [-11. -22. -33.]Values arrive as plain np.ndarray with a leading batch dimension, so they
can be handed directly to NumPy, SciPy, or any other library — no wrapper
types to unpack. Port types and shapes are declared at connection time,
which keeps runtime validation out of the hot path.
nonoha is designed for real-time data processing. Minimizing overhead in the hot path is critical.
- Eliminate unnecessary operations - Skip checks that can be guaranteed at setup time
- Avoid Python for-loops - Use NumPy batch operations instead
- Minimize function calls - Fewer call frames = less overhead
- Reduce processing steps - Combine operations where possible
Define input port types based on node properties to eliminate runtime type/shape validation:
# BAD: Runtime validation in hot path
def _on_input(self, values):
value_array = values[0]
if value_array.dtype != self._expected_dtype: # Runtime check
value_array = value_array.astype(self._expected_dtype)
if value_array.ndim == 1: # Runtime shape check
# handle 1D
elif value_array.ndim == 2:
# handle 2D
# GOOD: Type guaranteed by input port definition
def __init__(self, ...):
# Port type determined by properties
value_type = PortValueType(DataType.Float32, (2,))
input_port = StaticTypeInputPort("in", [value_type])
def _on_input(self, values):
value_array = values[0] # Type and shape guaranteed
# value_array.dtype == np.float32
# value_array.shape == (N,2)
# Direct processing without validationnonoha-core maintains minimal dependencies to enable nonoha's core functionality while maximizing platform compatibility.
Currently depends on:
- Python 3.11+
- NumPy 2.0+
Note: nonoha-core does not use threading to ensure broader compatibility.
For detailed dependency information, see pyproject.toml.
Using uv:
uv sync
uv run pytest -sUsing pip (>= 25.1):
pip install -e . --group dev
pytest -snonoha-core ships a pytest plugin that enforces the PortValue contract in
your own tests (opt out with -p no:nonoha_core).
- Port System Specification — typed ports, batch dimensions, dispatch flags
- NodeGraph Architecture — how nodes, ports, and graphs fit together
- Building Dataflow Applications — an end-to-end application guide
- Adding Node Properties — implementing configurable nodes
Follows Semantic Versioning from 1.0.0. Within a
major version, the node, port, data_type, and node_registry APIs
and the batch-array data model stay backward compatible; breaking changes
are deprecated first and removed in the next major.
Runtimes bundling this package (e.g. nonoha-engine) share its major version, so code written for 1.x runs on any 1.x runtime.
See CONTRIBUTING.md. First-time contributors sign the CLA with a single PR comment.
Loading an untrusted graph is equivalent to running untrusted Python code — see SECURITY.md for the threat model and how to report vulnerabilities.
Apache License 2.0 — see LICENSE. Redistributions must retain the attribution notices in NOTICE.