This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.8-dev by this push:
new ec1f544377 [TINKERPOP-3186] - Align Element.properties type for python
and javascript (#3242)
ec1f544377 is described below
commit ec1f544377f53382f784f33001e9653c97d48293
Author: Yang Xia <[email protected]>
AuthorDate: Mon Oct 20 17:36:55 2025 -0700
[TINKERPOP-3186] - Align Element.properties type for python and javascript
(#3242)
---
CHANGELOG.asciidoc | 3 +-
docs/src/upgrade/release-3.8.x.asciidoc | 72 +++++++++++++++++++--
.../gremlin-javascript/lib/structure/graph.js | 28 +++-----
.../lib/structure/io/type-serializers.js | 25 +++++++-
.../test/integration/client-tests.js | 66 ++++++-------------
.../test/integration/traversal-test.js | 15 ++---
.../test/unit/graphbinary/AnySerializer-test.js | 2 +-
.../gremlin-javascript/test/unit/graphson-test.js | 74 +++++++++++++++-------
.../test/unit/structure-types-test.js | 41 ++++++++++++
.../main/python/gremlin_python/structure/graph.py | 2 +-
.../gremlin_python/structure/io/graphsonV2d0.py | 6 +-
.../gremlin_python/structure/io/graphsonV3d0.py | 6 +-
.../tests/driver/test_driver_remote_connection.py | 12 ++--
.../python/tests/structure/io/test_graphsonV2d0.py | 58 ++++++++++++++++-
.../python/tests/structure/io/test_graphsonV3d0.py | 59 ++++++++++++++++-
.../src/main/python/tests/structure/test_graph.py | 23 +++++++
16 files changed, 369 insertions(+), 123 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index a0bfbcc2d3..888cf44f03 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -29,8 +29,9 @@ This release also includes changes from <<release-3-7-XXX,
3.7.XXX>>.
* Added the Air Routes dataset to the set of available samples packaged with
distributions.
* Added a minimal distribution for `tinkergraph-gremlin` using the `min`
classifier that doesn't include the sample datasets.
* Removed Vertex/ReferenceVertex from grammar. Use vertex id in traversals now
instead.
-* Renamed `none()` step to `discard()`.
* Fixed bug where `InlineFilterStrategy` could add an empty `has()`.
+* Normalized python and javascript `Element.properties` to lists.
+* Renamed `none()` step to `discard()`.
* Repurposed `none()` step as a list filtering step with the signature
`none(P)`.
* Modified mathematical operators to prevent overflows in steps such as
`sum()` and 'sack()' to prefer promotion to the next highest number type.
* Added `DateTime` ontop of the existing 'datetime' grammar.
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc
b/docs/src/upgrade/release-3.8.x.asciidoc
index 9e0cd612d1..e8795e8b43 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -311,21 +311,85 @@ g.inject("Hello").split("")
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3083[TINKERPOP-3083]
==== asString() No Longer Allow Nulls
-The `asString()` step will no longer allow `null` input. An
`IllegalArgumentException` will be thrown for consistency with all other
parsing steps (i.e. `asDate()`, `asBool()`, `asNumber()`).
+
+The `asString()` step will no longer allow `null` input. An
`IllegalArgumentException` will be thrown for consistency
+with all other parsing steps (i.e. `asDate()`, `asBool()`, `asNumber()`).
See:
link:https://lists.apache.org/thread/q76pgrvhprosb4lty63bnsnbw2ljyl7m[DISCUSS]
thread
-==== Javascript Set Deserialization
+==== Serialization Changes
+
+*Properties on Element Serialization in Python & Javascript*
+
+Element properties handling has been inconsistent across GLVs.
Previously,`gremlin-python` deserialized empty properties
+as None or array depending on the serializer, while `gremlin-javascript`
returned properties as objects or arrays, with
+empty properties as empty lists or undefined depending on the serializer.
+
+This inconsistency is now resolved, aligning to how properties are handled in
Gremlin core and in the Java GLV.
+Both GLVs will deserialize element properties into lists of property objects,
returning empty lists instead of null values
+for missing properties.
+
+For python, the most notable difference is in graphSON when "tokens" is turned
on for "materializeProperties". The
+properties returned are no longer `None`, but empty lists. Users should update
their code accordingly.
+
+For javascript, the change is slightly more extensive, as user should no
longer expect javascript objects to be returned.
+All properties are returned as lists of Property or VertexProperty objects.
+
+[source,javascript]
+----
+// 3.7 and before:
+g.with_("materializeProperties", "tokens").V(1).next() // skip properties with
token
+// graphson will return properties as a javascript object, which becomes
undefined
+Vertex { id: 1, label: 'person', properties: undefined }
+// graphbinary will return properties as empty lists
+Vertex { id: 1, label: 'person', properties: [] }
+
+g.V(1).next() // properties returned
+// graphson will return properties as a javascript object
+Vertex {
+ id: 1,
+ label: 'person',
+ properties: { name: [Array], age: [Array] }
+}
+// graphbinary will return properties as lists of VertexProperty objects
+Vertex {
+ id: 1,
+ label: 'person',
+ properties: [ [VertexProperty], [VertexProperty] ]
+}
+
+// 3.8.0 and newer - properties are always arrays, empty array [] for missing
properties:
+g.with_("materializeProperties", "tokens").V(1).next() // skip properties with
token
+// both graphson and graphbinary return
+Vertex { id: 1, label: 'person', properties: [] }
+g.V(1).next()
+// both graphson and graphbinary return
+Vertex {
+ id: 1,
+ label: 'person',
+ properties: [ [VertexProperty], [VertexProperty] ]
+}
+
+----
+
+This change only affects how GLVs deserialize property data in client
applications. The underlying graph serialization
+formats and server-side behavior remain unchanged.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3186[TINKERPOP-3186]
+
+*Javascript Set Deserialization*
Starting from this version, `gremlin-javascript` will deserialize `Set` data
into a ECMAScript 2015 Set. Previously,
these were deserialized into arrays.
-==== .NET Byte Serialization Change
+*.NET Byte Serialization Change*
The Gremlin .NET serializers has been updated to correctly handle byte values
as signed integers to align with the IO
specification, whereas previously it incorrectly serialized and deserialized
bytes as unsigned values.
-This is a breaking change for .NET applications that rely on byte values.
Existing applications using byte values should consider switching to `sbyte`
for signed byte operations or `short` for a wider range of values to maintain
compatibility.
+This is a breaking change for .NET applications that rely on byte values.
Existing applications using byte values
+should consider switching to `sbyte` for signed byte operations or `short` for
a wider range of values to maintain
+compatibility.
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3161[TINKERPOP-3161]
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
index 02459bc9be..46f4dd14d7 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
@@ -46,9 +46,11 @@ class Graph {
}
class Element {
- constructor(id, label) {
+ // properties are stored as list of property objects
+ constructor(id, label, properties = []) {
this.id = id;
this.label = label;
+ this.properties = properties != null ? properties : [];
}
/**
@@ -62,9 +64,8 @@ class Element {
}
class Vertex extends Element {
- constructor(id, label, properties) {
- super(id, label);
- this.properties = properties;
+ constructor(id, label, properties = []) {
+ super(id, label, properties);
}
toString() {
@@ -73,20 +74,10 @@ class Vertex extends Element {
}
class Edge extends Element {
- constructor(id, outV, label, inV, properties) {
- super(id, label);
+ constructor(id, outV, label, inV, properties = []) {
+ super(id, label, properties);
this.outV = outV;
this.inV = inV;
- this.properties = {};
- if (properties) {
- if (Array.isArray(properties)) {
- // Handle array of Property objects
- properties.forEach((prop) => (this.properties[prop.key] = prop.value));
- } else {
- // Handle object format as before
- Object.keys(properties).forEach((k) => (this.properties[k] =
properties[k].value));
- }
- }
}
toString() {
@@ -98,11 +89,10 @@ class Edge extends Element {
}
class VertexProperty extends Element {
- constructor(id, label, value, properties) {
- super(id, label);
+ constructor(id, label, value, properties = []) {
+ super(id, label, properties);
this.value = value;
this.key = this.label;
- this.properties = properties;
}
toString() {
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
index 22166a6e70..7f5a392fd6 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
@@ -311,10 +311,29 @@ class TraversalStrategySerializer extends TypeSerializer {
}
}
+/**
+ * Helper function to deserialize properties into arrays of VertexProperty or
Property according to graphSONV3.
+ */
+function deserializeProperties(value, reader) {
+ let properties = [];
+ if ('properties' in value) {
+ const props = reader.read(value['properties']);
+ if (props !== null && props !== undefined) {
+ properties = Object.entries(props).flatMap(([key, values]) => {
+ if (Array.isArray(values) && values.length > 0 && values[0] instanceof
g.VertexProperty) {
+ return values; // Flatten VertexProperty arrays
+ }
+ return values instanceof g.Property ? values : new g.Property(key,
values); // create Property object when needed
+ });
+ }
+ }
+ return properties;
+}
+
class VertexSerializer extends TypeSerializer {
deserialize(obj) {
const value = obj[valueKey];
- return new g.Vertex(this.reader.read(value['id']), value['label'],
this.reader.read(value['properties']));
+ return new g.Vertex(this.reader.read(value['id']), value['label'],
deserializeProperties(value, this.reader));
}
/** @param {Vertex} item */
@@ -340,7 +359,7 @@ class VertexPropertySerializer extends TypeSerializer {
this.reader.read(value['id']),
value['label'],
this.reader.read(value['value']),
- this.reader.read(value['properties']),
+ deserializeProperties(value, this.reader),
);
}
}
@@ -360,7 +379,7 @@ class EdgeSerializer extends TypeSerializer {
new g.Vertex(this.reader.read(value['outV']),
this.reader.read(value['outVLabel'])),
value['label'],
new g.Vertex(this.reader.read(value['inV']),
this.reader.read(value['inVLabel'])),
- this.reader.read(value['properties']),
+ deserializeProperties(value, this.reader),
);
}
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
index a61701d255..da4c2410cc 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
@@ -84,16 +84,8 @@ describe('Client', function () {
assert.strictEqual(result.length, 1);
const vertex = result.first().object;
assert.ok(vertex instanceof graphModule.Vertex);
- let age, name
- if (vertex.properties instanceof Array) {
- const ageProps = vertex.properties.filter(p => p.key === 'age');
- const nameProps = vertex.properties.filter(p => p.key === 'name');
- age = ageProps[0];
- name = nameProps[0];
- } else {
- age = vertex.properties.age[0]
- name = vertex.properties.name[0]
- }
+ const age = vertex.properties.find(p => p.key === 'age');
+ const name = vertex.properties.find(p => p.key === 'name');
assert.ok(age);
assert.ok(name);
assert.strictEqual(age.value, 29);
@@ -108,7 +100,7 @@ describe('Client', function () {
assert.strictEqual(result.length, 1);
const vertex = result.first().object;
assert.ok(vertex instanceof graphModule.Vertex);
- assert.ok(vertex.properties === undefined ||
vertex.properties.length === 0);
+ assert.ok(vertex.properties.length === 0);
});
});
@@ -119,17 +111,8 @@ describe('Client', function () {
assert.strictEqual(result.length, 1);
const vertex = result.first();
assert.ok(vertex instanceof graphModule.Vertex);
- // if/then until TINKERPOP-3186
- let age, name
- if (vertex.properties instanceof Array) {
- const ageProps = vertex.properties.filter(p => p.key === 'age');
- const nameProps = vertex.properties.filter(p => p.key === 'name');
- age = ageProps[0];
- name = nameProps[0];
- } else {
- age = vertex.properties.age[0]
- name = vertex.properties.name[0]
- }
+ const age = vertex.properties.find(p => p.key === 'age');
+ const name = vertex.properties.find(p => p.key === 'name');
assert.ok(age);
assert.ok(name);
assert.strictEqual(age.value, 29);
@@ -145,7 +128,7 @@ describe('Client', function () {
const edge = result.first();
assert.ok(edge instanceof graphModule.Edge);
assert.strictEqual(edge.label, 'knows');
- assert.strictEqual(edge.properties.weight, 0.5);
+ assert.strictEqual(edge.properties[0].value, 0.5);
assert.ok(edge.inV);
assert.ok(edge.outV);
});
@@ -161,18 +144,12 @@ describe('Client', function () {
assert.strictEqual(prop.key, 'location');
assert.strictEqual(prop.value, 'centreville');
- // Check meta-properties - TINKERPOP-3186
- if (prop.properties instanceof Object && !(prop.properties
instanceof Array)) {
- assert.strictEqual(prop.properties.startTime, 1990);
- assert.strictEqual(prop.properties.endTime, 2000);
- } else {
- const startTime = prop.properties.find(p => p.key === 'startTime');
- const endTime = prop.properties.find(p => p.key === 'endTime');
- assert.ok(startTime);
- assert.ok(endTime);
- assert.strictEqual(startTime.value, 1990);
- assert.strictEqual(endTime.value, 2000);
- }
+ const startTime = prop.properties.find(p => p.key === 'startTime');
+ const endTime = prop.properties.find(p => p.key === 'endTime');
+ assert.ok(startTime);
+ assert.ok(endTime);
+ assert.strictEqual(startTime.value, 1990);
+ assert.strictEqual(endTime.value, 2000);
});
});
@@ -183,7 +160,7 @@ describe('Client', function () {
assert.strictEqual(result.length, 1);
const vertex = result.first();
assert.ok(vertex instanceof graphModule.Vertex);
- assert.ok(vertex.properties === undefined ||
vertex.properties.length === 0);
+ assert.ok(vertex.properties.length === 0);
});
});
@@ -355,15 +332,10 @@ function assertVertexProperties(vertex) {
const vertexProperty = locations[0];
assert.strictEqual(vertexProperty.value, 'centreville');
- if (vertexProperty.properties instanceof Array) {
- const start = vertexProperty.properties.find(p => p.key === 'startTime');
- const end = vertexProperty.properties.find(p => p.key === 'endTime');
- assert.ok(start);
- assert.ok(end);
- assert.strictEqual(start.value, 1990);
- assert.strictEqual(end.value, 2000);
- } else {
- assert.strictEqual(vertexProperty.properties.startTime, 1990);
- assert.strictEqual(vertexProperty.properties.endTime, 2000);
- }
+ const start = vertexProperty.properties.find(p => p.key === 'startTime');
+ const end = vertexProperty.properties.find(p => p.key === 'endTime');
+ assert.ok(start);
+ assert.ok(end);
+ assert.strictEqual(start.value, 1990);
+ assert.strictEqual(end.value, 2000);
}
\ No newline at end of file
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
index 89b4c85232..60cd93bbfa 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
@@ -137,7 +137,7 @@ describe('Traversal', function () {
assert.ok(list);
assert.strictEqual(list.length, 6);
list.forEach(v => assert.ok(v instanceof Vertex));
- list.forEach(v => assert.ok(v.properties === undefined ||
v.properties.length === 0));
+ list.forEach(v => assert.strictEqual(v.properties.length, 0));
});
});
it('should skip edge properties when tokens is set', function () {
@@ -156,7 +156,7 @@ describe('Traversal', function () {
assert.ok(list);
assert.strictEqual(list.length, 12);
list.forEach(vp => assert.ok(vp instanceof VertexProperty));
- list.forEach(vp => assert.ok(vp.properties === undefined ||
vp.properties.length === 0));
+ list.forEach(vp => assert.strictEqual(vp.properties.length, 0));
});
});
it('should skip path element properties when tokens is set', function () {
@@ -171,9 +171,9 @@ describe('Traversal', function () {
assert.ok(a instanceof Vertex);
assert.ok(b instanceof Edge);
assert.ok(c instanceof Vertex);
- assert.ok(a.properties === undefined || a.properties.length === 0);
+ assert.strictEqual(a.properties.length, 0);
assert.strictEqual(Object.keys(b.properties).length, 0);
- assert.ok(c.properties === undefined || c.properties.length === 0);
+ assert.strictEqual(c.properties.length, 0);
});
});
it('should materialize path element properties when all is set', function
() {
@@ -207,12 +207,7 @@ describe('Traversal', function () {
assert.strictEqual(aAgeProps.length, 1);
assert.strictEqual(aAgeProps[0].value, 29);
assert.ok(b.properties);
- let bWeight;
- if (b.properties instanceof Array) {
- bWeight = b.properties.filter(p => p.key === 'weight');
- } else {
- bWeight = b.properties['weight'];
- }
+ const bWeight = b.properties[0].value
assert.ok(bWeight !== undefined);
assert.strictEqual(bWeight, 0.4);
assert.ok(c.properties);
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
index d723c85cd9..deb7f5ccf1 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
@@ -267,7 +267,7 @@ describe('GraphBinary.AnySerializer', () => {
0x00,0x00,0x00,0x05, ...from('Label'),
0x01,0x00, 0x00,0x00,0x00,0x2A,
0xFE,0x01,
- 0xFE,0x01,
+ 0x09,0x00, 0x00,0x00,0x00,0x00,
]
},
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
index 913102b098..8de0173ea6 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
@@ -92,21 +92,23 @@ describe('GraphSONReader', function () {
});
it('should parse vertices from GraphSON', function () {
const obj = {
- "@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person",
-
"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],
-
"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}};
+
"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person",
+
"properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},
+ "value":"marko","label":"name"}}],"age":[{
+
"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},
+ "value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}}
const reader = new GraphSONReader(obj);
const result = reader.read(obj);
assert.ok(result instanceof graph.Vertex);
assert.strictEqual(result.label, 'person');
assert.strictEqual(typeof result.id, 'number');
assert.ok(result.properties);
- assert.ok(result.properties['name']);
- assert.strictEqual(result.properties['name'].length, 1);
- assert.strictEqual(result.properties['name'][0].value, 'marko');
- assert.ok(result.properties['age']);
- assert.strictEqual(result.properties['age'].length, 1);
- assert.strictEqual(result.properties['age'][0].value, 29);
+ assert.ok(result.properties[0]);
+ assert.strictEqual(result.properties[0].key, 'name');
+ assert.strictEqual(result.properties[0].value, 'marko');
+ assert.ok(result.properties[1]);
+ assert.strictEqual(result.properties[1].key, 'age');
+ assert.strictEqual(result.properties[1].value, 29);
});
it('should parse paths from GraphSON', function () {
const obj =
{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[
@@ -136,19 +138,19 @@ describe('GraphSONReader', function () {
assert.strictEqual(a.label, 'person');
assert.strictEqual(bc.label, 'software');
assert.ok(a.properties);
- assert.ok(a.properties['name']);
- assert.strictEqual(a.properties['name'].length, 1);
- assert.strictEqual(a.properties['name'][0].value, 'marko');
- assert.ok(a.properties['age']);
- assert.strictEqual(a.properties['age'].length, 1);
- assert.strictEqual(a.properties['age'][0].value, 29);
+ assert.ok(a.properties[0]);
+ assert.strictEqual(a.properties[0].key, 'name');
+ assert.strictEqual(a.properties[0].value, 'marko');
+ assert.ok(a.properties[1]);
+ assert.strictEqual(a.properties[1].key, 'age');
+ assert.strictEqual(a.properties[1].value, 29);
assert.ok(bc.properties);
- assert.ok(bc.properties['name']);
- assert.strictEqual(bc.properties['name'].length, 1);
- assert.strictEqual(bc.properties['name'][0].value, 'lop');
- assert.ok(bc.properties['lang']);
- assert.strictEqual(bc.properties['lang'].length, 1);
- assert.strictEqual(bc.properties['lang'][0].value, 'java');
+ assert.ok(bc.properties[0]);
+ assert.strictEqual(bc.properties[0].key, 'name');
+ assert.strictEqual(bc.properties[0].value, 'lop');
+ assert.ok(bc.properties[1]);
+ assert.strictEqual(bc.properties[1].key, 'lang');
+ assert.strictEqual(bc.properties[1].value, 'java');
});
it('should parse paths from GraphSON3 without properties', function () {
const obj = {
@@ -203,8 +205,34 @@ describe('GraphSONReader', function () {
assert.ok(bc instanceof graph.Vertex);
assert.strictEqual(a.label, 'person');
assert.strictEqual(bc.label, 'software');
- assert.ok(a.properties === undefined);
- assert.ok(bc.properties === undefined);
+ assert.deepStrictEqual(a.properties, []);
+ assert.deepStrictEqual(bc.properties, []);
+ });
+
+ it('should deserialize vertices without properties to empty array',
function() {
+ const obj = {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}};
+ const reader = new GraphSONReader();
+ const vertex = reader.read(obj);
+ assert.strictEqual(vertex.constructor.name, 'Vertex');
+ assert.strictEqual(vertex.label, 'person');
+ assert.strictEqual(vertex.id, 2);
+ assert.deepStrictEqual(vertex.properties, []);
+ });
+
+ it('should deserialize edges without properties to empty array', function() {
+ const obj = {"@type":"g:Edge",
"@value":{"id":{"@type":"g:Int64","@value":18},"label":"knows","inV":"a","outV":"b","inVLabel":"xLab"}};
+ const reader = new GraphSONReader();
+ const edge = reader.read(obj);
+ assert.strictEqual(edge.constructor.name, 'Edge');
+ assert.deepStrictEqual(edge.properties, []);
+ });
+
+ it('should deserialize vertex properties without meta-properties to empty
array', function() {
+ const obj = {"@type":"g:VertexProperty",
"@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}};
+ const reader = new GraphSONReader();
+ const vp = reader.read(obj);
+ assert.strictEqual(vp.constructor.name, 'VertexProperty');
+ assert.deepStrictEqual(vp.properties, []);
});
});
describe('GraphSONWriter', function () {
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
index 29bebfad92..f319a656a9 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
@@ -32,6 +32,18 @@ describe('Edge', () => {
assert.strictEqual(element.toString(), `e[123][?-label1->?]`);
});
});
+
+ describe('properties', () => {
+ it('should default to empty array when not provided', () => {
+ const edge = new Edge('123', new Vertex(1), 'knows', new Vertex(2));
+ assert.deepStrictEqual(edge.properties, []);
+ });
+
+ it('should default to empty array when undefined', () => {
+ const edge = new Edge('123', new Vertex(1), 'knows', new Vertex(2),
undefined);
+ assert.deepStrictEqual(edge.properties, []);
+ });
+ });
});
describe('Vertex', () => {
@@ -41,6 +53,23 @@ describe('Vertex', () => {
assert.strictEqual(element.toString(), `v[-200]`);
});
});
+
+ describe('properties', () => {
+ it('should default to empty array when not provided', () => {
+ const vertex = new Vertex(1, 'person');
+ assert.deepStrictEqual(vertex.properties, []);
+ });
+
+ it('should default to empty array when undefined', () => {
+ const vertex = new Vertex(1, 'person', undefined);
+ assert.deepStrictEqual(vertex.properties, []);
+ });
+
+ it('should default to empty array when null', () => {
+ const vertex = new Vertex(1, 'person', null);
+ assert.deepStrictEqual(vertex.properties, []);
+ });
+ });
});
describe('VertexProperty', () => {
@@ -56,6 +85,18 @@ describe('VertexProperty', () => {
});
});
});
+
+ describe('properties', () => {
+ it('should default to empty array when not provided', () => {
+ const vp = new VertexProperty(24, 'name', 'marko');
+ assert.deepStrictEqual(vp.properties, []);
+ });
+
+ it('should default to empty array when undefined', () => {
+ const vp = new VertexProperty(24, 'name', 'marko', undefined);
+ assert.deepStrictEqual(vp.properties, []);
+ });
+ });
});
describe('Property', () => {
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/graph.py
b/gremlin-python/src/main/python/gremlin_python/structure/graph.py
index ab83a538e1..2e3dad2727 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/graph.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/graph.py
@@ -34,7 +34,7 @@ class Element(object):
def __init__(self, id, label, properties=None):
self.id = id
self.label = label
- self.properties = properties
+ self.properties = [] if properties is None else properties
def __eq__(self, other):
return isinstance(other, self.__class__) and self.id == other.id
diff --git
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
index 08c82c5e45..7ebffd01b9 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
@@ -607,7 +607,7 @@ class VertexDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
@@ -620,7 +620,7 @@ class EdgeDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
@@ -637,7 +637,7 @@ class VertexPropertyDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
diff --git
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
index 75bc642b26..66a1fb0d7f 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
@@ -704,7 +704,7 @@ class VertexDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
@@ -717,7 +717,7 @@ class EdgeDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
@@ -734,7 +734,7 @@ class VertexPropertyDeserializer(_GraphSONTypeIO):
@classmethod
def objectify(cls, d, reader):
- properties = None
+ properties = []
if "properties" in d:
properties = reader.to_object(d["properties"])
if properties is not None:
diff --git
a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
index 346d5ffbb3..80aaa272ef 100644
---
a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
+++
b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py
@@ -116,24 +116,24 @@ class TestDriverRemoteConnection(object):
# test materializeProperties in V - GraphSON will deserialize into
None and GraphBinary to []
results = g.with_("materializeProperties", "tokens").V().to_list()
for v in results:
- assert v.properties is None or len(v.properties) == 0
+ assert len(v.properties) == 0
# #
# test materializeProperties in E - GraphSON will deserialize into
None and GraphBinary to []
results = g.with_("materializeProperties", "tokens").E().to_list()
for e in results:
- assert e.properties is None or len(e.properties) == 0
+ assert len(e.properties) == 0
# #
# test materializeProperties in VP - GraphSON will deserialize into
None and GraphBinary to []
results = g.with_("materializeProperties",
"tokens").V().properties().to_list()
for vp in results:
- assert vp.properties is None or len(vp.properties) == 0
+ assert len(vp.properties) == 0
# #
# test materializeProperties in Path - GraphSON will deserialize into
None and GraphBinary to []
p = g.with_("materializeProperties", "tokens").V().has('name',
'marko').outE().inV().has_label('software').path().next()
assert 3 == len(p.objects)
- assert p.objects[0].properties is None or len(p.objects[0].properties)
== 0
- assert p.objects[1].properties is None or len(p.objects[1].properties)
== 0
- assert p.objects[2].properties is None or len(p.objects[2].properties)
== 0
+ assert len(p.objects[0].properties) == 0
+ assert len(p.objects[1].properties) == 0
+ assert len(p.objects[2].properties) == 0
# #
# test materializeProperties in Path - 'all' should materialize
properties on each element
p = g.with_("materializeProperties", "all").V().has('name',
'marko').outE().inV().has_label('software').path().next()
diff --git
a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
index 8b31970605..d6ff7cd7b0 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
@@ -154,13 +154,16 @@ class TestGraphSONReader:
def test_graph(self):
vertex = self.graphson_reader.read_object("""
- {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type"
[...]
+ {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}}""")
assert isinstance(vertex, Vertex)
assert "person" == vertex.label
assert 1 == vertex.id
assert isinstance(vertex.id, int)
assert vertex == Vertex(1)
assert 2 == len(vertex.properties)
+ # assert actual property values - Vertex.properties should be
VertexProperty objects
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
vertex.properties)
+ assert any(vp.label == 'age' and vp.value == 29 for vp in
vertex.properties)
##
vertex = self.graphson_reader.read_object("""
{"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
@@ -169,6 +172,18 @@ class TestGraphSONReader:
assert isinstance(vertex.id, FloatType)
assert "vertex" == vertex.label
assert vertex == Vertex(45.23)
+ # properties key omitted should yield empty list
+ assert vertex.properties == []
+ ##
+ # vertex with explicit label and without properties
+ vertex = self.graphson_reader.read_object(
+ """
+ {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}}
+ """)
+ assert isinstance(vertex, Vertex)
+ assert vertex.label == 'person'
+ assert vertex.id == 2
+ assert vertex.properties == []
##
vertex_property = self.graphson_reader.read_object("""
{"@type":"g:VertexProperty",
"@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
@@ -177,6 +192,8 @@ class TestGraphSONReader:
assert "aKey" == vertex_property.label
assert vertex_property.value
assert vertex_property.vertex == Vertex(9)
+ # no properties key should yield empty list of meta-properties
+ assert vertex_property.properties == []
##
vertex_property = self.graphson_reader.read_object("""
{"@type":"g:VertexProperty",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
@@ -185,6 +202,8 @@ class TestGraphSONReader:
assert "name" == vertex_property.label
assert "marko" == vertex_property.value
assert vertex_property.vertex is None
+ # no properties key should yield empty list of meta-properties
+ assert vertex_property.properties == []
##
edge = self.graphson_reader.read_object("""
{"@type":"g:Edge",
"@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
@@ -195,6 +214,14 @@ class TestGraphSONReader:
assert edge.inV == Vertex("x", "xLabel")
assert edge.outV == Vertex("y", "vertex")
##
+ # edge without properties should yield empty properties list
+ edge2 = self.graphson_reader.read_object(
+ """
+ {"@type":"g:Edge",
"@value":{"id":{"@type":"g:Int64","@value":18},"label":"knows","inV":"a","outV":"b","inVLabel":"xLab"}}
+ """)
+ assert isinstance(edge2, Edge)
+ assert edge2.properties == []
+ ##
property = self.graphson_reader.read_object("""
{"@type":"g:Property",
"@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
# print property
@@ -204,6 +231,7 @@ class TestGraphSONReader:
assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
def test_path(self):
+ # original path with vertices that include properties
path = self.graphson_reader.read_object(
"""{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32",
[...]
)
@@ -213,6 +241,34 @@ class TestGraphSONReader:
assert Vertex(1) == path["a"]
assert "lop" == path[2]
assert 3 == len(path)
+ # ensure element properties were populated from GraphSON
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
path[0].properties)
+ assert any(vp.label == 'age' and vp.value == 29 for vp in
path[0].properties)
+ assert any(vp.label == 'name' and vp.value == 'lop' for vp in
path[1].properties)
+ assert any(vp.label == 'lang' and vp.value == 'java' for vp in
path[1].properties)
+
+ # path with elements that exclude properties (no "properties" key)
+ path2 = self.graphson_reader.read_object(
+
"""{"@type":"g:Path","@value":{"labels":[["x"],["y"],["z"]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":11},"label":"person"}},{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":77},"label":"knows","outV":{"@type":"g:Int32","@value":11},"outVLabel":"person","inV":{"@type":"g:Int32","@value":12},"inVLabel":"person"}},"hello"]}}"""
+ )
+ assert isinstance(path2, Path)
+ assert 3 == len(path2)
+ assert Vertex(11, 'person') == path2[0]
+ assert path2[0].properties == []
+ assert isinstance(path2[1], Edge)
+ assert path2[1].properties == []
+ assert path2[2] == "hello"
+
+ # mixed path: first vertex with properties, second vertex without
+ path3 = self.graphson_reader.read_object(
+
"""{"@type":"g:Path","@value":{"labels":[["a"],["b"]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}}]}}"""
+ )
+ assert isinstance(path3, Path)
+ assert 2 == len(path3)
+ assert Vertex(1) == path3[0]
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
path3[0].properties)
+ assert Vertex(2) == path3[1]
+ assert path3[1].properties == []
def test_custom_mapping(self):
diff --git
a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
index 099c1ab37c..91c1e6d7a7 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
@@ -199,12 +199,16 @@ class TestGraphSONReader:
def test_graph(self):
vertex = self.graphson_reader.read_object("""
- {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type"
[...]
+ {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}}""")
assert isinstance(vertex, Vertex)
assert "person" == vertex.label
assert 1 == vertex.id
assert isinstance(vertex.id, int)
assert vertex == Vertex(1)
+ assert 2 == len(vertex.properties)
+ # assert actual property values - Vertex.properties should be
VertexProperty objects
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
vertex.properties)
+ assert any(vp.label == 'age' and vp.value == 29 for vp in
vertex.properties)
##
vertex = self.graphson_reader.read_object("""
{"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
@@ -213,6 +217,18 @@ class TestGraphSONReader:
assert isinstance(vertex.id, FloatType)
assert "vertex" == vertex.label
assert vertex == Vertex(45.23)
+ # properties key omitted should yield empty list
+ assert vertex.properties == []
+ ##
+ # vertex with explicit label and without properties
+ vertex = self.graphson_reader.read_object(
+ """
+ {"@type":"g:Vertex",
"@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}}
+ """)
+ assert isinstance(vertex, Vertex)
+ assert vertex.label == 'person'
+ assert vertex.id == 2
+ assert vertex.properties == []
##
vertex_property = self.graphson_reader.read_object("""
{"@type":"g:VertexProperty",
"@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
@@ -221,6 +237,8 @@ class TestGraphSONReader:
assert "aKey" == vertex_property.label
assert vertex_property.value
assert vertex_property.vertex == Vertex(9)
+ # no properties key should yield empty list of meta-properties
+ assert vertex_property.properties == []
##
vertex_property = self.graphson_reader.read_object("""
{"@type":"g:VertexProperty",
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
@@ -229,6 +247,8 @@ class TestGraphSONReader:
assert "name" == vertex_property.label
assert "marko" == vertex_property.value
assert vertex_property.vertex is None
+ # no properties key should yield empty list of meta-properties
+ assert vertex_property.properties == []
##
edge = self.graphson_reader.read_object("""
{"@type":"g:Edge",
"@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
@@ -239,6 +259,14 @@ class TestGraphSONReader:
assert edge.inV == Vertex("x", "xLabel")
assert edge.outV == Vertex("y", "vertex")
##
+ # edge without properties should yield empty properties list
+ edge2 = self.graphson_reader.read_object(
+ """
+ {"@type":"g:Edge",
"@value":{"id":{"@type":"g:Int64","@value":18},"label":"knows","inV":"a","outV":"b","inVLabel":"xLab"}}
+ """)
+ assert isinstance(edge2, Edge)
+ assert edge2.properties == []
+ ##
property = self.graphson_reader.read_object("""
{"@type":"g:Property",
"@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
# print property
@@ -248,6 +276,7 @@ class TestGraphSONReader:
assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
def test_path(self):
+ # original path with vertices that include properties
path = self.graphson_reader.read_object(
"""{"@type":"g:Path","@value":{"labels":{"@type":"g:List","@value":[{"@type":"g:Set","@value":["a"]},{"@type":"g:Set","@value":["b","c"]},{"@type":"g:Set","@value":[]}]},"objects":{"@type":"g:List","@value":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":
[...]
)
@@ -257,6 +286,34 @@ class TestGraphSONReader:
assert Vertex(1) == path["a"]
assert "lop" == path[2]
assert 3 == len(path)
+ # ensure element properties were populated from GraphSON
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
path[0].properties)
+ assert any(vp.label == 'age' and vp.value == 29 for vp in
path[0].properties)
+ assert any(vp.label == 'name' and vp.value == 'lop' for vp in
path[1].properties)
+ assert any(vp.label == 'lang' and vp.value == 'java' for vp in
path[1].properties)
+
+ # path with elements that exclude properties (no "properties" key)
+ path2 = self.graphson_reader.read_object(
+
"""{"@type":"g:Path","@value":{"labels":{"@type":"g:List","@value":[{"@type":"g:Set","@value":["x"]},{"@type":"g:Set","@value":["y"]},{"@type":"g:Set","@value":["z"]}]},"objects":{"@type":"g:List","@value":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":11},"label":"person"}},{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":77},"label":"knows","outV":{"@type":"g:Int32","@value":11},"outVLabel":"person","inV":{"@type":"g:Int32","@value":12},"inVLabe
[...]
+ )
+ assert isinstance(path2, Path)
+ assert 3 == len(path2)
+ assert Vertex(11, 'person') == path2[0]
+ assert path2[0].properties == []
+ assert isinstance(path2[1], Edge)
+ assert path2[1].properties == []
+ assert path2[2] == "hello"
+
+ # mixed path: first vertex with properties, second vertex without
+ path3 = self.graphson_reader.read_object(
+
"""{"@type":"g:Path","@value":{"labels":{"@type":"g:List","@value":[{"@type":"g:Set","@value":["a"]},{"@type":"g:Set","@value":["b"]}]},"objects":{"@type":"g:List","@value":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}}]}}}"""
+ )
+ assert isinstance(path3, Path)
+ assert 2 == len(path3)
+ assert Vertex(1) == path3[0]
+ assert any(vp.label == 'name' and vp.value == 'marko' for vp in
path3[0].properties)
+ assert Vertex(2) == path3[1]
+ assert path3[1].properties == []
def test_custom_mapping(self):
diff --git a/gremlin-python/src/main/python/tests/structure/test_graph.py
b/gremlin-python/src/main/python/tests/structure/test_graph.py
index 0937e3998b..8b7fe38300 100644
--- a/gremlin-python/src/main/python/tests/structure/test_graph.py
+++ b/gremlin-python/src/main/python/tests/structure/test_graph.py
@@ -34,6 +34,8 @@ class TestGraph(object):
assert "vertex" == vertex.label
assert "person" == Vertex(1, "person").label
assert vertex == Vertex(1)
+ # properties default to empty list when not provided
+ assert vertex.properties == []
#
edge = Edge(2, Vertex(1), "said", Vertex("hello", "phrase"))
assert "e[2][1-said->hello]" == str(edge)
@@ -42,6 +44,8 @@ class TestGraph(object):
assert "said" == edge.label
assert "phrase" == edge.inV.label
assert edge.inV != edge.outV
+ # properties default to empty list when not provided
+ assert edge.properties == []
#
vertex_property = VertexProperty(long(24), "name", "marko", Vertex(1))
assert "vp[name->marko]" == str(vertex_property)
@@ -52,6 +56,8 @@ class TestGraph(object):
assert Vertex(1) == vertex_property.vertex
assert isinstance(vertex_property.id, long)
assert vertex_property == VertexProperty(long(24), "name", "marko",
Vertex(1))
+ # meta-properties default to empty list when not provided
+ assert vertex_property.properties == []
#
property = Property("age", 29, Vertex(1))
assert "p[age->29]" == str(property)
@@ -61,6 +67,23 @@ class TestGraph(object):
assert isinstance(property.value, int)
assert property == Property("age", 29, Vertex(1))
#
+ # Now create elements with properties explicitly set
+ v2 = Vertex(10, "person", [VertexProperty(100, "name", "marko",
Vertex(10))])
+ assert len(v2.properties) == 1
+ assert isinstance(v2.properties[0], VertexProperty)
+ assert v2.properties[0].label == "name"
+ assert v2.properties[0].value == "marko"
+ e2 = Edge(20, Vertex(10), "knows", Vertex(11), [Property("weight",
0.5, None)])
+ assert len(e2.properties) == 1
+ assert isinstance(e2.properties[0], Property)
+ assert e2.properties[0].key == "weight"
+ assert e2.properties[0].value == 0.5
+ vp2 = VertexProperty(30, "name", "marko", Vertex(10),
[Property("since", 2006, None)])
+ assert len(vp2.properties) == 1
+ assert isinstance(vp2.properties[0], Property)
+ assert vp2.properties[0].key == "since"
+ assert vp2.properties[0].value == 2006
+ #
for i in [vertex, edge, vertex_property, property]:
for j in [vertex, edge, vertex_property, property]:
if type(i) != type(j):