Skip to content

Commit 4dd11ef

Browse files
authored
Cleanup (#5)
* Gif for data import tab updated + importing tab only displays json files now * Datetime in properties fix + relationship mappings added to data-import json generation
1 parent 4360c9c commit 4dd11ef

11 files changed

+48
-48
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# MOCK GRAPH DATA GENERATOR
22
This is a prototype app for generating mock graph data for [Neo4j](https://neo4j.com/) database instances.
33

4+
<!-- TODO: Add animated gif: 1. Design in Arrows, 2. Mapping options, 3. Uploading to data-importer -->
5+
46
## Requirements
57
[Poetry](https://python-poetry.org/) should be installed. Code in this repo uses Poetry for managing dependencies and running a virtual environment.
68

mock_generators/constants.py

-21
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,3 @@
2727

2828
# TODO: Can Streamlit's st.session hold all the data we'll be generating?
2929
MAPPINGS = "mappings"
30-
31-
# TODO: Add page titles
32-
# OVERVIEW_PAGE_TITLE = "🏠 Overview"
33-
# DESIGN_PAGE_TITLE = "✍️ Design"
34-
# IMPORT_PAGE_TITLE = "🔼 Import"
35-
# SETTINGS_PAGE_TITLE = "⚙️ Settings"
36-
# MAPPINGS_PAGE_TITLE = "🔀 Mapping"
37-
# GENERATORS_PAGE_TITLE = "👨‍👩‍👧‍👦 Generators"
38-
# GENERATE_PAGE_TITLE = "🏃‍♂️ Generate"
39-
# EXPORT_PAGE_TITLE = "🔽 Export"
40-
# PROPERTIES_PAGE_TITLE = "🧩 Properties"
41-
42-
# OVERVIEW_SHORT_TITLE = "Overview"
43-
# DESIGN_SHORT_TITLE = "Design"
44-
# IMPORT_SHORT_TITLE = "Import"
45-
# PROPERTIES_SHORT_TITLE = "Properties"
46-
# MAPPINGS_SHORT_TITLE = "Mapping"
47-
# GENERATE_SHORT_TITLE = "Generate"
48-
# EXPORT_SHORT_TITLE = "Export"
49-
# SETTINGS_SHORT_TITLE = "Settings"
50-
# GENERATORS_SHORT_TITLE = "Generators"

mock_generators/generators/ecdff22c.py

-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
# from base_generators.bool_generator import BoolGenerator
2-
3-
# class ConstantBoolGenerator(BoolGenerator):
4-
5-
# def generate(self, *args)->bool:
6-
# value = bool(args[0])
7-
# return value
8-
9-
101
# Do not change function name or arguments
112
def generate(args: list[any]):
123
value = args[0]

mock_generators/list_utils.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import datetime
2+
3+
def clean_list(list: list[any]) -> list[any]:
4+
# Remove None values from a list
5+
result = [item for item in list if item is not None]
6+
7+
# Convert datetime to string
8+
result = [item.isoformat() if isinstance(item, datetime.date) else item for item in result]
9+
10+
return result

mock_generators/models/data_import.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ def file_schema_for_property(property: PropertyMapping)-> dict:
1313
# Why is it so tough to catch datetime objects?
1414
if isinstance(sample_value, datetime.date):
1515
sample_value = sample_value.isoformat()
16-
if type(sample_value) is datetime:
17-
sample_value = sample_value.isoformat()
18-
if property.type == GeneratorType.DATETIME:
19-
sample_value = sample_value.isoformat()
16+
# if type(sample_value) is datetime:
17+
# sample_value = sample_value.isoformat()
18+
# if property.type == GeneratorType.DATETIME:
19+
# sample_value = sample_value.isoformat()
2020

2121
result = {
2222
"name": property.name,
@@ -60,6 +60,14 @@ def mapping_model_node_mappings(node:NodeMapping)->list[dict[str,str]]:
6060
})
6161
return result
6262

63+
def mapping_model_relationship_mappings(rel:RelationshipMapping)->list[dict[str,str]]:
64+
result = []
65+
for property in rel.properties.values():
66+
result.append({
67+
"field": property.name,
68+
})
69+
return result
70+
6371
class DataImporterJson():
6472
# Object for converting mapping info to a JSON file that can be imported into the Data Importer
6573

@@ -289,7 +297,7 @@ def add_relationship(
289297
{
290298
f"{relationship.rid}":{
291299
"relationshipSchema": f'{relationship.rid}',
292-
"mappings":[],
300+
"mappings":mapping_model_node_mappings(relationship),
293301
# NOTE: The prefixing
294302
"sourceMappings": [{
295303
"field":f"_from_{relationship.from_node.key_property.name}"

mock_generators/models/node_mapping.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from models.generator import Generator
33
import sys
44
import logging
5+
from list_utils import clean_list
56

67
# TODO: Should have made these dataclasses
78
class NodeMapping():
@@ -54,7 +55,7 @@ def to_dict(self):
5455
"labels": self.labels,
5556
"properties": {key: property.to_dict() for (key, property) in self.properties.items() if property.type is not None},
5657
"count_generator": self.count_generator.to_dict() if self.count_generator is not None else None,
57-
"count_args": self.count_args,
58+
"count_args": clean_list(self.count_args),
5859
"key_property" : self.key_property.to_dict() if self.key_property is not None else None
5960
}
6061

mock_generators/models/property_mapping.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from models.generator import Generator, GeneratorType
2+
from list_utils import clean_list
23
import logging
34

45
class PropertyMapping():
@@ -28,7 +29,9 @@ def __init__(
2829
self.args = args
2930

3031
def __str__(self):
31-
return f"PropertyMapping(pid={self.pid}, name={self.name}, type={self.type}, generator={self.generator.name}, generator_id={self.generator.id}, args={self.args})"
32+
name = self.name if self.name is not None else "<unnamed>"
33+
generator = self.generator if self.generator is not None else "<no_generator_assigned>"
34+
return f"PropertyMapping(pid={self.pid}, name={name}, type={self.type}, generator={generator}, args={self.args}"
3235

3336
def __repr__(self):
3437
return self.__str__()
@@ -40,9 +43,9 @@ def to_dict(self):
4043
return {
4144
"pid": self.pid,
4245
"name": self.name,
43-
"type": self.type.to_string(),
44-
"generator": self.generator.to_dict(),
45-
"args": self.args
46+
"type": self.type.to_string() if self.type is not None else None,
47+
"generator": self.generator.to_dict() if self.generator is not None else None,
48+
"args": clean_list(self.args)
4649
}
4750

4851
def ready_to_generate(self):

mock_generators/models/relationship_mapping.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import random
77
import sys
88
from copy import deepcopy
9+
from list_utils import clean_list
910

1011
class RelationshipMapping():
1112

@@ -50,12 +51,12 @@ def __init__(
5051
self.to_node = to_node
5152
self.properties = properties
5253
self.count_generator = count_generator
53-
self.count_args = count_args
54+
self.count_args = clean_list(count_args)
5455
self.generated_values = None
5556
self.filter_generator = filter_generator
56-
self.filter_generator_args = filter_args
57+
self.filter_generator_args = clean_list(filter_args)
5758
self.assignment_generator = assignment_generator
58-
self.assignment_args = assignment_args
59+
self.assignment_args = clean_list(assignment_args)
5960

6061
def __str__(self):
6162
return f"RelationshipMapping(rid={self.rid}, type={self.type}, from_node={self.from_node}, to_node={self.to_node}, properties={self.properties}, count_generator={self.count_generator}, count_args={self.count_args})"

mock_generators/tabs/data_importer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def data_importer_tab():
77

88
col1, col2 = st.columns([1,11])
99
with col1:
10-
st.image("mock_generators/media/abstract.gif")
10+
st.image("mock_generators/media/signpost.gif")
1111
with col2:
1212
st.write(f"Data Importer App.\n\nUse the [Data Importer Tool](https://data-importer.graphapp.io/) to upload generated .zip file to for review and ingesetion to a Neo4j database instance.")
1313
st.markdown("--------")

mock_generators/tabs/importing_tab.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def import_tab():
7777
st.write("Select an import file:")
7878

7979
folder_files_expander(
80-
folder_path=st.session_state[IMPORTS_PATH], file_selected=file_selected, file_selection_button_text="Load this file")
80+
folder_path=st.session_state[IMPORTS_PATH], file_selected=file_selected,
81+
specific_extension=".json",
82+
file_selection_button_text="Load this file")
8183

8284
elif import_option == "Upload":
8385
# Upload a new file

mock_generators/widgets/property_row.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ def property_row(
3131
if recommended_generator is None:
3232
logging.info(f'No recommended generator for property {existing_name}')
3333
name = st.text_input("Property Name",value=existing_name, key=f"{type}_{pid}_property_{index}_name")
34-
if name != "" and name[0] == "_":
35-
st.error("Property names cannot start with an underscore")
36-
name = None
34+
if name is None or name == "":
35+
st.error("Property name cannot be empty")
36+
# if name[0] == "_":
37+
# st.error("Property names cannot start with an underscore")
38+
# name = None
3739

3840
# Property type
3941
with pc2:
@@ -140,6 +142,7 @@ def sort_by_name(generator: Generator):
140142
st.write("Options")
141143
should_ignore = st.checkbox("Exclude/ignore", value=False, key=f"{type}_{pid}_property_{index}__ignore")
142144

145+
# TODO: Update to fail validation if any property items failed (ie empty name)
143146
if should_ignore == True:
144147
return PropertyMapping.empty()
145148

0 commit comments

Comments
 (0)