+ );
+};
+
+export default NodeSidebar;
diff --git a/src/convert_to_python.py b/src/convert_to_python.py
index 5d4e1a33..4f039d61 100644
--- a/src/convert_to_python.py
+++ b/src/convert_to_python.py
@@ -29,7 +29,36 @@ def convert_graph_to_python(graph_data: dict) -> str:
return template.render(context)
-def process_node_data(nodes: list[dict], edges: list[dict]) -> list[dict]:
+def make_var_name(node: dict) -> str:
+ """
+ Create a variable name from the node label, ensuring it is a valid Python identifier.
+ If the label contains invalid characters, they are replaced with underscores.
+ If the variable name is not unique, a number is appended to make it unique.
+
+ This is supposed to match the logic in NodeSidebar.jsx makeVarName function.
+ """
+ # Make a variable name from the label
+ invalid_chars = set("!@#$%^&*()+=[]{}|;:'\",.-<>?/\\`~")
+ base_var_name = node["data"]["label"].lower().replace(" ", "_")
+ for char in invalid_chars:
+ base_var_name = base_var_name.replace(char, "")
+
+ # Make the variable name unique by appending a number if needed
+ var_name = base_var_name
+ var_name = f"{base_var_name}_{node['id']}"
+
+ # Ensure the base variable name is a valid identifier
+ if not var_name.isidentifier():
+ var_name = f"var_{var_name}"
+ if not var_name.isidentifier():
+ raise ValueError(
+ f"Variable name must be a valid identifier. {node['data']['label']} to {var_name}"
+ )
+
+ return var_name
+
+
+def process_node_data(nodes: list[dict]) -> list[dict]:
"""
Given a list of node and edge data as dictionaries, process the nodes to create
variable names, class names, and expected arguments for each node.
@@ -38,30 +67,9 @@ def process_node_data(nodes: list[dict], edges: list[dict]) -> list[dict]:
The processed node data with variable names, class names, and expected arguments.
"""
nodes = nodes.copy()
- used_var_names = set()
for node in nodes:
- # Make a variable name from the label
- invalid_chars = set("!@#$%^&*()+=[]{}|;:'\",.-<>?/\\`~")
- base_var_name = node["data"]["label"].lower().replace(" ", "_")
- for char in invalid_chars:
- base_var_name = base_var_name.replace(char, "")
-
- # Ensure the base variable name is a valid identifier
- if not base_var_name.isidentifier():
- raise ValueError(
- f"Variable name must be a valid identifier. {node['data']['label']} to {base_var_name}"
- )
-
- # Make the variable name unique by appending a number if needed
- var_name = base_var_name
- counter = 1
- while var_name in used_var_names:
- var_name = f"{base_var_name}_{counter}"
- counter += 1
-
- node["var_name"] = var_name
- used_var_names.add(var_name)
+ node["var_name"] = make_var_name(node)
# Add pathsim class name
block_class = map_str_to_object.get(node["type"])
@@ -148,7 +156,7 @@ def process_graph_data_from_dict(data: dict) -> dict:
data = data.copy()
# Process nodes to create variable names and class names
- data["nodes"] = process_node_data(data["nodes"], data["edges"])
+ data["nodes"] = process_node_data(data["nodes"])
# Process to add source/target variable names to edges + ports
data["edges"] = make_edge_data(data)
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 00000000..e511ffbf
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,25 @@
+// Functions for managing global variables
+const isValidPythonIdentifier = (name) => {
+ // Check if name is empty
+ if (!name) return false;
+
+ // Python identifier rules:
+ // - Must start with letter or underscore
+ // - Can contain letters, digits, underscores
+ // - Cannot be a Python keyword
+ const pythonKeywords = [
+ 'False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue',
+ 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global',
+ 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass',
+ 'raise', 'return', 'try', 'while', 'with', 'yield'
+ ];
+
+ // Check if it's a keyword
+ if (pythonKeywords.includes(name)) return false;
+
+ // Check pattern: must start with letter or underscore, followed by letters, digits, or underscores
+ const pattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
+ return pattern.test(name);
+};
+
+export { isValidPythonIdentifier };
\ No newline at end of file
diff --git a/test/test_convert_python.py b/test/test_convert_python.py
index f20b9b50..1bd5fa28 100644
--- a/test/test_convert_python.py
+++ b/test/test_convert_python.py
@@ -138,7 +138,7 @@ def test_bubbler_has_reset_times():
"id": "1",
"type": "bubbler",
"data": {
- "label": "bubbler_1",
+ "label": "bubbler",
"replacement_times": "[10, 20]",
"conversion_efficiency": "1",
"vial_efficiency": "0.8",