Skip to content

# `` paths

This module implements the SPARQL 1.1 Property path operators, as defined in: http://www.w3.org/TR/sparql11-query/#propertypaths

In SPARQL the syntax is as follows:

Syntax | Matches
--- | ---
`iri` | An IRI. A path of length one.
`^elt` | Inverse path (object to subject).
`elt1 / elt2` | A sequence path of `elt1` followed by `elt2`.
`elt1 \| elt2` | An alternative path of `elt1` or `elt2` (all possibilities are tried).
`elt*` | A path that connects subject and object by zero or more matches of `elt`.
`elt+` | A path that connects subject and object by one or more matches of `elt`.
`elt?` | A path that connects subject and object by zero or one matches of `elt`.
`!iri` or `!(iri1 \| ... \| irin)` | Negated property set. An IRI not among `iri1` to `irin`. `!iri` is short for `!(iri)`.
`!^iri` or `!(^iri1 \| ... \| ^irin)` | Negated reverse property set. Excludes `^iri1` to `^irin` as reverse paths. `!^iri` is short for `!(^iri)`.
`!(iri1 \| ... \| irij \| ^irij+1 \| ... \| ^irin)` | A combination of forward and reverse properties in a negated property set.
`(elt)` | A grouped path `elt`, where parentheses control precedence.

This module is used internally by the SPARQL engine, but the property paths can also be used to query RDFLib Graphs directly.

Where possible the SPARQL syntax is mapped to Python operators, and property path objects can be constructed from existing URIRefs.

    >>> from rdflib import Graph, Namespace
    >>> from rdflib.namespace import FOAF

    >>> ~FOAF.knows
    Path(~http://xmlns.com/foaf/0.1/knows)

    >>> FOAF.knows/FOAF.name
    Path(http://xmlns.com/foaf/0.1/knows / http://xmlns.com/foaf/0.1/name)

    >>> FOAF.name|FOAF.givenName
    Path(http://xmlns.com/foaf/0.1/name | http://xmlns.com/foaf/0.1/givenName)

Modifiers (?, *, +) are done using * (the multiplication operator) and the strings ‘*‘, ‘?’, ‘+’, also defined as constants in this file.

    >>> FOAF.knows*OneOrMore
    Path(http://xmlns.com/foaf/0.1/knows+)

The path objects can also be used with the normal graph methods.

First some example data:

    >>> g=Graph()

    >>> g=g.parse(data='''
    ... @prefix : <ex:> .
    ...
    ... :a :p1 :c ; :p2 :f .
    ... :c :p2 :e ; :p3 :g .
    ... :g :p3 :h ; :p2 :j .
    ... :h :p3 :a ; :p2 :g .
    ...
    ... :q :px :q .
    ...
    ... ''', format='n3') # doctest: +ELLIPSIS

    >>> e = Namespace('ex:')

Graph contains:

    >>> (e.a, e.p1/e.p2, e.e) in g
    True

Graph generator functions, triples, subjects, objects, etc. :

    >>> list(g.objects(e.c, (e.p3*OneOrMore)/e.p2)) # doctest: +NORMALIZE_WHITESPACE
    [rdflib.term.URIRef('ex:j'), rdflib.term.URIRef('ex:g'),
        rdflib.term.URIRef('ex:f')]

A more complete set of tests:

    >>> list(eval_path(g, (None, e.p1/e.p2, None)))==[(e.a, e.e)]
    True
    >>> list(eval_path(g, (e.a, e.p1|e.p2, None)))==[(e.a,e.c), (e.a,e.f)]
    True
    >>> list(eval_path(g, (e.c, ~e.p1, None))) == [ (e.c, e.a) ]
    True
    >>> list(eval_path(g, (e.a, e.p1*ZeroOrOne, None))) == [(e.a, e.a), (e.a, e.c)]
    True
    >>> list(eval_path(g, (e.c, e.p3*OneOrMore, None))) == [
    ...     (e.c, e.g), (e.c, e.h), (e.c, e.a)]
    True
    >>> list(eval_path(g, (e.c, e.p3*ZeroOrMore, None))) == [(e.c, e.c),
    ...     (e.c, e.g), (e.c, e.h), (e.c, e.a)]
    True
    >>> list(eval_path(g, (e.a, -e.p1, None))) == [(e.a, e.f)]
    True
    >>> list(eval_path(g, (e.a, -(e.p1|e.p2), None))) == []
    True
    >>> list(eval_path(g, (e.g, -~e.p2, None))) == [(e.g, e.j)]
    True
    >>> list(eval_path(g, (e.e, ~(e.p1/e.p2), None))) == [(e.e, e.a)]
    True
    >>> list(eval_path(g, (e.a, e.p1/e.p3/e.p3, None))) == [(e.a, e.h)]
    True

    >>> list(eval_path(g, (e.q, e.px*OneOrMore, None)))
    [(rdflib.term.URIRef('ex:q'), rdflib.term.URIRef('ex:q'))]

    >>> list(eval_path(g, (None, e.p1|e.p2, e.c)))
    [(rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:c'))]

    >>> list(eval_path(g, (None, ~e.p1, e.a))) == [ (e.c, e.a) ]
    True
    >>> list(eval_path(g, (None, e.p1*ZeroOrOne, e.c))) # doctest: +NORMALIZE_WHITESPACE
    [(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:c')),
     (rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:c'))]

    >>> list(eval_path(g, (None, e.p3*OneOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE
    [(rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a'))]

    >>> list(eval_path(g, (None, e.p3*ZeroOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE
    [(rdflib.term.URIRef('ex:a'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a'))]

    >>> list(eval_path(g, (None, -e.p1, e.f))) == [(e.a, e.f)]
    True
    >>> list(eval_path(g, (None, -(e.p1|e.p2), e.c))) == []
    True
    >>> list(eval_path(g, (None, -~e.p2, e.j))) == [(e.g, e.j)]
    True
    >>> list(eval_path(g, (None, ~(e.p1/e.p2), e.a))) == [(e.e, e.a)]
    True
    >>> list(eval_path(g, (None, e.p1/e.p3/e.p3, e.h))) == [(e.a, e.h)]
    True

    >>> list(eval_path(g, (e.q, e.px*OneOrMore, None)))
    [(rdflib.term.URIRef('ex:q'), rdflib.term.URIRef('ex:q'))]

    >>> list(eval_path(g, (e.c, (e.p2|e.p3)*ZeroOrMore, e.j)))
    [(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:j'))]

No vars specified:

    >>> sorted(list(eval_path(g, (None, e.p3*OneOrMore, None)))) #doctest: +NORMALIZE_WHITESPACE
    [(rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:g')),
     (rdflib.term.URIRef('ex:c'), rdflib.term.URIRef('ex:h')),
     (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:a')),
     (rdflib.term.URIRef('ex:g'), rdflib.term.URIRef('ex:h')),
     (rdflib.term.URIRef('ex:h'), rdflib.term.URIRef('ex:a'))]

Classes:

- `AlternativePath` –
- `InvPath` –
- `MulPath` –
- `NegatedPath` –
- `Path` –

  Base class for all property paths.

- `PathList` –
- `SequencePath` –

Functions:

- `evalPath` –
- `eval_path` –
- `inv_path` –

  inverse path

- `mul_path` –

  cardinality path

- `neg_path` –

  negated path

- `path_alternative` –

  alternative path

- `path_sequence` –

  sequence path

Attributes:

- `OneOrMore` –
- `ZeroOrMore` –
- `ZeroOrOne` –

## `` OneOrMore `module-attribute`

    OneOrMore = '+'

## `` ZeroOrMore `module-attribute`

    ZeroOrMore = '*'

## `` ZeroOrOne `module-attribute`

    ZeroOrOne = '?'

## `` AlternativePath

    AlternativePath(*args: Union[Path, URIRef])

Bases: `Path`

Methods:

- `__repr__` –
- `eval` –
- `n3` –

Attributes:

- `args` (`List[Union[Path, URIRef]]`) –

Source code in `rdflib/paths.py`

    330
    331
    332
    333
    334
    335
    336

    def __init__(self, *args: Union[Path, URIRef]):
        self.args: List[Union[Path, URIRef]] = []
        for a in args:
            if isinstance(a, AlternativePath):
                self.args += a.args
            else:
                self.args.append(a)

### `` args `instance-attribute`

    args: List[Union[Path, URIRef]] = []

### `` __repr__

    __repr__() -> str

Source code in `rdflib/paths.py`

    348
    349

    def __repr__(self) -> str:
        return "Path(%s)" % " | ".join(str(x) for x in self.args)

### `` eval

    eval(graph: Graph, subj: Optional[_SubjectType] = None, obj: Optional[_ObjectType] = None) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]

Source code in `rdflib/paths.py`

    338
    339
    340
    341
    342
    343
    344
    345
    346

    def eval(
        self,
        graph: Graph,
        subj: Optional[_SubjectType] = None,
        obj: Optional[_ObjectType] = None,
    ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
        for x in self.args:
            for y in eval_path(graph, (subj, x, obj)):
                yield y

### `` n3

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    351
    352

    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
        return "|".join(_n3(a, namespace_manager) for a in self.args)

## `` InvPath

    InvPath(arg: Union[Path, URIRef])

Bases: `Path`

Methods:

- `__repr__` –
- `eval` –
- `n3` –

Attributes:

- `arg` –

Source code in `rdflib/paths.py`

    253
    254

    def __init__(self, arg: Union[Path, URIRef]):
        self.arg = arg

### `` arg `instance-attribute`

    arg = arg

### `` __repr__

    __repr__() -> str

Source code in `rdflib/paths.py`

    265
    266

    def __repr__(self) -> str:
        return "Path(~%s)" % (self.arg,)

### `` eval

    eval(graph: Graph, subj: Optional[_SubjectType] = None, obj: Optional[_ObjectType] = None) -> Generator[Tuple[_ObjectType, _SubjectType], None, None]

Source code in `rdflib/paths.py`

    256
    257
    258
    259
    260
    261
    262
    263

    def eval(
        self,
        graph: Graph,
        subj: Optional[_SubjectType] = None,
        obj: Optional[_ObjectType] = None,
    ) -> Generator[Tuple[_ObjectType, _SubjectType], None, None]:
        for s, o in eval_path(graph, (obj, self.arg, subj)):
            yield o, s

### `` n3

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    268
    269

    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
        return "^%s" % _n3(self.arg, namespace_manager)

## `` MulPath

    MulPath(path: Union[Path, URIRef], mod: _MulPathMod)

Bases: `Path`

Methods:

- `__repr__` –
- `eval` –
- `n3` –

Attributes:

- `mod` –
- `more` –
- `path` –
- `zero` –

Source code in `rdflib/paths.py`

    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370

    def __init__(self, path: Union[Path, URIRef], mod: _MulPathMod):
        self.path = path
        self.mod = mod

        if mod == ZeroOrOne:
            self.zero = True
            self.more = False
        elif mod == ZeroOrMore:
            self.zero = True
            self.more = True
        elif mod == OneOrMore:
            self.zero = False
            self.more = True
        else:
            raise Exception("Unknown modifier %s" % mod)

### `` mod `instance-attribute`

    mod = mod

### `` more `instance-attribute`

    more = False

### `` path `instance-attribute`

    path = path

### `` zero `instance-attribute`

    zero = True

### `` __repr__

    __repr__() -> str

Source code in `rdflib/paths.py`

    472
    473

    def __repr__(self) -> str:
        return "Path(%s%s)" % (self.path, self.mod)

### `` eval

    eval(graph: Graph, subj: Optional[_SubjectType] = None, obj: Optional[_ObjectType] = None, first: bool = True) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]

Source code in `rdflib/paths.py`

    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470

    def eval(
        self,
        graph: Graph,
        subj: Optional[_SubjectType] = None,
        obj: Optional[_ObjectType] = None,
        first: bool = True,
    ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
        if self.zero and first:
            if subj and obj:
                if subj == obj:
                    yield subj, obj
            elif subj:
                yield subj, subj
            elif obj:
                yield obj, obj

        def _fwd(
            subj: Optional[_SubjectType] = None,
            obj: Optional[_ObjectType] = None,
            seen: Optional[Set[_SubjectType]] = None,
        ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
            # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add"
            # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node"
            seen.add(subj)  # type: ignore[union-attr, arg-type]

            for s, o in eval_path(graph, (subj, self.path, None)):
                if not obj or o == obj:
                    yield s, o
                if self.more:
                    # type error: Unsupported right operand type for in ("Optional[Set[Node]]")
                    if o in seen:  # type: ignore[operator]
                        continue
                    for s2, o2 in _fwd(o, obj, seen):
                        yield s, o2

        def _bwd(
            subj: Optional[_SubjectType] = None,
            obj: Optional[_ObjectType] = None,
            seen: Optional[Set[_ObjectType]] = None,
        ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
            # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add"
            # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node"
            seen.add(obj)  # type: ignore[union-attr, arg-type]

            for s, o in eval_path(graph, (None, self.path, obj)):
                if not subj or subj == s:
                    yield s, o
                if self.more:
                    # type error: Unsupported right operand type for in ("Optional[Set[Node]]")
                    if s in seen:  # type: ignore[operator]
                        continue

                    for s2, o2 in _bwd(None, s, seen):
                        yield s2, o

        def _all_fwd_paths() -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
            if self.zero:
                seen1 = set()
                # According to the spec, ALL nodes are possible solutions
                # (even literals)
                # we cannot do this without going through ALL triples
                # unless we keep an index of all terms somehow
                # but let's just hope this query doesn't happen very often...
                for s, o in graph.subject_objects(None):
                    if s not in seen1:
                        seen1.add(s)
                        yield s, s
                    if o not in seen1:
                        seen1.add(o)
                        yield o, o

            seen = set()
            for s, o in eval_path(graph, (None, self.path, None)):
                if not self.more:
                    yield s, o
                else:
                    if s not in seen:
                        seen.add(s)
                        f = list(_fwd(s, None, set()))
                        for s1, o1 in f:
                            assert s1 == s
                            yield s1, o1

        done = set()  # the spec does, by defn, not allow duplicates
        if subj:
            for x in _fwd(subj, obj, set()):
                if x not in done:
                    done.add(x)
                    yield x
        elif obj:
            for x in _bwd(subj, obj, set()):
                if x not in done:
                    done.add(x)
                    yield x
        else:
            for x in _all_fwd_paths():
                if x not in done:
                    done.add(x)
                    yield x

### `` n3

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    475
    476

    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
        return "%s%s" % (_n3(self.path, namespace_manager), self.mod)

## `` NegatedPath

    NegatedPath(arg: Union[AlternativePath, InvPath, URIRef])

Bases: `Path`

Methods:

- `__repr__` –
- `eval` –
- `n3` –

Attributes:

- `args` (`List[Union[URIRef, Path]]`) –

Source code in `rdflib/paths.py`

    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490

    def __init__(self, arg: Union[AlternativePath, InvPath, URIRef]):
        self.args: List[Union[URIRef, Path]]
        if isinstance(arg, (URIRef, InvPath)):
            self.args = [arg]
        elif isinstance(arg, AlternativePath):
            self.args = arg.args
        else:
            raise Exception(
                "Can only negate URIRefs, InvPaths or "
                + "AlternativePaths, not: %s" % (arg,)
            )

### `` args `instance-attribute`

    args: List[Union[URIRef, Path]]

### `` __repr__

    __repr__() -> str

Source code in `rdflib/paths.py`

    506
    507

    def __repr__(self) -> str:
        return "Path(! %s)" % ",".join(str(x) for x in self.args)

### `` eval

    eval(graph, subj=None, obj=None)

Source code in `rdflib/paths.py`

    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504

    def eval(self, graph, subj=None, obj=None):
        for s, p, o in graph.triples((subj, None, obj)):
            for a in self.args:
                if isinstance(a, URIRef):
                    if p == a:
                        break
                elif isinstance(a, InvPath):
                    if (o, a.arg, s) in graph:
                        break
                else:
                    raise Exception("Invalid path in NegatedPath: %s" % a)
            else:
                yield s, o

### `` n3

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    509
    510

    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
        return "!(%s)" % ("|".join(_n3(arg, namespace_manager) for arg in self.args))

## `` Path

Bases: `ABC`

Base class for all property paths.

Methods:

- `__eq__` –
- `__hash__` –
- `__lt__` –
- `eval` –
- `n3` –

Attributes:

- `__invert__` (`Callable[[Path], InvPath]`) –
- `__mul__` (`Callable[[Path, str], MulPath]`) –
- `__neg__` (`Callable[[Path], NegatedPath]`) –
- `__or__` (`Callable[[Path, Union[URIRef, Path]], AlternativePath]`) –
- `__truediv__` (`Callable[[Path, Union[URIRef, Path]], SequencePath]`) –

### `` __invert__ `instance-attribute`

    __invert__: Callable[[Path], InvPath]

### `` __mul__ `instance-attribute`

    __mul__: Callable[[Path, str], MulPath]

### `` __neg__ `instance-attribute`

    __neg__: Callable[[Path], NegatedPath]

### `` __or__ `instance-attribute`

    __or__: Callable[[Path, Union[URIRef, Path]], AlternativePath]

### `` __truediv__ `instance-attribute`

    __truediv__: Callable[[Path, Union[URIRef, Path]], SequencePath]

### `` __eq__

    __eq__(other)

Source code in `rdflib/paths.py`

    241
    242

    def __eq__(self, other):
        return repr(self) == repr(other)

### `` __hash__

    __hash__()

Source code in `rdflib/paths.py`

    238
    239

    def __hash__(self):
        return hash(repr(self))

### `` __lt__

    __lt__(other: Any) -> bool

Source code in `rdflib/paths.py`

    244
    245
    246
    247
    248
    249

    def __lt__(self, other: Any) -> bool:
        if not isinstance(other, (Path, Node)):
            raise TypeError(
                "unorderable types: %s() < %s()" % (repr(self), repr(other))
            )
        return repr(self) < repr(other)

### `` eval `abstractmethod`

    eval(graph: Graph, subj: Optional[_SubjectType] = None, obj: Optional[_ObjectType] = None) -> Iterator[Tuple[_SubjectType, _ObjectType]]

Source code in `rdflib/paths.py`

    227
    228
    229
    230
    231
    232
    233

    @abstractmethod
    def eval(
        self,
        graph: Graph,
        subj: Optional[_SubjectType] = None,
        obj: Optional[_ObjectType] = None,
    ) -> Iterator[Tuple[_SubjectType, _ObjectType]]: ...

### `` n3 `abstractmethod`

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    235
    236

    @abstractmethod
    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: ...

## `` PathList

Bases: `list`

## `` SequencePath

    SequencePath(*args: Union[Path, URIRef])

Bases: `Path`

Methods:

- `__repr__` –
- `eval` –
- `n3` –

Attributes:

- `args` (`List[Union[Path, URIRef]]`) –

Source code in `rdflib/paths.py`

    273
    274
    275
    276
    277
    278
    279

    def __init__(self, *args: Union[Path, URIRef]):
        self.args: List[Union[Path, URIRef]] = []
        for a in args:
            if isinstance(a, SequencePath):
                self.args += a.args
            else:
                self.args.append(a)

### `` args `instance-attribute`

    args: List[Union[Path, URIRef]] = []

### `` __repr__

    __repr__() -> str

Source code in `rdflib/paths.py`

    322
    323

    def __repr__(self) -> str:
        return "Path(%s)" % " / ".join(str(x) for x in self.args)

### `` eval

    eval(graph: Graph, subj: Optional[_SubjectType] = None, obj: Optional[_ObjectType] = None) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]

Source code in `rdflib/paths.py`

    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320

    def eval(
        self,
        graph: Graph,
        subj: Optional[_SubjectType] = None,
        obj: Optional[_ObjectType] = None,
    ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
        def _eval_seq(
            paths: List[Union[Path, URIRef]],
            subj: Optional[_SubjectType],
            obj: Optional[_ObjectType],
        ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
            if paths[1:]:
                for s, o in eval_path(graph, (subj, paths[0], None)):
                    for r in _eval_seq(paths[1:], o, obj):
                        yield s, r[1]

            else:
                for s, o in eval_path(graph, (subj, paths[0], obj)):
                    yield s, o

        def _eval_seq_bw(
            paths: List[Union[Path, URIRef]],
            subj: Optional[_SubjectType],
            obj: _ObjectType,
        ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]:
            if paths[:-1]:
                for s, o in eval_path(graph, (None, paths[-1], obj)):
                    for r in _eval_seq(paths[:-1], subj, s):
                        yield r[0], o

            else:
                for s, o in eval_path(graph, (subj, paths[0], obj)):
                    yield s, o

        if subj:
            return _eval_seq(self.args, subj, obj)
        elif obj:
            return _eval_seq_bw(self.args, subj, obj)
        else:  # no vars bound, we can start anywhere
            return _eval_seq(self.args, subj, obj)

### `` n3

    n3(namespace_manager: Optional[NamespaceManager] = None) -> str

Source code in `rdflib/paths.py`

    325
    326

    def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
        return "/".join(_n3(a, namespace_manager) for a in self.args)

## `` evalPath

    evalPath(graph: Graph, t: Tuple[Optional[_SubjectType], Union[None, Path, _PredicateType], Optional[_ObjectType]]) -> Iterator[Tuple[_SubjectType, _ObjectType]]

Source code in `rdflib/paths.py`

    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550

    def evalPath(  # noqa: N802
        graph: Graph,
        t: Tuple[
            Optional[_SubjectType],
            Union[None, Path, _PredicateType],
            Optional[_ObjectType],
        ],
    ) -> Iterator[Tuple[_SubjectType, _ObjectType]]:
        warnings.warn(
            DeprecationWarning(
                "rdflib.path.evalPath() is deprecated, use the (snake-cased) eval_path(). "
                "The mixed-case evalPath() function name is incompatible with PEP8 "
                "recommendations and will be replaced by eval_path() in rdflib 7.0.0."
            )
        )
        return eval_path(graph, t)

## `` eval_path

    eval_path(graph: Graph, t: Tuple[Optional[_SubjectType], Union[None, Path, _PredicateType], Optional[_ObjectType]]) -> Iterator[Tuple[_SubjectType, _ObjectType]]

Source code in `rdflib/paths.py`

    553
    554
    555
    556
    557
    558
    559
    560
    561

    def eval_path(
        graph: Graph,
        t: Tuple[
            Optional[_SubjectType],
            Union[None, Path, _PredicateType],
            Optional[_ObjectType],
        ],
    ) -> Iterator[Tuple[_SubjectType, _ObjectType]]:
        return ((s, o) for s, p, o in graph.triples(t))

## `` inv_path

    inv_path(p: Union[URIRef, Path]) -> InvPath

inverse path

Source code in `rdflib/paths.py`

    571
    572
    573
    574
    575

    def inv_path(p: Union[URIRef, Path]) -> InvPath:
        """
        inverse path
        """
        return InvPath(p)

## `` mul_path

    mul_path(p: Union[URIRef, Path], mul: _MulPathMod) -> MulPath

cardinality path

Source code in `rdflib/paths.py`

    564
    565
    566
    567
    568

    def mul_path(p: Union[URIRef, Path], mul: _MulPathMod) -> MulPath:
        """
        cardinality path
        """
        return MulPath(p, mul)

## `` neg_path

    neg_path(p: Union[URIRef, AlternativePath, InvPath]) -> NegatedPath

negated path

Source code in `rdflib/paths.py`

    578
    579
    580
    581
    582

    def neg_path(p: Union[URIRef, AlternativePath, InvPath]) -> NegatedPath:
        """
        negated path
        """
        return NegatedPath(p)

## `` path_alternative

    path_alternative(self: Union[URIRef, Path], other: Union[URIRef, Path])

alternative path

Source code in `rdflib/paths.py`

    517
    518
    519
    520
    521
    522
    523

    def path_alternative(self: Union[URIRef, Path], other: Union[URIRef, Path]):
        """
        alternative path
        """
        if not isinstance(other, (URIRef, Path)):
            raise Exception("Only URIRefs or Paths can be in paths!")
        return AlternativePath(self, other)

## `` path_sequence

    path_sequence(self: Union[URIRef, Path], other: Union[URIRef, Path])

sequence path

Source code in `rdflib/paths.py`

    526
    527
    528
    529
    530
    531
    532

    def path_sequence(self: Union[URIRef, Path], other: Union[URIRef, Path]):
        """
        sequence path
        """
        if not isinstance(other, (URIRef, Path)):
            raise Exception("Only URIRefs or Paths can be in paths!")
        return SequencePath(self, other)