neo4j-viz 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- neo4j_viz/gql_create.py +2 -7
- neo4j_viz/neo4j.py +18 -6
- neo4j_viz/node.py +36 -9
- neo4j_viz/nvl.py +26 -13
- neo4j_viz/pandas.py +5 -2
- neo4j_viz/relationship.py +42 -10
- {neo4j_viz-0.3.0.dist-info → neo4j_viz-0.3.1.dist-info}/METADATA +1 -1
- {neo4j_viz-0.3.0.dist-info → neo4j_viz-0.3.1.dist-info}/RECORD +10 -10
- {neo4j_viz-0.3.0.dist-info → neo4j_viz-0.3.1.dist-info}/WHEEL +1 -1
- {neo4j_viz-0.3.0.dist-info → neo4j_viz-0.3.1.dist-info}/top_level.txt +0 -0
neo4j_viz/gql_create.py
CHANGED
|
@@ -249,13 +249,8 @@ def from_gql_create(
|
|
|
249
249
|
node_pattern = re.compile(r"^\(([^)]*)\)$")
|
|
250
250
|
rel_pattern = re.compile(r"^\(([^)]*)\)-\s*\[\s*:(\w+)\s*(\{[^}]*\})?\s*\]->\(([^)]*)\)$")
|
|
251
251
|
|
|
252
|
-
node_top_level_keys =
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
rel_top_level_keys = set(Relationship.model_fields.keys())
|
|
256
|
-
rel_top_level_keys.remove("id")
|
|
257
|
-
rel_top_level_keys.remove("source")
|
|
258
|
-
rel_top_level_keys.remove("target")
|
|
252
|
+
node_top_level_keys = Node.all_validation_aliases(exempted_fields=["id"])
|
|
253
|
+
rel_top_level_keys = Relationship.all_validation_aliases(exempted_fields=["id", "source", "target"])
|
|
259
254
|
|
|
260
255
|
nodes = []
|
|
261
256
|
relationships = []
|
neo4j_viz/neo4j.py
CHANGED
|
@@ -47,10 +47,15 @@ def from_neo4j(
|
|
|
47
47
|
else:
|
|
48
48
|
raise ValueError(f"Invalid input type `{type(result)}`. Expected `neo4j.Graph` or `neo4j.Result`")
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
all_node_field_aliases = Node.all_validation_aliases()
|
|
51
|
+
all_rel_field_aliases = Relationship.all_validation_aliases()
|
|
52
|
+
|
|
53
|
+
nodes = [
|
|
54
|
+
_map_node(node, all_node_field_aliases, size_property, caption_property=node_caption) for node in graph.nodes
|
|
55
|
+
]
|
|
51
56
|
relationships = []
|
|
52
57
|
for rel in graph.relationships:
|
|
53
|
-
mapped_rel = _map_relationship(rel, caption_property=relationship_caption)
|
|
58
|
+
mapped_rel = _map_relationship(rel, all_rel_field_aliases, caption_property=relationship_caption)
|
|
54
59
|
if mapped_rel:
|
|
55
60
|
relationships.append(mapped_rel)
|
|
56
61
|
|
|
@@ -62,7 +67,12 @@ def from_neo4j(
|
|
|
62
67
|
return VG
|
|
63
68
|
|
|
64
69
|
|
|
65
|
-
def _map_node(
|
|
70
|
+
def _map_node(
|
|
71
|
+
node: neo4j.graph.Node,
|
|
72
|
+
all_node_field_aliases: set[str],
|
|
73
|
+
size_property: Optional[str],
|
|
74
|
+
caption_property: Optional[str],
|
|
75
|
+
) -> Node:
|
|
66
76
|
top_level_fields = {"id": node.element_id}
|
|
67
77
|
|
|
68
78
|
if size_property:
|
|
@@ -78,7 +88,7 @@ def _map_node(node: neo4j.graph.Node, size_property: Optional[str], caption_prop
|
|
|
78
88
|
|
|
79
89
|
properties = {}
|
|
80
90
|
for prop, value in node.items():
|
|
81
|
-
if prop not in
|
|
91
|
+
if prop not in all_node_field_aliases:
|
|
82
92
|
properties[prop] = value
|
|
83
93
|
continue
|
|
84
94
|
|
|
@@ -95,7 +105,9 @@ def _map_node(node: neo4j.graph.Node, size_property: Optional[str], caption_prop
|
|
|
95
105
|
return Node(**top_level_fields, properties=properties)
|
|
96
106
|
|
|
97
107
|
|
|
98
|
-
def _map_relationship(
|
|
108
|
+
def _map_relationship(
|
|
109
|
+
rel: neo4j.graph.Relationship, all_rel_field_aliases: set[str], caption_property: Optional[str]
|
|
110
|
+
) -> Optional[Relationship]:
|
|
99
111
|
if rel.start_node is None or rel.end_node is None:
|
|
100
112
|
return None
|
|
101
113
|
|
|
@@ -109,7 +121,7 @@ def _map_relationship(rel: neo4j.graph.Relationship, caption_property: Optional[
|
|
|
109
121
|
|
|
110
122
|
properties = {}
|
|
111
123
|
for prop, value in rel.items():
|
|
112
|
-
if prop not in
|
|
124
|
+
if prop not in all_rel_field_aliases:
|
|
113
125
|
properties[prop] = value
|
|
114
126
|
continue
|
|
115
127
|
|
neo4j_viz/node.py
CHANGED
|
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Optional, Union
|
|
4
4
|
|
|
5
|
-
from pydantic import AliasChoices, BaseModel, Field, field_serializer, field_validator
|
|
5
|
+
from pydantic import AliasChoices, AliasGenerator, BaseModel, Field, field_serializer, field_validator
|
|
6
|
+
from pydantic.alias_generators import to_camel
|
|
6
7
|
from pydantic_extra_types.color import Color, ColorType
|
|
7
8
|
|
|
8
9
|
from .node_size import RealNumber
|
|
@@ -11,29 +12,46 @@ from .options import CaptionAlignment
|
|
|
11
12
|
NodeIdType = Union[str, int]
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
def create_aliases(field_name: str) -> AliasChoices:
|
|
16
|
+
valid_names = [field_name]
|
|
17
|
+
|
|
18
|
+
if field_name == "id":
|
|
19
|
+
valid_names.extend(["nodeid", "node_id"])
|
|
20
|
+
|
|
21
|
+
choices = [[choice, choice.upper(), to_camel(choice)] for choice in valid_names]
|
|
22
|
+
|
|
23
|
+
return AliasChoices(*[alias for aliases in choices for alias in aliases])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Node(
|
|
27
|
+
BaseModel,
|
|
28
|
+
extra="forbid",
|
|
29
|
+
alias_generator=AliasGenerator(
|
|
30
|
+
validation_alias=create_aliases,
|
|
31
|
+
serialization_alias=lambda field_name: to_camel(field_name),
|
|
32
|
+
),
|
|
33
|
+
):
|
|
15
34
|
"""
|
|
16
35
|
A node in a graph to visualize.
|
|
17
36
|
|
|
37
|
+
Each field is case-insensitive for input, and camelCase is also accepted.
|
|
38
|
+
For example, "CAPTION_ALIGN", "captionAlign" are also valid inputs keys for the `caption_align` field.
|
|
39
|
+
Upon construction however, the field names are converted to snake_case.
|
|
40
|
+
|
|
18
41
|
For more info on each field, see the NVL library docs: https://neo4j.com/docs/nvl/current/base-library/#_nodes
|
|
19
42
|
"""
|
|
20
43
|
|
|
21
44
|
#: Unique identifier for the node
|
|
22
|
-
id: NodeIdType = Field(
|
|
23
|
-
validation_alias=AliasChoices("id", "nodeId", "node_id"), description="Unique identifier for the node"
|
|
24
|
-
)
|
|
45
|
+
id: NodeIdType = Field(description="Unique identifier for the node")
|
|
25
46
|
#: The caption of the node
|
|
26
47
|
caption: Optional[str] = Field(None, description="The caption of the node")
|
|
27
48
|
#: The alignment of the caption text
|
|
28
|
-
caption_align: Optional[CaptionAlignment] = Field(
|
|
29
|
-
None, serialization_alias="captionAlign", description="The alignment of the caption text"
|
|
30
|
-
)
|
|
49
|
+
caption_align: Optional[CaptionAlignment] = Field(None, description="The alignment of the caption text")
|
|
31
50
|
#: The size of the caption text. The font size to node radius ratio
|
|
32
51
|
caption_size: Optional[int] = Field(
|
|
33
52
|
None,
|
|
34
53
|
ge=1,
|
|
35
54
|
le=3,
|
|
36
|
-
serialization_alias="captionSize",
|
|
37
55
|
description="The size of the caption text. The font size to node radius ratio",
|
|
38
56
|
)
|
|
39
57
|
#: The size of the node as radius in pixel
|
|
@@ -70,3 +88,12 @@ class Node(BaseModel, extra="allow"):
|
|
|
70
88
|
|
|
71
89
|
def to_dict(self) -> dict[str, Any]:
|
|
72
90
|
return self.model_dump(exclude_none=True, by_alias=True)
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def all_validation_aliases(exempted_fields: Optional[list[str]] = None) -> set[str]:
|
|
94
|
+
if exempted_fields is None:
|
|
95
|
+
exempted_fields = []
|
|
96
|
+
|
|
97
|
+
by_field = [v.validation_alias.choices for k, v in Node.model_fields.items() if k not in exempted_fields] # type: ignore
|
|
98
|
+
|
|
99
|
+
return {str(alias) for aliases in by_field for alias in aliases}
|
neo4j_viz/nvl.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
import uuid
|
|
5
5
|
from importlib.resources import files
|
|
6
|
+
from typing import Union
|
|
6
7
|
|
|
7
8
|
from IPython.display import HTML
|
|
8
9
|
|
|
@@ -40,10 +41,28 @@ class NVL:
|
|
|
40
41
|
with screenshot_path.open("r", encoding="utf-8") as file:
|
|
41
42
|
self.screenshot_svg = file.read()
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _serialize_entity(entity: Union[Node, Relationship]) -> str:
|
|
46
|
+
try:
|
|
47
|
+
entity_dict = entity.to_dict()
|
|
48
|
+
return json.dumps(entity_dict)
|
|
49
|
+
except TypeError:
|
|
50
|
+
props_as_strings = {}
|
|
51
|
+
for k, v in entity_dict["properties"].items():
|
|
52
|
+
try:
|
|
53
|
+
json.dumps(v)
|
|
54
|
+
except TypeError:
|
|
55
|
+
props_as_strings[k] = str(v)
|
|
56
|
+
entity_dict["properties"].update(props_as_strings)
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
return json.dumps(entity_dict)
|
|
60
|
+
except TypeError as e:
|
|
61
|
+
# This should never happen anymore, but just in case
|
|
62
|
+
if "not JSON serializable" in str(e):
|
|
63
|
+
raise ValueError(f"A field of a {type(entity).__name__} object is not supported: {str(e)}")
|
|
64
|
+
else:
|
|
65
|
+
raise e
|
|
47
66
|
|
|
48
67
|
def render(
|
|
49
68
|
self,
|
|
@@ -54,14 +73,8 @@ class NVL:
|
|
|
54
73
|
height: str,
|
|
55
74
|
show_hover_tooltip: bool,
|
|
56
75
|
) -> HTML:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
except TypeError as e:
|
|
60
|
-
raise self.unsupported_field_type_error(e, "node")
|
|
61
|
-
try:
|
|
62
|
-
rels_json = json.dumps([rel.to_dict() for rel in relationships])
|
|
63
|
-
except TypeError as e:
|
|
64
|
-
raise self.unsupported_field_type_error(e, "relationship")
|
|
76
|
+
nodes_json = f"[{','.join([self._serialize_entity(node) for node in nodes])}]"
|
|
77
|
+
rels_json = f"[{','.join([self._serialize_entity(rel) for rel in relationships])}]"
|
|
65
78
|
|
|
66
79
|
render_options_json = json.dumps(render_options.to_dict())
|
|
67
80
|
container_id = str(uuid.uuid4())
|
|
@@ -112,7 +125,7 @@ class NVL:
|
|
|
112
125
|
<script>
|
|
113
126
|
getTheme = () => {{
|
|
114
127
|
const backgroundColorString = window.getComputedStyle(document.body, null).getPropertyValue('background-color')
|
|
115
|
-
const colorsArray = backgroundColorString.match(
|
|
128
|
+
const colorsArray = backgroundColorString.match(/\\d+/g);
|
|
116
129
|
const brightness = Number(colorsArray[0]) * 0.2126 + Number(colorsArray[1]) * 0.7152 + Number(colorsArray[2]) * 0.0722
|
|
117
130
|
return brightness < 128 ? "dark" : "light"
|
|
118
131
|
}}
|
neo4j_viz/pandas.py
CHANGED
|
@@ -23,6 +23,9 @@ def _from_dfs(
|
|
|
23
23
|
else:
|
|
24
24
|
node_dfs_iter = node_dfs
|
|
25
25
|
|
|
26
|
+
all_node_field_aliases = Node.all_validation_aliases()
|
|
27
|
+
all_rel_field_aliases = Relationship.all_validation_aliases()
|
|
28
|
+
|
|
26
29
|
has_size = True
|
|
27
30
|
nodes = []
|
|
28
31
|
for node_df in node_dfs_iter:
|
|
@@ -31,7 +34,7 @@ def _from_dfs(
|
|
|
31
34
|
top_level = {}
|
|
32
35
|
properties = {}
|
|
33
36
|
for key, value in row.to_dict().items():
|
|
34
|
-
if key in
|
|
37
|
+
if key in all_node_field_aliases:
|
|
35
38
|
top_level[key] = value
|
|
36
39
|
else:
|
|
37
40
|
if rename_properties and key in rename_properties:
|
|
@@ -51,7 +54,7 @@ def _from_dfs(
|
|
|
51
54
|
top_level = {}
|
|
52
55
|
properties = {}
|
|
53
56
|
for key, value in row.to_dict().items():
|
|
54
|
-
if key in
|
|
57
|
+
if key in all_rel_field_aliases:
|
|
55
58
|
top_level[key] = value
|
|
56
59
|
else:
|
|
57
60
|
if rename_properties and key in rename_properties:
|
neo4j_viz/relationship.py
CHANGED
|
@@ -3,16 +3,41 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any, Optional, Union
|
|
4
4
|
from uuid import uuid4
|
|
5
5
|
|
|
6
|
-
from pydantic import AliasChoices, BaseModel, Field, field_serializer, field_validator
|
|
6
|
+
from pydantic import AliasChoices, AliasGenerator, BaseModel, Field, field_serializer, field_validator
|
|
7
|
+
from pydantic.alias_generators import to_camel
|
|
7
8
|
from pydantic_extra_types.color import Color, ColorType
|
|
8
9
|
|
|
9
10
|
from .options import CaptionAlignment
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
def create_aliases(field_name: str) -> AliasChoices:
|
|
14
|
+
valid_names = [field_name]
|
|
15
|
+
|
|
16
|
+
if field_name == "source":
|
|
17
|
+
valid_names.extend(["sourcenodeid", "source_node_id", "from"])
|
|
18
|
+
if field_name == "target":
|
|
19
|
+
valid_names.extend(["targetnodeid", "target_node_id", "to"])
|
|
20
|
+
|
|
21
|
+
choices = [[choice, choice.upper(), to_camel(choice)] for choice in valid_names]
|
|
22
|
+
|
|
23
|
+
return AliasChoices(*[alias for aliases in choices for alias in aliases])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Relationship(
|
|
27
|
+
BaseModel,
|
|
28
|
+
extra="forbid",
|
|
29
|
+
alias_generator=AliasGenerator(
|
|
30
|
+
validation_alias=create_aliases,
|
|
31
|
+
serialization_alias=lambda field_name: to_camel(field_name),
|
|
32
|
+
),
|
|
33
|
+
):
|
|
13
34
|
"""
|
|
14
35
|
A relationship in a graph to visualize.
|
|
15
36
|
|
|
37
|
+
Each field is case-insensitive for input, and camelCase is also accepted.
|
|
38
|
+
For example, "CAPTION_ALIGN", "captionAlign" are also valid inputs keys for the `caption_align` field.
|
|
39
|
+
Upon construction however, the field names are converted to snake_case.
|
|
40
|
+
|
|
16
41
|
For more info on each field, see the NVL library docs: https://neo4j.com/docs/nvl/current/base-library/#_relationships
|
|
17
42
|
"""
|
|
18
43
|
|
|
@@ -23,25 +48,19 @@ class Relationship(BaseModel, extra="allow"):
|
|
|
23
48
|
#: Node ID where the relationship points from
|
|
24
49
|
source: Union[str, int] = Field(
|
|
25
50
|
serialization_alias="from",
|
|
26
|
-
validation_alias=AliasChoices("source", "sourceNodeId", "source_node_id", "from"),
|
|
27
51
|
description="Node ID where the relationship points from",
|
|
28
52
|
)
|
|
29
53
|
#: Node ID where the relationship points to
|
|
30
54
|
target: Union[str, int] = Field(
|
|
31
55
|
serialization_alias="to",
|
|
32
|
-
validation_alias=AliasChoices("target", "targetNodeId", "target_node_id", "to"),
|
|
33
56
|
description="Node ID where the relationship points to",
|
|
34
57
|
)
|
|
35
58
|
#: The caption of the relationship
|
|
36
59
|
caption: Optional[str] = Field(None, description="The caption of the relationship")
|
|
37
60
|
#: The alignment of the caption text
|
|
38
|
-
caption_align: Optional[CaptionAlignment] = Field(
|
|
39
|
-
None, serialization_alias="captionAlign", description="The alignment of the caption text"
|
|
40
|
-
)
|
|
61
|
+
caption_align: Optional[CaptionAlignment] = Field(None, description="The alignment of the caption text")
|
|
41
62
|
#: The size of the caption text
|
|
42
|
-
caption_size: Optional[Union[int, float]] = Field(
|
|
43
|
-
None, gt=0.0, serialization_alias="captionSize", description="The size of the caption text"
|
|
44
|
-
)
|
|
63
|
+
caption_size: Optional[Union[int, float]] = Field(None, gt=0.0, description="The size of the caption text")
|
|
45
64
|
#: The color of the relationship. Allowed input is for example "#FF0000", "red" or (255, 0, 0)
|
|
46
65
|
color: Optional[ColorType] = Field(None, description="The color of the relationship")
|
|
47
66
|
#: Additional properties of the relationship that do not directly impact the visualization
|
|
@@ -76,3 +95,16 @@ class Relationship(BaseModel, extra="allow"):
|
|
|
76
95
|
|
|
77
96
|
def to_dict(self) -> dict[str, Any]:
|
|
78
97
|
return self.model_dump(exclude_none=True, by_alias=True)
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def all_validation_aliases(exempted_fields: Optional[list[str]] = None) -> set[str]:
|
|
101
|
+
if exempted_fields is None:
|
|
102
|
+
exempted_fields = []
|
|
103
|
+
|
|
104
|
+
by_field = [
|
|
105
|
+
v.validation_alias.choices # type: ignore
|
|
106
|
+
for k, v in Relationship.model_fields.items()
|
|
107
|
+
if k not in exempted_fields
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
return {str(alias) for aliases in by_field for alias in aliases}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
neo4j_viz/__init__.py,sha256=ATDPdaupFWIWaOWtJtfCGVRVuuwXKNe1hNdENofgRLk,270
|
|
2
2
|
neo4j_viz/colors.py,sha256=IvOCTmCu7WTMna_wNLZ3GrThTwFyIoKtNkmZYDLdYac,6694
|
|
3
3
|
neo4j_viz/gds.py,sha256=v6b3XdSoWSoOu-U2MWQM-5QXLiPT3_9gGOv7haxuozE,4135
|
|
4
|
-
neo4j_viz/gql_create.py,sha256=
|
|
5
|
-
neo4j_viz/neo4j.py,sha256=
|
|
6
|
-
neo4j_viz/node.py,sha256=
|
|
4
|
+
neo4j_viz/gql_create.py,sha256=YH9mZUx-b86h714wCIbikGoxZD7IEuOmhKDdrp5fhXk,13264
|
|
5
|
+
neo4j_viz/neo4j.py,sha256=UTrLZRlDgkw2w8Ov4P1oP8w-25Kf0sMCkLFDq3qD-Q8,4855
|
|
6
|
+
neo4j_viz/node.py,sha256=MiLoghsn2NLs_iV65NuW7u3iaxP8MTKoNy6La9TdreY,3886
|
|
7
7
|
neo4j_viz/node_size.py,sha256=c_sMtQSD8eJ_6Y0Kr6ku0LOs9VoEDxfYCUUzUWZ-1Xo,1197
|
|
8
|
-
neo4j_viz/nvl.py,sha256=
|
|
8
|
+
neo4j_viz/nvl.py,sha256=ZN3tyWar9ugR88r5N6txW3ThfNEWOt5A1KzrrRnLKwk,5262
|
|
9
9
|
neo4j_viz/options.py,sha256=QBeHLqHOJFtSCjzHvv-2A9TzTbnIaC6_onQq9fUlT_4,3079
|
|
10
|
-
neo4j_viz/pandas.py,sha256=
|
|
10
|
+
neo4j_viz/pandas.py,sha256=bju4Pcoe-d_MFG6XOpVPPkD_p3cF-gWuXqfA9oxyvSU,3382
|
|
11
11
|
neo4j_viz/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
neo4j_viz/relationship.py,sha256=
|
|
12
|
+
neo4j_viz/relationship.py,sha256=sRgGjNzlqt6wPmiB3WXBTxR_W_5Z40VofpHUZvkRS1I,4143
|
|
13
13
|
neo4j_viz/visualization_graph.py,sha256=ogYhxAyPzqOcSogYSesGAV6iRQDLIA-YhBImEShuCPM,13175
|
|
14
14
|
neo4j_viz/resources/icons/screenshot.svg,sha256=Ns9Yi2Iq4lIaiFvzc0pXBmjxt4fcmBO-I4cI8Xiu1HE,311
|
|
15
15
|
neo4j_viz/resources/icons/zoom-in.svg,sha256=PsO5yFkA1JnGM2QV_qxHKG13qmoR-RrlWARpaXNp5qU,415
|
|
16
16
|
neo4j_viz/resources/icons/zoom-out.svg,sha256=OQRADAoe2bxbCeFufg6W22nR41q5NlI8QspT9l5pXUw,400
|
|
17
17
|
neo4j_viz/resources/nvl_entrypoint/base.js,sha256=QfFjqd7Uo2F-plgFlPfLzUcjqzTzqUh533VaBemJhLI,1816247
|
|
18
18
|
neo4j_viz/resources/nvl_entrypoint/styles.css,sha256=JjeTSB9OJT2KMfb8yFUUMLMG7Rzrf3o60hSCD547zTk,1123
|
|
19
|
-
neo4j_viz-0.3.
|
|
20
|
-
neo4j_viz-0.3.
|
|
21
|
-
neo4j_viz-0.3.
|
|
22
|
-
neo4j_viz-0.3.
|
|
19
|
+
neo4j_viz-0.3.1.dist-info/METADATA,sha256=p8n2aK9ELDWZX75mUyDCh1pLR22TdWrQarXTXmXYcAU,7074
|
|
20
|
+
neo4j_viz-0.3.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
21
|
+
neo4j_viz-0.3.1.dist-info/top_level.txt,sha256=jPUM3z8MOtxqDanc2VzqkxG4HJn8aaq4S7rnCFNk_Vs,10
|
|
22
|
+
neo4j_viz-0.3.1.dist-info/RECORD,,
|
|
File without changes
|