diff --git a/pyproject.toml b/pyproject.toml index e1378ec1..b9b433b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,3 +87,10 @@ ignore = ["E501"] #ignore line-length violations [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] # Ignore unused imports in init files -- we specify APIs this way + +[tool.black] +extend-exclude = ''' +( + ^/docs +) +''' diff --git a/tests/integration/test_output_injection.py b/tests/integration/test_output_injection.py index 786fc0e6..b7db3832 100644 --- a/tests/integration/test_output_injection.py +++ b/tests/integration/test_output_injection.py @@ -169,7 +169,7 @@ def test_without_parent(self): d1, d2, msg="Outside the scope of a parent, we can't expect to re-access an " - "equivalent node", + "equivalent node", ) self.assertEqual( d1.label, diff --git a/tests/integration/test_parallel_speedup.py b/tests/integration/test_parallel_speedup.py index e3cbdefc..a59d0d29 100644 --- a/tests/integration/test_parallel_speedup.py +++ b/tests/integration/test_parallel_speedup.py @@ -63,14 +63,14 @@ def make_workflow(label): dt_parallel, 0.5 * dt_serial, msg=f"Expected the parallel solution to be at least 2x faster, but got" - f"{dt_parallel} and {dt_serial} for parallel and serial times, " - f"respectively", + f"{dt_parallel} and {dt_serial} for parallel and serial times, " + f"respectively", ) self.assertLess( dt_cached_parallel, 0.01 * t, msg="The cache should be trivially fast compared to actual execution of " - "a sleep node", + "a sleep node", ) def test_executor_instructions(self): @@ -93,8 +93,8 @@ def test_executor_instructions(self): dt, 1.1 * t, msg="Expected the sleeps to run in parallel with minimal overhead (since " - "it's just a thread pool executor) -- the advantage is that the " - "constructors should survive (de)serialization", + "it's just a thread pool executor) -- the advantage is that the " + "constructors should survive (de)serialization", ) diff --git a/tests/integration/test_provenance.py b/tests/integration/test_provenance.py index 48078d15..15609581 100644 --- a/tests/integration/test_provenance.py +++ b/tests/integration/test_provenance.py @@ -58,14 +58,14 @@ def test_executed_provenance(self): ["t", "slow", "fast", "double"], self.wf.prov.provenance_by_execution, msg="Later connections get priority over earlier connections, so we expect " - "the t-node to trigger 'slow' before 'fast'", + "the t-node to trigger 'slow' before 'fast'", ) self.assertListEqual( self.wf.prov.provenance_by_execution, self.wf.prov.provenance_by_completion, msg="The macro is running on an executor, but its children are in serial," - "so completion and execution order should be the same", + "so completion and execution order should be the same", ) def test_execution_vs_completion(self): @@ -82,14 +82,14 @@ def test_execution_vs_completion(self): ["t", "slow", "fast", "double"], self.wf.prov.provenance_by_execution, msg="Later connections get priority over earlier connections, so we expect " - "the t-node to trigger 'slow' before 'fast'", + "the t-node to trigger 'slow' before 'fast'", ) self.assertListEqual( ["t", "fast", "slow", "double"], self.wf.prov.provenance_by_completion, msg="Since 'slow' is slow it shouldn't _finish_ until after 'fast' (but " - "still before 'double' since 'double' depends on 'slow')", + "still before 'double' since 'double' depends on 'slow')", ) self.assertListEqual( diff --git a/tests/integration/test_transform.py b/tests/integration/test_transform.py index fd0370a4..69acb769 100644 --- a/tests/integration/test_transform.py +++ b/tests/integration/test_transform.py @@ -28,7 +28,7 @@ def test_list(self): inp_class, inp.__class__, msg="Regardless of origin, we expect to be constructing the exact same " - "class", + "class", ) self.assertIs(out_class, out.__class__) diff --git a/tests/integration/test_workflow.py b/tests/integration/test_workflow.py index fe6ed412..16cba1c5 100644 --- a/tests/integration/test_workflow.py +++ b/tests/integration/test_workflow.py @@ -179,7 +179,7 @@ def test_executors(self): self.assertFalse( wf.running, msg="The workflow should stop. For thread pool this required a " - "little sleep", + "little sleep", ) wf.executor = None @@ -192,8 +192,8 @@ def test_executors(self): self.assertFalse( any(n.running for n in wf), msg=f"All children should be done running -- for thread pools this " - f"requires a very short sleep -- got " - f"{[(n.label, n.running) for n in wf]}", + f"requires a very short sleep -- got " + f"{[(n.label, n.running) for n in wf]}", ) for child in wf: child.executor = None @@ -218,8 +218,8 @@ def Sleep(t): first_out, second_out, msg="Even thought the _input_ hasn't changed, we expect to avoid the first " - "(cached) result by virtue of resetting the cache when the body of " - "the composite graph has changed", + "(cached) result by virtue of resetting the cache when the body of " + "the composite graph has changed", ) t0 = time.perf_counter() @@ -234,7 +234,7 @@ def Sleep(t): dt, 0.1 * wf.c.inputs.t.value, msg="And because it used the cache we expect it much faster than the sleep " - "time", + "time", ) def test_failure(self): @@ -322,10 +322,10 @@ def test_failure(self): self.assertFalse( wf.as_path().exists(), msg=f"The parent-most object is the _only_ one who should have " - f"written a recovery file, so after removing that the whole " - f"node directory for the workflow should be cleaned up." - f"Instead, {wf.as_path()} exists and has content " - f"{[f for f in wf.as_path().iterdir()] if wf.as_path().is_dir() else None}", + f"written a recovery file, so after removing that the whole " + f"node directory for the workflow should be cleaned up." + f"Instead, {wf.as_path()} exists and has content " + f"{[f for f in wf.as_path().iterdir()] if wf.as_path().is_dir() else None}", ) diff --git a/tests/unit/mixin/test_preview.py b/tests/unit/mixin/test_preview.py index 7983155d..c8b3b8ad 100644 --- a/tests/unit/mixin/test_preview.py +++ b/tests/unit/mixin/test_preview.py @@ -70,7 +70,7 @@ def Mixed(x, y: int = 42): {"x": (None, NOT_DATA), "y": (int, 42)}, Mixed.preview_inputs(), msg="Input specifications should be available at the class level, with or " - "without type hints and/or defaults provided.", + "without type hints and/or defaults provided.", ) with ( @@ -179,10 +179,12 @@ def Branched(x) -> bool: with self.subTest("Uninspectable function"): def _uninspectable(): - template = dedent(""" + template = dedent( + """ def __source_code_not_available(x): return x - """) + """ + ) exec(template) return locals()["__source_code_not_available"] @@ -191,7 +193,7 @@ def __source_code_not_available(x): with self.assertRaises( OSError, msg="If the source code cannot be inspected for output labels, they " - "_must_ be provided.", + "_must_ be provided.", ): as_scraper()(f) diff --git a/tests/unit/mixin/test_run.py b/tests/unit/mixin/test_run.py index 0af18380..009e03b5 100644 --- a/tests/unit/mixin/test_run.py +++ b/tests/unit/mixin/test_run.py @@ -82,8 +82,8 @@ def test_runnable_not_ready(self): runnable.expected_run_output, result, msg="We should be able to bypass the readiness check with a flag, and " - "in this simple case expect to get perfectly normal behaviour " - "afterwards", + "in this simple case expect to get perfectly normal behaviour " + "afterwards", ) def test_failure(self): @@ -100,7 +100,7 @@ def test_failure(self): self.assertTrue( runnable.failed, msg="We should be able to stop the exception from getting raised, but the " - "status should still be failed", + "status should still be failed", ) def test_runnable_run_local(self): @@ -165,7 +165,7 @@ def maybe_get_executor(get_executor): with self.assertRaises( TypeError, msg="Callables are ok, but if they don't return an executor we should get " - "and error.", + "and error.", ): runnable.executor = (maybe_get_executor, (False,), {}) runnable.run() diff --git a/tests/unit/mixin/test_semantics.py b/tests/unit/mixin/test_semantics.py index 103b41dd..dd40c5f0 100644 --- a/tests/unit/mixin/test_semantics.py +++ b/tests/unit/mixin/test_semantics.py @@ -48,9 +48,9 @@ def test_semantic_delimiter(self): "/", Semantic.semantic_delimiter, msg="This is just a hard-code to the current value, update it freely so " - "the test passes; if it fails it's just a reminder that your change is " - "not backwards compatible, and the next release number should reflect " - "this.", + "the test passes; if it fails it's just a reminder that your change is " + "not backwards compatible, and the next release number should reflect " + "this.", ) def test_parent(self): @@ -121,26 +121,26 @@ def test_detached_parent_path(self): orphan.detached_parent_path.split(orphan.semantic_delimiter), self.child2.semantic_path.split(orphan.semantic_delimiter)[:-1], msg="Despite not having a parent, the detached path should store semantic " - "path info through the get/set state routine", + "path info through the get/set state routine", ) self.assertEqual( orphan.semantic_path, self.child2.semantic_path, msg="The detached path should carry through to semantic path in the " - "absence of a parent", + "absence of a parent", ) orphan.label = "orphan" # Re-set label after getting state orphan.parent = self.child2.parent self.assertIsNone( orphan.detached_parent_path, msg="Detached paths aren't necessary and shouldn't co-exist with the " - "presence of a parent", + "presence of a parent", ) self.assertListEqual( orphan.semantic_path.split(orphan.semantic_delimiter)[:-1], self.child2.semantic_path.split(self.child2.semantic_delimiter)[:-1], msg="Sanity check -- except for the now-different labels, we should be " - "recovering the usual semantic path on setting a parent.", + "recovering the usual semantic path on setting a parent.", ) diff --git a/tests/unit/nodes/test_composite.py b/tests/unit/nodes/test_composite.py index 3569dedb..af4ed8ee 100644 --- a/tests/unit/nodes/test_composite.py +++ b/tests/unit/nodes/test_composite.py @@ -72,7 +72,7 @@ def bar(x: int = 0) -> int: self.assertIsNone( from_instance.parent, msg="Wrappers are not creators, wrapping from the instance makes no " - "difference", + "difference", ) def test_node_addition(self): @@ -118,9 +118,9 @@ def test_node_access(self): with self.assertRaises( AttributeError, msg="Composites should override the attribute access portion of their " - "`HasIOWithInjection` mixin to guarantee that attribute access is " - "always looking for children. If attribute access is actually desired, " - " it can be accomplished with a `GetAttr` node.", + "`HasIOWithInjection` mixin to guarantee that attribute access is " + "always looking for children. If attribute access is actually desired, " + " it can be accomplished with a `GetAttr` node.", ): self.comp.not_a_child_or_attribute # noqa: B018 @@ -169,7 +169,7 @@ def test_label_uniqueness(self): with self.assertRaises( AttributeError, msg="The provided label is ok, but then assigning to baz should give " - "trouble since that name is already occupied", + "trouble since that name is already occupied", ): self.comp.foo = Composite.create.function_node(plus_one, label="whatever") @@ -206,7 +206,7 @@ def test_label_uniqueness(self): ["foo", "foo0"], list(self.comp.children.keys()), msg="When adding a node with an existing name and relaxed naming, the new " - "node should get an index on its label so each label is still unique", + "node should get an index on its label so each label is still unique", ) def test_singular_ownership(self): @@ -293,7 +293,7 @@ def different_output_channel(x: int = 0) -> int: self.comp.n3, replacement, msg="Sanity check -- when replacing with class, a _new_ instance " - "should be created", + "should be created", ) self.comp.replace_child(self.comp.n3, n3) @@ -302,7 +302,7 @@ def different_output_channel(x: int = 0) -> int: (0 + 2) + 1 + 1, self.comp.run(n1__x=0).n3__y, msg="Assigning a new _class_ to an existing node should be a shortcut " - "for replacement", + "for replacement", ) self.comp.replace_child(self.comp.n1, n1) # Return to original state @@ -311,7 +311,7 @@ def different_output_channel(x: int = 0) -> int: (0 + 10) + 1 + 1, self.comp.run(n1__z=0).n3__y, msg="Different IO should be compatible as long as what's missing is " - "not connected", + "not connected", ) self.comp.replace_child(self.comp.n1, n1) @@ -320,7 +320,7 @@ def different_output_channel(x: int = 0) -> int: (0 + 1) + 1 + 100, self.comp.run(n1__x=0).n3__z, msg="Different IO should be compatible as long as what's missing is " - "not connected", + "not connected", ) self.comp.replace_child(self.comp.n3, n3) @@ -373,7 +373,7 @@ def wrong_hint(x: float = 0) -> float: 3, self.comp.run().n3__y, msg="Failed replacements should always restore the original state " - "cleanly", + "cleanly", ) def test_length(self): @@ -441,7 +441,7 @@ def test_return(self): 1, self.comp.outputs.n1__y.value, msg="Sanity check that the output has been filled and is stored under the " - "name we think it is", + "name we think it is", ) # Make sure the returned object is functionally a dot-dict self.assertEqual(1, out["n1__y"], msg="Should work with item-access") @@ -499,7 +499,7 @@ def test_graph_info(self): self.assertTrue( top.middle_composite.deep_node.graph_path.startswith(top.graph_path), msg="The path should go to the parent-most object, recursively from " - "all depths.", + "all depths.", ) with self.subTest("test_graph_root"): @@ -535,7 +535,7 @@ def test_import_ready(self): self.assertFalse( bad_class.import_ready, msg="The node is in an importable location, but the imported object is not " - "the node class (but rather the node function)", + "the node class (but rather the node function)", ) with self.subTest(msg="Made up module"): og_module = totally_findable.__class__.__module__ @@ -552,7 +552,7 @@ def test_import_ready(self): self.assertTrue( self.comp.import_ready, msg="Sanity check on initial condition -- tests are in the path, so this " - "is importable", + "is importable", ) self.comp.totally_findable = totally_findable self.assertTrue( @@ -575,13 +575,13 @@ def test_with_executor(self): self.comp.sub_composite.parent, self.comp, msg="After processing a remotely-executed self, the local self should " - "retain its parent", + "retain its parent", ) self.assertIs( self.comp.sub_composite.executor, exe, msg="After processing a remotely-executed self, the local self should " - "retain its executor", + "retain its executor", ) def test_result_serialization(self): @@ -613,7 +613,7 @@ def test_result_serialization(self): self.assertFalse( self.comp.as_path().is_dir(), msg="Actually, we expect cleanup to have removed empty directories up to " - "and including the semantic root's own directory", + "and including the semantic root's own directory", ) diff --git a/tests/unit/nodes/test_for_loop.py b/tests/unit/nodes/test_for_loop.py index e3a3d3fd..00d62d1c 100644 --- a/tests/unit/nodes/test_for_loop.py +++ b/tests/unit/nodes/test_for_loop.py @@ -409,16 +409,16 @@ def test_body_node_executor(self): dt, grace * t_sleep, msg=f"Parallelization over children should result in faster " - f"completion. Expected limit {grace} x {t_sleep} = " - f"{grace * t_sleep} -- got {dt}", + f"completion. Expected limit {grace} x {t_sleep} = " + f"{grace * t_sleep} -- got {dt}", ) reloaded = pickle.loads(pickle.dumps(for_parallel)) self.assertIsNone( reloaded.body_node_executor, msg="Just like regular nodes, until executors can be delayed creators " - "instead of actual executor nodes, we need to purge executors from " - "nodes on serialization or the thread lock/queue objects hit us", + "instead of actual executor nodes, we need to purge executors from " + "nodes on serialization or the thread lock/queue objects hit us", ) def test_with_connections_dataframe(self): @@ -544,7 +544,7 @@ def test_shortcut(self): out.mul, [(1 + 1) * 1, (1 + 2) * 2], msg="We should be able to call for_node right from node classes to bypass " - "needing to provide the `body_node_class` argument", + "needing to provide the `body_node_class` argument", ) def test_macro_body(self): @@ -607,8 +607,8 @@ def test_executor_deserialization(self): n.body_node_executor, expected, msg="Executor instances should get removed on " - "(de)serialization, but instructions on how to build one " - "should not.", + "(de)serialization, but instructions on how to build one " + "should not.", ) finally: n.delete_storage() diff --git a/tests/unit/nodes/test_function.py b/tests/unit/nodes/test_function.py index 34e21635..3ea0af3c 100644 --- a/tests/unit/nodes/test_function.py +++ b/tests/unit/nodes/test_function.py @@ -48,7 +48,7 @@ def test_instantiation(self): NOT_DATA, node.outputs.y.value, msg="Sanity check that output just has the standard not-data value at " - "instantiation", + "instantiation", ) node.inputs.x = 10 self.assertIs( @@ -61,7 +61,7 @@ def test_instantiation(self): node.outputs.y.value, 11, msg="Expected the run to update the output -- did the test function" - "change or something?", + "change or something?", ) node = function_node(no_default, 1, y=2, output_labels="output") @@ -100,19 +100,19 @@ def test_defaults(self): with_defaults.inputs.x.value, 1, msg=f"Expected to get the default provided in the underlying function but " - f"got {with_defaults.inputs.x.value}", + f"got {with_defaults.inputs.x.value}", ) without_defaults = function_node(no_default) self.assertIs( without_defaults.inputs.x.value, NOT_DATA, msg=f"Expected values with no default specified to start as {NOT_DATA} but " - f"got {without_defaults.inputs.x.value}", + f"got {without_defaults.inputs.x.value}", ) self.assertFalse( without_defaults.ready, msg="I guess we should test for behaviour and not implementation... Without" - "defaults, the node should not be ready!", + "defaults, the node should not be ready!", ) def test_label_choices(self): @@ -170,7 +170,7 @@ def bilinear(x, y): bilinear(2, 3).run(), 2 * 3, msg="Children of `Function` should have their `node_function` exposed for " - "use at the class level", + "use at the class level", ) def test_statuses(self): @@ -184,7 +184,7 @@ def test_statuses(self): with self.assertRaises( TypeError, msg="We expect the int+str type error because there were no type hints " - "guarding this function from running with bad data", + "guarding this function from running with bad data", ): n.run() self.assertFalse(n.ready) @@ -239,7 +239,7 @@ def test_return_value(self): return_on_explicit_run, plus_one(2), msg="On explicit run, the most recent input data should be used and " - "the result should be returned", + "the result should be returned", ) return_on_call = node(1) @@ -284,13 +284,13 @@ def plus_one_hinted(x: int = 0) -> int: self.assertFalse( node.connected, msg="The x-input connection should have been copied, but should be " - "removed when the copy fails.", + "removed when the copy fails.", ) with self.assertRaises( ConnectionCopyError, msg="An unhinted channel is not a valid connection for a hinted " - "channel, and should raise and exception", + "channel, and should raise and exception", ): hinted_node._copy_connections(to_copy) hinted_node.disconnect() # Make sure you've got a clean slate @@ -305,14 +305,14 @@ def plus_one_hinted(x: int = 0) -> int: self.assertFalse( hinted_node.inputs.connected, msg="Without hard failure the copy should be allowed to proceed, but " - "we don't actually expect any connections to get copied since the " - "only one available had type hint problems", + "we don't actually expect any connections to get copied since the " + "only one available had type hint problems", ) self.assertTrue( hinted_node.outputs.connected, msg="Without hard failure the copy should be allowed to proceed, so " - "the output should connect fine since feeding hinted to un-hinted " - "is a-ok", + "the output should connect fine since feeding hinted to un-hinted " + "is a-ok", ) def test_copy_values(self): @@ -391,7 +391,7 @@ def test_easy_output_connection(self): n1.outputs.y, n2.inputs.x.connections, msg="Single-output functions should be able to make connections between " - "their output and another node's input by passing themselves", + "their output and another node's input by passing themselves", ) n1 >> n2 @@ -400,7 +400,7 @@ def test_easy_output_connection(self): n2.outputs.y.value, 3, msg="Single-output function connections should pass data just like usual; " - "in this case default->plus_one->plus_one = 1 + 1 +1 = 3", + "in this case default->plus_one->plus_one = 1 + 1 +1 = 3", ) at_instantiation = function_node(plus_one, x=n1) @@ -408,7 +408,7 @@ def test_easy_output_connection(self): n1.outputs.y, at_instantiation.inputs.x.connections, msg="The parsing of Single-output functions' output as a connection should " - "also work from assignment at instantiation", + "also work from assignment at instantiation", ) def test_nested_declaration(self): @@ -494,7 +494,7 @@ def NoReturn(x): {"None": type(None)}, NoReturn.preview_outputs(), msg="Functions without a return value should be permissible, although it " - "is not interesting", + "is not interesting", ) # Honestly, functions with no return should probably be made illegal to # encourage functional setups... @@ -534,8 +534,8 @@ def test_decoration(self): with self.assertRaises( MultipleDispatchError, msg="This shouldn't be accessible from a regular decorator usage pattern, " - "but make sure that mixing-and-matching argument-free calls and calls " - "directly providing the wrapped node fail cleanly", + "but make sure that mixing-and-matching argument-free calls and calls " + "directly providing the wrapped node fail cleanly", ): as_function_node(plus_one, "z") diff --git a/tests/unit/nodes/test_macro.py b/tests/unit/nodes/test_macro.py index 92e7f59c..6b9fc605 100644 --- a/tests/unit/nodes/test_macro.py +++ b/tests/unit/nodes/test_macro.py @@ -149,7 +149,7 @@ def test_creation_from_decorator(self): m.outputs.three__result.value, NOT_DATA, msg="Output should be accessible with the usual naming convention, but we " - "have not run yet so there shouldn't be any data", + "have not run yet so there shouldn't be any data", ) input_x = 1 @@ -234,7 +234,7 @@ def test_with_executor(self): NOT_DATA, downstream.outputs.result.value, msg="Downstream events should not yet have triggered either, we should wait" - "for the callback when the result is ready", + "for the callback when the result is ready", ) returned_nodes = result.result(timeout=120) # Wait for the process to finish @@ -280,7 +280,7 @@ def test_with_executor(self): 0 + 3 + 1, downstream.outputs.result.value, msg="The finishing callback should also fire off the ran signal triggering" - "downstream execution", + "downstream execution", ) macro.executor_shutdown() @@ -297,15 +297,15 @@ def test_pulling_from_inside_a_macro(self): 0 + 1 + 1, macro.two.pull(run_parent_trees_too=False), msg="Without running parent trees, the pulling should only run upstream " - "nodes _inside_ the scope of the macro, relying on the explicit input" - "value", + "nodes _inside_ the scope of the macro, relying on the explicit input" + "value", ) self.assertEqual( (2 + 1) + 1 + 1, macro.two.pull(run_parent_trees_too=True), msg="Running with parent trees, the pulling should also run the parents " - "data dependencies first", + "data dependencies first", ) def test_recovery_after_failed_pull(self): @@ -340,7 +340,7 @@ def grab_connections(macro): initial_labels, list(m.children.keys()), msg="Labels should be restored after failing to pull because of " - "acyclicity", + "acyclicity", ) self.assertTrue( all( @@ -350,7 +350,7 @@ def grab_connections(macro): ) ), msg="Connections should be restored after failing to pull because of " - "cyclic data flow", + "cyclic data flow", ) with self.subTest("When the parent scope has cyclic data flow"): @@ -384,7 +384,7 @@ def grab_connections(macro): ) ), msg="Connections should be restored after failing to pull because of " - "cyclic data flow in the outer scope", + "cyclic data flow in the outer scope", ) self.assertEqual( "n1", n1.label, msg="Labels should get restored in the outer scope" @@ -393,7 +393,7 @@ def grab_connections(macro): "one", m.one.label, msg="Labels should not have even gotten perturbed to start with in the" - "inner scope", + "inner scope", ) with self.subTest("When a node breaks upstream"): @@ -437,7 +437,7 @@ def MutlipleUseInput(self, x): 2 + 1, len(m), msg="Signature input that is forked to multiple children should result " - "in the automatic creation of a new node to manage the forking.", + "in the automatic creation of a new node to manage the forking.", ) with self.subTest("Single destination input"): @@ -452,7 +452,7 @@ def SingleUseInput(self, x): 1, len(m), msg=f"Signature input with only one destination should not create an " - f"interface node. Found nodes {m.child_labels}", + f"interface node. Found nodes {m.child_labels}", ) with self.subTest("Mixed input"): @@ -507,12 +507,12 @@ def test_storage_for_modified_macros(self): demo_nodes.AddThree.__name__, reloaded.__class__.__name__, msg=f"LOOK OUT! This all (de)serialized nicely, but what we " - f"loaded is _falsely_ claiming to be an " - f"{demo_nodes.AddThree.__name__}. This is " - f"not any sort of technical error -- what other class name " - f"would we load? -- but is a deeper problem with saving " - f"modified objects that we need ot figure out some better " - f"solution for later.", + f"loaded is _falsely_ claiming to be an " + f"{demo_nodes.AddThree.__name__}. This is " + f"not any sort of technical error -- what other class name " + f"would we load? -- but is a deeper problem with saving " + f"modified objects that we need ot figure out some better " + f"solution for later.", ) rerun = reloaded() @@ -520,8 +520,8 @@ def test_storage_for_modified_macros(self): reloaded.two, demo_nodes.AddPlusOne, msg="pickle instantiates the macro node class, but " - "but then uses its serialized state, so we retain " - "the replaced node.", + "but then uses its serialized state, so we retain " + "the replaced node.", ) self.assertDictEqual( modified_result, @@ -583,14 +583,14 @@ def test_pickle(self): self.assertFalse( reloaded_two.connected, msg="Children are expected to be de-parenting on serialization, so that if " - "we ship them off to another process, they don't drag their whole " - "graph with them", + "we ship them off to another process, they don't drag their whole " + "graph with them", ) self.assertEqual( m.two.outputs.to_value_dict(), reloaded_two.outputs.to_value_dict(), msg="The remainder of the child node state should be recovering just " - "fine on (de)serialization, this is a spot-check", + "fine on (de)serialization, this is a spot-check", ) def test_autoload(self): @@ -610,9 +610,9 @@ def AutoloadsChildren(self, x): AutoloadsChildren().some_child.outputs.x.value, existing_node.outputs.x.value, msg="Autoloading macro children can result in a child node coming with " - "pre-loaded data if the child's label at instantiation results in a " - "match with some already-saved node (if the load is compatible). This " - "is almost certainly undesirable", + "pre-loaded data if the child's label at instantiation results in a " + "match with some already-saved node (if the load is compatible). This " + "is almost certainly undesirable", ) @as_macro_node @@ -625,8 +625,8 @@ def AutofailsChildren(self, x): with self.assertRaises( TypeError, msg="When the macro auto-loads a child but the loaded type is not " - "compatible with the child type, we will even get an error at macro " - "instantiation time! Autoloading macro children is really not wise.", + "compatible with the child type, we will even get an error at macro " + "instantiation time! Autoloading macro children is really not wise.", ): AutofailsChildren() @@ -639,9 +639,9 @@ def DoesntAutoloadChildren(self, x): DoesntAutoloadChildren().some_child.outputs.x.value, NOT_DATA, msg="Despite having the same label as a saved node at instantiation time, " - "without autoloading children, our macro safely gets a fresh instance. " - "Since this is clearly preferable, here we leave autoload to take its " - "default value (which for macros should thus not autoload.)", + "without autoloading children, our macro safely gets a fresh instance. " + "Since this is clearly preferable, here we leave autoload to take its " + "default value (which for macros should thus not autoload.)", ) finally: existing_node.delete_storage("pickle") diff --git a/tests/unit/nodes/test_transform.py b/tests/unit/nodes/test_transform.py index a26ceb1d..569fc799 100644 --- a/tests/unit/nodes/test_transform.py +++ b/tests/unit/nodes/test_transform.py @@ -87,7 +87,7 @@ def test_inputs_to_dict(self): with self.assertRaises( ValueError, msg="List instances are not hashable, we should not be able to auto-" - "generate a class name from this.", + "generate a class name from this.", ): inputs_to_dict(unhashable_spec) @@ -126,7 +126,7 @@ def test_inputs_to_dataframe(self): with self.assertRaises( ValueError, msg="If the input rows don't have commensurate length, we expect to get " - "the relevant pandas error", + "the relevant pandas error", ): n(row_0=d1, row_1=d3, row_2=d1) @@ -159,11 +159,11 @@ class DC: self.assertTrue( is_dataclass(DC), msg="Note that passing the underlying dataclass variable through the " - "`dataclasses.dataclass` operator actually transforms it, so it " - "too is now a real dataclass, even though it wasn't defined as " - "one! This is just a side effect. I don't see it being harmful, " - "but in case it gives some future reader trouble, I want to " - "explicitly note the side effect here in the tests.", + "`dataclasses.dataclass` operator actually transforms it, so it " + "too is now a real dataclass, even though it wasn't defined as " + "one! This is just a side effect. I don't see it being harmful, " + "but in case it gives some future reader trouble, I want to " + "explicitly note the side effect here in the tests.", ) self.assertListEqual( list(DC.__dataclass_fields__.keys()), @@ -246,7 +246,7 @@ class DecoratedDCLike: prev["with_factory"][1], NOT_DATA, msg="Fields with default factory won't see their default until " - "instantiation", + "instantiation", ) def test_dataclass_typing_and_storage(self): diff --git a/tests/unit/test_channels.py b/tests/unit/test_channels.py index fda17d62..eaeb4a85 100644 --- a/tests/unit/test_channels.py +++ b/tests/unit/test_channels.py @@ -170,7 +170,7 @@ def test_fetch(self): self.ni1.value, 3, msg="Data fetch should to first connected value that's actually data," - "in this case skipping over no_empty", + "in this case skipping over no_empty", ) self.no_empty.value = 4 @@ -179,7 +179,7 @@ def test_fetch(self): self.ni1.value, 4, msg="As soon as no_empty actually has data, it's position as 0th " - "element in the connections list should give it priority", + "element in the connections list should give it priority", ) def test_connection_validity(self): @@ -228,14 +228,14 @@ def test_copy_connections(self): with self.assertRaises( ChannelConnectionError, msg="Should not be able to connect to so1 because of type hint " - "incompatibility", + "incompatibility", ): self.ni2.copy_connections(self.ni1) self.assertListEqual( self.ni2.connections, [self.no_empty], msg="On failing, copy should revert the copying channel to its orignial " - "state", + "state", ) def test_value_receiver(self): @@ -317,12 +317,12 @@ def test_ready(self): without_default.value, NOT_DATA, msg=f"Without a default, spec is to have a NOT_DATA value but got " - f"{type(without_default.value)}", + f"{type(without_default.value)}", ) self.assertFalse( without_default.ready, msg="Even without type hints, readiness should be false when the value " - "is NOT_DATA", + "is NOT_DATA", ) self.ni1.value = 1 @@ -392,7 +392,7 @@ def test_aggregating_call(self): with self.assertRaises( TypeError, msg="For an aggregating input signal, it _matters_ who called it, so " - "receiving an output signal is not optional", + "receiving an output signal is not optional", ): agg() @@ -446,7 +446,7 @@ def test_aggregating_call(self): [0, 1, 2], owner.foo, msg="Having a vestigial received signal (i.e. one from an output signal " - "that is no longer connected) shouldn't hurt anything", + "that is no longer connected) shouldn't hurt anything", ) self.assertEqual( 0, diff --git a/tests/unit/test_find.py b/tests/unit/test_find.py index 812f78ad..4243947d 100644 --- a/tests/unit/test_find.py +++ b/tests/unit/test_find.py @@ -34,13 +34,13 @@ def test_find_nodes(self): [o.__name__ for o in found_by_path], [o.__name__ for o in found_by_string], msg=f"You should find the same thing regardless of source representation;" - f"by path got {found_by_path} and by string got {found_by_string}", + f"by path got {found_by_path} and by string got {found_by_string}", ) self.assertListEqual( [o.__name__ for o in found_by_string], [o.__name__ for o in found_by_module], msg=f"You should find the same thing regardless of source representation;" - f"by string got {found_by_string} and by module got {found_by_module}", + f"by string got {found_by_string} and by module got {found_by_module}", ) self.assertListEqual( [o.__name__ for o in found_by_string], @@ -51,8 +51,8 @@ def test_find_nodes(self): demo_nodes.OptionallyAdd.__name__, ], msg=f"Should match a hand-selected expectation list that ignores the " - f"private and non-local nodes. If you update the demo nodes this may " - f"fail and need to be trivially updated. Got {found_by_module}", + f"private and non-local nodes. If you update the demo nodes this may " + f"fail and need to be trivially updated. Got {found_by_module}", ) diff --git a/tests/unit/test_io.py b/tests/unit/test_io.py index 614f1fef..32a58a2e 100644 --- a/tests/unit/test_io.py +++ b/tests/unit/test_io.py @@ -89,7 +89,7 @@ def test_assignment(self): self.post_facto_output.label, label_before_assignment, msg="Labels should not get updated on assignment of channels to IO " - "collections", + "collections", ) def test_connection(self): @@ -163,7 +163,7 @@ def test_connections_property(self): self.input.connections[0], self.input.x.connections[0], msg="The IO connection found should be the same object as the channel " - "connection", + "connection", ) def test_to_list(self): @@ -171,8 +171,8 @@ def test_to_list(self): [0.0, 1.0], self.input.to_list(), msg="Expected a shortcut to channel values. Order is explicitly not " - "guaranteed in the docstring, but it would be nice to appear in the " - "order the channels are added here", + "guaranteed in the docstring, but it would be nice to appear in the " + "order the channels are added here", ) @@ -363,7 +363,7 @@ def test_copy_io(self): with self.assertRaises( ConnectionCopyError, msg="The copier is missing all sorts of connected channels and should " - "fail to copy", + "fail to copy", ): copier.copy_io( to_copy, connections_fail_hard=True, values_fail_hard=False @@ -371,7 +371,7 @@ def test_copy_io(self): self.assertFalse( copier.connected, msg="After a failure, any connections that _were_ made should get " - "reset", + "reset", ) with self.subTest("Force missing connections"): @@ -444,7 +444,7 @@ def test_copy_io(self): self.assertRaises( ValueCopyError, msg="The copier doesn't have channels to hold all the values that need" - "copying, so we should fail", + "copying, so we should fail", ), ): copier.copy_io(to_copy, connections_fail_hard=True, values_fail_hard=True) diff --git a/tests/unit/test_node.py b/tests/unit/test_node.py index df004cbc..25119400 100644 --- a/tests/unit/test_node.py +++ b/tests/unit/test_node.py @@ -116,7 +116,7 @@ def test_check_readiness(self): self.assertFalse( self.n3.failed, msg="The benefit of the readiness check should be that we don't actually " - "qualify as failed", + "qualify as failed", ) with self.assertRaises( @@ -142,7 +142,7 @@ def test_check_readiness(self): 1, self.n3.run(run_data_tree=False, fetch_input=False, check_readiness=True), msg="After manually resetting the failed state and providing good input, " - "running should proceed", + "running should proceed", ) self.n3.use_cache = n3_cache @@ -161,7 +161,7 @@ def test_emit_ran_signal(self): add_one(add_one(add_one(self.n1.inputs.x.value))), self.n3.outputs.y.value, msg="With the connection and signal, we should have pushed downstream " - "execution", + "execution", ) def test_failure_signal(self): @@ -194,7 +194,7 @@ def test_failure_recovery(self): self.assertFalse( n.as_path().exists(), msg="When the run exception is not raised, we don't expect any " - "recovery file to be needed", + "recovery file to be needed", ) default_recovery = n.recovery @@ -205,7 +205,7 @@ def test_failure_recovery(self): self.assertFalse( n.has_saved_content(filename=n.as_path().joinpath("recovery")), msg="Without a recovery back end specified, we don't expect a file to " - "be saved on failure.", + "be saved on failure.", ) n.recovery = default_recovery @@ -239,7 +239,7 @@ def test_failure_recovery(self): self.assertFalse( n.as_path().exists(), msg="The recovery file should have been the only thing in the node " - "directory, so cleaning should remove the directory entirely.", + "directory, so cleaning should remove the directory entirely.", ) def test_execute(self): @@ -253,7 +253,7 @@ def test_execute(self): self.assertFalse( self.n3.ready, msg="Executing should not be triggering downstream runs, even though we " - "made a ran/run connection", + "made a ran/run connection", ) self.n2.inputs.x._value = "manually override the desired int" @@ -261,7 +261,7 @@ def test_execute(self): with self.assertRaises( TypeError, msg="Execute should be running without a readiness check and hitting the " - "string + int error", + "string + int error", ): self.n2.execute() @@ -278,7 +278,7 @@ def test_pull(self): self.assertFalse( self.n3.ready, msg="Pulling should not be triggering downstream runs, even though we " - "made a ran/run connection", + "made a ran/run connection", ) def test___call__(self): @@ -296,7 +296,7 @@ def test___call__(self): self.assertFalse( self.n3.ready, msg="Calling should not be triggering downstream runs, even though we " - "made a ran/run connection", + "made a ran/run connection", ) def test_draw(self): @@ -313,7 +313,7 @@ def test_draw(self): self.assertTrue( self.n1.as_path().joinpath(expected_name).is_file(), msg="If `save` is called, expect the rendered image to " - "exist in the working directory", + "exist in the working directory", ) user_specified_name = "foo" @@ -322,7 +322,7 @@ def test_draw(self): self.assertTrue( self.n1.as_path().joinpath(expected_name).is_file(), msg="If the user specifies a filename, we should assume they want the " - "thing saved", + "thing saved", ) finally: # No matter what happens in the tests, clean up after yourself @@ -350,14 +350,14 @@ def test_graph_info(self): n.semantic_delimiter + n.label, n.graph_path, msg="Lone nodes should just have their label as the path, as there is no " - "parent above.", + "parent above.", ) self.assertIs( n, n.graph_root, msg="Lone nodes should be their own graph_root, as there is no parent " - "above.", + "above.", ) def test_single_value(self): @@ -366,7 +366,7 @@ def test_single_value(self): node.outputs.y, node.channel, msg="With a single output, the `HasChannel` interface fulfillment should " - "use that output.", + "use that output.", ) with_addition = node + 5 @@ -374,7 +374,7 @@ def test_single_value(self): with_addition, Node, msg="With a single output, acting on the node should fall back on acting " - "on the single (with-injection) output", + "on the single (with-injection) output", ) node2 = ANode(label="n2") @@ -383,14 +383,14 @@ def test_single_value(self): [node.outputs.y], node2.inputs.x.connections, msg="With a single output, the node should fall back on the single output " - "for output-like use cases", + "for output-like use cases", ) node.outputs["z"] = OutputDataWithInjection("z", node, type_hint=int) with self.assertRaises( AmbiguousOutputError, msg="With multiple outputs, trying to exploit the `HasChannel` interface " - "should fail cleanly", + "should fail cleanly", ): node.channel # noqa: B018 @@ -450,7 +450,7 @@ def test_storage(self): load_and_rerun_origal_input.outputs.y.value, run_right_away.outputs.y.value, msg="Loading and then running immediately is fine, and should " - "recover existing input", + "recover existing input", ) load_and_rerun_new_input = ANode( label=self.n1.label, x=x + 1, autorun=True, autoload=backend @@ -459,7 +459,7 @@ def test_storage(self): load_and_rerun_new_input.outputs.y.value, run_right_away.outputs.y.value + 1, msg="Loading and then running immediately is fine, and should " - "notice the new input", + "notice the new input", ) force_run = ANode( @@ -544,7 +544,7 @@ def test_checkpoint(self): NOT_DATA, not_reloaded.outputs.y.value, msg="Should not have saved, therefore should have been nothing " - "to load", + "to load", ) find_saved = ANode(label="run_and_save", autoload=backend) @@ -552,7 +552,7 @@ def test_checkpoint(self): y, find_saved.outputs.y.value, msg="Should have saved automatically after run, and reloaded " - "on instantiation", + "on instantiation", ) finally: saves.delete_storage(backend) # Clean up @@ -584,7 +584,7 @@ def test_result_serialization(self): self.assertFalse( n.as_path().is_dir(), msg="Actually, we expect cleanup to have removed empty directories up to " - "and including the node's own directory", + "and including the node's own directory", ) diff --git a/tests/unit/test_output_parser.py b/tests/unit/test_output_parser.py index aecfcd2a..169410da 100644 --- a/tests/unit/test_output_parser.py +++ b/tests/unit/test_output_parser.py @@ -23,7 +23,7 @@ def add(x, y): with self.subTest("Weird whitespace"): def add_with_whitespace(x, y): - return x + y + return x + y self.assertListEqual(ParseOutput(add_with_whitespace).output, ["x + y"]) diff --git a/tests/unit/test_storage.py b/tests/unit/test_storage.py index f6c26d32..8587c4ba 100644 --- a/tests/unit/test_storage.py +++ b/tests/unit/test_storage.py @@ -14,8 +14,8 @@ def test_default_backend(self): backends[0], PickleStorage, msg="If more standard backends are added, this will fail -- that's fine, " - "just update the test to make sure you're getting the defaults you now " - "expect.", + "just update the test to make sure you're getting the defaults you now " + "expect.", ) def test_specific_backend(self): @@ -24,8 +24,8 @@ def test_specific_backend(self): len(backends), 1, msg="Once more standard backends are available, we should test that string " - "access results in the the correct priority assignment among these " - "defaults.", + "access results in the the correct priority assignment among these " + "defaults.", ) self.assertIsInstance(backends[0], PickleStorage) diff --git a/tests/unit/test_workflow.py b/tests/unit/test_workflow.py index e74dcd26..174013d3 100644 --- a/tests/unit/test_workflow.py +++ b/tests/unit/test_workflow.py @@ -141,7 +141,7 @@ def test_io_map_bijectivity(self): with self.assertRaises( ValueDuplicationError, msg="Should not be allowed to update a second child's channel onto an " - "existing mapped channel", + "existing mapped channel", ): wf.inputs_map["n2__x"] = "x" @@ -201,7 +201,7 @@ def test_with_executor(self): self.assertIsNone( original_a.parent, msg=f"Original nodes should be orphaned, but {original_a.full_label} has " - f"parent {original_a.parent}", + f"parent {original_a.parent}", # Note: At time of writing, this is accomplished in Node.__getstate__, # which feels a bit dangerous... ) @@ -243,7 +243,7 @@ def test_parallel_execution(self): wf.sum.outputs.sum.value, 5 + 5, msg="After the slow node completes, its output should be updated as a " - "callback, and downstream nodes should proceed", + "callback, and downstream nodes should proceed", ) wf.executor_shutdown() @@ -270,7 +270,7 @@ def sum_(a, b): plus_one(42) + plus_one(42), wf.sum.outputs.sum.value, msg="Workflow should accept input channel kwargs and update inputs " - "accordingly", + "accordingly", # Since the nodes run automatically, there is no need for wf.run() here ) @@ -290,7 +290,7 @@ def test_return_value(self): return_on_call, DotDict({"b__y": 1 + 2}), msg="Run output should be returned on call. Expecting a DotDict of " - "output values", + "output values", ) wf.inputs.a__x = 2 @@ -299,7 +299,7 @@ def test_return_value(self): return_on_explicit_run["b__y"], 2 + 2, msg="On explicit run, the most recent input data should be used and " - "the result should be returned", + "the result should be returned", ) def test_execution_automation(self): @@ -355,7 +355,7 @@ def matches_expectations(results): user.n1r.signals.output.ran, user.n2r.signals.input.accumulate_and_run.connections, msg="The automated flow uses a non-linear accumulating approach, so the " - "accumulating run signal is the one that should hold a connection", + "accumulating run signal is the one that should hold a connection", ) with self.subTest("Make sure automated cyclic graphs throw an error"):