From 43a9cc02f74289118d80d0f9110799fc723c36e7 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:05:14 -0700 Subject: [PATCH 1/8] Update tests for compliance URIs are not inherited, so add them. And the undesirable side effect of inheriting restrictions has been resolved upstream, so adapt/remove those tests. Signed-off-by: liamhuber --- tests/integration/test_suggest.py | 69 +++++++++++++++++-------------- tests/unit/test_knowledge.py | 13 ++++-- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/tests/integration/test_suggest.py b/tests/integration/test_suggest.py index af2733fc..7d8226db 100644 --- a/tests/integration/test_suggest.py +++ b/tests/integration/test_suggest.py @@ -9,7 +9,6 @@ from semantikon.metadata import u import pyiron_workflow as pwf -from pyiron_workflow.channels import ChannelConnectionError from pyiron_workflow.nodes import static_io from pyiron_workflow.suggest import ( ConnectedInputError, @@ -30,7 +29,12 @@ def __init__(self, contents=None): @pwf.as_function_node def AddNuts( gets_nuts: u(Storage, uri=EX.Shelf), -) -> u(Storage, derived_from="inputs.gets_nuts", triples=(EX.hasComponents, EX.nut)): +) -> u( + Storage, + uri=EX.Shelf, + derived_from="inputs.gets_nuts", + triples=(EX.hasComponents, EX.nut), +): has_nuts = gets_nuts return has_nuts @@ -39,7 +43,10 @@ def AddNuts( def AddWashers( gets_washer: u(Storage, uri=EX.Shelf), ) -> u( - Storage, derived_from="inputs.gets_washer", triples=(EX.hasComponents, EX.washer) + Storage, + uri=EX.Shelf, + derived_from="inputs.gets_washer", + triples=(EX.hasComponents, EX.washer), ): # Like a washer, the purpose here is to go between the nuts and bolts # In our case, to make sure we catch and avoid circular connection suggestions @@ -50,7 +57,12 @@ def AddWashers( @pwf.as_function_node def AddBolts( gets_bolts: u(Storage, uri=EX.Shelf), -) -> u(Storage, derived_from="inputs.gets_bolts", triples=(EX.hasComponents, EX.bolt)): +) -> u( + Storage, + uri=EX.Shelf, + derived_from="inputs.gets_bolts", + triples=(EX.hasComponents, EX.bolt), +): has_bolts = gets_bolts return has_bolts @@ -75,7 +87,12 @@ def AssembleShelf( ), ), ), -) -> u(Storage, derived_from="inputs.to_assemble", triples=(EX.hasState, EX.assembled)): +) -> u( + Storage, + uri=EX.Shelf, + derived_from="inputs.to_assemble", + triples=(EX.hasState, EX.assembled), +): assembled = to_assemble return assembled @@ -91,7 +108,12 @@ def PlaceBooks( ), ), *books: str, -) -> u(Storage, derived_from="inputs.bookshelf", triples=(EX.hasContents, EX.book)): +) -> u( + Storage, + uri=EX.Shelf, + derived_from="inputs.bookshelf", + triples=(EX.hasContents, EX.book), +): bookshelf.contents = books return bookshelf @@ -109,7 +131,7 @@ def NoHints(shelf): @pwf.as_function_node def WrongHint( fridge: u(Storage, uri=EX.Fridge), -) -> u(Storage, derived_from="inputs.fridge"): +) -> u(Storage, uri=EX.Fridge, derived_from="inputs.fridge"): return fridge @@ -160,13 +182,6 @@ def setUp(self): self.wf.no_hints = NoHints() self.wf.wrong_hint = WrongHint() - def test_unfulfilled_restrictions(self): - with self.assertRaises( - ChannelConnectionError, - msg=INHERITANCE_DISCLAIMER, - ): - self.wf.bookshelf.inputs.bookshelf = self.wf.assembled.outputs.assembled - def test_exceptions(self): with self.subTest("Connected input"): for channel in [ @@ -258,10 +273,8 @@ def test_input_connection_suggestions(self): with self.subTest("Fulfilled suggestions present"): self.assertIn(self.wf.bolts, suggestions[self.wf.assembled]) - with self.subTest( - "Side effect in derived from: unfulfilled restrictions get inherited" - ): - self.assertNotIn( + with self.subTest("Unfulfilled upstream restrictions do not get inherited"): + self.assertIn( self.wf.assembled, suggestions[self.wf.bookshelf], msg=INHERITANCE_DISCLAIMER, @@ -322,10 +335,8 @@ def test_output_connection_suggestions(self): with self.subTest("Fulfilled suggestions present"): self.assertIn(self.wf.assembled, suggestions[self.wf.bolts]) - with self.subTest( - "Side effect in derived from: unfulfilled restrictions get inherited" - ): - self.assertNotIn( + with self.subTest("Unfulfilled upstream restrictions do not get inherited"): + self.assertIn( self.wf.bookshelf, suggestions[self.wf.assembled], msg=INHERITANCE_DISCLAIMER, @@ -393,10 +404,8 @@ def test_input_node_suggestions(self): "might be nice in the future.", ) - with self.subTest( - "Side effect in derived from: unfulfilled restrictions get inherited" - ): - self.assertNotIn( + with self.subTest("Unfulfilled upstream restrictions do not get inherited"): + self.assertIn( AssembleShelf, suggestions[self.wf.bookshelf], msg=INHERITANCE_DISCLAIMER, @@ -419,10 +428,8 @@ def test_output_node_suggestions(self): hinted_corpus.remove(NoHints) self.assertListEqual(hinted_corpus, suggestions[self.wf.only_type]) - with self.subTest( - "Side effect in derived from: unfulfilled restrictions get inherited" - ): - self.assertNotIn( + with self.subTest("Unfulfilled upstream restrictions do not get inherited"): + self.assertIn( PlaceBooks, suggestions[self.wf.assembled], msg=INHERITANCE_DISCLAIMER, @@ -473,6 +480,8 @@ def test_multiple_channels(self): msg="All correctly typed channels should be suggested.", ) + for n, c in suggest_connections(wf.single.outputs.has_nuts): + print(n.full_label, c.label) self.assertListEqual( [ (wf.multiple, wf.multiple.inputs.data_typed), diff --git a/tests/unit/test_knowledge.py b/tests/unit/test_knowledge.py index 340f6155..257e8438 100644 --- a/tests/unit/test_knowledge.py +++ b/tests/unit/test_knowledge.py @@ -397,7 +397,12 @@ class Clothes: @pwf.as_function_node def Wash( clothes: u(Clothes, uri=EX.Clothes), -) -> u(Clothes, triples=(EX.hasProperty, EX.cleaned), derived_from="inputs.clothes"): +) -> u( + Clothes, + uri=EX.Clothes, + triples=(EX.hasProperty, EX.cleaned), + derived_from="inputs.clothes", +): ... return clothes @@ -405,8 +410,9 @@ def Wash( @pwf.as_function_node def Dye(clothes: u(Clothes, uri=EX.Clothes), color="blue") -> u( Clothes, - triples=(EX.hasProperty, EX.color), + uri=EX.Clothes, derived_from="inputs.clothes", + triples=(EX.hasProperty, EX.color), ): ... return clothes @@ -436,8 +442,9 @@ def Sell( @pwf.as_function_node def DyeWithCancel(clothes: Clothes, color="blue") -> u( Clothes, - triples=(EX.hasProperty, EX.color), + uri=EX.Clothes, derived_from="inputs.clothes", + triples=(EX.hasProperty, EX.color), cancel=(EX.hasProperty, EX.cleaned), ): return clothes From fbe3fd6a99ac7c49c45ffe8d1c1d74744538e0af Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:14:33 -0700 Subject: [PATCH 2/8] Update example To explicitly re-state URIs since they are no longer inherited with `derived_from`. And to update expectations around how requirements (don't!) propagate Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index 5370eca5..d3b48c4b 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -391,6 +391,7 @@ "@pwf.as_function_node\n", "def wash(clothes: u(Clothes, uri=EX.Clothes)) -> u(\n", " Clothes,\n", + " uri=EX.Clothes,\n", " triples=(EX.hasProperty, EX.cleaned),\n", " derived_from=\"inputs.clothes\"\n", "):\n", @@ -400,6 +401,7 @@ "@pwf.as_function_node\n", "def dye(clothes: u(Clothes, uri=EX.Clothes), color=\"blue\") -> u(\n", " Clothes,\n", + " uri=EX.Clothes,\n", " triples=(EX.hasProperty, EX.color),\n", " derived_from=\"inputs.clothes\",\n", "):\n", @@ -616,8 +618,9 @@ "@pwf.as_function_node\n", "def dye_with_cancel(clothes: Clothes, color=\"blue\") -> u(\n", " Clothes,\n", - " triples=(EX.hasProperty, EX.color),\n", + " uri=EX.Clothes,\n", " derived_from=\"inputs.clothes\",\n", + " triples=(EX.hasProperty, EX.color),\n", " cancel=(EX.hasProperty, EX.cleaned)\n", "):\n", " return clothes" @@ -882,7 +885,7 @@ { "metadata": {}, "cell_type": "markdown", - "source": "There is also one sneaky edge case where it _looks_ like a given node fulfills certain requirements, but because of the interaction of `derived_from` and inherited `requirements` in `semantikon` (Cf. [this issue](https://github.com/pyiron/semantikon/issues/262)), we can fail to find a suggestion we might expect to be there:", + "source": "Note that inter-node connections do _not_ cause restrictions to propagate. Nicely, that means that if we have a node guarnateeing our immediate demands, we can get suggestions for it, even if it would itself introduce new demands. See below, where the middle node `GivesAndTakes` promises to fulfill the requirements of `TakesDownstream` even though it has its own needs:", "id": "38b026f5e536acdb" }, { @@ -910,6 +913,7 @@ " ),\n", ") -> u(\n", " str,\n", + " uri=EX.Data,\n", " derived_from=\"inputs.y\",\n", " triples=(EX.has, EX.Downstream)\n", "):\n", @@ -1013,7 +1017,12 @@ "@pwf.as_function_node\n", "def ItsStuck(\n", " jar: u(Jar.dataclass, uri=EX.Jar)\n", - ") -> u(Jar.dataclass, derived_from=\"inputs.jar\", triples=(EX.lidState, EX.stuck)):\n", + ") -> u(\n", + " Jar.dataclass,\n", + " uri=EX.Jar,\n", + " derived_from=\"inputs.jar\",\n", + " triples=(EX.lidState, EX.stuck)\n", + "):\n", " return jar\n", "\n", "@pwf.as_function_node\n", @@ -1200,7 +1209,7 @@ { "metadata": {}, "cell_type": "markdown", - "source": "(Note that inheriting units with `derived_from=` in the annotation is not currently working like other ontological properties: https://github.com/pyiron/semantikon/issues/256)", + "source": "Note that units are not inherited when `derived_from=` is used in the annotation; this is to easily allow for unit-converting nodes.", "id": "dafffcc1823b711f" }, { From 72c12e8616c4a4b351a59c4f10e7a0d68f23723d Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:17:21 -0700 Subject: [PATCH 3/8] Synchronize comment with validation report Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index d3b48c4b..6d5aa112 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -632,7 +632,7 @@ { "metadata": {}, "cell_type": "markdown", - "source": "We fail, as expected. The error messages for failed ontology validations are still extremely opaque, but we can see that the upstream node `'cancel'`s the `.../cleaned` property, while the downstream type hint still requires `#someValuesFrom` `.../cleaned`.", + "source": "We fail, as expected. The error messages for failed ontology validations are still extremely opaque, but we can see that the upstream node `'cancel'`s the `.../cleaned` property, while the downstream type hint still requires `hasProperty` `cleaned`.", "id": "599404a35b15ef6b" }, { From cb2a742529dc11ef96789ec3e0bbeeba7deaeffb Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:17:52 -0700 Subject: [PATCH 4/8] Remove redundant cells Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 34 --------------------------- 1 file changed, 34 deletions(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index 6d5aa112..35b133af 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -954,40 +954,6 @@ ], "execution_count": 22 }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "If we first supply the middle node with its needs in the live graph, we'll get the expected downstream input as a suggestion:", - "id": "60aa5cd26788b1ae" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-04T20:32:25.614018Z", - "start_time": "2025-09-04T20:32:25.401642Z" - } - }, - "cell_type": "code", - "source": [ - "wf.middle.inputs.y = wf.up\n", - "suggest.suggest_connections(wf.middle.outputs.y)" - ], - "id": "3f288e5a3d1faa9e", - "outputs": [ - { - "data": { - "text/plain": [ - "[(<__main__.TakesDownstream at 0x13f7c1b20>,\n", - " )]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 23 - }, { "metadata": {}, "cell_type": "markdown", From 04fa6fb0e950eb58e4ab68926c0ae56e279b7801 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:20:25 -0700 Subject: [PATCH 5/8] Re-execute notebook Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 207 +++++++++++++------------- 1 file changed, 100 insertions(+), 107 deletions(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index 35b133af..b4d41122 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -27,8 +27,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:22.795557Z", - "start_time": "2025-09-04T20:32:22.171053Z" + "end_time": "2025-09-12T15:17:55.850601Z", + "start_time": "2025-09-12T15:17:55.840634Z" } }, "cell_type": "code", @@ -79,7 +79,7 @@ ], "id": "996ce3d6152f1beb", "outputs": [], - "execution_count": 1 + "execution_count": 28 }, { "metadata": {}, @@ -94,8 +94,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.633454Z", - "start_time": "2025-09-04T20:32:22.800111Z" + "end_time": "2025-09-12T15:17:55.990573Z", + "start_time": "2025-09-12T15:17:55.855512Z" } }, "cell_type": "code", @@ -113,12 +113,12 @@ "{'eat__verdict': 'Yummy Meal pizza'}" ] }, - "execution_count": 2, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 2 + "execution_count": 29 }, { "metadata": {}, @@ -133,8 +133,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.695871Z", - "start_time": "2025-09-04T20:32:23.691903Z" + "end_time": "2025-09-12T15:17:55.998798Z", + "start_time": "2025-09-12T15:17:55.995091Z" } }, "cell_type": "code", @@ -154,11 +154,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "/no_type encountered error in child: {'/no_type/eat.accumulate_and_run': TypeError(\"The channel /no_type/eat.meal cannot take the value `<__main__.Garbage object at 0x13fe89070>` () because it is not compliant with the type hint typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Pizza'))]\")}\n" + "/no_type encountered error in child: {'/no_type/eat.accumulate_and_run': TypeError(\"The channel /no_type/eat.meal cannot take the value `<__main__.Garbage object at 0x132838950>` () because it is not compliant with the type hint typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Pizza'))]\")}\n" ] } ], - "execution_count": 3 + "execution_count": 30 }, { "metadata": {}, @@ -173,8 +173,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.708422Z", - "start_time": "2025-09-04T20:32:23.704193Z" + "end_time": "2025-09-12T15:17:56.024027Z", + "start_time": "2025-09-12T15:17:56.020676Z" } }, "cell_type": "code", @@ -196,7 +196,7 @@ ] } ], - "execution_count": 4 + "execution_count": 31 }, { "metadata": {}, @@ -217,8 +217,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.717957Z", - "start_time": "2025-09-04T20:32:23.714207Z" + "end_time": "2025-09-12T15:17:56.040728Z", + "start_time": "2025-09-12T15:17:56.036621Z" } }, "cell_type": "code", @@ -236,12 +236,12 @@ "{'eat__verdict': 'Yummy Meal pizza'}" ] }, - "execution_count": 5, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 5 + "execution_count": 32 }, { "metadata": {}, @@ -256,8 +256,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.766856Z", - "start_time": "2025-09-04T20:32:23.724845Z" + "end_time": "2025-09-12T15:17:56.125043Z", + "start_time": "2025-09-12T15:17:56.057272Z" } }, "cell_type": "code", @@ -276,11 +276,11 @@ "output_type": "stream", "text": [ "The upstream channel /failed_ontology/make.rice cannot connect to the downstream channel /failed_ontology/eat_pizza.meal because the upstream type hint (typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Rice'))]) and downstream type hint (typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Pizza'))]) produce a non-empty ontological validation report:\n", - "{'missing_triples': [], 'incompatible_connections': [(rdflib.term.URIRef('failed_ontology.eat_pizza.inputs.meal'), rdflib.term.URIRef('failed_ontology.make.outputs.rice'), [rdflib.term.URIRef('http://www.example.org/Pizza'), rdflib.term.URIRef('http://www.example.org/Rice')], [rdflib.term.URIRef('http://www.example.org/Rice')])], 'distinct_units': {}}\n" + "{'missing_triples': [], 'incompatible_connections': [(rdflib.term.URIRef('failed_ontology.eat_pizza.inputs.meal'), rdflib.term.URIRef('failed_ontology.make.outputs.rice'), [rdflib.term.URIRef('http://www.example.org/Pizza')], [rdflib.term.URIRef('http://www.example.org/Rice')])], 'distinct_units': {}}\n" ] } ], - "execution_count": 6 + "execution_count": 33 }, { "metadata": {}, @@ -295,8 +295,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.812357Z", - "start_time": "2025-09-04T20:32:23.772125Z" + "end_time": "2025-09-12T15:17:56.209281Z", + "start_time": "2025-09-12T15:17:56.142961Z" } }, "cell_type": "code", @@ -315,11 +315,11 @@ "output_type": "stream", "text": [ "The upstream channel /relaxed_ontology/make.rice cannot connect to the downstream channel /relaxed_ontology/eat.meal because the upstream type hint (typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Rice'))]) and downstream type hint (typing.Annotated[__main__.Meal, ('uri', rdflib.term.URIRef('http://www.example.org/Meal'))]) produce a non-empty ontological validation report:\n", - "{'missing_triples': [], 'incompatible_connections': [(rdflib.term.URIRef('relaxed_ontology.eat.inputs.meal'), rdflib.term.URIRef('relaxed_ontology.make.outputs.rice'), [rdflib.term.URIRef('http://www.example.org/Meal'), rdflib.term.URIRef('http://www.example.org/Rice')], [rdflib.term.URIRef('http://www.example.org/Rice')])], 'distinct_units': {}}\n" + "{'missing_triples': [], 'incompatible_connections': [(rdflib.term.URIRef('relaxed_ontology.eat.inputs.meal'), rdflib.term.URIRef('relaxed_ontology.make.outputs.rice'), [rdflib.term.URIRef('http://www.example.org/Meal')], [rdflib.term.URIRef('http://www.example.org/Rice')])], 'distinct_units': {}}\n" ] } ], - "execution_count": 7 + "execution_count": 34 }, { "metadata": {}, @@ -334,8 +334,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.886198Z", - "start_time": "2025-09-04T20:32:23.815872Z" + "end_time": "2025-09-12T15:17:56.332796Z", + "start_time": "2025-09-12T15:17:56.213505Z" } }, "cell_type": "code", @@ -357,12 +357,12 @@ "{'eat__verdict': 'Yummy Meal meal'}" ] }, - "execution_count": 8, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 8 + "execution_count": 35 }, { "metadata": {}, @@ -377,8 +377,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:23.896847Z", - "start_time": "2025-09-04T20:32:23.889463Z" + "end_time": "2025-09-12T15:17:56.342201Z", + "start_time": "2025-09-12T15:17:56.335705Z" } }, "cell_type": "code", @@ -424,7 +424,7 @@ ], "id": "dceaab6f57226f07", "outputs": [], - "execution_count": 9 + "execution_count": 36 }, { "metadata": {}, @@ -441,8 +441,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.161793Z", - "start_time": "2025-09-04T20:32:23.900061Z" + "end_time": "2025-09-12T15:17:56.752725Z", + "start_time": "2025-09-12T15:17:56.349889Z" } }, "cell_type": "code", @@ -461,12 +461,12 @@ "{'money__price': 10}" ] }, - "execution_count": 10, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 10 + "execution_count": 37 }, { "metadata": {}, @@ -481,8 +481,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.441222Z", - "start_time": "2025-09-04T20:32:24.170811Z" + "end_time": "2025-09-12T15:17:57.215696Z", + "start_time": "2025-09-12T15:17:56.759043Z" } }, "cell_type": "code", @@ -505,12 +505,12 @@ "{'money': 10}" ] }, - "execution_count": 11, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 11 + "execution_count": 38 }, { "metadata": {}, @@ -525,8 +525,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.498841Z", - "start_time": "2025-09-04T20:32:24.444620Z" + "end_time": "2025-09-12T15:17:57.303813Z", + "start_time": "2025-09-12T15:17:57.220611Z" } }, "cell_type": "code", @@ -544,12 +544,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "The upstream channel /my_wrong_workflow/washed_clothes.clothes cannot connect to the downstream channel /my_wrong_workflow/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned')), 'derived_from', 'inputs.clothes')]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", + "The upstream channel /my_wrong_workflow/washed_clothes.clothes cannot connect to the downstream channel /my_wrong_workflow/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned')), 'derived_from', 'inputs.clothes')]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", "{'missing_triples': [(rdflib.term.URIRef('my_wrong_workflow.sell.inputs.clothes'), rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/color'))], 'incompatible_connections': [], 'distinct_units': {}}\n" ] } ], - "execution_count": 12 + "execution_count": 39 }, { "metadata": {}, @@ -566,8 +566,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.566973Z", - "start_time": "2025-09-04T20:32:24.508485Z" + "end_time": "2025-09-12T15:17:57.393224Z", + "start_time": "2025-09-12T15:17:57.308032Z" } }, "cell_type": "code", @@ -589,12 +589,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "The upstream channel /my_wrong_macro/washed_clothes.clothes cannot connect to the downstream channel /my_wrong_macro/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned')), 'derived_from', 'inputs.clothes')]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", + "The upstream channel /my_wrong_macro/washed_clothes.clothes cannot connect to the downstream channel /my_wrong_macro/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned')), 'derived_from', 'inputs.clothes')]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", "{'missing_triples': [(rdflib.term.URIRef('my_wrong_macro.sell.inputs.clothes'), rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/color'))], 'incompatible_connections': [], 'distinct_units': {}}\n" ] } ], - "execution_count": 13 + "execution_count": 40 }, { "metadata": {}, @@ -609,8 +609,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.572923Z", - "start_time": "2025-09-04T20:32:24.570058Z" + "end_time": "2025-09-12T15:17:57.399302Z", + "start_time": "2025-09-12T15:17:57.396390Z" } }, "cell_type": "code", @@ -627,7 +627,7 @@ ], "id": "3055fbc547280d91", "outputs": [], - "execution_count": 14 + "execution_count": 41 }, { "metadata": {}, @@ -638,8 +638,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.659414Z", - "start_time": "2025-09-04T20:32:24.578908Z" + "end_time": "2025-09-12T15:17:57.496940Z", + "start_time": "2025-09-12T15:17:57.408824Z" } }, "cell_type": "code", @@ -658,12 +658,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "The upstream channel /my_wf_with_cancellation/dyed_clothes.clothes cannot connect to the downstream channel /my_wf_with_cancellation/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/color')), 'derived_from', 'inputs.clothes', 'extra', {'cancel': (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned'))})]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", + "The upstream channel /my_wf_with_cancellation/dyed_clothes.clothes cannot connect to the downstream channel /my_wf_with_cancellation/sell.clothes because the upstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'triples', (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/color')), 'derived_from', 'inputs.clothes', 'extra', {'cancel': (rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned'))})]) and downstream type hint (typing.Annotated[__main__.Clothes, ('uri', rdflib.term.URIRef('http://www.example.org/Clothes'), 'restrictions', (((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/cleaned'))), ((rdflib.term.URIRef('http://www.w3.org/2002/07/owl#onProperty'), rdflib.term.URIRef('http://www.example.org/hasProperty')), (rdflib.term.URIRef('http://www.w3.org/2002/07/owl#someValuesFrom'), rdflib.term.URIRef('http://www.example.org/color')))))]) produce a non-empty ontological validation report:\n", "{'missing_triples': [(rdflib.term.URIRef('my_wf_with_cancellation.sell.inputs.clothes'), rdflib.term.URIRef('http://www.example.org/hasProperty'), rdflib.term.URIRef('http://www.example.org/cleaned'))], 'incompatible_connections': [], 'distinct_units': {}}\n" ] } ], - "execution_count": 15 + "execution_count": 42 }, { "metadata": {}, @@ -678,8 +678,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.668308Z", - "start_time": "2025-09-04T20:32:24.662811Z" + "end_time": "2025-09-12T15:17:57.506378Z", + "start_time": "2025-09-12T15:17:57.500847Z" } }, "cell_type": "code", @@ -699,12 +699,12 @@ "{'money__price': 10}" ] }, - "execution_count": 16, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 16 + "execution_count": 43 }, { "metadata": {}, @@ -719,8 +719,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.717709Z", - "start_time": "2025-09-04T20:32:24.675991Z" + "end_time": "2025-09-12T15:17:57.593370Z", + "start_time": "2025-09-12T15:17:57.521877Z" } }, "cell_type": "code", @@ -742,7 +742,7 @@ ] } ], - "execution_count": 17 + "execution_count": 44 }, { "metadata": {}, @@ -753,8 +753,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.764227Z", - "start_time": "2025-09-04T20:32:24.721407Z" + "end_time": "2025-09-12T15:17:57.673606Z", + "start_time": "2025-09-12T15:17:57.600956Z" } }, "cell_type": "code", @@ -767,12 +767,12 @@ "[__main__.prepare_pizza]" ] }, - "execution_count": 18, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 18 + "execution_count": 45 }, { "metadata": {}, @@ -787,8 +787,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.773883Z", - "start_time": "2025-09-04T20:32:24.767569Z" + "end_time": "2025-09-12T15:17:57.685801Z", + "start_time": "2025-09-12T15:17:57.678728Z" } }, "cell_type": "code", @@ -807,12 +807,12 @@ "[]" ] }, - "execution_count": 19, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 19 + "execution_count": 46 }, { "metadata": {}, @@ -823,8 +823,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:24.958865Z", - "start_time": "2025-09-04T20:32:24.779408Z" + "end_time": "2025-09-12T15:17:57.956281Z", + "start_time": "2025-09-12T15:17:57.693531Z" } }, "cell_type": "code", @@ -841,12 +841,12 @@ "[__main__.wash, __main__.dye, __main__.dye_with_cancel]" ] }, - "execution_count": 20, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 20 + "execution_count": 47 }, { "metadata": {}, @@ -857,8 +857,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:25.296602Z", - "start_time": "2025-09-04T20:32:24.962807Z" + "end_time": "2025-09-12T15:17:58.545855Z", + "start_time": "2025-09-12T15:17:57.961545Z" } }, "cell_type": "code", @@ -880,7 +880,7 @@ ] } ], - "execution_count": 21 + "execution_count": 48 }, { "metadata": {}, @@ -891,8 +891,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:25.388366Z", - "start_time": "2025-09-04T20:32:25.312200Z" + "end_time": "2025-09-12T15:17:58.648898Z", + "start_time": "2025-09-12T15:17:58.551401Z" } }, "cell_type": "code", @@ -944,15 +944,16 @@ { "data": { "text/plain": [ - "[]" + "[(<__main__.TakesDownstream at 0x132987350>,\n", + " )]" ] }, - "execution_count": 22, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 22 + "execution_count": 49 }, { "metadata": {}, @@ -967,8 +968,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:28.168211Z", - "start_time": "2025-09-04T20:32:25.627729Z" + "end_time": "2025-09-12T15:18:02.119036Z", + "start_time": "2025-09-12T15:17:58.666670Z" } }, "cell_type": "code", @@ -1033,14 +1034,6 @@ ], "id": "d3bfd2d5b856d187", "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/liamhuber/dev/pyiron/semantikon/semantikon/ontology.py:48: FutureWarning: semantikon_class is experimental - triples may change in the future\n", - " warnings.warn(\n" - ] - }, { "data": { "text/plain": [ @@ -1048,12 +1041,12 @@ " 'platter__lunch': ['jam sandwich', 'honey sandwich', 'butter sandwich']}" ] }, - "execution_count": 24, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 24 + "execution_count": 50 }, { "metadata": {}, @@ -1070,8 +1063,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:28.276798Z", - "start_time": "2025-09-04T20:32:28.191943Z" + "end_time": "2025-09-12T15:18:02.276165Z", + "start_time": "2025-09-12T15:18:02.139675Z" } }, "cell_type": "code", @@ -1093,7 +1086,7 @@ ], "id": "7fa30c5bb66141ee", "outputs": [], - "execution_count": 25 + "execution_count": 51 }, { "metadata": {}, @@ -1104,8 +1097,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:28.327523Z", - "start_time": "2025-09-04T20:32:28.281527Z" + "end_time": "2025-09-12T15:18:02.353940Z", + "start_time": "2025-09-12T15:18:02.280458Z" } }, "cell_type": "code", @@ -1132,7 +1125,7 @@ ] } ], - "execution_count": 26 + "execution_count": 52 }, { "metadata": {}, @@ -1143,8 +1136,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:28.424358Z", - "start_time": "2025-09-04T20:32:28.336554Z" + "end_time": "2025-09-12T15:18:02.507222Z", + "start_time": "2025-09-12T15:18:02.365891Z" } }, "cell_type": "code", @@ -1165,12 +1158,12 @@ "{'speed__s': 10.0}" ] }, - "execution_count": 27, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 27 + "execution_count": 53 }, { "metadata": {}, @@ -1197,8 +1190,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-09-04T20:32:28.433508Z", - "start_time": "2025-09-04T20:32:28.431929Z" + "end_time": "2025-09-12T15:18:02.520567Z", + "start_time": "2025-09-12T15:18:02.519351Z" } }, "cell_type": "code", From 30774236b1034c677b2d4d183ecb12a466e0a18c Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:21:15 -0700 Subject: [PATCH 6/8] Add comment Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index b4d41122..94142836 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -370,10 +370,16 @@ "source": [ "# Ontological triples\n", "\n", - "Alright, for our simple pizza example things are working beautifully. Let's try it with the clothes example." + "Alright, for our simple pizza example things are working beautifully. Let's try it with the clothes example. Note that the `derived_from` annotation does not cause the `uri` annotation to be inherited, so even when we derive our output from our input, we re-state the URI." ], "id": "574ac2f3813504ca" }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "", + "id": "69923a637cd8bc00" + }, { "metadata": { "ExecuteTime": { From 8b6ca68d587f18aa8403e1f689c1ff5f40f45776 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:22:34 -0700 Subject: [PATCH 7/8] Bump semantikon This release doesn't exist yet, but this commit is compatible with the HEAD of semantikon right now, so let's look forward. Signed-off-by: liamhuber --- .binder/environment.yml | 2 +- .ci_support/environment.yml | 2 +- .ci_support/lower_bound.yml | 2 +- docs/environment.yml | 2 +- pyproject.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.binder/environment.yml b/.binder/environment.yml index 881ec2b1..ea1cb359 100644 --- a/.binder/environment.yml +++ b/.binder/environment.yml @@ -12,7 +12,7 @@ dependencies: - python >=3.11,<3.14 - python-graphviz =0.21 - rdflib =7.1.4 -- semantikon =0.0.22 +- semantikon =0.0.23 - setuptools>=68 - toposort =1.10 - typeguard =4.4.4 diff --git a/.ci_support/environment.yml b/.ci_support/environment.yml index 881ec2b1..ea1cb359 100644 --- a/.ci_support/environment.yml +++ b/.ci_support/environment.yml @@ -12,7 +12,7 @@ dependencies: - python >=3.11,<3.14 - python-graphviz =0.21 - rdflib =7.1.4 -- semantikon =0.0.22 +- semantikon =0.0.23 - setuptools>=68 - toposort =1.10 - typeguard =4.4.4 diff --git a/.ci_support/lower_bound.yml b/.ci_support/lower_bound.yml index 84a67003..ff43bfde 100644 --- a/.ci_support/lower_bound.yml +++ b/.ci_support/lower_bound.yml @@ -14,6 +14,6 @@ dependencies: - pyiron_snippets =0.1.4 - python-graphviz =0.20.3 - rdflib =7.1.4 -- semantikon =0.0.22 +- semantikon =0.0.23 - toposort =1.10 - typeguard =4.2.0 diff --git a/docs/environment.yml b/docs/environment.yml index eac306a6..0ee90128 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -18,7 +18,7 @@ dependencies: - python >=3.11,<3.14 - python-graphviz =0.21 - rdflib =7.1.4 -- semantikon =0.0.22 +- semantikon =0.0.23 - setuptools>=68 - toposort =1.10 - typeguard =4.4.4 diff --git a/pyproject.toml b/pyproject.toml index b0463c30..3e157403 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "pint==0.25", "pyiron_snippets==0.2.0", "rdflib==7.1.4", - "semantikon==0.0.22", + "semantikon==0.0.23", "toposort==1.10", "typeguard==4.4.4", ] From 116c5c778d127eefca0a59a30ad9415115fe4fa7 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Fri, 12 Sep 2025 08:22:49 -0700 Subject: [PATCH 8/8] Remove empty cell Signed-off-by: liamhuber --- notebooks/ontological_workflows.ipynb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/notebooks/ontological_workflows.ipynb b/notebooks/ontological_workflows.ipynb index 94142836..5278b8d8 100644 --- a/notebooks/ontological_workflows.ipynb +++ b/notebooks/ontological_workflows.ipynb @@ -374,12 +374,6 @@ ], "id": "574ac2f3813504ca" }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "", - "id": "69923a637cd8bc00" - }, { "metadata": { "ExecuteTime": {