diff --git a/java/pom.xml b/java/pom.xml
index 6f689f7..f597b66 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -1,403 +1,409 @@
4.0.0
org.softwareheritage.graph
swh-graph
${git.closest.tag.name}
swh-graph
https://forge.softwareheritage.org/source/swh-graph/
UTF-8
11
3.21.1
1.47.0
ch.qos.logback
logback-classic
1.2.3
org.junit.jupiter
junit-jupiter-api
5.7.0
test
org.junit.jupiter
junit-jupiter-engine
5.7.0
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.7.0
+ test
+
org.slf4j
slf4j-simple
1.7.26
it.unimi.dsi
webgraph-big
3.7.0
it.unimi.dsi
fastutil
8.5.8
it.unimi.dsi
dsiutils
2.7.2
it.unimi.dsi
sux4j
5.4.0
it.unimi.dsi
law
2.7.2
org.apache.hadoop
hadoop-common
org.umlgraph
umlgraph
org.eclipse.jetty.aggregate
jetty-all
it.unimi.di
mg4j
it.unimi.di
mg4j-big
com.martiansoftware
jsap
2.1
commons-codec
commons-codec
1.15
com.github.luben
zstd-jni
1.5.1-1
org.apache.orc
orc-core
1.7.1
org.apache.hadoop
hadoop-common
3.3.1
org.apache.hadoop
hadoop-client-runtime
3.3.1
com.google.protobuf
protobuf-java
${protobuf.version}
io.grpc
grpc-netty-shaded
${grpc.version}
io.grpc
grpc-protobuf
${grpc.version}
io.grpc
grpc-stub
${grpc.version}
io.grpc
grpc-services
${grpc.version}
io.grpc
grpc-testing
${grpc.version}
javax.annotation
javax.annotation-api
1.3.2
com.google.protobuf
protobuf-java-util
${protobuf.version}
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
11
11
-verbose
-Xlint:all
maven-surefire-plugin
2.22.2
maven-failsafe-plugin
2.22.2
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-dependency-plugin
3.1.2
maven-assembly-plugin
3.3.0
org.softwareheritage.graph.rpc.GraphServer
jar-with-dependencies
false
make-assembly
package
single
com.diffplug.spotless
spotless-maven-plugin
2.22.1
*.md
.gitignore
true
4
4.16.0
.coding-style.xml
pl.project13.maven
git-commit-id-plugin
3.0.1
get-the-git-infos
revision
initialize
true
true
true
true
v*
git.closest.tag.name
^v
true
maven-source-plugin
2.1.1
bundle-sources
package
jar-no-fork
test-jar-no-fork
org.apache.maven.plugins
maven-javadoc-plugin
3.3.1
resource-bundles
package
resource-bundle
test-resource-bundle
false
javadoc-jar
package
jar
true
it.unimi.dsi:webgraph-big:*
https://webgraph.di.unimi.it/docs-big/
https://dsiutils.di.unimi.it/docs/
https://fastutil.di.unimi.it/docs/
https://law.di.unimi.it/software/law-docs/
implSpec
a
Implementation Requirements:
implNote
a
Implementation Note:
org.xolstice.maven.plugins
protobuf-maven-plugin
0.6.1
com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
compile
compile-custom
test-compile
test-compile-custom
kr.motd.maven
os-maven-plugin
1.6.2
diff --git a/java/src/main/java/org/softwareheritage/graph/rpc/Traversal.java b/java/src/main/java/org/softwareheritage/graph/rpc/Traversal.java
index bbdf4fa..394caf9 100644
--- a/java/src/main/java/org/softwareheritage/graph/rpc/Traversal.java
+++ b/java/src/main/java/org/softwareheritage/graph/rpc/Traversal.java
@@ -1,533 +1,553 @@
/*
* Copyright (c) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
package org.softwareheritage.graph.rpc;
import it.unimi.dsi.big.webgraph.labelling.ArcLabelledNodeIterator;
import it.unimi.dsi.big.webgraph.labelling.Label;
import org.softwareheritage.graph.*;
import java.util.*;
/** Traversal contains all the algorithms used for graph traversals */
public class Traversal {
/**
* Wrapper around g.successors(), only follows edges that are allowed by the given
* {@link AllowedEdges} object.
*/
private static ArcLabelledNodeIterator.LabelledArcIterator filterLabelledSuccessors(SwhUnidirectionalGraph g,
long nodeId, AllowedEdges allowedEdges) {
if (allowedEdges.restrictedTo == null) {
// All edges are allowed, bypass edge check
return g.labelledSuccessors(nodeId);
} else {
ArcLabelledNodeIterator.LabelledArcIterator allSuccessors = g.labelledSuccessors(nodeId);
return new ArcLabelledNodeIterator.LabelledArcIterator() {
@Override
public Label label() {
return allSuccessors.label();
}
@Override
public long nextLong() {
long neighbor;
while ((neighbor = allSuccessors.nextLong()) != -1) {
if (allowedEdges.isAllowed(g.getNodeType(nodeId), g.getNodeType(neighbor))) {
return neighbor;
}
}
return -1;
}
@Override
public long skip(final long n) {
long i = 0;
while (i < n && nextLong() != -1)
i++;
return i;
}
};
}
}
/** Helper class to check that a given node is "valid" for some given {@link NodeFilter} */
private static class NodeFilterChecker {
private final SwhUnidirectionalGraph g;
private final NodeFilter filter;
private final AllowedNodes allowedNodes;
private NodeFilterChecker(SwhUnidirectionalGraph graph, NodeFilter filter) {
this.g = graph;
this.filter = filter;
this.allowedNodes = new AllowedNodes(filter.hasTypes() ? filter.getTypes() : "*");
}
public boolean allowed(long nodeId) {
if (filter == null) {
return true;
}
if (!this.allowedNodes.isAllowed(g.getNodeType(nodeId))) {
return false;
}
return true;
}
}
/** Returns the unidirectional graph from a bidirectional graph and a {@link GraphDirection}. */
public static SwhUnidirectionalGraph getDirectedGraph(SwhBidirectionalGraph g, GraphDirection direction) {
switch (direction) {
case FORWARD:
return g.getForwardGraph();
case BACKWARD:
return g.getBackwardGraph();
/*
* TODO: add support for BOTH case BOTH: return new SwhUnidirectionalGraph(g.symmetrize(),
* g.getProperties());
*/
default :
throw new IllegalArgumentException("Unknown direction: " + direction);
}
}
/** Returns the opposite of a given {@link GraphDirection} (equivalent to a graph transposition). */
public static GraphDirection reverseDirection(GraphDirection direction) {
switch (direction) {
case FORWARD:
return GraphDirection.BACKWARD;
case BACKWARD:
return GraphDirection.FORWARD;
/*
* TODO: add support for BOTH case BOTH: return GraphDirection.BOTH;
*/
default :
throw new IllegalArgumentException("Unknown direction: " + direction);
}
}
/** Dummy exception to short-circuit and interrupt a graph traversal. */
static class StopTraversalException extends RuntimeException {
}
/** Generic BFS traversal algorithm. */
static class BFSVisitor {
/** The graph to traverse. */
protected final SwhUnidirectionalGraph g;
/** Depth of the node currently being visited */
protected long depth = 0;
/**
* Number of traversal successors (i.e., successors that will be considered by the traversal) of the
* node currently being visited
*/
protected long traversalSuccessors = 0;
/** Number of edges accessed since the beginning of the traversal */
protected long edgesAccessed = 0;
/**
* Map from a node ID to its parent node ID. The key set can be used as the set of all visited
* nodes.
*/
protected HashMap parents = new HashMap<>();
/** Queue of nodes to visit (also called "frontier", "open set", "wavefront" etc.) */
protected ArrayDeque queue = new ArrayDeque<>();
/** If > 0, the maximum depth of the traversal. */
private long maxDepth = -1;
/** If > 0, the maximum number of edges to traverse. */
private long maxEdges = -1;
BFSVisitor(SwhUnidirectionalGraph g) {
this.g = g;
}
/** Add a new source node to the initial queue. */
public void addSource(long nodeId) {
queue.add(nodeId);
parents.put(nodeId, -1L);
}
/** Set the maximum depth of the traversal. */
public void setMaxDepth(long depth) {
maxDepth = depth;
}
/** Set the maximum number of edges to traverse. */
public void setMaxEdges(long edges) {
maxEdges = edges;
}
/** Setup the visit counters and depth sentinel. */
public void visitSetup() {
edgesAccessed = 0;
depth = 0;
queue.add(-1L); // depth sentinel
}
/** Perform the visit */
public void visit() {
visitSetup();
while (!queue.isEmpty()) {
visitStep();
}
}
/** Single "step" of a visit. Advance the frontier of exactly one node. */
public void visitStep() {
try {
assert !queue.isEmpty();
long curr = queue.poll();
if (curr == -1L) {
++depth;
if (!queue.isEmpty()) {
queue.add(-1L);
visitStep();
}
return;
}
if (maxDepth >= 0 && depth > maxDepth) {
throw new StopTraversalException();
}
edgesAccessed += g.outdegree(curr);
if (maxEdges >= 0 && edgesAccessed > maxEdges) {
throw new StopTraversalException();
}
visitNode(curr);
} catch (StopTraversalException e) {
// Traversal is over, clear the to-do queue.
queue.clear();
}
}
/**
* Get the successors of a node. Override this function if you want to filter which successors are
* considered during the traversal.
*/
protected ArcLabelledNodeIterator.LabelledArcIterator getSuccessors(long nodeId) {
return g.labelledSuccessors(nodeId);
}
/** Visit a node. Override to do additional processing on the node. */
protected void visitNode(long node) {
ArcLabelledNodeIterator.LabelledArcIterator it = getSuccessors(node);
traversalSuccessors = 0;
for (long succ; (succ = it.nextLong()) != -1;) {
traversalSuccessors++;
visitEdge(node, succ, it.label());
}
}
/** Visit an edge. Override to do additional processing on the edge. */
protected void visitEdge(long src, long dst, Label label) {
if (!parents.containsKey(dst)) {
queue.add(dst);
parents.put(dst, src);
}
}
}
/**
* SimpleTraversal is used by the Traverse endpoint. It extends BFSVisitor with additional
* processing, notably related to graph properties and filters.
*/
static class SimpleTraversal extends BFSVisitor {
private final NodeFilterChecker nodeReturnChecker;
private final AllowedEdges allowedEdges;
private final TraversalRequest request;
private final NodePropertyBuilder.NodeDataMask nodeDataMask;
private final NodeObserver nodeObserver;
+ private long remainingMatches;
private Node.Builder nodeBuilder;
SimpleTraversal(SwhBidirectionalGraph bidirectionalGraph, TraversalRequest request, NodeObserver nodeObserver) {
super(getDirectedGraph(bidirectionalGraph, request.getDirection()));
this.request = request;
this.nodeObserver = nodeObserver;
this.nodeReturnChecker = new NodeFilterChecker(g, request.getReturnNodes());
this.nodeDataMask = new NodePropertyBuilder.NodeDataMask(request.hasMask() ? request.getMask() : null);
this.allowedEdges = new AllowedEdges(request.hasEdges() ? request.getEdges() : "*");
request.getSrcList().forEach(srcSwhid -> {
long srcNodeId = g.getNodeId(new SWHID(srcSwhid));
addSource(srcNodeId);
});
if (request.hasMaxDepth()) {
setMaxDepth(request.getMaxDepth());
}
if (request.hasMaxEdges()) {
setMaxEdges(request.getMaxEdges());
}
+ if (request.hasMaxMatchingNodes() && request.getMaxMatchingNodes() > 0) {
+ this.remainingMatches = request.getMaxMatchingNodes();
+ } else {
+ this.remainingMatches = -1;
+ }
}
@Override
protected ArcLabelledNodeIterator.LabelledArcIterator getSuccessors(long nodeId) {
return filterLabelledSuccessors(g, nodeId, allowedEdges);
}
@Override
public void visitNode(long node) {
nodeBuilder = null;
if (nodeReturnChecker.allowed(node) && (!request.hasMinDepth() || depth >= request.getMinDepth())) {
nodeBuilder = Node.newBuilder();
NodePropertyBuilder.buildNodeProperties(g, nodeDataMask, nodeBuilder, node);
}
super.visitNode(node);
- if (request.getReturnNodes().hasMinTraversalSuccessors()
- && traversalSuccessors < request.getReturnNodes().getMinTraversalSuccessors()
- || request.getReturnNodes().hasMaxTraversalSuccessors()
- && traversalSuccessors > request.getReturnNodes().getMaxTraversalSuccessors()) {
- nodeBuilder = null;
+
+ boolean nodeMatchesConstraints = true;
+
+ if (request.getReturnNodes().hasMinTraversalSuccessors()) {
+ nodeMatchesConstraints &= traversalSuccessors >= request.getReturnNodes().getMinTraversalSuccessors();
}
- if (nodeBuilder != null) {
- nodeObserver.onNext(nodeBuilder.build());
+ if (request.getReturnNodes().hasMaxTraversalSuccessors()) {
+ nodeMatchesConstraints &= traversalSuccessors <= request.getReturnNodes().getMaxTraversalSuccessors();
+ }
+
+ if (nodeMatchesConstraints) {
+ if (nodeBuilder != null) {
+ nodeObserver.onNext(nodeBuilder.build());
+ }
+
+ if (remainingMatches >= 0) {
+ remainingMatches--;
+ if (remainingMatches == 0) {
+ // We matched as many nodes as allowed
+ throw new StopTraversalException();
+ }
+ }
}
}
@Override
protected void visitEdge(long src, long dst, Label label) {
super.visitEdge(src, dst, label);
NodePropertyBuilder.buildSuccessorProperties(g, nodeDataMask, nodeBuilder, src, dst, label);
}
}
/**
* FindPathTo searches for a path from a source node to a node matching a given criteria It extends
* BFSVisitor with additional processing, and makes the traversal stop as soon as a node matching
* the given criteria is found.
*/
static class FindPathTo extends BFSVisitor {
private final AllowedEdges allowedEdges;
private final FindPathToRequest request;
private final NodePropertyBuilder.NodeDataMask nodeDataMask;
private final NodeFilterChecker targetChecker;
private Long targetNode = null;
FindPathTo(SwhBidirectionalGraph bidirectionalGraph, FindPathToRequest request) {
super(getDirectedGraph(bidirectionalGraph, request.getDirection()));
this.request = request;
this.targetChecker = new NodeFilterChecker(g, request.getTarget());
this.nodeDataMask = new NodePropertyBuilder.NodeDataMask(request.hasMask() ? request.getMask() : null);
this.allowedEdges = new AllowedEdges(request.hasEdges() ? request.getEdges() : "*");
if (request.hasMaxDepth()) {
setMaxDepth(request.getMaxDepth());
}
if (request.hasMaxEdges()) {
setMaxEdges(request.getMaxEdges());
}
request.getSrcList().forEach(srcSwhid -> {
long srcNodeId = g.getNodeId(new SWHID(srcSwhid));
addSource(srcNodeId);
});
}
@Override
protected ArcLabelledNodeIterator.LabelledArcIterator getSuccessors(long nodeId) {
return filterLabelledSuccessors(g, nodeId, allowedEdges);
}
@Override
public void visitNode(long node) {
if (targetChecker.allowed(node)) {
targetNode = node;
throw new StopTraversalException();
}
super.visitNode(node);
}
/**
* Once the visit has been performed and a matching node has been found, return the shortest path
* from the source set to that node. To do so, we need to backtrack the parents of the node until we
* find one of the source nodes (whose parent is -1).
*/
public Path getPath() {
if (targetNode == null) {
return null; // No path found.
}
/* Backtrack from targetNode to a source node */
long curNode = targetNode;
ArrayList path = new ArrayList<>();
while (curNode != -1) {
path.add(curNode);
curNode = parents.get(curNode);
}
Collections.reverse(path);
/* Enrich path with node properties */
Path.Builder pathBuilder = Path.newBuilder();
for (long nodeId : path) {
Node.Builder nodeBuilder = Node.newBuilder();
NodePropertyBuilder.buildNodeProperties(g, nodeDataMask, nodeBuilder, nodeId);
pathBuilder.addNode(nodeBuilder.build());
}
return pathBuilder.build();
}
}
/**
* FindPathBetween searches for a shortest path between a set of source nodes and a set of
* destination nodes.
*
* It does so by performing a *bidirectional breadth-first search*, i.e., two parallel breadth-first
* searches, one from the source set ("src-BFS") and one from the destination set ("dst-BFS"), until
* both searches find a common node that joins their visited sets. This node is called the "midpoint
* node". The path returned is the path src -> ... -> midpoint -> ... -> dst, which is always a
* shortest path between src and dst.
*
* The graph direction of both BFS can be configured separately. By default, the dst-BFS will use
* the graph in the opposite direction than the src-BFS (if direction = FORWARD, by default
* direction_reverse = BACKWARD, and vice-versa). The default behavior is thus to search for a
* shortest path between two nodes in a given direction. However, one can also specify FORWARD or
* BACKWARD for *both* the src-BFS and the dst-BFS. This will search for a common descendant or a
* common ancestor between the two sets, respectively. These will be the midpoints of the returned
* path.
*/
static class FindPathBetween extends BFSVisitor {
private final FindPathBetweenRequest request;
private final NodePropertyBuilder.NodeDataMask nodeDataMask;
private final AllowedEdges allowedEdgesSrc;
private final AllowedEdges allowedEdgesDst;
private final BFSVisitor srcVisitor;
private final BFSVisitor dstVisitor;
private Long middleNode = null;
FindPathBetween(SwhBidirectionalGraph bidirectionalGraph, FindPathBetweenRequest request) {
super(getDirectedGraph(bidirectionalGraph, request.getDirection()));
this.request = request;
this.nodeDataMask = new NodePropertyBuilder.NodeDataMask(request.hasMask() ? request.getMask() : null);
GraphDirection direction = request.getDirection();
// if direction_reverse is not specified, use the opposite direction of direction
GraphDirection directionReverse = request.hasDirectionReverse()
? request.getDirectionReverse()
: reverseDirection(request.getDirection());
SwhUnidirectionalGraph srcGraph = getDirectedGraph(bidirectionalGraph, direction);
SwhUnidirectionalGraph dstGraph = getDirectedGraph(bidirectionalGraph, directionReverse);
this.allowedEdgesSrc = new AllowedEdges(request.hasEdges() ? request.getEdges() : "*");
/*
* If edges_reverse is not specified: - If `edges` is not specified either, defaults to "*" - If
* direction == direction_reverse, defaults to `edges` - If direction != direction_reverse, defaults
* to the reverse of `edges` (e.g. "rev:dir" becomes "dir:rev").
*/
this.allowedEdgesDst = request.hasEdgesReverse()
? new AllowedEdges(request.getEdgesReverse())
: (request.hasEdges()
? (direction == directionReverse
? new AllowedEdges(request.getEdges())
: new AllowedEdges(request.getEdges()).reverse())
: new AllowedEdges("*"));
/*
* Source sub-visitor. Aborts as soon as it finds a node already visited by the destination
* sub-visitor.
*/
this.srcVisitor = new BFSVisitor(srcGraph) {
@Override
protected ArcLabelledNodeIterator.LabelledArcIterator getSuccessors(long nodeId) {
return filterLabelledSuccessors(g, nodeId, allowedEdgesSrc);
}
@Override
public void visitNode(long node) {
if (dstVisitor.parents.containsKey(node)) {
middleNode = node;
throw new StopTraversalException();
}
super.visitNode(node);
}
};
/*
* Destination sub-visitor. Aborts as soon as it finds a node already visited by the source
* sub-visitor.
*/
this.dstVisitor = new BFSVisitor(dstGraph) {
@Override
protected ArcLabelledNodeIterator.LabelledArcIterator getSuccessors(long nodeId) {
return filterLabelledSuccessors(g, nodeId, allowedEdgesDst);
}
@Override
public void visitNode(long node) {
if (srcVisitor.parents.containsKey(node)) {
middleNode = node;
throw new StopTraversalException();
}
super.visitNode(node);
}
};
if (request.hasMaxDepth()) {
this.srcVisitor.setMaxDepth(request.getMaxDepth());
this.dstVisitor.setMaxDepth(request.getMaxDepth());
}
if (request.hasMaxEdges()) {
this.srcVisitor.setMaxEdges(request.getMaxEdges());
this.dstVisitor.setMaxEdges(request.getMaxEdges());
}
request.getSrcList().forEach(srcSwhid -> {
long srcNodeId = g.getNodeId(new SWHID(srcSwhid));
srcVisitor.addSource(srcNodeId);
});
request.getDstList().forEach(srcSwhid -> {
long srcNodeId = g.getNodeId(new SWHID(srcSwhid));
dstVisitor.addSource(srcNodeId);
});
}
@Override
public void visit() {
/*
* Bidirectional BFS: maintain two sub-visitors, and alternately run a visit step in each of them.
*/
srcVisitor.visitSetup();
dstVisitor.visitSetup();
while (!srcVisitor.queue.isEmpty() || !dstVisitor.queue.isEmpty()) {
if (!srcVisitor.queue.isEmpty()) {
srcVisitor.visitStep();
}
if (!dstVisitor.queue.isEmpty()) {
dstVisitor.visitStep();
}
}
}
public Path getPath() {
if (middleNode == null) {
return null; // No path found.
}
Path.Builder pathBuilder = Path.newBuilder();
ArrayList path = new ArrayList<>();
/* First section of the path: src -> midpoint */
long curNode = middleNode;
while (curNode != -1) {
path.add(curNode);
curNode = srcVisitor.parents.get(curNode);
}
pathBuilder.setMidpointIndex(path.size() - 1);
Collections.reverse(path);
/* Second section of the path: midpoint -> dst */
curNode = dstVisitor.parents.get(middleNode);
while (curNode != -1) {
path.add(curNode);
curNode = dstVisitor.parents.get(curNode);
}
/* Enrich path with node properties */
for (long nodeId : path) {
Node.Builder nodeBuilder = Node.newBuilder();
NodePropertyBuilder.buildNodeProperties(g, nodeDataMask, nodeBuilder, nodeId);
pathBuilder.addNode(nodeBuilder.build());
}
return pathBuilder.build();
}
}
public interface NodeObserver {
void onNext(Node nodeId);
}
}
diff --git a/java/src/test/java/org/softwareheritage/graph/GraphTest.java b/java/src/test/java/org/softwareheritage/graph/GraphTest.java
index 872784f..63defa5 100644
--- a/java/src/test/java/org/softwareheritage/graph/GraphTest.java
+++ b/java/src/test/java/org/softwareheritage/graph/GraphTest.java
@@ -1,67 +1,96 @@
/*
* Copyright (c) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
package org.softwareheritage.graph;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import com.github.luben.zstd.ZstdInputStream;
import it.unimi.dsi.big.webgraph.LazyLongIterator;
import it.unimi.dsi.big.webgraph.LazyLongIterators;
import org.junit.jupiter.api.BeforeAll;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
public class GraphTest {
static SwhBidirectionalGraph graph;
final protected String TEST_ORIGIN_ID = "swh:1:ori:83404f995118bd25774f4ac14422a8f175e7a054";
@BeforeAll
public static void setUp() throws IOException {
graph = SwhBidirectionalGraph.loadLabelled(getGraphPath().toString());
}
public static Path getGraphPath() {
return Paths.get("..", "swh", "graph", "tests", "dataset", "compressed", "example");
}
public static SwhBidirectionalGraph getGraph() {
return graph;
}
public static SWHID fakeSWHID(String type, int num) {
return new SWHID(String.format("swh:1:%s:%040d", type, num));
}
public static void assertEqualsAnyOrder(Collection expected, Collection actual) {
ArrayList expectedList = new ArrayList<>(expected);
ArrayList actualList = new ArrayList<>(actual);
expectedList.sort(Comparator.comparing(Object::toString));
actualList.sort(Comparator.comparing(Object::toString));
assertEquals(expectedList, actualList);
}
+ public static void assertContainsAll(Collection expected, Collection actual) {
+ ArrayList expectedList = new ArrayList<>(expected);
+ ArrayList actualList = new ArrayList<>(actual);
+ expectedList.sort(Comparator.comparing(Object::toString));
+ Iterator expectedIterator = expectedList.iterator();
+
+ actualList.sort(Comparator.comparing(Object::toString));
+
+ for (T actualItem : actualList) {
+ boolean found = false;
+ while (expectedIterator.hasNext()) {
+ if (expectedIterator.next().equals(actualItem)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // TODO: better message when actualItem is present twice in actualList,
+ // but only once in expectedList
+ fail(String.format("%s not found in %s", actualItem, expectedList));
+ }
+ }
+ }
+
+ public static void assertLength(int expected, Collection actual) {
+ assertEquals(String.format("Size of collection %s:", actual), expected, actual.size());
+ }
+
public static ArrayList lazyLongIteratorToList(LazyLongIterator input) {
ArrayList inputList = new ArrayList<>();
Iterator inputIt = LazyLongIterators.eager(input);
inputIt.forEachRemaining(inputList::add);
return inputList;
}
public static String[] readZstFile(Path zstFile) throws IOException {
ZstdInputStream zis = new ZstdInputStream(new FileInputStream(zstFile.toFile()));
return (new String(zis.readAllBytes())).split("\n");
}
}
diff --git a/java/src/test/java/org/softwareheritage/graph/rpc/CountEdgesTest.java b/java/src/test/java/org/softwareheritage/graph/rpc/CountEdgesTest.java
index 7445671..bc0afc6 100644
--- a/java/src/test/java/org/softwareheritage/graph/rpc/CountEdgesTest.java
+++ b/java/src/test/java/org/softwareheritage/graph/rpc/CountEdgesTest.java
@@ -1,84 +1,109 @@
/*
* Copyright (c) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
package org.softwareheritage.graph.rpc;
import com.google.protobuf.FieldMask;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import org.junit.jupiter.api.Test;
import org.softwareheritage.graph.SWHID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
public class CountEdgesTest extends TraversalServiceTest {
private TraversalRequest.Builder getTraversalRequestBuilder(SWHID src) {
return TraversalRequest.newBuilder().addSrc(src.toString());
}
@Test
public void testSwhidErrors() {
StatusRuntimeException thrown;
thrown = assertThrows(StatusRuntimeException.class, () -> client
.countEdges(TraversalRequest.newBuilder().addSrc(fakeSWHID("cnt", 404).toString()).build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
thrown = assertThrows(StatusRuntimeException.class, () -> client.countEdges(
TraversalRequest.newBuilder().addSrc("swh:1:lol:0000000000000000000000000000000000000001").build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
thrown = assertThrows(StatusRuntimeException.class, () -> client.countEdges(
TraversalRequest.newBuilder().addSrc("swh:1:cnt:000000000000000000000000000000000000000z").build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
}
@Test
public void forwardFromRoot() {
CountResponse actual = client.countEdges(getTraversalRequestBuilder(new SWHID(TEST_ORIGIN_ID)).build());
assertEquals(13, actual.getCount());
}
+ @ParameterizedTest
+ @ValueSource(ints = {0, 1, 2, 13, 14, 15, Integer.MAX_VALUE})
+ public void forwardFromRootWithLimit(int limit) {
+ CountResponse actual = client
+ .countEdges(getTraversalRequestBuilder(new SWHID(TEST_ORIGIN_ID)).setMaxMatchingNodes(limit).build());
+
+ switch (limit) {
+ case 1:
+ // 1. origin -> snp:20
+ assertEquals(1, actual.getCount());
+ break;
+ case 2:
+ // 1. origin -> snp:20
+ // 2. either snp:20 -> rev:9 or snp:20 -> rel:10
+ assertEquals(3, actual.getCount());
+ break;
+ default :
+ // Counts all edges
+ assertEquals(13, actual.getCount());
+ break;
+ }
+ }
+
@Test
public void forwardFromMiddle() {
CountResponse actual = client.countEdges(getTraversalRequestBuilder(fakeSWHID("dir", 12)).build());
assertEquals(7, actual.getCount());
}
@Test
public void forwardRelRev() {
CountResponse actual = client
.countEdges(getTraversalRequestBuilder(fakeSWHID("rel", 10)).setEdges("rel:rev,rev:rev").build());
assertEquals(2, actual.getCount());
}
@Test
public void backwardFromMiddle() {
CountResponse actual = client.countEdges(
getTraversalRequestBuilder(fakeSWHID("dir", 12)).setDirection(GraphDirection.BACKWARD).build());
assertEquals(3, actual.getCount());
}
@Test
public void backwardFromLeaf() {
CountResponse actual = client.countEdges(
getTraversalRequestBuilder(fakeSWHID("cnt", 4)).setDirection(GraphDirection.BACKWARD).build());
assertEquals(12, actual.getCount());
}
@Test
public void backwardRevToRevRevToRel() {
CountResponse actual = client.countEdges(getTraversalRequestBuilder(fakeSWHID("rev", 3))
.setEdges("rev:rev,rev:rel").setDirection(GraphDirection.BACKWARD).build());
assertEquals(5, actual.getCount());
}
@Test
public void testWithEmptyMask() {
CountResponse actual = client.countEdges(
getTraversalRequestBuilder(fakeSWHID("dir", 12)).setMask(FieldMask.getDefaultInstance()).build());
assertEquals(7, actual.getCount());
}
}
diff --git a/java/src/test/java/org/softwareheritage/graph/rpc/CountNodesTest.java b/java/src/test/java/org/softwareheritage/graph/rpc/CountNodesTest.java
index a0bebc1..97792c5 100644
--- a/java/src/test/java/org/softwareheritage/graph/rpc/CountNodesTest.java
+++ b/java/src/test/java/org/softwareheritage/graph/rpc/CountNodesTest.java
@@ -1,84 +1,107 @@
/*
* Copyright (c) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
package org.softwareheritage.graph.rpc;
import com.google.protobuf.FieldMask;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import org.junit.jupiter.api.Test;
import org.softwareheritage.graph.SWHID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
public class CountNodesTest extends TraversalServiceTest {
private TraversalRequest.Builder getTraversalRequestBuilder(SWHID src) {
return TraversalRequest.newBuilder().addSrc(src.toString());
}
@Test
public void testSwhidErrors() {
StatusRuntimeException thrown;
thrown = assertThrows(StatusRuntimeException.class, () -> client
.countNodes(TraversalRequest.newBuilder().addSrc(fakeSWHID("cnt", 404).toString()).build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
thrown = assertThrows(StatusRuntimeException.class, () -> client.countNodes(
TraversalRequest.newBuilder().addSrc("swh:1:lol:0000000000000000000000000000000000000001").build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
thrown = assertThrows(StatusRuntimeException.class, () -> client.countNodes(
TraversalRequest.newBuilder().addSrc("swh:1:cnt:000000000000000000000000000000000000000z").build()));
assertEquals(Status.INVALID_ARGUMENT.getCode(), thrown.getStatus().getCode());
}
@Test
public void forwardFromRoot() {
CountResponse actual = client.countNodes(getTraversalRequestBuilder(new SWHID(TEST_ORIGIN_ID)).build());
assertEquals(12, actual.getCount());
}
+ @ParameterizedTest
+ @ValueSource(ints = {0, 1, 2, 5, 11, 12, 13, 14, 15, Integer.MAX_VALUE})
+ public void forwardFromRootWithLimit(int limit) {
+ CountResponse actual = client
+ .countNodes(getTraversalRequestBuilder(new SWHID(TEST_ORIGIN_ID)).setMaxMatchingNodes(limit).build());
+
+ if (limit == 0) {
+ assertEquals(12, actual.getCount());
+ } else {
+ assertEquals(Math.min(limit, 12), actual.getCount());
+ }
+ }
+
@Test
public void forwardFromMiddle() {
CountResponse actual = client.countNodes(getTraversalRequestBuilder(fakeSWHID("dir", 12)).build());
assertEquals(8, actual.getCount());
}
@Test
public void forwardRelRev() {
CountResponse actual = client
.countNodes(getTraversalRequestBuilder(fakeSWHID("rel", 10)).setEdges("rel:rev,rev:rev").build());
assertEquals(3, actual.getCount());
}
@Test
public void backwardFromMiddle() {
CountResponse actual = client.countNodes(
getTraversalRequestBuilder(fakeSWHID("dir", 12)).setDirection(GraphDirection.BACKWARD).build());
assertEquals(4, actual.getCount());
}
@Test
public void backwardFromLeaf() {
CountResponse actual = client.countNodes(
getTraversalRequestBuilder(fakeSWHID("cnt", 4)).setDirection(GraphDirection.BACKWARD).build());
assertEquals(11, actual.getCount());
}
@Test
public void backwardRevToRevRevToRel() {
CountResponse actual = client.countNodes(getTraversalRequestBuilder(fakeSWHID("rev", 3))
.setEdges("rev:rev,rev:rel").setDirection(GraphDirection.BACKWARD).build());
assertEquals(6, actual.getCount());
}
+ @ParameterizedTest
+ @ValueSource(ints = {1, 2, 3, 4, 5, 6, 7})
+ public void backwardRevToRevRevToRelWithLimit(int limit) {
+ CountResponse actual = client.countNodes(getTraversalRequestBuilder(fakeSWHID("rev", 3))
+ .setEdges("rev:rev,rev:rel").setDirection(GraphDirection.BACKWARD).setMaxMatchingNodes(limit).build());
+ assertEquals(Math.min(limit, 6), actual.getCount());
+ }
+
@Test
public void testWithEmptyMask() {
CountResponse actual = client.countNodes(
getTraversalRequestBuilder(fakeSWHID("dir", 12)).setMask(FieldMask.getDefaultInstance()).build());
assertEquals(8, actual.getCount());
}
}
diff --git a/java/src/test/java/org/softwareheritage/graph/rpc/TraverseLeavesTest.java b/java/src/test/java/org/softwareheritage/graph/rpc/TraverseLeavesTest.java
index 6e8a7ee..949fa00 100644
--- a/java/src/test/java/org/softwareheritage/graph/rpc/TraverseLeavesTest.java
+++ b/java/src/test/java/org/softwareheritage/graph/rpc/TraverseLeavesTest.java
@@ -1,100 +1,133 @@
/*
* Copyright (c) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
package org.softwareheritage.graph.rpc;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.softwareheritage.graph.GraphTest;
import org.softwareheritage.graph.SWHID;
import java.util.ArrayList;
public class TraverseLeavesTest extends TraversalServiceTest {
private TraversalRequest.Builder getLeavesRequestBuilder(SWHID src) {
return TraversalRequest.newBuilder().addSrc(src.toString())
.setReturnNodes(NodeFilter.newBuilder().setMaxTraversalSuccessors(0).build());
}
- @Test
- public void forwardFromSnp() {
- TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("snp", 20)).build();
-
+ private void _checkForwardFromSnp(int limit, ArrayList actualLeaves) {
ArrayList expectedLeaves = new ArrayList<>();
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000001"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000005"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000007"));
+ if (limit == 0) {
+ GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
+ } else {
+ GraphTest.assertContainsAll(expectedLeaves, actualLeaves);
+ GraphTest.assertLength(Math.max(0, Math.min(limit, 4)), actualLeaves);
+ }
+ }
+
+ @Test
+ public void forwardFromSnp() {
+ TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("snp", 20)).build();
+
ArrayList actualLeaves = getSWHIDs(client.traverse(request));
- GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
+
+ _checkForwardFromSnp(0, actualLeaves);
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 1, 2, 3, 4, 5, Integer.MAX_VALUE})
+ public void forwardFromSnpWithLimit(int limit) {
+ TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("snp", 20)).setMaxMatchingNodes(limit).build();
+
+ ArrayList actualLeaves = getSWHIDs(client.traverse(request));
+
+ _checkForwardFromSnp(limit, actualLeaves);
}
@Test
public void forwardFromRel() {
TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("rel", 19)).build();
ArrayList actualLeaves = getSWHIDs(client.traverse(request));
ArrayList expectedLeaves = new ArrayList<>();
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000015"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000014"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000001"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000005"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000007"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000011"));
GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
}
@Test
public void backwardFromLeaf() {
TraversalRequest request1 = getLeavesRequestBuilder(fakeSWHID("cnt", 15)).setDirection(GraphDirection.BACKWARD)
.build();
ArrayList actualLeaves1 = getSWHIDs(client.traverse(request1));
ArrayList expectedLeaves1 = new ArrayList<>();
expectedLeaves1.add(new SWHID("swh:1:rel:0000000000000000000000000000000000000019"));
GraphTest.assertEqualsAnyOrder(expectedLeaves1, actualLeaves1);
TraversalRequest request2 = getLeavesRequestBuilder(fakeSWHID("cnt", 4)).setDirection(GraphDirection.BACKWARD)
.build();
ArrayList actualLeaves2 = getSWHIDs(client.traverse(request2));
ArrayList expectedLeaves2 = new ArrayList<>();
expectedLeaves2.add(new SWHID(TEST_ORIGIN_ID));
expectedLeaves2.add(new SWHID("swh:1:rel:0000000000000000000000000000000000000019"));
GraphTest.assertEqualsAnyOrder(expectedLeaves2, actualLeaves2);
}
@Test
public void forwardRevToRevOnly() {
TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("rev", 18)).setEdges("rev:rev").build();
ArrayList actualLeaves = getSWHIDs(client.traverse(request));
ArrayList expectedLeaves = new ArrayList<>();
expectedLeaves.add(new SWHID("swh:1:rev:0000000000000000000000000000000000000003"));
GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
}
@Test
public void forwardDirToAll() {
TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("dir", 8)).setEdges("dir:*").build();
ArrayList actualLeaves = getSWHIDs(client.traverse(request));
ArrayList expectedLeaves = new ArrayList<>();
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000005"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000001"));
expectedLeaves.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000007"));
GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
}
@Test
public void backwardCntToDirDirToDir() {
TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("cnt", 5)).setEdges("cnt:dir,dir:dir")
.setDirection(GraphDirection.BACKWARD).build();
ArrayList actualLeaves = getSWHIDs(client.traverse(request));
ArrayList expectedLeaves = new ArrayList<>();
expectedLeaves.add(new SWHID("swh:1:dir:0000000000000000000000000000000000000012"));
GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
}
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 1, 2, Integer.MAX_VALUE})
+ public void backwardCntToDirDirToDirWithLimit(int limit) {
+ TraversalRequest request = getLeavesRequestBuilder(fakeSWHID("cnt", 5)).setEdges("cnt:dir,dir:dir")
+ .setDirection(GraphDirection.BACKWARD).setMaxMatchingNodes(limit).build();
+ ArrayList actualLeaves = getSWHIDs(client.traverse(request));
+ ArrayList expectedLeaves = new ArrayList<>();
+ expectedLeaves.add(new SWHID("swh:1:dir:0000000000000000000000000000000000000012"));
+ GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves);
+ }
}
diff --git a/proto/swhgraph.proto b/proto/swhgraph.proto
index 7c40a6e..eb30969 100644
--- a/proto/swhgraph.proto
+++ b/proto/swhgraph.proto
@@ -1,316 +1,319 @@
syntax = "proto3";
import "google/protobuf/field_mask.proto";
option java_multiple_files = true;
option java_package = "org.softwareheritage.graph.rpc";
option java_outer_classname = "GraphService";
package swh.graph;
/* Graph traversal service */
service TraversalService {
/* GetNode returns a single Node and its properties. */
rpc GetNode (GetNodeRequest) returns (Node);
/* Traverse performs a breadth-first graph traversal from a set of source
* nodes, then streams the nodes it encounters (if they match a given
* return filter), along with their properties.
*/
rpc Traverse (TraversalRequest) returns (stream Node);
/* FindPathTo searches for a shortest path between a set of source nodes
* and a node that matches a specific *criteria*.
*
* It does so by performing a breadth-first search from the source node,
* until any node that matches the given criteria is found, then follows
* back its parents to return a shortest path from the source set to that
* node.
*/
rpc FindPathTo (FindPathToRequest) returns (Path);
/* FindPathBetween searches for a shortest path between a set of source
* nodes and a set of destination nodes.
*
* It does so by performing a *bidirectional breadth-first search*, i.e.,
* two parallel breadth-first searches, one from the source set ("src-BFS")
* and one from the destination set ("dst-BFS"), until both searches find a
* common node that joins their visited sets. This node is called the
* "midpoint node".
* The path returned is the path src -> ... -> midpoint -> ... -> dst,
* which is always a shortest path between src and dst.
*
* The graph direction of both BFS can be configured separately. By
* default, the dst-BFS will use the graph in the opposite direction than
* the src-BFS (if direction = FORWARD, by default direction_reverse =
* BACKWARD, and vice-versa). The default behavior is thus to search for
* a shortest path between two nodes in a given direction. However, one
* can also specify FORWARD or BACKWARD for *both* the src-BFS and the
* dst-BFS. This will search for a common descendant or a common ancestor
* between the two sets, respectively. These will be the midpoints of the
* returned path.
*/
rpc FindPathBetween (FindPathBetweenRequest) returns (Path);
/* CountNodes does the same as Traverse, but only returns the number of
* nodes accessed during the traversal. */
rpc CountNodes (TraversalRequest) returns (CountResponse);
/* CountEdges does the same as Traverse, but only returns the number of
* edges accessed during the traversal. */
rpc CountEdges (TraversalRequest) returns (CountResponse);
/* Stats returns various statistics on the overall graph. */
rpc Stats (StatsRequest) returns (StatsResponse);
}
/* Direction of the graph */
enum GraphDirection {
/* Forward DAG: ori -> snp -> rel -> rev -> dir -> cnt */
FORWARD = 0;
/* Transposed DAG: cnt -> dir -> rev -> rel -> snp -> ori */
BACKWARD = 1;
}
/* Describe a node to return */
message GetNodeRequest {
/* SWHID of the node to return */
string swhid = 1;
/* FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
* By default, all fields are returned. */
optional google.protobuf.FieldMask mask = 8;
}
/* TraversalRequest describes how a breadth-first traversal should be
* performed, and what should be returned to the client. */
message TraversalRequest {
/* Set of source nodes (SWHIDs) */
repeated string src = 1;
/* Direction of the graph to traverse. Defaults to FORWARD. */
GraphDirection direction = 2;
/* Edge restriction string (e.g. "rev:dir,dir:cnt").
* Defaults to "*" (all). */
optional string edges = 3;
/* Maximum number of edges accessed in the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_edges = 4;
/* Do not return nodes with a depth lower than this number.
* By default, all depths are returned. */
optional int64 min_depth = 5;
/* Maximum depth of the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_depth = 6;
/* Filter which nodes will be sent to the stream. By default, all nodes are
* returned. */
optional NodeFilter return_nodes = 7;
/* FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
* By default, all fields are returned. */
optional google.protobuf.FieldMask mask = 8;
+ /* Maximum number of matching results before stopping. For Traverse(), this is
+ * the total number of results. Defaults to infinite. */
+ optional int64 max_matching_nodes = 9;
}
/* FindPathToRequest describes a request to find a shortest path between a
* set of nodes and a given target criteria, as well as what should be returned
* in the path.
*/
message FindPathToRequest {
/* Set of source nodes (SWHIDs) */
repeated string src = 1;
/* Target criteria, i.e., what constitutes a valid path destination. */
NodeFilter target = 2;
/* Direction of the graph to traverse. Defaults to FORWARD. */
GraphDirection direction = 3;
/* Edge restriction string (e.g. "rev:dir,dir:cnt").
* Defaults to "*" (all). */
optional string edges = 4;
/* Maximum number of edges accessed in the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_edges = 5;
/* Maximum depth of the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_depth = 6;
/* FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
* By default, all fields are returned. */
optional google.protobuf.FieldMask mask = 7;
}
/* FindPathToRequest describes a request to find a shortest path between a
* set of source nodes and a set of destination nodes. It works by performing a
* bidirectional breadth-first traversal from both sets at the same time.
*/
message FindPathBetweenRequest {
/* Set of source nodes (SWHIDs) */
repeated string src = 1;
/* Set of destination nodes (SWHIDs) */
repeated string dst = 2;
/* Direction of the graph to traverse from the source set. Defaults to
* FORWARD. */
GraphDirection direction = 3;
/* Direction of the graph to traverse from the destination set. Defaults to
* the opposite of `direction`. If direction and direction_reverse are
* identical, it will find the first common successor of both sets in the
* given direction. */
optional GraphDirection direction_reverse = 4;
/* Edge restriction string for the traversal from the source set.
* (e.g. "rev:dir,dir:cnt"). Defaults to "*" (all). */
optional string edges = 5;
/* Edge restriction string for the reverse traversal from the destination
* set.
* If not specified:
* - If `edges` is not specified either, defaults to "*"
* - If direction == direction_reverse, defaults to `edges`
* - If direction != direction_reverse, defaults to the reverse of `edges`
* (e.g. "rev:dir" becomes "dir:rev").
*/
optional string edges_reverse = 6;
/* Maximum number of edges accessed in the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_edges = 7;
/* Maximum depth of the traversal, after which it stops.
* Defaults to infinite. */
optional int64 max_depth = 8;
/* FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
* By default, all fields are returned. */
optional google.protobuf.FieldMask mask = 9;
}
/* Represents various criteria that make a given node "valid". A node is
* only valid if all the subcriteria present in this message are fulfilled.
*/
message NodeFilter {
/* Node restriction string. (e.g. "dir,cnt,rev"). Defaults to "*" (all). */
optional string types = 1;
/* Minimum number of successors encountered *during the traversal*.
* Default: no constraint */
optional int64 min_traversal_successors = 2;
/* Maximum number of successors encountered *during the traversal*.
* Default: no constraint */
optional int64 max_traversal_successors = 3;
}
/* Represents a node in the graph. */
message Node {
/* The SWHID of the graph node. */
string swhid = 1;
/* List of relevant successors of this node. */
repeated Successor successor = 2;
/* Number of relevant successors. */
optional int64 num_successors = 9;
/* Node properties */
oneof data {
ContentData cnt = 3;
RevisionData rev = 5;
ReleaseData rel = 6;
OriginData ori = 8;
};
}
/* Represents a path in the graph. */
message Path {
/* List of nodes in the path, from source to destination */
repeated Node node = 1;
/* Index of the "midpoint" of the path. For paths obtained with
* bidirectional search queries, this is the node that joined the two
* sets together. When looking for a common ancestor between two nodes by
* performing a FindPathBetween search with two backward graphs, this will
* be the index of the common ancestor in the path. */
optional int32 midpoint_index = 2;
}
/* Represents a successor of a given node. */
message Successor {
/* The SWHID of the successor */
optional string swhid = 1;
/* A list of edge labels for the given edge */
repeated EdgeLabel label = 2;
}
/* Content node properties */
message ContentData {
/* Length of the blob, in bytes */
optional int64 length = 1;
/* Whether the content was skipped during ingestion. */
optional bool is_skipped = 2;
}
/* Revision node properties */
message RevisionData {
/* Revision author ID (anonymized) */
optional int64 author = 1;
/* UNIX timestamp of the revision date (UTC) */
optional int64 author_date = 2;
/* Timezone of the revision author date as an offset from UTC */
optional int32 author_date_offset = 3;
/* Revision committer ID (anonymized) */
optional int64 committer = 4;
/* UNIX timestamp of the revision committer date (UTC) */
optional int64 committer_date = 5;
/* Timezone of the revision committer date as an offset from UTC */
optional int32 committer_date_offset = 6;
/* Revision message */
optional bytes message = 7;
}
/* Release node properties */
message ReleaseData {
/* Release author ID (anonymized) */
optional int64 author = 1;
/* UNIX timestamp of the release date (UTC) */
optional int64 author_date = 2;
/* Timezone of the release author date as an offset from UTC */
optional int32 author_date_offset = 3;
/* Release name */
optional bytes name = 4;
/* Release message */
optional bytes message = 5;
}
/* Origin node properties */
message OriginData {
/* URL of the origin */
optional string url = 1;
}
message EdgeLabel {
/* Directory entry name for directories, branch name for snapshots */
bytes name = 1;
/* Entry permission (only set for directories). */
int32 permission = 2;
}
message CountResponse {
int64 count = 1;
}
message StatsRequest {
}
message StatsResponse {
/* Number of nodes in the graph */
int64 num_nodes = 1;
/* Number of edges in the graph */
int64 num_edges = 2;
/* Ratio between the graph size and the information-theoretical lower
* bound */
double compression_ratio = 3;
/* Number of bits per node (overall graph size in bits divided by the
* number of nodes) */
double bits_per_node = 4;
/* Number of bits per edge (overall graph size in bits divided by the
* number of arcs). */
double bits_per_edge = 5;
double avg_locality = 6;
/* Smallest indegree */
int64 indegree_min = 7;
/* Largest indegree */
int64 indegree_max = 8;
/* Average indegree */
double indegree_avg = 9;
/* Smallest outdegree */
int64 outdegree_min = 10;
/* Largest outdegree */
int64 outdegree_max = 11;
/* Average outdegree */
double outdegree_avg = 12;
}
diff --git a/swh/graph/grpc/swhgraph_pb2.py b/swh/graph/grpc/swhgraph_pb2.py
index 2809a58..55646ea 100644
--- a/swh/graph/grpc/swhgraph_pb2.py
+++ b/swh/graph/grpc/swhgraph_pb2.py
@@ -1,196 +1,196 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: swh/graph/grpc/swhgraph.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from google.protobuf import field_mask_pb2 as google_dot_protobuf_dot_field__mask__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dswh/graph/grpc/swhgraph.proto\x12\tswh.graph\x1a google/protobuf/field_mask.proto\"W\n\x0eGetNodeRequest\x12\r\n\x05swhid\x18\x01 \x01(\t\x12-\n\x04mask\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x00\x88\x01\x01\x42\x07\n\x05_mask\"\xd8\x02\n\x10TraversalRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12,\n\tdirection\x18\x02 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x12\n\x05\x65\x64ges\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tmax_edges\x18\x04 \x01(\x03H\x01\x88\x01\x01\x12\x16\n\tmin_depth\x18\x05 \x01(\x03H\x02\x88\x01\x01\x12\x16\n\tmax_depth\x18\x06 \x01(\x03H\x03\x88\x01\x01\x12\x30\n\x0creturn_nodes\x18\x07 \x01(\x0b\x32\x15.swh.graph.NodeFilterH\x04\x88\x01\x01\x12-\n\x04mask\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x05\x88\x01\x01\x42\x08\n\x06_edgesB\x0c\n\n_max_edgesB\x0c\n\n_min_depthB\x0c\n\n_max_depthB\x0f\n\r_return_nodesB\x07\n\x05_mask\"\x97\x02\n\x11\x46indPathToRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12%\n\x06target\x18\x02 \x01(\x0b\x32\x15.swh.graph.NodeFilter\x12,\n\tdirection\x18\x03 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x12\n\x05\x65\x64ges\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tmax_edges\x18\x05 \x01(\x03H\x01\x88\x01\x01\x12\x16\n\tmax_depth\x18\x06 \x01(\x03H\x02\x88\x01\x01\x12-\n\x04mask\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x03\x88\x01\x01\x42\x08\n\x06_edgesB\x0c\n\n_max_edgesB\x0c\n\n_max_depthB\x07\n\x05_mask\"\x81\x03\n\x16\x46indPathBetweenRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12\x0b\n\x03\x64st\x18\x02 \x03(\t\x12,\n\tdirection\x18\x03 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x39\n\x11\x64irection_reverse\x18\x04 \x01(\x0e\x32\x19.swh.graph.GraphDirectionH\x00\x88\x01\x01\x12\x12\n\x05\x65\x64ges\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\redges_reverse\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tmax_edges\x18\x07 \x01(\x03H\x03\x88\x01\x01\x12\x16\n\tmax_depth\x18\x08 \x01(\x03H\x04\x88\x01\x01\x12-\n\x04mask\x18\t \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x05\x88\x01\x01\x42\x14\n\x12_direction_reverseB\x08\n\x06_edgesB\x10\n\x0e_edges_reverseB\x0c\n\n_max_edgesB\x0c\n\n_max_depthB\x07\n\x05_mask\"\xb2\x01\n\nNodeFilter\x12\x12\n\x05types\x18\x01 \x01(\tH\x00\x88\x01\x01\x12%\n\x18min_traversal_successors\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12%\n\x18max_traversal_successors\x18\x03 \x01(\x03H\x02\x88\x01\x01\x42\x08\n\x06_typesB\x1b\n\x19_min_traversal_successorsB\x1b\n\x19_max_traversal_successors\"\x92\x02\n\x04Node\x12\r\n\x05swhid\x18\x01 \x01(\t\x12\'\n\tsuccessor\x18\x02 \x03(\x0b\x32\x14.swh.graph.Successor\x12\x1b\n\x0enum_successors\x18\t \x01(\x03H\x01\x88\x01\x01\x12%\n\x03\x63nt\x18\x03 \x01(\x0b\x32\x16.swh.graph.ContentDataH\x00\x12&\n\x03rev\x18\x05 \x01(\x0b\x32\x17.swh.graph.RevisionDataH\x00\x12%\n\x03rel\x18\x06 \x01(\x0b\x32\x16.swh.graph.ReleaseDataH\x00\x12$\n\x03ori\x18\x08 \x01(\x0b\x32\x15.swh.graph.OriginDataH\x00\x42\x06\n\x04\x64\x61taB\x11\n\x0f_num_successors\"U\n\x04Path\x12\x1d\n\x04node\x18\x01 \x03(\x0b\x32\x0f.swh.graph.Node\x12\x1b\n\x0emidpoint_index\x18\x02 \x01(\x05H\x00\x88\x01\x01\x42\x11\n\x0f_midpoint_index\"N\n\tSuccessor\x12\x12\n\x05swhid\x18\x01 \x01(\tH\x00\x88\x01\x01\x12#\n\x05label\x18\x02 \x03(\x0b\x32\x14.swh.graph.EdgeLabelB\x08\n\x06_swhid\"U\n\x0b\x43ontentData\x12\x13\n\x06length\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x17\n\nis_skipped\x18\x02 \x01(\x08H\x01\x88\x01\x01\x42\t\n\x07_lengthB\r\n\x0b_is_skipped\"\xc6\x02\n\x0cRevisionData\x12\x13\n\x06\x61uthor\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x18\n\x0b\x61uthor_date\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12\x61uthor_date_offset\x18\x03 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tcommitter\x18\x04 \x01(\x03H\x03\x88\x01\x01\x12\x1b\n\x0e\x63ommitter_date\x18\x05 \x01(\x03H\x04\x88\x01\x01\x12\"\n\x15\x63ommitter_date_offset\x18\x06 \x01(\x05H\x05\x88\x01\x01\x12\x14\n\x07message\x18\x07 \x01(\x0cH\x06\x88\x01\x01\x42\t\n\x07_authorB\x0e\n\x0c_author_dateB\x15\n\x13_author_date_offsetB\x0c\n\n_committerB\x11\n\x0f_committer_dateB\x18\n\x16_committer_date_offsetB\n\n\x08_message\"\xcd\x01\n\x0bReleaseData\x12\x13\n\x06\x61uthor\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x18\n\x0b\x61uthor_date\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12\x61uthor_date_offset\x18\x03 \x01(\x05H\x02\x88\x01\x01\x12\x11\n\x04name\x18\x04 \x01(\x0cH\x03\x88\x01\x01\x12\x14\n\x07message\x18\x05 \x01(\x0cH\x04\x88\x01\x01\x42\t\n\x07_authorB\x0e\n\x0c_author_dateB\x15\n\x13_author_date_offsetB\x07\n\x05_nameB\n\n\x08_message\"&\n\nOriginData\x12\x10\n\x03url\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_url\"-\n\tEdgeLabel\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x12\n\npermission\x18\x02 \x01(\x05\"\x1e\n\rCountResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\"\x0e\n\x0cStatsRequest\"\x9b\x02\n\rStatsResponse\x12\x11\n\tnum_nodes\x18\x01 \x01(\x03\x12\x11\n\tnum_edges\x18\x02 \x01(\x03\x12\x19\n\x11\x63ompression_ratio\x18\x03 \x01(\x01\x12\x15\n\rbits_per_node\x18\x04 \x01(\x01\x12\x15\n\rbits_per_edge\x18\x05 \x01(\x01\x12\x14\n\x0c\x61vg_locality\x18\x06 \x01(\x01\x12\x14\n\x0cindegree_min\x18\x07 \x01(\x03\x12\x14\n\x0cindegree_max\x18\x08 \x01(\x03\x12\x14\n\x0cindegree_avg\x18\t \x01(\x01\x12\x15\n\routdegree_min\x18\n \x01(\x03\x12\x15\n\routdegree_max\x18\x0b \x01(\x03\x12\x15\n\routdegree_avg\x18\x0c \x01(\x01*+\n\x0eGraphDirection\x12\x0b\n\x07\x46ORWARD\x10\x00\x12\x0c\n\x08\x42\x41\x43KWARD\x10\x01\x32\xcf\x03\n\x10TraversalService\x12\x35\n\x07GetNode\x12\x19.swh.graph.GetNodeRequest\x1a\x0f.swh.graph.Node\x12:\n\x08Traverse\x12\x1b.swh.graph.TraversalRequest\x1a\x0f.swh.graph.Node0\x01\x12;\n\nFindPathTo\x12\x1c.swh.graph.FindPathToRequest\x1a\x0f.swh.graph.Path\x12\x45\n\x0f\x46indPathBetween\x12!.swh.graph.FindPathBetweenRequest\x1a\x0f.swh.graph.Path\x12\x43\n\nCountNodes\x12\x1b.swh.graph.TraversalRequest\x1a\x18.swh.graph.CountResponse\x12\x43\n\nCountEdges\x12\x1b.swh.graph.TraversalRequest\x1a\x18.swh.graph.CountResponse\x12:\n\x05Stats\x12\x17.swh.graph.StatsRequest\x1a\x18.swh.graph.StatsResponseB0\n\x1eorg.softwareheritage.graph.rpcB\x0cGraphServiceP\x01\x62\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dswh/graph/grpc/swhgraph.proto\x12\tswh.graph\x1a google/protobuf/field_mask.proto\"W\n\x0eGetNodeRequest\x12\r\n\x05swhid\x18\x01 \x01(\t\x12-\n\x04mask\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x00\x88\x01\x01\x42\x07\n\x05_mask\"\x90\x03\n\x10TraversalRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12,\n\tdirection\x18\x02 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x12\n\x05\x65\x64ges\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tmax_edges\x18\x04 \x01(\x03H\x01\x88\x01\x01\x12\x16\n\tmin_depth\x18\x05 \x01(\x03H\x02\x88\x01\x01\x12\x16\n\tmax_depth\x18\x06 \x01(\x03H\x03\x88\x01\x01\x12\x30\n\x0creturn_nodes\x18\x07 \x01(\x0b\x32\x15.swh.graph.NodeFilterH\x04\x88\x01\x01\x12-\n\x04mask\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x05\x88\x01\x01\x12\x1f\n\x12max_matching_nodes\x18\t \x01(\x03H\x06\x88\x01\x01\x42\x08\n\x06_edgesB\x0c\n\n_max_edgesB\x0c\n\n_min_depthB\x0c\n\n_max_depthB\x0f\n\r_return_nodesB\x07\n\x05_maskB\x15\n\x13_max_matching_nodes\"\x97\x02\n\x11\x46indPathToRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12%\n\x06target\x18\x02 \x01(\x0b\x32\x15.swh.graph.NodeFilter\x12,\n\tdirection\x18\x03 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x12\n\x05\x65\x64ges\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tmax_edges\x18\x05 \x01(\x03H\x01\x88\x01\x01\x12\x16\n\tmax_depth\x18\x06 \x01(\x03H\x02\x88\x01\x01\x12-\n\x04mask\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x03\x88\x01\x01\x42\x08\n\x06_edgesB\x0c\n\n_max_edgesB\x0c\n\n_max_depthB\x07\n\x05_mask\"\x81\x03\n\x16\x46indPathBetweenRequest\x12\x0b\n\x03src\x18\x01 \x03(\t\x12\x0b\n\x03\x64st\x18\x02 \x03(\t\x12,\n\tdirection\x18\x03 \x01(\x0e\x32\x19.swh.graph.GraphDirection\x12\x39\n\x11\x64irection_reverse\x18\x04 \x01(\x0e\x32\x19.swh.graph.GraphDirectionH\x00\x88\x01\x01\x12\x12\n\x05\x65\x64ges\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\redges_reverse\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tmax_edges\x18\x07 \x01(\x03H\x03\x88\x01\x01\x12\x16\n\tmax_depth\x18\x08 \x01(\x03H\x04\x88\x01\x01\x12-\n\x04mask\x18\t \x01(\x0b\x32\x1a.google.protobuf.FieldMaskH\x05\x88\x01\x01\x42\x14\n\x12_direction_reverseB\x08\n\x06_edgesB\x10\n\x0e_edges_reverseB\x0c\n\n_max_edgesB\x0c\n\n_max_depthB\x07\n\x05_mask\"\xb2\x01\n\nNodeFilter\x12\x12\n\x05types\x18\x01 \x01(\tH\x00\x88\x01\x01\x12%\n\x18min_traversal_successors\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12%\n\x18max_traversal_successors\x18\x03 \x01(\x03H\x02\x88\x01\x01\x42\x08\n\x06_typesB\x1b\n\x19_min_traversal_successorsB\x1b\n\x19_max_traversal_successors\"\x92\x02\n\x04Node\x12\r\n\x05swhid\x18\x01 \x01(\t\x12\'\n\tsuccessor\x18\x02 \x03(\x0b\x32\x14.swh.graph.Successor\x12\x1b\n\x0enum_successors\x18\t \x01(\x03H\x01\x88\x01\x01\x12%\n\x03\x63nt\x18\x03 \x01(\x0b\x32\x16.swh.graph.ContentDataH\x00\x12&\n\x03rev\x18\x05 \x01(\x0b\x32\x17.swh.graph.RevisionDataH\x00\x12%\n\x03rel\x18\x06 \x01(\x0b\x32\x16.swh.graph.ReleaseDataH\x00\x12$\n\x03ori\x18\x08 \x01(\x0b\x32\x15.swh.graph.OriginDataH\x00\x42\x06\n\x04\x64\x61taB\x11\n\x0f_num_successors\"U\n\x04Path\x12\x1d\n\x04node\x18\x01 \x03(\x0b\x32\x0f.swh.graph.Node\x12\x1b\n\x0emidpoint_index\x18\x02 \x01(\x05H\x00\x88\x01\x01\x42\x11\n\x0f_midpoint_index\"N\n\tSuccessor\x12\x12\n\x05swhid\x18\x01 \x01(\tH\x00\x88\x01\x01\x12#\n\x05label\x18\x02 \x03(\x0b\x32\x14.swh.graph.EdgeLabelB\x08\n\x06_swhid\"U\n\x0b\x43ontentData\x12\x13\n\x06length\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x17\n\nis_skipped\x18\x02 \x01(\x08H\x01\x88\x01\x01\x42\t\n\x07_lengthB\r\n\x0b_is_skipped\"\xc6\x02\n\x0cRevisionData\x12\x13\n\x06\x61uthor\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x18\n\x0b\x61uthor_date\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12\x61uthor_date_offset\x18\x03 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tcommitter\x18\x04 \x01(\x03H\x03\x88\x01\x01\x12\x1b\n\x0e\x63ommitter_date\x18\x05 \x01(\x03H\x04\x88\x01\x01\x12\"\n\x15\x63ommitter_date_offset\x18\x06 \x01(\x05H\x05\x88\x01\x01\x12\x14\n\x07message\x18\x07 \x01(\x0cH\x06\x88\x01\x01\x42\t\n\x07_authorB\x0e\n\x0c_author_dateB\x15\n\x13_author_date_offsetB\x0c\n\n_committerB\x11\n\x0f_committer_dateB\x18\n\x16_committer_date_offsetB\n\n\x08_message\"\xcd\x01\n\x0bReleaseData\x12\x13\n\x06\x61uthor\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x18\n\x0b\x61uthor_date\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12\x61uthor_date_offset\x18\x03 \x01(\x05H\x02\x88\x01\x01\x12\x11\n\x04name\x18\x04 \x01(\x0cH\x03\x88\x01\x01\x12\x14\n\x07message\x18\x05 \x01(\x0cH\x04\x88\x01\x01\x42\t\n\x07_authorB\x0e\n\x0c_author_dateB\x15\n\x13_author_date_offsetB\x07\n\x05_nameB\n\n\x08_message\"&\n\nOriginData\x12\x10\n\x03url\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_url\"-\n\tEdgeLabel\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x12\n\npermission\x18\x02 \x01(\x05\"\x1e\n\rCountResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\"\x0e\n\x0cStatsRequest\"\x9b\x02\n\rStatsResponse\x12\x11\n\tnum_nodes\x18\x01 \x01(\x03\x12\x11\n\tnum_edges\x18\x02 \x01(\x03\x12\x19\n\x11\x63ompression_ratio\x18\x03 \x01(\x01\x12\x15\n\rbits_per_node\x18\x04 \x01(\x01\x12\x15\n\rbits_per_edge\x18\x05 \x01(\x01\x12\x14\n\x0c\x61vg_locality\x18\x06 \x01(\x01\x12\x14\n\x0cindegree_min\x18\x07 \x01(\x03\x12\x14\n\x0cindegree_max\x18\x08 \x01(\x03\x12\x14\n\x0cindegree_avg\x18\t \x01(\x01\x12\x15\n\routdegree_min\x18\n \x01(\x03\x12\x15\n\routdegree_max\x18\x0b \x01(\x03\x12\x15\n\routdegree_avg\x18\x0c \x01(\x01*+\n\x0eGraphDirection\x12\x0b\n\x07\x46ORWARD\x10\x00\x12\x0c\n\x08\x42\x41\x43KWARD\x10\x01\x32\xcf\x03\n\x10TraversalService\x12\x35\n\x07GetNode\x12\x19.swh.graph.GetNodeRequest\x1a\x0f.swh.graph.Node\x12:\n\x08Traverse\x12\x1b.swh.graph.TraversalRequest\x1a\x0f.swh.graph.Node0\x01\x12;\n\nFindPathTo\x12\x1c.swh.graph.FindPathToRequest\x1a\x0f.swh.graph.Path\x12\x45\n\x0f\x46indPathBetween\x12!.swh.graph.FindPathBetweenRequest\x1a\x0f.swh.graph.Path\x12\x43\n\nCountNodes\x12\x1b.swh.graph.TraversalRequest\x1a\x18.swh.graph.CountResponse\x12\x43\n\nCountEdges\x12\x1b.swh.graph.TraversalRequest\x1a\x18.swh.graph.CountResponse\x12:\n\x05Stats\x12\x17.swh.graph.StatsRequest\x1a\x18.swh.graph.StatsResponseB0\n\x1eorg.softwareheritage.graph.rpcB\x0cGraphServiceP\x01\x62\x06proto3')
_GRAPHDIRECTION = DESCRIPTOR.enum_types_by_name['GraphDirection']
GraphDirection = enum_type_wrapper.EnumTypeWrapper(_GRAPHDIRECTION)
FORWARD = 0
BACKWARD = 1
_GETNODEREQUEST = DESCRIPTOR.message_types_by_name['GetNodeRequest']
_TRAVERSALREQUEST = DESCRIPTOR.message_types_by_name['TraversalRequest']
_FINDPATHTOREQUEST = DESCRIPTOR.message_types_by_name['FindPathToRequest']
_FINDPATHBETWEENREQUEST = DESCRIPTOR.message_types_by_name['FindPathBetweenRequest']
_NODEFILTER = DESCRIPTOR.message_types_by_name['NodeFilter']
_NODE = DESCRIPTOR.message_types_by_name['Node']
_PATH = DESCRIPTOR.message_types_by_name['Path']
_SUCCESSOR = DESCRIPTOR.message_types_by_name['Successor']
_CONTENTDATA = DESCRIPTOR.message_types_by_name['ContentData']
_REVISIONDATA = DESCRIPTOR.message_types_by_name['RevisionData']
_RELEASEDATA = DESCRIPTOR.message_types_by_name['ReleaseData']
_ORIGINDATA = DESCRIPTOR.message_types_by_name['OriginData']
_EDGELABEL = DESCRIPTOR.message_types_by_name['EdgeLabel']
_COUNTRESPONSE = DESCRIPTOR.message_types_by_name['CountResponse']
_STATSREQUEST = DESCRIPTOR.message_types_by_name['StatsRequest']
_STATSRESPONSE = DESCRIPTOR.message_types_by_name['StatsResponse']
GetNodeRequest = _reflection.GeneratedProtocolMessageType('GetNodeRequest', (_message.Message,), {
'DESCRIPTOR' : _GETNODEREQUEST,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.GetNodeRequest)
})
_sym_db.RegisterMessage(GetNodeRequest)
TraversalRequest = _reflection.GeneratedProtocolMessageType('TraversalRequest', (_message.Message,), {
'DESCRIPTOR' : _TRAVERSALREQUEST,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.TraversalRequest)
})
_sym_db.RegisterMessage(TraversalRequest)
FindPathToRequest = _reflection.GeneratedProtocolMessageType('FindPathToRequest', (_message.Message,), {
'DESCRIPTOR' : _FINDPATHTOREQUEST,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.FindPathToRequest)
})
_sym_db.RegisterMessage(FindPathToRequest)
FindPathBetweenRequest = _reflection.GeneratedProtocolMessageType('FindPathBetweenRequest', (_message.Message,), {
'DESCRIPTOR' : _FINDPATHBETWEENREQUEST,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.FindPathBetweenRequest)
})
_sym_db.RegisterMessage(FindPathBetweenRequest)
NodeFilter = _reflection.GeneratedProtocolMessageType('NodeFilter', (_message.Message,), {
'DESCRIPTOR' : _NODEFILTER,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.NodeFilter)
})
_sym_db.RegisterMessage(NodeFilter)
Node = _reflection.GeneratedProtocolMessageType('Node', (_message.Message,), {
'DESCRIPTOR' : _NODE,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.Node)
})
_sym_db.RegisterMessage(Node)
Path = _reflection.GeneratedProtocolMessageType('Path', (_message.Message,), {
'DESCRIPTOR' : _PATH,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.Path)
})
_sym_db.RegisterMessage(Path)
Successor = _reflection.GeneratedProtocolMessageType('Successor', (_message.Message,), {
'DESCRIPTOR' : _SUCCESSOR,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.Successor)
})
_sym_db.RegisterMessage(Successor)
ContentData = _reflection.GeneratedProtocolMessageType('ContentData', (_message.Message,), {
'DESCRIPTOR' : _CONTENTDATA,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.ContentData)
})
_sym_db.RegisterMessage(ContentData)
RevisionData = _reflection.GeneratedProtocolMessageType('RevisionData', (_message.Message,), {
'DESCRIPTOR' : _REVISIONDATA,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.RevisionData)
})
_sym_db.RegisterMessage(RevisionData)
ReleaseData = _reflection.GeneratedProtocolMessageType('ReleaseData', (_message.Message,), {
'DESCRIPTOR' : _RELEASEDATA,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.ReleaseData)
})
_sym_db.RegisterMessage(ReleaseData)
OriginData = _reflection.GeneratedProtocolMessageType('OriginData', (_message.Message,), {
'DESCRIPTOR' : _ORIGINDATA,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.OriginData)
})
_sym_db.RegisterMessage(OriginData)
EdgeLabel = _reflection.GeneratedProtocolMessageType('EdgeLabel', (_message.Message,), {
'DESCRIPTOR' : _EDGELABEL,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.EdgeLabel)
})
_sym_db.RegisterMessage(EdgeLabel)
CountResponse = _reflection.GeneratedProtocolMessageType('CountResponse', (_message.Message,), {
'DESCRIPTOR' : _COUNTRESPONSE,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.CountResponse)
})
_sym_db.RegisterMessage(CountResponse)
StatsRequest = _reflection.GeneratedProtocolMessageType('StatsRequest', (_message.Message,), {
'DESCRIPTOR' : _STATSREQUEST,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.StatsRequest)
})
_sym_db.RegisterMessage(StatsRequest)
StatsResponse = _reflection.GeneratedProtocolMessageType('StatsResponse', (_message.Message,), {
'DESCRIPTOR' : _STATSRESPONSE,
'__module__' : 'swh.graph.grpc.swhgraph_pb2'
# @@protoc_insertion_point(class_scope:swh.graph.StatsResponse)
})
_sym_db.RegisterMessage(StatsResponse)
_TRAVERSALSERVICE = DESCRIPTOR.services_by_name['TraversalService']
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\036org.softwareheritage.graph.rpcB\014GraphServiceP\001'
- _GRAPHDIRECTION._serialized_start=2854
- _GRAPHDIRECTION._serialized_end=2897
+ _GRAPHDIRECTION._serialized_start=2910
+ _GRAPHDIRECTION._serialized_end=2953
_GETNODEREQUEST._serialized_start=78
_GETNODEREQUEST._serialized_end=165
_TRAVERSALREQUEST._serialized_start=168
- _TRAVERSALREQUEST._serialized_end=512
- _FINDPATHTOREQUEST._serialized_start=515
- _FINDPATHTOREQUEST._serialized_end=794
- _FINDPATHBETWEENREQUEST._serialized_start=797
- _FINDPATHBETWEENREQUEST._serialized_end=1182
- _NODEFILTER._serialized_start=1185
- _NODEFILTER._serialized_end=1363
- _NODE._serialized_start=1366
- _NODE._serialized_end=1640
- _PATH._serialized_start=1642
- _PATH._serialized_end=1727
- _SUCCESSOR._serialized_start=1729
- _SUCCESSOR._serialized_end=1807
- _CONTENTDATA._serialized_start=1809
- _CONTENTDATA._serialized_end=1894
- _REVISIONDATA._serialized_start=1897
- _REVISIONDATA._serialized_end=2223
- _RELEASEDATA._serialized_start=2226
- _RELEASEDATA._serialized_end=2431
- _ORIGINDATA._serialized_start=2433
- _ORIGINDATA._serialized_end=2471
- _EDGELABEL._serialized_start=2473
- _EDGELABEL._serialized_end=2518
- _COUNTRESPONSE._serialized_start=2520
- _COUNTRESPONSE._serialized_end=2550
- _STATSREQUEST._serialized_start=2552
- _STATSREQUEST._serialized_end=2566
- _STATSRESPONSE._serialized_start=2569
- _STATSRESPONSE._serialized_end=2852
- _TRAVERSALSERVICE._serialized_start=2900
- _TRAVERSALSERVICE._serialized_end=3363
+ _TRAVERSALREQUEST._serialized_end=568
+ _FINDPATHTOREQUEST._serialized_start=571
+ _FINDPATHTOREQUEST._serialized_end=850
+ _FINDPATHBETWEENREQUEST._serialized_start=853
+ _FINDPATHBETWEENREQUEST._serialized_end=1238
+ _NODEFILTER._serialized_start=1241
+ _NODEFILTER._serialized_end=1419
+ _NODE._serialized_start=1422
+ _NODE._serialized_end=1696
+ _PATH._serialized_start=1698
+ _PATH._serialized_end=1783
+ _SUCCESSOR._serialized_start=1785
+ _SUCCESSOR._serialized_end=1863
+ _CONTENTDATA._serialized_start=1865
+ _CONTENTDATA._serialized_end=1950
+ _REVISIONDATA._serialized_start=1953
+ _REVISIONDATA._serialized_end=2279
+ _RELEASEDATA._serialized_start=2282
+ _RELEASEDATA._serialized_end=2487
+ _ORIGINDATA._serialized_start=2489
+ _ORIGINDATA._serialized_end=2527
+ _EDGELABEL._serialized_start=2529
+ _EDGELABEL._serialized_end=2574
+ _COUNTRESPONSE._serialized_start=2576
+ _COUNTRESPONSE._serialized_end=2606
+ _STATSREQUEST._serialized_start=2608
+ _STATSREQUEST._serialized_end=2622
+ _STATSRESPONSE._serialized_start=2625
+ _STATSRESPONSE._serialized_end=2908
+ _TRAVERSALSERVICE._serialized_start=2956
+ _TRAVERSALSERVICE._serialized_end=3419
# @@protoc_insertion_point(module_scope)
diff --git a/swh/graph/grpc/swhgraph_pb2.pyi b/swh/graph/grpc/swhgraph_pb2.pyi
index 8e108b0..b0ba4eb 100644
--- a/swh/graph/grpc/swhgraph_pb2.pyi
+++ b/swh/graph/grpc/swhgraph_pb2.pyi
@@ -1,683 +1,694 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
import builtins
-import collections.abc
import google.protobuf.descriptor
import google.protobuf.field_mask_pb2
import google.protobuf.internal.containers
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
-import sys
import typing
-
-if sys.version_info >= (3, 10):
- import typing as typing_extensions
-else:
- import typing_extensions
+import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class _GraphDirection:
- ValueType = typing.NewType("ValueType", builtins.int)
+ ValueType = typing.NewType('ValueType', builtins.int)
V: typing_extensions.TypeAlias = ValueType
-
-class _GraphDirectionEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_GraphDirection.ValueType], builtins.type): # noqa: F821
+class _GraphDirectionEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_GraphDirection.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
FORWARD: _GraphDirection.ValueType # 0
"""Forward DAG: ori -> snp -> rel -> rev -> dir -> cnt"""
+
BACKWARD: _GraphDirection.ValueType # 1
"""Transposed DAG: cnt -> dir -> rev -> rel -> snp -> ori"""
class GraphDirection(_GraphDirection, metaclass=_GraphDirectionEnumTypeWrapper):
"""Direction of the graph"""
+ pass
FORWARD: GraphDirection.ValueType # 0
"""Forward DAG: ori -> snp -> rel -> rev -> dir -> cnt"""
+
BACKWARD: GraphDirection.ValueType # 1
"""Transposed DAG: cnt -> dir -> rev -> rel -> snp -> ori"""
+
global___GraphDirection = GraphDirection
+
class GetNodeRequest(google.protobuf.message.Message):
"""Describe a node to return"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SWHID_FIELD_NUMBER: builtins.int
MASK_FIELD_NUMBER: builtins.int
- swhid: builtins.str
+ swhid: typing.Text
"""SWHID of the node to return"""
+
@property
def mask(self) -> google.protobuf.field_mask_pb2.FieldMask:
"""FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
By default, all fields are returned.
"""
- def __init__(
- self,
+ pass
+ def __init__(self,
*,
- swhid: builtins.str = ...,
- mask: google.protobuf.field_mask_pb2.FieldMask | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_mask", b"_mask", "mask", b"mask"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_mask", b"_mask", "mask", b"mask", "swhid", b"swhid"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask", b"_mask"]) -> typing_extensions.Literal["mask"] | None: ...
-
+ swhid: typing.Text = ...,
+ mask: typing.Optional[google.protobuf.field_mask_pb2.FieldMask] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_mask",b"_mask","mask",b"mask"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_mask",b"_mask","mask",b"mask","swhid",b"swhid"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask",b"_mask"]) -> typing.Optional[typing_extensions.Literal["mask"]]: ...
global___GetNodeRequest = GetNodeRequest
class TraversalRequest(google.protobuf.message.Message):
"""TraversalRequest describes how a breadth-first traversal should be
performed, and what should be returned to the client.
"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SRC_FIELD_NUMBER: builtins.int
DIRECTION_FIELD_NUMBER: builtins.int
EDGES_FIELD_NUMBER: builtins.int
MAX_EDGES_FIELD_NUMBER: builtins.int
MIN_DEPTH_FIELD_NUMBER: builtins.int
MAX_DEPTH_FIELD_NUMBER: builtins.int
RETURN_NODES_FIELD_NUMBER: builtins.int
MASK_FIELD_NUMBER: builtins.int
+ MAX_MATCHING_NODES_FIELD_NUMBER: builtins.int
@property
- def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]:
"""Set of source nodes (SWHIDs)"""
+ pass
direction: global___GraphDirection.ValueType
"""Direction of the graph to traverse. Defaults to FORWARD."""
- edges: builtins.str
+
+ edges: typing.Text
"""Edge restriction string (e.g. "rev:dir,dir:cnt").
Defaults to "*" (all).
"""
+
max_edges: builtins.int
"""Maximum number of edges accessed in the traversal, after which it stops.
Defaults to infinite.
"""
+
min_depth: builtins.int
"""Do not return nodes with a depth lower than this number.
By default, all depths are returned.
"""
+
max_depth: builtins.int
"""Maximum depth of the traversal, after which it stops.
Defaults to infinite.
"""
+
@property
def return_nodes(self) -> global___NodeFilter:
"""Filter which nodes will be sent to the stream. By default, all nodes are
returned.
"""
+ pass
@property
def mask(self) -> google.protobuf.field_mask_pb2.FieldMask:
"""FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
By default, all fields are returned.
"""
- def __init__(
- self,
+ pass
+ max_matching_nodes: builtins.int
+ """Maximum number of matching results before stopping. For Traverse(), this is
+ the total number of results. Defaults to infinite.
+ """
+
+ def __init__(self,
*,
- src: collections.abc.Iterable[builtins.str] | None = ...,
+ src: typing.Optional[typing.Iterable[typing.Text]] = ...,
direction: global___GraphDirection.ValueType = ...,
- edges: builtins.str | None = ...,
- max_edges: builtins.int | None = ...,
- min_depth: builtins.int | None = ...,
- max_depth: builtins.int | None = ...,
- return_nodes: global___NodeFilter | None = ...,
- mask: google.protobuf.field_mask_pb2.FieldMask | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_edges", b"_edges", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "_min_depth", b"_min_depth", "_return_nodes", b"_return_nodes", "edges", b"edges", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges", "min_depth", b"min_depth", "return_nodes", b"return_nodes"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_edges", b"_edges", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "_min_depth", b"_min_depth", "_return_nodes", b"_return_nodes", "direction", b"direction", "edges", b"edges", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges", "min_depth", b"min_depth", "return_nodes", b"return_nodes", "src", b"src"]) -> None: ...
+ edges: typing.Optional[typing.Text] = ...,
+ max_edges: typing.Optional[builtins.int] = ...,
+ min_depth: typing.Optional[builtins.int] = ...,
+ max_depth: typing.Optional[builtins.int] = ...,
+ return_nodes: typing.Optional[global___NodeFilter] = ...,
+ mask: typing.Optional[google.protobuf.field_mask_pb2.FieldMask] = ...,
+ max_matching_nodes: typing.Optional[builtins.int] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_edges",b"_edges","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","_max_matching_nodes",b"_max_matching_nodes","_min_depth",b"_min_depth","_return_nodes",b"_return_nodes","edges",b"edges","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges","max_matching_nodes",b"max_matching_nodes","min_depth",b"min_depth","return_nodes",b"return_nodes"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_edges",b"_edges","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","_max_matching_nodes",b"_max_matching_nodes","_min_depth",b"_min_depth","_return_nodes",b"_return_nodes","direction",b"direction","edges",b"edges","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges","max_matching_nodes",b"max_matching_nodes","min_depth",b"min_depth","return_nodes",b"return_nodes","src",b"src"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges", b"_edges"]) -> typing_extensions.Literal["edges"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges",b"_edges"]) -> typing.Optional[typing_extensions.Literal["edges"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask", b"_mask"]) -> typing_extensions.Literal["mask"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask",b"_mask"]) -> typing.Optional[typing_extensions.Literal["mask"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth", b"_max_depth"]) -> typing_extensions.Literal["max_depth"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth",b"_max_depth"]) -> typing.Optional[typing_extensions.Literal["max_depth"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges", b"_max_edges"]) -> typing_extensions.Literal["max_edges"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges",b"_max_edges"]) -> typing.Optional[typing_extensions.Literal["max_edges"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_min_depth", b"_min_depth"]) -> typing_extensions.Literal["min_depth"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_matching_nodes",b"_max_matching_nodes"]) -> typing.Optional[typing_extensions.Literal["max_matching_nodes"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_return_nodes", b"_return_nodes"]) -> typing_extensions.Literal["return_nodes"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_min_depth",b"_min_depth"]) -> typing.Optional[typing_extensions.Literal["min_depth"]]: ...
+ @typing.overload
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_return_nodes",b"_return_nodes"]) -> typing.Optional[typing_extensions.Literal["return_nodes"]]: ...
global___TraversalRequest = TraversalRequest
class FindPathToRequest(google.protobuf.message.Message):
"""FindPathToRequest describes a request to find a shortest path between a
set of nodes and a given target criteria, as well as what should be returned
in the path.
"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SRC_FIELD_NUMBER: builtins.int
TARGET_FIELD_NUMBER: builtins.int
DIRECTION_FIELD_NUMBER: builtins.int
EDGES_FIELD_NUMBER: builtins.int
MAX_EDGES_FIELD_NUMBER: builtins.int
MAX_DEPTH_FIELD_NUMBER: builtins.int
MASK_FIELD_NUMBER: builtins.int
@property
- def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]:
"""Set of source nodes (SWHIDs)"""
+ pass
@property
def target(self) -> global___NodeFilter:
"""Target criteria, i.e., what constitutes a valid path destination."""
+ pass
direction: global___GraphDirection.ValueType
"""Direction of the graph to traverse. Defaults to FORWARD."""
- edges: builtins.str
+
+ edges: typing.Text
"""Edge restriction string (e.g. "rev:dir,dir:cnt").
Defaults to "*" (all).
"""
+
max_edges: builtins.int
"""Maximum number of edges accessed in the traversal, after which it stops.
Defaults to infinite.
"""
+
max_depth: builtins.int
"""Maximum depth of the traversal, after which it stops.
Defaults to infinite.
"""
+
@property
def mask(self) -> google.protobuf.field_mask_pb2.FieldMask:
"""FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
By default, all fields are returned.
"""
- def __init__(
- self,
+ pass
+ def __init__(self,
*,
- src: collections.abc.Iterable[builtins.str] | None = ...,
- target: global___NodeFilter | None = ...,
+ src: typing.Optional[typing.Iterable[typing.Text]] = ...,
+ target: typing.Optional[global___NodeFilter] = ...,
direction: global___GraphDirection.ValueType = ...,
- edges: builtins.str | None = ...,
- max_edges: builtins.int | None = ...,
- max_depth: builtins.int | None = ...,
- mask: google.protobuf.field_mask_pb2.FieldMask | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_edges", b"_edges", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "edges", b"edges", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges", "target", b"target"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_edges", b"_edges", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "direction", b"direction", "edges", b"edges", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges", "src", b"src", "target", b"target"]) -> None: ...
+ edges: typing.Optional[typing.Text] = ...,
+ max_edges: typing.Optional[builtins.int] = ...,
+ max_depth: typing.Optional[builtins.int] = ...,
+ mask: typing.Optional[google.protobuf.field_mask_pb2.FieldMask] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_edges",b"_edges","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","edges",b"edges","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges","target",b"target"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_edges",b"_edges","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","direction",b"direction","edges",b"edges","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges","src",b"src","target",b"target"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges", b"_edges"]) -> typing_extensions.Literal["edges"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges",b"_edges"]) -> typing.Optional[typing_extensions.Literal["edges"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask", b"_mask"]) -> typing_extensions.Literal["mask"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask",b"_mask"]) -> typing.Optional[typing_extensions.Literal["mask"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth", b"_max_depth"]) -> typing_extensions.Literal["max_depth"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth",b"_max_depth"]) -> typing.Optional[typing_extensions.Literal["max_depth"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges", b"_max_edges"]) -> typing_extensions.Literal["max_edges"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges",b"_max_edges"]) -> typing.Optional[typing_extensions.Literal["max_edges"]]: ...
global___FindPathToRequest = FindPathToRequest
class FindPathBetweenRequest(google.protobuf.message.Message):
"""FindPathToRequest describes a request to find a shortest path between a
set of source nodes and a set of destination nodes. It works by performing a
bidirectional breadth-first traversal from both sets at the same time.
"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SRC_FIELD_NUMBER: builtins.int
DST_FIELD_NUMBER: builtins.int
DIRECTION_FIELD_NUMBER: builtins.int
DIRECTION_REVERSE_FIELD_NUMBER: builtins.int
EDGES_FIELD_NUMBER: builtins.int
EDGES_REVERSE_FIELD_NUMBER: builtins.int
MAX_EDGES_FIELD_NUMBER: builtins.int
MAX_DEPTH_FIELD_NUMBER: builtins.int
MASK_FIELD_NUMBER: builtins.int
@property
- def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ def src(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]:
"""Set of source nodes (SWHIDs)"""
+ pass
@property
- def dst(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ def dst(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]:
"""Set of destination nodes (SWHIDs)"""
+ pass
direction: global___GraphDirection.ValueType
"""Direction of the graph to traverse from the source set. Defaults to
FORWARD.
"""
+
direction_reverse: global___GraphDirection.ValueType
"""Direction of the graph to traverse from the destination set. Defaults to
the opposite of `direction`. If direction and direction_reverse are
identical, it will find the first common successor of both sets in the
given direction.
"""
- edges: builtins.str
+
+ edges: typing.Text
"""Edge restriction string for the traversal from the source set.
(e.g. "rev:dir,dir:cnt"). Defaults to "*" (all).
"""
- edges_reverse: builtins.str
+
+ edges_reverse: typing.Text
"""Edge restriction string for the reverse traversal from the destination
set.
If not specified:
- If `edges` is not specified either, defaults to "*"
- If direction == direction_reverse, defaults to `edges`
- If direction != direction_reverse, defaults to the reverse of `edges`
(e.g. "rev:dir" becomes "dir:rev").
"""
+
max_edges: builtins.int
"""Maximum number of edges accessed in the traversal, after which it stops.
Defaults to infinite.
"""
+
max_depth: builtins.int
"""Maximum depth of the traversal, after which it stops.
Defaults to infinite.
"""
+
@property
def mask(self) -> google.protobuf.field_mask_pb2.FieldMask:
"""FieldMask of which fields are to be returned (e.g., "swhid,cnt.length").
By default, all fields are returned.
"""
- def __init__(
- self,
+ pass
+ def __init__(self,
*,
- src: collections.abc.Iterable[builtins.str] | None = ...,
- dst: collections.abc.Iterable[builtins.str] | None = ...,
+ src: typing.Optional[typing.Iterable[typing.Text]] = ...,
+ dst: typing.Optional[typing.Iterable[typing.Text]] = ...,
direction: global___GraphDirection.ValueType = ...,
- direction_reverse: global___GraphDirection.ValueType | None = ...,
- edges: builtins.str | None = ...,
- edges_reverse: builtins.str | None = ...,
- max_edges: builtins.int | None = ...,
- max_depth: builtins.int | None = ...,
- mask: google.protobuf.field_mask_pb2.FieldMask | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_direction_reverse", b"_direction_reverse", "_edges", b"_edges", "_edges_reverse", b"_edges_reverse", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "direction_reverse", b"direction_reverse", "edges", b"edges", "edges_reverse", b"edges_reverse", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_direction_reverse", b"_direction_reverse", "_edges", b"_edges", "_edges_reverse", b"_edges_reverse", "_mask", b"_mask", "_max_depth", b"_max_depth", "_max_edges", b"_max_edges", "direction", b"direction", "direction_reverse", b"direction_reverse", "dst", b"dst", "edges", b"edges", "edges_reverse", b"edges_reverse", "mask", b"mask", "max_depth", b"max_depth", "max_edges", b"max_edges", "src", b"src"]) -> None: ...
+ direction_reverse: typing.Optional[global___GraphDirection.ValueType] = ...,
+ edges: typing.Optional[typing.Text] = ...,
+ edges_reverse: typing.Optional[typing.Text] = ...,
+ max_edges: typing.Optional[builtins.int] = ...,
+ max_depth: typing.Optional[builtins.int] = ...,
+ mask: typing.Optional[google.protobuf.field_mask_pb2.FieldMask] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_direction_reverse",b"_direction_reverse","_edges",b"_edges","_edges_reverse",b"_edges_reverse","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","direction_reverse",b"direction_reverse","edges",b"edges","edges_reverse",b"edges_reverse","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_direction_reverse",b"_direction_reverse","_edges",b"_edges","_edges_reverse",b"_edges_reverse","_mask",b"_mask","_max_depth",b"_max_depth","_max_edges",b"_max_edges","direction",b"direction","direction_reverse",b"direction_reverse","dst",b"dst","edges",b"edges","edges_reverse",b"edges_reverse","mask",b"mask","max_depth",b"max_depth","max_edges",b"max_edges","src",b"src"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_direction_reverse", b"_direction_reverse"]) -> typing_extensions.Literal["direction_reverse"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_direction_reverse",b"_direction_reverse"]) -> typing.Optional[typing_extensions.Literal["direction_reverse"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges", b"_edges"]) -> typing_extensions.Literal["edges"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges",b"_edges"]) -> typing.Optional[typing_extensions.Literal["edges"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges_reverse", b"_edges_reverse"]) -> typing_extensions.Literal["edges_reverse"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_edges_reverse",b"_edges_reverse"]) -> typing.Optional[typing_extensions.Literal["edges_reverse"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask", b"_mask"]) -> typing_extensions.Literal["mask"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_mask",b"_mask"]) -> typing.Optional[typing_extensions.Literal["mask"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth", b"_max_depth"]) -> typing_extensions.Literal["max_depth"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_depth",b"_max_depth"]) -> typing.Optional[typing_extensions.Literal["max_depth"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges", b"_max_edges"]) -> typing_extensions.Literal["max_edges"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_edges",b"_max_edges"]) -> typing.Optional[typing_extensions.Literal["max_edges"]]: ...
global___FindPathBetweenRequest = FindPathBetweenRequest
class NodeFilter(google.protobuf.message.Message):
"""Represents various criteria that make a given node "valid". A node is
only valid if all the subcriteria present in this message are fulfilled.
"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
TYPES_FIELD_NUMBER: builtins.int
MIN_TRAVERSAL_SUCCESSORS_FIELD_NUMBER: builtins.int
MAX_TRAVERSAL_SUCCESSORS_FIELD_NUMBER: builtins.int
- types: builtins.str
+ types: typing.Text
"""Node restriction string. (e.g. "dir,cnt,rev"). Defaults to "*" (all)."""
+
min_traversal_successors: builtins.int
"""Minimum number of successors encountered *during the traversal*.
Default: no constraint
"""
+
max_traversal_successors: builtins.int
"""Maximum number of successors encountered *during the traversal*.
Default: no constraint
"""
- def __init__(
- self,
+
+ def __init__(self,
*,
- types: builtins.str | None = ...,
- min_traversal_successors: builtins.int | None = ...,
- max_traversal_successors: builtins.int | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_max_traversal_successors", b"_max_traversal_successors", "_min_traversal_successors", b"_min_traversal_successors", "_types", b"_types", "max_traversal_successors", b"max_traversal_successors", "min_traversal_successors", b"min_traversal_successors", "types", b"types"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_max_traversal_successors", b"_max_traversal_successors", "_min_traversal_successors", b"_min_traversal_successors", "_types", b"_types", "max_traversal_successors", b"max_traversal_successors", "min_traversal_successors", b"min_traversal_successors", "types", b"types"]) -> None: ...
+ types: typing.Optional[typing.Text] = ...,
+ min_traversal_successors: typing.Optional[builtins.int] = ...,
+ max_traversal_successors: typing.Optional[builtins.int] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_max_traversal_successors",b"_max_traversal_successors","_min_traversal_successors",b"_min_traversal_successors","_types",b"_types","max_traversal_successors",b"max_traversal_successors","min_traversal_successors",b"min_traversal_successors","types",b"types"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_max_traversal_successors",b"_max_traversal_successors","_min_traversal_successors",b"_min_traversal_successors","_types",b"_types","max_traversal_successors",b"max_traversal_successors","min_traversal_successors",b"min_traversal_successors","types",b"types"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_traversal_successors", b"_max_traversal_successors"]) -> typing_extensions.Literal["max_traversal_successors"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_max_traversal_successors",b"_max_traversal_successors"]) -> typing.Optional[typing_extensions.Literal["max_traversal_successors"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_min_traversal_successors", b"_min_traversal_successors"]) -> typing_extensions.Literal["min_traversal_successors"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_min_traversal_successors",b"_min_traversal_successors"]) -> typing.Optional[typing_extensions.Literal["min_traversal_successors"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_types", b"_types"]) -> typing_extensions.Literal["types"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_types",b"_types"]) -> typing.Optional[typing_extensions.Literal["types"]]: ...
global___NodeFilter = NodeFilter
class Node(google.protobuf.message.Message):
"""Represents a node in the graph."""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SWHID_FIELD_NUMBER: builtins.int
SUCCESSOR_FIELD_NUMBER: builtins.int
NUM_SUCCESSORS_FIELD_NUMBER: builtins.int
CNT_FIELD_NUMBER: builtins.int
REV_FIELD_NUMBER: builtins.int
REL_FIELD_NUMBER: builtins.int
ORI_FIELD_NUMBER: builtins.int
- swhid: builtins.str
+ swhid: typing.Text
"""The SWHID of the graph node."""
+
@property
def successor(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Successor]:
"""List of relevant successors of this node."""
+ pass
num_successors: builtins.int
"""Number of relevant successors."""
+
@property
def cnt(self) -> global___ContentData: ...
@property
def rev(self) -> global___RevisionData: ...
@property
def rel(self) -> global___ReleaseData: ...
@property
def ori(self) -> global___OriginData: ...
- def __init__(
- self,
+ def __init__(self,
*,
- swhid: builtins.str = ...,
- successor: collections.abc.Iterable[global___Successor] | None = ...,
- num_successors: builtins.int | None = ...,
- cnt: global___ContentData | None = ...,
- rev: global___RevisionData | None = ...,
- rel: global___ReleaseData | None = ...,
- ori: global___OriginData | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_num_successors", b"_num_successors", "cnt", b"cnt", "data", b"data", "num_successors", b"num_successors", "ori", b"ori", "rel", b"rel", "rev", b"rev"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_num_successors", b"_num_successors", "cnt", b"cnt", "data", b"data", "num_successors", b"num_successors", "ori", b"ori", "rel", b"rel", "rev", b"rev", "successor", b"successor", "swhid", b"swhid"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_num_successors", b"_num_successors"]) -> typing_extensions.Literal["num_successors"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["data", b"data"]) -> typing_extensions.Literal["cnt", "rev", "rel", "ori"] | None: ...
-
+ swhid: typing.Text = ...,
+ successor: typing.Optional[typing.Iterable[global___Successor]] = ...,
+ num_successors: typing.Optional[builtins.int] = ...,
+ cnt: typing.Optional[global___ContentData] = ...,
+ rev: typing.Optional[global___RevisionData] = ...,
+ rel: typing.Optional[global___ReleaseData] = ...,
+ ori: typing.Optional[global___OriginData] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_num_successors",b"_num_successors","cnt",b"cnt","data",b"data","num_successors",b"num_successors","ori",b"ori","rel",b"rel","rev",b"rev"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_num_successors",b"_num_successors","cnt",b"cnt","data",b"data","num_successors",b"num_successors","ori",b"ori","rel",b"rel","rev",b"rev","successor",b"successor","swhid",b"swhid"]) -> None: ...
+ @typing.overload
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_num_successors",b"_num_successors"]) -> typing.Optional[typing_extensions.Literal["num_successors"]]: ...
+ @typing.overload
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["data",b"data"]) -> typing.Optional[typing_extensions.Literal["cnt","rev","rel","ori"]]: ...
global___Node = Node
class Path(google.protobuf.message.Message):
"""Represents a path in the graph."""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
NODE_FIELD_NUMBER: builtins.int
MIDPOINT_INDEX_FIELD_NUMBER: builtins.int
@property
def node(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Node]:
"""List of nodes in the path, from source to destination"""
+ pass
midpoint_index: builtins.int
"""Index of the "midpoint" of the path. For paths obtained with
bidirectional search queries, this is the node that joined the two
sets together. When looking for a common ancestor between two nodes by
performing a FindPathBetween search with two backward graphs, this will
be the index of the common ancestor in the path.
"""
- def __init__(
- self,
- *,
- node: collections.abc.Iterable[global___Node] | None = ...,
- midpoint_index: builtins.int | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_midpoint_index", b"_midpoint_index", "midpoint_index", b"midpoint_index"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_midpoint_index", b"_midpoint_index", "midpoint_index", b"midpoint_index", "node", b"node"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_midpoint_index", b"_midpoint_index"]) -> typing_extensions.Literal["midpoint_index"] | None: ...
+ def __init__(self,
+ *,
+ node: typing.Optional[typing.Iterable[global___Node]] = ...,
+ midpoint_index: typing.Optional[builtins.int] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_midpoint_index",b"_midpoint_index","midpoint_index",b"midpoint_index"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_midpoint_index",b"_midpoint_index","midpoint_index",b"midpoint_index","node",b"node"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_midpoint_index",b"_midpoint_index"]) -> typing.Optional[typing_extensions.Literal["midpoint_index"]]: ...
global___Path = Path
class Successor(google.protobuf.message.Message):
"""Represents a successor of a given node."""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
SWHID_FIELD_NUMBER: builtins.int
LABEL_FIELD_NUMBER: builtins.int
- swhid: builtins.str
+ swhid: typing.Text
"""The SWHID of the successor"""
+
@property
def label(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___EdgeLabel]:
"""A list of edge labels for the given edge"""
- def __init__(
- self,
+ pass
+ def __init__(self,
*,
- swhid: builtins.str | None = ...,
- label: collections.abc.Iterable[global___EdgeLabel] | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_swhid", b"_swhid", "swhid", b"swhid"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_swhid", b"_swhid", "label", b"label", "swhid", b"swhid"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_swhid", b"_swhid"]) -> typing_extensions.Literal["swhid"] | None: ...
-
+ swhid: typing.Optional[typing.Text] = ...,
+ label: typing.Optional[typing.Iterable[global___EdgeLabel]] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_swhid",b"_swhid","swhid",b"swhid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_swhid",b"_swhid","label",b"label","swhid",b"swhid"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_swhid",b"_swhid"]) -> typing.Optional[typing_extensions.Literal["swhid"]]: ...
global___Successor = Successor
class ContentData(google.protobuf.message.Message):
"""Content node properties"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
LENGTH_FIELD_NUMBER: builtins.int
IS_SKIPPED_FIELD_NUMBER: builtins.int
length: builtins.int
"""Length of the blob, in bytes"""
+
is_skipped: builtins.bool
"""Whether the content was skipped during ingestion."""
- def __init__(
- self,
+
+ def __init__(self,
*,
- length: builtins.int | None = ...,
- is_skipped: builtins.bool | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_is_skipped", b"_is_skipped", "_length", b"_length", "is_skipped", b"is_skipped", "length", b"length"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_is_skipped", b"_is_skipped", "_length", b"_length", "is_skipped", b"is_skipped", "length", b"length"]) -> None: ...
+ length: typing.Optional[builtins.int] = ...,
+ is_skipped: typing.Optional[builtins.bool] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_is_skipped",b"_is_skipped","_length",b"_length","is_skipped",b"is_skipped","length",b"length"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_is_skipped",b"_is_skipped","_length",b"_length","is_skipped",b"is_skipped","length",b"length"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_is_skipped", b"_is_skipped"]) -> typing_extensions.Literal["is_skipped"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_is_skipped",b"_is_skipped"]) -> typing.Optional[typing_extensions.Literal["is_skipped"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_length", b"_length"]) -> typing_extensions.Literal["length"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_length",b"_length"]) -> typing.Optional[typing_extensions.Literal["length"]]: ...
global___ContentData = ContentData
class RevisionData(google.protobuf.message.Message):
"""Revision node properties"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
AUTHOR_FIELD_NUMBER: builtins.int
AUTHOR_DATE_FIELD_NUMBER: builtins.int
AUTHOR_DATE_OFFSET_FIELD_NUMBER: builtins.int
COMMITTER_FIELD_NUMBER: builtins.int
COMMITTER_DATE_FIELD_NUMBER: builtins.int
COMMITTER_DATE_OFFSET_FIELD_NUMBER: builtins.int
MESSAGE_FIELD_NUMBER: builtins.int
author: builtins.int
"""Revision author ID (anonymized)"""
+
author_date: builtins.int
"""UNIX timestamp of the revision date (UTC)"""
+
author_date_offset: builtins.int
"""Timezone of the revision author date as an offset from UTC"""
+
committer: builtins.int
"""Revision committer ID (anonymized)"""
+
committer_date: builtins.int
"""UNIX timestamp of the revision committer date (UTC)"""
+
committer_date_offset: builtins.int
"""Timezone of the revision committer date as an offset from UTC"""
+
message: builtins.bytes
"""Revision message"""
- def __init__(
- self,
+
+ def __init__(self,
*,
- author: builtins.int | None = ...,
- author_date: builtins.int | None = ...,
- author_date_offset: builtins.int | None = ...,
- committer: builtins.int | None = ...,
- committer_date: builtins.int | None = ...,
- committer_date_offset: builtins.int | None = ...,
- message: builtins.bytes | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_author", b"_author", "_author_date", b"_author_date", "_author_date_offset", b"_author_date_offset", "_committer", b"_committer", "_committer_date", b"_committer_date", "_committer_date_offset", b"_committer_date_offset", "_message", b"_message", "author", b"author", "author_date", b"author_date", "author_date_offset", b"author_date_offset", "committer", b"committer", "committer_date", b"committer_date", "committer_date_offset", b"committer_date_offset", "message", b"message"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_author", b"_author", "_author_date", b"_author_date", "_author_date_offset", b"_author_date_offset", "_committer", b"_committer", "_committer_date", b"_committer_date", "_committer_date_offset", b"_committer_date_offset", "_message", b"_message", "author", b"author", "author_date", b"author_date", "author_date_offset", b"author_date_offset", "committer", b"committer", "committer_date", b"committer_date", "committer_date_offset", b"committer_date_offset", "message", b"message"]) -> None: ...
+ author: typing.Optional[builtins.int] = ...,
+ author_date: typing.Optional[builtins.int] = ...,
+ author_date_offset: typing.Optional[builtins.int] = ...,
+ committer: typing.Optional[builtins.int] = ...,
+ committer_date: typing.Optional[builtins.int] = ...,
+ committer_date_offset: typing.Optional[builtins.int] = ...,
+ message: typing.Optional[builtins.bytes] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_author",b"_author","_author_date",b"_author_date","_author_date_offset",b"_author_date_offset","_committer",b"_committer","_committer_date",b"_committer_date","_committer_date_offset",b"_committer_date_offset","_message",b"_message","author",b"author","author_date",b"author_date","author_date_offset",b"author_date_offset","committer",b"committer","committer_date",b"committer_date","committer_date_offset",b"committer_date_offset","message",b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_author",b"_author","_author_date",b"_author_date","_author_date_offset",b"_author_date_offset","_committer",b"_committer","_committer_date",b"_committer_date","_committer_date_offset",b"_committer_date_offset","_message",b"_message","author",b"author","author_date",b"author_date","author_date_offset",b"author_date_offset","committer",b"committer","committer_date",b"committer_date","committer_date_offset",b"committer_date_offset","message",b"message"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author", b"_author"]) -> typing_extensions.Literal["author"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author",b"_author"]) -> typing.Optional[typing_extensions.Literal["author"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date", b"_author_date"]) -> typing_extensions.Literal["author_date"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date",b"_author_date"]) -> typing.Optional[typing_extensions.Literal["author_date"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date_offset", b"_author_date_offset"]) -> typing_extensions.Literal["author_date_offset"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date_offset",b"_author_date_offset"]) -> typing.Optional[typing_extensions.Literal["author_date_offset"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer", b"_committer"]) -> typing_extensions.Literal["committer"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer",b"_committer"]) -> typing.Optional[typing_extensions.Literal["committer"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer_date", b"_committer_date"]) -> typing_extensions.Literal["committer_date"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer_date",b"_committer_date"]) -> typing.Optional[typing_extensions.Literal["committer_date"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer_date_offset", b"_committer_date_offset"]) -> typing_extensions.Literal["committer_date_offset"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_committer_date_offset",b"_committer_date_offset"]) -> typing.Optional[typing_extensions.Literal["committer_date_offset"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_message", b"_message"]) -> typing_extensions.Literal["message"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_message",b"_message"]) -> typing.Optional[typing_extensions.Literal["message"]]: ...
global___RevisionData = RevisionData
class ReleaseData(google.protobuf.message.Message):
"""Release node properties"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
AUTHOR_FIELD_NUMBER: builtins.int
AUTHOR_DATE_FIELD_NUMBER: builtins.int
AUTHOR_DATE_OFFSET_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
MESSAGE_FIELD_NUMBER: builtins.int
author: builtins.int
"""Release author ID (anonymized)"""
+
author_date: builtins.int
"""UNIX timestamp of the release date (UTC)"""
+
author_date_offset: builtins.int
"""Timezone of the release author date as an offset from UTC"""
+
name: builtins.bytes
"""Release name"""
+
message: builtins.bytes
"""Release message"""
- def __init__(
- self,
+
+ def __init__(self,
*,
- author: builtins.int | None = ...,
- author_date: builtins.int | None = ...,
- author_date_offset: builtins.int | None = ...,
- name: builtins.bytes | None = ...,
- message: builtins.bytes | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_author", b"_author", "_author_date", b"_author_date", "_author_date_offset", b"_author_date_offset", "_message", b"_message", "_name", b"_name", "author", b"author", "author_date", b"author_date", "author_date_offset", b"author_date_offset", "message", b"message", "name", b"name"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_author", b"_author", "_author_date", b"_author_date", "_author_date_offset", b"_author_date_offset", "_message", b"_message", "_name", b"_name", "author", b"author", "author_date", b"author_date", "author_date_offset", b"author_date_offset", "message", b"message", "name", b"name"]) -> None: ...
+ author: typing.Optional[builtins.int] = ...,
+ author_date: typing.Optional[builtins.int] = ...,
+ author_date_offset: typing.Optional[builtins.int] = ...,
+ name: typing.Optional[builtins.bytes] = ...,
+ message: typing.Optional[builtins.bytes] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_author",b"_author","_author_date",b"_author_date","_author_date_offset",b"_author_date_offset","_message",b"_message","_name",b"_name","author",b"author","author_date",b"author_date","author_date_offset",b"author_date_offset","message",b"message","name",b"name"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_author",b"_author","_author_date",b"_author_date","_author_date_offset",b"_author_date_offset","_message",b"_message","_name",b"_name","author",b"author","author_date",b"author_date","author_date_offset",b"author_date_offset","message",b"message","name",b"name"]) -> None: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author", b"_author"]) -> typing_extensions.Literal["author"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author",b"_author"]) -> typing.Optional[typing_extensions.Literal["author"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date", b"_author_date"]) -> typing_extensions.Literal["author_date"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date",b"_author_date"]) -> typing.Optional[typing_extensions.Literal["author_date"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date_offset", b"_author_date_offset"]) -> typing_extensions.Literal["author_date_offset"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_author_date_offset",b"_author_date_offset"]) -> typing.Optional[typing_extensions.Literal["author_date_offset"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_message", b"_message"]) -> typing_extensions.Literal["message"] | None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_message",b"_message"]) -> typing.Optional[typing_extensions.Literal["message"]]: ...
@typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_name", b"_name"]) -> typing_extensions.Literal["name"] | None: ...
-
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_name",b"_name"]) -> typing.Optional[typing_extensions.Literal["name"]]: ...
global___ReleaseData = ReleaseData
class OriginData(google.protobuf.message.Message):
"""Origin node properties"""
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
URL_FIELD_NUMBER: builtins.int
- url: builtins.str
+ url: typing.Text
"""URL of the origin"""
- def __init__(
- self,
- *,
- url: builtins.str | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_url", b"_url", "url", b"url"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_url", b"_url", "url", b"url"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_url", b"_url"]) -> typing_extensions.Literal["url"] | None: ...
+ def __init__(self,
+ *,
+ url: typing.Optional[typing.Text] = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_url",b"_url","url",b"url"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_url",b"_url","url",b"url"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_url",b"_url"]) -> typing.Optional[typing_extensions.Literal["url"]]: ...
global___OriginData = OriginData
class EdgeLabel(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
NAME_FIELD_NUMBER: builtins.int
PERMISSION_FIELD_NUMBER: builtins.int
name: builtins.bytes
"""Directory entry name for directories, branch name for snapshots"""
+
permission: builtins.int
"""Entry permission (only set for directories)."""
- def __init__(
- self,
+
+ def __init__(self,
*,
name: builtins.bytes = ...,
permission: builtins.int = ...,
- ) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "permission", b"permission"]) -> None: ...
-
+ ) -> None: ...
+ def ClearField(self, field_name: typing_extensions.Literal["name",b"name","permission",b"permission"]) -> None: ...
global___EdgeLabel = EdgeLabel
class CountResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
COUNT_FIELD_NUMBER: builtins.int
count: builtins.int
- def __init__(
- self,
+ def __init__(self,
*,
count: builtins.int = ...,
- ) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["count", b"count"]) -> None: ...
-
+ ) -> None: ...
+ def ClearField(self, field_name: typing_extensions.Literal["count",b"count"]) -> None: ...
global___CountResponse = CountResponse
class StatsRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
- def __init__(
- self,
- ) -> None: ...
-
+ def __init__(self,
+ ) -> None: ...
global___StatsRequest = StatsRequest
class StatsResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
-
NUM_NODES_FIELD_NUMBER: builtins.int
NUM_EDGES_FIELD_NUMBER: builtins.int
COMPRESSION_RATIO_FIELD_NUMBER: builtins.int
BITS_PER_NODE_FIELD_NUMBER: builtins.int
BITS_PER_EDGE_FIELD_NUMBER: builtins.int
AVG_LOCALITY_FIELD_NUMBER: builtins.int
INDEGREE_MIN_FIELD_NUMBER: builtins.int
INDEGREE_MAX_FIELD_NUMBER: builtins.int
INDEGREE_AVG_FIELD_NUMBER: builtins.int
OUTDEGREE_MIN_FIELD_NUMBER: builtins.int
OUTDEGREE_MAX_FIELD_NUMBER: builtins.int
OUTDEGREE_AVG_FIELD_NUMBER: builtins.int
num_nodes: builtins.int
"""Number of nodes in the graph"""
+
num_edges: builtins.int
"""Number of edges in the graph"""
+
compression_ratio: builtins.float
"""Ratio between the graph size and the information-theoretical lower
bound
"""
+
bits_per_node: builtins.float
"""Number of bits per node (overall graph size in bits divided by the
number of nodes)
"""
+
bits_per_edge: builtins.float
"""Number of bits per edge (overall graph size in bits divided by the
number of arcs).
"""
+
avg_locality: builtins.float
indegree_min: builtins.int
"""Smallest indegree"""
+
indegree_max: builtins.int
"""Largest indegree"""
+
indegree_avg: builtins.float
"""Average indegree"""
+
outdegree_min: builtins.int
"""Smallest outdegree"""
+
outdegree_max: builtins.int
"""Largest outdegree"""
+
outdegree_avg: builtins.float
"""Average outdegree"""
- def __init__(
- self,
+
+ def __init__(self,
*,
num_nodes: builtins.int = ...,
num_edges: builtins.int = ...,
compression_ratio: builtins.float = ...,
bits_per_node: builtins.float = ...,
bits_per_edge: builtins.float = ...,
avg_locality: builtins.float = ...,
indegree_min: builtins.int = ...,
indegree_max: builtins.int = ...,
indegree_avg: builtins.float = ...,
outdegree_min: builtins.int = ...,
outdegree_max: builtins.int = ...,
outdegree_avg: builtins.float = ...,
- ) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["avg_locality", b"avg_locality", "bits_per_edge", b"bits_per_edge", "bits_per_node", b"bits_per_node", "compression_ratio", b"compression_ratio", "indegree_avg", b"indegree_avg", "indegree_max", b"indegree_max", "indegree_min", b"indegree_min", "num_edges", b"num_edges", "num_nodes", b"num_nodes", "outdegree_avg", b"outdegree_avg", "outdegree_max", b"outdegree_max", "outdegree_min", b"outdegree_min"]) -> None: ...
-
+ ) -> None: ...
+ def ClearField(self, field_name: typing_extensions.Literal["avg_locality",b"avg_locality","bits_per_edge",b"bits_per_edge","bits_per_node",b"bits_per_node","compression_ratio",b"compression_ratio","indegree_avg",b"indegree_avg","indegree_max",b"indegree_max","indegree_min",b"indegree_min","num_edges",b"num_edges","num_nodes",b"num_nodes","outdegree_avg",b"outdegree_avg","outdegree_max",b"outdegree_max","outdegree_min",b"outdegree_min"]) -> None: ...
global___StatsResponse = StatsResponse