From 4ec191f9a8cd0849bcb19df4eebbb43d03db759d Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 16:49:24 -0400 Subject: [PATCH 1/7] Resolve #436: add wasInformedBy property to Activity --- sbol3/constants.py | 1 + sbol3/provenance.py | 5 +++++ test/test_provenance.py | 1 + 3 files changed, 7 insertions(+) diff --git a/sbol3/constants.py b/sbol3/constants.py index 39e5822..e73ec51 100644 --- a/sbol3/constants.py +++ b/sbol3/constants.py @@ -163,6 +163,7 @@ PROV_PLANS = PROV_NS + 'hadPlan' PROV_QUALIFIED_ASSOCIATION = PROV_NS + 'qualifiedAssociation' PROV_QUALIFIED_USAGE = PROV_NS + 'qualifiedUsage' +PROV_INFORMED_BY = PROV_NS + 'wasInformedBy' PROV_ROLES = PROV_NS + 'hadRole' PROV_STARTED_AT_TIME = PROV_NS + 'startedAtTime' PROV_ENDED_AT_TIME = PROV_NS + 'endedAtTime' diff --git a/sbol3/provenance.py b/sbol3/provenance.py index 95c1e16..daa3918 100644 --- a/sbol3/provenance.py +++ b/sbol3/provenance.py @@ -214,6 +214,7 @@ def __init__(self, identity: str, end_time: Union[str, datetime.datetime] = None, usage: List[Identified] = None, association: List[Identified] = None, + informed_by: List[Identified] = None, namespace: str = None, attachments: List[str] = None, name: str = None, description: str = None, @@ -239,6 +240,10 @@ def __init__(self, identity: str, 0, math.inf, initial_value=association, type_constraint=Association) + self.informed_by = OwnedObject(self, PROV_INFORMED_BY, + 0, math.inf, + initial_value=informed_by, + type_constraint=Activity) def accept(self, visitor: Any) -> Any: """Invokes `visit_activity` on `visitor` with `self` as the only diff --git a/test/test_provenance.py b/test/test_provenance.py index 4195db7..3bba0b3 100644 --- a/test/test_provenance.py +++ b/test/test_provenance.py @@ -24,6 +24,7 @@ def test_create(self): self.assertEqual(None, activity.end_time) self.assertEqual([], activity.usage) self.assertEqual([], activity.association) + self.assertEqual([], activity.informed_by) def test_list_wrapping(self): # Ensure that at least certain properties handle automatic list From 859f7004e01dc7d2d377a71c245f1c4940159441 Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 17:19:40 -0400 Subject: [PATCH 2/7] Try changing to new readthedocs build --- .readthedocs.yaml | 12 ++++++++++++ docs/Makefile | 20 -------------------- 2 files changed, 12 insertions(+), 20 deletions(-) create mode 100644 .readthedocs.yaml delete mode 100644 docs/Makefile diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..d6bbb5a --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,12 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cb..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) From 0afb96012ec8c2183f3b5ef5eafa06be0ad72dca Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 17:47:56 -0400 Subject: [PATCH 3/7] Try restoring docs Makefile --- docs/Makefile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/Makefile diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) From 790414df9b9aecffbf5f336f48ee62ccae657483 Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 17:52:08 -0400 Subject: [PATCH 4/7] readthedocs yaml needs to Include requirements --- .readthedocs.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index d6bbb5a..71b1189 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,3 +10,8 @@ build: # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/conf.py + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt From acd15cb555dd8768e0cbce5e480e27b6ae722875 Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 17:54:32 -0400 Subject: [PATCH 5/7] Requirements was missing sphinx_rtd_theme --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 44a988d..3935b1a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,2 @@ sphinx-autoapi +sphinx_rtd_theme From 6254b763fef0cde2da8402665da99a7d3706ff3d Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 18:22:40 -0400 Subject: [PATCH 6/7] Fix #437 by actually returning the value of visitor functions, as promised by the visitor function documentation --- sbol3/attachment.py | 2 +- sbol3/collection.py | 4 ++-- sbol3/combderiv.py | 2 +- sbol3/component.py | 2 +- sbol3/compref.py | 2 +- sbol3/constraint.py | 2 +- sbol3/document.py | 2 +- sbol3/expdata.py | 2 +- sbol3/extdef.py | 2 +- sbol3/implementation.py | 2 +- sbol3/interaction.py | 2 +- sbol3/interface.py | 2 +- sbol3/localsub.py | 2 +- sbol3/location.py | 6 +++--- sbol3/model.py | 2 +- sbol3/om_compound.py | 6 +++--- sbol3/om_prefix.py | 4 ++-- sbol3/om_unit.py | 6 +++--- sbol3/participation.py | 2 +- sbol3/provenance.py | 10 +++++----- sbol3/seqfeat.py | 2 +- sbol3/sequence.py | 2 +- sbol3/subcomponent.py | 2 +- sbol3/varcomp.py | 2 +- 24 files changed, 36 insertions(+), 36 deletions(-) diff --git a/sbol3/attachment.py b/sbol3/attachment.py index 1451667..69d3788 100644 --- a/sbol3/attachment.py +++ b/sbol3/attachment.py @@ -56,7 +56,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_attachment(self) + return visitor.visit_attachment(self) def build_attachment(identity: str, diff --git a/sbol3/collection.py b/sbol3/collection.py index 1ef88a5..a155b71 100644 --- a/sbol3/collection.py +++ b/sbol3/collection.py @@ -48,7 +48,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_collection(self) + return visitor.visit_collection(self) class Experiment(Collection): @@ -86,7 +86,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_experiment(self) + return visitor.visit_experiment(self) Document.register_builder(SBOL_COLLECTION, Collection) diff --git a/sbol3/combderiv.py b/sbol3/combderiv.py index ae66eae..a4269cb 100644 --- a/sbol3/combderiv.py +++ b/sbol3/combderiv.py @@ -62,7 +62,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_combinatorial_derivation(self) + return visitor.visit_combinatorial_derivation(self) def build_combinatorial_derivation(identity: str, diff --git a/sbol3/component.py b/sbol3/component.py index 7b33560..32a1ba6 100644 --- a/sbol3/component.py +++ b/sbol3/component.py @@ -64,7 +64,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_component(self) + return visitor.visit_component(self) def build_component(identity: str, *, type_uri: str = SBOL_COMPONENT) -> SBOLObject: diff --git a/sbol3/compref.py b/sbol3/compref.py index f29b288..3b92c6b 100644 --- a/sbol3/compref.py +++ b/sbol3/compref.py @@ -53,7 +53,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_component_reference(self) + return visitor.visit_component_reference(self) def build_component_reference(identity: str, *, diff --git a/sbol3/constraint.py b/sbol3/constraint.py index 488105a..4b4f9f9 100644 --- a/sbol3/constraint.py +++ b/sbol3/constraint.py @@ -58,7 +58,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_constraint(self) + return visitor.visit_constraint(self) def build_constraint(identity: str, type_uri: str = SBOL_CONSTRAINT) -> SBOLObject: diff --git a/sbol3/document.py b/sbol3/document.py index 07b6c9f..f65a636 100644 --- a/sbol3/document.py +++ b/sbol3/document.py @@ -607,7 +607,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_document(self) + return visitor.visit_document(self) def traverse(self, func: Callable[[Identified], None]): """Enable a traversal of the entire object hierarchy contained diff --git a/sbol3/expdata.py b/sbol3/expdata.py index b57d273..0316a82 100644 --- a/sbol3/expdata.py +++ b/sbol3/expdata.py @@ -38,7 +38,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_experimental_data(self) + return visitor.visit_experimental_data(self) Document.register_builder(SBOL_EXPERIMENTAL_DATA, ExperimentalData) diff --git a/sbol3/extdef.py b/sbol3/extdef.py index a80de53..42c6c49 100644 --- a/sbol3/extdef.py +++ b/sbol3/extdef.py @@ -55,7 +55,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_externally_defined(self) + return visitor.visit_externally_defined(self) def build_externally_defined(identity: str, diff --git a/sbol3/implementation.py b/sbol3/implementation.py index a8e3a84..3346256 100644 --- a/sbol3/implementation.py +++ b/sbol3/implementation.py @@ -45,7 +45,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_implementation(self) + return visitor.visit_implementation(self) Document.register_builder(SBOL_IMPLEMENTATION, Implementation) diff --git a/sbol3/interaction.py b/sbol3/interaction.py index a7888b0..81419ac 100644 --- a/sbol3/interaction.py +++ b/sbol3/interaction.py @@ -50,7 +50,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_interaction(self) + return visitor.visit_interaction(self) def build_interaction(identity: str, *, type_uri: str = SBOL_INTERACTION) -> SBOLObject: diff --git a/sbol3/interface.py b/sbol3/interface.py index 91cb1af..149a6ff 100644 --- a/sbol3/interface.py +++ b/sbol3/interface.py @@ -41,7 +41,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_interface(self) + return visitor.visit_interface(self) def build_interface(identity: str, *, type_uri: str = SBOL_INTERFACE) -> SBOLObject: diff --git a/sbol3/localsub.py b/sbol3/localsub.py index dadfad4..4550ddd 100644 --- a/sbol3/localsub.py +++ b/sbol3/localsub.py @@ -47,7 +47,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_local_sub_component(self) + return visitor.visit_local_sub_component(self) def build_local_subcomponent(identity: str, diff --git a/sbol3/location.py b/sbol3/location.py index 591ea1f..d1769e1 100644 --- a/sbol3/location.py +++ b/sbol3/location.py @@ -83,7 +83,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_range(self) + return visitor.visit_range(self) def build_range(identity: str, type_uri: str = SBOL_RANGE): @@ -138,7 +138,7 @@ def accept(self, visitor: Any) -> Any: :return: Whatever `visitor.visit_cut` returns :rtype: Any """ - visitor.visit_cut(self) + return visitor.visit_cut(self) def build_cut(identity: str, type_uri: str = SBOL_CUT): @@ -184,7 +184,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_entire_sequence(self) + return visitor.visit_entire_sequence(self) def build_entire_sequence(identity: str, type_uri: str = SBOL_ENTIRE_SEQUENCE): diff --git a/sbol3/model.py b/sbol3/model.py index 0de118c..8185ca7 100644 --- a/sbol3/model.py +++ b/sbol3/model.py @@ -62,7 +62,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_model(self) + return visitor.visit_model(self) def build_model(identity: str, type_uri: str = SBOL_MODEL): diff --git a/sbol3/om_compound.py b/sbol3/om_compound.py index 28b2da8..85b57f3 100644 --- a/sbol3/om_compound.py +++ b/sbol3/om_compound.py @@ -82,7 +82,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_unit_multiplication(self) + return visitor.visit_unit_multiplication(self) def build_unit_multiplication(identity: str, @@ -145,7 +145,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_unit_division(self) + return visitor.visit_unit_division(self) def build_unit_division(identity: str, @@ -209,7 +209,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_unit_exponentiation(self) + return visitor.visit_unit_exponentiation(self) def build_unit_exponentiation(identity: str, diff --git a/sbol3/om_prefix.py b/sbol3/om_prefix.py index fd9f935..8375996 100644 --- a/sbol3/om_prefix.py +++ b/sbol3/om_prefix.py @@ -103,7 +103,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_si_prefix(self) + return visitor.visit_si_prefix(self) def build_si_prefix(identity: str, *, type_uri: str = OM_SI_PREFIX) -> SBOLObject: @@ -161,7 +161,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_binary_prefix(self) + return visitor.visit_binary_prefix(self) def build_binary_prefix(identity: str, diff --git a/sbol3/om_unit.py b/sbol3/om_unit.py index 7769e36..6c957a2 100644 --- a/sbol3/om_unit.py +++ b/sbol3/om_unit.py @@ -86,7 +86,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_measure(self) + return visitor.visit_measure(self) def build_measure(identity: str, *, type_uri: str = OM_MEASURE) -> SBOLObject: @@ -149,7 +149,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_singular_unit(self) + return visitor.visit_singular_unit(self) def build_singular_unit(identity: str, @@ -213,7 +213,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_prefixed_unit(self) + return visitor.visit_prefixed_unit(self) def build_prefixed_unit(identity: str, diff --git a/sbol3/participation.py b/sbol3/participation.py index a21e728..91f351e 100644 --- a/sbol3/participation.py +++ b/sbol3/participation.py @@ -50,7 +50,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_participation(self) + return visitor.visit_participation(self) def build_participation(identity: str, diff --git a/sbol3/provenance.py b/sbol3/provenance.py index 95c1e16..85ee034 100644 --- a/sbol3/provenance.py +++ b/sbol3/provenance.py @@ -47,7 +47,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_usage(self) + return visitor.visit_usage(self) def build_usage(identity: str, *, type_uri: str = PROV_USAGE) -> SBOLObject: @@ -93,7 +93,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_agent(self) + return visitor.visit_agent(self) Document.register_builder(PROV_AGENT, Agent) @@ -129,7 +129,7 @@ def accept(self, visitor: Any) -> Any: :return: Whatever `visitor.visit_plan` returns :rtype: Any """ - visitor.visit_plan(self) + return visitor.visit_plan(self) Document.register_builder(PROV_PLAN, Plan) @@ -174,7 +174,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_association(self) + return visitor.visit_association(self) def build_association(identity: str, @@ -251,7 +251,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_activity(self) + return visitor.visit_activity(self) Document.register_builder(PROV_ACTIVITY, Activity) diff --git a/sbol3/seqfeat.py b/sbol3/seqfeat.py index 36d75d0..049a298 100644 --- a/sbol3/seqfeat.py +++ b/sbol3/seqfeat.py @@ -38,7 +38,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_sequence_feature(self) + return visitor.visit_sequence_feature(self) def build_sequence_feature(identity: str, diff --git a/sbol3/sequence.py b/sbol3/sequence.py index d05b8e4..e54ae74 100644 --- a/sbol3/sequence.py +++ b/sbol3/sequence.py @@ -58,7 +58,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_sequence(self) + return visitor.visit_sequence(self) Document.register_builder(SBOL_SEQUENCE, Sequence) diff --git a/sbol3/subcomponent.py b/sbol3/subcomponent.py index efbc0d6..efff7af 100644 --- a/sbol3/subcomponent.py +++ b/sbol3/subcomponent.py @@ -54,7 +54,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_sub_component(self) + return visitor.visit_sub_component(self) def build_subcomponent(identity: str, type_uri: str = SBOL_SUBCOMPONENT) -> Identified: diff --git a/sbol3/varcomp.py b/sbol3/varcomp.py index 066e7cd..a0494ac 100644 --- a/sbol3/varcomp.py +++ b/sbol3/varcomp.py @@ -79,7 +79,7 @@ def accept(self, visitor: Any) -> Any: :rtype: Any """ - visitor.visit_variable_feature(self) + return visitor.visit_variable_feature(self) def build_variable_feature(identity: str, type_uri: str = SBOL_VARIABLE_FEATURE): From a71a93aff5e4401d70b5bc6fc9a81a5816978975 Mon Sep 17 00:00:00 2001 From: Jake Beal Date: Sat, 7 Oct 2023 18:31:38 -0400 Subject: [PATCH 7/7] Issue #437: Add a test that the visitor return values are working as expected --- test/test_visitors.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/test_visitors.py diff --git a/test/test_visitors.py b/test/test_visitors.py new file mode 100644 index 0000000..27b7701 --- /dev/null +++ b/test/test_visitors.py @@ -0,0 +1,26 @@ +import unittest +from pathlib import Path + +import sbol3 + + +class TestVisitors(unittest.TestCase): + + def test_visitor_pattern(self): + """Test that the visitor pattern is implemented and can use return values from visit functions""" + class SumVisitor: + def visit_document(self, doc: sbol3.Document): + return sum(v.accept(self) for v in doc.objects) + + @staticmethod + def visit_component(_: sbol3.Component): + return 1 + + doc = sbol3.Document() + doc.read(Path(__file__).parent / 'resources' / 'circuit.nt') + # File containing five Components and no other TopLevel objects + self.assertEqual(doc.accept(SumVisitor()), 5) + + +if __name__ == '__main__': + unittest.main()