Skip to content

notation3

notation3.py - Standalone Notation3 Parser Derived from CWM, the Closed World Machine

Authors of the original suite:

http://www.w3.org/2000/10/swap/notation3.py

Copyright 2000-2007, World Wide Web Consortium. Copyright 2001, MIT. Copyright 2001, Zolera Systems Inc.

License: W3C Software License http://www.w3.org/Consortium/Legal/copyright-software

Modified by Sean B. Palmer Copyright 2007, Sean B. Palmer.

Modified to work with rdflib by Gunnar Aastrand Grimnes Copyright 2010, Gunnar A. Grimnes

Classes:

Functions:

  • base

    The base URI for this process - the Web equiv of cwd

  • hexify

    Use URL encoding to return an ASCII string

  • join

    join an absolute URI and URI reference

  • runNamespace

    Returns a URI suitable as a namespace for run-local objects

  • splitFragP

    Split a URI reference before the fragment

  • uniqueURI

    A unique URI

ADDED_HASH module-attribute

ADDED_HASH = '#'

ALL4 module-attribute

ALL4 = (CONTEXT, PRED, SUBJ, OBJ)

ANONYMOUS module-attribute

ANONYMOUS = 3

BOOLEAN_DATATYPE module-attribute

BOOLEAN_DATATYPE = _XSD_PFX + 'boolean'

CONTEXT module-attribute

CONTEXT = 0

DAML_sameAs module-attribute

DAML_sameAs = (SYMBOL, DAML_sameAs_URI)

DAML_sameAs_URI module-attribute

DAML_sameAs_URI = OWL_NS + 'sameAs'

DECIMAL_DATATYPE module-attribute

DECIMAL_DATATYPE = _XSD_PFX + 'decimal'

DOUBLE_DATATYPE module-attribute

DOUBLE_DATATYPE = _XSD_PFX + 'double'

FLOAT_DATATYPE module-attribute

FLOAT_DATATYPE = _XSD_PFX + 'float'

FORMULA module-attribute

FORMULA = 1

INTEGER_DATATYPE module-attribute

INTEGER_DATATYPE = _XSD_PFX + 'integer'

LITERAL module-attribute

LITERAL = 2

LITERAL_DT module-attribute

LITERAL_DT = 21

LITERAL_LANG module-attribute

LITERAL_LANG = 22

LOG_implies_URI module-attribute

LOG_implies_URI = 'http://www.w3.org/2000/10/swap/log#implies'

List_NS module-attribute

List_NS = RDF_NS_URI

Logic_NS module-attribute

Logic_NS = 'http://www.w3.org/2000/10/swap/log#'

N3CommentCharacter module-attribute

N3CommentCharacter = '#'

N3_Empty module-attribute

N3_Empty = (SYMBOL, List_NS + 'Empty')

N3_List module-attribute

N3_List = (SYMBOL, List_NS + 'List')

N3_first module-attribute

N3_first = (SYMBOL, List_NS + 'first')

N3_forAll_URI module-attribute

N3_forAll_URI = forAllSym

N3_forSome_URI module-attribute

N3_forSome_URI = forSomeSym

N3_li module-attribute

N3_li = (SYMBOL, List_NS + 'li')

N3_nil module-attribute

N3_nil = (SYMBOL, List_NS + 'nil')

N3_rest module-attribute

N3_rest = (SYMBOL, List_NS + 'rest')

NODE_MERGE_URI module-attribute

NODE_MERGE_URI = Logic_NS + 'is'

OBJ module-attribute

OBJ = 3

OWL_NS module-attribute

OWL_NS = 'http://www.w3.org/2002/07/owl#'

PARTS module-attribute

PARTS = (PRED, SUBJ, OBJ)

PRED module-attribute

PRED = 1

RDF_NS_URI module-attribute

RDF_NS_URI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'

RDF_spec module-attribute

RDF_spec = 'http://www.w3.org/TR/REC-rdf-syntax/'

RDF_type module-attribute

RDF_type = (SYMBOL, RDF_type_URI)

RDF_type_URI module-attribute

RDF_type_URI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'

SUBJ module-attribute

SUBJ = 2

SYMBOL module-attribute

SYMBOL = 0

XMLLITERAL module-attribute

XMLLITERAL = 25

__all__ module-attribute

__all__ = ['BadSyntax', 'N3Parser', 'TurtleParser', 'splitFragP', 'join', 'base', 'runNamespace', 'uniqueURI', 'hexify', 'Formula', 'RDFSink', 'SinkParser', 'sfloat']

chatty_flag module-attribute

chatty_flag = 50

decimal_syntax module-attribute

decimal_syntax = compile('[-+]?[0-9]*\\.[0-9]+')

digitstring module-attribute

digitstring = compile('[0-9]+')

eof module-attribute

eof = compile('[ \\t]*(#[^\\n]*)?$')

eol module-attribute

eol = compile('[ \\t]*(#[^\\n]*)?\\r?\\n')

escapeChars module-attribute

escapeChars = set("(_~.-!$&'()*+,;=/?#@%)")

exponent_syntax module-attribute

exponent_syntax = compile('[-+]?(?:[0-9]+\\.[0-9]*|\\.[0-9]+|[0-9]+)(?:e|E)[-+]?[0-9]+')

forAllSym module-attribute

forAllSym = Logic_NS + 'forAll'

forSomeSym module-attribute

forSomeSym = Logic_NS + 'forSome'

hexChars module-attribute

hexChars = set('ABCDEFabcdef0123456789')

integer_syntax module-attribute

integer_syntax = compile('[-+]?[0-9]+')

interesting module-attribute

interesting = compile('[\\\\\\r\\n\\"\\\']')

langcode module-attribute

langcode = compile('[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*')

nextu module-attribute

nextu = 0

numberChars module-attribute

numberChars = set('0123456789-')

numberCharsPlus module-attribute

numberCharsPlus = numberChars | {'+', '.'}

option_noregen module-attribute

option_noregen = 0

parsesTo_URI module-attribute

parsesTo_URI = Logic_NS + 'parsesTo'

r_hibyte module-attribute

r_hibyte = compile('([\\x80-\\xff])')

runNamespaceValue module-attribute

runNamespaceValue: Optional[str] = None

signed_integer module-attribute

signed_integer = compile('[-+]?[0-9]+')

tracking module-attribute

tracking = False

unicodeEscape4 module-attribute

unicodeEscape4 = compile('\\\\u([0-9a-fA-F]{4})')

unicodeEscape8 module-attribute

unicodeEscape8 = compile('\\\\U([0-9a-fA-F]{8})')

ws module-attribute

ws = compile('[ \\t]*')

BadSyntax

BadSyntax(uri: str, lines: int, argstr: str, i: int, why: str)

Bases: SyntaxError

Methods:

Attributes:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(self, uri: str, lines: int, argstr: str, i: int, why: str):
    self._str = argstr.encode("utf-8")  # Better go back to strings for errors
    self._i = i
    self._why = why
    self.lines = lines
    self._uri = uri

lines instance-attribute

lines = lines

message property

message: str

__str__

__str__() -> str
Source code in rdflib/plugins/parsers/notation3.py
def __str__(self) -> str:
    argstr = self._str
    i = self._i
    st = 0
    if i > 60:
        pre = "..."
        st = i - 60
    else:
        pre = ""
    if len(argstr) - i > 60:
        post = "..."
    else:
        post = ""

    # type error: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior
    return 'at line %i of <%s>:\nBad syntax (%s) at ^ in:\n"%s%s^%s%s"' % (
        self.lines + 1,  # type: ignore[str-bytes-safe]
        self._uri,
        self._why,
        pre,
        argstr[st:i],
        argstr[i : i + 60],
        post,
    )

Formula

Formula(parent: Graph)

Methods:

Attributes:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(self, parent: Graph):
    self.uuid = uuid4().hex
    self.counter = 0
    Formula.number += 1
    self.number = Formula.number
    self.existentials: Dict[str, BNode] = {}
    self.universals: Dict[str, BNode] = {}

    self.quotedgraph = QuotedGraph(store=parent.store, identifier=self.id())

counter instance-attribute

counter = 0

existentials instance-attribute

existentials: Dict[str, BNode] = {}

number class-attribute instance-attribute

number = number

quotedgraph instance-attribute

quotedgraph = QuotedGraph(store=store, identifier=id())

universals instance-attribute

universals: Dict[str, BNode] = {}

uuid instance-attribute

uuid = hex

__str__

__str__() -> str
Source code in rdflib/plugins/parsers/notation3.py
def __str__(self) -> str:
    return "_:Formula%s" % self.number

close

close() -> QuotedGraph
Source code in rdflib/plugins/parsers/notation3.py
def close(self) -> QuotedGraph:
    return self.quotedgraph

declareExistential

declareExistential(x: str) -> None
Source code in rdflib/plugins/parsers/notation3.py
def declareExistential(self, x: str) -> None:
    self.existentials[x] = self.newBlankNode()

id

id() -> BNode
Source code in rdflib/plugins/parsers/notation3.py
def id(self) -> BNode:
    return BNode("_:Formula%s" % self.number)

newBlankNode

newBlankNode(uri: Optional[str] = None, why: Optional[Any] = None) -> BNode
Source code in rdflib/plugins/parsers/notation3.py
def newBlankNode(
    self, uri: Optional[str] = None, why: Optional[Any] = None
) -> BNode:
    if uri is None:
        self.counter += 1
        bn = BNode("f%sb%s" % (self.uuid, self.counter))
    else:
        bn = BNode(uri.split("#").pop().replace("_", "b"))
    return bn

newUniversal

newUniversal(uri: str, why: Optional[Any] = None) -> Variable
Source code in rdflib/plugins/parsers/notation3.py
def newUniversal(self, uri: str, why: Optional[Any] = None) -> Variable:
    return Variable(uri.split("#").pop())

N3Parser

N3Parser()

Bases: TurtleParser

An RDFLib parser for Notation3

See http://www.w3.org/DesignIssues/Notation3.html

Methods:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(self):
    pass

parse

parse(source: InputSource, graph: Graph, encoding: Optional[str] = 'utf-8') -> None
Source code in rdflib/plugins/parsers/notation3.py
def parse(  # type: ignore[override]
    self, source: InputSource, graph: Graph, encoding: Optional[str] = "utf-8"
) -> None:
    # we're currently being handed a Graph, not a ConjunctiveGraph
    # context-aware is this implied by formula_aware
    ca = getattr(graph.store, "context_aware", False)
    fa = getattr(graph.store, "formula_aware", False)
    if not ca:
        raise ParserError("Cannot parse N3 into non-context-aware store.")
    elif not fa:
        raise ParserError("Cannot parse N3 into non-formula-aware store.")

    conj_graph = Dataset(store=graph.store)
    conj_graph.default_context = graph  # TODO: CG __init__ should have a
    # default_context arg
    # TODO: update N3Processor so that it can use conj_graph as the sink
    conj_graph.namespace_manager = graph.namespace_manager

    TurtleParser.parse(self, source, conj_graph, encoding, turtle=False)

RDFSink

RDFSink(graph: Graph)

Methods:

Attributes:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(self, graph: Graph):
    self.rootFormula: Optional[Formula] = None
    self.uuid = uuid4().hex
    self.counter = 0
    self.graph = graph

counter instance-attribute

counter = 0

graph instance-attribute

graph = graph

rootFormula instance-attribute

rootFormula: Optional[Formula] = None

uuid instance-attribute

uuid = hex

bind

bind(pfx, uri) -> None
Source code in rdflib/plugins/parsers/notation3.py
def bind(self, pfx, uri) -> None:
    pass  # print pfx, ':', uri

endDoc

endDoc(formula: Optional[Formula]) -> None
Source code in rdflib/plugins/parsers/notation3.py
def endDoc(self, formula: Optional[Formula]) -> None:
    pass

intern

intern(something: _AnyT) -> _AnyT
Source code in rdflib/plugins/parsers/notation3.py
def intern(self, something: _AnyT) -> _AnyT:
    return something

makeStatement

makeStatement(quadruple: Tuple[Optional[Union[Formula, Graph]], Node, Node, Node], why: Optional[Any] = None) -> None
Source code in rdflib/plugins/parsers/notation3.py
def makeStatement(
    self,
    quadruple: Tuple[Optional[Union[Formula, Graph]], Node, Node, Node],
    why: Optional[Any] = None,
) -> None:
    f, p, s, o = quadruple

    if hasattr(p, "formula"):
        raise ParserError("Formula used as predicate")

    # type error: Argument 1 to "normalise" of "RDFSink" has incompatible type "Union[Formula, Graph, None]"; expected "Optional[Formula]"
    s = self.normalise(f, s)  # type: ignore[arg-type]
    p = self.normalise(f, p)  # type: ignore[arg-type]
    o = self.normalise(f, o)  # type: ignore[arg-type]

    if f == self.rootFormula:
        # print s, p, o, '.'
        self.graph.add((s, p, o))
    elif isinstance(f, Formula):
        f.quotedgraph.add((s, p, o))
    else:
        # type error: Item "None" of "Optional[Graph]" has no attribute "add"
        f.add((s, p, o))  # type: ignore[union-attr]

newBlankNode

newBlankNode(arg: Optional[Union[Formula, Graph, Any]] = None, uri: Optional[str] = None, why: Optional[Callable[[], None]] = None) -> BNode
Source code in rdflib/plugins/parsers/notation3.py
def newBlankNode(
    self,
    arg: Optional[Union[Formula, Graph, Any]] = None,
    uri: Optional[str] = None,
    why: Optional[Callable[[], None]] = None,
) -> BNode:
    if isinstance(arg, Formula):
        return arg.newBlankNode(uri)
    elif isinstance(arg, Graph) or arg is None:
        self.counter += 1
        bn = BNode("n%sb%s" % (self.uuid, self.counter))
    else:
        bn = BNode(str(arg[0]).split("#").pop().replace("_", "b"))
    return bn

newFormula

newFormula() -> Formula
Source code in rdflib/plugins/parsers/notation3.py
def newFormula(self) -> Formula:
    fa = getattr(self.graph.store, "formula_aware", False)
    if not fa:
        raise ParserError(
            "Cannot create formula parser with non-formula-aware store."
        )
    f = Formula(self.graph)
    return f

newGraph

newGraph(identifier: Identifier) -> Graph
Source code in rdflib/plugins/parsers/notation3.py
def newGraph(self, identifier: Identifier) -> Graph:
    return Graph(self.graph.store, identifier)

newList

newList(n: List[Any], f: Optional[Formula]) -> IdentifiedNode
Source code in rdflib/plugins/parsers/notation3.py
def newList(self, n: typing.List[Any], f: Optional[Formula]) -> IdentifiedNode:
    nil = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil")
    if not n:
        return nil

    first = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#first")
    rest = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest")
    af = a = self.newBlankNode(f)

    for ne in n[:-1]:
        self.makeStatement((f, first, a, ne))
        an = self.newBlankNode(f)
        self.makeStatement((f, rest, a, an))
        a = an
    self.makeStatement((f, first, a, n[-1]))
    self.makeStatement((f, rest, a, nil))
    return af

newLiteral

newLiteral(s: str, dt: Optional[URIRef], lang: Optional[str]) -> Literal
Source code in rdflib/plugins/parsers/notation3.py
def newLiteral(self, s: str, dt: Optional[URIRef], lang: Optional[str]) -> Literal:
    if dt:
        return Literal(s, datatype=dt)
    else:
        return Literal(s, lang=lang)

newSet

newSet(*args: _AnyT) -> Set[_AnyT]
Source code in rdflib/plugins/parsers/notation3.py
def newSet(self, *args: _AnyT) -> Set[_AnyT]:
    return set(args)

newSymbol

newSymbol(*args: str) -> URIRef
Source code in rdflib/plugins/parsers/notation3.py
def newSymbol(self, *args: str) -> URIRef:
    return URIRef(args[0])

normalise

normalise(f: Optional[Formula], n: Union[Tuple[int, str], bool, int, Decimal, sfloat, _AnyT]) -> Union[URIRef, Literal, BNode, _AnyT]
Source code in rdflib/plugins/parsers/notation3.py
def normalise(
    self,
    f: Optional[Formula],
    n: Union[Tuple[int, str], bool, int, Decimal, sfloat, _AnyT],
) -> Union[URIRef, Literal, BNode, _AnyT]:
    if isinstance(n, tuple):
        return URIRef(str(n[1]))

    if isinstance(n, bool):
        s = Literal(str(n).lower(), datatype=BOOLEAN_DATATYPE)
        return s

    if isinstance(n, int) or isinstance(n, long_type):
        s = Literal(str(n), datatype=INTEGER_DATATYPE)
        return s

    if isinstance(n, Decimal):
        value = str(n)
        if value == "-0":
            value = "0"
        s = Literal(value, datatype=DECIMAL_DATATYPE)
        return s

    if isinstance(n, sfloat):
        s = Literal(str(n), datatype=DOUBLE_DATATYPE)
        return s

    if isinstance(f, Formula):
        if n in f.existentials:
            if TYPE_CHECKING:
                assert isinstance(n, URIRef)
            return f.existentials[n]

    # if isinstance(n, Var):
    #    if f.universals.has_key(n):
    #       return f.universals[n]
    #    f.universals[n] = f.newBlankNode()
    #    return f.universals[n]
    # type error: Incompatible return value type (got "Union[int, _AnyT]", expected "Union[URIRef, Literal, BNode, _AnyT]")  [return-value]
    return n

setDefaultNamespace

setDefaultNamespace(*args: bytes) -> str
Source code in rdflib/plugins/parsers/notation3.py
def setDefaultNamespace(self, *args: bytes) -> str:
    return ":".join(repr(n) for n in args)

startDoc

startDoc(formula: Optional[Formula]) -> None
Source code in rdflib/plugins/parsers/notation3.py
def startDoc(self, formula: Optional[Formula]) -> None:
    self.rootFormula = formula

SinkParser

SinkParser(store: RDFSink, openFormula: Optional[Formula] = None, thisDoc: str = '', baseURI: Optional[str] = None, genPrefix: str = '', why: Optional[Callable[[], None]] = None, turtle: bool = False)

Methods:

Attributes:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(
    self,
    store: RDFSink,
    openFormula: Optional[Formula] = None,
    thisDoc: str = "",
    baseURI: Optional[str] = None,
    genPrefix: str = "",
    why: Optional[Callable[[], None]] = None,
    turtle: bool = False,
):
    """note: namespace names should *not* end in  # ;
    the  # will get added during qname processing"""

    self._bindings = {}
    if thisDoc != "":
        assert ":" in thisDoc, "Document URI not absolute: <%s>" % thisDoc
        self._bindings[""] = thisDoc + "#"  # default

    self._store = store
    if genPrefix:
        # TODO FIXME: there is no function named setGenPrefix
        store.setGenPrefix(genPrefix)  # type: ignore[attr-defined] # pass it on

    self._thisDoc = thisDoc
    self.lines = 0  # for error handling
    self.startOfLine = 0  # For calculating character number
    self._genPrefix = genPrefix
    self.keywords = ["a", "this", "bind", "has", "is", "of", "true", "false"]
    self.keywordsSet = 0  # Then only can others be considered qnames
    self._anonymousNodes: Dict[str, BNode] = {}
    # Dict of anon nodes already declared ln: Term
    self._variables: Dict[str, Variable] = {}
    self._parentVariables: Dict[str, Variable] = {}
    self._reason = why  # Why the parser was asked to parse this

    self.turtle = turtle  # raise exception when encountering N3 extensions
    # Turtle allows single or double quotes around strings, whereas N3
    # only allows double quotes.
    self.string_delimiters = ('"', "'") if turtle else ('"',)

    self._reason2: Optional[Callable[..., None]] = None  # Why these triples
    # was: diag.tracking
    if tracking:
        # type error: "BecauseOfData" does not return a value
        self._reason2 = BecauseOfData(  # type: ignore[func-returns-value]
            store.newSymbol(thisDoc), because=self._reason
        )

    self._baseURI: Optional[str]
    if baseURI:
        self._baseURI = baseURI
    else:
        if thisDoc:
            self._baseURI = thisDoc
        else:
            self._baseURI = None

    assert not self._baseURI or ":" in self._baseURI

    if not self._genPrefix:
        if self._thisDoc:
            self._genPrefix = self._thisDoc + "#_g"
        else:
            self._genPrefix = uniqueURI()

    self._formula: Optional[Formula]
    if openFormula is None and not turtle:
        if self._thisDoc:
            # TODO FIXME: store.newFormula does not take any arguments
            self._formula = store.newFormula(thisDoc + "#_formula")  # type: ignore[call-arg]
        else:
            self._formula = store.newFormula()
    else:
        self._formula = openFormula

    self._context: Optional[Formula] = self._formula
    self._parentContext: Optional[Formula] = None

keywords instance-attribute

keywords = ['a', 'this', 'bind', 'has', 'is', 'of', 'true', 'false']

keywordsSet instance-attribute

keywordsSet = 0

lines instance-attribute

lines = 0

startOfLine instance-attribute

startOfLine = 0

string_delimiters instance-attribute

string_delimiters = ('"', "'") if turtle else ('"',)

turtle instance-attribute

turtle = turtle

BadSyntax

BadSyntax(argstr: str, i: int, msg: str) -> NoReturn
Source code in rdflib/plugins/parsers/notation3.py
def BadSyntax(self, argstr: str, i: int, msg: str) -> NoReturn:
    raise BadSyntax(self._thisDoc, self.lines, argstr, i, msg)

UEscape

UEscape(argstr: str, i: int, startline: int) -> Tuple[int, str]
Source code in rdflib/plugins/parsers/notation3.py
def UEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]:
    return self._unicodeEscape(argstr, i, startline, unicodeEscape8, 8, "U")

anonymousNode

anonymousNode(ln: str) -> BNode

Remember or generate a term for one of these _: anonymous nodes

Source code in rdflib/plugins/parsers/notation3.py
def anonymousNode(self, ln: str) -> BNode:
    """Remember or generate a term for one of these _: anonymous nodes"""
    term = self._anonymousNodes.get(ln, None)
    if term is not None:
        return term
    term = self._store.newBlankNode(self._context, why=self._reason2)
    self._anonymousNodes[ln] = term
    return term

bareWord

bareWord(argstr: str, i: int, res: MutableSequence[Any]) -> int

abc -> :abc

Source code in rdflib/plugins/parsers/notation3.py
def bareWord(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    """abc -> :abc"""
    j = self.skipSpace(argstr, i)
    if j < 0:
        return -1

    if argstr[j] in numberChars or argstr[j] in _notKeywordsChars:
        return -1
    i = j
    len_argstr = len(argstr)
    while i < len_argstr and argstr[i] not in _notKeywordsChars:
        i += 1
    res.append(argstr[j:i])
    return i

bind

bind(qn: str, uri: bytes) -> None
Source code in rdflib/plugins/parsers/notation3.py
def bind(self, qn: str, uri: bytes) -> None:
    assert isinstance(uri, bytes), "Any unicode must be %x-encoded already"
    if qn == "":
        self._store.setDefaultNamespace(uri)
    else:
        self._store.bind(qn, uri)

blankNode

blankNode(uri: Optional[str] = None) -> BNode
Source code in rdflib/plugins/parsers/notation3.py
def blankNode(self, uri: Optional[str] = None) -> BNode:
    return self._store.newBlankNode(self._context, uri, why=self._reason2)

checkDot

checkDot(argstr: str, i: int) -> int
Source code in rdflib/plugins/parsers/notation3.py
def checkDot(self, argstr: str, i: int) -> int:
    j = self.skipSpace(argstr, i)
    if j < 0:
        return j  # eof
    ch = argstr[j]
    if ch == ".":
        return j + 1  # skip
    if ch == "}":
        return j  # don't skip it
    if ch == "]":
        return j
    self.BadSyntax(argstr, j, "expected '.' or '}' or ']' at end of statement")

commaSeparatedList

commaSeparatedList(argstr: str, j: int, res: MutableSequence[Any], what: Callable[[str, int, MutableSequence[Any]], int]) -> int

return value: -1 bad syntax; >1 new position in argstr res has things found appended

Source code in rdflib/plugins/parsers/notation3.py
def commaSeparatedList(
    self,
    argstr: str,
    j: int,
    res: MutableSequence[Any],
    what: Callable[[str, int, MutableSequence[Any]], int],
) -> int:
    """return value: -1 bad syntax; >1 new position in argstr
    res has things found appended
    """
    i = self.skipSpace(argstr, j)
    if i < 0:
        self.BadSyntax(argstr, i, "EOF found expecting comma sep list")
    if argstr[i] == ".":
        return j  # empty list is OK
    i = what(argstr, i, res)
    if i < 0:
        return -1

    while 1:
        j = self.skipSpace(argstr, i)
        if j < 0:
            return j  # eof
        ch = argstr[j]
        if ch != ",":
            if ch != ".":
                return -1
            return j  # Found  but not swallowed "."
        i = what(argstr, j + 1, res)
        if i < 0:
            self.BadSyntax(argstr, i, "bad list content")

directive

directive(argstr: str, i: int) -> int
Source code in rdflib/plugins/parsers/notation3.py
def directive(self, argstr: str, i: int) -> int:
    j = self.skipSpace(argstr, i)
    if j < 0:
        return j  # eof
    res: typing.List[str] = []

    j = self.tok("bind", argstr, i)  # implied "#". Obsolete.
    if j > 0:
        self.BadSyntax(argstr, i, "keyword bind is obsolete: use @prefix")

    j = self.tok("keywords", argstr, i)
    if j > 0:
        if self.turtle:
            self.BadSyntax(argstr, i, "Found 'keywords' when in Turtle mode.")

        i = self.commaSeparatedList(argstr, j, res, self.bareWord)
        if i < 0:
            self.BadSyntax(
                argstr, i, "'@keywords' needs comma separated list of words"
            )
        self.setKeywords(res[:])
        return i

    j = self.tok("forAll", argstr, i)
    if j > 0:
        if self.turtle:
            self.BadSyntax(argstr, i, "Found 'forAll' when in Turtle mode.")

        i = self.commaSeparatedList(argstr, j, res, self.uri_ref2)
        if i < 0:
            self.BadSyntax(argstr, i, "Bad variable list after @forAll")
        for x in res:
            # self._context.declareUniversal(x)
            if x not in self._variables or x in self._parentVariables:
                # type error: Item "None" of "Optional[Formula]" has no attribute "newUniversal"
                self._variables[x] = self._context.newUniversal(x)  # type: ignore[union-attr]
        return i

    j = self.tok("forSome", argstr, i)
    if j > 0:
        if self.turtle:
            self.BadSyntax(argstr, i, "Found 'forSome' when in Turtle mode.")

        i = self.commaSeparatedList(argstr, j, res, self.uri_ref2)
        if i < 0:
            self.BadSyntax(argstr, i, "Bad variable list after @forSome")
        for x in res:
            # type error: Item "None" of "Optional[Formula]" has no attribute "declareExistential"
            self._context.declareExistential(x)  # type: ignore[union-attr]
        return i

    j = self.tok("prefix", argstr, i, colon=True)  # no implied "#"
    if j >= 0:
        t: typing.List[Union[Identifier, Tuple[str, str]]] = []
        i = self.qname(argstr, j, t)
        if i < 0:
            self.BadSyntax(argstr, j, "expected qname after @prefix")
        j = self.uri_ref2(argstr, i, t)
        if j < 0:
            self.BadSyntax(argstr, i, "expected <uriref> after @prefix _qname_")
        ns: str = self.uriOf(t[1])

        if self._baseURI:
            ns = join(self._baseURI, ns)
        elif ":" not in ns:
            self.BadSyntax(
                argstr,
                j,
                f"With no base URI, cannot use relative URI in @prefix <{ns}>",
            )
        assert ":" in ns  # must be absolute
        self._bindings[t[0][0]] = ns
        self.bind(t[0][0], hexify(ns))
        return j

    j = self.tok("base", argstr, i)  # Added 2007/7/7
    if j >= 0:
        t = []
        i = self.uri_ref2(argstr, j, t)
        if i < 0:
            self.BadSyntax(argstr, j, "expected <uri> after @base ")
        ns = self.uriOf(t[0])

        if self._baseURI:
            ns = join(self._baseURI, ns)
        else:
            self.BadSyntax(
                argstr,
                j,
                "With no previous base URI, cannot use "
                + "relative URI in @base  <"
                + ns
                + ">",
            )
        assert ":" in ns  # must be absolute
        self._baseURI = ns
        return i

    return -1  # Not a directive, could be something else.

directiveOrStatement

directiveOrStatement(argstr: str, h: int) -> int
Source code in rdflib/plugins/parsers/notation3.py
def directiveOrStatement(self, argstr: str, h: int) -> int:
    i = self.skipSpace(argstr, h)
    if i < 0:
        return i  # EOF

    if self.turtle:
        j = self.sparqlDirective(argstr, i)
        if j >= 0:
            return j

    j = self.directive(argstr, i)
    if j >= 0:
        return self.checkDot(argstr, j)

    j = self.statement(argstr, i)
    if j >= 0:
        return self.checkDot(argstr, j)

    return j

endDoc

endDoc() -> Optional[Formula]

Signal end of document and stop parsing. returns formula

Source code in rdflib/plugins/parsers/notation3.py
def endDoc(self) -> Optional[Formula]:
    """Signal end of document and stop parsing. returns formula"""
    self._store.endDoc(self._formula)  # don't canonicalize yet
    return self._formula

feed

feed(octets: Union[str, bytes]) -> None

Feed an octet stream to the parser

if BadSyntax is raised, the string passed in the exception object is the remainder after any statements have been parsed. So if there is more data to feed to the parser, it should be straightforward to recover.

Source code in rdflib/plugins/parsers/notation3.py
def feed(self, octets: Union[str, bytes]) -> None:
    """Feed an octet stream to the parser

    if BadSyntax is raised, the string
    passed in the exception object is the
    remainder after any statements have been parsed.
    So if there is more data to feed to the
    parser, it should be straightforward to recover."""

    if not isinstance(octets, str):
        s = octets.decode("utf-8")
        # NB already decoded, so \ufeff
        if len(s) > 0 and s[0] == codecs.BOM_UTF8.decode("utf-8"):
            s = s[1:]
    else:
        s = octets

    i = 0
    while i >= 0:
        j = self.skipSpace(s, i)
        if j < 0:
            return

        i = self.directiveOrStatement(s, j)
        if i < 0:
            # print("# next char: %s" % s[j])
            self.BadSyntax(s, j, "expected directive or statement")

formula

formula() -> Optional[Formula]
Source code in rdflib/plugins/parsers/notation3.py
def formula(self) -> Optional[Formula]:
    return self._formula

here

here(i: int) -> str

String generated from position in file

This is for repeatability when referring people to bnodes in a document. This has diagnostic uses less formally, as it should point one to which bnode the arbitrary identifier actually is. It gives the line and character number of the ‘[’ charcacter or path character which introduced the blank node. The first blank node is boringly _L1C1. It used to be used only for tracking, but for tests in general it makes the canonical ordering of bnodes repeatable.

Source code in rdflib/plugins/parsers/notation3.py
def here(self, i: int) -> str:
    """String generated from position in file

    This is for repeatability when referring people to bnodes in a document.
    This has diagnostic uses less formally, as it should point one to which
    bnode the arbitrary identifier actually is. It gives the
    line and character number of the '[' charcacter or path character
    which introduced the blank node. The first blank node is boringly
    _L1C1. It used to be used only for tracking, but for tests in general
    it makes the canonical ordering of bnodes repeatable."""

    return "%s_L%iC%i" % (self._genPrefix, self.lines, i - self.startOfLine + 1)

item

item(argstr: str, i, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def item(self, argstr: str, i, res: MutableSequence[Any]) -> int:
    return self.path(argstr, i, res)

loadBuf

loadBuf(buf: Union[str, bytes]) -> Optional[Formula]

Parses a buffer and returns its top level formula

Source code in rdflib/plugins/parsers/notation3.py
def loadBuf(self, buf: Union[str, bytes]) -> Optional[Formula]:
    """Parses a buffer and returns its top level formula"""
    self.startDoc()

    self.feed(buf)
    return self.endDoc()  # self._formula

loadStream

loadStream(stream: Union[IO[str], IO[bytes]]) -> Optional[Formula]
Source code in rdflib/plugins/parsers/notation3.py
def loadStream(self, stream: Union[IO[str], IO[bytes]]) -> Optional[Formula]:
    return self.loadBuf(stream.read())  # Not ideal

makeStatement

makeStatement(quadruple) -> None
Source code in rdflib/plugins/parsers/notation3.py
def makeStatement(self, quadruple) -> None:
    # $$$$$$$$$$$$$$$$$$$$$
    # print "# Parser output: ", `quadruple`
    self._store.makeStatement(quadruple, why=self._reason2)

node

node(argstr: str, i: int, res: MutableSequence[Any], subjectAlready: Optional[Node] = None) -> int

Parse the production. Space is now skipped once at the beginning instead of in multiple calls to self.skipSpace().

Source code in rdflib/plugins/parsers/notation3.py
def node(
    self,
    argstr: str,
    i: int,
    res: MutableSequence[Any],
    subjectAlready: Optional[Node] = None,
) -> int:
    """Parse the <node> production.
    Space is now skipped once at the beginning
    instead of in multiple calls to self.skipSpace().
    """
    subj: Optional[Node] = subjectAlready

    j = self.skipSpace(argstr, i)
    if j < 0:
        return j  # eof
    i = j
    ch = argstr[i]  # Quick 1-character checks first:

    if ch == "[":
        bnodeID = self.here(i)
        j = self.skipSpace(argstr, i + 1)
        if j < 0:
            self.BadSyntax(argstr, i, "EOF after '['")
        # Hack for "is" binding name to anon node
        if argstr[j] == "=":
            if self.turtle:
                self.BadSyntax(
                    argstr, j, "Found '[=' or '[ =' when in turtle mode."
                )
            i = j + 1
            objs: typing.List[Node] = []
            j = self.objectList(argstr, i, objs)
            if j >= 0:
                subj = objs[0]
                if len(objs) > 1:
                    for obj in objs:
                        self.makeStatement((self._context, DAML_sameAs, subj, obj))
                j = self.skipSpace(argstr, j)
                if j < 0:
                    self.BadSyntax(
                        argstr, i, "EOF when objectList expected after [ = "
                    )
                if argstr[j] == ";":
                    j += 1
            else:
                self.BadSyntax(argstr, i, "objectList expected after [= ")

        if subj is None:
            subj = self.blankNode(uri=bnodeID)

        i = self.property_list(argstr, j, subj)
        if i < 0:
            self.BadSyntax(argstr, j, "property_list expected")

        j = self.skipSpace(argstr, i)
        if j < 0:
            self.BadSyntax(
                argstr, i, "EOF when ']' expected after [ <propertyList>"
            )
        if argstr[j] != "]":
            self.BadSyntax(argstr, j, "']' expected")
        res.append(subj)
        return j + 1

    if not self.turtle and ch == "{":
        # if self.turtle:
        #     self.BadSyntax(argstr, i,
        #                     "found '{' while in Turtle mode, Formulas not supported!")
        ch2 = argstr[i + 1]
        if ch2 == "$":
            # a set
            i += 1
            j = i + 1
            List = []
            first_run = True
            while 1:
                i = self.skipSpace(argstr, j)
                if i < 0:
                    self.BadSyntax(argstr, i, "needed '$}', found end.")
                if argstr[i : i + 2] == "$}":
                    j = i + 2
                    break

                if not first_run:
                    if argstr[i] == ",":
                        i += 1
                    else:
                        self.BadSyntax(argstr, i, "expected: ','")
                else:
                    first_run = False

                item: typing.List[Any] = []
                j = self.item(argstr, i, item)  # @@@@@ should be path, was object
                if j < 0:
                    self.BadSyntax(argstr, i, "expected item in set or '$}'")
                List.append(self._store.intern(item[0]))
            res.append(self._store.newSet(List, self._context))
            return j
        else:
            # parse a formula
            j = i + 1
            oldParentContext = self._parentContext
            self._parentContext = self._context
            parentAnonymousNodes = self._anonymousNodes
            grandParentVariables = self._parentVariables
            self._parentVariables = self._variables
            self._anonymousNodes = {}
            self._variables = self._variables.copy()
            reason2 = self._reason2
            self._reason2 = becauseSubexpression
            if subj is None:
                # type error: Incompatible types in assignment (expression has type "Formula", variable has type "Optional[Node]")
                subj = self._store.newFormula()  # type: ignore[assignment]
            # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Optional[Formula]")
            self._context = subj  # type: ignore[assignment]

            while 1:
                i = self.skipSpace(argstr, j)
                if i < 0:
                    self.BadSyntax(argstr, i, "needed '}', found end.")

                if argstr[i] == "}":
                    j = i + 1
                    break

                j = self.directiveOrStatement(argstr, i)
                if j < 0:
                    self.BadSyntax(argstr, i, "expected statement or '}'")

            self._anonymousNodes = parentAnonymousNodes
            self._variables = self._parentVariables
            self._parentVariables = grandParentVariables
            self._context = self._parentContext
            self._reason2 = reason2
            self._parentContext = oldParentContext
            # type error: Item "Node" of "Optional[Node]" has no attribute "close"
            res.append(
                subj.close()  # type: ignore[union-attr]
            )  # No use until closed
            return j

    if ch == "(":
        thing_type: Callable[
            [typing.List[Any], Optional[Formula]], Union[Set[Any], IdentifiedNode]
        ]
        thing_type = self._store.newList
        ch2 = argstr[i + 1]
        if ch2 == "$":
            thing_type = self._store.newSet
            i += 1
        j = i + 1

        List = []
        while 1:
            i = self.skipSpace(argstr, j)
            if i < 0:
                self.BadSyntax(argstr, i, "needed ')', found end.")
            if argstr[i] == ")":
                j = i + 1
                break

            item = []
            j = self.item(argstr, i, item)  # @@@@@ should be path, was object
            if j < 0:
                self.BadSyntax(argstr, i, "expected item in list or ')'")
            List.append(self._store.intern(item[0]))
        res.append(thing_type(List, self._context))
        return j

    j = self.tok("this", argstr, i)  # This context
    if j >= 0:
        self.BadSyntax(
            argstr,
            i,
            "Keyword 'this' was ancient N3. Now use "
            + "@forSome and @forAll keywords.",
        )

    # booleans
    j = self.tok("true", argstr, i)
    if j >= 0:
        res.append(True)
        return j
    j = self.tok("false", argstr, i)
    if j >= 0:
        res.append(False)
        return j

    if subj is None:  # If this can be a named node, then check for a name.
        j = self.uri_ref2(argstr, i, res)
        if j >= 0:
            return j

    return -1

nodeOrLiteral

nodeOrLiteral(argstr: str, i: int, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def nodeOrLiteral(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    j = self.node(argstr, i, res)
    startline = self.lines  # Remember where for error messages
    if j >= 0:
        return j
    else:
        j = self.skipSpace(argstr, i)
        if j < 0:
            return -1
        else:
            i = j

        ch = argstr[i]
        if ch in numberCharsPlus:
            m = exponent_syntax.match(argstr, i)
            if m:
                j = m.end()
                res.append(sfloat(argstr[i:j]))
                return j

            m = decimal_syntax.match(argstr, i)
            if m:
                j = m.end()
                res.append(Decimal(argstr[i:j]))
                return j

            m = integer_syntax.match(argstr, i)
            if m:
                j = m.end()
                res.append(long_type(argstr[i:j]))
                return j

            # return -1  ## or fall through?

        ch_three = ch * 3
        if ch in self.string_delimiters:
            if argstr[i : i + 3] == ch_three:
                delim = ch_three
                i += 3
            else:
                delim = ch
                i += 1

            dt = None
            j, s = self.strconst(argstr, i, delim)
            lang = None
            if argstr[j] == "@":  # Language?
                m = langcode.match(argstr, j + 1)
                if m is None:
                    raise BadSyntax(
                        self._thisDoc,
                        startline,
                        argstr,
                        i,
                        "Bad language code syntax on string " + "literal, after @",
                    )
                i = m.end()
                lang = argstr[j + 1 : i]
                j = i
            if argstr[j : j + 2] == "^^":
                res2: typing.List[Any] = []
                j = self.uri_ref2(argstr, j + 2, res2)  # Read datatype URI
                dt = res2[0]
            res.append(self._store.newLiteral(s, dt, lang))
            return j
        else:
            return -1

object

object(argstr: str, i: int, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def object(
    self,
    argstr: str,
    i: int,
    res: MutableSequence[Any],
) -> int:
    j = self.subject(argstr, i, res)
    if j >= 0:
        return j
    else:
        j = self.skipSpace(argstr, i)
        if j < 0:
            return -1
        else:
            i = j

        ch = argstr[i]
        if ch in self.string_delimiters:
            ch_three = ch * 3
            if argstr[i : i + 3] == ch_three:
                delim = ch_three
                i += 3
            else:
                delim = ch
                i += 1

            j, s = self.strconst(argstr, i, delim)

            res.append(self._store.newLiteral(s))  # type: ignore[call-arg] # TODO FIXME
            return j
        else:
            return -1

objectList

objectList(argstr: str, i: int, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def objectList(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    i = self.object(argstr, i, res)
    if i < 0:
        return -1
    while 1:
        j = self.skipSpace(argstr, i)
        if j < 0:
            self.BadSyntax(argstr, j, "EOF found after object")
        if argstr[j] != ",":
            return j  # Found something else!
        i = self.object(argstr, j + 1, res)
        if i < 0:
            return i

path

path(argstr: str, i: int, res: MutableSequence[Any]) -> int

Parse the path production.

Source code in rdflib/plugins/parsers/notation3.py
def path(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    """Parse the path production."""
    j = self.nodeOrLiteral(argstr, i, res)
    if j < 0:
        return j  # nope

    while argstr[j] in {"!", "^"}:  # no spaces, must follow exactly (?)
        ch = argstr[j]
        subj = res.pop()
        obj = self.blankNode(uri=self.here(j))
        j = self.node(argstr, j + 1, res)
        if j < 0:
            self.BadSyntax(argstr, j, "EOF found in middle of path syntax")
        pred = res.pop()
        if ch == "^":  # Reverse traverse
            self.makeStatement((self._context, pred, obj, subj))
        else:
            self.makeStatement((self._context, pred, subj, obj))
        res.append(obj)
    return j

prop

prop(argstr: str, i: int, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def prop(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    return self.item(argstr, i, res)

property_list

property_list(argstr: str, i: int, subj: Node) -> int

Parse property list Leaves the terminating punctuation in the buffer

Source code in rdflib/plugins/parsers/notation3.py
def property_list(self, argstr: str, i: int, subj: Node) -> int:
    """Parse property list
    Leaves the terminating punctuation in the buffer
    """
    while 1:
        while 1:  # skip repeat ;
            j = self.skipSpace(argstr, i)
            if j < 0:
                self.BadSyntax(
                    argstr, i, "EOF found when expected verb in property list"
                )
            if argstr[j] != ";":
                break
            i = j + 1

        if argstr[j : j + 2] == ":-":
            if self.turtle:
                self.BadSyntax(argstr, j, "Found in ':-' in Turtle mode")
            i = j + 2
            res: typing.List[Any] = []
            j = self.node(argstr, i, res, subj)
            if j < 0:
                self.BadSyntax(argstr, i, "bad {} or () or [] node after :- ")
            i = j
            continue
        i = j
        v: typing.List[Any] = []
        j = self.verb(argstr, i, v)
        if j <= 0:
            return i  # void but valid

        objs: typing.List[Any] = []
        i = self.objectList(argstr, j, objs)
        if i < 0:
            self.BadSyntax(argstr, j, "objectList expected")
        for obj in objs:
            dira, sym = v[0]
            if dira == "->":
                self.makeStatement((self._context, sym, subj, obj))
            else:
                self.makeStatement((self._context, sym, obj, subj))

        j = self.skipSpace(argstr, i)
        if j < 0:
            self.BadSyntax(argstr, j, "EOF found in list of objects")
        if argstr[i] != ";":
            return i
        i += 1  # skip semicolon and continue

qname

qname(argstr: str, i: int, res: MutableSequence[Union[Identifier, Tuple[str, str]]]) -> int

xyz:def -> (‘xyz’, ‘def’) If not in keywords and keywordsSet: def -> (‘’, ‘def’) :def -> (‘’, ‘def’)

Source code in rdflib/plugins/parsers/notation3.py
def qname(
    self,
    argstr: str,
    i: int,
    res: MutableSequence[Union[Identifier, Tuple[str, str]]],
) -> int:
    """
    xyz:def -> ('xyz', 'def')
    If not in keywords and keywordsSet: def -> ('', 'def')
    :def -> ('', 'def')
    """

    i = self.skipSpace(argstr, i)
    if i < 0:
        return -1

    c = argstr[i]
    if c in numberCharsPlus:
        return -1
    len_argstr = len(argstr)
    if c not in _notNameChars:
        j = i
        i += 1

        try:
            while argstr[i] not in _notNameChars:
                i += 1
        except IndexError:
            pass  # Very rare.

        if argstr[i - 1] == ".":  # qname cannot end with "."
            i -= 1
            if i == j:
                return -1
        ln = argstr[j:i]

    else:  # First character is non-alpha
        ln = ""  # Was:  None - TBL (why? useful?)

    if i < len_argstr and argstr[i] == ":":
        pfx = ln
        # bnodes names have different rules
        if pfx == "_":
            allowedChars = _notNameChars
        else:
            allowedChars = _notQNameChars

        i += 1
        lastslash = False
        start = i
        ln = ""
        while i < len_argstr:
            c = argstr[i]
            if c == "\\" and not lastslash:  # Very rare.
                lastslash = True
                if start < i:
                    ln += argstr[start:i]
                start = i + 1
            elif c not in allowedChars or lastslash:  # Most common case is "a-zA-Z"
                if lastslash:
                    if c not in escapeChars:
                        raise BadSyntax(
                            self._thisDoc,
                            self.lines,
                            argstr,
                            i,
                            "illegal escape " + c,
                        )
                elif c == "%":  # Very rare.
                    if (
                        argstr[i + 1] not in hexChars
                        or argstr[i + 2] not in hexChars
                    ):
                        raise BadSyntax(
                            self._thisDoc,
                            self.lines,
                            argstr,
                            i,
                            "illegal hex escape " + c,
                        )
                lastslash = False
            else:
                break
            i += 1

        if lastslash:
            raise BadSyntax(
                self._thisDoc, self.lines, argstr, i, "qname cannot end with \\"
            )

        if argstr[i - 1] == ".":
            # localname cannot end in .
            if len(ln) == 0 and start == i:
                return -1
            i -= 1

        if start < i:
            ln += argstr[start:i]

        res.append((pfx, ln))
        return i

    else:  # delimiter was not ":"
        if ln and self.keywordsSet and ln not in self.keywords:
            res.append(("", ln))
            return i
        return -1

setKeywords

setKeywords(k: Optional[List[str]]) -> None

Takes a list of strings

Source code in rdflib/plugins/parsers/notation3.py
def setKeywords(self, k: Optional[typing.List[str]]) -> None:
    """Takes a list of strings"""
    if k is None:
        self.keywordsSet = 0
    else:
        self.keywords = k
        self.keywordsSet = 1

skipSpace

skipSpace(argstr: str, i: int) -> int

Skip white space, newlines and comments. return -1 if EOF, else position of first non-ws character

Source code in rdflib/plugins/parsers/notation3.py
def skipSpace(self, argstr: str, i: int) -> int:
    """Skip white space, newlines and comments.
    return -1 if EOF, else position of first non-ws character"""

    # Most common case is a non-commented line starting with few spaces and tabs.
    try:
        while True:
            ch = argstr[i]
            if ch in {" ", "\t"}:
                i += 1
                continue
            elif ch not in {"#", "\r", "\n"}:
                return i
            break
    except IndexError:
        return -1

    while 1:
        m = eol.match(argstr, i)
        if m is None:
            break
        self.lines += 1
        self.startOfLine = i = m.end()  # Point to first character unmatched
    m = ws.match(argstr, i)
    if m is not None:
        i = m.end()
    m = eof.match(argstr, i)
    return i if m is None else -1

sparqlDirective

sparqlDirective(argstr: str, i: int) -> int

turtle and trig support BASE/PREFIX without @ and without terminating .

Source code in rdflib/plugins/parsers/notation3.py
def sparqlDirective(self, argstr: str, i: int) -> int:
    """
    turtle and trig support BASE/PREFIX without @ and without
    terminating .
    """

    j = self.skipSpace(argstr, i)
    if j < 0:
        return j  # eof

    j = self.sparqlTok("PREFIX", argstr, i)
    if j >= 0:
        t: typing.List[Any] = []
        i = self.qname(argstr, j, t)
        if i < 0:
            self.BadSyntax(argstr, j, "expected qname after @prefix")
        j = self.uri_ref2(argstr, i, t)
        if j < 0:
            self.BadSyntax(argstr, i, "expected <uriref> after @prefix _qname_")
        ns = self.uriOf(t[1])

        if self._baseURI:
            ns = join(self._baseURI, ns)
        elif ":" not in ns:
            self.BadSyntax(
                argstr,
                j,
                "With no base URI, cannot use "
                + "relative URI in @prefix <"
                + ns
                + ">",
            )
        assert ":" in ns  # must be absolute
        self._bindings[t[0][0]] = ns
        self.bind(t[0][0], hexify(ns))
        return j

    j = self.sparqlTok("BASE", argstr, i)
    if j >= 0:
        t = []
        i = self.uri_ref2(argstr, j, t)
        if i < 0:
            self.BadSyntax(argstr, j, "expected <uri> after @base ")
        ns = self.uriOf(t[0])

        if self._baseURI:
            ns = join(self._baseURI, ns)
        else:
            self.BadSyntax(
                argstr,
                j,
                "With no previous base URI, cannot use "
                + "relative URI in @base  <"
                + ns
                + ">",
            )
        assert ":" in ns  # must be absolute
        self._baseURI = ns
        return i

    return -1  # Not a directive, could be something else.

sparqlTok

sparqlTok(tok: str, argstr: str, i: int) -> int

Check for SPARQL keyword. Space must have been stripped on entry and we must not be at end of file. Case insensitive and not preceded by @

Source code in rdflib/plugins/parsers/notation3.py
def sparqlTok(self, tok: str, argstr: str, i: int) -> int:
    """Check for SPARQL keyword.  Space must have been stripped on entry
    and we must not be at end of file.
    Case insensitive and not preceded by @
    """

    assert tok[0] not in _notNameChars  # not for punctuation

    len_tok = len(tok)
    if argstr[i : i + len_tok].lower() == tok.lower() and (
        argstr[i + len_tok] in _notQNameChars
    ):
        i += len_tok
        return i
    else:
        return -1

startDoc

startDoc() -> None
Source code in rdflib/plugins/parsers/notation3.py
def startDoc(self) -> None:
    # was: self._store.startDoc()
    self._store.startDoc(self._formula)

statement

statement(argstr: str, i: int) -> int
Source code in rdflib/plugins/parsers/notation3.py
def statement(self, argstr: str, i: int) -> int:
    r: typing.List[Any] = []
    i = self.object(argstr, i, r)  # Allow literal for subject - extends RDF
    if i < 0:
        return i

    j = self.property_list(argstr, i, r[0])

    if j < 0:
        self.BadSyntax(argstr, i, "expected propertylist")
    return j

strconst

strconst(argstr: str, i: int, delim: str) -> Tuple[int, str]

parse an N3 string constant delimited by delim. return index, val

Source code in rdflib/plugins/parsers/notation3.py
def strconst(self, argstr: str, i: int, delim: str) -> Tuple[int, str]:
    """parse an N3 string constant delimited by delim.
    return index, val
    """
    delim1 = delim[0]
    delim2, delim3, delim4, delim5 = delim1 * 2, delim1 * 3, delim1 * 4, delim1 * 5

    j = i
    ustr = ""  # Empty unicode string
    startline = self.lines  # Remember where for error messages
    len_argstr = len(argstr)
    while j < len_argstr:
        if argstr[j] == delim1:
            if delim == delim1:  # done when delim is " or '
                i = j + 1
                return i, ustr
            if (
                delim == delim3
            ):  # done when delim is """ or ''' and, respectively ...
                if argstr[j : j + 5] == delim5:  # ... we have "" or '' before
                    i = j + 5
                    ustr += delim2
                    return i, ustr
                if argstr[j : j + 4] == delim4:  # ... we have " or ' before
                    i = j + 4
                    ustr += delim1
                    return i, ustr
                if argstr[j : j + 3] == delim3:  # current " or ' is part of delim
                    i = j + 3
                    return i, ustr

                # we are inside of the string and current char is " or '
                j += 1
                ustr += delim1
                continue

        m = interesting.search(argstr, j)  # was argstr[j:].
        # Note for pos param to work, MUST be compiled  ... re bug?
        assert m, "Quote expected in string at ^ in %s^%s" % (
            argstr[j - 20 : j],
            argstr[j : j + 20],
        )  # at least need a quote

        i = m.start()
        try:
            ustr += argstr[j:i]
        except UnicodeError:
            err = ""
            for c in argstr[j:i]:
                err = err + (" %02x" % ord(c))
            streason = sys.exc_info()[1].__str__()
            raise BadSyntax(
                self._thisDoc,
                startline,
                argstr,
                j,
                "Unicode error appending characters"
                + " %s to string, because\n\t%s" % (err, streason),
            )

        # print "@@@ i = ",i, " j=",j, "m.end=", m.end()

        ch = argstr[i]
        if ch == delim1:
            j = i
            continue
        elif ch in {'"', "'"} and ch != delim1:
            ustr += ch
            j = i + 1
            continue
        elif ch in {"\r", "\n"}:
            if delim == delim1:
                raise BadSyntax(
                    self._thisDoc,
                    startline,
                    argstr,
                    i,
                    "newline found in string literal",
                )
            self.lines += 1
            ustr += ch
            j = i + 1
            self.startOfLine = j

        elif ch == "\\":
            j = i + 1
            ch = argstr[j]  # Will be empty if string ends
            if not ch:
                raise BadSyntax(
                    self._thisDoc,
                    startline,
                    argstr,
                    i,
                    "unterminated string literal (2)",
                )
            k = "abfrtvn\\\"'".find(ch)
            if k >= 0:
                uch = "\a\b\f\r\t\v\n\\\"'"[k]
                ustr += uch
                j += 1
            elif ch == "u":
                j, ch = self.uEscape(argstr, j + 1, startline)
                ustr += ch
            elif ch == "U":
                j, ch = self.UEscape(argstr, j + 1, startline)
                ustr += ch
            else:
                self.BadSyntax(argstr, i, "bad escape")

    self.BadSyntax(argstr, i, "unterminated string literal")

subject

subject(argstr: str, i: int, res: MutableSequence[Any]) -> int
Source code in rdflib/plugins/parsers/notation3.py
def subject(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    return self.item(argstr, i, res)

tok

tok(tok: str, argstr: str, i: int, colon: bool = False) -> int

Check for keyword. Space must have been stripped on entry and we must not be at end of file.

if colon, then keyword followed by colon is ok (@prefix:<blah> is ok, rdf:type shortcut a must be followed by ws)

Source code in rdflib/plugins/parsers/notation3.py
def tok(self, tok: str, argstr: str, i: int, colon: bool = False) -> int:
    """Check for keyword.  Space must have been stripped on entry and
    we must not be at end of file.

    if colon, then keyword followed by colon is ok
    (`@prefix:<blah>` is ok, rdf:type shortcut a must be followed by ws)
    """

    assert tok[0] not in _notNameChars  # not for punctuation
    if argstr[i] == "@":
        i += 1
    else:
        if tok not in self.keywords:
            return -1  # No, this has neither keywords declaration nor "@"

    i_plus_len_tok = i + len(tok)
    if (
        argstr[i:i_plus_len_tok] == tok
        and (argstr[i_plus_len_tok] in _notKeywordsChars)
        or (colon and argstr[i_plus_len_tok] == ":")
    ):
        return i_plus_len_tok
    else:
        return -1

uEscape

uEscape(argstr: str, i: int, startline: int) -> Tuple[int, str]
Source code in rdflib/plugins/parsers/notation3.py
def uEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]:
    return self._unicodeEscape(argstr, i, startline, unicodeEscape4, 4, "u")

uriOf

uriOf(sym: Union[Identifier, Tuple[str, str]]) -> str
Source code in rdflib/plugins/parsers/notation3.py
def uriOf(self, sym: Union[Identifier, Tuple[str, str]]) -> str:
    if isinstance(sym, tuple):
        return sym[1]  # old system for --pipe
    # return sym.uriref()  # cwm api
    return sym

uri_ref2

uri_ref2(argstr: str, i: int, res: MutableSequence[Any]) -> int

Generate uri from n3 representation.

Note that the RDF convention of directly concatenating NS and local name is now used though I prefer inserting a ‘#’ to make the namesapces look more like what XML folks expect.

Source code in rdflib/plugins/parsers/notation3.py
def uri_ref2(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    """Generate uri from n3 representation.

    Note that the RDF convention of directly concatenating
    NS and local name is now used though I prefer inserting a '#'
    to make the namesapces look more like what XML folks expect.
    """
    qn: typing.List[Any] = []
    j = self.qname(argstr, i, qn)
    if j >= 0:
        pfx, ln = qn[0]
        if pfx is None:
            assert 0, "not used?"
            ns = self._baseURI + ADDED_HASH  # type: ignore[unreachable]
        else:
            try:
                ns = self._bindings[pfx]
            except KeyError:
                if pfx == "_":  # Magic prefix 2001/05/30, can be changed
                    res.append(self.anonymousNode(ln))
                    return j
                if not self.turtle and pfx == "":
                    ns = join(self._baseURI or "", "#")
                else:
                    self.BadSyntax(argstr, i, 'Prefix "%s:" not bound' % (pfx))
        symb = self._store.newSymbol(ns + ln)
        res.append(self._variables.get(symb, symb))
        return j

    i = self.skipSpace(argstr, i)
    if i < 0:
        return -1

    if argstr[i] == "?":
        v: typing.List[Any] = []
        j = self.variable(argstr, i, v)
        if j > 0:  # Forget variables as a class, only in context.
            res.append(v[0])
            return j
        return -1

    elif argstr[i] == "<":
        st = i + 1
        i = argstr.find(">", st)
        if i >= 0:
            uref = argstr[st:i]  # the join should dealt with "":

            # expand unicode escapes
            uref = unicodeEscape8.sub(unicodeExpand, uref)
            uref = unicodeEscape4.sub(unicodeExpand, uref)

            if self._baseURI:
                uref = join(self._baseURI, uref)  # was: uripath.join
            else:
                assert (
                    ":" in uref
                ), "With no base URI, cannot deal with relative URIs"
            if argstr[i - 1] == "#" and not uref[-1:] == "#":
                uref += "#"  # She meant it! Weirdness in urlparse?
            symb = self._store.newSymbol(uref)
            res.append(self._variables.get(symb, symb))
            return i + 1
        self.BadSyntax(argstr, j, "unterminated URI reference")

    elif self.keywordsSet:
        v = []
        j = self.bareWord(argstr, i, v)
        if j < 0:
            return -1  # Forget variables as a class, only in context.
        if v[0] in self.keywords:
            self.BadSyntax(argstr, i, 'Keyword "%s" not allowed here.' % v[0])
        res.append(self._store.newSymbol(self._bindings[""] + v[0]))
        return j
    else:
        return -1

variable

variable(argstr: str, i: int, res) -> int

?abc -> variable(:abc)

Source code in rdflib/plugins/parsers/notation3.py
def variable(self, argstr: str, i: int, res) -> int:
    """?abc -> variable(:abc)"""

    j = self.skipSpace(argstr, i)
    if j < 0:
        return -1

    if argstr[j] != "?":
        return -1
    j += 1
    i = j
    if argstr[j] in numberChars:
        self.BadSyntax(argstr, j, "Variable name can't start with '%s'" % argstr[j])
    len_argstr = len(argstr)
    while i < len_argstr and argstr[i] not in _notKeywordsChars:
        i += 1
    if self._parentContext is None:
        varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i])  # type: ignore[operator]
        if varURI not in self._variables:
            # type error: Item "None" of "Optional[Formula]" has no attribute "newUniversal"
            self._variables[varURI] = self._context.newUniversal(  # type: ignore[union-attr]
                varURI, why=self._reason2
            )
        res.append(self._variables[varURI])
        return i
        # @@ was:
        # self.BadSyntax(argstr, j,
        #     "Can't use ?xxx syntax for variable in outermost level: %s"
        #     % argstr[j-1:i])
    varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i])  # type: ignore[operator]
    if varURI not in self._parentVariables:
        self._parentVariables[varURI] = self._parentContext.newUniversal(
            varURI, why=self._reason2
        )
    res.append(self._parentVariables[varURI])
    return i

verb

verb(argstr: str, i: int, res: MutableSequence[Any]) -> int

has prop is prop of a = prop

  • prop -> <- prop -< operator
Source code in rdflib/plugins/parsers/notation3.py
def verb(self, argstr: str, i: int, res: MutableSequence[Any]) -> int:
    """has _prop_
    is _prop_ of
    a
    =
    _prop_
    >- prop ->
    <- prop -<
    _operator_"""

    j = self.skipSpace(argstr, i)
    if j < 0:
        return j  # eof

    r: typing.List[Any] = []

    j = self.tok("has", argstr, i)
    if j >= 0:
        if self.turtle:
            self.BadSyntax(argstr, i, "Found 'has' keyword in Turtle mode")

        i = self.prop(argstr, j, r)
        if i < 0:
            self.BadSyntax(argstr, j, "expected property after 'has'")
        res.append(("->", r[0]))
        return i

    j = self.tok("is", argstr, i)
    if j >= 0:
        if self.turtle:
            self.BadSyntax(argstr, i, "Found 'is' keyword in Turtle mode")

        i = self.prop(argstr, j, r)
        if i < 0:
            self.BadSyntax(argstr, j, "expected <property> after 'is'")
        j = self.skipSpace(argstr, i)
        if j < 0:
            self.BadSyntax(
                argstr, i, "End of file found, expected property after 'is'"
            )
        i = j
        j = self.tok("of", argstr, i)
        if j < 0:
            self.BadSyntax(argstr, i, "expected 'of' after 'is' <prop>")
        res.append(("<-", r[0]))
        return j

    j = self.tok("a", argstr, i)
    if j >= 0:
        res.append(("->", RDF_type))
        return j

    if argstr[i : i + 2] == "<=":
        if self.turtle:
            self.BadSyntax(argstr, i, "Found '<=' in Turtle mode. ")

        res.append(("<-", self._store.newSymbol(Logic_NS + "implies")))
        return i + 2

    if argstr[i] == "=":
        if self.turtle:
            self.BadSyntax(argstr, i, "Found '=' in Turtle mode")
        if argstr[i + 1] == ">":
            res.append(("->", self._store.newSymbol(Logic_NS + "implies")))
            return i + 2
        res.append(("->", DAML_sameAs))
        return i + 1

    if argstr[i : i + 2] == ":=":
        if self.turtle:
            self.BadSyntax(argstr, i, "Found ':=' in Turtle mode")

        # patch file relates two formulae, uses this    @@ really?
        res.append(("->", Logic_NS + "becomes"))
        return i + 2

    j = self.prop(argstr, i, r)
    if j >= 0:
        res.append(("->", r[0]))
        return j

    if argstr[i : i + 2] == ">-" or argstr[i : i + 2] == "<-":
        self.BadSyntax(argstr, j, ">- ... -> syntax is obsolete.")

    return -1

TurtleParser

TurtleParser()

Bases: Parser

An RDFLib parser for Turtle

See http://www.w3.org/TR/turtle/

Methods:

Source code in rdflib/plugins/parsers/notation3.py
def __init__(self):
    pass

parse

parse(source: InputSource, graph: Graph, encoding: Optional[str] = 'utf-8', turtle: bool = True) -> None
Source code in rdflib/plugins/parsers/notation3.py
def parse(
    self,
    source: InputSource,
    graph: Graph,
    encoding: Optional[str] = "utf-8",
    turtle: bool = True,
) -> None:
    if encoding not in [None, "utf-8"]:
        raise ParserError(
            "N3/Turtle files are always utf-8 encoded, I was passed: %s" % encoding
        )

    sink = RDFSink(graph)

    baseURI = graph.absolutize(source.getPublicId() or source.getSystemId() or "")
    p = SinkParser(sink, baseURI=baseURI, turtle=turtle)
    # N3 parser prefers str stream
    stream = source.getCharacterStream()
    if not stream:
        stream = source.getByteStream()
    p.loadStream(stream)

    for prefix, namespace in p._bindings.items():
        graph.bind(prefix, namespace)

sfloat

Bases: str

don’t normalize raw XSD.double string representation

BecauseOfData

BecauseOfData(*args: Any, **kargs: Any) -> None
Source code in rdflib/plugins/parsers/notation3.py
def BecauseOfData(*args: Any, **kargs: Any) -> None:
    # print args, kargs
    pass

base

base() -> str

The base URI for this process - the Web equiv of cwd

Relative or absolute unix-standard filenames parsed relative to this yield the URI of the file. If we had a reliable way of getting a computer name, we should put it in the hostname just to prevent ambiguity

Source code in rdflib/plugins/parsers/notation3.py
def base() -> str:
    """The base URI for this process - the Web equiv of cwd

    Relative or absolute unix-standard filenames parsed relative to
    this yield the URI of the file.
    If we had a reliable way of getting a computer name,
    we should put it in the hostname just to prevent ambiguity
    """
    # return "file://" + hostname + os.getcwd() + "/"
    return "file://" + _fixslash(os.getcwd()) + "/"

becauseSubexpression

becauseSubexpression(*args: Any, **kargs: Any) -> None
Source code in rdflib/plugins/parsers/notation3.py
def becauseSubexpression(*args: Any, **kargs: Any) -> None:
    # print args, kargs
    pass

hexify

hexify(ustr: str) -> bytes

Use URL encoding to return an ASCII string corresponding to the given UTF8 string

>>> hexify("http://example/a b")
b'http://example/a%20b'
Source code in rdflib/plugins/parsers/notation3.py
def hexify(ustr: str) -> bytes:
    """Use URL encoding to return an ASCII string
    corresponding to the given UTF8 string

    ```python
    >>> hexify("http://example/a b")
    b'http://example/a%20b'

    ```
    """
    # s1=ustr.encode('utf-8')
    s = ""
    for ch in ustr:  # .encode('utf-8'):
        if ord(ch) > 126 or ord(ch) < 33:
            ch = "%%%02X" % ord(ch)
        else:
            ch = "%c" % ord(ch)
        s = s + ch
    return s.encode("latin-1")

join

join(here: str, there: str) -> str

join an absolute URI and URI reference (non-ascii characters are supported/doctested; haven’t checked the details of the IRI spec though)

here is assumed to be absolute. there is URI reference.

>>> join('http://example/x/y/z', '../abc')
'http://example/x/abc'

Raise ValueError if there uses relative path syntax but here has no hierarchical path.

>>> join('mid:foo@example', '../foo') # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
    raise ValueError(here)
ValueError: Base <mid:foo@example> has no slash
after colon - with relative '../foo'.

>>> join('http://example/x/y/z', '')
'http://example/x/y/z'

>>> join('mid:foo@example', '#foo')
'mid:foo@example#foo'

We grok IRIs

>>> len('Andr\xe9')
5

>>> join('http://example.org/', '#Andr\xe9')
'http://example.org/#Andr\xe9'
Source code in rdflib/plugins/parsers/notation3.py
def join(here: str, there: str) -> str:
    """join an absolute URI and URI reference
    (non-ascii characters are supported/doctested;
    haven't checked the details of the IRI spec though)

    `here` is assumed to be absolute.
    `there` is URI reference.

    ```python
    >>> join('http://example/x/y/z', '../abc')
    'http://example/x/abc'

    ```

    Raise ValueError if there uses relative path
    syntax but here has no hierarchical path.

    ```python
    >>> join('mid:foo@example', '../foo') # doctest: +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
        raise ValueError(here)
    ValueError: Base <mid:foo@example> has no slash
    after colon - with relative '../foo'.

    >>> join('http://example/x/y/z', '')
    'http://example/x/y/z'

    >>> join('mid:foo@example', '#foo')
    'mid:foo@example#foo'

    ```

    We grok IRIs

    ```python
    >>> len('Andr\\xe9')
    5

    >>> join('http://example.org/', '#Andr\\xe9')
    'http://example.org/#Andr\\xe9'

    ```
    """

    #    assert(here.find("#") < 0), \
    #        "Base may not contain hash: '%s'" % here  # why must caller splitFrag?

    slashl = there.find("/")
    colonl = there.find(":")

    # join(base, 'foo:/') -- absolute
    if colonl >= 0 and (slashl < 0 or colonl < slashl):
        return there

    bcolonl = here.find(":")
    assert bcolonl >= 0, (
        "Base uri '%s' is not absolute" % here
    )  # else it's not absolute

    path, frag = splitFragP(there)
    if not path:
        return here + frag

    # join('mid:foo@example', '../foo') bzzt
    if here[bcolonl + 1 : bcolonl + 2] != "/":
        raise ValueError(
            "Base <%s> has no slash after "
            "colon - with relative '%s'." % (here, there)
        )

    if here[bcolonl + 1 : bcolonl + 3] == "//":
        bpath = here.find("/", bcolonl + 3)
    else:
        bpath = bcolonl + 1

    # join('http://xyz', 'foo')
    if bpath < 0:
        bpath = len(here)
        here = here + "/"

    # join('http://xyz/', '//abc') => 'http://abc'
    if there[:2] == "//":
        return here[: bcolonl + 1] + there

    # join('http://xyz/', '/abc') => 'http://xyz/abc'
    if there[:1] == "/":
        return here[:bpath] + there

    slashr = here.rfind("/")

    while 1:
        if path[:2] == "./":
            path = path[2:]
        if path == ".":
            path = ""
        elif path[:3] == "../" or path == "..":
            path = path[3:]
            i = here.rfind("/", bpath, slashr)
            if i >= 0:
                here = here[: i + 1]
                slashr = i
        else:
            break

    return here[: slashr + 1] + path + frag

runNamespace

runNamespace() -> str

Returns a URI suitable as a namespace for run-local objects

Source code in rdflib/plugins/parsers/notation3.py
def runNamespace() -> str:
    """Returns a URI suitable as a namespace for run-local objects"""
    # @@@ include hostname (privacy?) (hash it?)
    global runNamespaceValue
    if runNamespaceValue is None:
        runNamespaceValue = join(base(), _unique_id()) + "#"
    return runNamespaceValue

splitFragP

splitFragP(uriref: str, punc: int = 0) -> Tuple[str, str]

Split a URI reference before the fragment

Punctuation is kept. e.g.

>>> splitFragP("abc#def")
('abc', '#def')

>>> splitFragP("abcdef")
('abcdef', '')
Source code in rdflib/plugins/parsers/notation3.py
def splitFragP(uriref: str, punc: int = 0) -> Tuple[str, str]:
    """Split a URI reference before the fragment

    Punctuation is kept. e.g.

    ```python
    >>> splitFragP("abc#def")
    ('abc', '#def')

    >>> splitFragP("abcdef")
    ('abcdef', '')

    ```
    """

    i = uriref.rfind("#")
    if i >= 0:
        return uriref[:i], uriref[i:]
    else:
        return uriref, ""

unicodeExpand

unicodeExpand(m: Match) -> str
Source code in rdflib/plugins/parsers/notation3.py
def unicodeExpand(m: Match) -> str:
    try:
        return chr(int(m.group(1), 16))
    except Exception:
        raise Exception("Invalid unicode code point: " + m.group(1))

uniqueURI

uniqueURI() -> str

A unique URI

Source code in rdflib/plugins/parsers/notation3.py
def uniqueURI() -> str:
    """A unique URI"""
    global nextu
    nextu += 1
    return runNamespace() + "u_" + str(nextu)