Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions rdflib/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,13 @@ def bind(self, prefix, namespace, override=True, replace=False) -> None:
for example: graph.bind("foaf", "http://xmlns.com/foaf/0.1/")

"""
# TODO FIXME: This method's behaviour should be simplified and made
# more robust. If the method cannot do what it is asked it should raise
# an exception, it is also unclear why this method has all the
# different modes. It seems to just make it more complex to use, maybe
# it should be clarified when someone will need to use override=False
# and replace=False. And also why silent failure here is preferred over
# raising an excpetion.
return self.namespace_manager.bind(
prefix, namespace, override=override, replace=replace
)
Expand Down
15 changes: 11 additions & 4 deletions rdflib/plugins/stores/berkeleydb.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,10 +471,17 @@ def bind(self, prefix, namespace, override=True):
prefix = prefix.encode("utf-8")
namespace = namespace.encode("utf-8")
bound_prefix = self.__prefix.get(namespace)
if override and bound_prefix:
self.__namespace.delete(bound_prefix)
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
bound_namespace = self.__namespace.get(prefix)
if override:
if bound_prefix:
self.__namespace.delete(bound_prefix)
if bound_namespace:
self.__prefix.delete(bound_namespace)
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
else:
self.__prefix[bound_namespace or namespace] = bound_prefix or prefix
self.__namespace[bound_prefix or prefix] = bound_namespace or namespace

def namespace(self, prefix):
prefix = prefix.encode("utf-8")
Expand Down
51 changes: 41 additions & 10 deletions rdflib/plugins/stores/memory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#
#
from rdflib.store import Store
from rdflib.util import _coalesce

__all__ = ["SimpleMemory", "Memory"]

Expand Down Expand Up @@ -149,11 +150,26 @@ def __len__(self, context=None):
return i

def bind(self, prefix, namespace, override=True):
bound_prefix = self.__prefix.get(namespace)
if override and bound_prefix:
del self.__namespace[bound_prefix]
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
# should be identical to `Memory.bind`
bound_namespace = self.__namespace.get(prefix)
bound_prefix = _coalesce(
self.__prefix.get(namespace),
self.__prefix.get(bound_namespace),
)
if override:
if bound_prefix is not None:
del self.__namespace[bound_prefix]
if bound_namespace is not None:
del self.__prefix[bound_namespace]
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
else:
self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce(
bound_prefix, prefix
)
self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce(
bound_namespace, namespace
)

def namespace(self, prefix):
return self.__namespace.get(prefix, None)
Expand Down Expand Up @@ -403,11 +419,26 @@ def triples(self, triple_pattern, context=None):
yield triple, self.__contexts(triple)

def bind(self, prefix, namespace, override=True):
bound_prefix = self.__prefix.get(namespace)
if override and bound_prefix:
del self.__namespace[bound_prefix]
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
# should be identical to `SimpleMemory.bind`
bound_namespace = self.__namespace.get(prefix)
bound_prefix = _coalesce(
self.__prefix.get(namespace),
self.__prefix.get(bound_namespace),
)
if override:
if bound_prefix is not None:
del self.__namespace[bound_prefix]
if bound_namespace is not None:
del self.__prefix[bound_namespace]
self.__prefix[namespace] = prefix
self.__namespace[prefix] = namespace
else:
self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce(
bound_prefix, prefix
)
self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce(
bound_namespace, namespace
)

def namespace(self, prefix):
return self.__namespace.get(prefix, None)
Expand Down
26 changes: 25 additions & 1 deletion rdflib/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

# from time import daylight
from time import altzone, gmtime, localtime, time, timezone
from typing import Optional
from typing import Optional, TypeVar

import rdflib.graph # avoid circular dependency
from rdflib.compat import sign
Expand All @@ -44,6 +44,7 @@
"guess_format",
"find_roots",
"get_tree",
"_coalesce",
]


Expand Down Expand Up @@ -430,6 +431,29 @@ def get_tree(
return (mapper(root), sorted(tree, key=sortkey))


_AnyT = TypeVar("_AnyT")


def _coalesce(*args: Optional[_AnyT]) -> Optional[_AnyT]:
"""
This is a null coalescing function, it will return the first non-`None`
argument passed to it, otherwise it will return `None`.

For more info regarding the rationale of this function see deferred `PEP
505 <https://peps.python.org/pep-0505/>`_.

:param args: Values to consider as candidates to return, the first arg that
is not `None` will be returned. If no argument is passed this function
will return None.
:return: The first ``arg`` that is not `None`, otherwise `None` if there
are no args or if all args are `None`.
"""
for arg in args:
if arg is not None:
return arg
return None


def test():
import doctest

Expand Down
Loading