From c1a9911dc51966610cc53987d9537f7f46842008 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Mon, 14 Dec 2020 19:53:42 -0600
Subject: [PATCH 01/47] Specifying branch for owm clone

- Temporary until c302 is not using the project directly
---
 .travis.yml | 2 +-
 README.md   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index af87dd68..8e258c86 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,7 +19,7 @@ before_install:
 
 install:
 - pip install .
-- owm clone https://github.com/openworm/OpenWormData.git
+- owm clone https://github.com/openworm/OpenWormData.git --branch owmeta
 - |
   if [ $BUNDLE_TESTS ] ; then
     owm bundle register ./owmeta-schema-bundle.yml
diff --git a/README.md b/README.md
index 40add0ed..35e8902a 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@ This project holds a working-copy of the database. You can retrieve it by
 executing the following command line after owmeta installation:
 
 ```bash
-owm clone https://github.com/openworm/OpenWormData.git
+owm clone https://github.com/openworm/OpenWormData.git --branch owmeta
 ```
 
 This command should create a directory `.owm` in your current working

From 6f632ec7c92a20cf806b8825ebbee9d335772c3a Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Mon, 14 Dec 2020 19:55:28 -0600
Subject: [PATCH 02/47] Dropping dev part from version

---
 owmeta/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/owmeta/__init__.py b/owmeta/__init__.py
index 84f21260..bdc0864a 100644
--- a/owmeta/__init__.py
+++ b/owmeta/__init__.py
@@ -13,7 +13,7 @@
 """
 
 from __future__ import print_function
-__version__ = '0.12.3.dev0'
+__version__ = '0.12.3'
 __author__ = 'OpenWorm.org authors and contributors'
 
 import logging

From 7115cb328422a62bac97b6787dae17b336352813 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Mon, 14 Dec 2020 20:02:29 -0600
Subject: [PATCH 03/47] Bumping version number

---
 owmeta/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/owmeta/__init__.py b/owmeta/__init__.py
index bdc0864a..1905f81b 100644
--- a/owmeta/__init__.py
+++ b/owmeta/__init__.py
@@ -13,7 +13,7 @@
 """
 
 from __future__ import print_function
-__version__ = '0.12.3'
+__version__ = '0.12.4.dev0'
 __author__ = 'OpenWorm.org authors and contributors'
 
 import logging

From 31d864a9128e0d4268f63c37fbef89913494818c Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 3 Jan 2021 18:56:20 -0600
Subject: [PATCH 04/47] Updating for changes to owmeta_core.identifier_mixin

---
 owmeta/bibtex.py                 | 3 +--
 owmeta/cell.py                   | 4 +++-
 owmeta/data_trans/connections.py | 3 ---
 tests/DocumentationTest.py       | 3 ++-
 4 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/owmeta/bibtex.py b/owmeta/bibtex.py
index 80165513..a03a3739 100644
--- a/owmeta/bibtex.py
+++ b/owmeta/bibtex.py
@@ -1,4 +1,3 @@
-import re
 import bibtexparser
 
 from .evidence import Evidence
@@ -15,7 +14,7 @@ def bibtex_to_document(bibtex_entry, context=None):
 
 
 def update_document_with_bibtex(document, bibtex_entry):
-    document.set_key(bibtex_entry['ID'])
+    document.key = bibtex_entry['ID']
     for ath in bibtex_entry.get('author', tuple()):
         document.author(ath)
 
diff --git a/owmeta/cell.py b/owmeta/cell.py
index 48142ad8..802513c5 100644
--- a/owmeta/cell.py
+++ b/owmeta/cell.py
@@ -56,7 +56,9 @@ class Cell(BiologyType):
 
     parentOf = ObjectProperty(value_type=This, multiple=True)
 
-    key_property = {'property': name, 'type': 'direct'}
+    key_property = 'name'
+
+    direct_key = True
 
     def __init__(self, name=None, lineageName=None, **kwargs):
         # NOTE: We name the `name` and `lineageName` as positional parameters for
diff --git a/owmeta/data_trans/connections.py b/owmeta/data_trans/connections.py
index 297cdf6a..c540e140 100644
--- a/owmeta/data_trans/connections.py
+++ b/owmeta/data_trans/connections.py
@@ -1,9 +1,6 @@
-import re
-import traceback
 import csv
 import logging
 
-from owmeta_core.context import Context
 from owmeta_core.datasource import GenericTranslation
 from owmeta_core.dataobject import ObjectProperty
 from owmeta_core.data_trans.csv_ds import CSVDataTranslator, CSVDataSource
diff --git a/tests/DocumentationTest.py b/tests/DocumentationTest.py
index 98e907fe..edb0a7a1 100644
--- a/tests/DocumentationTest.py
+++ b/tests/DocumentationTest.py
@@ -72,7 +72,8 @@ class Widget(DataObject):
             hardiness = DatatypeProperty()
             fullness = DatatypeProperty()
             part_number = DatatypeProperty()
-            key_property = {'name': 'part_number', 'type': 'direct'}
+            key_property = 'part_number'
+            direct_key = True
 
         ctx = Context(ident='http://example.org/data/imports/BDW_Widgets_2018-2019')
 

From 8bf5e31c102c312412a3df24e1534d646f4d8e2f Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 3 Jan 2021 20:01:38 -0600
Subject: [PATCH 05/47] Allowing dev version for owmeta-core

---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index 997d3909..5b688457 100644
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,7 @@
         'pytest-parallel'
     ],
     install_requires=[
-        'owmeta-core',
+        'owmeta-core>=0.14.0.dev0',
         'bibtexparser~=1.1.0',
         'libneuroml',
         'rdflib>=4.1.2',

From cf2161e7da5e58733d372b747bc448334e1f6341 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Wed, 17 Feb 2021 17:13:48 -0600
Subject: [PATCH 06/47] Specifying value type for DWEDS contexts

- Prevents ambiguity since the combined context has the same ID as the DWEDS
---
 owmeta/data_trans/data_with_evidence_ds.py | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/owmeta/data_trans/data_with_evidence_ds.py b/owmeta/data_trans/data_with_evidence_ds.py
index 3aecd75f..d7931e69 100644
--- a/owmeta/data_trans/data_with_evidence_ds.py
+++ b/owmeta/data_trans/data_with_evidence_ds.py
@@ -1,8 +1,7 @@
-from rdflib.namespace import Namespace
-
 from owmeta_core.context import Context
 from owmeta_core.datasource import Informational, DataSource
-from owmeta_core.data_trans.context_datasource import VariableIdentifierContext
+from owmeta_core.data_trans.context_datasource import (VariableIdentifierContext,
+        VariableIdentifierContextDataObject)
 
 from .. import CONTEXT, SCI_CTX
 
@@ -22,6 +21,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                               property_name='evidence_context',
                                               property_type='ObjectProperty',
                                               multiple=False,
+                                              value_type=VariableIdentifierContextDataObject,
                                               description='The context in which evidence'
                                                           ' for the "Data context" is defined')
 
@@ -29,6 +29,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                           property_name='data_context',
                                           property_type='ObjectProperty',
                                           multiple=False,
+                                          value_type=VariableIdentifierContextDataObject,
                                           description='The context in which primary data'
                                                       ' for this data source is defined')
 
@@ -36,6 +37,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                               property_name='combined_context',
                                               property_type='ObjectProperty',
                                               multiple=False,
+                                              value_type=VariableIdentifierContextDataObject,
                                               description='Context importing both the data and evidence contexts')
 
     def __init__(self, *args, **kwargs):

From a8693f5812679fd8ccd28428b9c2b7bb826efdd7 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Fri, 4 Jun 2021 19:24:57 -0500
Subject: [PATCH 07/47] Adding owmeta-pytest-plugin as a test requirement

---
 test-requirements.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test-requirements.txt b/test-requirements.txt
index 6ef09b1a..ce5823a3 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,3 +3,4 @@ pytest-cov>=2.5.1
 discover==0.4.0
 requests
 pytest-parallel
+owmeta-pytest-plugin

From 4068664c2516602d255359bfbcb2048bc71d315c Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Tue, 3 Aug 2021 21:24:39 -0500
Subject: [PATCH 08/47] WIP: Added SourcedFrom property

---
 owmeta/document.py | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/owmeta/document.py b/owmeta/document.py
index b5add9f2..60bafb92 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -6,7 +6,8 @@
 
 from owmeta_core.graph_object import IdentifierMissingException
 from owmeta_core.context import Context
-from owmeta_core.dataobject import DataObject, DatatypeProperty, Alias
+from owmeta_core.dataobject import DataObject, DatatypeProperty, Alias, BaseDataObject
+import owmeta_core.dataobject_property as DP
 
 from . import SCI_CTX
 from . import bibtex as BIB
@@ -283,6 +284,18 @@ def pmRequest(pmid):
                                            ' Please try with just one Pubmed ID')
 
 
+class SourcedFrom(DP.ObjectProperty):
+    '''
+    Indicates which document provided the source for an object
+    '''
+    class_context = SCI_CTX
+    link_name = "sourced_from"
+    value_type = BaseDocument
+    owner_type = BaseDataObject
+    multiple = False
+    lazy = True
+
+
 def _wormbase_uri_to_wbid(uri):
     return str(urlparse(uri).path.split("/")[2])
 

From 1e4c0d0ed24ac41ad391853c82cff921082dcf5e Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 26 Sep 2021 14:15:43 -0500
Subject: [PATCH 09/47] Updating for rename of DataSource.commit/commit_augment

---
 owmeta/data_trans/bibtex.py                           | 4 ++--
 owmeta/data_trans/data_with_evidence_ds.py            | 3 ++-
 tests/ConnectionNeurotransmitterDataTranslatorTest.py | 4 ----
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/owmeta/data_trans/bibtex.py b/owmeta/data_trans/bibtex.py
index 120ba0cb..99d1f1d5 100644
--- a/owmeta/data_trans/bibtex.py
+++ b/owmeta/data_trans/bibtex.py
@@ -1,4 +1,3 @@
-from rdflib.namespace import Namespace
 from owmeta_core.datasource import Informational, DataTranslator, DataSource
 from owmeta_core.data_trans.local_file_ds import LocalFileDataSource
 from owmeta_core.data_trans.context_datasource import VariableIdentifierContext
@@ -23,7 +22,8 @@ def __init__(self, *args, **kwargs):
                                                                     imported=(CONTEXT,))
         self.context_property(self.evidence_context.rdf_object)
 
-    def commit_augment(self):
+    def after_transform(self):
+        super(EvidenceDataSource, self).after_transform()
         saved_contexts = set([])
         self.data_context.save_context(inline_imports=True, saved_contexts=saved_contexts)
         self.context.save_context(inline_imports=True, saved_contexts=saved_contexts)
diff --git a/owmeta/data_trans/data_with_evidence_ds.py b/owmeta/data_trans/data_with_evidence_ds.py
index d7931e69..9d56e7a5 100644
--- a/owmeta/data_trans/data_with_evidence_ds.py
+++ b/owmeta/data_trans/data_with_evidence_ds.py
@@ -82,7 +82,8 @@ def context_for(self, ident=None, **kwargs):
             res = self.__ad_hoc_contexts[key]
         return res
 
-    def commit_augment(self):
+    def after_transform(self):
+        super(DataWithEvidenceDataSource, self).after_transform()
         for ctx in self.__ad_hoc_contexts.values():
             ctx.save()
 
diff --git a/tests/ConnectionNeurotransmitterDataTranslatorTest.py b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
index 6b39139a..5ed88f60 100644
--- a/tests/ConnectionNeurotransmitterDataTranslatorTest.py
+++ b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
@@ -49,13 +49,11 @@ def setUp(self):
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(len(list(conn.load())), 1)
 
     def test_adds_nt(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(list(conn.load())[0].synclass(), 'neurotransmitter')
 
@@ -77,12 +75,10 @@ def setUp(self):
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(len(list(conn.load())), 1)
 
     def test_adds_nt(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(list(conn.load())[0].synclass(), 'neurotransmitter')

From 6dee49b9b28e4bb6482594423042ea5898c09d57 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 25 Nov 2021 20:39:23 -0600
Subject: [PATCH 10/47] wip: adding support for evidence ds mixin

---
 tests/EvidenceDSMixinTest.py | 45 ++++++++++++++++++++++++++++++++++++
 tests/conftest.py            |  5 ++++
 2 files changed, 50 insertions(+)
 create mode 100644 tests/EvidenceDSMixinTest.py

diff --git a/tests/EvidenceDSMixinTest.py b/tests/EvidenceDSMixinTest.py
new file mode 100644
index 00000000..e17aeba6
--- /dev/null
+++ b/tests/EvidenceDSMixinTest.py
@@ -0,0 +1,45 @@
+from os.path import join as p
+import json
+
+import pytest
+from rdflib.namespace import Namespace
+
+from owmeta_core.datasource import DataSource
+from owmeta_pytest_plugin import bundle_versions
+
+
+EX = Namespace('http://example.org/')
+
+
+@pytest.mark.inttest
+@bundle_versions('owmeta_schema_bundle', [3])
+@pytest.mark.bundle_remote('ow')
+def test_augment_cmd_load(owmeta_schema_bundle, owm_project):
+    owm_project.fetch(owmeta_schema_bundle)
+    owm = owm_project.owm()
+    deps = [{'id': owmeta_schema_bundle.id, 'version': owmeta_schema_bundle.version}]
+    owm.config.set('dependencies', json.dumps(deps))
+
+    modpath = owm_project.make_module('test_module')
+    owm_project.writefile(p(modpath, 'asource.py'),
+            'tests/test_modules/evidence_ds_mixin_source.py')
+    owm_project.sh('owm save test_module.asource')
+
+    with owm_project.owm().connect() as conn:
+        conn.rdf.namespace_manager.bind('ex', EX)
+
+    owm_project.sh(
+            'owm declare owmeta.document:Document doi=10.1101/398370 --id=ex:doc')
+    with owm_project.owm().connect() as conn:
+        print(conn.rdf.serialize(format='n3').decode('utf-8'))
+    owm_project.sh(
+            'owm declare owmeta.evidence:Evidence reference=ex:doc'
+            '    rdfs_comment="This says some stuff" --id=ex:ev',
+            'owm declare test_module.asource:ASource a="Some arbitrary value" --id=ex:ds',
+            'owm source attach-evidence ex:ds ex:ev')
+
+    owm = owm_project.owm()
+    with owm.connect():
+        ds = list(owm.default_context(DataSource)(ident=EX['ds']).load())
+        ev = ds.attached_evidence.one()
+        assert ev.identifier == EX['ev']
diff --git a/tests/conftest.py b/tests/conftest.py
index 02c227e9..21f231e5 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -8,6 +8,7 @@
 import tempfile
 
 import requests
+from owmeta_pytest_plugin import bundle_fixture_helper
 from pytest import fixture
 
 
@@ -119,3 +120,7 @@ def wait_for_started(server_data, max_tries=10):
             done = True
         except Exception:
             L.info("Unable to connect to the bundle server. Trying again.", exc_info=True)
+
+
+data_bundle = fixture(bundle_fixture_helper('openworm/owmeta-data'))
+owmeta_schema_bundle = fixture(bundle_fixture_helper('openworm/owmeta-schema'))

From dcdc17799a948cfd3d3857c17ffa2409c475cc47 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Wed, 17 Feb 2021 17:13:48 -0600
Subject: [PATCH 11/47] Specifying value type for DWEDS contexts

- Prevents ambiguity since the combined context has the same ID as the DWEDS
---
 owmeta/data_trans/data_with_evidence_ds.py | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/owmeta/data_trans/data_with_evidence_ds.py b/owmeta/data_trans/data_with_evidence_ds.py
index 3aecd75f..d7931e69 100644
--- a/owmeta/data_trans/data_with_evidence_ds.py
+++ b/owmeta/data_trans/data_with_evidence_ds.py
@@ -1,8 +1,7 @@
-from rdflib.namespace import Namespace
-
 from owmeta_core.context import Context
 from owmeta_core.datasource import Informational, DataSource
-from owmeta_core.data_trans.context_datasource import VariableIdentifierContext
+from owmeta_core.data_trans.context_datasource import (VariableIdentifierContext,
+        VariableIdentifierContextDataObject)
 
 from .. import CONTEXT, SCI_CTX
 
@@ -22,6 +21,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                               property_name='evidence_context',
                                               property_type='ObjectProperty',
                                               multiple=False,
+                                              value_type=VariableIdentifierContextDataObject,
                                               description='The context in which evidence'
                                                           ' for the "Data context" is defined')
 
@@ -29,6 +29,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                           property_name='data_context',
                                           property_type='ObjectProperty',
                                           multiple=False,
+                                          value_type=VariableIdentifierContextDataObject,
                                           description='The context in which primary data'
                                                       ' for this data source is defined')
 
@@ -36,6 +37,7 @@ class DataWithEvidenceDataSource(DSMixin, DataSource):
                                               property_name='combined_context',
                                               property_type='ObjectProperty',
                                               multiple=False,
+                                              value_type=VariableIdentifierContextDataObject,
                                               description='Context importing both the data and evidence contexts')
 
     def __init__(self, *args, **kwargs):

From 7ad6ac45c5cb80955220e3f50f443cc6fa4ebd58 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Fri, 4 Jun 2021 19:24:57 -0500
Subject: [PATCH 12/47] Adding owmeta-pytest-plugin as a test requirement

---
 test-requirements.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test-requirements.txt b/test-requirements.txt
index 6ef09b1a..ce5823a3 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,3 +3,4 @@ pytest-cov>=2.5.1
 discover==0.4.0
 requests
 pytest-parallel
+owmeta-pytest-plugin

From ebfc28264de46ef9fb267aac5d5480494437e1bf Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 26 Sep 2021 14:15:43 -0500
Subject: [PATCH 13/47] Updating for rename of DataSource.commit/commit_augment

---
 owmeta/data_trans/bibtex.py                           | 4 ++--
 owmeta/data_trans/data_with_evidence_ds.py            | 3 ++-
 tests/ConnectionNeurotransmitterDataTranslatorTest.py | 4 ----
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/owmeta/data_trans/bibtex.py b/owmeta/data_trans/bibtex.py
index 120ba0cb..99d1f1d5 100644
--- a/owmeta/data_trans/bibtex.py
+++ b/owmeta/data_trans/bibtex.py
@@ -1,4 +1,3 @@
-from rdflib.namespace import Namespace
 from owmeta_core.datasource import Informational, DataTranslator, DataSource
 from owmeta_core.data_trans.local_file_ds import LocalFileDataSource
 from owmeta_core.data_trans.context_datasource import VariableIdentifierContext
@@ -23,7 +22,8 @@ def __init__(self, *args, **kwargs):
                                                                     imported=(CONTEXT,))
         self.context_property(self.evidence_context.rdf_object)
 
-    def commit_augment(self):
+    def after_transform(self):
+        super(EvidenceDataSource, self).after_transform()
         saved_contexts = set([])
         self.data_context.save_context(inline_imports=True, saved_contexts=saved_contexts)
         self.context.save_context(inline_imports=True, saved_contexts=saved_contexts)
diff --git a/owmeta/data_trans/data_with_evidence_ds.py b/owmeta/data_trans/data_with_evidence_ds.py
index d7931e69..9d56e7a5 100644
--- a/owmeta/data_trans/data_with_evidence_ds.py
+++ b/owmeta/data_trans/data_with_evidence_ds.py
@@ -82,7 +82,8 @@ def context_for(self, ident=None, **kwargs):
             res = self.__ad_hoc_contexts[key]
         return res
 
-    def commit_augment(self):
+    def after_transform(self):
+        super(DataWithEvidenceDataSource, self).after_transform()
         for ctx in self.__ad_hoc_contexts.values():
             ctx.save()
 
diff --git a/tests/ConnectionNeurotransmitterDataTranslatorTest.py b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
index 6b39139a..5ed88f60 100644
--- a/tests/ConnectionNeurotransmitterDataTranslatorTest.py
+++ b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
@@ -49,13 +49,11 @@ def setUp(self):
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(len(list(conn.load())), 1)
 
     def test_adds_nt(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(list(conn.load())[0].synclass(), 'neurotransmitter')
 
@@ -77,12 +75,10 @@ def setUp(self):
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(len(list(conn.load())), 1)
 
     def test_adds_nt(self):
         res = self.cut(self.conn_ds, self.nt_ds)
-        res.commit()
         conn = res.data_context.stored(Connection).query()
         self.assertEqual(list(conn.load())[0].synclass(), 'neurotransmitter')

From 1da514a5d3a3d211826d0f4ad216e22becdc9178 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 27 Nov 2021 11:50:40 -0600
Subject: [PATCH 14/47] Updating for changes for embedded transformations in
 core

---
 test-requirements.txt                                 | 1 +
 tests/ConnectionNeurotransmitterDataTranslatorTest.py | 5 ++---
 tests/test_default.conf                               | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/test-requirements.txt b/test-requirements.txt
index ce5823a3..ee75c336 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -4,3 +4,4 @@ discover==0.4.0
 requests
 pytest-parallel
 owmeta-pytest-plugin
+http-server-pytest-fixtures
diff --git a/tests/ConnectionNeurotransmitterDataTranslatorTest.py b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
index 5ed88f60..023494a2 100644
--- a/tests/ConnectionNeurotransmitterDataTranslatorTest.py
+++ b/tests/ConnectionNeurotransmitterDataTranslatorTest.py
@@ -44,8 +44,7 @@ def setUp(self):
         self.conn_ds.data_context(Connection)(pre_cell=Neuron('PreCell'),
                                               post_cell=Neuron('PostCell'),
                                               syntype='send')
-        self.nt_ds.commit()
-        self.conn_ds.commit()
+        self.conn_ds.data_context.save()
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
@@ -71,7 +70,7 @@ def setUp(self):
                                               post_cell=Neuron('PostCell'),
                                               syntype='send',
                                               number=3)
-        self.conn_ds.commit()
+        self.conn_ds.data_context.save()
 
     def test_connection_exists(self):
         res = self.cut(self.conn_ds, self.nt_ds)
diff --git a/tests/test_default.conf b/tests/test_default.conf
index 972e1db2..7a0d34b2 100644
--- a/tests/test_default.conf
+++ b/tests/test_default.conf
@@ -6,5 +6,6 @@
     "user.email" : "jerry@cn.com",
     "rdf.upload_block_statement_count" : 50,
     "test_variable" : "test_value",
-    "pubmed.api_key" : "$PUBMED_API_KEY"
+    "pubmed.api_key" : "$PUBMED_API_KEY",
+    "imports_context_id" : "https://example.org/imports-context"
 }

From 189787ac7173f9ffd23b4273aa4b21c998abbeea Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 27 Nov 2021 20:03:52 -0600
Subject: [PATCH 15/47] Adding an install script for CI

---
 ci-install.sh | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100755 ci-install.sh

diff --git a/ci-install.sh b/ci-install.sh
new file mode 100755
index 00000000..ea294d2e
--- /dev/null
+++ b/ci-install.sh
@@ -0,0 +1,10 @@
+pip install -e .
+pip install coveralls
+pip install -r test-requirements.txt
+owm clone https://github.com/openworm/OpenWormData.git --branch owmeta
+if [ $BUNDLE_TESTS ] ; then
+    owm bundle register ./owmeta-schema-bundle.yml
+    owm bundle register ./owmeta-data-bundle.yml
+    owm bundle install openworm/owmeta-schema
+    owm bundle install openworm/owmeta-data
+fi

From 185e85744d4d44446fdffd3a7fda78ab7c5bb8ff Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 27 Nov 2021 20:26:21 -0600
Subject: [PATCH 16/47] Adding Github workflows

---
 .github/workflows/dev-test.yml               | 23 ++++++++++++++++++++
 .github/workflows/scheduled-dev-build.yml    | 13 +++++++++++
 .github/workflows/scheduled-master-build.yml | 12 ++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 .github/workflows/dev-test.yml
 create mode 100644 .github/workflows/scheduled-dev-build.yml
 create mode 100644 .github/workflows/scheduled-master-build.yml

diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml
new file mode 100644
index 00000000..b5f0ebe7
--- /dev/null
+++ b/.github/workflows/dev-test.yml
@@ -0,0 +1,23 @@
+name: Dev Test/Deploy
+
+on:
+  push: {}
+  pull_request:
+    branches: develop
+
+jobs:
+  test:
+    uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
+    with:
+      coveralls: ${{github.event_name != 'schedule'}}
+      ref: ${{ github.ref }}
+    secrets:
+      github_token: ${{secrets.GITHUB_TOKEN}}
+
+  coveralls:
+    if: github.event_name == 'push'
+    needs: test
+    uses: openworm/owmeta/.github/workflows/coveralls-upload.yml@github-workflows
+    secrets:
+      github_token: ${{secrets.GITHUB_TOKEN}}
+
diff --git a/.github/workflows/scheduled-dev-build.yml b/.github/workflows/scheduled-dev-build.yml
new file mode 100644
index 00000000..e2a9ff2e
--- /dev/null
+++ b/.github/workflows/scheduled-dev-build.yml
@@ -0,0 +1,13 @@
+name: Build develop
+
+on:
+  schedule:
+    # minute 39 of every hour
+    - cron:  '39 * * * *'
+
+jobs:
+  test:
+    uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
+    with:
+      ref: refs/heads/develop
+
diff --git a/.github/workflows/scheduled-master-build.yml b/.github/workflows/scheduled-master-build.yml
new file mode 100644
index 00000000..4dbd8cd3
--- /dev/null
+++ b/.github/workflows/scheduled-master-build.yml
@@ -0,0 +1,12 @@
+name: Build master
+
+on:
+  schedule:
+    - cron:  '13 2 * * *'
+
+jobs:
+  test:
+    uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
+    with:
+      ref: refs/heads/master
+

From 7d6796396e08947681a1ff7abcede469c3cd68ec Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 27 Nov 2021 20:38:05 -0600
Subject: [PATCH 17/47] Removing defunct setup configs

- Also adding -x, -e to ci-install.sh
---
 ci-install.sh |  2 ++
 setup.py      | 10 ----------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/ci-install.sh b/ci-install.sh
index ea294d2e..e1c3b272 100755
--- a/ci-install.sh
+++ b/ci-install.sh
@@ -1,3 +1,5 @@
+#!/bin/sh -ex
+
 pip install -e .
 pip install coveralls
 pip install -r test-requirements.txt
diff --git a/setup.py b/setup.py
index 5b688457..6dd743fd 100644
--- a/setup.py
+++ b/setup.py
@@ -2,8 +2,6 @@
 #
 
 from setuptools import setup
-import os
-import sys
 
 
 long_description = """
@@ -34,14 +32,6 @@
 setup(
     name='owmeta',
     zip_safe=False,
-    setup_requires=['pytest-runner'],
-    tests_require=[
-        'pytest>=3.4.0',
-        'pytest-cov>=2.5.1',
-        'discover==0.4.0',
-        'requests',
-        'pytest-parallel'
-    ],
     install_requires=[
         'owmeta-core>=0.14.0.dev0',
         'bibtexparser~=1.1.0',

From 5f0992356e4f0b5e59376a46089a906f449aeec5 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 27 Nov 2021 21:18:39 -0600
Subject: [PATCH 18/47] Correcting dev branch reference in CI

---
 .github/workflows/dev-test.yml            | 2 +-
 .github/workflows/scheduled-dev-build.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml
index b5f0ebe7..c4f7e4d7 100644
--- a/.github/workflows/dev-test.yml
+++ b/.github/workflows/dev-test.yml
@@ -3,7 +3,7 @@ name: Dev Test/Deploy
 on:
   push: {}
   pull_request:
-    branches: develop
+    branches: dev
 
 jobs:
   test:
diff --git a/.github/workflows/scheduled-dev-build.yml b/.github/workflows/scheduled-dev-build.yml
index e2a9ff2e..e0bc57c1 100644
--- a/.github/workflows/scheduled-dev-build.yml
+++ b/.github/workflows/scheduled-dev-build.yml
@@ -9,5 +9,5 @@ jobs:
   test:
     uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
     with:
-      ref: refs/heads/develop
+      ref: refs/heads/dev
 

From fd39f57554d0a8ab3ed0753c4103a477e122df6c Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 28 Nov 2021 08:52:01 -0600
Subject: [PATCH 19/47] Adjusting for rdflib.Graph.serialize interface change
 in 6.0

- Caused by rdflib/rdflib#1183
---
 docs/adding_data.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/adding_data.rst b/docs/adding_data.rst
index 92ad8fe4..09e54d29 100644
--- a/docs/adding_data.rst
+++ b/docs/adding_data.rst
@@ -152,7 +152,7 @@ using contexts. The code below shows how to do that::
 
    >>> # Serialize the data in the nquads format so we can see that all of our
    >>> # statements are in the proper context
-   >>> print(g.serialize(format='nquads').decode('UTF-8'))
+   >>> print(g.serialize(format='nquads', encoding='UTF-8').decode('UTF-8'))
    <http://example.org/BDW/entities/Widget#12> <http...> <http://example.org/data/imports/BDW_Widgets_2017-2018> .
    <http://example.org/BDW/entities/Widget#12> <...
 

From 55d5d7d9e625ddc59c20b68b082aedd89b309fe8 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 28 Nov 2021 09:09:30 -0600
Subject: [PATCH 20/47] Adding PubMed API key secret

---
 .github/workflows/dev-test.yml               | 1 +
 .github/workflows/scheduled-dev-build.yml    | 3 ++-
 .github/workflows/scheduled-master-build.yml | 3 ++-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml
index c4f7e4d7..113b814c 100644
--- a/.github/workflows/dev-test.yml
+++ b/.github/workflows/dev-test.yml
@@ -13,6 +13,7 @@ jobs:
       ref: ${{ github.ref }}
     secrets:
       github_token: ${{secrets.GITHUB_TOKEN}}
+      pubmed_api_key: ${{secrets.PUBMED_API_KEY}}
 
   coveralls:
     if: github.event_name == 'push'
diff --git a/.github/workflows/scheduled-dev-build.yml b/.github/workflows/scheduled-dev-build.yml
index e0bc57c1..408c90c1 100644
--- a/.github/workflows/scheduled-dev-build.yml
+++ b/.github/workflows/scheduled-dev-build.yml
@@ -10,4 +10,5 @@ jobs:
     uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
     with:
       ref: refs/heads/dev
-
+    secrets:
+      pubmed_api_key: ${{secrets.PUBMED_API_KEY}}
diff --git a/.github/workflows/scheduled-master-build.yml b/.github/workflows/scheduled-master-build.yml
index 4dbd8cd3..f7087e9b 100644
--- a/.github/workflows/scheduled-master-build.yml
+++ b/.github/workflows/scheduled-master-build.yml
@@ -9,4 +9,5 @@ jobs:
     uses: openworm/owmeta/.github/workflows/test.yml@github-workflows
     with:
       ref: refs/heads/master
-
+    secrets:
+      pubmed_api_key: ${{secrets.PUBMED_API_KEY}}

From 27c7e4b3eb20b2d4dfde3f6b1ede1e030cb1a24a Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 28 Nov 2021 10:38:53 -0600
Subject: [PATCH 21/47] Adding a constraint for pyparsing ver on py 3.6

- Also adding 3.9 and 3.10 classifiers to project metadata
---
 ci-install.sh | 13 +++++++++++++
 setup.py      |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/ci-install.sh b/ci-install.sh
index e1c3b272..91e17a06 100755
--- a/ci-install.sh
+++ b/ci-install.sh
@@ -10,3 +10,16 @@ if [ $BUNDLE_TESTS ] ; then
     owm bundle install openworm/owmeta-schema
     owm bundle install openworm/owmeta-data
 fi
+if [ "$PYTHON_VERSION" == "3.6" ] ; then
+    # pyparsing 3.0 no longer allows setting the .name attribute for
+    # TokenConverter, but the fix for that only goes in RDFLib 6 which
+    # does not support Python 3.6. See
+    # https://github.com/RDFLib/rdflib/issues/1190 and
+    # https://github.com/rdflib/rdflib/issues/1370 for details on the issue.
+    #
+    # Since we're a library, it's up to the user how to resolve this
+    # (e.g., ignore and do not use SPARQL) so we do not impose any
+    # version constraints in package metadata, just adjust so the build
+    # passes
+    pip install 'pyparsing<3.0.0'
+fi
diff --git a/setup.py b/setup.py
index 6dd743fd..3e13ec82 100644
--- a/setup.py
+++ b/setup.py
@@ -65,6 +65,8 @@
         'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
+        'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
         'Topic :: Scientific/Engineering'
     ]
 )

From 8f1e3b777d90f3ea8d821c7814d5d5677bd40b76 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 28 Nov 2021 10:50:14 -0600
Subject: [PATCH 22/47] Fixing version constraint specification

---
 ci-install.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci-install.sh b/ci-install.sh
index 91e17a06..f3941884 100755
--- a/ci-install.sh
+++ b/ci-install.sh
@@ -10,7 +10,7 @@ if [ $BUNDLE_TESTS ] ; then
     owm bundle install openworm/owmeta-schema
     owm bundle install openworm/owmeta-data
 fi
-if [ "$PYTHON_VERSION" == "3.6" ] ; then
+if [ "$PYTHON_VERSION" = "3.6" ] ; then
     # pyparsing 3.0 no longer allows setting the .name attribute for
     # TokenConverter, but the fix for that only goes in RDFLib 6 which
     # does not support Python 3.6. See

From 541a9039b782915df26b5b4d8c1a5de1817f91ee Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 4 Dec 2021 15:44:48 -0600
Subject: [PATCH 23/47] Adding a wrapper for Git requests

---
 owmeta/requests_stream.py | 62 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 owmeta/requests_stream.py

diff --git a/owmeta/requests_stream.py b/owmeta/requests_stream.py
new file mode 100644
index 00000000..bd302409
--- /dev/null
+++ b/owmeta/requests_stream.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+# Based on https://gist.github.com/obskyr/b9d4b4223e7eaf4eedcd9defabb34f13
+# released into the public domain
+
+from io import BytesIO, SEEK_SET, SEEK_END
+
+
+class RequestsResponseStream:
+    '''
+    Provides a :term:`file-like object` by wrapping a `requests` response iterator.
+    Requires the request is made with ``stream=True``.
+
+    Use the response as a context manager or call close when finished with this stream.
+    '''
+
+    def __init__(self, response, chunksize=4096):
+        self._bytes = BytesIO()
+        self._iterator = response.iter_content(chunksize)
+        self._response = response
+
+    def _load_all(self):
+        self._bytes.seek(0, SEEK_END)
+        for chunk in self._iterator:
+            self._bytes.write(chunk)
+
+    def _load_until(self, goal_position):
+        current_position = self._bytes.seek(0, SEEK_END)
+        while current_position < goal_position:
+            try:
+                current_position += self._bytes.write(next(self._iterator))
+            except StopIteration:
+                break
+
+    def tell(self):
+        return self._bytes.tell()
+
+    def read(self, size=None):
+        left_off_at = self._bytes.tell()
+        if size is None:
+            self._load_all()
+        else:
+            goal_position = left_off_at + size
+            self._load_until(goal_position)
+
+        self._bytes.seek(left_off_at)
+        return self._bytes.read(size)
+
+    def seek(self, position, whence=SEEK_SET):
+        if whence == SEEK_END:
+            self._load_all()
+        else:
+            self._bytes.seek(position, whence)
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self):
+        self.close()
+
+    def close(self):
+        self._response.close()
+        self._bytes.close()

From 9495fa97b4affea2825b58c5bc3b5f11158b0bf0 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 4 Dec 2021 15:50:50 -0600
Subject: [PATCH 24/47] Adding automatic retries to document elaboration HTTP
 requests

---
 owmeta/document.py | 59 ++++++++++++++++++++++++++--------------------
 setup.py           |  3 ++-
 2 files changed, 36 insertions(+), 26 deletions(-)

diff --git a/owmeta/document.py b/owmeta/document.py
index b5add9f2..48c8e6b5 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -1,5 +1,4 @@
 from six.moves.urllib.parse import urlparse, urlencode
-from six.moves.urllib.request import Request, urlopen
 from six.moves.urllib.error import HTTPError, URLError
 import re
 import logging
@@ -10,6 +9,8 @@
 
 from . import SCI_CTX
 from . import bibtex as BIB
+from .requests_stream import RequestsResponseStream
+
 
 logger = logging.getLogger(__name__)
 
@@ -239,22 +240,24 @@ def crRequest(doi):
                 if 'year' in r:
                     self.year(r['year'])
 
-    def update_from_pubmed(self):
+    def update_from_pubmed(self, requests_session=None):
         def pmRequest(pmid):
             import xml.etree.ElementTree as ET  # Python 2.5 and up
-            url = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=' + str(pmid)
+
+            url = ('https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?'
+                    f'db=pubmed&id={pmid}')
             key = self.get('pubmed.api_key', None)
             if key:
-                url += '&api_key=' + key
+                url += f'&api_key={key}'
             else:
                 logger.warning("PubMed API key not defined. API calls will be limited.")
-            s = _url_request(url)
+            s = _url_request(url, requests_session=requests_session)
             if hasattr(s, 'charset'):
                 parser = ET.XMLParser(encoding=s.charset)
             else:
                 parser = None
 
-            return ET.parse(s, parser)
+            return ET.parse(RequestsResponseStream(s), parser)
 
         pmid = self.pmid.defined_values
         if len(pmid) == 1:
@@ -307,35 +310,41 @@ def read(self):
         return bytes()
 
 
-def _url_request(url, headers={}):
+def _url_request(url, headers={}, requests_session=None, **kwargs):
+    import requests
+    from requests.adapters import HTTPAdapter
+    from requests.packages.urllib3.util.retry import Retry
+
+    sess = requests.Session()
+    retries = Retry()
+    adapter = HTTPAdapter(max_retries=retries)
+    sess.mount('http://', adapter)
+    sess.mount('https://', adapter)
+
+    if 'headers' not in kwargs:
+        kwargs['headers'] = headers
+
+    if 'timeout' not in kwargs:
+        kwargs['timeout'] = 1
+
     try:
-        r = Request(url, headers=headers)
-        s = urlopen(r, timeout=1)
-        info = dict(s.info())
-        content_type = {k.lower(): info[k] for k in info}['content-type']
+        resp = sess.get(url, **kwargs)
+        content_type = resp.headers['content-type']
         md = re.search("charset *= *([^ ]+)", content_type)
         if md:
-            s.charset = md.group(1)
+            resp.charset = md.group(1)
 
-        return s
-    except HTTPError:
-        logger.error("Error in request for {}".format(url), exc_info=True)
-        return EmptyRes()
-    except URLError:
-        logger.error("Error in request for {}".format(url), exc_info=True)
+        return resp
+    except Exception:
+        logger.error("Error in request for %s", url, exc_info=True)
         return EmptyRes()
 
 
 def _json_request(url):
-    import json
     headers = {'Accept': 'application/json'}
     try:
-        data = _url_request(url, headers).read().decode('UTF-8')
-        if hasattr(data, 'charset'):
-            return json.loads(data, encoding=data.charset)
-        else:
-            return json.loads(data)
+        return _url_request(url, headers).json()
     except BaseException:
-        logger.warning("Couldn't retrieve JSON data from " + url,
+        logger.warning("Couldn't retrieve JSON data from %s", url,
                        exc_info=True)
         return {}
diff --git a/setup.py b/setup.py
index 3e13ec82..e55c3a67 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,8 @@
         'bibtexparser~=1.1.0',
         'libneuroml',
         'rdflib>=4.1.2',
-        'six~=1.10'
+        'six~=1.10',
+        'requests',
     ],
     version=version,
     packages=['owmeta',

From 8c06373c173a2e54988b72b0ac727ac99a042ed1 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 4 Dec 2021 16:34:17 -0600
Subject: [PATCH 25/47] Allowing to pass in requests arguments for doc
 elaboration

---
 docs/conf.py       |  1 +
 owmeta/document.py | 69 +++++++++++++++++++++++++++++++---------------
 2 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/docs/conf.py b/docs/conf.py
index 38785258..9ea7fd92 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -37,6 +37,7 @@
 intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
                        'rdflib': ('https://rdflib.readthedocs.io/en/stable/', None),
                        'owmeta-core': ('https://owmeta-core.readthedocs.io/en/stable/', None),
+                       'requests': ('https://docs.python-requests.org/en/stable/', None),
                        'bibtexparser': ('https://bibtexparser.readthedocs.io/en/master/', None)}
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
diff --git a/owmeta/document.py b/owmeta/document.py
index 48c8e6b5..c620a380 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -1,11 +1,13 @@
 from six.moves.urllib.parse import urlparse, urlencode
-from six.moves.urllib.error import HTTPError, URLError
 import re
 import logging
 
 from owmeta_core.graph_object import IdentifierMissingException
 from owmeta_core.context import Context
 from owmeta_core.dataobject import DataObject, DatatypeProperty, Alias
+import requests
+from requests.adapters import HTTPAdapter
+from requests.packages.urllib3.util.retry import Retry
 
 from . import SCI_CTX
 from . import bibtex as BIB
@@ -160,11 +162,17 @@ def identifier_augment(self):
                 return self.make_identifier(s)
         raise IdentifierMissingException(self)
 
-    # TODO: Provide a way to override modification of already set values.
-    def update_from_wormbase(self, replace_existing=False):
-        """ Queries wormbase for additional data to fill in the Document.
+    def update_from_wormbase(self, replace_existing=False, **kwargs):
+        """ Queries WormBase.org for additional data to fill in the `Document`.
 
         If replace_existing is set to `True`, then existing values will be cleared.
+
+        Parameters
+        ----------
+        replace_existing : bool
+            Whether to replace values that are already set for a given property
+        **kwargs
+            Passed on as arguments to `requests.Session.get`
         """
 
         # XXX: wormbase's REST API is pretty sparse in terms of data provided.
@@ -177,8 +185,8 @@ def update_from_wormbase(self, replace_existing=False):
             # get the author
             try:
                 root = self.conf.get('wormbase_api_root_url', 'http://rest.wormbase.org')
-                url = root + '/rest/widget/paper/' + str(wbid) + '/overview?content-type=application%2Fjson'
-                j = _json_request(url)
+                url = f'{root}/rest/widget/paper/{wbid}/overview?content-type=application%2Fjson'
+                j = _json_request(url, **kwargs)
                 if 'fields' in j:
                     f = j['fields']
                     if 'authors' in f:
@@ -240,7 +248,16 @@ def crRequest(doi):
                 if 'year' in r:
                     self.year(r['year'])
 
-    def update_from_pubmed(self, requests_session=None):
+    def update_from_pubmed(self, **kwargs):
+        '''
+        Update the document attributes from NCBI Entrez API using the pubmed attribute
+
+        Parameters
+        ----------
+        **kwargs
+            Passed on as arguments to `requests.Session.get`
+        '''
+
         def pmRequest(pmid):
             import xml.etree.ElementTree as ET  # Python 2.5 and up
 
@@ -251,7 +268,11 @@ def pmRequest(pmid):
                 url += f'&api_key={key}'
             else:
                 logger.warning("PubMed API key not defined. API calls will be limited.")
-            s = _url_request(url, requests_session=requests_session)
+
+            if 'do_retries' not in kwargs:
+                kwargs['do_retries'] = True
+
+            s = _url_request(url, **kwargs)
             if hasattr(s, 'charset'):
                 parser = ET.XMLParser(encoding=s.charset)
             else:
@@ -310,19 +331,18 @@ def read(self):
         return bytes()
 
 
-def _url_request(url, headers={}, requests_session=None, **kwargs):
-    import requests
-    from requests.adapters import HTTPAdapter
-    from requests.packages.urllib3.util.retry import Retry
+def _url_request(url, requests_session=None, do_retries=False, **kwargs):
 
-    sess = requests.Session()
-    retries = Retry()
-    adapter = HTTPAdapter(max_retries=retries)
-    sess.mount('http://', adapter)
-    sess.mount('https://', adapter)
+    if requests_session is None:
+        sess = requests.Session()
+    else:
+        sess = requests_session
 
-    if 'headers' not in kwargs:
-        kwargs['headers'] = headers
+    if do_retries:
+        retries = Retry()
+        adapter = HTTPAdapter(max_retries=retries)
+        sess.mount('http://', adapter)
+        sess.mount('https://', adapter)
 
     if 'timeout' not in kwargs:
         kwargs['timeout'] = 1
@@ -340,10 +360,15 @@ def _url_request(url, headers={}, requests_session=None, **kwargs):
         return EmptyRes()
 
 
-def _json_request(url):
-    headers = {'Accept': 'application/json'}
+def _json_request(url, **kwargs):
+    if 'headers' in kwargs:
+        headers = kwargs['headers']
+    else:
+        headers = {}
+        kwargs['headers'] = headers
+    headers['Accept'] = 'application/json'
     try:
-        return _url_request(url, headers).json()
+        return _url_request(url, **kwargs).json()
     except BaseException:
         logger.warning("Couldn't retrieve JSON data from %s", url,
                        exc_info=True)

From 734f2cb982566441d6c117a2dd0e898defb87f7e Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 4 Dec 2021 21:01:32 -0600
Subject: [PATCH 26/47] Removing RequestsResponseStream

---
 owmeta/document.py        | 16 +++++++---
 owmeta/requests_stream.py | 62 ---------------------------------------
 2 files changed, 12 insertions(+), 66 deletions(-)
 delete mode 100644 owmeta/requests_stream.py

diff --git a/owmeta/document.py b/owmeta/document.py
index c620a380..2985456b 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -1,6 +1,7 @@
 from six.moves.urllib.parse import urlparse, urlencode
 import re
 import logging
+from contextlib import closing
 
 from owmeta_core.graph_object import IdentifierMissingException
 from owmeta_core.context import Context
@@ -11,7 +12,6 @@
 
 from . import SCI_CTX
 from . import bibtex as BIB
-from .requests_stream import RequestsResponseStream
 
 
 logger = logging.getLogger(__name__)
@@ -248,12 +248,15 @@ def crRequest(doi):
                 if 'year' in r:
                     self.year(r['year'])
 
-    def update_from_pubmed(self, **kwargs):
+    def update_from_pubmed(self, read_size=2**16, **kwargs):
         '''
         Update the document attributes from NCBI Entrez API using the pubmed attribute
 
         Parameters
         ----------
+        chunk_size : int
+            The number of bytes to pass to `requests.Response.iter_content`. This *may*
+            reduce runtime memory requirements for the request.
         **kwargs
             Passed on as arguments to `requests.Session.get`
         '''
@@ -272,13 +275,18 @@ def pmRequest(pmid):
             if 'do_retries' not in kwargs:
                 kwargs['do_retries'] = True
 
+            kwargs['stream'] = True
+
             s = _url_request(url, **kwargs)
             if hasattr(s, 'charset'):
                 parser = ET.XMLParser(encoding=s.charset)
             else:
-                parser = None
+                parser = ET.XMLParser(encoding='UTF-8')
 
-            return ET.parse(RequestsResponseStream(s), parser)
+            with s:
+                for chunk in s.iter_content(read_size):
+                    parser.feed(chunk)
+                return parser.close()
 
         pmid = self.pmid.defined_values
         if len(pmid) == 1:
diff --git a/owmeta/requests_stream.py b/owmeta/requests_stream.py
deleted file mode 100644
index bd302409..00000000
--- a/owmeta/requests_stream.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- coding: utf-8 -*-
-# Based on https://gist.github.com/obskyr/b9d4b4223e7eaf4eedcd9defabb34f13
-# released into the public domain
-
-from io import BytesIO, SEEK_SET, SEEK_END
-
-
-class RequestsResponseStream:
-    '''
-    Provides a :term:`file-like object` by wrapping a `requests` response iterator.
-    Requires the request is made with ``stream=True``.
-
-    Use the response as a context manager or call close when finished with this stream.
-    '''
-
-    def __init__(self, response, chunksize=4096):
-        self._bytes = BytesIO()
-        self._iterator = response.iter_content(chunksize)
-        self._response = response
-
-    def _load_all(self):
-        self._bytes.seek(0, SEEK_END)
-        for chunk in self._iterator:
-            self._bytes.write(chunk)
-
-    def _load_until(self, goal_position):
-        current_position = self._bytes.seek(0, SEEK_END)
-        while current_position < goal_position:
-            try:
-                current_position += self._bytes.write(next(self._iterator))
-            except StopIteration:
-                break
-
-    def tell(self):
-        return self._bytes.tell()
-
-    def read(self, size=None):
-        left_off_at = self._bytes.tell()
-        if size is None:
-            self._load_all()
-        else:
-            goal_position = left_off_at + size
-            self._load_until(goal_position)
-
-        self._bytes.seek(left_off_at)
-        return self._bytes.read(size)
-
-    def seek(self, position, whence=SEEK_SET):
-        if whence == SEEK_END:
-            self._load_all()
-        else:
-            self._bytes.seek(position, whence)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self):
-        self.close()
-
-    def close(self):
-        self._response.close()
-        self._bytes.close()

From 4b324c5bbe5aed96af21c39ee7e9ba572eba4d13 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Mon, 6 Dec 2021 18:59:04 -0600
Subject: [PATCH 27/47] Raising for doc elaboration HTTP request errors

---
 owmeta/document.py | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/owmeta/document.py b/owmeta/document.py
index 2985456b..9fcf4661 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -1,7 +1,6 @@
 from six.moves.urllib.parse import urlparse, urlencode
 import re
 import logging
-from contextlib import closing
 
 from owmeta_core.graph_object import IdentifierMissingException
 from owmeta_core.context import Context
@@ -334,11 +333,6 @@ def _doi_uri_to_doi(uri):
     return doi
 
 
-class EmptyRes(object):
-    def read(self):
-        return bytes()
-
-
 def _url_request(url, requests_session=None, do_retries=False, **kwargs):
 
     if requests_session is None:
@@ -365,7 +359,7 @@ def _url_request(url, requests_session=None, do_retries=False, **kwargs):
         return resp
     except Exception:
         logger.error("Error in request for %s", url, exc_info=True)
-        return EmptyRes()
+        raise
 
 
 def _json_request(url, **kwargs):

From f580a1194fab79d2229ba9fdc6133b5fd78dd933 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Fri, 10 Dec 2021 14:07:49 -0600
Subject: [PATCH 28/47] Updating a couple of links in the readme

---
 README.md | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 35e8902a..6fed7ff7 100644
--- a/README.md
+++ b/README.md
@@ -267,9 +267,10 @@ Finally, when you're done accessing the database, be sure to disconnect from it:
 
 ```
 
-More examples can be found
-[here](http://owm-doc.readthedocs.org/en/latest/making_dataObjects.html) and
-[here](https://github.com/openworm/owmeta/tree/master/examples).
+More examples can be found [in the owmeta-core
+documentation](https://owmeta-core.readthedocs.io/en/latest/making_dataObjects.html)
+and [in the ./examples directory of the owmeta Git
+repository](https://github.com/openworm/owmeta/tree/master/examples).
 
 Documentation
 -------------

From 957a4fe53ee2c2862b56b8de0899f5b5181f9fbd Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Tue, 14 Dec 2021 07:35:14 -0600
Subject: [PATCH 29/47] Adjusting for github_token suddenly being reserved

---
 .github/workflows/dev-test.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml
index 113b814c..8d1f5f75 100644
--- a/.github/workflows/dev-test.yml
+++ b/.github/workflows/dev-test.yml
@@ -12,7 +12,7 @@ jobs:
       coveralls: ${{github.event_name != 'schedule'}}
       ref: ${{ github.ref }}
     secrets:
-      github_token: ${{secrets.GITHUB_TOKEN}}
+      my_github_token: ${{secrets.GITHUB_TOKEN}}
       pubmed_api_key: ${{secrets.PUBMED_API_KEY}}
 
   coveralls:
@@ -20,5 +20,5 @@ jobs:
     needs: test
     uses: openworm/owmeta/.github/workflows/coveralls-upload.yml@github-workflows
     secrets:
-      github_token: ${{secrets.GITHUB_TOKEN}}
+      my_github_token: ${{secrets.GITHUB_TOKEN}}
 

From fd184488b7666713cb8321ce95878dd34205fa54 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Tue, 14 Dec 2021 07:44:32 -0600
Subject: [PATCH 30/47] Updating badge

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6fed7ff7..9f2b9589 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://travis-ci.org/openworm/owmeta.png?branch=dev)](https://travis-ci.org/openworm/owmeta/builds)
+[![Build Status](https://github.com/openworm/owmeta/actions/workflows/dev-test.yml/badge.svg)](https://github.com/openworm/owmeta/actions/workflows/dev-test.yml)
 [![Docs](https://readthedocs.org/projects/owmeta/badge/?version=latest)](https://owmeta.readthedocs.io/en/latest)
 [![Coverage Status](https://coveralls.io/repos/github/openworm/owmeta/badge.svg?branch=dev)](https://coveralls.io/github/openworm/owmeta?branch=dev)
 

From 1f410b97e43ec5b903dca8654d1458c719e25af4 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 18 Dec 2021 18:18:05 -0600
Subject: [PATCH 31/47] Adding a test for SourcedFrom

---
 ...ixinTest.py => DocumentSourcedFromTest.py} | 26 +++++++++----------
 .../test_modules/evidence_ds_mixin_source.py  |  6 +++++
 2 files changed, 18 insertions(+), 14 deletions(-)
 rename tests/{EvidenceDSMixinTest.py => DocumentSourcedFromTest.py} (58%)
 create mode 100644 tests/test_modules/evidence_ds_mixin_source.py

diff --git a/tests/EvidenceDSMixinTest.py b/tests/DocumentSourcedFromTest.py
similarity index 58%
rename from tests/EvidenceDSMixinTest.py
rename to tests/DocumentSourcedFromTest.py
index e17aeba6..b762774f 100644
--- a/tests/EvidenceDSMixinTest.py
+++ b/tests/DocumentSourcedFromTest.py
@@ -7,6 +7,8 @@
 from owmeta_core.datasource import DataSource
 from owmeta_pytest_plugin import bundle_versions
 
+from owmeta.document import SourcedFrom
+
 
 EX = Namespace('http://example.org/')
 
@@ -25,21 +27,17 @@ def test_augment_cmd_load(owmeta_schema_bundle, owm_project):
             'tests/test_modules/evidence_ds_mixin_source.py')
     owm_project.sh('owm save test_module.asource')
 
-    with owm_project.owm().connect() as conn:
-        conn.rdf.namespace_manager.bind('ex', EX)
-
-    owm_project.sh(
-            'owm declare owmeta.document:Document doi=10.1101/398370 --id=ex:doc')
-    with owm_project.owm().connect() as conn:
-        print(conn.rdf.serialize(format='n3').decode('utf-8'))
+    owm_project.sh(f'owm namespace bind ex {EX}')
+    ctxid = owm.default_context.identifier
     owm_project.sh(
-            'owm declare owmeta.evidence:Evidence reference=ex:doc'
-            '    rdfs_comment="This says some stuff" --id=ex:ev',
-            'owm declare test_module.asource:ASource a="Some arbitrary value" --id=ex:ds',
-            'owm source attach-evidence ex:ds ex:ev')
+            f'owm contexts add-import {ctxid} http://schema.openworm.org/2020/07/sci',
+            'owm declare owmeta.document:Document doi=10.1101/398370 --id=ex:doc',
+            'owm declare test_module.asource:ASource'
+            ' owmeta.document:SourcedFrom=ex:doc'
+            ' --id=ex:ds',)
 
     owm = owm_project.owm()
     with owm.connect():
-        ds = list(owm.default_context(DataSource)(ident=EX['ds']).load())
-        ev = ds.attached_evidence.one()
-        assert ev.identifier == EX['ev']
+        ds = owm.default_context.stored(DataSource)(ident=EX['ds']).load_one()
+        doc = ds.attach_property(SourcedFrom).one()
+        assert doc.identifier == EX['doc']
diff --git a/tests/test_modules/evidence_ds_mixin_source.py b/tests/test_modules/evidence_ds_mixin_source.py
new file mode 100644
index 00000000..e1beb165
--- /dev/null
+++ b/tests/test_modules/evidence_ds_mixin_source.py
@@ -0,0 +1,6 @@
+from owmeta_core.datasource import DataSource, Informational
+
+
+class ASource(DataSource):
+    class_context = 'http://example.org/a_context'
+    a = Informational(display_name='A Value')

From 02411683416421574e3198cca0fabbc07d4b7adc Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 05:38:51 -0600
Subject: [PATCH 32/47] Adding automated deploy of dev snapshots from CI

---
 .github/workflows/dev-test.yml |  8 ++++++++
 deploy.sh                      | 14 ++++++++++++++
 2 files changed, 22 insertions(+)
 create mode 100755 deploy.sh

diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml
index 8d1f5f75..38adadd1 100644
--- a/.github/workflows/dev-test.yml
+++ b/.github/workflows/dev-test.yml
@@ -14,6 +14,14 @@ jobs:
     secrets:
       my_github_token: ${{secrets.GITHUB_TOKEN}}
       pubmed_api_key: ${{secrets.PUBMED_API_KEY}}
+  dev-deploy:
+    if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
+    uses: openworm/owmeta-core/.github/workflows/deploy.yml@github-workflows
+    needs: test
+    with:
+      ref: refs/heads/dev
+    secrets:
+      twine_token: ${{secrets.TWINE_PASSWORD}}
 
   coveralls:
     if: github.event_name == 'push'
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 00000000..57bd96d3
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,14 @@
+#!/bin/bash -xe
+HEAD_REV=$(git rev-parse HEAD)
+ORIGIN_DEV_REV=$(git ls-remote origin refs/heads/develop | grep -E -o '^[^[:space:]]+')
+if [ "$HEAD_REV" != "$ORIGIN_DEV_REV" ] ; then
+    echo "Not deploying since we aren't on the 'develop' branch" >&2
+    exit 0
+fi
+
+git log --format=%s -n 1 "$HEAD_REV" | grep -E -q '(^MINOR:)|(\[skip-deploy\])' && exit 0
+
+date=$(date +"%Y%m%d%H%M%S")
+sed -i -r "s/__version__ = '([^']+)\\.dev0'/__version__ = '\\1.dev$date'/" owmeta/__init__.py
+python setup.py egg_info sdist bdist_wheel
+twine upload -c "Built by CI. Uploaded after $(date +"%Y-%m-%d %H:%M:%S")" dist/owmeta*tar.gz dist/owmeta*whl

From d4c0113015c809f007bf337683a42884c5007a0e Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 08:59:33 -0600
Subject: [PATCH 33/47] Disabling wormbase document elaboration tests in CI
 temporarily

---
 ci-test.sh | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ci-test.sh b/ci-test.sh
index afe07331..6d354be5 100755
--- a/ci-test.sh
+++ b/ci-test.sh
@@ -4,7 +4,6 @@ pt () {
     sh -c "pytest --cov=owmeta $*"
 }
 
-
 COVERAGES=""
 
 add_coverage () {
@@ -31,7 +30,7 @@ if [ $BUNDLE_TESTS ] ; then
 else
     pt --verbose -m "'not inttest'"
     add_coverage
-    pt --verbose -m "'inttest and not data_bundle'"
+    pt --verbose -m "'inttest and not data_bundle'" -k 'not wormbase'
     add_coverage
 fi
 coverage combine $(list_coverage)

From 1c8ecae8135b1a7de36afab4dac68624a37de792 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 10:13:56 -0600
Subject: [PATCH 34/47] Making Document elaboration response handling more
 robust

- Should not fail for lack of content-type in response since we
  only retrieve it for determining the character encoding
- We do expect a successful response, so fail first if we do not
  get one
---
 ci-test.sh         |  2 +-
 owmeta/document.py | 11 +++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/ci-test.sh b/ci-test.sh
index 6d354be5..a324cd7b 100755
--- a/ci-test.sh
+++ b/ci-test.sh
@@ -30,7 +30,7 @@ if [ $BUNDLE_TESTS ] ; then
 else
     pt --verbose -m "'not inttest'"
     add_coverage
-    pt --verbose -m "'inttest and not data_bundle'" -k 'not wormbase'
+    pt --verbose -m "'inttest and not data_bundle'" -k "'not wormbase'"
     add_coverage
 fi
 coverage combine $(list_coverage)
diff --git a/owmeta/document.py b/owmeta/document.py
index 5bb78abc..200569e1 100644
--- a/owmeta/document.py
+++ b/owmeta/document.py
@@ -364,10 +364,13 @@ def _url_request(url, requests_session=None, do_retries=False, **kwargs):
 
     try:
         resp = sess.get(url, **kwargs)
-        content_type = resp.headers['content-type']
-        md = re.search("charset *= *([^ ]+)", content_type)
-        if md:
-            resp.charset = md.group(1)
+        if resp.status_code != 200:
+            raise Exception(f'Service returned status code {resp.status_code}')
+        content_type = resp.headers.get('content-type')
+        if content_type:
+            md = re.search("charset *= *([^ ]+)", content_type)
+            if md:
+                resp.charset = md.group(1)
 
         return resp
     except Exception:

From ba0888d15bd830cb03bab4c6bd1fe41c1c72ed7d Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 10:22:33 -0600
Subject: [PATCH 35/47] Attempting to correct deploy.sh for owmeta

---
 deploy.sh | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/deploy.sh b/deploy.sh
index 57bd96d3..202f9604 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -1,10 +1,8 @@
 #!/bin/bash -xe
 HEAD_REV=$(git rev-parse HEAD)
-ORIGIN_DEV_REV=$(git ls-remote origin refs/heads/develop | grep -E -o '^[^[:space:]]+')
-if [ "$HEAD_REV" != "$ORIGIN_DEV_REV" ] ; then
-    echo "Not deploying since we aren't on the 'develop' branch" >&2
+git ls-remote origin refs/heads/dev | grep -q -E -o "^$HEAD_REV" || \
+    echo "Not deploying since we aren't on the 'dev' branch" >&2 && \
     exit 0
-fi
 
 git log --format=%s -n 1 "$HEAD_REV" | grep -E -q '(^MINOR:)|(\[skip-deploy\])' && exit 0
 

From 29c6bf8a29ec8a2e58fcddeaa8d5eb9bc08fe8c5 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 10:37:41 -0600
Subject: [PATCH 36/47] Attempting (again) to correct deploy.sh for owmeta

---
 deploy.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/deploy.sh b/deploy.sh
index 202f9604..2969d619 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -1,8 +1,8 @@
 #!/bin/bash -xe
 HEAD_REV=$(git rev-parse HEAD)
-git ls-remote origin refs/heads/dev | grep -q -E -o "^$HEAD_REV" || \
-    echo "Not deploying since we aren't on the 'dev' branch" >&2 && \
-    exit 0
+git ls-remote origin refs/heads/dev | grep -q -E "^$HEAD_REV" || \
+    ( echo "Not deploying since we aren't on the 'dev' branch" >&2 && \
+    exit 0 )
 
 git log --format=%s -n 1 "$HEAD_REV" | grep -E -q '(^MINOR:)|(\[skip-deploy\])' && exit 0
 

From 6cb3925e6d6e76400f42e10942ef1112c61639da Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 23 Dec 2021 16:42:14 -0600
Subject: [PATCH 37/47] Re-enabling wormbase tests

---
 ci-test.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci-test.sh b/ci-test.sh
index a324cd7b..45919e07 100755
--- a/ci-test.sh
+++ b/ci-test.sh
@@ -30,7 +30,7 @@ if [ $BUNDLE_TESTS ] ; then
 else
     pt --verbose -m "'not inttest'"
     add_coverage
-    pt --verbose -m "'inttest and not data_bundle'" -k "'not wormbase'"
+    pt --verbose -m "'inttest and not data_bundle'"
     add_coverage
 fi
 coverage combine $(list_coverage)

From 78394d07fb242b9278a95749c44fa0946e989a8a Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Fri, 24 Dec 2021 16:00:29 -0600
Subject: [PATCH 38/47] Adding some detail on how DWEDS IDs work

---
 owmeta/data_trans/data_with_evidence_ds.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/owmeta/data_trans/data_with_evidence_ds.py b/owmeta/data_trans/data_with_evidence_ds.py
index 9d56e7a5..d51249d3 100644
--- a/owmeta/data_trans/data_with_evidence_ds.py
+++ b/owmeta/data_trans/data_with_evidence_ds.py
@@ -11,8 +11,10 @@
 class DataWithEvidenceDataSource(DSMixin, DataSource):
     '''
     A data source that has an "evidence context" containing statements which support those
-    in its "data context". The data source also has a combined context which  imports both
-    the data and evidence contexts.
+    in its "data context". The data source also has a combined context which imports both
+    the data and evidence contexts. The data and evidence contexts have identifiers based
+    on the data source's identifier and the combined context has the same identifier as
+    the data source.
     '''
 
     class_context = SCI_CTX

From 4d546107c12ecb12f3d946db7a44b93b80877132 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 26 Dec 2021 20:03:34 -0600
Subject: [PATCH 39/47] Reducing scheduled dev builds to 4 per day

---
 .github/workflows/scheduled-dev-build.yml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/.github/workflows/scheduled-dev-build.yml b/.github/workflows/scheduled-dev-build.yml
index 408c90c1..7048b87b 100644
--- a/.github/workflows/scheduled-dev-build.yml
+++ b/.github/workflows/scheduled-dev-build.yml
@@ -2,8 +2,7 @@ name: Build develop
 
 on:
   schedule:
-    # minute 39 of every hour
-    - cron:  '39 * * * *'
+    - cron:  '39 4,10,16,22 * * *'
 
 jobs:
   test:

From db578231c38bfe2e7ae336a5fefc59a3abda7cc7 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 24 Apr 2022 22:08:06 -0500
Subject: [PATCH 40/47] Setting class registry context for test configs

---
 tests/DataTestTemplate.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/DataTestTemplate.py b/tests/DataTestTemplate.py
index c55dc9f1..eb29f930 100644
--- a/tests/DataTestTemplate.py
+++ b/tests/DataTestTemplate.py
@@ -7,6 +7,7 @@
 
 from owmeta_core.context import Context
 from owmeta_core.data import Data
+from owmeta_core.mapper import CLASS_REGISTRY_CONTEXT_KEY
 from .GraphDBInit import delete_zodb_data_store, TEST_CONFIG
 
 
@@ -34,6 +35,7 @@ def setUp(self):
             x = z[len(td):]
             h = tempfile.mkdtemp()
             self.TestConfig['rdf.store_conf'] = h + x
+        self.TestConfig[CLASS_REGISTRY_CONTEXT_KEY] = 'http://example.org/class_registry'
         self.delete_dir()
         self.connection = owmeta_core.connect(conf=self.TestConfig)
         self.mapper = self.connection.mapper

From 59b9652dcf8e52a3a36f6809c0b4ee892b9e9d56 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sun, 29 May 2022 13:07:08 -0500
Subject: [PATCH 41/47] Switching to the official requests sphinx ref

- See https://github.com/psf/requests/issues/6140#issuecomment-1135071992 for details
---
 docs/conf.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/conf.py b/docs/conf.py
index 9ea7fd92..00ac7c64 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -37,7 +37,7 @@
 intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
                        'rdflib': ('https://rdflib.readthedocs.io/en/stable/', None),
                        'owmeta-core': ('https://owmeta-core.readthedocs.io/en/stable/', None),
-                       'requests': ('https://docs.python-requests.org/en/stable/', None),
+                       'requests': ('https://requests.readthedocs.io/en/stable/', None),
                        'bibtexparser': ('https://bibtexparser.readthedocs.io/en/master/', None)}
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']

From 7776c337970246dcff0a49268a7b498bedbb10af Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Sat, 18 Jun 2022 19:29:29 -0500
Subject: [PATCH 42/47] Adding transaction managers for docs/examples

---
 README.md        | 5 +++--
 examples/rmgr.py | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 9f2b9589..fcd63300 100644
--- a/README.md
+++ b/README.md
@@ -178,8 +178,9 @@ data and models to corresponding articles from peer-reviewed literature:
 owmeta_core.statement.Statement(subj=Neuron(ident=rdflib.term.URIRef('http://data.openworm.org/sci/bio/Neuron#AVDL')), prop=owmeta.cell.Cell_lineageName(owner=Neuron(ident=rdflib.term.URIRef('http://data.openworm.org/sci/bio/Neuron#AVDL'))), obj=owmeta_core.dataobject_property.ContextualizedPropertyValue(rdflib.term.Literal('AB alaaapalr')), context=owmeta_core.context.Context(ident="http://example.org/data/context"))
 >>> e.supports(dctx.rdf_object)
 owmeta_core.statement.Statement(subj=Evidence(ident=rdflib.term.URIRef('http://data.openworm.org/Evidence#Sulston83')), prop=owmeta.evidence.Evidence_supports(owner=Evidence(ident=rdflib.term.URIRef('http://data.openworm.org/Evidence#Sulston83'))), obj=ContextDataObject(ident=rdflib.term.URIRef('http://example.org/data/context')), context=owmeta_core.context.Context(ident="http://example.org/evidence/context"))
->>> dctx.save_context()
->>> evctx.save_context()
+>>> with conn.transaction_manager:
+...     dctx.save_context()
+...     evctx.save_context()
 
 ```
 
diff --git a/examples/rmgr.py b/examples/rmgr.py
index 9fc16be9..5fbfd0e5 100644
--- a/examples/rmgr.py
+++ b/examples/rmgr.py
@@ -113,7 +113,7 @@ def setup(sctx, ctx, name, type):
     return n
 
 
-with OWM('../.owm').connect() as conn:
+with OWM('../.owm').connect().transaction() as conn:
     ctx = conn(Context)('http://example.org/data')
     evctx = conn(Context)('http://example.org/evidence')
 

From 1c48bafa9a7b9c65be9b451b9fdae717491fc162 Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Mon, 29 May 2023 18:56:39 -0500
Subject: [PATCH 43/47] fixing a couple of tests

---
 examples/add_reference.py | 21 ++++++++++++++++++---
 tests/EvidenceTest.py     |  5 ++++-
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/examples/add_reference.py b/examples/add_reference.py
index 3cf334d9..6fdfe61e 100644
--- a/examples/add_reference.py
+++ b/examples/add_reference.py
@@ -10,7 +10,8 @@
 
 import owmeta_core as P
 from owmeta_core.data import Data
-from owmeta_core.context import Context
+from owmeta_core.dataobject import DataObject
+from owmeta_core.context import Context, IMPORTS_CONTEXT_KEY
 
 from owmeta.evidence import Evidence
 from owmeta.neuron import Neuron
@@ -18,13 +19,18 @@
 
 # Create dummy database configuration.
 d = Data()
+d[IMPORTS_CONTEXT_KEY] = 'http://example.org/imports'
 
 # Connect to database with dummy configuration
 conn = P.connect(conf=d)
 conn.mapper.add_class(Evidence)
 conn.mapper.add_class(Document)
-ctx = conn(Context)(ident='http://example.org/data')
 evctx = conn(Context)(ident='http://example.org/meta')
+ctx = evctx(Context)(ident='http://example.org/data')
+
+# Add the Context RDF class to the mapper -- normally you'd get these from the
+# openworm/owmeta-core bundle as a dependency
+conn.mapper.add_class(type(ctx.rdf_object))
 
 # Create a new Neuron object to work with
 n = ctx(Neuron)(name='AVAL')
@@ -46,9 +52,18 @@
 ctx.save_context()
 evctx.save_context()
 
+evctx.add_import(Document.definition_context)
+evctx.save_imports()
+
+# Add a couple contexts to the store so we can resolve needed types. normally you'd get
+# these from the openworm/owmeta-core bundle as a dependency, so they don't have to be
+# added to the database again.
+Document.definition_context.save_context(conn.rdf)
+DataObject.definition_context.save_context(conn.rdf)
+
 # What does my evidence object contain?
 for e_i in evctx.stored(Evidence)().load():
     print(e_i.reference(), e_i.supports())
 
 # Disconnect from the database.
-P.disconnect(conn)
+conn.disconnect()
diff --git a/tests/EvidenceTest.py b/tests/EvidenceTest.py
index 5cb47dc8..4024b153 100644
--- a/tests/EvidenceTest.py
+++ b/tests/EvidenceTest.py
@@ -4,6 +4,7 @@
 
 from owmeta_core.dataobject import DataObject
 from owmeta_core.configure import Configurable
+from owmeta_core.context import Context
 
 from owmeta.evidence import Evidence
 
@@ -14,6 +15,7 @@
 except ImportError:
     from mock import patch
 
+import rdflib
 
 class EvidenceTest(_DataTest):
     ctx_classes = (Evidence,)
@@ -32,7 +34,8 @@ def test_asserts(self):
         Asserting something should allow us to get it back.
         """
         e = self.ctx.Evidence(key='WBPaper00044600')
-        r = DataObject(key="context_data_object")
+        ctx = self.context(Context)(rdflib.URIRef('https://example.org/context'))
+        r = ctx.rdf_object
         e.supports(r)
         s = list(e.supports.get())
         self.assertIn(r, s)

From 0ecc5b936573897d02f56902b2216b16a2edf52c Mon Sep 17 00:00:00 2001
From: Mark Watts <watts.mark2015@gmail.com>
Date: Thu, 1 Jun 2023 23:59:29 -0500
Subject: [PATCH 44/47] Correcting context for data context declaration in
 README

- The supports query constrains to contexts, but the evidence context lacked the
  rdf:type statement for the data context
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index fcd63300..e1945b58 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,7 @@ data and models to corresponding articles from peer-reviewed literature:
 >>> evctx = conn(Context)(ident='http://example.org/evidence/context')
 
 # Make a context for defining domain knowledge
->>> dctx = conn(Context)(ident='http://example.org/data/context')
+>>> dctx = evctx(Context)(ident='http://example.org/data/context')
 >>> doc = evctx(Document)(key="Sulston83", author='Sulston et al.', date='1983')
 >>> e = evctx(Evidence)(key="Sulston83", reference=doc)
 >>> avdl = dctx(Neuron)(name="AVDL")

From f5d55309b8059dc7fed8898dcafa8ffba34f61b2 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson <p.gleeson@gmail.com>
Date: Mon, 24 Jun 2024 18:48:52 +0100
Subject: [PATCH 45/47] Update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index e1945b58..4720c5d3 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 [![Docs](https://readthedocs.org/projects/owmeta/badge/?version=latest)](https://owmeta.readthedocs.io/en/latest)
 [![Coverage Status](https://coveralls.io/repos/github/openworm/owmeta/badge.svg?branch=dev)](https://coveralls.io/github/openworm/owmeta?branch=dev)
 
-owmeta
+owmeta 
 ======
 <img width="1207" alt="pyow_in_overview" src="openworm-overview.png">
 

From a1d3f3ff9cb726a7e148381cceb4e17e49456224 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson <p.gleeson@gmail.com>
Date: Mon, 22 Jul 2024 14:07:54 -0300
Subject: [PATCH 46/47] Update scheduled-dev-build.yml

---
 .github/workflows/scheduled-dev-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/scheduled-dev-build.yml b/.github/workflows/scheduled-dev-build.yml
index 7048b87b..20889a3f 100644
--- a/.github/workflows/scheduled-dev-build.yml
+++ b/.github/workflows/scheduled-dev-build.yml
@@ -2,7 +2,7 @@ name: Build develop
 
 on:
   schedule:
-    - cron:  '39 4,10,16,22 * * *'
+    - cron:  '39 12 10,23 * *'
 
 jobs:
   test:

From 16a9199b803c26119f2d227395da1ccf608d6ad9 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson <p.gleeson@gmail.com>
Date: Mon, 22 Jul 2024 14:11:33 -0300
Subject: [PATCH 47/47] Update scheduled-master-build.yml

---
 .github/workflows/scheduled-master-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/scheduled-master-build.yml b/.github/workflows/scheduled-master-build.yml
index f7087e9b..d70e2a38 100644
--- a/.github/workflows/scheduled-master-build.yml
+++ b/.github/workflows/scheduled-master-build.yml
@@ -2,7 +2,7 @@ name: Build master
 
 on:
   schedule:
-    - cron:  '13 2 * * *'
+    - cron:  '13 2 10,23 * *'
 
 jobs:
   test: