allegedb¶
Object relational mapper for graphs with in-built revision control.
allegedb serves its own special variants on the networkx graph classes: Graph, DiGraph, MultiGraph, and MultiDiGraph. Every change to them is stored in an SQL database.
This means you can keep multiple versions of one set of graphs and switch between them without the need to save, load, or run git-checkout. Just point the ORM at the correct branch and revision, and all of the graphs in the program will change. All the different branches and revisions remain in the database to be brought back when needed.
usage¶
>>> from allegedb import ORM
>>> orm = ORM('sqlite:///test.db')
>>> orm.initdb() # only necessary the first time you use a particular database
>>> g = orm.new_graph('test') # also new_digraph, new_multigraph, new_multidigraph
>>> g.add_nodes_from(['spam', 'eggs', 'ham'])
>>> g.add_edge('spam', 'eggs')
>>> g.edge # strings become unicode because that's the way sqlite3 rolls
{u'eggs': {u'ham': {}, u'spam': {}}, u'ham': {u'eggs': {}}, u'spam': {u'eggs': {}}}
>>> del g
>>> orm.close()
>>> del orm
>>> orm = ORM('sqlite:///test.db')
>>> g = orm.get_graph('test') # returns whatever graph type you stored by that name
>>> g.edge
{u'eggs': {u'ham': {}, u'spam': {}}, u'ham': {u'eggs': {}}, u'spam': {u'eggs': {}}}
>>> import networkx as nx
>>> red = nx.random_lobster(10,0.9,0.9)
>>> blue = orm.new_graph('red', red) # initialize with data from the given graph
>>> red.edge == blue.edge
True
>>> orm.rev = 1
>>> blue.add_edge(17, 15)
>>> red.edge = blue.edge
False
>>> orm.rev = 0 # undoing what I did when rev-1
>>> red.edge == blue.edge
True
>>> orm.rev = 0
>>> orm.branch = 'test' # navigating to a branch for the first time creates that branch
>>> orm.rev = 1
>>> red.edge == blue.edge
True
>>> orm.branch = 'trunk'
>>> red.edge == blue.edge
False
ORM¶
The main interface to the allegedb ORM, and some supporting functions and classes
-
class
allegedb.
ORM
(dbstring, alchemy=True, connect_args={}, validate=False)[source]¶ Instantiate this with the same string argument you’d use for a SQLAlchemy
create_engine
call. This will be your interface to allegedb.-
advancing
()[source]¶ A context manager for when time is moving forward one turn at a time.
When used in LiSE, this means that the game is being simulated. It changes how the caching works, making it more efficient.
-
batch
()[source]¶ A context manager for when you’re creating lots of state.
Reads will be much slower in a batch, but writes will be faster.
You can combine this with
advancing
but it isn’t any faster.
-
commit
()[source]¶ Write the state of all graphs to the database and commit the transaction.
Also saves the current branch, turn, and tick.
-
contextmanager
()¶ @contextmanager decorator.
Typical usage:
@contextmanager def some_generator(<arguments>):
<setup> try:
yield <value>- finally:
- <cleanup>
This makes this:
- with some_generator(<arguments>) as <variable>:
- <body>
equivalent to this:
<setup> try:
<variable> = <value> <body>- finally:
- <cleanup>
-
edge_cls
¶ alias of
allegedb.graph.Edge
-
get_delta
(branch, turn_from, tick_from, turn_to, tick_to)[source]¶ Get a dictionary describing changes to all graphs.
The keys are graph names. Their values are dictionaries of the graphs’ attributes’ new values, with
None
for deleted keys. Also in those graph dictionaries are special keys ‘node_val’ and ‘edge_val’ describing changes to node and edge attributes, and ‘nodes’ and ‘edges’ full of booleans indicating whether a node or edge exists.
-
get_graph
(name)[source]¶ Return a graph previously created with
new_graph
,new_digraph
,new_multigraph
, ornew_multidigraph
-
get_turn_delta
(branch=None, turn=None, tick_from=0, tick_to=None)[source]¶ Get a dictionary describing changes made on a given turn.
If
tick_to
is not supplied, report all changes aftertick_from
(default 0).The keys are graph names. Their values are dictionaries of the graphs’ attributes’ new values, with
None
for deleted keys. Also in those graph dictionaries are special keys ‘node_val’ and ‘edge_val’ describing changes to node and edge attributes, and ‘nodes’ and ‘edges’ full of booleans indicating whether a node or edge exists.
-
is_parent_of
(parent, child)[source]¶ Return whether
child
is a branch descended fromparent
at any remove.
-
nbtt
()[source]¶ Increment the tick and return branch, turn, tick
Unless we’re viewing the past, in which case raise HistoryError.
Idea is you use this when you want to advance time, which you can only do once per branch, turn, tick.
-
new_digraph
(name, data=None, **attr)[source]¶ Return a new instance of type DiGraph, initialized with the given data if provided.
-
new_graph
(name, data=None, **attr)[source]¶ Return a new instance of type Graph, initialized with the given data if provided.
-
new_multidigraph
(name, data=None, **attr)[source]¶ Return a new instance of type MultiDiGraph, initialized with the given data if provided.
-
new_multigraph
(name, data=None, **attr)[source]¶ Return a new instance of type MultiGraph, initialized with the given data if provided.
-
node_cls
¶ alias of
allegedb.graph.Node
-
plan
()[source]¶ A context manager for ‘hypothetical’ edits.
Start a block of code like:
``` with orm.plan():
…and any changes you make to the world state within that block will be ‘plans,’ meaning that they are used as defaults. The world will obey your plan unless you make changes to the same entities outside of the plan, in which case the world will obey those, and cancel any future plan.
New branches cannot be started within plans.
-
query_engine_cls
¶ alias of
allegedb.query.QueryEngine
-
-
class
allegedb.
PlanningContext
(orm)[source]¶ A context manager for ‘hypothetical’ edits.
Start a block of code like:
``` with orm.plan():
…and any changes you make to the world state within that block will be ‘plans,’ meaning that they are used as defaults. The world will obey your plan unless you make changes to the same entities outside of the plan, in which case the world will obey those, and cancel any future plan.
New branches cannot be started within plans.
-
class
allegedb.
TimeSignal
(engine)[source]¶ Acts like a list of
[branch, turn]
for the most part.You can set these to new values, or even replace them with a whole new
[branch, turn]
if you wish. It’s even possible to use the strings'branch'
or'turn'
in the place of indices, but at that point you might prefer to setengine.branch
orengine.turn
directly.This is a Signal, so pass a function to the connect(…) method and it will be called whenever the time changes. Not when the tick changes, though. If you really need something done whenever the tick changes, override the _set_tick method of
allegedb.ORM
.
-
class
allegedb.
TimeSignalDescriptor
[source]¶ Acts like a list of
[branch, turn]
for the most part.You can set these to new values, or even replace them with a whole new
[branch, turn]
if you wish. It’s even possible to use the strings'branch'
or'turn'
in the place of indices, but at that point you might prefer to setengine.branch
orengine.turn
directly.This is a Signal, so pass a function to the connect(…) method and it will be called whenever the time changes. Not when the tick changes, though. If you really need something done whenever the tick changes, override the _set_tick method of
allegedb.ORM
.
-
allegedb.
setedge
(delta, is_multigraph, graph, orig, dest, idx, exists)[source]¶ Change a delta to say that an edge was created or deleted
-
allegedb.
setedgeval
(delta, is_multigraph, graph, orig, dest, idx, key, value)[source]¶ Change a delta to say that an edge stat was set to a certain value
-
allegedb.
setgraphval
(delta, graph, key, val)[source]¶ Change a delta to say that a graph stat was set to a certain value
cache¶
Classes for in-memory storage and retrieval of historical graph data.
-
class
allegedb.cache.
Cache
(db)[source]¶ A data store that’s useful for tracking graph revisions.
-
branches
= None¶ A less structured alternative to
keys
.For when you already know the entity and the key within it, but still need to iterate through history to find the value.
-
contains_entity
(*args)¶ Check if an entity has a key at the given time, if entity specified.
Otherwise check if the entity exists.
-
contains_entity_key
(*args)¶ Check if an entity has a key at the given time, if entity specified.
Otherwise check if the entity exists.
-
contains_entity_or_key
(*args)[source]¶ Check if an entity has a key at the given time, if entity specified.
Otherwise check if the entity exists.
-
contains_key
(*args)¶ Check if an entity has a key at the given time, if entity specified.
Otherwise check if the entity exists.
-
count_entities
(*args, forward=None)¶ Return the number of keys an entity has, if you specify an entity.
Otherwise return the number of entities.
-
count_entities_or_keys
(*args, forward=None)[source]¶ Return the number of keys an entity has, if you specify an entity.
Otherwise return the number of entities.
-
count_entity_keys
(*args, forward=None)¶ Return the number of keys an entity has, if you specify an entity.
Otherwise return the number of entities.
-
count_keys
(*args, forward=None)¶ Return the number of keys an entity has, if you specify an entity.
Otherwise return the number of entities.
-
iter_entities
(*args, forward=None)¶ Iterate over the keys an entity has, if you specify an entity.
Otherwise iterate over the entities themselves, or at any rate the tuple specifying which entity.
-
iter_entities_or_keys
(*args, forward=None)[source]¶ Iterate over the keys an entity has, if you specify an entity.
Otherwise iterate over the entities themselves, or at any rate the tuple specifying which entity.
-
iter_entity_keys
(*args, forward=None)¶ Iterate over the keys an entity has, if you specify an entity.
Otherwise iterate over the entities themselves, or at any rate the tuple specifying which entity.
-
iter_keys
(*args, forward=None)¶ Iterate over the keys an entity has, if you specify an entity.
Otherwise iterate over the entities themselves, or at any rate the tuple specifying which entity.
-
keycache
= None¶ Keys an entity has at a given turn and tick.
-
keys
= None¶ Cache of entity data keyed by the entities themselves.
That means the whole tuple identifying the entity is the top-level key in this cache here. The second-to-top level is the key within the entity.
Deeper layers of this cache are keyed by branch, turn, and tick.
-
load
(data, validate=False, cb=None)[source]¶ Add a bunch of data. It doesn’t need to be in chronological order.
With
validate=True
, raise ValueError if this results in an incoherent cache.If a callable
cb
is provided, it will be called with each row. It will also be passed myvalidate
argument.
-
parents
= None¶ Entity data keyed by the entities’ parents.
An entity’s parent is what it’s contained in. When speaking of a node, this is its graph. When speaking of an edge, the parent is usually the graph and the origin in a pair, though for multigraphs the destination might be part of the parent as well.
Deeper layers of this cache are keyed by branch and revision.
-
presettings
= None¶ The values prior to
entity[key] = value
operations performed on some turn
-
retrieve
(*args)[source]¶ Get a value previously .store(…)’d.
Needs at least five arguments. The -1th is the tick within the turn you want, the -2th is that turn, the -3th is the branch, and the -4th is the key. All other arguments identify the entity that the key is in.
-
settings
= None¶ All the
entity[key] = value
operations that were performed on some turn
-
shallowest
= None¶ A dictionary for plain, unstructured hinting.
-
store
(*args, planning=None, forward=None)[source]¶ Put a value in various dictionaries for later .retrieve(…).
Needs at least five arguments, of which the -1th is the value to store, the -2th is the tick to store it at, the -3th is the turn to store it in, the -4th is the branch the revision is in, the -5th is the key the value is for, and the remaining arguments identify the entity that has the key, eg. a graph, node, or edge.
With
planning=True
, you will be permitted to alter “history” that takes place after the last non-planning moment of time, without much regard to consistency. Otherwise, contradictions will be handled by deleting everything after the present moment.
-
-
class
allegedb.cache.
EdgesCache
(db)[source]¶ A cache for remembering whether edges exist at a given time.
-
count_predecessors
(graph, dest, branch, turn, tick, *, forward=None)[source]¶ Return the number of predecessors from a given destination node at a given time.
-
count_successors
(graph, orig, branch, turn, tick, *, forward=None)[source]¶ Return the number of successors to a given origin node at a given time.
-
has_predecessor
(graph, dest, orig, branch, turn, tick)[source]¶ Return whether an edge connects the destination to the origin at the given time.
-
has_successor
(graph, orig, dest, branch, turn, tick)[source]¶ Return whether an edge connects the origin to the destination at the given time.
-
-
class
allegedb.cache.
FuturistWindowDict
(data=None)[source]¶ A WindowDict that does not let you rewrite the past.
-
class
allegedb.cache.
NodesCache
(db)[source]¶ A cache for remembering whether nodes exist at a given time.
-
class
allegedb.cache.
PickyDefaultDict
(type=<class 'object'>, args_munger=<function _default_args_munger>, kwargs_munger=<function _default_kwargs_munger>)[source]¶ A
defaultdict
alternative that requires values of a specific type.Pass some type object (such as a class) to the constructor to specify what type to use by default, which is the only type I will accept.
Default values are constructed with no arguments by default; supply
args_munger
and/orkwargs_munger
to override this. They take argumentsself
and the unused key being looked up.
-
class
allegedb.cache.
StructuredDefaultDict
(layers, type=<class 'object'>, args_munger=<function _default_args_munger>, kwargs_munger=<function _default_kwargs_munger>)[source]¶ A
defaultdict
-like class that expects values stored at a specific depth.Requires an integer to tell it how many layers deep to go. The innermost layer will be
PickyDefaultDict
, which will take thetype
,args_munger
, andkwargs_munger
arguments supplied to my constructor.
-
class
allegedb.cache.
TurnDict
(data=None)[source]¶ -
cls
¶ alias of
FuturistWindowDict
-
graph¶
allegedb’s special implementations of the NetworkX graph objects
-
class
allegedb.graph.
AbstractSuccessors
(container, orig)[source]¶ -
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
class
allegedb.graph.
AllegedGraph
(db, name, data=None, **attr)[source]¶ Class giving the graphs those methods they share in common.
-
clear
()[source]¶ Remove all nodes and edges from the graph.
Unlike the regular networkx implementation, this does not remove the graph’s name. But all the other graph, node, and edge attributes go away.
-
graph_map_cls
¶ alias of
GraphMapping
-
node_map_cls
¶ alias of
GraphNodeMapping
-
-
class
allegedb.graph.
AllegedMapping
[source]¶ Common amenities for mappings
-
class
allegedb.graph.
DiGraph
(db, name, data=None, **attr)[source]¶ A version of the networkx.DiGraph class that stores its state in a database.
-
add_edge
(u, v, attr_dict=None, **attr)[source]¶ Version of add_edge that only writes to the database once
-
add_edges_from
(ebunch, attr_dict=None, **attr)[source]¶ Version of add_edges_from that only writes to the database once
-
adj_cls
¶ alias of
DiGraphSuccessorsMapping
-
pred_cls
¶ alias of
DiGraphPredecessorsMapping
-
-
class
allegedb.graph.
DiGraphPredecessorsMapping
(graph)[source]¶ Mapping for Predecessors instances, which map to Edges that end at the dest provided to this
-
class
allegedb.graph.
Edge
(graph, orig, dest, idx=0)[source]¶ Mapping for edge attributes
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
exception
allegedb.graph.
EntityCollisionError
[source]¶ For when there’s a discrepancy between the kind of entity you’re creating and the one by the same name
-
class
allegedb.graph.
Graph
(db, name, data=None, **attr)[source]¶ A version of the networkx.Graph class that stores its state in a database.
-
adj_cls
¶ alias of
GraphSuccessorsMapping
-
-
class
allegedb.graph.
GraphEdgeMapping
(graph)[source]¶ Provides an adjacency mapping and possibly a predecessor mapping for a graph.
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
class
allegedb.graph.
GraphMapping
(graph)[source]¶ Mapping for graph attributes
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
class
allegedb.graph.
GraphNodeMapping
(graph)[source]¶ Mapping for nodes in a graph
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
class
allegedb.graph.
GraphSuccessorsMapping
(graph)[source]¶ Mapping for Successors (itself a MutableMapping)
-
class
allegedb.graph.
MultiDiGraph
(db, name, data=None, **attr)[source]¶ A version of the networkx.MultiDiGraph class that stores its state in a database.
-
add_edge
(u, v, key=None, attr_dict=None, **attr)[source]¶ Version of add_edge that only writes to the database once.
-
adj_cls
¶ alias of
MultiDiGraphSuccessorsMapping
-
pred_cls
¶ alias of
MultiDiGraphPredecessorsMapping
-
-
class
allegedb.graph.
MultiDiGraphPredecessorsMapping
(graph)[source]¶ Version of DiGraphPredecessorsMapping for multigraphs
-
class
allegedb.graph.
MultiEdges
(graph, orig, dest)[source]¶ Mapping of Edges between two nodes
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
-
class
allegedb.graph.
MultiGraph
(db, name, data=None, **attr)[source]¶ A version of the networkx.MultiGraph class that stores its state in a database.
-
adj_cls
¶ alias of
MultiGraphSuccessorsMapping
-
-
class
allegedb.graph.
MultiGraphSuccessorsMapping
(graph)[source]¶ Mapping of Successors that map to MultiEdges
-
class
allegedb.graph.
Node
(graph, node)[source]¶ Mapping for node attributes
-
db
¶ attrgetter(attr, …) –> attrgetter object
Return a callable object that fetches the given attribute(s) from its operand. After f = attrgetter(‘name’), the call f(r) returns r.name. After g = attrgetter(‘name’, ‘date’), the call g(r) returns (r.name, r.date). After h = attrgetter(‘name.first’, ‘name.last’), the call h(r) returns (r.name.first, r.name.last).
-
query¶
Wrapper to run SQL queries in a lightly abstracted way, such that code that’s more to do with the queries than with the data per se doesn’t pollute the other files so much.
-
class
allegedb.query.
GlobalKeyValueStore
(qe)[source]¶ A dict-like object that keeps its contents in a table.
Mostly this is for holding the current branch and revision.
-
class
allegedb.query.
QueryEngine
(dbstring, connect_args, alchemy, pack=None, unpack=None)[source]¶ Wrapper around either a DBAPI2.0 connection or an Alchemist. Provides methods to run queries using either.
-
edge_val_del
(graph, orig, dest, idx, key, branch, turn, tick)[source]¶ Declare that the key no longer applies to this edge, as of this branch and revision.
-
edge_val_set
(graph, orig, dest, idx, key, branch, turn, tick, value)[source]¶ Set this key of this edge to this value.
-
exist_edge
(graph, orig, dest, idx, branch, turn, tick, extant)[source]¶ Declare whether or not this edge exists.
-
exist_node
(graph, node, branch, turn, tick, extant)[source]¶ Declare that the node exists or doesn’t.
Inserts a new record or updates an old one, as needed.
-
global_set
(key, value)[source]¶ Set
key
tovalue
globally (not at any particular branch or revision)
-
new_branch
(branch, parent, parent_turn, parent_tick)[source]¶ Declare that the
branch
is descended fromparent
atparent_turn
,parent_tick
-
node_val_del
(graph, node, key, branch, turn, tick)[source]¶ Delete a key from a node at a specific branch and revision
-
node_val_set
(graph, node, key, branch, turn, tick, value)[source]¶ Set a key-value pair on a node at a specific branch and revision
-
wrap¶
Wrapper classes to let you store mutable data types in the allegedb ORM
-
class
allegedb.wrap.
DictWrapper
(getter, setter, outer, key)[source]¶ A dictionary synchronized with a serialized field.
This is meant to be used in allegedb entities (graph, node, or edge), for when the user stores a dictionary in them.
-
class
allegedb.wrap.
ListWrapper
(getter, setter, outer, key)[source]¶ A list synchronized with a serialized field.
This is meant to be used in allegedb entities (graph, node, or edge), for when the user stores a list in them.
-
class
allegedb.wrap.
SetWrapper
(getter, setter, outer, key)[source]¶ A set synchronized with a serialized field.
This is meant to be used in allegedb entities (graph, node, or edge), for when the user stores a set in them.