-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexplore_database.py
164 lines (133 loc) · 5.28 KB
/
explore_database.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Explore Database
"""
###############################################################################
import re
from datetime import datetime
from flask import Flask
from sqlalchemy.orm import class_mapper
from flask_security import Security, hash_password
# Local
from models_sqla import CustomLoginForm
from models_sqla import db, user_datastore
from models_sqla import User, Role
from models_sqla import Corpus, Chapter, Verse, Line, Analysis
from models_sqla import Lexicon, NodeLabel, RelationLabel, Node, Relation
from settings import app
from utils.database import search_node, search_relation, search_model
from utils.database import get_progress
###############################################################################
webapp = Flask(__name__)
webapp.config['SECRET_KEY'] = app.secret_key
webapp.config['SECURITY_PASSWORD_SALT'] = app.security_password_salt
webapp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
webapp.config['SQLALCHEMY_DATABASE_URI'] = app.sqla['database_uri']
webapp.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
"pool_pre_ping": True,
}
db.init_app(webapp)
security = Security(webapp, user_datastore, login_form=CustomLoginForm)
webapp.app_context().push()
###############################################################################
MODELS = {}
for model in [User, Role, Corpus, Chapter, Verse, Line, Analysis,
Lexicon, NodeLabel, RelationLabel, Node, Relation]:
name = re.sub(r'(?<!^)(?=[A-Z])', '_', model.__name__).lower()
MODELS[name] = model
###############################################################################
def model_to_dict(
obj,
max_depth: int = 1,
visited_children: set = None,
back_relationships: set = None,
):
"""SQLAlchmey objects as python `dict`
Parameters
----------
obj : SQLAlchemy model object
Similar to an instance returned by declarative_base()
max_depth : int, optional
Maximum depth for recursion on relationships.
The default is 1.
visited_children : set, optional
Set of children already visited.
The default is None.
Primary use of this attribute is for recursive calls, and a user
usually does not explicitly set this.
back_relationships : set, optional
Set of back relationships already explored.
The default is None.
Primary use of this attribute is for recursive calls, and a user
usually does not explicitly set this.
Returns
-------
dict
Python `dict` representation of the SQLAlchemy object
"""
if visited_children is None:
visited_children = set()
if back_relationships is None:
back_relationships = set()
mapper = class_mapper(obj.__class__)
columns = [column.key for column in mapper.columns]
get_key_value = (
lambda c: (c, getattr(obj, c).isoformat())
if isinstance(getattr(obj, c), datetime) else
(c, getattr(obj, c))
)
data = dict(map(get_key_value, columns))
if max_depth > 0:
for name, relation in mapper.relationships.items():
if name in back_relationships:
continue
if relation.backref:
back_relationships.add(name)
relationship_children = getattr(obj, name)
if relationship_children is not None:
if relation.uselist:
children = []
for child in (
c
for c in relationship_children
if c not in visited_children
):
visited_children.add(child)
children.append(model_to_dict(
child,
max_depth=max_depth-1,
visited_children=visited_children,
back_relationships=back_relationships
))
data[name] = children
else:
data[name] = model_to_dict(
relationship_children,
max_depth=max_depth-1,
visited_children=visited_children,
back_relationships=back_relationships
)
return data
###############################################################################
def define_getter(model_name: str):
def model_getter(model_id, as_dict=False, max_depth=1):
f'Get {model_name}'
result = MODELS.get(model_name).query.get(model_id)
if as_dict:
return model_to_dict(result, max_depth=max_depth)
return result
return model_getter
globals().update({
f'get_{model_name}': define_getter(model_name) for model_name in MODELS
})
###############################################################################
def save_progress(progress_file: str = "chapter_verse_annotation_log.csv"):
progress = get_progress()
with open(progress_file, "w", encoding="utf-8") as f:
content = [
f"{cid},{cname},{vid},{start},{end}"
for cid, cname, vid, start, end in progress["verse_annotation_log"]
]
f.write("\n".join(content))
###############################################################################