funcnodes-basic 0.2.1__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. funcnodes_basic-0.2.3/MANIFEST.in +14 -0
  2. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3}/PKG-INFO +11 -11
  3. funcnodes_basic-0.2.3/pyproject.toml +45 -0
  4. funcnodes_basic-0.2.3/setup.cfg +4 -0
  5. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/__init__.py +5 -2
  6. funcnodes_basic-0.2.3/src/funcnodes_basic/dataclass.py +64 -0
  7. funcnodes_basic-0.2.3/src/funcnodes_basic/input.py +84 -0
  8. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/PKG-INFO +51 -0
  9. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/SOURCES.txt +27 -0
  10. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/dependency_links.txt +1 -0
  11. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/entry_points.txt +3 -0
  12. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/requires.txt +2 -0
  13. funcnodes_basic-0.2.3/src/funcnodes_basic.egg-info/top_level.txt +1 -0
  14. funcnodes_basic-0.2.3/tests/test_all_nodes_pytest.py +6 -0
  15. funcnodes_basic-0.2.3/tests/test_dataclass.py +141 -0
  16. funcnodes_basic-0.2.3/tests/test_dict.py +101 -0
  17. funcnodes_basic-0.2.3/tests/test_import.py +8 -0
  18. funcnodes_basic-0.2.3/tests/test_inputs.py +123 -0
  19. funcnodes_basic-0.2.3/tests/test_lists.py +239 -0
  20. funcnodes_basic-0.2.3/tests/test_logic.py +102 -0
  21. funcnodes_basic-0.2.3/tests/test_math.py +681 -0
  22. funcnodes_basic-0.2.3/tests/test_strings.py +316 -0
  23. funcnodes_basic-0.2.1/pyproject.toml +0 -39
  24. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3}/LICENSE +0 -0
  25. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3}/README.md +0 -0
  26. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/dicts.py +0 -0
  27. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/lists.py +0 -0
  28. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/logic.py +0 -0
  29. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/math_nodes.py +0 -0
  30. {funcnodes_basic-0.2.1 → funcnodes_basic-0.2.3/src}/funcnodes_basic/strings.py +0 -0
@@ -0,0 +1,14 @@
1
+ graft src
2
+ graft tests
3
+
4
+ global-exclude __pycache__/*
5
+ prune __pycache__
6
+ prune */__pycache__
7
+ recursive-exclude */__pycache__ *
8
+
9
+ global-exclude .venv/*
10
+ global-exclude .venv/**/*
11
+ prune .venv
12
+ prune */.venv
13
+ recursive-exclude .venv *
14
+ recursive-exclude */.venv *
@@ -1,19 +1,20 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: funcnodes-basic
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Basic functionalities for funcnodes
5
+ Author-email: Julian Kimmig <julian.kimmig@linkdlab.de>
5
6
  License: AGPL-3.0
6
- Author: Julian Kimmig
7
- Author-email: julian.kimmig@linkdlab.de>
8
- Requires-Python: >=3.11
9
- Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
10
- Requires-Dist: funcnodes
11
- Requires-Dist: funcnodes-core (>=0.3.9)
12
- Project-URL: Homepage, https://github.com/Linkdlab/funcnodes_basic
13
- Project-URL: download, https://pypi.org/project/funcnodes-basic/#files
7
+ Project-URL: homepage, https://github.com/Linkdlab/funcnodes_basic
14
8
  Project-URL: source, https://github.com/Linkdlab/funcnodes_basic
15
9
  Project-URL: tracker, https://github.com/Linkdlab/funcnodes_basic/issues
10
+ Project-URL: download, https://pypi.org/project/funcnodes-basic/#files
11
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
12
+ Requires-Python: >=3.11
16
13
  Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: funcnodes-core>=0.3.9
16
+ Requires-Dist: funcnodes
17
+ Dynamic: license-file
17
18
 
18
19
  # FuncNodes Basic
19
20
 
@@ -48,4 +49,3 @@ This project is licensed under the MIT License.
48
49
  ## Contact
49
50
 
50
51
  For any questions or issues, please open an issue on the GitHub repository.
51
-
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "funcnodes-basic"
3
+ version = "0.2.3"
4
+ description = "Basic functionalities for funcnodes"
5
+ readme = "README.md"
6
+ classifiers = [ "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",]
7
+ requires-python = ">=3.11"
8
+ dependencies = [
9
+ "funcnodes-core>=0.3.9",
10
+ "funcnodes",
11
+ ]
12
+ authors = [{name = "Julian Kimmig", email = "julian.kimmig@linkdlab.de"}]
13
+
14
+
15
+ [dependency-groups]
16
+ dev = [
17
+ "funcnodes-module>=0.2.9",
18
+ "pre-commit>=4.1.0",
19
+ "pytest>=8.3.4",
20
+ "pytest-funcnodes>=0.1.0",
21
+ ]
22
+
23
+ [build-system]
24
+ requires = [ "setuptools>=42",]
25
+ build-backend = "setuptools.build_meta"
26
+
27
+ [project.license]
28
+ text = "AGPL-3.0"
29
+
30
+ [project.urls]
31
+ homepage = "https://github.com/Linkdlab/funcnodes_basic"
32
+ source = "https://github.com/Linkdlab/funcnodes_basic"
33
+ tracker = "https://github.com/Linkdlab/funcnodes_basic/issues"
34
+ download = "https://pypi.org/project/funcnodes-basic/#files"
35
+
36
+ [project.entry-points."funcnodes.module"]
37
+ module = "funcnodes_basic"
38
+ shelf = "funcnodes_basic:NODE_SHELF"
39
+
40
+ [tool.setuptools.package-dir]
41
+ "" = "src"
42
+
43
+
44
+ [tool.setuptools.packages.find]
45
+ where = [ "src",]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -4,15 +4,18 @@ from .math_nodes import NODE_SHELF as math_shelf
4
4
  from .lists import NODE_SHELF as lists_shelf
5
5
  from .strings import NODE_SHELF as strings_shelf
6
6
  from .dicts import NODE_SHELF as dicts_shelf
7
+ from .input import NODE_SHELF as input_shelf
8
+ from .dataclass import NODE_SHELF as dataclass_shelf
7
9
 
8
-
9
- __version__ = "0.2.1"
10
+ __version__ = "0.2.3"
10
11
 
11
12
  NODE_SHELF = Shelf(
12
13
  nodes=[],
13
14
  subshelves=[
15
+ input_shelf,
14
16
  lists_shelf,
15
17
  dicts_shelf,
18
+ dataclass_shelf,
16
19
  strings_shelf,
17
20
  math_shelf,
18
21
  logic_shelf,
@@ -0,0 +1,64 @@
1
+ import dataclasses
2
+ import funcnodes_core as fn
3
+ from typing import Any, Dict
4
+
5
+
6
+ @fn.NodeDecorator(
7
+ id="dataclass.to_dict",
8
+ )
9
+ def dataclass_to_dict(instance: Any) -> Dict[str, Any]:
10
+ """
11
+ Convert a dataclass instance to a dictionary.
12
+
13
+ Args:
14
+ instance (object): The dataclass instance to convert.
15
+
16
+ Returns:
17
+ dict: The dictionary representation of the dataclass instance.
18
+ """
19
+ if not dataclasses.is_dataclass(instance):
20
+ raise TypeError(f"Expected a dataclass instance, got {type(instance)}")
21
+
22
+ return dataclasses.asdict(instance)
23
+
24
+
25
+ @fn.NodeDecorator(
26
+ id="dataclass.get_field",
27
+ default_io_options={
28
+ "instance": {
29
+ "on": {
30
+ "after_set_value": fn.decorator.update_other_io_value_options(
31
+ "field_name",
32
+ lambda result: {
33
+ "options": [field.name for field in dataclasses.fields(result)]
34
+ if dataclasses.is_dataclass(result)
35
+ else None,
36
+ },
37
+ )
38
+ }
39
+ }
40
+ },
41
+ )
42
+ def dataclass_get_field(instance: Any, field_name: str) -> Any:
43
+ """
44
+ Get a field value from a dataclass instance.
45
+ """
46
+ if not dataclasses.is_dataclass(instance):
47
+ raise TypeError(f"Expected a dataclass instance, got {type(instance)}")
48
+
49
+ if not hasattr(instance, field_name):
50
+ raise AttributeError(
51
+ f"{instance.__class__.__name__} has no field '{field_name}'"
52
+ )
53
+
54
+ return getattr(instance, field_name)
55
+
56
+
57
+ NODE_SHELF = fn.Shelf(
58
+ nodes=[
59
+ dataclass_to_dict,
60
+ dataclass_get_field,
61
+ ],
62
+ name="dataclass",
63
+ description="Nodes for working with dataclasses",
64
+ )
@@ -0,0 +1,84 @@
1
+ from typing import Union
2
+ import funcnodes_core as fn
3
+
4
+
5
+ @fn.NodeDecorator(
6
+ node_id="input.any",
7
+ node_name="Input",
8
+ description="Any input",
9
+ outputs=[
10
+ {"name": "out"},
11
+ ],
12
+ )
13
+ def any_input(input: Union[str, float, int, bool]) -> str:
14
+ return input
15
+
16
+
17
+ @fn.NodeDecorator(
18
+ node_id="input.str",
19
+ node_name="String Input",
20
+ description="Input a string",
21
+ outputs=[
22
+ {"name": "string"},
23
+ ],
24
+ )
25
+ def str_input(input: str) -> str:
26
+ return str(input)
27
+
28
+
29
+ @fn.NodeDecorator(
30
+ node_id="input.int",
31
+ node_name="Integer Input",
32
+ description="Input an integer",
33
+ outputs=[
34
+ {"name": "integer"},
35
+ ],
36
+ )
37
+ def int_input(input: int) -> int:
38
+ return int(input)
39
+
40
+
41
+ @fn.NodeDecorator(
42
+ node_id="input.float",
43
+ node_name="Float Input",
44
+ description="Input a float",
45
+ outputs=[
46
+ {"name": "float"},
47
+ ],
48
+ )
49
+ def float_input(input: float) -> float:
50
+ return float(input)
51
+
52
+
53
+ @fn.NodeDecorator(
54
+ node_id="input.bool",
55
+ node_name="Boolean Input",
56
+ description="Input a boolean",
57
+ outputs=[
58
+ {"name": "boolean"},
59
+ ],
60
+ )
61
+ def bool_input(input: bool) -> bool:
62
+ if isinstance(input, str):
63
+ if input.lower() in ("true", "1", "yes"):
64
+ input = True
65
+ elif input.lower() in ("false", "0", "no"):
66
+ input = False
67
+ elif isinstance(input, (int, float)):
68
+ input = bool(input)
69
+ else:
70
+ input = bool(input)
71
+ return bool(input)
72
+
73
+
74
+ NODE_SHELF = fn.Shelf(
75
+ nodes=[
76
+ any_input,
77
+ str_input,
78
+ int_input,
79
+ float_input,
80
+ bool_input,
81
+ ],
82
+ name="Input",
83
+ description="Simple input nodes",
84
+ )
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: funcnodes-basic
3
+ Version: 0.2.3
4
+ Summary: Basic functionalities for funcnodes
5
+ Author-email: Julian Kimmig <julian.kimmig@linkdlab.de>
6
+ License: AGPL-3.0
7
+ Project-URL: homepage, https://github.com/Linkdlab/funcnodes_basic
8
+ Project-URL: source, https://github.com/Linkdlab/funcnodes_basic
9
+ Project-URL: tracker, https://github.com/Linkdlab/funcnodes_basic/issues
10
+ Project-URL: download, https://pypi.org/project/funcnodes-basic/#files
11
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: funcnodes-core>=0.3.9
16
+ Requires-Dist: funcnodes
17
+ Dynamic: license-file
18
+
19
+ # FuncNodes Basic
20
+
21
+ ## Overview
22
+
23
+ `funcnodes-basic` is a collection of essential nodes designed to handle fundamental operations in [Funcnodes](https://github.com/linkdlab/funcnodes), such as list manipulation, dictionary operations, logic control, mathematical functions, and string processing. It provides a foundation of commonly needed functionalities in computational graphs built with the FuncNodes framework. Each module within this package contains a set of nodes, grouped by their operation type, allowing seamless integration into broader systems.
24
+
25
+ ## Installation
26
+
27
+ Install the package with:
28
+
29
+ ```bash
30
+ pip install funcnodes-basic
31
+ ```
32
+
33
+ ## Getting Started
34
+
35
+ Please refere to the [Funcnodes](https://github.com/linkdlab/funcnodes) package
36
+
37
+ ## Example Usage
38
+
39
+ You can integrate the provided nodes in your computational graphs, connecting inputs and outputs between nodes to build complex workflows that utilize dictionaries, lists, logic, math, and string operations.
40
+
41
+ ## Contribution
42
+
43
+ Feel free to contribute to this project by submitting pull requests. You can help by adding new nodes, fixing bugs, or enhancing documentation.
44
+
45
+ ## License
46
+
47
+ This project is licensed under the MIT License.
48
+
49
+ ## Contact
50
+
51
+ For any questions or issues, please open an issue on the GitHub repository.
@@ -0,0 +1,27 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ src/funcnodes_basic/__init__.py
6
+ src/funcnodes_basic/dataclass.py
7
+ src/funcnodes_basic/dicts.py
8
+ src/funcnodes_basic/input.py
9
+ src/funcnodes_basic/lists.py
10
+ src/funcnodes_basic/logic.py
11
+ src/funcnodes_basic/math_nodes.py
12
+ src/funcnodes_basic/strings.py
13
+ src/funcnodes_basic.egg-info/PKG-INFO
14
+ src/funcnodes_basic.egg-info/SOURCES.txt
15
+ src/funcnodes_basic.egg-info/dependency_links.txt
16
+ src/funcnodes_basic.egg-info/entry_points.txt
17
+ src/funcnodes_basic.egg-info/requires.txt
18
+ src/funcnodes_basic.egg-info/top_level.txt
19
+ tests/test_all_nodes_pytest.py
20
+ tests/test_dataclass.py
21
+ tests/test_dict.py
22
+ tests/test_import.py
23
+ tests/test_inputs.py
24
+ tests/test_lists.py
25
+ tests/test_logic.py
26
+ tests/test_math.py
27
+ tests/test_strings.py
@@ -0,0 +1,3 @@
1
+ [funcnodes.module]
2
+ module = funcnodes_basic
3
+ shelf = funcnodes_basic:NODE_SHELF
@@ -0,0 +1,2 @@
1
+ funcnodes-core>=0.3.9
2
+ funcnodes
@@ -0,0 +1 @@
1
+ funcnodes_basic
@@ -0,0 +1,6 @@
1
+ from pytest_funcnodes import all_nodes_tested
2
+ import funcnodes_basic as fnmodule # noqa
3
+
4
+
5
+ def test_all_nodes_tested(all_nodes):
6
+ all_nodes_tested(all_nodes, fnmodule.NODE_SHELF, ignore=[])
@@ -0,0 +1,141 @@
1
+ from funcnodes_basic import dataclass as dc_nodes
2
+ import pytest_funcnodes
3
+ import pytest
4
+ import funcnodes_core as fn
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass
9
+ class SimpleDataClass:
10
+ name: str
11
+ value: int
12
+ is_active: bool = True
13
+
14
+
15
+ @dataclass
16
+ class NestedDataClass:
17
+ id: int
18
+ data: SimpleDataClass
19
+
20
+
21
+ @pytest_funcnodes.nodetest(dc_nodes.dataclass_to_dict)
22
+ async def test_dataclass_to_dict():
23
+ node = dc_nodes.dataclass_to_dict()
24
+
25
+ # Test with a simple dataclass
26
+ instance1 = SimpleDataClass(name="Test1", value=100)
27
+ node.inputs["instance"].value = instance1
28
+ await node
29
+ assert node.outputs["out"].value == {
30
+ "name": "Test1",
31
+ "value": 100,
32
+ "is_active": True,
33
+ }
34
+
35
+ # Test with a nested dataclass
36
+ instance2 = NestedDataClass(
37
+ id=1, data=SimpleDataClass(name="Nested", value=200, is_active=False)
38
+ )
39
+ node.inputs["instance"].value = instance2
40
+ await node
41
+ assert node.outputs["out"].value == {
42
+ "id": 1,
43
+ "data": {"name": "Nested", "value": 200, "is_active": False},
44
+ }
45
+
46
+ # Test with non-dataclass input
47
+ node.inputs["instance"].value = {"not": "a dataclass"}
48
+ with pytest.raises(fn.NodeTriggerError) as excinfo:
49
+ await node
50
+ assert "Expected a dataclass instance" in str(excinfo.value)
51
+
52
+ node.inputs["instance"].value = 123
53
+ with pytest.raises(fn.NodeTriggerError) as excinfo:
54
+ await node
55
+ assert "Expected a dataclass instance" in str(excinfo.value)
56
+
57
+
58
+ @pytest_funcnodes.nodetest(dc_nodes.dataclass_get_field)
59
+ async def test_dataclass_get_field():
60
+ node = dc_nodes.dataclass_get_field()
61
+
62
+ instance_simple = SimpleDataClass(name="TestSimple", value=123)
63
+ instance_nested = NestedDataClass(
64
+ id=1, data=SimpleDataClass(name="Nested", value=200, is_active=False)
65
+ )
66
+
67
+ # Test setting instance updates field_name options
68
+ node.inputs["instance"].value = instance_simple
69
+ await node # Initial trigger to process instance and update options
70
+ assert node.inputs["field_name"].value_options["options"] == [
71
+ "name",
72
+ "value",
73
+ "is_active",
74
+ ]
75
+
76
+ # Test getting a valid field 'name'
77
+ node.inputs["field_name"].value = "name"
78
+ await node
79
+ assert node.outputs["out"].value == "TestSimple"
80
+
81
+ # Test getting a valid field 'value'
82
+ node.inputs["field_name"].value = "value"
83
+ await node
84
+ assert node.outputs["out"].value == 123
85
+
86
+ # Test getting a valid field 'is_active'
87
+ node.inputs["field_name"].value = "is_active"
88
+ await node
89
+ assert node.outputs["out"].value is True
90
+
91
+ # Test with nested dataclass, first update options
92
+ node.inputs["instance"].value = instance_nested
93
+
94
+ assert node.inputs["field_name"].value_options["options"] == ["id", "data"]
95
+
96
+ # Test getting 'id' from nested
97
+ node.inputs["field_name"].value = "id"
98
+ await node
99
+ assert node.outputs["out"].value == 1
100
+
101
+ # Test getting 'data' (which is another dataclass)
102
+ node.inputs["field_name"].value = "data"
103
+ await node
104
+ assert node.outputs["out"].value == SimpleDataClass(
105
+ name="Nested", value=200, is_active=False
106
+ )
107
+
108
+ # Test getting non-existent field
109
+ node.inputs["instance"].value = instance_simple
110
+ node.inputs["field_name"].value = "non_existent_field"
111
+ with pytest.raises(fn.NodeTriggerError) as excinfo:
112
+ await node
113
+ assert "has no field 'non_existent_field'" in str(excinfo.value)
114
+
115
+ # Test with non-dataclass input
116
+ node.inputs["instance"].value = {"not": "a dataclass"}
117
+ node.inputs["field_name"].value = "some_field" # field_name options will be None
118
+ assert node.inputs["field_name"].value_options["options"] is None
119
+
120
+ with pytest.raises(fn.NodeTriggerError) as excinfo:
121
+ await node # trigger the func with invalid instance
122
+ assert "Expected a dataclass instance" in str(excinfo.value)
123
+
124
+ # Test dynamic update of options when instance changes
125
+ node.inputs["instance"].value = instance_nested
126
+ assert node.inputs["field_name"].value_options["options"] == ["id", "data"]
127
+ node.inputs["field_name"].value = "id"
128
+ await node
129
+ assert node.outputs["out"].value == 1
130
+
131
+ node.inputs["instance"].value = instance_simple
132
+ assert node.inputs["field_name"].value_options["options"] == [
133
+ "name",
134
+ "value",
135
+ "is_active",
136
+ ]
137
+ node.inputs[
138
+ "field_name"
139
+ ].value = "name" # previous 'id' is no longer valid for options, but value remains
140
+ await node
141
+ assert node.outputs["out"].value == "TestSimple"
@@ -0,0 +1,101 @@
1
+ from funcnodes_basic import dicts
2
+ import pytest_funcnodes
3
+ # DictGetNode,
4
+ # dict_keys,
5
+ # dict_values,
6
+ # dict_items,
7
+ # dict_from_items,
8
+ # dict_from_keys_values,
9
+ # dict_to_list,
10
+
11
+
12
+ @pytest_funcnodes.nodetest(dicts.DictGetNode)
13
+ async def test_dict_get():
14
+ testdict = {"a": 1, "b": 2, "c": 3}
15
+
16
+ node = dicts.DictGetNode()
17
+
18
+ node.inputs["dictionary"].value = testdict
19
+ await node
20
+
21
+ assert node.inputs["key"].value_options["options"] == {"a": "0", "b": "1", "c": "2"}
22
+
23
+ node.inputs["key"].value = "0"
24
+ await node
25
+
26
+ assert node.outputs["value"].value == 1
27
+
28
+
29
+ @pytest_funcnodes.nodetest(dicts.dict_keys)
30
+ async def test_dict_keys():
31
+ testdict = {"a": 1, "b": 2, "c": 3}
32
+
33
+ node = dicts.dict_keys()
34
+
35
+ node.inputs["dictionary"].value = testdict
36
+ await node
37
+
38
+ assert node.outputs["out"].value == ["a", "b", "c"]
39
+
40
+
41
+ @pytest_funcnodes.nodetest(dicts.dict_values)
42
+ async def test_dict_values():
43
+ testdict = {"a": 1, "b": 2, "c": 3}
44
+
45
+ node = dicts.dict_values()
46
+
47
+ node.inputs["dictionary"].value = testdict
48
+ await node
49
+
50
+ assert node.outputs["out"].value == [1, 2, 3]
51
+
52
+
53
+ @pytest_funcnodes.nodetest(dicts.dict_items)
54
+ async def test_dict_items():
55
+ testdict = {"a": 1, "b": 2, "c": 3}
56
+
57
+ node = dicts.dict_items()
58
+
59
+ node.inputs["dictionary"].value = testdict
60
+ await node
61
+
62
+ assert node.outputs["out"].value == [("a", 1), ("b", 2), ("c", 3)]
63
+
64
+
65
+ @pytest_funcnodes.nodetest(dicts.dict_from_items)
66
+ async def test_dict_from_items():
67
+ testitems = [("a", 1), ("b", 2), ("c", 3)]
68
+
69
+ node = dicts.dict_from_items()
70
+
71
+ node.inputs["items"].value = testitems
72
+ await node
73
+
74
+ assert node.outputs["out"].value == {"a": 1, "b": 2, "c": 3}
75
+
76
+
77
+ @pytest_funcnodes.nodetest(dicts.dict_from_keys_values)
78
+ async def test_dict_from_keys_values():
79
+ testkeys = ["a", "b", "c"]
80
+ testvalues = [1, 2, 3]
81
+
82
+ node = dicts.dict_from_keys_values()
83
+
84
+ node.inputs["keys"].value = testkeys
85
+ node.inputs["values"].value = testvalues
86
+ await node
87
+
88
+ assert node.outputs["out"].value == {"a": 1, "b": 2, "c": 3}
89
+
90
+
91
+ @pytest_funcnodes.nodetest(dicts.dict_to_list)
92
+ async def test_dict_to_list():
93
+ testdict = {"a": 1, "b": 2, "c": 3}
94
+
95
+ node = dicts.dict_to_list()
96
+
97
+ node.inputs["dictionary"].value = testdict
98
+ await node
99
+
100
+ assert node.outputs["keys"].value == ["a", "b", "c"]
101
+ assert node.outputs["values"].value == [1, 2, 3]
@@ -0,0 +1,8 @@
1
+ import funcnodes as fn
2
+
3
+
4
+ def test_find():
5
+ res = fn.lib.libfinder.find_shelf_from_module("funcnodes_basic")
6
+
7
+ assert res[0].name == "basics", res
8
+ len(res[0].subshelves) > 0