Tests, documentation, fixes

This commit is contained in:
2023-03-10 20:45:07 +01:00
parent 62347eaf31
commit c9df6b5408
9 changed files with 547 additions and 34 deletions

View File

@@ -0,0 +1,200 @@
{
"Uuid": "76de5c79-17c5-4c74-9f90-ad99a213d339",
"IsCustomNode": false,
"Description": "",
"Name": "no_python",
"ElementResolver": {
"ResolutionMap": {}
},
"Inputs": [],
"Outputs": [],
"Nodes": [
{
"ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore",
"NodeType": "FunctionNode",
"FunctionSignature": "+@var[]..[],var[]..[]",
"Id": "f8f4d3310211429ea8f301284983849e",
"Inputs": [
{
"Id": "264e2d2a3442445180048463a555399a",
"Name": "x",
"Description": "Integer value, double value or string\n\nvar[]..[]",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
},
{
"Id": "f627c4088ee943aeba708e81f9945f1e",
"Name": "y",
"Description": "Integer value, double value or string\n\nvar[]..[]",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Outputs": [
{
"Id": "72975df34c2542ff949630ef7253bed5",
"Name": "var",
"Description": "The sum of two input numbers, or the concatenation of two strings",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Replication": "Auto",
"Description": "Returns addition of x and y\n\n+ (x: var[]..[], y: var[]..[]): var[]..[]"
},
{
"ConcreteType": "Dynamo.Graph.Nodes.CodeBlockNodeModel, DynamoCore",
"NodeType": "CodeBlockNode",
"Code": "1;",
"Id": "24cee4b3934f46309d34386a1b5a674a",
"Inputs": [],
"Outputs": [
{
"Id": "dffa5271656d49e0b61ba8133b92a05e",
"Name": "",
"Description": "Value of expression at line 1",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Replication": "Disabled",
"Description": "Allows for DesignScript code to be authored directly"
},
{
"ConcreteType": "CoreNodeModels.Watch, CoreNodeModels",
"NodeType": "ExtensionNode",
"Id": "26fc878922fd425a89112c6b14c9779b",
"Inputs": [
{
"Id": "1587eb8d7d8f41e6833e2b90f95b63fb",
"Name": "",
"Description": "Node to show output from",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Outputs": [
{
"Id": "d70e73be40114b9cb129a91cd4777c4a",
"Name": "",
"Description": "Node output",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Replication": "Disabled",
"Description": "Visualizes a node's output"
}
],
"Connectors": [
{
"Start": "72975df34c2542ff949630ef7253bed5",
"End": "1587eb8d7d8f41e6833e2b90f95b63fb",
"Id": "8d017b34cb5b47f1b900c1c6ed8fd8d0",
"IsHidden": "False"
},
{
"Start": "dffa5271656d49e0b61ba8133b92a05e",
"End": "264e2d2a3442445180048463a555399a",
"Id": "46f9099ffb1a4e08ad78d7e13d36d8bc",
"IsHidden": "False"
},
{
"Start": "dffa5271656d49e0b61ba8133b92a05e",
"End": "f627c4088ee943aeba708e81f9945f1e",
"Id": "f167bc9b5eed4d5c96bac03015664979",
"IsHidden": "False"
}
],
"Dependencies": [],
"NodeLibraryDependencies": [],
"Thumbnail": "",
"GraphDocumentationURL": null,
"ExtensionWorkspaceData": [
{
"ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670",
"Name": "Properties",
"Version": "2.17",
"Data": {}
}
],
"Author": "",
"Linting": {
"activeLinter": "None",
"activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a",
"warningCount": 0,
"errorCount": 0
},
"Bindings": [],
"View": {
"Dynamo": {
"ScaleFactor": 1.0,
"HasRunWithoutCrash": true,
"IsVisibleInDynamoLibrary": true,
"Version": "2.17.0.3472",
"RunType": "Automatic",
"RunPeriod": "1000"
},
"Camera": {
"Name": "_Background Preview",
"EyeX": -17.0,
"EyeY": 24.0,
"EyeZ": 50.0,
"LookX": 12.0,
"LookY": -13.0,
"LookZ": -58.0,
"UpX": 0.0,
"UpY": 1.0,
"UpZ": 0.0
},
"ConnectorPins": [],
"NodeViews": [
{
"Name": "+",
"ShowGeometry": true,
"Id": "f8f4d3310211429ea8f301284983849e",
"IsSetAsInput": false,
"IsSetAsOutput": false,
"Excluded": false,
"X": 779.0,
"Y": 566.5
},
{
"Name": "Code Block",
"ShowGeometry": true,
"Id": "24cee4b3934f46309d34386a1b5a674a",
"IsSetAsInput": false,
"IsSetAsOutput": false,
"Excluded": false,
"X": 402.0,
"Y": 500.0
},
{
"Name": "Watch",
"ShowGeometry": true,
"Id": "26fc878922fd425a89112c6b14c9779b",
"IsSetAsInput": false,
"IsSetAsOutput": false,
"Excluded": false,
"X": 1102.0,
"Y": 587.0
}
],
"Annotations": [],
"X": 127.12026168573345,
"Y": 129.76719880218047,
"Zoom": 0.7658293928515516
}
}

View File

@@ -0,0 +1,106 @@
{
"Uuid": "76de5c79-17c5-4c74-9f90-ad99a213d339",
"IsCustomNode": false,
"Description": "",
"Name": "single_node",
"ElementResolver": {
"ResolutionMap": {}
},
"Inputs": [],
"Outputs": [],
"Nodes": [
{
"ConcreteType": "PythonNodeModels.PythonNode, PythonNodeModels",
"NodeType": "PythonScriptNode",
"Code": "# Load the Python Standard and DesignScript Libraries\r\nimport sys\r\nimport clr\r\nclr.AddReference('ProtoGeometry')\r\nfrom Autodesk.DesignScript.Geometry import *\r\n\r\n# The inputs to this node will be stored as a list in the IN variables.\r\ndataEnteringNode = IN\r\n\r\noutput = {\r\n \"python_version\": sys.version,\r\n \"asd_string\": \"asd_string\"\r\n}\r\n\r\n\r\n# Assign your output to the OUT variable.\r\nOUT = output",
"Engine": "CPython3",
"EngineName": "CPython3",
"VariableInputPorts": true,
"Id": "1c5d99792882409e97e132b3e9f814b0",
"Inputs": [
{
"Id": "7a29134d5d35492b80cd49a3ebac1847",
"Name": "IN[0]",
"Description": "Input #0",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Outputs": [
{
"Id": "a6a87605c777416bb759eaa87c976285",
"Name": "OUT",
"Description": "Result of the python script",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Replication": "Disabled",
"Description": "Runs an embedded Python script."
}
],
"Connectors": [],
"Dependencies": [],
"NodeLibraryDependencies": [],
"Thumbnail": "",
"GraphDocumentationURL": null,
"ExtensionWorkspaceData": [
{
"ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670",
"Name": "Properties",
"Version": "2.17",
"Data": {}
}
],
"Author": "",
"Linting": {
"activeLinter": "None",
"activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a",
"warningCount": 0,
"errorCount": 0
},
"Bindings": [],
"View": {
"Dynamo": {
"ScaleFactor": 1.0,
"HasRunWithoutCrash": true,
"IsVisibleInDynamoLibrary": true,
"Version": "2.17.0.3472",
"RunType": "Automatic",
"RunPeriod": "1000"
},
"Camera": {
"Name": "_Background Preview",
"EyeX": -17.0,
"EyeY": 24.0,
"EyeZ": 50.0,
"LookX": 12.0,
"LookY": -13.0,
"LookZ": -58.0,
"UpX": 0.0,
"UpY": 1.0,
"UpZ": 0.0
},
"ConnectorPins": [],
"NodeViews": [
{
"Name": "Python Script",
"ShowGeometry": true,
"Id": "1c5d99792882409e97e132b3e9f814b0",
"IsSetAsInput": false,
"IsSetAsOutput": false,
"Excluded": false,
"X": 208.0,
"Y": 367.0
}
],
"Annotations": [],
"X": 84.425000000000011,
"Y": -8.4125000000000227,
"Zoom": 1.1575
}
}

12
tests/support.py Normal file
View File

@@ -0,0 +1,12 @@
import pathlib
INPUT_DIR = "tests/input_files"
OUTPUT_DIR = "tests/output_files"
def cleanup_output_dir():
output_dir = pathlib.Path(OUTPUT_DIR)
if output_dir.exists():
for f in output_dir.iterdir():
f.unlink()
else:
output_dir.mkdir()

View File

@@ -1,6 +1,5 @@
import unittest
import subprocess
import platform
class TestCommandLine(unittest.TestCase):

View File

@@ -2,16 +2,8 @@ import unittest
import dyn2py
import pathlib
INPUT_DIR = "tests/input_files"
OUTPUT_DIR = "tests/output_files"
from tests.support import *
def cleanup_output_dir():
output_dir = pathlib.Path(OUTPUT_DIR)
if output_dir.exists():
for f in output_dir.iterdir():
f.unlink()
else:
output_dir.mkdir()
class TestDynamoFile(unittest.TestCase):
@@ -21,7 +13,7 @@ class TestDynamoFile(unittest.TestCase):
# update_python_node
# write
def test_read(self):
def test_read_and_variables(self):
dyn = dyn2py.DynamoFile(f"{INPUT_DIR}/python_nodes.dyn")
dyn.read()
@@ -38,7 +30,7 @@ class TestDynamoFile(unittest.TestCase):
dyn2.read()
def test_get_python_node(self):
def test_get_python_nodes(self):
dyn = dyn2py.DynamoFile(f"{INPUT_DIR}/python_nodes.dyn")
py_nodes = dyn.get_python_nodes()
py_node = dyn.get_python_node_by_id("d7704617c75e4bf1a5c387b7c3f001ea")
@@ -46,11 +38,19 @@ class TestDynamoFile(unittest.TestCase):
self.assertEqual(len(py_nodes), 6)
self.assertTrue(py_node)
self.assertTrue(py_node in py_nodes)
self.assertTrue(py_node in dyn.python_nodes)
self.assertEqual(py_node.checksum, "1f3d9e6153804fe1ed37571a9cda8e26")
with self.assertRaises(dyn2py.PythonNodeNotFoundException):
dyn.get_python_node_by_id("wrongid")
dyn2 = dyn2py.DynamoFile(f"{INPUT_DIR}/no_python.dyn")
# Raise error on file without python nodes:
with self.assertRaises(dyn2py.DynamoFileException):
dyn2.get_python_nodes()
def test_extract_python(self):
cleanup_output_dir()

92
tests/test_File.py Normal file
View File

@@ -0,0 +1,92 @@
import unittest
import dyn2py
import pathlib
import platform
from tests.support import *
class TestFile(unittest.TestCase):
# Methods to test:
# is_dynamo_file
# is_python_file
def test_init(self):
paths = [
f"{INPUT_DIR}/python_nodes.dyn",
pathlib.Path(f"{INPUT_DIR}/python_nodes.dyn")
]
if platform.system() == "Windows":
paths.extend([
fr"{INPUT_DIR}\python_nodes.dyn",
pathlib.Path(fr"{INPUT_DIR}\python_nodes.dyn")
])
for path in paths:
the_file = dyn2py.File(path)
self.assertEqual(the_file.filepath,
pathlib.Path(f"{INPUT_DIR}/python_nodes.dyn"))
self.assertEqual(the_file.basename, "python_nodes")
self.assertEqual(the_file.dirpath, pathlib.Path(INPUT_DIR))
self.assertEqual(the_file.realpath, pathlib.Path(path).resolve())
self.assertEqual(the_file.mtime, 1678287111.4672492)
self.assertEqual(the_file.mtimeiso, "2023-03-08T15:51:51.467249")
self.assertTrue(the_file.exists)
self.assertEqual(the_file.extension, ".dyn")
self.assertFalse(the_file.modified)
def test_init_newfile(self):
paths = [
f"{INPUT_DIR}/new_file.dyn",
pathlib.Path(f"{INPUT_DIR}/new_file.dyn")
]
if platform.system() == "Windows":
paths.extend([
fr"{INPUT_DIR}\new_file.dyn",
pathlib.Path(fr"{INPUT_DIR}\new_file.dyn")
])
for path in paths:
the_file = dyn2py.File(path)
self.assertEqual(the_file.filepath,
pathlib.Path(f"{INPUT_DIR}/new_file.dyn"))
self.assertEqual(the_file.basename, "new_file")
self.assertEqual(the_file.dirpath, pathlib.Path(INPUT_DIR))
self.assertEqual(the_file.realpath, pathlib.Path(path).resolve())
self.assertEqual(the_file.mtime, 0.0)
self.assertEqual(the_file.mtimeiso, "")
self.assertFalse(the_file.exists)
self.assertEqual(the_file.extension, ".dyn")
self.assertFalse(the_file.modified)
def test_newer(self):
older_file = dyn2py.File(f"{INPUT_DIR}/python_nodes.dyn")
newer_file = dyn2py.File(f"{INPUT_DIR}/no_python.dyn")
nonexisting_file = dyn2py.File(f"{INPUT_DIR}/new_file.dyn")
self.assertTrue(newer_file.is_newer(older_file))
self.assertTrue(newer_file.is_newer(nonexisting_file))
self.assertFalse(older_file.is_newer(newer_file))
self.assertTrue(older_file.is_newer(nonexisting_file))
self.assertFalse(nonexisting_file.is_newer(older_file))
self.assertFalse(nonexisting_file.is_newer(newer_file))
def test_write(self):
existing_file = dyn2py.File(f"{INPUT_DIR}/python_nodes.dyn")
nonexisting_file = dyn2py.File(f"{INPUT_DIR}/new_file.dyn")
options = dyn2py.Options()
with self.assertRaises(TypeError):
existing_file.write(options)
with self.assertRaises(TypeError):
nonexisting_file.write(options)

19
tests/test_PythonFile.py Normal file
View File

@@ -0,0 +1,19 @@
import unittest
from tests.support import *
class TestPythonFile(unittest.TestCase):
pass
# Missing variables:
# code
# header_data
# text
# open_files
# Missing methods:
# generate_text()
# update_dynamo()
# get_source_dynamo_file()
# read()
# write()

63
tests/test_PythonNode.py Normal file
View File

@@ -0,0 +1,63 @@
import unittest
import dyn2py
import hashlib
from tests.support import *
class TestPythonNode(unittest.TestCase):
def test_init_from_dyn(self):
dyn = dyn2py.DynamoFile(f"{INPUT_DIR}/single_node.dyn")
dyn.read()
node_dict = next((n for n in dyn.full_dict["Nodes"]
if n["NodeType"] == "PythonScriptNode"), {})
# Found a node:
self.assertTrue(node_dict)
node_views = dyn.full_dict["View"]["NodeViews"]
node = dyn2py.PythonNode(
node_dict_from_dyn=node_dict,
full_nodeviews_dict_from_dyn=node_views,
source_dynamo_file=dyn
)
self.assertEqual(node.id, "1c5d99792882409e97e132b3e9f814b0")
self.assertEqual(node.engine, "CPython3")
self.assertEqual(node.checksum, "ec2c85a11ddbf8375da03f11272d427a")
self.assertEqual(node.name, "Python Script")
self.assertEqual(
node.filename, "single_node_1c5d99792882409e97e132b3e9f814b0.py")
def test_init_from_py(self):
cleanup_output_dir()
# Extract py:
options = dyn2py.Options(python_folder=OUTPUT_DIR)
dyn = dyn2py.DynamoFile(f"{INPUT_DIR}/single_node.dyn")
dyn.extract_python(options)
# Open the extracted file and replace a string:
with open(f"{OUTPUT_DIR}/single_node_1c5d99792882409e97e132b3e9f814b0.py") as orig_py, \
open(f"{OUTPUT_DIR}/single_node_mod.py", "w") as mod_py:
for line in orig_py:
if "asd_string" in line:
line = line.replace("asd_string", "qwe_string")
mod_py.write(line)
py = dyn2py.PythonFile(f"{OUTPUT_DIR}/single_node_mod.py")
py.read()
node = dyn2py.PythonNode(
node_id=py.header_data["py_id"],
engine=py.header_data["py_engine"],
code=py.code,
checksum=hashlib.md5(py.code.encode()).hexdigest()
)
self.assertEqual(node.id, "1c5d99792882409e97e132b3e9f814b0")
self.assertEqual(node.engine, "CPython3")
self.assertEqual(node.checksum, "bf0f039ef6f11c3043e0821143801d48")