Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add formatting step to CI #32

Merged
merged 7 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ jobs:
echo "package.json not found, skipping npm commands."
fi

- name: Check formatting
run: |
npm run prettier:check
black . --check --exclude=node_modules

- name: Run frontend tests
run: |
npm run vitest
Expand Down
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"singleAttributePerLine": true
"singleAttributePerLine": true,
"tabWidth": 4
}
6 changes: 3 additions & 3 deletions arches_lingo/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
if platform.system().lower() == "windows":
os.environ.setdefault("FORKED_BY_MULTIPROCESSING", "1")

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'arches_lingo.settings')
app = Celery('arches_lingo')
app.config_from_object('django.conf:settings', namespace='CELERY')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "arches_lingo.settings")
app = Celery("arches_lingo")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
171 changes: 124 additions & 47 deletions arches_lingo/etl_modules/migrate_to_lingo.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from arches.app.datatypes.datatypes import DataTypeFactory
from arches.app.etl_modules.save import save_to_tiles
from arches.app.etl_modules.decorators import load_data_async
from arches.app.etl_modules.base_import_module import BaseImportModule, FileValidationError
from arches.app.etl_modules.base_import_module import (
BaseImportModule,
FileValidationError,
)
from arches.app.models import models
from arches.app.models.concept import Concept
from arches.app.models.models import LoadStaging, NodeGroup, LoadEvent
Expand Down Expand Up @@ -47,17 +50,24 @@ def __init__(self, request=None, loadid=None):
self.moduleid = request.POST.get("module") if request else None
self.loadid = request.POST.get("loadid") if request else loadid
self.datatype_factory = DataTypeFactory()

def etl_schemes(self, cursor, nodegroup_lookup, node_lookup):
schemes = []
for concept in models.Concept.objects.filter(nodetype="ConceptScheme").prefetch_related("value_set"):
for concept in models.Concept.objects.filter(
nodetype="ConceptScheme"
).prefetch_related("value_set"):
scheme_to_load = {"type": "Scheme", "tile_data": []}
for value in concept.value_set.all():
scheme_to_load["resourceinstanceid"] = concept.pk # use old conceptid as new resourceinstanceid
scheme_to_load["resourceinstanceid"] = (
concept.pk
) # use old conceptid as new resourceinstanceid

name = {}
identifier = {}
if value.valuetype_id == "prefLabel" or value.valuetype_id == "altLabel":
if (
value.valuetype_id == "prefLabel"
or value.valuetype_id == "altLabel"
):
name["name_content"] = value.value
name["name_language"] = value.language_id
name["name_type"] = value.valuetype_id
Expand All @@ -67,18 +77,25 @@ def etl_schemes(self, cursor, nodegroup_lookup, node_lookup):
identifier["identifier_type"] = value.valuetype_id
scheme_to_load["tile_data"].append({"identifier": identifier})
schemes.append(scheme_to_load)
self.populate_staging_table(cursor, schemes, nodegroup_lookup, node_lookup)
self.populate_staging_table(cursor, schemes, nodegroup_lookup, node_lookup)

def etl_concepts(self, cursor, nodegroup_lookup, node_lookup):
concepts = []
for concept in models.Concept.objects.filter(nodetype="Concept").prefetch_related("value_set"):
for concept in models.Concept.objects.filter(
nodetype="Concept"
).prefetch_related("value_set"):
concept_to_load = {"type": "Concept", "tile_data": []}
for value in concept.value_set.all():
concept_to_load["resourceinstanceid"] = concept.pk # use old conceptid as new resourceinstanceid
concept_to_load["resourceinstanceid"] = (
concept.pk
) # use old conceptid as new resourceinstanceid

name = {}
identifier = {}
if value.valuetype_id == "prefLabel" or value.valuetype_id == "altLabel":
if (
value.valuetype_id == "prefLabel"
or value.valuetype_id == "altLabel"
):
name["name_content"] = value.value
name["name_language"] = value.language_id
name["name_type"] = value.valuetype_id
Expand All @@ -90,8 +107,9 @@ def etl_concepts(self, cursor, nodegroup_lookup, node_lookup):
concepts.append(concept_to_load)
self.populate_staging_table(cursor, concepts, nodegroup_lookup, node_lookup)


def populate_staging_table(self, cursor, concepts_to_load, nodegroup_lookup, node_lookup):
def populate_staging_table(
self, cursor, concepts_to_load, nodegroup_lookup, node_lookup
):
tiles_to_load = []
for concept_to_load in concepts_to_load:
for mock_tile in concept_to_load["tile_data"]:
Expand All @@ -100,23 +118,32 @@ def populate_staging_table(self, cursor, concepts_to_load, nodegroup_lookup, nod
nodegroup_depth = nodegroup_lookup[nodegroup_id]["depth"]
tile_id = uuid.uuid4()
parent_tile_id = None
tile_value_json, passes_validation = self.create_tile_value(cursor, mock_tile, nodegroup_alias, nodegroup_lookup, node_lookup)
tile_value_json, passes_validation = self.create_tile_value(
cursor, mock_tile, nodegroup_alias, nodegroup_lookup, node_lookup
)
operation = "insert"
tiles_to_load.append(LoadStaging(
load_event=LoadEvent(self.loadid),
nodegroup=NodeGroup(nodegroup_id),
resourceid=concept_to_load["resourceinstanceid"],
tileid=tile_id,
parenttileid=parent_tile_id,
value=tile_value_json,
nodegroup_depth=nodegroup_depth,
source_description="{0}: {1}".format(concept_to_load["type"], nodegroup_alias), # source_description
passes_validation=passes_validation,
operation=operation,
))
tiles_to_load.append(
LoadStaging(
load_event=LoadEvent(self.loadid),
nodegroup=NodeGroup(nodegroup_id),
resourceid=concept_to_load["resourceinstanceid"],
tileid=tile_id,
parenttileid=parent_tile_id,
value=tile_value_json,
nodegroup_depth=nodegroup_depth,
source_description="{0}: {1}".format(
concept_to_load["type"], nodegroup_alias
), # source_description
passes_validation=passes_validation,
operation=operation,
)
)
staged_tiles = LoadStaging.objects.bulk_create(tiles_to_load)

cursor.execute("""CALL __arches_check_tile_cardinality_violation_for_load(%s)""", [self.loadid])

cursor.execute(
"""CALL __arches_check_tile_cardinality_violation_for_load(%s)""",
[self.loadid],
)
cursor.execute(
"""
INSERT INTO load_errors (type, source, error, loadid, nodegroupid)
Expand All @@ -127,7 +154,9 @@ def populate_staging_table(self, cursor, concepts_to_load, nodegroup_lookup, nod
[self.loadid],
)

def create_tile_value(self, cursor, mock_tile, nodegroup_alias, nodegroup_lookup, node_lookup):
def create_tile_value(
self, cursor, mock_tile, nodegroup_alias, nodegroup_lookup, node_lookup
):
tile_value = {}
tile_valid = True
for node_alias in mock_tile[nodegroup_alias].keys():
Expand All @@ -140,8 +169,10 @@ def create_tile_value(self, cursor, mock_tile, nodegroup_alias, nodegroup_lookup
config = node_details["config"]
config["loadid"] = self.loadid
config["nodeid"] = nodeid

value, validation_errors = self.prepare_data_for_loading(datatype_instance, source_value, config)

value, validation_errors = self.prepare_data_for_loading(
datatype_instance, source_value, config
)
valid = True if len(validation_errors) == 0 else False
if not valid:
tile_valid = False
Expand All @@ -150,18 +181,34 @@ def create_tile_value(self, cursor, mock_tile, nodegroup_alias, nodegroup_lookup
error_message = error["message"]
cursor.execute(
"""INSERT INTO load_errors (type, value, source, error, message, datatype, loadid, nodeid) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)""",
("node", source_value, "", error["title"], error["message"], datatype, self.loadid, nodeid),
(
"node",
source_value,
"",
error["title"],
error["message"],
datatype,
self.loadid,
nodeid,
),
)

tile_value[nodeid] = {"value": value, "valid": valid, "source": source_value, "notes": error_message, "datatype": datatype}

tile_value[nodeid] = {
"value": value,
"valid": valid,
"source": source_value,
"notes": error_message,
"datatype": datatype,
}
except KeyError:
pass
pass

return tile_value, tile_valid

def init_relationships(self, cursor, loadid):
# Create top concept of scheme relationships (derived from relations with 'hasTopConcept' relationtype)
cursor.execute("""
cursor.execute(
"""
insert into load_staging(
value,
resourceid,
Expand Down Expand Up @@ -193,10 +240,17 @@ def init_relationships(self, cursor, loadid):
'insert' as operation
from relations
where relationtype = 'hasTopConcept';
""", (CONCEPTS_TOP_CONCEPT_OF_NODEGROUP_ID, loadid, CONCEPTS_TOP_CONCEPT_OF_NODEGROUP_ID))
""",
(
CONCEPTS_TOP_CONCEPT_OF_NODEGROUP_ID,
loadid,
CONCEPTS_TOP_CONCEPT_OF_NODEGROUP_ID,
),
)

# Create broader relationships (derived from relations with 'narrower' relationtype)
cursor.execute("""
cursor.execute(
"""
insert into load_staging(
value,
resourceid,
Expand Down Expand Up @@ -228,11 +282,14 @@ def init_relationships(self, cursor, loadid):
'insert' as operation
from relations
where relationtype = 'narrower';
""", (CONCEPTS_BROADER_NODEGROUP_ID, loadid, CONCEPTS_BROADER_NODEGROUP_ID))
""",
(CONCEPTS_BROADER_NODEGROUP_ID, loadid, CONCEPTS_BROADER_NODEGROUP_ID),
)

# Create Part of Scheme relationships - derived by recursively generating concept hierarchy & associating
# concepts with their schemes
cursor.execute("""
cursor.execute(
"""
insert into load_staging(
value,
resourceid,
Expand Down Expand Up @@ -274,14 +331,28 @@ def init_relationships(self, cursor, loadid):
%s::uuid as nodegroupid,
'insert' as operation
FROM concept_hierarchy;
""", (CONCEPTS_PART_OF_SCHEME_NODEGROUP_ID, loadid, CONCEPTS_PART_OF_SCHEME_NODEGROUP_ID))
""",
(
CONCEPTS_PART_OF_SCHEME_NODEGROUP_ID,
loadid,
CONCEPTS_PART_OF_SCHEME_NODEGROUP_ID,
),
)

def start(self, request):
load_details = {"operation": "RDM to Lingo Migration"}
cursor = connection.cursor()
cursor.execute(
"""INSERT INTO load_event (loadid, complete, status, etl_module_id, load_details, load_start_time, user_id) VALUES (%s, %s, %s, %s, %s, %s, %s)""",
(self.loadid, False, "running", self.moduleid, json.dumps(load_details), datetime.now(), self.userid),
(
self.loadid,
False,
"running",
self.moduleid,
json.dumps(load_details),
datetime.now(),
self.userid,
),
)
message = "load event created"
return {"success": True, "data": message}
Expand All @@ -290,22 +361,26 @@ def write(self, request):
self.loadid = request.POST.get("loadid")
if models.Concept.objects.count() < 500:
response = self.run_load_task(self.userid, self.loadid)
else:
else:
response = self.run_load_task_async(request, self.loadid)
message = "Schemes and Concept Migration to Lingo Models Complete"
return {"success": True, "data": message}

def run_load_task(self, userid, loadid):
self.loadid = loadid # currently redundant, but be certain

with connection.cursor() as cursor:

# Gather and load schemes and concepts
schemes_nodegroup_lookup, schemes_nodes = self.get_graph_tree(SCHEMES_GRAPH_ID)
schemes_nodegroup_lookup, schemes_nodes = self.get_graph_tree(
SCHEMES_GRAPH_ID
)
schemes_node_lookup = self.get_node_lookup(schemes_nodes)
self.etl_schemes(cursor, schemes_nodegroup_lookup, schemes_node_lookup)

concepts_nodegroup_lookup, concepts_nodes = self.get_graph_tree(CONCEPTS_GRAPH_ID)
concepts_nodegroup_lookup, concepts_nodes = self.get_graph_tree(
CONCEPTS_GRAPH_ID
)
concepts_node_lookup = self.get_node_lookup(concepts_nodes)
self.etl_concepts(cursor, concepts_nodegroup_lookup, concepts_node_lookup)

Expand All @@ -320,11 +395,13 @@ def run_load_task(self, userid, loadid):
("validated", loadid),
)
response = save_to_tiles(userid, loadid)
cursor.execute("""CALL __arches_update_resource_x_resource_with_graphids();""")
cursor.execute(
"""CALL __arches_update_resource_x_resource_with_graphids();"""
)
cursor.execute("""SELECT __arches_refresh_spatial_views();""")
refresh_successful = cursor.fetchone()[0]
if not refresh_successful:
raise Exception('Unable to refresh spatial views')
raise Exception("Unable to refresh spatial views")
return response
else:
cursor.execute(
Expand Down
5 changes: 3 additions & 2 deletions arches_lingo/install/requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
livereload
sst
coverage
sauceclient
django-silk==5.1.0
django-silk==5.1.0
pre-commit
black==24.4.2
8 changes: 5 additions & 3 deletions arches_lingo/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ def add_plugins(apps, schema_editor):
componentname="reference-data-manager",
config={},
slug="reference-data-manager",
sortorder=0
sortorder=0,
)

def remove_plugin(apps, schema_editor):
Plugin = apps.get_model("models", "Plugin")

for plugin in Plugin.objects.filter(pluginid__in=["29321ce0-bd95-4357-a2a5-822e9cb06f70"]):
for plugin in Plugin.objects.filter(
pluginid__in=["29321ce0-bd95-4357-a2a5-822e9cb06f70"]
):
plugin.delete()

operations = [
migrations.RunPython(add_plugins, remove_plugin),
]
]
14 changes: 12 additions & 2 deletions arches_lingo/search_indexes/sample_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@

class SampleIndex(BaseIndex):
def prepare_index(self):
self.index_metadata = {"mappings": {"properties": {"tile_count": {"type": "keyword"}, "graph_id": {"type": "keyword"}}}}
self.index_metadata = {
"mappings": {
"properties": {
"tile_count": {"type": "keyword"},
"graph_id": {"type": "keyword"},
}
}
}
super(SampleIndex, self).prepare_index()

def get_documents_to_index(self, resourceinstance, tiles):
return ({"tile_count": len(tiles), "graph_id": resourceinstance.graph_id}, str(resourceinstance.resourceinstanceid))
return (
{"tile_count": len(tiles), "graph_id": resourceinstance.graph_id},
str(resourceinstance.resourceinstanceid),
)
2 changes: 1 addition & 1 deletion arches_lingo/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import Foo from "@/components/FooComponent.vue";

<template>
<Foo />
</template>
</template>
Loading
Loading