#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint: disable-msg=C0103
################################################################################
# Copyright (c) 2006-2017 Franz Inc.
# All rights reserved. This program and the accompanying materials are
# made available under the terms of the MIT License which accompanies
# this distribution, and is available at http://opensource.org/licenses/MIT
################################################################################
from __future__ import absolute_import
from __future__ import with_statement
from __future__ import unicode_literals
from future.builtins import object
from past.builtins import map, unicode, basestring
from franz.miniclient.request import wrap_callback
from franz.openrdf.util.contexts import output_to
from .repositoryresult import RepositoryResult
from ..exceptions import IllegalOptionException, IllegalArgumentException
from ..model import Statement, Value, URI
from ..model.literal import RangeLiteral, GeoCoordinate, GeoSpatialRegion, GeoBox, GeoCircle, GeoPolygon, Literal
from ..query.dataset import ALL_CONTEXTS, MINI_NULL_CONTEXT
from ..query.query import Query, TupleQuery, UpdateQuery, GraphQuery, BooleanQuery, QueryLanguage
from ..rio.rdfformat import RDFFormat
from ..util import uris
from collections import namedtuple
import copy, sys, warnings
from contextlib import contextmanager
if sys.version_info[0] > 2:
# Hack for isinstance checks
import io
file = io.IOBase
[docs]class RepositoryConnection(object):
"""
The RepositoryConnection class is the main interface for updating data
in and performing queries on a
:class:`~franz.openrdf.repository.repository.Repository`. By default, a
RespositoryConnection is in autoCommit mode, meaning that each
operation corresponds to a single transaction on the underlying triple
store. autoCommit can be switched off, in which case it is up to the
user to handle transaction commit/rollback. Note that care should be
taken to always properly close a RepositoryConnection after one is
finished with it, to free up resources and avoid unnecessary locks.
Note that concurrent access to the same connection object is explicitly
forbidden. The client must perform its own synchronization to ensure
non-concurrent access.
Several methods take a *vararg* argument that optionally specifies a
set of contexts on which the method should operate. (A context is
the URI of a subgraph.) Note that a *vararg* parameter is optional, it
can be completely left out of the method call, in which case a method
either operates on a provided statement's context (if one of the method
parameters is a statement or collection of statements), or operates on
the repository as a whole, completely ignoring context. A *vararg*
argument may also be ``None``, meaning that the method operates on
those statements which have no associated context only.
"""
[docs] def __init__(self, repository, close_repo=False):
"""
Call through :meth:`~franz.openrdf.repository.repository.Repository.getConnection`.
:param repository: Repository to connect to.
:type repository: Repository
:param close_repo: If ``True`` shutdown the repository when this connection is closed.
The default is ``False``.
:type close_repo: bool
"""
self.repository = repository
self.mini_repository = repository.mini_repository
self.is_closed = False
self._add_commit_size = None
self._close_repo = close_repo
self.is_session_active = False
[docs] def getSpec(self):
"""
Get the session specification string for this repository.
:return: Spec string suitable for use with
:meth:`~franz.openrdf.sail.allegrographserver.AllegroGraphServer.openSession`.
"""
return self.repository.getSpec()
def _get_mini_repository(self):
return self.mini_repository
[docs] def getValueFactory(self):
"""
Get the :class:`.ValueFactory` associated with this repository.
Note that it is recommended to use methods defined in :class:`RepositoryConnection`
instead of a value factory. The latter is only provided for RDF4J compatibility.
:return: A value factory.
:rtype: ValueFactory
"""
return self.repository.getValueFactory()
[docs] def close(self):
"""
Close the connection. This also closes the session if it is active.
It is safe to call this on a connection that has already been closed.
Note that using ``with`` is the preferred way to manage connections.
"""
if not self.is_closed:
self.closeSession()
self.is_closed = True
if self._close_repo:
self.repository.shutDown()
[docs] def setAddCommitSize(self, triple_count):
"""
Set the value of :attr:`.add_commit_size`.
:param triple_count: Value of :attr:`.add_commit_size`.
"""
if not triple_count or triple_count < 0:
self._add_commit_size = None
else:
self._add_commit_size = int(triple_count)
[docs] def getAddCommitSize(self):
"""
Get the current value of :attr:`.add_commit_size`.
:return: Value of :attr:`.add_commit_size`.
"""
return self._add_commit_size
add_commit_size = property(
getAddCommitSize, setAddCommitSize,
doc="""The threshold for commit size during triple add operations.
Set to 0 (zero) or None to clear size-based autocommit behavior.
When set to an integer triple_count > 0, a commit will occur every
triple_count triples added and at the end of the triples being added.""")
[docs] def prepareQuery(self, queryLanguage, queryString, baseURI=None):
"""
Embed 'queryString' into a query object which can be
executed against the RDF storage.
"""
query = Query(queryLanguage, queryString, baseURI)
query.setConnection(self)
return query
[docs] def prepareTupleQuery(self, queryLanguage=QueryLanguage.SPARQL,
query=None, baseURI=None, queryString=None):
"""
Parse ``query`` into a tuple query object which can be
executed against the triple stroe.
:param queryLanguage: Either ``QueryLanguage.SPARQL`` or ``QueryLanguage.PROLOG``.
:type queryLanguage: QueryLanguage
:param query: The query string (must contain a ``SELECT`` query).
:type query: string
:param baseURI: An optional base used to resolve relative URIs in the query.
:type baseURI: string|URI
:param queryString: Legacy name of the ``query`` parameter.
:type queryString: string
:return: A query object.
:rtype: TupleQuery
"""
query = TupleQuery(queryLanguage, query or queryString, baseURI=baseURI)
query.setConnection(self)
return query
[docs] def prepareUpdate(self, queryLanguage=QueryLanguage.SPARQL,
query=None, baseURI=None, queryString=None):
"""
Parse ``query`` into an update query object which can be
executed against the triple store.
:param queryLanguage: Either ``QueryLanguage.SPARQL`` or ``QueryLanguage.PROLOG``.
:type queryLanguage: QueryLanguage
:param query: The query string (must contain an ``UPDATE`` query).
:type query: string
:param baseURI: An optional base used to resolve relative URIs in the query.
:type baseURI: string|URI
:param queryString: Legacy name of the ``query`` parameter.
:type queryString: string
:return: A query object.
:rtype: UpdateQuery
"""
query = UpdateQuery(queryLanguage, query or queryString,
baseURI=baseURI)
query.setConnection(self)
return query
[docs] def prepareGraphQuery(self, queryLanguage=QueryLanguage.SPARQL,
query=None, baseURI=None, queryString=None):
"""
Parse ``query`` into a graph query object which can be
executed against the triple store.
:param queryLanguage: Either ``QueryLanguage.SPARQL`` or ``QueryLanguage.PROLOG``.
:type queryLanguage: QueryLanguage
:param query: The query string (must be a``CONSTRUCT`` or ``DESCRIBE`` query).
:type query: string
:param baseURI: An optional base used to resolve relative URIs in the query.
:type baseURI: string|URI
:param queryString: Legacy name of the ``query`` parameter.
:type queryString: string
:return: A query object.
:rtype: GraphQuery
"""
query = GraphQuery(queryLanguage, query or queryString, baseURI=baseURI)
query.setConnection(self)
return query
[docs] def prepareBooleanQuery(self, queryLanguage=QueryLanguage.SPARQL,
query=None, baseURI=None, queryString=None):
"""
Parse ``query`` into a boolean query object which can be
executed against the triple store.
:param queryLanguage: Either ``QueryLanguage.SPARQL`` or ``QueryLanguage.PROLOG``.
:type queryLanguage: QueryLanguage
:param query: The query string (must contain an ``ASK`` query).
:type query: string
:param baseURI: An optional base used to resolve relative URIs in the query.
:type baseURI: string|URI
:param queryString: Legacy name of the ``query`` parameter.
:type queryString: string
:return: A query object.
:rtype: BooleanQuery
"""
query = BooleanQuery(queryLanguage, query or queryString,
baseURI=baseURI)
query.setConnection(self)
return query
[docs] def getContextIDs(self):
"""
Return a list of context resources, one for each context referenced by a quad in
the triple store. Note that the default context will not be included in the result.
:return: A list of contexts (as :class:`URI` objects).
:rtype: list[URI]
"""
contexts = []
for cxt in self._get_mini_repository().listContexts():
contexts.append(self.createURI(cxt))
return contexts
[docs] def size(self, contexts=ALL_CONTEXTS):
"""
Returns the number of (explicit) statements that are in the specified
contexts in this repository.
:param contexts: List of contexts (graph URIs) to count the statements in.
By default statements in all graphs will be counted.
:type contexts: Iterable[string|URI]
"""
cxts = self._contexts_to_ntriple_contexts(contexts, False)
if cxts == ALL_CONTEXTS or not cxts:
return self._get_mini_repository().getSize()
elif len(cxts) == 1:
return self._get_mini_repository().getSize(cxts[0])
else:
total = 0
for cxt in cxts:
total += self._get_mini_repository().getSize(cxt)
return total
[docs] def isEmpty(self):
"""
Return ``True`` if this repository does not contain any (explicit) statements.
"""
return self.size() == 0
def _context_to_ntriples(self, context, none_is_mini_null=False):
if context is None:
return MINI_NULL_CONTEXT if none_is_mini_null else None
if context == MINI_NULL_CONTEXT:
return MINI_NULL_CONTEXT
if context == 'null':
return MINI_NULL_CONTEXT
if context:
return context if isinstance(context, basestring) else context.toNTriples()
if none_is_mini_null:
return MINI_NULL_CONTEXT
return None
def _contexts_to_ntriple_contexts(self, contexts, none_is_mini_null=False):
"""
Do three transformations here. Convert from context object(s) to
context strings (angle brackets).
Also, convert singleton context to list of contexts, and convert
ALL_CONTEXTS to None.
And, convert None context to 'null'.
"""
if contexts == ALL_CONTEXTS: ## or contexts is None:
## consistency would dictate that None => [None], but this would
## likely surprise users, so we don't do that:
cxts = None
elif contexts is None:
if none_is_mini_null: cxts = [MINI_NULL_CONTEXT]
else: cxts = None
elif contexts == 'null':
cxts = [MINI_NULL_CONTEXT]
elif isinstance(contexts, (list, tuple)):
cxts = [self._context_to_ntriples(c, none_is_mini_null=True) for c in contexts]
else:
cxts = [self._context_to_ntriples(contexts, none_is_mini_null=True)]
return cxts
def _convert_term_to_mini_term(self, term, predicate_for_object=None):
"""
If 'term' is a Value, convert it to an ntriples string. If its a Python
term, do likewise
If 'term' is a CompoundLiteral or a list or tuple, separate out the second
value, ntriplize it, and return a binary tuple.
TODO: FIGURE OUT HOW COORDINATE PAIRS WILL WORK HERE
"""
if isinstance(term, GeoSpatialRegion): return term
factory = self.getValueFactory()
if isinstance(term, GeoCoordinate):
geoType = term.geoType
miniGeoType = geoType._getMiniGeoType()
if geoType.system == GeoType.Cartesian:
return self._get_mini_repository().createCartesianGeoLiteral(miniGeoType, term.xcoor, term.ycoor)
elif geoType.system == GeoType.Spherical:
unit = term.unit or term.geoType.unit
return self._get_mini_repository().createSphericalGeoLiteral(miniGeoType, term.xcoor, term.ycoor, unit=unit)
else:
raise IllegalOptionException("Unsupported geo coordinate system", geoType.system)
if isinstance(term, RangeLiteral):
beginTerm = term.getLowerBound()
endTerm = term.getUpperBound()
return (self._to_ntriples(beginTerm), self._to_ntriples(endTerm))
elif isinstance(term, (tuple, list)):
return [self._convert_term_to_mini_term(t, predicate_for_object=predicate_for_object) for t in term]
## OBSOLETE: CONVERT LIST TO RANGE LITERAL:
elif isinstance(term, (tuple, list)):
factory = self.getValueFactory()
beginTerm = factory.object_position_term_to_openrdf_term(term[0])
factory.validateRangeConstant(beginTerm, predicate_for_object)
endTerm = factory.object_position_term_to_openrdf_term(term[1])
factory.validateRangeConstant(endTerm, predicate_for_object)
return (self._to_ntriples(beginTerm), self._to_ntriples(endTerm))
## END OBSOLETE
elif predicate_for_object:
term = factory.object_position_term_to_openrdf_term(term, predicate=predicate_for_object)
return self._to_ntriples(term)
else:
return self._to_ntriples(term)
[docs] def getStatements(self, subject=None, predicate=None, object=None, contexts=ALL_CONTEXTS, includeInferred=False,
limit=None, offset=None, tripleIDs=False, output=None, output_format=RDFFormat.NQX):
"""
Get all statements with a specific subject, predicate and/or
object from the repository. The result is optionally
restricted to the specified set of named contexts (graphs).
Return a :class:`RepositoryResult` object that can be used to
iterate over the resulting statements and filter out
duplicates if desired. Alternatively one can write the
results to a file or stream using the ``output`` parameter.
:param subject: Subject value or ``None`` (no subject filtering).
:type subject: Value
:param predicate: Predicate value or ``None`` (no predicatefiltering).
:type predicate: URI
:param object: Object value or ``None`` (no object filtering).
:type object: Value
:param contexts: An optional list of graphs to retrieve the
statements from.
By default statements are taken from all graphs.
:type contexts: URI|string|Iterable[URI|string]
:param includeInferred: If ``True``, include triples inferred through
RDFS++ reasoning.
The default is ``False``.
:type includeInferred: bool
:param limit: Max number of statements to retrieve (optional).
:type limit: int
:param offset: Used in conjunction with ``limit`` to return results
starting from the nth statement.
:type offset: int
:param tripleIDs: If ``True`` the id field will be filled
in the returned statements.
:param output: File path or a file-like object to write
the result to.
:type output: str|file
:param output_format: Serialization format for ``output``.
:type output_format: RDFFormat
:return: An iterator over the resulting statements
or ``None`` (if ``output`` is used).
:rtype: RepositoryResult
"""
# note: so with tripleIDs we'll get triples that are quads consisting of five elements.
with output_to(output) as out_file:
callback = None if output is None else out_file.write
accept = None if output is None else RDFFormat.mime_type_for_format(output_format)
subj = self._convert_term_to_mini_term(subject)
pred = self._convert_term_to_mini_term(predicate)
obj = self._convert_term_to_mini_term(object, predicate)
cxt = self._contexts_to_ntriple_contexts(contexts)
if isinstance(object, GeoSpatialRegion):
if cxt is not None and cxt != ALL_CONTEXTS:
raise ValueError('Geospatial queries cannot be limited to a context.')
return self._getStatementsInRegion(subj, pred, obj, limit=limit, offset=offset,
accept=accept, callback=callback)
else:
result = self._get_mini_repository().getStatements(
subj, pred, obj, cxt,
infer=includeInferred, limit=limit, offset=offset, tripleIDs=tripleIDs,
accept=accept, callback=callback)
if output is None:
return RepositoryResult(result, tripleIDs=tripleIDs)
else:
return None
[docs] def getStatementsById(self, ids, output=None, output_format=RDFFormat.NQX):
"""
Return all statements whose triple ID matches an ID in the list 'ids'.
:param ids: List of statement ids.
:type ids: Iterable[int]
:param output: File path or a file-like object to write
the result to.
:type output: str|file
:param output_format: Serialization format for ``output``.
:type output_format: RDFFormat
:return: An iterator over requested statements
or ``None`` (if ``output`` is used).
:rtype: RepositoryResult
"""
with output_to(output) as out_file:
callback = None if output is None else out_file.write
accept = None if output is None else RDFFormat.mime_type_for_format(output_format)
result = self._get_mini_repository().getStatementsById(ids, accept=accept, callback=callback)
if output is None:
return RepositoryResult(result, tripleIDs=False)
else:
return False
def _getStatementsInRegion(self, subject, predicate, region, limit=None, offset=None, accept=None, callback=None):
geoType = region.geoType
miniGeoType = geoType._getMiniGeoType()
common_args = {
'limit': limit,
'offset': offset,
'accept': accept,
'callback': callback
}
if isinstance(region, GeoBox):
if geoType.system == GeoType.Cartesian:
stringTuples = self._get_mini_repository().getStatementsInsideBox(
miniGeoType, predicate, region.xMin, region.xMax, region.yMin, region.yMax,
**common_args)
elif geoType.system == GeoType.Spherical:
stringTuples = self._get_mini_repository().getStatementsInsideBox(
miniGeoType, predicate, region.yMin, region.yMax, region.xMin, region.xMax,
**common_args)
else:
raise ValueError('Unsupported coordinate system: %s' % geoType.system)
elif isinstance(region, GeoCircle):
if geoType.system == GeoType.Cartesian:
stringTuples = self._get_mini_repository().getStatementsInsideCircle(miniGeoType, predicate,
region.x, region.y, region.radius, **common_args)
elif geoType.system == GeoType.Spherical:
stringTuples = self._get_mini_repository().getStatementsHaversine(miniGeoType, predicate,
region.x, region.y, region.radius, unit=region.unit,
**common_args)
else:
raise ValueError('Unsupported coordinate system: %s' % geoType.system)
elif isinstance(region, GeoPolygon):
stringTuples = self._get_mini_repository().getStatementsInsidePolygon(miniGeoType, predicate,
self._convert_term_to_mini_term(region.getResource()),
**common_args)
else:
raise ValueError('Unsupported region type: %s' % type(region)) # can't happen
if callback is None:
return RepositoryResult(stringTuples, subjectFilter=subject)
else:
return None
# NOTE: 'format' shadows a built-in symbol but it is too late to change the public API
[docs] def add(self, arg0, arg1=None, arg2=None, contexts=None, base=None, format=None, serverSide=False):
"""
Calls :meth:`.addTriple`, :meth:`.addStatement`, or :meth:`.addFile`.
Best practice is to avoid ``add()`` and use :meth:`addTriple`, :meth:`addStatement`
or :meth:`addFile` instead.
:param arg0: May be a Statement or a filepath. If so, arg1 and arg2 default to None.
May also be the subject of a triple (in that case arg1 and arg2 must be
the predicate and the object respectively).
:type arg0: Statement|string|Value
:param arg1: Predicate of the new triple.
:type arg1: string|Value
:param arg2: Object of the new triple.
:type arg2: string|Value
:param contexts: Optional list of contexts (subgraph URIs), defaulting to None.
A context is the URI of a subgraph. If None, the triple(s) will
be added to the null context (the default or background graph).
:type contexts: Iterable[URI|string]
:param base: The baseURI to associate with loading a file. Defaults to ``None``.
If ``None`` the baseURI will be chosen by the server.
:type base: string
:param format: Either ``RDFFormat.NTRIPLES`` or ``RDFFormat.RDFXML``. Defaults to ``None``.
:type format: RDFFormat
:param serverSide: Indicates whether the filepath refers to a file on the client computer
or on the server. Defaults to ``False`` (i.e. client-side).
:type serverSide: bool
"""
if contexts and not isinstance(contexts, list):
contexts = [contexts]
if isinstance(arg0, (basestring, file)):
if contexts:
if len(contexts) > 1:
raise IllegalArgumentException("Only one context may be specified when loading from a file.")
context = contexts[0]
else:
context = None
return self.addFile(arg0, base=base, format=format, context=context, serverSide=serverSide)
elif isinstance(arg0, Value):
return self.addTriple(arg0, arg1, arg2, contexts=contexts)
elif isinstance(arg0, Statement):
return self.addStatement(arg0, contexts=contexts)
elif hasattr(arg0, '__iter__'):
for s in arg0:
self.addStatement(s, contexts=contexts)
else:
raise IllegalArgumentException("Illegal first argument to 'add'. Expected a Value, Statement, File, or string.")
# NOTE: 'format' shadows a built-in symbol but it is too late to change the public API
[docs] def addFile(self, filePath, base=None, format=None, context=None, serverSide=False, content_encoding=None):
"""
Loads a file into the triple store. Note that a file can be loaded into only one context.
:param filepath: Identifies the file to load.
:type filePath: string
:param context: An optional context URI (subgraph URI), defaulting to ``None``.
If ``None``, the triple(s) will be added to the null context
(the default or background graph).
:type context: URI|string|list[URI|string]
:param base: The baseURI to associate with loading a file. Defaults to ``None``.
If ``None`` the baseURI will be chosen by the server.
:type base: string
:param format: Either ``RDFFormat.NTRIPLES`` or ``RDFFormat.RDFXML``. Defaults to ``None``.
:type format: RDFFormat
:param serverSide: Indicates whether the filepath refers to a file on the client computer
or on the server. Defaults to ``False`` (i.e. client-side).
:type serverSide: bool
"""
if isinstance(context, (list, tuple)):
if len(context) > 1:
raise IllegalArgumentException("Multiple contexts passed to 'addFile': %s" % context)
context = context[0] if context else None
contextString = self._context_to_ntriples(context, none_is_mini_null=True)
fmt, ce = RDFFormat.format_for_file_name(filePath)
format = format or fmt
content_encoding = content_encoding or ce
self._get_mini_repository().loadFile(
filePath, format, context=contextString, serverSide=serverSide,
commitEvery=self.add_commit_size, baseURI=base,
content_encoding=content_encoding)
[docs] def addData(self, data, rdf_format=RDFFormat.TURTLE, base_uri=None, context=None):
"""
Adds data from a string to the repository.
:param data: Data to be added.
:type data: string
:param rdf_format: Data format - either a RDFFormat or a MIME type (string).
:type rdf_format: RDFFormat|str
:param base_uri: Base for resolving relative URIs.
If None (default), the URI will be chosen by the server.
:type base_uri: string
:param context: Graph to add the data to.
If None (default) the default graph will be used.
:type context: URI|string
"""
ctx = self._context_to_ntriples(context, none_is_mini_null=True)
self._get_mini_repository().loadData(
data, rdf_format, base_uri=base_uri, context=ctx)
[docs] def addTriple(self, subject, predicate, object, contexts=None):
"""
Add a single triple to the repository.
:param subject: Subject of the new triple.
:type subject: Value
:param predicate: Predicate of the new triple.
:type predicate: Value
:param object: Object of the new triple.
:type object: Value
:param contexts: List of contexts (graph URIs) to add the triple to.
Defaults to ``None``, which adds the statement to the
null context (the default or background graph).
:type contexts: Iterable[string|URI]
"""
obj = self.getValueFactory().object_position_term_to_openrdf_term(object, predicate=predicate)
cxts = self._contexts_to_ntriple_contexts(contexts, none_is_mini_null=True)
for cxt in cxts:
self._get_mini_repository().addStatement(self._to_ntriples(subject), self._to_ntriples(predicate),
self._convert_term_to_mini_term(obj), cxt)
def _to_ntriples(self, term):
"""
If 'term' is an OpenRDF term, convert it to a string. If it's already
a string, assume it's in ntriples format, and just pass it through.
If the term is None, return None.
Otherwise convert `term` to Literal and make a string from that.
"""
if term is None or isinstance(term, basestring):
return term
elif hasattr(term, 'toNTriples'):
return term.toNTriples()
else:
return Literal(term).toNTriples()
[docs] def addTriples(self, triples_or_quads, context=ALL_CONTEXTS, ntriples=False):
"""
Add the supplied triples or quads to this repository.
:param triples_or_quads: List of triples or quads. Each element can be
either a statement or a list or tuple of :class:`Value` objects
or strings.
:type triples_or_quads: Iterable[list[string|Value]|tuple[string|Value]]
:param context: Context (graph) to add the triples to. Default to null (the default graph).
:type context: string
:param ntriples: If ``True``, parts of the triples are assumed to be strings
in N-Triples format and are sent to the server without any
conversion.
:type ntriples: bool
"""
ntripleContexts = self._contexts_to_ntriple_contexts(context, none_is_mini_null=True)
quads = []
for q in triples_or_quads:
isQuad = len(q) == 4
quad = [None] * 4
if ntriples:
quad[0] = q[0]
quad[1] = q[1]
quad[2] = q[2]
quad[3] = q[3] if isQuad and q[3] else ntripleContexts
elif isinstance(quad, (list, tuple)):
predicate = q[1]
obj = self.getValueFactory().object_position_term_to_openrdf_term(q[2], predicate=predicate)
quad[0] = self._to_ntriples(q[0])
quad[1] = self._to_ntriples(predicate)
quad[2] = self._to_ntriples(obj)
quad[3] = self._to_ntriples(q[3]) if isQuad and q[3] else ntripleContexts
else: # must be a statement
predicate = q.getPredicate()
obj = self.getValueFactory().object_position_term_to_openrdf_term(q.getObject(), predicate=predicate)
quad[0] = self._to_ntriples(q.getSubject())
quad[1] = self._to_ntriples(predicate)
quad[2] = self._to_ntriples(obj)
quad[3] = self._to_ntriples(q.getContext()) if isQuad and q.getContext() else ntripleContexts
quads.append(quad)
self._get_mini_repository().addStatements(quads, commitEvery=self.add_commit_size)
[docs] def addStatement(self, statement, contexts=None):
"""
Add the supplied statement to the specified contexts in the repository.
:param statement: The statement to be added. Note that the ``context`` field is
ignored (use the ``contexts`` parameters instead).
:type statement: Statement
:param contexts: List of contexts (graph URIs) to add the statement to.
Defaults to ``None``, which adds the statement to the
null context (the default or background graph).
:type contexts: Iterable[string|URI]
"""
self.addTriple(statement.getSubject(), statement.getPredicate(), statement.getObject(),
contexts=contexts)
[docs] def remove(self, arg0, arg1=None, arg2=None, contexts=None):
"""
Call :meth:`removeTriples` or :meth:`removeStatement`.
Best practice is to avoid :meth:`remove` and use :meth:`removeTriples`
or :meth:`removeStatement` directly.
Note that ``context`` fields of statements passed to this method are ignored.
``arg0`` may be a :class:`Statement`. If so, then ``arg1`` and ``arg2`` default to None.
``arg0``, ``arg1``, and ``arg2`` may be the subject, predicate and object of a triple.
:param arg0: Either a :class:`Statement`, a list of statements or the subject of a triple.
:type arg0: Statement|Value|Iterable[Statement]
:param arg1: Predicate of a triple.
:type arg1: URI
:param arg2: Object of a triple.
:type arg2: Value
:param contexts: An optional list of graphs to remove triples from.
:type contexts: Iterable[URI|string]
"""
if contexts and not isinstance(contexts, list):
contexts = [contexts]
if isinstance(arg0, Value) or arg0 is None: self.removeTriples(arg0, arg1, arg2, contexts=contexts)
elif isinstance(arg0, Statement): self.removeStatement(arg0, contexts=contexts)
elif hasattr(arg0, '__iter__'):
for s in arg0:
self.removeStatement(s, contexts=contexts)
else:
raise IllegalArgumentException("Illegal first argument to 'remove'. Expected a Value, Statement, or iterator.")
[docs] def removeTriples(self, subject, predicate, object, contexts=ALL_CONTEXTS):
"""
Remove the statement(s) with the specified subject, predicate and object
from the repository, optionally restricted to the specified contexts.
:param subject: Subject of the triples to be removed.
:type subject: Value
:param predicate: Predicate of the triples to be removed.
:type predicate: URI
:param object: Object of the triples to be removed.
:type object: Value
:param contexts: An optional list of graphs to remove triples from.
:type contexts: Iterable[URI|string]
"""
subj = self._to_ntriples(subject)
pred = self._to_ntriples(predicate)
obj = self._to_ntriples(self.getValueFactory().object_position_term_to_openrdf_term(object))
ntripleContexts = self._contexts_to_ntriple_contexts(contexts, none_is_mini_null=True)
if ntripleContexts is None or len(ntripleContexts) == 0:
self._get_mini_repository().deleteMatchingStatements(subj, pred, obj, None)
else:
for cxt in ntripleContexts:
self._get_mini_repository().deleteMatchingStatements(subj, pred, obj, cxt)
[docs] def removeQuads(self, quads, ntriples=False):
"""
Remove enumerated quads from this repository. Each quad can
be a list or a tuple of :class:`Value` objects.
:param quads: List of quads. Each element can be
either a statement or a list or tuple of :class:`Value` objects
or strings.
:type quads: Iterable[list[string|Value]|tuple[string|Value]]
:param ntriples: If ``True``, parts of the quads are assumed to be strings
in N-Triples format and are sent to the server without any
conversion.
:type ntriples: bool
"""
removeQuads = []
for q in quads:
quad = [None] * 4
if ntriples:
quad[0] = q[0]
quad[1] = q[1]
quad[2] = q[2]
quad[3] = q[3]
elif isinstance(quad, (list, tuple)):
predicate = q[1]
obj = self.getValueFactory().object_position_term_to_openrdf_term(q[2], predicate=predicate)
quad[0] = self._to_ntriples(q[0])
quad[1] = self._to_ntriples(predicate)
quad[2] = self._to_ntriples(obj)
quad[3] = self._to_ntriples(q[3])
else: # must be a statement
predicate = q.getPredicate()
obj = self.getValueFactory().object_position_term_to_openrdf_term(q.getObject(), predicate=predicate)
quad[0] = self._to_ntriples(q.getSubject())
quad[1] = self._to_ntriples(predicate)
quad[2] = self._to_ntriples(obj)
quad[3] = self._to_ntriples(q.getContext())
removeQuads.append(quad)
self._get_mini_repository().deleteStatements(removeQuads)
[docs] def removeQuadsByID(self, tids):
"""
Remove all quads with matching IDs.
:param tids: List of IDs to be removed.
:type tids: list[int]
"""
self._get_mini_repository().deleteStatementsById(tids)
[docs] def removeStatement(self, statement, contexts=None):
"""
Remove the supplied statement from the specified contexts in the repository.
:param statement: Statement to be removed. Note that the ``context`` field of this object
will be ignored.
:type statement: Statement
:param contexts: An optional list of graphs to remove the statement from.
:type contexts: Iterable[URI|string]
"""
self.removeTriples(statement.getSubject(), statement.getPredicate(), statement.getObject(), contexts=contexts)
[docs] def clear(self, contexts=ALL_CONTEXTS):
"""
Removes all statements from designated contexts in the repository. If
``contexts`` is ALL_CONTEXTS, clears the repository of all statements.
:param contexts: A context or list of contexts.
:type contexts: Iterable[string|URI]|string|URI
"""
self.removeTriples(None, None, None, contexts=contexts)
[docs] def export(self, handler, contexts=ALL_CONTEXTS):
"""
Export all explicit statements in the specified contexts to a file.
.. deprecated:: 4.14.1
Use :meth:`saveResponse` instead.
:param handler: An RDFWriter instance describing the target file and data format.
:type handler: RDFWriter
:param contexts: A context or list of contexts (default: all contexts).
:type contexts: Iterable[string|URI]|string|URI
"""
warnings.warn("export is deprecated. Use saveResponse instead.", DeprecationWarning, stacklevel=2)
self.exportStatements(None, None, None, False, handler, contexts=contexts)
[docs] def exportStatements(self, subj, pred, obj, includeInferred, handler, contexts=ALL_CONTEXTS):
"""
Export statements to a file.
.. deprecated:: 4.14.1
Use :meth:`saveResponse` instead.
:param subj: Subject or ``None`` (i.e. no filtering on subject).
:type subj: Value
:param pred: Predicate or ``None`` (i.e. no filtering on predicate).
:type pred: URI
:param obj: Object or ``None`` (i.e. no filtering on object).
:type obj: Value
:param includeInferred: If ``True`` inferred triples will be included
in the output. The default is ``False``.
:type includeInferred: bool
:param handler: An RDFWriter instance describing the target file and data format.
:type handler: RDFWriter
:param contexts: A context or list of contexts (default: all contexts).
:type contexts: Iterable[string|URI]|string|URI
"""
warnings.warn("exportStatements is deprecated. Use getStatements(output=...) instead.",
DeprecationWarning, stacklevel=2)
self.getStatements(subj, pred, obj, contexts,
output=handler.getFilePath() or sys.stdout,
output_format=handler.getRDFFormat(),
includeInferred=includeInferred)
[docs] def getSubjectTriplesCacheSize(self):
"""
Return the current size of the subject triples cache.
.. seealso::
:meth:`.enablerSubjectTriplesCache`
"""
return self._get_mini_repository().getTripleCacheSize()
[docs] def disableSubjectTriplesCache(self):
"""
Disable the subject triples cache (see :meth:`.enableSubjectTriplesCache`).
"""
self._get_mini_repository().disableTripleCache()
[docs] def enableSubjectTriplesCache(self, size=None):
"""
Maintain a cache of size ``size`` that caches, for each accessed
resource, quads where the resource appears in subject position.
This can accelerate the performance of certain types of queries.
:param size: The maximum number of subjects whose triples will be cached.
Default is 100,000.
:type size: int
"""
self._get_mini_repository().enableTripleCache(size=size)
## Indexing control methods
[docs] def listIndices(self):
"""
Return the list of the current set of triple indices.
Index names are strings such as ``"gospi"``, ``"spogi"`` etc.
Use :meth:`.listValidIndices` to get the list of index names
supported by the server.
:return: List of index names (see :meth:`.listValidIndices`).
:rtype: list[string]
"""
return self._get_mini_repository().listIndices()
[docs] def listValidIndices(self):
"""
Return the list of valid index names.
:return: List of index names.
:rtype: list[string]
"""
return self._get_mini_repository().listValidIndices()
[docs] def addIndex(self, _type):
"""
Add a specific type of index to the current set of triple indices.
:param _type: Index name (see :meth:`.listIndices`).
:type _type: string
"""
return self._get_mini_repository().addIndex(_type)
[docs] def dropIndex(self, _type):
"""
Removes a specific type of index to the current set of triple indices.
:param _type: Index name (see :meth:`.listIndices`).
:type _type: string
"""
return self._get_mini_repository().dropIndex(_type)
[docs] def optimizeIndices(self, level=None, wait=None):
"""
Optimize indices.
Please see documentation for argument values and meanings:
https://franz.com/agraph/support/documentation/current/triple-index.html#optimize
"""
return self._get_mini_repository().optimizeIndices(level, wait)
#############################################################################################
## ValueFactory methods
## Added here because its inconvenient to have to dispatch from three different objects
## (connection, repository, and value factory) when one will do
#############################################################################################
[docs] def registerDatatypeMapping(self, predicate=None, datatype=None, nativeType=None):
"""
Register an inlined datatype.
See :meth:`.Repository.registerDatatypeMapping`.
"""
return self.repository.registerDatatypeMapping(predicate=predicate, datatype=datatype, nativeType=nativeType)
[docs] def createLiteral(self, value, datatype=None, language=None):
"""
Create a new literal with value ``value``. ``datatype``, if supplied,
should be a URI (it can be a string or an :class:`.URI` instance, in which
case ``value`` must be a string.
:param value: Literal value - can be a string, a number or a datetime object.
:type value: int|long|float|string|datetime.datetime|datetime.date|datetime.time
:param datatype: Optional literal type. Note that if ``value`` is not a string
the type will be guessed automatically.
:type datatype: string|URI
:param language: Optional language tag.
:type language: string
"""
return self.getValueFactory().createLiteral(value, datatype=datatype, language=language)
[docs] def createURI(self, uri=None, namespace=None, localname=None):
"""
Creates a new URI from the supplied string-representation(s).
If two non-keyword arguments are passed, assumes they represent a
namespace/localname pair.
:param uri: URI text, unless namespace is passed and localname is not,
in which case this becomes the namespace.
:type uri: string
:param namespace: Namespace part of the URI if ``localname`` is passed,
otherwise this becomes the local name.
:type namespace: string|URI
:param localname: Local part of the URI. Should only be used as a
keyword argument and together with ``namespace``.
:return: An URI object.
:rtype: URI
"""
return self.getValueFactory().createURI(uri=uri, namespace=namespace, localname=localname)
[docs] def createBNode(self, nodeID=None):
"""
Create a new blank node.
:param nodeID: Optional node identifier, if not given a fresh one will be generated.
:type nodeID: string
:return: A BNode value.
:rtype: BNode
"""
return self.getValueFactory().createBNode(nodeID=nodeID)
[docs] def createStatement(self, subject, predicate, object, context=None):
"""
Create a new Statement object.
Note that this does *not* cause the statement to be added to the repository.
:param subject: Subject of the new statement.
:type subject: Resource
:param predicate: Predicate of the new statement.
:type predicate: URI
:param object: Object of the new statement.
:type object: Value
:param context: Graph of the new statement (optional).
:type context: URI
:return: A new statement.
:rtype: Statement
"""
return self.getValueFactory().createStatement(subject, predicate, object, context=context)
[docs] def createRange(self, lowerBound, upperBound):
"""
Create a compound literal representing a range from lowerBound to upperBound.
:param lowerBound: Lower bound of the range.
:type lowerBound: int
:param upperBound: Upper bound of the range.
:type upperBound: int
:return: A new literal object.
:rtype: RangeLiteral
"""
return self.getValueFactory().createRange(lowerBound=lowerBound, upperBound=upperBound)
[docs] def addRules(self, rules, language=QueryLanguage.PROLOG):
"""
Add Prolog functors to the current session.
Note that this only works with a dedicated session (See :meth:`.session`.
.. seealso::
http://franz.com/agraph/support/documentation/current/prolog-tutorial.html
Tutorial describing the syntax of Prolog rules (functors).
:param rules: A string containing Prolog rule definitions. The definitions
are S-expressions using the ``<-`` and ``<--`` operators
(to append and overwrite rules respectively).
:type rules: string
:param language: Ignored.
"""
del language
if not self._get_mini_repository().sessionAlive:
raise Exception('Prolog rules can only be added in a dedicated session.')
self._get_mini_repository().definePrologFunctors(rules)
[docs] def loadRules(self, filename, language=QueryLanguage.PROLOG):
"""
Add Prolog rules from file to the current session.
Note that this only works with a dedicated session.
:param filename: Path to the file containing Prolog rules.
:type filename: string
:param language: Ignored.
"""
with open(filename) as _file:
body = _file.read()
self.addRules(body, language)
#############################################################################################
## Server-side implementation of namespaces
#############################################################################################
[docs] def getNamespaces(self):
"""
Get all declared prefix/namespace pairs.
The result is a dictionary mapping prefixes to namespace URIs.
:return: A dictionary of namespaces.
:rtype: dict[string,string]
"""
namespaces = {}
for pair in self._get_mini_repository().listNamespaces():
namespaces[pair['prefix']] = pair['namespace']
return namespaces
[docs] def getNamespace(self, prefix):
"""
Get the namespace that is associated with the specified prefix, if any.
:param prefix: Namespace prefix.
:return: Namespace URI.
:raises RequestError: if there is no namespace with given prefix.
"""
return self._get_mini_repository().getNamespace(prefix)
[docs] def setNamespace(self, prefix, name):
"""
Define or redefine a namespace mapping in the repository.
:param prefix: Namespace prefix.
:type prefix: string
:param name: Namespace URI.
:type name: string
"""
self._get_mini_repository().addNamespace(prefix, name)
[docs] def removeNamespace(self, prefix):
"""
Remove a namespace declaration by removing the association between a
prefix and a namespace name.
:param prefix: Namespace prefix.
:type prefix: string
"""
self._get_mini_repository().deleteNamespace(prefix)
[docs] def clearNamespaces(self, reset=True):
"""
Delete all namespaces in this repository for the current user.
:param reset: If ``True`` (default) the user's namespaces are reset
to the default set of namespaces, otherwise all namespaces
are cleared.
"""
self._get_mini_repository().clearNamespaces(reset)
#############################################################################################
## Geo-spatial
#############################################################################################
[docs] def createRectangularSystem(self, scale=1, unit=None, xMin=0, xMax=None, yMin=0, yMax=None):
"""
Create a Cartesian coordinate system and use it as the current coordinate system.
:param scale: Estimate of the Y size of a typical search region.
:type scale: float|int
:param unit: Must be ``None`` (the default).
:param xMin: Left edge of the rectangle.
:type xMin: float|int
:param xMax: Right edge of the rectangle.
:type xMax: float|int
:param yMin: Bottom edge of the rectangle.
:type yMin: float|int
:param yMax: Top edge of the rectangle.
:type yMax: float|int
:return: The new coordinate system.
"""
self.geoType = GeoType(GeoType.Cartesian, scale=scale, unit=unit, xMin=xMin, xMax=xMax, yMin=yMin, yMax=yMax)
##,latMin=None, latMax=None, longMin=None, longMax=None)
self.geoType.setConnection(self)
return self.geoType
[docs] def createLatLongSystem(self, unit='degree', scale=None, latMin=None, latMax=None, longMin=None, longMax=None):
"""
Create a spherical coordinate system and use it as the current coordinate system.
:param scale: Estimate of the size of a typical search region in the latitudinal direction.
:type scale: float|int
:param unit: One of: ``'degree'``, ``'mile'``, ``'radian'``, ``'km'``.
The default is ``'degree'``.
:type unit: string
:param longMin: Left side of the coordinate system.
:type longMin: float|int
:param longMax: Right side of the coordinate system.
:type longMax: float|int
:param latMin: Bottom border of the coordinate system.
:type latMin: float|int
:param latMax: Top border of the coordinate system.
:type latMax: float|int
:return: The new coordinate system.
"""
self.geoType = GeoType(GeoType.Spherical, unit=unit, scale=scale, latMin=latMin, latMax=latMax, longMin=longMin, longMax=longMax)
self.geoType.setConnection(self)
return self.geoType
[docs] def getGeoType(self):
"""
Get the current geospatial coordinate system.
:return: A coordinate system.
:rtype: GeoType
"""
return self.geoType
[docs] def setGeoType(self, geoType):
"""
Set the current geospatial coordinate system.
:param geoType: The new coordinate system.
:type geoType: GeoType
"""
self.geoType = geoType
geoType.setConnection(self)
[docs] def createCoordinate(self, x=None, y=None, latitude=None, longitude=None):
"""
Create an x, y or latitude, longitude coordinate in the current coordinate system.
Either ``x``, ``y`` or ``latitude``, ``longitude`` must be given.
:param x: X coordinate of the created point.
:param y: Y coordinate of the created point.
:param latitude: Latitude of the created point.
:param longitude: Longitude of the created point.
:return: A literal representing the created point.
:rtype: Literal
"""
return self.geoType.createCoordinate(x=x, y=y, latitude=latitude, longitude=longitude)
[docs] def createBox(self, xMin=None, xMax=None, yMin=None, yMax=None):
"""
Create a rectangular search region (a box) for geospatial search.
This method works for both Cartesian and spherical coordinate systems.
:param xMin: Minimum latitude.
:type xMin: float|int
:param xMax: Maximum latitude.
:type xMax: float|int
:param yMin: Minimum longitude.
:type yMin: float|int
:param yMax: Maximum longitude.
:type yMax: float|int
:return: A geospatial literal corresponding to the specified search region.
:rtype: Literal
"""
return self.geoType.createBox(xMin=xMin, xMax=xMax, yMin=yMin, yMax=yMax)
[docs] def createCircle(self, x, y, radius, unit=None):
"""
Create a circular search region for geospatial search.
This method works for both Cartesian and spherical coordinate systems.
:param x: Latitude of the center.
:type x: float|int
:param y: Longitude of the center.
:type y: float|int
:param radius: The radius of the circle expressed in the designated ``unit``.
:type radius: float|int
:param unit: Unit in which the ``radius`` is expressed.
Defaults to the unit assigned to the coordinate system.
Legal values are ``"degree"``, ``"radian"``, ``"km"`` and ``"mile"``.
:type unit: string
"""
return self.geoType.createCircle(x, y, radius, unit=unit)
[docs] def createPolygon(self, vertices, uri=None, geoType=None):
"""
Define a polygonal region with the specified vertices.
:param vertices: List of x, y pairs.
:type vertices: list[(float, float)]
:param uri: URI under which the polygon will be stored in the repository.
If not given a blank node will be used.
:type uri: URI
:param geoType: unused
:return: An object representing the newly created polygon.
:rtype: GeoPolygon
"""
del geoType
return self.geoType.createPolygon(vertices, uri=uri)
#############################################################################################
## SNA Social Network Analysis Methods
#############################################################################################
[docs] def registerSNAGenerator(self, name, subjectOf=None, objectOf=None, undirected=None, generator_query=None):
"""
Create a new SNA generator named ``name``.
If one already exists with the same name - redefine it.
The edges traversed by the new generator can be defined in one of two ways:
- Using three lists of predicates to define edges between subjects and
objects of triples (``subjectOf``, ``objectOf``, ``undirected``).
- Using a Prolog query (``generator_query``).
Requires a dedicated session.
:param name: Name of the new/modified generator.
:type name: string
:param subjectOf: Create object to subject edges for these predicates.
:type subjectOf: list[URI|string]
:param objectOf: Create subject to object edges for these predicates.
:type objectOf: list[URI|string]
:param undirected: Create edges in both directions for these predicates.
:type undirected: list[URI|string]
:param generator_query: A Prolog query that generates neighbors given
a start node ``?node``.
"""
miniRep = self._get_mini_repository()
miniRep.registerSNAGenerator(name, subjectOf=subjectOf, objectOf=objectOf, undirected=undirected,
query=generator_query)
[docs] def registerNeighborMatrix(self, name, generator, group_uris, max_depth=2):
"""
Construct a neighbor matrix named ``name``.
The generator named ``generator`` is applied to each URI in ``group_uris``,
computing edges to max depth ``max_depth``.
Requires a dedicated session.
:param name: Name that will be used to identify the matrix.
:type name: string
:param generator: Name of the SNA generator used to compute the edges.
See :meth:`.registerSNAGenerator`.
:type generator: string
:param group_uris: Initial list of vertices from which the graph will be created.
:type group_uris: list[URI|string]
:param max_depth: Max distance from the initial vertices.
:type max_depth: int
"""
miniRep = self._get_mini_repository()
miniRep.registerNeighborMatrix(name, group_uris, generator, max_depth)
[docs] def listFreeTextIndices(self):
"""
Get the names of currently defined free-text indices.
:return: List of index names.
:rtype: list[string]
"""
return self.mini_repository.listFreeTextIndices()
[docs] def createFreeTextIndex(self, name, predicates=None, indexLiterals=None, indexResources=None,
indexFields=None, minimumWordSize=None, stopWords=None, wordFilters=None,
innerChars=None, borderChars=None, tokenizer=None):
"""
Create a free-text index with the given parameters.
.. seealso::
http://franz.com/agraph/support/documentation/current/http-protocol.html#put-freetext-index
Documentation of the HTTP endpoint used by this method.
http://franz.com/agraph/support/documentation/current/text-index.html
General information about text indexing in AllegroGraph.
:param name: Name for the new index.
:type name: string
:param predicates: A list of predicates to be indexed. If not given all
triples will be indexed regardless of predicate.
:type predicates: list[string|URI]
:param indexLiterals: Determines which literals to index. It can be``True``
(the default), ``False``, or a list of resources,
indicating the literal types that should be indexed.
:type indexLiterals: bool|list[URI]
:param indexResources: Determines which resources are indexed. It can be
``True``, ``False`` (the default), or ``"short"``,
to index only the part of resources after the last
slash or hash character.
:type indexResources: bool|string
:param indexFields: List of triples fields to index. Can be any combination
of ``"subject"``, ``"predicate"``, ``"object"``, and
``"graph"``. The default is ``["object"]``.
:type indexFields: list[string]
:param minimumWordSize: Determines the minimum size a word must have to be
indexed. The default is 3.
:type minimumWordSize: int
:param stopWords: List of words that should not be indexed.
When not given, a list of common English words is used.
:type stopWords: list[string]
:param wordFilters: List of normalizing filters used to process words
before indexing. The list if supported filters can
be found here:
http://franz.com/agraph/support/documentation/current/text-index.html
:type wordFilters: list[string]
:param innerChars: The character set to be used as the constituent characters of a word.
Should be a list of character classes. Valid classes are:
- `"alpha"``: All (unicode) alphabetic characters.
- ``"digit"``: All base-10 digits.
- ``"alphanumeric"``: All digits and alphabetic characters.
- a single character
- a range of characters: A single character, followed by a dash (-)
character, followed by another single character.
:type innerChars: list[string]
:param borderChars: The character set to be used as the border characters of indexed words.
Uses the same syntax as ``innerChars``.
:type borderChars: list[string]
:param tokenizer: Controls the way in which the text is plit into tokens.
Can be either ``"default"`` or ``"japaense"``.
Note that the ``japaense`` tokenizer ignores ``innerChars``
and ``borderChars``.
:type tokenizer: string
"""
if predicates: predicates = list(map(uris.asURIString, predicates))
if isinstance(indexLiterals, list): indexLiterals = list(map(uris.asURIString, indexLiterals))
self.mini_repository.createFreeTextIndex(name, predicates=predicates, indexLiterals = indexLiterals,
indexResources=indexResources, indexFields=indexFields,
minimumWordSize=minimumWordSize, stopWords=stopWords,
wordFilters=wordFilters, innerChars=innerChars,
borderChars=borderChars, tokenizer=tokenizer)
[docs] def modifyFreeTextIndex(self, name, predicates=None, indexLiterals=None, indexResources=None,
indexFields=None, minimumWordSize=None, stopWords=None, wordFilters=None,
reIndex=None, innerChars=None, borderChars=None, tokenizer=None):
"""
Modify parameters of a free-text index.
:param name: Name of the index to be modified.
:type name: string
:param predicates: A list of predicates to be indexed. If not given all
triples will be indexed regardless of predicate.
:type predicates: list[string|URI]
:param indexLiterals: Determines which literals to index. It can be``True``
(the default), ``False``, or a list of resources,
indicating the literal types that should be indexed.
:type indexLiterals: bool|list[URI]
:param indexResources: Determines which resources are indexed. It can be
``True``, ``False`` (the default), or ``"short"``,
to index only the part of resources after the last
slash or hash character.
:type indexResources: bool|string
:param indexFields: List of triples fields to index. Can be any combination
of ``"subject"``, ``"predicate"``, ``"object"``, and
``"graph"``. The default is ``["object"]``.
:type indexFields: list[string]
:param minimumWordSize: Determines the minimum size a word must have to be
indexed. The default is 3.
:type minimumWordSize: int
:param stopWords: List of words that should not be indexed.
When not given, a list of common English words is used.
:type stopWords: list[string]
:param wordFilters: List of normalizing filters used to process words
before indexing. The list if supported filters can
be found here:
http://franz.com/agraph/support/documentation/current/text-index.html
:type wordFilters: list[string]
:param innerChars: The character set to be used as the constituent characters of a word.
Should be a list of character classes. Valid classes are:
- `"alpha"``: All (unicode) alphabetic characters.
- ``"digit"``: All base-10 digits.
- ``"alphanumeric"``: All digits and alphabetic characters.
- a single character
- a range of characters: A single character, followed by a dash (-)
character, followed by another single character.
:type innerChars: list[string]
:param borderChars: The character set to be used as the border characters of indexed words.
Uses the same syntax as ``innerChars``.
:type borderChars: list[string]
:param tokenizer: Controls the way in which the text is plit into tokens.
Can be either ``"default"`` or ``"japaense"``.
Note that the ``japaense`` tokenizer ignores ``innerChars``
and ``borderChars``.
:type tokenizer: string
"""
if predicates: predicates = list(map(uris.asURIString, predicates))
if isinstance(indexLiterals, list): indexLiterals = list(map(uris.asURIString, indexLiterals))
self.mini_repository.modifyFreeTextIndex(name, predicates=predicates, indexLiterals = indexLiterals,
indexResources=indexResources, indexFields=indexFields,
minimumWordSize=minimumWordSize, stopWords=stopWords,
wordFilters=wordFilters, reIndex=reIndex, innerChars=innerChars,
borderChars=borderChars, tokenizer=tokenizer)
[docs] def deleteFreeTextIndex(self, name):
"""
Delete a free-text index from the server.
:param name: Index name.
:type name: string
"""
self.mini_repository.deleteFreeTextIndex(name)
[docs] def getFreeTextIndexConfiguration(self, name):
"""
Get the current settings of a free-text index.
The result will be a dictionary where keys are parameter names
as used in :meth:`.createFreeTextIndex`.
:param name: Index name.
:type name: string
:return: A dictionary with configuration data, keys are argument
names from :meth:`.createFreeTextIndex`.
:rtype: dict
"""
value = self.mini_repository.getFreeTextIndexConfiguration(name)
value["predicates"] = list(map(URI, value["predicates"]))
if isinstance(value["indexLiterals"], list):
value["indexLiterals"] = list(map(URI, value["indexLiterals"]))
return value
[docs] def evalFreeTextSearch(self, pattern, infer=False, callback=None, limit=None, offset=None, index=None):
"""
Return a list of statements for the given free-text pattern search.
If no index is provided, all indices will be used.
:param pattern: Search pattern, see
http://franz.com/agraph/support/documentation/current/http-protocol.html#get-post-freetext
for details.
:type pattern: string
:param index: List of indices to query. If not given - query all indices.
:type index: string|list[string]
"""
miniRep = self._get_mini_repository()
return miniRep.evalFreeTextSearch(pattern, index, infer, wrap_callback(callback), limit, offset=offset)
[docs] def openSession(self, autocommit=False, lifetime=None, loadinitfile=False):
"""
Open a session.
It is not an error to call this when a session is already active on this connection,
but no new session will be created (i.e. nested sessions are not supported).
.. seealso::
http://franz.com/agraph/support/documentation/current/http-protocol.html#sessions
More detailed explanation of session-related concepts in the HTTP API reference.
:param autocommit: if ``True``, commits are done on each request, otherwise
you will need to call :meth:`.commit` or :meth:`.rollback`
as appropriate for your application.
The default value is ``False``.
:type autocommit: bool
:param lifetime: Time (in seconds) before the session expires when idle.
Note that the client maintains a thread that pings the
session before this happens.
The maximum acceptable value is 21600 (6 hours).
When the value is ``None`` (the default) the lifetime
is set to 300 seconds (5 minutes).
:type lifetime: int
:param loadinitfile: if ``True`` then the current initfile will be loaded
for you when the session starts. The default is ``False``.
:type loadinitfile: bool
"""
if not self.is_session_active:
miniRep = self._get_mini_repository()
if miniRep == self.repository.mini_repository:
# Don't use the shared mini_repository for a session
miniRep = self.mini_repository = copy.copy(self.repository.mini_repository)
miniRep.openSession(autocommit, lifetime, loadinitfile)
self.is_session_active = True
[docs] def closeSession(self):
"""
Close a session.
It is not an error to call this when no session is active.
"""
if self.is_session_active:
# Not deleting the dedicated mini_repository in case the user
# calls openSession again.
self._get_mini_repository().closeSession()
self.is_session_active = False
def __enter__(self):
return self
def __exit__(self, *args):
del args
self.close()
[docs] @contextmanager
def session(self, autocommit=False, lifetime=None, loadinitfile=False):
"""
A session context manager for use with the ``with`` statement:
.. code:: python
with conn.session():
# Automatically calls openSession at block start
# Do work
# Automatically calls closeSession at block end
# or in case of an exception.
:param autocommit: if ``True``, commits are done on each request, otherwise
you will need to call :meth:`.commit` or :meth:`.rollback`
as appropriate for your application.
The default value is ``False``.
:type autocommit: bool
:param lifetime: Time (in seconds) before the session expires when idle.
Note that the client maintains a thread that ping the
session before this happens.
:type lifetime: int
:param loadinitfile: if ``True`` then the current initfile will be loaded
for you when the session starts. The default is ``False``.
:type loadinitfile: bool
"""
self.openSession(autocommit, lifetime, loadinitfile)
yield self
self.closeSession()
[docs] def runAsUser(self, username=None):
"""
Only for use as a superuser during a session.
Runs requests on this connection as username.
None - the default - clears the setting.
"""
return self._get_mini_repository().runAsUser(username)
# This is completely insane. Are we really suggesting that to the users!?
[docs] @contextmanager
def saveResponse(self, fileobj, accept, raiseAll=False):
"""
Save the server response(s) for the call(s) within the with statement
to fileobj, using accept for the response type requested.
.. deprecated:: 100.0.1
Use getStatements(output=...) or evaluate(output=...) to export data.
Responses will be uncompressed and saved to fileobj, but not decoded.
Therefore, the API called will likely error out shortly after the
response is saved (which is okay because we really only want
the side-effect of saving the response).
RequestError is always thrown on errors from the server.
Other exceptions can be optionally raised with raiseAll=True.
You will only want to make only one conn call in the with statement
unless you wrap each call in its own try/except.
Example:
with open('out', 'w') as response:
with conn.saveResponse(response, 'application/rdf+xml'):
conn.getStatements(None, None, None) # The response is written to response
"""
with self._get_mini_repository().saveResponse(fileobj, accept, raiseAll):
yield
[docs] def commit(self):
"""
Commit changes on an open session.
"""
return self._get_mini_repository().commit()
[docs] def rollback(self):
"""
Roll back changes on open session.
"""
return self._get_mini_repository().rollback()
[docs] def evalInServer(self, code):
"""
Evaluate the Lisp code in the server.
You must have "eval" permissions to the store to use this feature.
"""
return self._get_mini_repository().evalInServer(code)
[docs] def evalJavaScript(self, code):
"""
Evaluate the JavaScript code in the server.
You must have "eval" permissions to the store to use this feature.
"""
return self._get_mini_repository().evalJavaScript(code)
# NOTE: 'format' shadows a built-in symbol but it is too late to change the public API
[docs] def registerEncodedIdPrefix(self, prefix, format):
"""
Registers a single encoded prefix.
See: https://franz.com/agraph/support/documentation/current/encoded-ids.html
"""
return self._get_mini_repository().registerEncodedIdPrefix(prefix, format)
[docs] def registerEncodedIdPrefixes(self, registrations):
"""
Registers multiple encoded prefixes. Any kind of iteratable collection
of items with a prefix attribute and format attribute, or the prefix
at index 0 and the format at index 1 will do (e.g. a list of tuples).
Using PrefixFormat instances also works well.
See: https://franz.com/agraph/support/documentation/current/encoded-ids.html
"""
return self._get_mini_repository().registerEncodedIdPrefixes(registrations)
[docs] def listEncodedIdPrefixes(self):
"""
Lists all encoded id prefixes.
See: https://franz.com/agraph/support/documentation/current/encoded-ids.html
"""
regs = []
enc_ids = self._get_mini_repository().listEncodedIdPrefixes()
for enc_id in enc_ids:
regs.append(PrefixFormat(enc_id["prefix"], enc_id["format"]))
return regs
[docs] def unregisterEncodedIdPrefix(self, prefix):
"""
Unregisters the specified encoded id prefix.
See: https://franz.com/agraph/support/documentation/current/encoded-ids.html
"""
return self._get_mini_repository().unregisterEncodedIdPrefix(prefix)
[docs] def allocateEncodedIds(self, prefix, amount=1):
"""
allocateEncodedIds allows you to use the server to allocate
unique ids for a given registered prefix which has a fixed-width
format specifier.
See notes on next-encoded-upi-for-prefix in:
https://franz.com/agraph/support/documentation/current/encoded-ids.html
"""
return self._get_mini_repository().allocateEncodedIds(prefix, amount)
[docs] def deleteDuplicates(self, mode):
"""
Delete duplicate triples from the store.
:param mode: can be `"spo"` (triples are duplicates if they have the same subject,
predicate, and object, regardless of the graph) or `"spog"` (triples
are duplicates if they have the same subject, predicate, object, and
graph).
.. seealso::
Method :meth:`getDuplicateStatements`.
"""
self._get_mini_repository().deleteDuplicates(mode)
[docs] def getDuplicateStatements(self, mode):
"""
Return all duplicates in the store.
:param mode: can be `"spo"` (triples are duplicates if they have the same subject,
predicate, and object, regardless of the graph) or `"spog"` (triples
are duplicates if they have the same subject, predicate, object, and
graph).
:return: An iterator over duplicate statements.
:rtype: RepositoryResult
"""
stringTuples = self._get_mini_repository().getDuplicateStatements(mode)
return RepositoryResult(stringTuples)
[docs] def getDuplicateSuppressionPolicy(self):
"""
Return the duplicate suppression policy used by the store.
See https://franz.com/agraph/support/documentation/current/deleting-duplicate-triples.html
:return: Duplicate suppression policy: "spo", "spog" or None.
:rtype: str
"""
return self._get_mini_repository().getDuplicateSuppressionPolicy()
[docs] def setDuplicateSuppressionPolicy(self, mode):
"""
Set the duplicate suppression policy used by the store.
See https://franz.com/agraph/support/documentation/current/deleting-duplicate-triples.html
:param mode: Duplicate suppression policy: "spo", "spog" or None (disable suppression).
:type mode: str
"""
self._get_mini_repository().setDuplicateSuppressionPolicy(mode)
[docs] def disableDuplicateSuppression(self):
"""
Disable duplicate suppression for this store.
See https://franz.com/agraph/support/documentation/current/deleting-duplicate-triples.html
"""
self._get_mini_repository().disableDuplicateSuppression()
[docs] def callStoredProc(self, function, module, *args):
return self._get_mini_repository().callStoredProc(function, module,
*args)
[docs] def getSpinFunction(self, uri):
"""
Gets the string of the function for the given uri.
uri - Spin function identifier
"""
return self._get_mini_repository().getSpinFunction(uri)
[docs] def putSpinFunction(self, uri, sparqlQuery, arguments):
"""
Adds a Spin function.
uri - Spin function identifier
sparqlQuery - Spin function query text
arguments - names of arguments in the sparqlQuery
"""
self._get_mini_repository().putSpinFunction(uri, sparqlQuery, arguments)
[docs] def deleteSpinFunction(self, uri):
"""
Deletes the Spin function at the given uri.
uri - Spin function identifier
"""
return self._get_mini_repository().deleteSpinFunction(uri)
[docs] def listSpinFunctions(self):
"""
Returns a list of defined SPIN function.
"""
return self._get_mini_repository().listSpinFunctions()
[docs] def putSpinMagicProperty(self, uri, sparqlQuery, arguments):
"""
Add a Spin magic property.
uri - Spin magic property identifier
sparqlQuery
arguments - names of arguments to the sparqlQuery - must contain the leading question mark
"""
self._get_mini_repository().putSpinMagicProperty(uri, sparqlQuery, arguments)
[docs] def getSpinMagicProperty(self, uri):
"""
Get the spin magic property for the uri
uri - spin magic property identifier
"""
return self._get_mini_repository().getSpinMagicProperty(uri)
[docs] def listSpinMagicProperties(self):
"""
Returns a list of defined SPIN magic properties function.
"""
return self._get_mini_repository().listSpinMagicProperties()
[docs] def deleteSpinMagicProperty(self, uri):
"""
Deletes the Spin magic property at the given uri.
uri - Spin magic property identifier
"""
self._get_mini_repository().deleteSpinMagicProperty(uri)
[docs] def materializeEntailed(self, _with=None, without=None, useTypeSubproperty=False, commit=100000):
"""
Call to materialize entailed triples to enable reasoning queries without the dynamic query-time reasoner.
Returns the number of triples added.
_with and without can be either a single string or a list of strings denoting rules beyond rdfs++ you wish to use.
See the documentation for the current set, but "same-as", "restriction", "values-from", "class", and "property" are examples.
useTypeSubproperty tells the materializer to prefer using types that are rdfs:subPropertyOf rdf:type rather than rdf:type directly.
commit indicates the number of triples per commit for the materializer.
"""
return self._get_mini_repository().materializeEntailed(_with=_with, without=without, useTypeSubproperty=useTypeSubproperty, commit=commit)
[docs] def deleteMaterialized(self):
"""
Deletes all previously materialized triples.
Returns the number of triples deleted.
"""
return self._get_mini_repository().deleteMaterialized()
[docs] def executeTupleQuery(self, query, language=QueryLanguage.SPARQL,
output=None, output_format=RDFFormat.TABLE):
"""
Prepare and immediately evaluate a query that returns tuples.
:param query: Query text.
:type query: str
:param language: Query language, the default is SPARQL.
:type language: QueryLanguage
:param output: File path or a file-like object to write
the result to.
:type output: str|file
:param output_format: Serialization format for ``output``.
:type output_format: RDFFormat
:return: Query result, or ``None`` if ``output`` is used.
:rtype: TupleQueryResult
"""
q = self.prepareTupleQuery(language, query)
return q.evaluate(output=output, output_format=output_format)
[docs] def executeGraphQuery(self, query, language=QueryLanguage.SPARQL,
output=None, output_format=RDFFormat.NQX):
"""
Prepare and immediately evaluate a query that returns RDF.
:param query: Query text.
:type query: str
:param language: Query language, the default is SPARQL.
:type language: QueryLanguage
:param output: File path or a file-like object to write
the result to.
:type output: str|file
:param output_format: Serialization format for ``output``.
:type output_format: RDFFormat
:return: Query result, or ``None`` if ``output`` is used.
:rtype: RepositoryResult|None
"""
q = self.prepareGraphQuery(language, query)
return q.evaluate(output=output, output_format=output_format)
[docs] def executeBooleanQuery(self, query, language=QueryLanguage.SPARQL):
"""
Prepare and immediately evaluate a query that returns
a boolean.
:param query: Query text.
:type query: str
:param language: Query language, the default is SPARQL.
:type language: QueryLanguage
:return: Query result.
:rtype: bool
"""
q = self.prepareBooleanQuery(language, query)
return q.evaluate()
[docs] def executeUpdate(self, query):
"""
Prepare and immediately evaluate a SPARQL update query.
:param query: Query text.
:type query: str
:return: Query result (true iff the store has been modified).
:rtype: bool
"""
q = self.prepareUpdate(QueryLanguage.SPARQL, query)
return q.evaluate()
[docs]class GeoType(object):
Cartesian = 'CARTESIAN'
Spherical = 'SPHERICAL'
[docs] def __init__(self, system, scale=None, unit=None, xMin=None, xMax=None, yMin=None, yMax=None, latMin=None, latMax=None, longMin=None, longMax=None):
self.system = system
self.connection = None
self.scale = scale
self.unit = unit
self.xMin = xMin
self.xMax = xMax
self.yMin = yMin
self.yMax = yMax
self.latMin = latMin
self.latMax = latMax
self.longMin = longMin
self.longMax = longMax
self.miniGeoType = None
if system == GeoType.Cartesian:
if unit:
raise Exception("Units not yet supported for rectangular coordinates.")
else: pass ## can't happen
[docs] def setConnection(self, connection): self.connection = connection
def _getMiniGeoType(self):
def stringify(term): return unicode(term) if term is not None else None
if not self.miniGeoType:
if self.system == GeoType.Cartesian:
self.miniGeoType = self.connection._get_mini_repository().getCartesianGeoType(stringify(self.scale), stringify(self.xMin), stringify(self.xMax),
stringify(self.yMin), stringify(self.yMax))
elif self.system == GeoType.Spherical:
self.miniGeoType = self.connection._get_mini_repository().getSphericalGeoType(stringify(self.scale), unit=stringify(self.unit),
latMin=stringify(self.latMin), latMax=stringify(self.latMax), longMin=stringify(self.longMin), longMax=stringify(self.longMax))
return self.miniGeoType
[docs] def createCoordinate(self, x=None, y=None, latitude=None, longitude=None, unit=None):
"""
Create an x, y or lat, long coordinate for the system defined by this geotype.
"""
return GeoCoordinate(x=(x or latitude), y=y or longitude, unit=unit, geoType=self)
[docs] def createBox(self, xMin=None, xMax=None, yMin=None, yMax=None, unit=None):
"""
Define a rectangular region for the current coordinate system.
"""
return GeoBox(xMin, xMax, yMin, yMax, unit=unit, geoType=self)
[docs] def createCircle(self, x, y, radius, unit=None):
"""
Define a circular region with vertex x,y and radius "radius".
The distance unit for the radius is either 'unit' or the unit specified
for this GeoType. If 'innerRadius' is specified, the region is
ring-shaped, consisting of the space between the inner and outer circles.
"""
return GeoCircle(x, y, radius, unit=unit, geoType=self)
[docs] def createPolygon(self, vertices, uri=None):
"""
Define a polygonal region with the specified vertices. 'vertices'
is a list of x,y pairs. The 'uri' is optional.
"""
poly = GeoPolygon(vertices, uri=uri, geoType=self)
poly.resource = self.connection.createURI(uri) if uri else self.connection.createBNode()
miniResource = self.connection._convert_term_to_mini_term(poly.resource)
miniRep = self.connection._get_mini_repository()
if self.system == GeoType.Cartesian:
miniVertices = [miniRep.createCartesianGeoLiteral(self._getMiniGeoType(), coord[0], coord[1]) for coord in poly.vertices]
elif self.system == GeoType.Spherical:
miniVertices = [miniRep.createSphericalGeoLiteral(self._getMiniGeoType(), coord[0], coord[1]) for coord in poly.vertices]
miniRep.createPolygon(miniResource, miniVertices)
return poly