Skip to content

Commit 9c09930

Browse files
committed
Adding some docs for transactions
1 parent 5e34f78 commit 9c09930

File tree

7 files changed

+80
-8
lines changed

7 files changed

+80
-8
lines changed

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@ named graphs you want to include in the bundle, serializing them, and putting
4141
them in a particular file structure. Here's how you can do that:
4242

4343
>>> from owmeta_core.bundle import Installer, Descriptor
44-
>>> from owmeta_core.data import TRANSACTION_MANAGER_KEY
4544
>>> from rdflib.term import URIRef
46-
>>> import transaction
4745

48-
>>> with connect() as conn, conn.conf[TRANSACTION_MANAGER_KEY]:
46+
>>> with connect().transaction() as conn:
4947
... # add some stuff to http://example.org/ctx ...
5048
... g = conn.rdf.graph(URIRef('http://example.org/ctx'))
5149
... _ = g.add((URIRef('http://example.org/s'),

docs/transactions.rst

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
.. _transactions:
2+
3+
Transactions
4+
============
5+
Transactions in |owm| are managed through the `transaction`_ library. The
6+
default RDF store is transactional. You can execute code within a transaction
7+
using a transaction manager. |owm| connections come with a transaction manager
8+
which you can access via the `transaction_manager` attribute. It's recommended
9+
to use a context manager to start and commit transactions like this::
10+
11+
>>> from rdflib.term import URIRef
12+
>>> from owmeta_core import connect
13+
>>> with connect() as conn, conn.transaction_manager:
14+
... conn.rdf.add((
15+
... URIRef('http://example.org/bob'),
16+
... URIRef('http://example.org/likes'),
17+
... URIRef('http://example.org/alice')))
18+
19+
Because this is a common pattern, there's a
20+
:meth:`~owmeta_core.Connection.transaction` method that does something
21+
equivalent which is provided for convenience::
22+
23+
>>> with connect().transaction() as conn:
24+
... conn.rdf.add((
25+
... URIRef('http://example.org/bob'),
26+
... URIRef('http://example.org/likes'),
27+
... URIRef('http://example.org/alice')))
28+
29+
Similar usage is possible with project connections through the high-level
30+
`~owmeta_core.command.OWM` interface::
31+
32+
>>> from owmeta_core.command import OWM
33+
>>> owm = OWM(non_interactive=True)
34+
>>> owm.init(default_context_id=URIRef("http://example.org/context"))
35+
Initialized owmeta-core project at .../.owm
36+
37+
>>> with owm.connect().transaction() as conn:
38+
... conn.rdf.add((
39+
... URIRef('http://example.org/bob'),
40+
... URIRef('http://example.org/likes'),
41+
... URIRef('http://example.org/alice')))
42+
43+
However, the methods of `~owmeta_core.command.OWM` and its "sub-commands" will
44+
typically manage the transactions themselves, so it wouldn't be necessary to
45+
start a transaction explicitly before calling these methods--in fact, doing so
46+
would typically cause an exception. For example, in this code::
47+
48+
>>> owm.say('http://example.org/bob',
49+
... 'http://example.org/likes',
50+
... 'http://example.org/eve')
51+
52+
we don't have to declare a transaction since the `~owmeta_core.command.OWM.say`
53+
method handles that for us.
54+
55+
For read-only operations, it is not strictly necessary to read from the RDF
56+
store within the context of a transaction, but it is recommended if you're in a
57+
multithreaded context to avoid getting an inconsistent picture of the data if
58+
there's an update part way through your operation.
59+
60+
.. _transaction: https://transaction.readthedocs.io/en/latest/

docs/userdocs.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ For Users
1212
python_release_compatibility
1313
bittorrent
1414
query
15-
15+
transactions

owmeta_core/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import logging
1818
import uuid
1919
from os.path import join as pth_join
20+
from contextlib import contextmanager
2021

2122
LOGGER = logging.getLogger(__name__)
2223
LOGGER.addHandler(logging.NullHandler())
@@ -145,6 +146,15 @@ def transaction_manager(self):
145146
from .data import TRANSACTION_MANAGER_KEY
146147
return self.conf[TRANSACTION_MANAGER_KEY]
147148

149+
@contextmanager
150+
def transaction(self):
151+
'''
152+
Context manager that executes the enclosed code in a transaction and then closes
153+
the connection. Provides the connection for binding with ``as``.
154+
'''
155+
with self, self.transaction_manager:
156+
yield self
157+
148158
def disconnect(self):
149159
'''
150160
Close the database and stop listening to module loaders

owmeta_core/command.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2583,10 +2583,10 @@ def __str__(self):
25832583
def transaction(self):
25842584
'''
25852585
Context manager that executes the enclosed code in a transaction and then closes
2586-
the connection
2586+
the connection. Provides the connection for binding with ``as``.
25872587
'''
25882588
with self, self.transaction_manager:
2589-
yield
2589+
yield self
25902590

25912591

25922592
class _ProjectContext(Context):

tests/CommandTest.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,9 @@ def test_unsupported_namespace_manager_conf_for_read_only(self):
572572

573573
def test_connect_transaction(self):
574574
self._init_conf()
575-
with self.cut.connect(read_only=True).transaction():
576-
pass
575+
with self.cut.connect(read_only=True).transaction() as conn:
576+
# get a transaction
577+
conn.transaction_manager.get()
577578

578579
assert not self.cut.connected
579580

tests/DocumentationTest.py

+3
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ def execute(self, fname, **kwargs):
8787

8888
def test_making_dataObjects(self):
8989
self.execute('making_dataObjects')
90+
91+
def test_transactions(self):
92+
self.execute('transactions')

0 commit comments

Comments
 (0)