Source code for owmeta_core
# -*- coding: utf-8 -*-
"""
.. _owm_module:
owmeta_core
===========
owmeta-core is a platform for sharing relational data over the internet.
"""
from __future__ import print_function
__version__ = '0.14.0.dev0'
__author__ = 'OpenWorm.org authors and contributors'
import sys
import os
import logging
import uuid
from os.path import join as pth_join
from contextlib import contextmanager
LOGGER = logging.getLogger(__name__)
LOGGER.addHandler(logging.NullHandler())
BASE_SCHEMA_URL = 'http://schema.openworm.org/2020/07'
BASE_DATA_URL = 'http://data.openworm.org'
# The c extensions are incompatible with our code...
os.environ['WRAPT_DISABLE_EXTENSIONS'] = '1'
OWMETA_PROFILE_DIR = os.environ.get('OWMETA_PROFILE_DIR', pth_join('~', '.owmeta'))
'''
Base directory in the user's profile for owmeta (e.g., shared configuration, bundle cache)
'''
from .configure import Configurable
from .context import Context, ClassContext
__all__ = [
"get_data",
"disconnect",
"connect",
"Configurable",
]
DEF_CTX = Context()
RDF_CONTEXT = ClassContext(ident='http://www.w3.org/1999/02/22-rdf-syntax-ns',
base_namespace='http://www.w3.org/1999/02/22-rdf-syntax-ns#')
RDFS_CONTEXT = ClassContext(ident='http://www.w3.org/2000/01/rdf-schema',
imported=(RDF_CONTEXT,),
base_namespace='http://www.w3.org/2000/01/rdf-schema#')
BASE_CONTEXT = ClassContext(imported=(RDFS_CONTEXT,),
ident=BASE_SCHEMA_URL,
base_namespace=BASE_SCHEMA_URL + '#')
def get_data(path):
# get a resource from the installed package location
from sysconfig import get_path
from pkgutil import get_loader
from glob import glob
package_paths = glob(os.path.join(get_path('platlib'), '*'))
sys.path = package_paths + sys.path
installed_package_root = os.path.dirname(get_loader('owmeta_core').get_filename())
sys.path = sys.path[len(package_paths):]
filename = os.path.join(installed_package_root, path)
return filename
[docs]class Connection(object):
'''
Connection to an owmeta_core database. Essentially, wraps a `~owmeta_core.data.Data`
object.
'''
def __init__(self, configFile=None, conf=None, mapper=None):
"""
Load desired configuration and open the database
Parameters
----------
configFile : str, optional
The configuration file for owmeta_core.
conf : dict, .Configuration, .Data, optional
A configuration object for the connection. Takes precedence over `configFile`
mapper : owmeta_core.mapper.Mapper
Provides the mapper for this connection
Returns
-------
Connection
connection wrapping the configuration
"""
from .data import Data, DatabaseConflict
from .mapper import Mapper
if configFile is not None and not isinstance(configFile, str):
conf = configFile
configFile = None
if conf:
if not isinstance(conf, Data):
conf = Data(conf)
elif configFile:
conf = Data.open(configFile)
else:
conf = Data({"rdf.source": "default"})
try:
conf.init_database()
except DatabaseConflict as e:
raise ConnectionFailError(e, "It looks like a connection is already opened by a living process") from e
except Exception as e:
raise ConnectionFailError(e) from e
logging.getLogger('owmeta_core').info("Connected to database")
self.conf = conf
if mapper is None:
mapper = Mapper(conf=conf)
self._context = Context(conf=self.conf, mapper=mapper)
self.identifier = str(uuid.uuid4())
'''
Identifier for this connection.
Primarily, so that this Connection can be passed to contextualize for a Context
'''
self.mapper = mapper
@property
def rdf(self):
return self.conf['rdf.graph']
@property
def transaction_manager(self):
'''
`~transaction.TransactionManager` for the connection
'''
from .data import TRANSACTION_MANAGER_KEY
return self.conf[TRANSACTION_MANAGER_KEY]
[docs] @contextmanager
def transaction(self):
'''
Context manager that executes the enclosed code in a transaction and then closes
the connection. Provides the connection for binding with ``as``.
'''
with self, self.transaction_manager:
yield self
[docs] def disconnect(self):
'''
Close the database and stop listening to module loaders
'''
self.conf.closeDatabase()
def __enter__(self):
return self
def __exit__(self, *args):
self.disconnect()
def __call__(self, target):
'''
Contextualize the given `Context`
'''
if target is not None:
return target.contextualize(self._context)
else:
raise TypeError('Connections can only contextualize owmeta_core.context.Context'
' or subclasses thereof. Received %s' % target)
def __str__(self):
conf = self.conf
return 'Connection:{source}:{store_conf}'.format(
source=conf.get('rdf.source'),
store_conf=conf.get('rdf.store_conf', 'default'))
[docs]def disconnect(c=None):
"""
Close the connection.
Deprecated: Just calls disconnect on the given connection
"""
import warnings
warnings.warn(
'owmeta_core.disconnect() is redundant:'
' it just calls disconnect() on the given connection',
DeprecationWarning,
stacklevel=2)
if c:
c.disconnect()
[docs]class ConnectionFailError(Exception):
'''
Thrown when a connection fails
'''
def __init__(self, cause, *args):
if args:
super(ConnectionFailError, self).__init__('owmeta_core connection failed: {}. {}'.format(cause, *args))
else:
super(ConnectionFailError, self).__init__('owmeta_core connection failed: {}'.format(cause))
connect = Connection