Skip to content

Commit d3ded3d

Browse files
authored
Merge pull request #165 from neo4j/case-insensitive-continued
Consider all field aliases in convenience constructors
2 parents db1f544 + bbbb868 commit d3ded3d

File tree

8 files changed

+84
-27
lines changed

8 files changed

+84
-27
lines changed

examples/snowpark-example.ipynb

Lines changed: 13 additions & 12 deletions
Large diffs are not rendered by default.

python-wrapper/src/neo4j_viz/gql_create.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,8 @@ def from_gql_create(
249249
node_pattern = re.compile(r"^\(([^)]*)\)$")
250250
rel_pattern = re.compile(r"^\(([^)]*)\)-\s*\[\s*:(\w+)\s*(\{[^}]*\})?\s*\]->\(([^)]*)\)$")
251251

252-
node_top_level_keys = set(Node.model_fields.keys())
253-
node_top_level_keys.remove("id")
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"])
259254

260255
nodes = []
261256
relationships = []

python-wrapper/src/neo4j_viz/neo4j.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,15 @@ def from_neo4j(
4747
else:
4848
raise ValueError(f"Invalid input type `{type(result)}`. Expected `neo4j.Graph` or `neo4j.Result`")
4949

50-
nodes = [_map_node(node, size_property, caption_property=node_caption) for node in graph.nodes]
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+
]
5156
relationships = []
5257
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)
5459
if mapped_rel:
5560
relationships.append(mapped_rel)
5661

@@ -62,7 +67,12 @@ def from_neo4j(
6267
return VG
6368

6469

65-
def _map_node(node: neo4j.graph.Node, size_property: Optional[str], caption_property: Optional[str]) -> 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:
6676
top_level_fields = {"id": node.element_id}
6777

6878
if size_property:
@@ -78,7 +88,7 @@ def _map_node(node: neo4j.graph.Node, size_property: Optional[str], caption_prop
7888

7989
properties = {}
8090
for prop, value in node.items():
81-
if prop not in Node.model_fields.keys():
91+
if prop not in all_node_field_aliases:
8292
properties[prop] = value
8393
continue
8494

@@ -95,7 +105,9 @@ def _map_node(node: neo4j.graph.Node, size_property: Optional[str], caption_prop
95105
return Node(**top_level_fields, properties=properties)
96106

97107

98-
def _map_relationship(rel: neo4j.graph.Relationship, caption_property: Optional[str]) -> Optional[Relationship]:
108+
def _map_relationship(
109+
rel: neo4j.graph.Relationship, all_rel_field_aliases: set[str], caption_property: Optional[str]
110+
) -> Optional[Relationship]:
99111
if rel.start_node is None or rel.end_node is None:
100112
return None
101113

@@ -109,7 +121,7 @@ def _map_relationship(rel: neo4j.graph.Relationship, caption_property: Optional[
109121

110122
properties = {}
111123
for prop, value in rel.items():
112-
if prop not in Relationship.model_fields.keys():
124+
if prop not in all_rel_field_aliases:
113125
properties[prop] = value
114126
continue
115127

python-wrapper/src/neo4j_viz/node.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,12 @@ def cast_color(cls, color: ColorType) -> Color:
8888

8989
def to_dict(self) -> dict[str, Any]:
9090
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}

python-wrapper/src/neo4j_viz/pandas.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ def _from_dfs(
2323
else:
2424
node_dfs_iter = node_dfs
2525

26+
all_node_field_aliases = Node.all_validation_aliases()
27+
all_rel_field_aliases = Relationship.all_validation_aliases()
28+
2629
has_size = True
2730
nodes = []
2831
for node_df in node_dfs_iter:
@@ -31,7 +34,7 @@ def _from_dfs(
3134
top_level = {}
3235
properties = {}
3336
for key, value in row.to_dict().items():
34-
if key in Node.model_fields.keys():
37+
if key in all_node_field_aliases:
3538
top_level[key] = value
3639
else:
3740
if rename_properties and key in rename_properties:
@@ -51,7 +54,7 @@ def _from_dfs(
5154
top_level = {}
5255
properties = {}
5356
for key, value in row.to_dict().items():
54-
if key in Relationship.model_fields.keys():
57+
if key in all_rel_field_aliases:
5558
top_level[key] = value
5659
else:
5760
if rename_properties and key in rename_properties:

python-wrapper/src/neo4j_viz/relationship.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,16 @@ def cast_color(cls, color: ColorType) -> Color:
9595

9696
def to_dict(self) -> dict[str, Any]:
9797
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}

python-wrapper/tests/test_node.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,15 @@ def test_node_casing() -> None:
9393
assert node.caption == "Person"
9494
assert node.caption_align == CaptionAlignment.TOP
9595
assert node.caption_size == 1
96+
97+
98+
def test_all_validation_aliases() -> None:
99+
all_aliases = Node.all_validation_aliases()
100+
assert "CAPTION_ALIGN" in all_aliases
101+
assert "captionAlign" in all_aliases
102+
assert "caption_align" in all_aliases
103+
104+
all_aliases = Node.all_validation_aliases(exempted_fields=["caption_align"])
105+
assert "CAPTION_ALIGN" not in all_aliases
106+
assert "captionAlign" not in all_aliases
107+
assert "caption_align" not in all_aliases

python-wrapper/tests/test_relationship.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,15 @@ def test_rel_casing() -> None:
101101
assert rel.id == "1"
102102
assert rel.caption_align == CaptionAlignment.TOP
103103
assert rel.caption_size == 12
104+
105+
106+
def test_all_validation_aliases() -> None:
107+
all_aliases = Relationship.all_validation_aliases()
108+
assert "CAPTION_ALIGN" in all_aliases
109+
assert "captionAlign" in all_aliases
110+
assert "caption_align" in all_aliases
111+
112+
all_aliases = Relationship.all_validation_aliases(exempted_fields=["caption_align"])
113+
assert "CAPTION_ALIGN" not in all_aliases
114+
assert "captionAlign" not in all_aliases
115+
assert "caption_align" not in all_aliases

0 commit comments

Comments
 (0)