Skip to main content

Flow-based visual scripting for Python

Project description

This project is not very actively maintained. With the latest release - which I'm currently working on getting mostly stable - the project became quite accurately what I wanted it to be, and I'll have limited time for it in the future. If you are a contributor and interested in maintaining, please contact me.

drawing

Ryven is an experimental node editor written in Python, it implements a Qt-based visual interface for flow-based programming in Python. It provides a powerful system for developing nodes executing any Python code, and an editor for building graphs using those nodes. Ryven features a bunch of configuration options and a headless mode for running graphs without any GUI. Some relevant GitHub repos:

Installation and Configuration

Once you have Python and pip installed, Ryven is available on PyPI via

pip install ryven

There is also a conda-forge package (conda install -c conda-forge ryven).

Ryven can be launched from the command line with ryven. If you installed Ryven into a Python virtual environment, the environment needs to be activated first.

Ryven itself only comes with some small example nodes. You should use Ryven either to develop nodes, or use a third-party nodes package for your use case if there is one. The example nodes are - indeed - just examples, and not stable in any way, so you should not depend on them.

When installed, ryven will create a directory .ryven in your user home with the following structure:

~/.ryven
├── nodes
│   ├── your_nodes_pkg_1
│       ├── nodes.py
│       └── gui.py
│   └── ...
├── saves
│   ├── your_project_1.json
│   └── ...
└── ryven.cfg

The ryven.cfg file contains global configurations for Ryven.

Ryven can be configured in four ways:

  1. from the command line, e.g. ryven --nodes your_nodes_pkg_1 --no-animations
  2. from a configuration file, e.g. in ~/.ryven/ryven.cfg:
    nodes = your_nodes_pkg_1
    no_animations = True
    
  3. through arguments when it's integrated in another Python application, e.g.
    import ryven
    ryven.run_ryven(nodes=['your_nodes_pkg_1'], no_animations=True)
    
  4. using a GUI in the startup dialog
    • you can also convert the manual configuration to cmd line args (or a config file) in the dialog

See ryven --help for a list of available options.

To deploy a Ryven project headless, without any GUI, use the ryven-console command.

Example: headless deployment with REPL access
> ryven-console /home/leon/.ryven/saves/basics.json
Welcome to the Ryven Console! Your project has been loaded.
You can access the ryvencore session by typing `session`.
For more information, visit https://leon-thomm.github.io/ryvencore/

>>> f = session.flows[0]
>>> ctr_var_result_node = f.nodes[2]
>>> ctr_set_var_node = f.nodes[8]
>>> ctr_var_result_node.val
3738
>>> ctr_set_var_node.update(0)
>>> ctr_var_result_node.val
3739

Editor Usage

Quickstart guide:

  • open Ryven by running ryven from the command line
  • you should see the startup dialog
  • create a new project
  • import some example nodes
    • File -> Import Example Nodes and select <installation_dir>/example_nodes/std/nodes.py
  • you should now see a list of nodes on the left
  • drag and drop them into the scene and connect them with your mouse
  • everything is being executed at runtime; try this:
    • drag two val nodes into the scene
    • wire them together with a + node
    • display the result in a result node
    • now replace one of them with a slider node generating real numbers
  • by right-clicking, you can also get an interactive nodes list preview inside the scene
  • you can pan around also with the right mouse button (hold and drag)
  • and zoom via ctrl + scroll

Developing Nodes

quick start into to developing node packages

Navigate to ~/.ryven/nodes/ and create a sub-directory of the following structure

~/.ryven/nodes
└── your_nodes_pkg_1
    ├── nodes.py
    └── gui.py

With the following contents:

nodes.py

from ryven.node_env import *

# your node definitions go here

export_nodes([
    # list your node classes here
])

gui.py

from ryven.gui_env import *

# your node gui definitions go here

export_guis([
    # list your node gui classes here
])

You can now start defining your own nodes. Let's define two basic nodes. One which generates random numbers

from random import random

class RandNode(Node):
    """Generates scaled random float values"""

    title = 'Rand'
    tags = ['random', 'numbers']
    init_inputs = [NodeInputType()]
    init_outputs = [NodeOutputType()]

    def update_event(self, inp=-1):
        self.set_output_val(0, 
            Data(random() * self.input(0).payload)
        )

and another one which prints them

class PrintNode(Node):
    title = 'Print'
    init_inputs = [NodeInputType()]

    def update_event(self, inp=-1):
        print(self.input(0))

and expose them to Ryven

export_nodes([
    RandNode,
    PrintNode,
])

That's it! You can import your nodes package in Ryven (File -> Import Nodes), place the nodes in the graph, and wire them up. Now add a val node and connect it to the Rand node, to feed its input with data. If you type a number into the widget of the val node and hit enter, it will send the number to the Rand node, which will send a scaled random number to the Print node, which will print it to the standard output.

Notice that the standard output is by default the in-editor console, which you can access at the very bottom of the editor window (drag the blue handle up to make it visible).

Adding GUI

You can now spice up your nodes with some GUI. Ryven runs on Qt, using the qtpy library. You can configure the GUI of your nodes in a separate gui.py file, and add custom Qt widgets to your nodes. Make sure to always clearly separate the node logic from the GUI. The nodes.py file should NOT have any dependency to Qt. One of the central features of Ryven is to run projects headless (on ryvencore) without any GUI dependencies, if your node packages obey the rules.

Let's give them some color and add a slider to the Rand node, in gui.py:

from ryven.gui_env import *

from qtpy.QtWidgets import QSlider
from qtpy.QtCore import Qt


class RandSliderWidget(NodeInputWidget, QSlider):
    """a standard Qt slider widget, which updates the node
    input it is attached to, every time the slider value changes"""
    
    def __init__(self, params):
        NodeInputWidget.__init__(self, params)
        QSlider.__init__(self)
        
        self.setOrientation(Qt.Horizontal)
        self.setMinimumWidth(100)
        self.setMinimum(0)
        self.setMaximum(100)
        self.setValue(50)
        self.valueChanged.connect(self.value_changed)
    
    def value_changed(self, val):
        # updates the node input this widget is attached to
        self.update_node_input(Data(val))
    
    def get_state(self) -> dict:
        # return the state of the widget
        return {'value': self.value()}
    
    def set_state(self, state: dict):
        # set the state of the widget
        self.setValue(state['value'])
    

class RandNodeGui(NodeGUI):
    color = '#fcba03'
    
    # register the input widget class
    input_widget_classes = { 'slider': RandSliderWidget }
    
    # attach the slider widget to the first node input
    # display it _below_ the input pin
    init_input_widgets = {
        0: {'name': 'slider', 'pos': 'below'}
    }

export_guis([
    RandNodeGui,
])

and you now just need to reference the RandNodeGUI in nodes.py:

guis = import_guis(__file__)

class RandNode(Node):
    ...
    GUI = guis.RandNodeGui

The value provided by an input widget (through self.update_node_input(val)) will be returned in Node by self.input(0) only when the corresponding input is not connected. Otherwise the value of the connected output will be returned.

So now we can reconstruct the previous example, but we don't need to connect the val node to the Rand node anymore. Change the slider and see how many different random values are printed.

Please find further resources on the GitHub wiki page in this repository.

Features

A (possibly incomplete) list of features:

  • headless mode to run projects without GUI dependencies at high performance
  • sophisticated nodes system allowing for stateful nodes and widgets
  • cross-platform; running anywhere where Qt runs (for GUI), or simply Python (headless)
  • rendering flow images into PNGs
  • built-in exec flow support (like UE BluePrints) unlike most other node editors
  • custom Qt widgets support
  • various themes, including light
  • right-click operations system for nodes
  • variables add-on with observer mechanism, to build nodes that automatically adapt to change of data
  • very basic logging support
  • primitive, very experimental stylus support for adding handwritten notes on touch devices

License

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

Credits

A huge thanks to the contributors. This project does not exist without the open-source community. I personally want to particularly thank the people listed in the CREDITS.md file, which have strongly impacted the project.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ryven-3.4.0a2.tar.gz (7.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ryven-3.4.0a2-py3-none-any.whl (4.4 MB view details)

Uploaded Python 3

File details

Details for the file ryven-3.4.0a2.tar.gz.

File metadata

  • Download URL: ryven-3.4.0a2.tar.gz
  • Upload date:
  • Size: 7.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for ryven-3.4.0a2.tar.gz
Algorithm Hash digest
SHA256 d45c67a7d6f83d2078c08284e547b5f50d7ae9cc43069dbfa5641813b8decaec
MD5 1ae42e903f95f48f3602d9a80245514f
BLAKE2b-256 ea945225f2efef5c0e3f29aeeb2187368d7dbbd43d23710b474e21a4c6138a59

See more details on using hashes here.

File details

Details for the file ryven-3.4.0a2-py3-none-any.whl.

File metadata

  • Download URL: ryven-3.4.0a2-py3-none-any.whl
  • Upload date:
  • Size: 4.4 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for ryven-3.4.0a2-py3-none-any.whl
Algorithm Hash digest
SHA256 7e9e7700e9c01085baf9e4d8a23a1e83979e5447aaea247face05c871655fe80
MD5 e011f70b18a484f0392d2c675019420b
BLAKE2b-256 f8e8e4672c799846b4fd0624c5e02a8bf64ade93a1b74e134a95d7995ce61e4b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page