Skip to content

Commit

Permalink
Merge pull request #191 from leon-thomm/dev
Browse files Browse the repository at this point in the history
type checking, pyside6 support, updated packages
  • Loading branch information
leon-thomm committed May 20, 2024
2 parents 15c2d20 + a49f6fe commit bd5a37b
Show file tree
Hide file tree
Showing 73 changed files with 1,659 additions and 1,382 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/publish-ryven.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish Ryven wheel to TestPyPi and PyPi
name: Publish Ryven wheel to PyPi
on:
create:
tags:
Expand All @@ -18,12 +18,12 @@ jobs:
- name: Build binary wheel and source tarball
run: python -m build --sdist --wheel --outdir dist/
working-directory: ./ryven-editor
- name: Publish distribution to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.GH_AC_RYVEN_TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/
packages-dir: ryven-editor/dist/
# - name: Publish distribution to TestPyPI
# uses: pypa/gh-action-pypi-publish@release/v1
# with:
# password: ${{ secrets.GH_AC_RYVEN_TEST_PYPI_API_TOKEN }}
# repository-url: https://test.pypi.org/legacy/
# packages-dir: ryven-editor/dist/
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/publish-ryvencore-qt.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish ryvencore-qt wheel to TestPyPi and PyPi
name: Publish ryvencore-qt wheel to PyPi
on:
create:
tags:
Expand All @@ -18,12 +18,12 @@ jobs:
- name: Build binary wheel and source tarball
run: python -m build --sdist --wheel --outdir dist/
working-directory: ./ryvencore-qt
- name: Publish distribution to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.GH_AC_RCQT_TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/
packages-dir: ryvencore-qt/dist/
# - name: Publish distribution to TestPyPI
# uses: pypa/gh-action-pypi-publish@release/v1
# with:
# password: ${{ secrets.GH_AC_RCQT_TEST_PYPI_API_TOKEN }}
# repository-url: https://test.pypi.org/legacy/
# packages-dir: ryvencore-qt/dist/
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/type-checking.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Type-check Ryven and ryvencore-qt using mypy
on:
push:
branches:
- main
- dev
pull_request:
branches:
- '*'
workflow_dispatch:
jobs:
Type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.10.x
architecture: x64
# if we are not on the main branch, install ryvencore from the dev branch from github
# otherise, install ryvencore from the main branch from github
- if: github.ref != 'refs/heads/main'
run: python -m pip install git+https://github.com/leon-thomm/ryvencore.git@dev
- if: github.ref == 'refs/heads/main'
run: python -m pip install git+https://github.com/leon-thomm/ryvencore.git@main
- name: Install ryvencore-qt dependencies
run: python -m pip install . --user
working-directory: ./ryvencore-qt
- name: Install Ryven dependencies
run: python -m pip install . --user
working-directory: ./ryven-editor
- name: Uninstall ryvencore-qt and ryven (keep dependencies)
run: python -m pip uninstall ryven ryvencore-qt --yes
working-directory: ./ryven-editor
- name: Install type-checking dependencies
run: python -m pip install mypy pyside2 pyside6 PySide6-stubs types-Pygments --user
- name: Typecheck
run: mypy
working-directory: .
54 changes: 25 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,21 @@ For more information, visit https://leon-thomm.github.io/ryvencore/
<details>
<summary>quick start into to developing node packages</summary>

A Ryven nodes package is simply a typical Python package which contains at least a `nodes.py` file, and calls the Ryven node API to expose node definitions.

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

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

With the following contents:
with the following contents:

`nodes.py`
`nodes.py`:

```python
from ryven.node_env import *
Expand All @@ -132,21 +135,25 @@ from ryven.node_env import *
export_nodes([
# list your node classes here
])


@on_gui_load
def load_gui():
# import gui sources here only
from . import gui
```

`gui.py`
and `gui.py`:

```python
from ryven.gui_env import *

# your node gui definitions go here
from . import nodes

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

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

```python
from random import random
Expand All @@ -165,7 +172,7 @@ class RandNode(Node):
)
```

and another one which prints them
...and another one which prints them

```python
class PrintNode(Node):
Expand All @@ -185,22 +192,24 @@ export_nodes([
])
```

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.
That's it! You can import your nodes package in Ryven (`File -> Import Nodes`), place the nodes in the graph, and wire them up. 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](https://github.com/spyder-ide/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.
You can now spice up your nodes with some GUI. Ryven runs on Qt, using either PySide2 or PySide6 (through the [qtpy](https://github.com/spyder-ide/qtpy) library). You can configure the GUI of your nodes in a separate file, and add custom Qt widgets to your nodes. Make sure to always clearly separate the node logic from the GUI components. One of the central features of Ryven is to run projects headless (on ryvencore) without any GUI dependencies. In order for this to work, your `nodes.py` files should never depend on Qt directly. Instead, you can attach custom GUI to your nodes from the GUI files as shown below.

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

```python
from ryven.gui_env import *

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

from ryven.gui_env import *

from . import nodes


class RandSliderWidget(NodeInputWidget, QSlider):
"""a standard Qt slider widget, which updates the node
Expand Down Expand Up @@ -230,6 +239,7 @@ class RandSliderWidget(NodeInputWidget, QSlider):
self.setValue(state['value'])


@node_gui(nodes.RandNode)
class RandNodeGui(NodeGUI):
color = '#fcba03'

Expand All @@ -241,25 +251,11 @@ class RandNodeGui(NodeGUI):
init_input_widgets = {
0: {'name': 'slider', 'pos': 'below'}
}

export_guis([
RandNodeGui,
])
```

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

```python
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.
and this is it! Ryven will now register `RandNodeGui` as "GUI class" of the `RandNode` class, which serves as a container for all UI things. Your can add custom primary ("main") widgets to your nodes, input widgets, and further customize the look of the nodes.

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.
The value provided by an input widget (e.g. `self.update_node_input(val)` above) will be returned in the node, when calling `input()` (e.g. `self.input(0)` in the `RandNode`), but only when the corresponding input is _not connected_. Otherwise, the value of the connected output will be returned.

</details>

Expand Down
30 changes: 30 additions & 0 deletions debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python3

# manually debug ryven; ensure that the following packages are
# not installed in the current environment:
# * ryven
# * ryvencore-qt'
# * ryvencore

RYVEN_PATH = './ryven-editor'
RYVEN_QT_PATH = './ryvencore-qt'
RYVENCORE_PATH = '../ryvencore'

import sys

sys.path.insert(0, RYVEN_PATH)
sys.path.insert(0, RYVEN_QT_PATH)
sys.path.insert(0, RYVENCORE_PATH)

from ryven import run_ryven

if __name__ == '__main__':
run_ryven(
f"{RYVEN_PATH}/ryven/example_projects/matrices.json",
nodes=[
f"{RYVEN_PATH}/ryven/example_nodes/examples",
f"{RYVEN_PATH}/ryven/example_nodes/linalg",
],
qt_api='pyside6',
show_dialog=False,
)
21 changes: 21 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# mypy configuration, type-checking both the Ryven editor, and the
# ryvencore-qt library. ryvencore must be installed for this to work.
# Simply run `mypy` in the Ryven root directory to check the code.

[mypy]
warn_return_any = True
warn_unused_configs = True
warn_unused_ignores = True
files = ryven-editor/ryven, ryvencore-qt/ryvencore_qt

[mypy-ryven.*]
check_untyped_defs = False

[mypy-ryven.example_nodes.*]
ignore_errors = True

[mypy-ryven.main.packages.built_in.*]
ignore_errors = True

[mypy-ryven.gui.uic.*]
ignore_errors = True
6 changes: 0 additions & 6 deletions ryven-editor/pyproject.toml

This file was deleted.

2 changes: 2 additions & 0 deletions ryven-editor/ryven/example_nodes/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This package contains a bunch of nodes for different purposes, to showcase some of Ryven's features.
Some simple nodes are found in `basic_operators.py`, while more advanced ideas are implemented in `special_nodes.py`.
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
from ryven.node_env import *

guis = import_guis(__file__)


class OperatorNodeBase(Node):
"""
Base class for nodes implementing a binary operation.
"""

version = 'v0.2'
version = 'v0.3'
init_inputs = [
NodeInputType(),
NodeInputType(),
]
init_outputs = [
NodeOutputType(),
]
GUI = guis.OperatorNodeBaseGui

def __init__(self, params):
super().__init__(params)
Expand Down Expand Up @@ -50,7 +47,7 @@ def apply_op(self, elements: list):


class LogicNodeBase(OperatorNodeBase):
GUI = guis.LogicNodeBaseGui
pass


class NOT_Node(LogicNodeBase):
Expand Down Expand Up @@ -123,7 +120,7 @@ def apply_op(self, elements: list):


class ArithmeticNodeBase(OperatorNodeBase):
GUI = guis.ArithNodeBaseGui
pass


class Plus_Node(ArithmeticNodeBase):
Expand Down Expand Up @@ -194,7 +191,6 @@ def apply_op(self, elements: list):


class ComparatorNodeBase(OperatorNodeBase):
GUI = guis.CompNodeBaseGui

def apply_op(self, elements: list):
# if len(elements) > 0:
Expand Down Expand Up @@ -264,9 +260,20 @@ def comp(self, a, b) -> bool:
export
"""


nodes = [
node_types = [
*logic_nodes,
*arithmetic_nodes,
*comparator_nodes,
]

# account for old package name
for n in node_types:
n.legacy_identifiers = [
*getattr(n, 'legacy_identifiers', []),
f'std.{n.__class__.__name__}',
]

export_nodes(
node_types=node_types,
sub_pkg_name='basic_operators'
)
Loading

0 comments on commit bd5a37b

Please sign in to comment.