educelab-hercdb 0.1.0.dev1__tar.gz
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.
- educelab_hercdb-0.1.0.dev1/PKG-INFO +22 -0
- educelab_hercdb-0.1.0.dev1/README.md +3 -0
- educelab_hercdb-0.1.0.dev1/pyproject.toml +39 -0
- educelab_hercdb-0.1.0.dev1/setup.cfg +4 -0
- educelab_hercdb-0.1.0.dev1/src/educelab/hercdb/__init__.py +6 -0
- educelab_hercdb-0.1.0.dev1/src/educelab/hercdb/api.py +232 -0
- educelab_hercdb-0.1.0.dev1/src/educelab/hercdb/config.py +63 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/PKG-INFO +22 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/SOURCES.txt +11 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/dependency_links.txt +1 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/entry_points.txt +2 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/requires.txt +4 -0
- educelab_hercdb-0.1.0.dev1/src/educelab_hercdb.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: educelab-hercdb
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: Graph database API for Herculaneum data
|
|
5
|
+
Author-email: Mami Hayashida <mami.hayashida@uky.edu>, Seth Parker <c.seth.parker@uky.edu>
|
|
6
|
+
Project-URL: Repository, https://gitlab.com/educelab/herculaneum-graph-db
|
|
7
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: neo4j>=5.20
|
|
16
|
+
Requires-Dist: numpy>=2.0
|
|
17
|
+
Requires-Dist: pandas>=2.2
|
|
18
|
+
Requires-Dist: prompt-toolkit
|
|
19
|
+
|
|
20
|
+
# Herculaneum Graph Database Project
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 62"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools.packages.find]
|
|
6
|
+
where = ["src/"]
|
|
7
|
+
include = ["educelab.hercdb"]
|
|
8
|
+
|
|
9
|
+
[project]
|
|
10
|
+
name = "educelab-hercdb"
|
|
11
|
+
version = "0.1.0.dev1"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"neo4j>=5.20",
|
|
14
|
+
"numpy>=2.0",
|
|
15
|
+
"pandas>=2.2",
|
|
16
|
+
"prompt-toolkit"
|
|
17
|
+
]
|
|
18
|
+
requires-python = ">= 3.10"
|
|
19
|
+
authors = [
|
|
20
|
+
{name = "Mami Hayashida", email = "mami.hayashida@uky.edu"},
|
|
21
|
+
{name = "Seth Parker", email = "c.seth.parker@uky.edu"}
|
|
22
|
+
]
|
|
23
|
+
description = "Graph database API for Herculaneum data"
|
|
24
|
+
readme = "README.md"
|
|
25
|
+
classifiers = [
|
|
26
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Repository = "https://gitlab.com/educelab/herculaneum-graph-db"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
el-hercdb-search = "educelab.hercdb.apps.search:main"
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
from neo4j import GraphDatabase
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DatasetType(Enum):
|
|
9
|
+
FlatbedScan = 'FlatbedScanDataset'
|
|
10
|
+
PGSRaw = 'PGSRaw'
|
|
11
|
+
SpectralRaw = 'SpectralRaw'
|
|
12
|
+
|
|
13
|
+
def __str__(self):
|
|
14
|
+
return f'{self.value}'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
FlatbedScanType = DatasetType.FlatbedScan
|
|
18
|
+
PGSRawType = DatasetType.PGSRaw
|
|
19
|
+
SpectralRawType = DatasetType.SpectralRaw
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _GraphConnector:
|
|
23
|
+
logger = logging.getLogger('hercdb.connector')
|
|
24
|
+
uri: str = None
|
|
25
|
+
user: str = None
|
|
26
|
+
|
|
27
|
+
def __init__(self, uri, user, password):
|
|
28
|
+
self.uri = uri
|
|
29
|
+
self.user = user
|
|
30
|
+
self.driver = GraphDatabase.driver(uri, auth=(user, password))
|
|
31
|
+
|
|
32
|
+
def __del__(self):
|
|
33
|
+
self.close()
|
|
34
|
+
|
|
35
|
+
def close(self):
|
|
36
|
+
self.driver.close()
|
|
37
|
+
|
|
38
|
+
def verify_conn(self):
|
|
39
|
+
self.driver.verify_connectivity()
|
|
40
|
+
self.logger.info(f"connected to {self.uri} as '{self.user}'")
|
|
41
|
+
|
|
42
|
+
def delete_all(self):
|
|
43
|
+
records, summary, keys = self.driver.execute_query(
|
|
44
|
+
"""
|
|
45
|
+
MATCH (n)
|
|
46
|
+
DETACH DELETE n
|
|
47
|
+
""",
|
|
48
|
+
database_="neo4j",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def return_all(self):
|
|
52
|
+
records, summary, keys = self.driver.execute_query(
|
|
53
|
+
"""
|
|
54
|
+
MATCH (n)
|
|
55
|
+
RETURN n
|
|
56
|
+
""",
|
|
57
|
+
database_="neo4j",
|
|
58
|
+
)
|
|
59
|
+
self.logger.debug(records)
|
|
60
|
+
self.logger.debug(summary)
|
|
61
|
+
self.logger.debug(keys)
|
|
62
|
+
|
|
63
|
+
def node_count(self) -> int:
|
|
64
|
+
record, keys, summary = self.driver.execute_query(
|
|
65
|
+
"""
|
|
66
|
+
MATCH (n)
|
|
67
|
+
RETURN count(n)
|
|
68
|
+
""",
|
|
69
|
+
database_="neo4j",
|
|
70
|
+
)
|
|
71
|
+
count = record[0]
|
|
72
|
+
assert isinstance(count, int)
|
|
73
|
+
return count
|
|
74
|
+
|
|
75
|
+
def get_human_readable_name(self, pherc, cornice=None, pezzo=None):
|
|
76
|
+
|
|
77
|
+
pherc_n = None
|
|
78
|
+
corn_n = None
|
|
79
|
+
pezzo_n = None
|
|
80
|
+
|
|
81
|
+
if cornice:
|
|
82
|
+
records, summary, keys = self.driver.execute_query(
|
|
83
|
+
"""
|
|
84
|
+
MATCH (ph:PHerc {name: $ph})-[:HAS]->(cr:Cornice {name: $cor})
|
|
85
|
+
RETURN ph.human_name, cr.human_name
|
|
86
|
+
""", ph=pherc, cor=cornice,
|
|
87
|
+
database_="neo4j",
|
|
88
|
+
)
|
|
89
|
+
if records:
|
|
90
|
+
pherc_n = records[0]["ph.human_name"]
|
|
91
|
+
corn_n = records[0]["c.human_name"]
|
|
92
|
+
|
|
93
|
+
if pezzo:
|
|
94
|
+
# Currently this is irrelevant since there are no pezzo with "names"
|
|
95
|
+
records, summary, keys = self.driver.execute_query(
|
|
96
|
+
"""
|
|
97
|
+
MATCH (ph:PHerc {name: $ph})-[:HAS]->(:Cornice)
|
|
98
|
+
-[:HAS]->(pz:Pezzo {name: $pz})
|
|
99
|
+
RETURN ph.human_name, pz.human_name
|
|
100
|
+
""", ph=pherc, pz=pezzo,
|
|
101
|
+
database_="neo4j",
|
|
102
|
+
)
|
|
103
|
+
if records:
|
|
104
|
+
pherc_n = records[0]["ph.human_name"]
|
|
105
|
+
pezzo_n = records[0]["pz.human_name"]
|
|
106
|
+
|
|
107
|
+
if not pherc_n:
|
|
108
|
+
# If there was neither cornice nor pezzo names given
|
|
109
|
+
records, summary, keys = self.driver.execute_query(
|
|
110
|
+
"""
|
|
111
|
+
MATCH (ph:PHerc {name: $ph})
|
|
112
|
+
RETURN ph.human_name
|
|
113
|
+
""", ph=pherc,
|
|
114
|
+
database_="neo4j",
|
|
115
|
+
)
|
|
116
|
+
if records:
|
|
117
|
+
pherc_n = records[0]["ph.human_name"]
|
|
118
|
+
|
|
119
|
+
return pherc_n, corn_n, pezzo_n
|
|
120
|
+
|
|
121
|
+
def list_cornici_pezzi(self, pherc):
|
|
122
|
+
# Use display names
|
|
123
|
+
records, summary, keys = self.driver.execute_query(
|
|
124
|
+
"""
|
|
125
|
+
MATCH (ph:PHerc {human_name: $ph})
|
|
126
|
+
OPTIONAL MATCH (ph)-[:HAS]-(cr:Cornice)
|
|
127
|
+
OPTIONAL MATCH (cr)-[:HAS]-(pz:Pezzo)
|
|
128
|
+
RETURN ph, cr, pz
|
|
129
|
+
""", ph=pherc,
|
|
130
|
+
database_="neo4j",
|
|
131
|
+
)
|
|
132
|
+
return records
|
|
133
|
+
|
|
134
|
+
def find_datasets(self, ds_type: DatasetType, pherc, cornice=None,
|
|
135
|
+
pezzo=None):
|
|
136
|
+
# Use display names
|
|
137
|
+
if cornice:
|
|
138
|
+
records, summary, keys = self.driver.execute_query(
|
|
139
|
+
"""
|
|
140
|
+
MATCH (ph:PHerc {name: $ph})-[:HAS]-(cr:Cornice {name: $cor})
|
|
141
|
+
MATCH (cr)<-[:ASSIGNED_TO]-(e:EduceLabID)
|
|
142
|
+
MATCH (e)<-[:BELONGS_TO]-(n)
|
|
143
|
+
WHERE $data_t IN LABELS(n)
|
|
144
|
+
RETURN n
|
|
145
|
+
""", data_t=str(ds_type), ph=pherc, cor=cornice,
|
|
146
|
+
database_="neo4j",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
else:
|
|
150
|
+
# Pezzo
|
|
151
|
+
records, summary, keys = self.driver.execute_query(
|
|
152
|
+
"""
|
|
153
|
+
MATCH (ph:PHerc {name: $ph})-[:HAS]->(:Cornice)
|
|
154
|
+
-[:HAS]->(pz:Pezzo {human_name: $pz})
|
|
155
|
+
MATCH (pz)<-[:ASSIGNED_TO]-(e:EduceLabID)
|
|
156
|
+
MATCH (e)<-[:BELONGS_TO]-(n)
|
|
157
|
+
WHERE $data_t IN LABELS(n)
|
|
158
|
+
RETURN n
|
|
159
|
+
""", data_t=str(ds_type), ph=pherc, pz=pezzo,
|
|
160
|
+
database_="neo4j",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
properties = []
|
|
164
|
+
for record in records:
|
|
165
|
+
dataset = record[0]
|
|
166
|
+
properties.append(dict(dataset))
|
|
167
|
+
|
|
168
|
+
return properties
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Server connector instance
|
|
172
|
+
_connector: Optional[_GraphConnector] = None
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def connect(uri=None, user=None, password=None) -> bool:
|
|
176
|
+
# use system config values if not provided
|
|
177
|
+
from educelab.hercdb import config
|
|
178
|
+
if uri is None:
|
|
179
|
+
uri = config.uri
|
|
180
|
+
if user is None:
|
|
181
|
+
user = config.username
|
|
182
|
+
if password is None:
|
|
183
|
+
password = config.password
|
|
184
|
+
|
|
185
|
+
# close existing connection
|
|
186
|
+
global _connector
|
|
187
|
+
if _connector is not None:
|
|
188
|
+
disconnect()
|
|
189
|
+
|
|
190
|
+
# open new connection
|
|
191
|
+
_connector = _GraphConnector(uri, user, password)
|
|
192
|
+
return verify_connection()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def disconnect():
|
|
196
|
+
global _connector
|
|
197
|
+
if _connector is not None:
|
|
198
|
+
_connector.close()
|
|
199
|
+
_connector = None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def verify_connection() -> bool:
|
|
203
|
+
if _connector is None:
|
|
204
|
+
return False
|
|
205
|
+
try:
|
|
206
|
+
_connector.verify_conn()
|
|
207
|
+
return True
|
|
208
|
+
except Exception as e:
|
|
209
|
+
logging.getLogger(__name__).debug('failed to connect', exc_info=e)
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def node_count() -> int:
|
|
214
|
+
if _connector is None:
|
|
215
|
+
return -1
|
|
216
|
+
else:
|
|
217
|
+
return _connector.node_count()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_display_name(*args, **kwargs):
|
|
221
|
+
if _connector is not None:
|
|
222
|
+
return _connector.get_human_readable_name(*args, **kwargs)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def list_cornici_pezzi(*args, **kwargs):
|
|
226
|
+
if _connector is not None:
|
|
227
|
+
return _connector.list_cornici_pezzi(*args, **kwargs)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def find_datasets(*args, **kwargs):
|
|
231
|
+
if _connector is not None:
|
|
232
|
+
return _connector.find_datasets(*args, **kwargs)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from prompt_toolkit import prompt
|
|
7
|
+
from getpass import getpass, GetPassWarning
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@lru_cache(maxsize=2)
|
|
11
|
+
def _load_config():
|
|
12
|
+
"""Load ~/.educedb as a dictionary."""
|
|
13
|
+
cfg_path = Path.home() / '.educedb'
|
|
14
|
+
if not cfg_path.exists():
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
with cfg_path.open() as f:
|
|
18
|
+
cfg = json.load(f)
|
|
19
|
+
|
|
20
|
+
return cfg
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _get_cfg_val(env_key, config_key):
|
|
24
|
+
"""Return a config value from the environment or config file."""
|
|
25
|
+
# Prefer env val
|
|
26
|
+
val = os.getenv(env_key, None)
|
|
27
|
+
if val is not None:
|
|
28
|
+
return val
|
|
29
|
+
|
|
30
|
+
# Load config
|
|
31
|
+
cfg = _load_config()
|
|
32
|
+
if cfg is None:
|
|
33
|
+
_load_config.cache_clear()
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
return cfg.get(config_key, None)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __getattr__(name):
|
|
40
|
+
"""Stub to avoid attribute errors on this module"""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Default properties #
|
|
45
|
+
uri = _get_cfg_val('EDUCEDB_URI', 'uri')
|
|
46
|
+
username = _get_cfg_val('EDUCEDB_USER', 'username')
|
|
47
|
+
password = _get_cfg_val('EDUCEDB_PASSWORD', 'password')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def request_required():
|
|
51
|
+
"""Prompt the user to provide required configuration information."""
|
|
52
|
+
global uri, username, password
|
|
53
|
+
if uri is None:
|
|
54
|
+
uri = prompt('Enter URI: ')
|
|
55
|
+
|
|
56
|
+
if username is None:
|
|
57
|
+
username = prompt('Enter username: ')
|
|
58
|
+
|
|
59
|
+
if password is None:
|
|
60
|
+
try:
|
|
61
|
+
password = getpass('Enter password: ')
|
|
62
|
+
except GetPassWarning:
|
|
63
|
+
pass
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: educelab-hercdb
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: Graph database API for Herculaneum data
|
|
5
|
+
Author-email: Mami Hayashida <mami.hayashida@uky.edu>, Seth Parker <c.seth.parker@uky.edu>
|
|
6
|
+
Project-URL: Repository, https://gitlab.com/educelab/herculaneum-graph-db
|
|
7
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: neo4j>=5.20
|
|
16
|
+
Requires-Dist: numpy>=2.0
|
|
17
|
+
Requires-Dist: pandas>=2.2
|
|
18
|
+
Requires-Dist: prompt-toolkit
|
|
19
|
+
|
|
20
|
+
# Herculaneum Graph Database Project
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/educelab/hercdb/__init__.py
|
|
4
|
+
src/educelab/hercdb/api.py
|
|
5
|
+
src/educelab/hercdb/config.py
|
|
6
|
+
src/educelab_hercdb.egg-info/PKG-INFO
|
|
7
|
+
src/educelab_hercdb.egg-info/SOURCES.txt
|
|
8
|
+
src/educelab_hercdb.egg-info/dependency_links.txt
|
|
9
|
+
src/educelab_hercdb.egg-info/entry_points.txt
|
|
10
|
+
src/educelab_hercdb.egg-info/requires.txt
|
|
11
|
+
src/educelab_hercdb.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
educelab
|