Skip to content

Commit af02519

Browse files
reelmatthcat-pge
andauthored
Back-end code cleanup, docs, style (#91)
* chore: Change mentions of 'React' to generic 'ui-graph' * fix: Change node update from POST->PATCH to be RESTful * doc: Update/add docstrings for Nodes * fix: Update remaining Nodes to use flow_vars instead of `**self.options` * chore: Remove unused import statements * style: Update spacing, long line lengths * fix: Update (de)serialization of Workflow to include all attributes Slight modification to make method `to_json()` instead of `to_session_dict()`. Should be functionally the same. * style: Re-order method to group be by similar actions Alphabetical by group. Makes it easier to find, `add_edge` for example. * chore: Remove old TODOs that have been completed * fix: Update remaining Workflow calls to `to_json()` * test: Update to use new to_json method * chore: Update coverage badges --------- Co-authored-by: Matt Thomas <matthew_thomas@hms.harvard.edu>
1 parent 348106d commit af02519

File tree

18 files changed

+333
-268
lines changed

18 files changed

+333
-268
lines changed

back-end/pyworkflow/pyworkflow/node.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ def get_execution_options(self, workflow, flow_nodes):
4848
"""
4949
execution_options = dict()
5050

51-
# TODO: Can we iterate through flow_vars instead?
52-
# If none are included, we can just return `self.options`.
5351
for key, option in self.options.items():
5452

5553
if key in flow_nodes:

back-end/pyworkflow/pyworkflow/node_factory.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33

44

55
def node_factory(node_info):
6-
# Create a new Node with info
7-
# TODO: should perform error-checking or add default values if missing
6+
"""Create a new Node with info."""
87
node_type = node_info.get('node_type')
98
node_key = node_info.get('node_key')
109

back-end/pyworkflow/pyworkflow/nodes/flow_control/integer_input.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from pyworkflow.node import FlowNode, NodeException
1+
from pyworkflow.node import FlowNode
22
from pyworkflow.parameters import *
33

44

55
class IntegerNode(FlowNode):
6-
"""StringNode object
6+
"""IntegerNode object
77
8-
Allows for Strings to replace 'string' fields in Nodes
8+
Allows for Integers to replace fields representing numbers in Nodes
99
"""
1010
name = "Integer Input"
1111
num_in = 0

back-end/pyworkflow/pyworkflow/nodes/io/read_csv.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55

66

77
class ReadCsvNode(IONode):
8-
"""ReadCsvNode
9-
10-
Reads a CSV file into a pandas DataFrame.
8+
"""Reads a CSV file into a pandas DataFrame.
119
1210
Raises:
13-
NodeException: any error reading CSV file, converting
14-
to DataFrame.
11+
NodeException: any error reading CSV file, converting to DataFrame.
1512
"""
1613
name = "Read CSV"
1714
num_in = 0

back-end/pyworkflow/pyworkflow/nodes/io/write_csv.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55

66

77
class WriteCsvNode(IONode):
8-
"""WriteCsvNode
9-
10-
Writes the current DataFrame to a CSV file.
8+
"""Writes the current DataFrame to a CSV file.
119
1210
Raises:
13-
NodeException: any error writing CSV file, converting
14-
from DataFrame.
11+
NodeException: any error writing CSV file, converting from DataFrame.
1512
"""
1613
name = "Write CSV"
1714
num_in = 1

back-end/pyworkflow/pyworkflow/nodes/manipulation/filter.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55

66

77
class FilterNode(ManipulationNode):
8+
"""Subset the DataFrame rows or columns according to the specified index labels.
9+
10+
pandas API reference:
11+
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.filter.html
12+
13+
Raises:
14+
NodeException: catches exceptions when dealing with pandas DataFrames.
15+
"""
816
name = "Filter"
917
num_in = 1
1018
num_out = 1
@@ -31,7 +39,13 @@ class FilterNode(ManipulationNode):
3139
def execute(self, predecessor_data, flow_vars):
3240
try:
3341
input_df = pd.DataFrame.from_dict(predecessor_data[0])
34-
output_df = pd.DataFrame.filter(input_df, **self.options)
42+
output_df = pd.DataFrame.filter(
43+
input_df,
44+
items=flow_vars['items'].get_value(),
45+
like=flow_vars['like'].get_value(),
46+
regex=flow_vars['regex'].get_value(),
47+
axis=flow_vars['axis'].get_value(),
48+
)
3549
return output_df.to_json()
3650
except Exception as e:
3751
raise NodeException('filter', str(e))

back-end/pyworkflow/pyworkflow/nodes/manipulation/join.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@
55

66

77
class JoinNode(ManipulationNode):
8+
"""Merge DataFrame or named Series objects with a database-style join.
9+
10+
pandas API reference:
11+
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.merge.html
12+
13+
Raises:
14+
NodeException: catches exceptions when dealing with pandas DataFrames.
15+
"""
816
name = "Joiner"
917
num_in = 2
1018
num_out = 1
1119

1220
OPTIONS = {
13-
"on": StringParameter("Join Column", docstring="Name of column to join on")
21+
"on": StringParameter(
22+
"Join Column",
23+
docstring="Name of column to join on"
24+
)
1425
}
1526

1627
def execute(self, predecessor_data, flow_vars):

back-end/pyworkflow/pyworkflow/nodes/manipulation/pivot.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55

66

77
class PivotNode(ManipulationNode):
8+
"""Create a spreadsheet-style pivot table as a DataFrame.
9+
10+
pandas reference:
11+
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.pivot_table.html
12+
13+
Raises:
14+
NodeException: catches exceptions when dealing with pandas DataFrames.
15+
"""
816
name = "Pivoting"
917
num_in = 1
1018
num_out = 3
@@ -56,7 +64,18 @@ class PivotNode(ManipulationNode):
5664
def execute(self, predecessor_data, flow_vars):
5765
try:
5866
input_df = pd.DataFrame.from_dict(predecessor_data[0])
59-
output_df = pd.DataFrame.pivot_table(input_df, **self.options)
67+
output_df = pd.DataFrame.pivot_table(
68+
input_df,
69+
index=flow_vars['index'].get_value(),
70+
values=flow_vars['values'].get_value(),
71+
columns=flow_vars['columns'].get_value(),
72+
aggfunc=flow_vars['aggfunc'].get_value(),
73+
fill_value=flow_vars['fill_value'].get_value(),
74+
margins=flow_vars['margins'].get_value(),
75+
dropna=flow_vars['dropna'].get_value(),
76+
margins_name=flow_vars['margins_name'].get_value(),
77+
observed=flow_vars['observed'].get_value(),
78+
)
6079
return output_df.to_json()
6180
except Exception as e:
6281
raise NodeException('pivot', str(e))

back-end/pyworkflow/pyworkflow/tests/test_workflow.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_workflow_filename(self):
5353

5454
def test_workflow_from_json(self):
5555
new_workflow = Workflow("Untitled", root_dir="/tmp")
56-
workflow_copy = Workflow.from_json(self.workflow.to_session_dict())
56+
workflow_copy = Workflow.from_json(self.workflow.to_json())
5757

5858
self.assertEqual(new_workflow.name, workflow_copy.name)
5959

@@ -62,16 +62,17 @@ def test_workflow_from_json_key_error(self):
6262
new_workflow = Workflow.from_json(dict())
6363

6464
def test_empty_workflow_to_session(self):
65-
new_workflow = Workflow("Untitled", root_dir="/tmp")
66-
saved_workflow = new_workflow.to_session_dict()
65+
new_workflow = Workflow("Untitled", root_dir="/tmp", node_dir=os.path.join(os.getcwd(), 'nodes'))
66+
saved_workflow = new_workflow.to_json()
6767

6868
workflow_to_compare = {
6969
'name': 'Untitled',
7070
'root_dir': '/tmp',
71+
'node_dir': os.path.join(os.getcwd(), 'nodes'),
7172
'graph': Workflow.to_graph_json(new_workflow.graph),
7273
'flow_vars': Workflow.to_graph_json(new_workflow.flow_vars),
7374
}
74-
self.assertDictEqual(new_workflow.to_session_dict(), workflow_to_compare)
75+
self.assertDictEqual(new_workflow.to_json(), workflow_to_compare)
7576

7677
##########################
7778
# Node lists

0 commit comments

Comments
 (0)