rcsb.db 1.812__py3-none-any.whl
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.
- rcsb/__init__.py +1 -0
- rcsb/db/__init__.py +1 -0
- rcsb/db/cli/ETLExec.py +180 -0
- rcsb/db/cli/RepoHoldingsEtlWorker.py +224 -0
- rcsb/db/cli/RepoLoadExec.py +323 -0
- rcsb/db/cli/RepoScanExec.py +235 -0
- rcsb/db/cli/SchemaUpdateExec.py +223 -0
- rcsb/db/cli/SequenceClustersEtlWorker.py +184 -0
- rcsb/db/cli/__init__.py +0 -0
- rcsb/db/config/exdb-config-example.yml +292 -0
- rcsb/db/define/ContentDefinition.py +741 -0
- rcsb/db/define/DataTypeApiProvider.py +110 -0
- rcsb/db/define/DataTypeApplicationInfo.py +489 -0
- rcsb/db/define/DataTypeInstanceInfo.py +125 -0
- rcsb/db/define/SchemaDefAccess.py +918 -0
- rcsb/db/define/SchemaDefAccess.py-prev +34 -0
- rcsb/db/define/SchemaDefBuild.py +1299 -0
- rcsb/db/define/__init__.py +0 -0
- rcsb/db/helpers/ContentDefinitionHelper.py +420 -0
- rcsb/db/helpers/DocumentDefinitionHelper.py +1006 -0
- rcsb/db/helpers/__init__.py +0 -0
- rcsb/db/mongo/Connection.py +116 -0
- rcsb/db/mongo/ConnectionBase.py +175 -0
- rcsb/db/mongo/DocumentLoader.py +366 -0
- rcsb/db/mongo/MongoDbUtil.py +562 -0
- rcsb/db/mongo/PdbxLoader.py +1253 -0
- rcsb/db/mongo/__init__.py +0 -0
- rcsb/db/processors/ClusterDataPrep.py +185 -0
- rcsb/db/processors/DataExchangeStatus.py +151 -0
- rcsb/db/processors/DataTransformFactory.py +468 -0
- rcsb/db/processors/RepoHoldingsDataPrep.py +711 -0
- rcsb/db/processors/RepoHoldingsRemoteDataPrep.py +174 -0
- rcsb/db/processors/SchemaDefDataPrep.py +795 -0
- rcsb/db/processors/SchemaDefReShape.py +596 -0
- rcsb/db/processors/__init__.py +0 -0
- rcsb/db/utils/CaseNormalizedDict.py +106 -0
- rcsb/db/utils/PdbxSchemaMapReader.py +299 -0
- rcsb/db/utils/ProvenanceProvider.py +106 -0
- rcsb/db/utils/SchemaProvider.py +499 -0
- rcsb/db/utils/TextUtil.py +46 -0
- rcsb/db/utils/TimeUtil.py +80 -0
- rcsb/db/utils/__init__.py +0 -0
- rcsb/db/wf/RepoLoadWorkflow.py +615 -0
- rcsb/db/wf/__init__.py +0 -0
- rcsb_db-1.812.dist-info/METADATA +541 -0
- rcsb_db-1.812.dist-info/RECORD +49 -0
- rcsb_db-1.812.dist-info/WHEEL +4 -0
- rcsb_db-1.812.dist-info/entry_points.txt +5 -0
- rcsb_db-1.812.dist-info/licenses/LICENSE +12 -0
rcsb/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
rcsb/db/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
rcsb/db/cli/ETLExec.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
##
|
|
2
|
+
# File: ETLExec.py
|
|
3
|
+
# Date: 2-Jul-2018 jdw
|
|
4
|
+
#
|
|
5
|
+
# Execution wrapper -- ETL utilities for derived and remote data sources -
|
|
6
|
+
#
|
|
7
|
+
# Updates:
|
|
8
|
+
# 15-Jul-2018 jdw add repository holdings, move all path configuration to a separate site dependent config section.
|
|
9
|
+
# 9-Dec-2018 jdw add chemical reference ETL options
|
|
10
|
+
# 4-Jan-2019 jdw differentiate config sections for provenance
|
|
11
|
+
# 9-Apr-2019 jdw add tree node list loader
|
|
12
|
+
# 25-Apr-2019 jdw move the --etl_tree_node_lists function to the rcsb.exdb package.
|
|
13
|
+
# 2-Sep-2019 jdw add cache options and move trees and chemref to module rcsb.exdb
|
|
14
|
+
#
|
|
15
|
+
##
|
|
16
|
+
__docformat__ = "restructuredtext en"
|
|
17
|
+
__author__ = "John Westbrook"
|
|
18
|
+
__email__ = "jwest@rcsb.rutgers.edu"
|
|
19
|
+
__license__ = "Apache 2.0"
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import logging
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
from rcsb.db.cli.RepoHoldingsEtlWorker import RepoHoldingsEtlWorker
|
|
27
|
+
from rcsb.db.cli.SequenceClustersEtlWorker import SequenceClustersEtlWorker
|
|
28
|
+
|
|
29
|
+
# from rcsb.db.cli.TreeNodeListWorker import TreeNodeListWorker
|
|
30
|
+
from rcsb.utils.dictionary.DictMethodResourceProvider import DictMethodResourceProvider
|
|
31
|
+
from rcsb.db.mongo.DocumentLoader import DocumentLoader
|
|
32
|
+
from rcsb.db.utils.TimeUtil import TimeUtil
|
|
33
|
+
from rcsb.utils.config.ConfigUtil import ConfigUtil
|
|
34
|
+
|
|
35
|
+
HERE = os.path.abspath(os.path.dirname(__file__))
|
|
36
|
+
TOPDIR = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
|
|
37
|
+
|
|
38
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s]-%(module)s.%(funcName)s: %(message)s")
|
|
39
|
+
logger = logging.getLogger()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def loadStatus(statusList, cfgOb, cachePath, readBackCheck=True):
|
|
43
|
+
sectionName = "data_exchange_configuration"
|
|
44
|
+
dl = DocumentLoader(cfgOb, cachePath, "MONGO_DB", numProc=2, chunkSize=2, documentLimit=None, verbose=False, readBackCheck=readBackCheck)
|
|
45
|
+
#
|
|
46
|
+
databaseName = cfgOb.get("DATABASE_NAME", sectionName=sectionName)
|
|
47
|
+
collectionName = cfgOb.get("COLLECTION_UPDATE_STATUS", sectionName=sectionName)
|
|
48
|
+
ok = dl.load(databaseName, collectionName, loadType="append", documentList=statusList, indexAttributeList=["update_id", "database_name", "object_name"], keyNames=None)
|
|
49
|
+
return ok
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def buildResourceCache(cfgOb, configName, cachePath, rebuildCache=False):
|
|
53
|
+
"""Generate and cache resource dependencies."""
|
|
54
|
+
ret = False
|
|
55
|
+
try:
|
|
56
|
+
rp = DictMethodResourceProvider(cfgOb, configName=configName, cachePath=cachePath)
|
|
57
|
+
ret = rp.cacheResources(useCache=not rebuildCache)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
logger.exception("Failing with %s", str(e))
|
|
60
|
+
return ret
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def main():
|
|
64
|
+
parser = argparse.ArgumentParser()
|
|
65
|
+
#
|
|
66
|
+
defaultConfigName = "site_info_configuration"
|
|
67
|
+
#
|
|
68
|
+
parser.add_argument("--full", default=True, action="store_true", help="Fresh full load in a new tables/collections (Default)")
|
|
69
|
+
#
|
|
70
|
+
parser.add_argument("--etl_entity_sequence_clusters", default=False, action="store_true", help="ETL entity sequence clusters")
|
|
71
|
+
parser.add_argument("--etl_repository_holdings", default=False, action="store_true", help="ETL repository holdings")
|
|
72
|
+
# parser.add_argument("--etl_chemref", default=False, action="store_true", help="ETL integrated chemical reference data")
|
|
73
|
+
# parser.add_argument("--etl_tree_node_lists", default=False, action='store_true', help="ETL tree node lists")
|
|
74
|
+
|
|
75
|
+
parser.add_argument("--data_set_id", default=None, help="Data set identifier (default= 2018_14 for current week)")
|
|
76
|
+
#
|
|
77
|
+
parser.add_argument("--sequence_cluster_data_path", default=None, help="Sequence cluster data path (default set by configuration")
|
|
78
|
+
parser.add_argument("--sandbox_data_path", default=None, help="Date exchange sandboxPath data path (default set by configuration")
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
parser.add_argument("--config_path", default=None, help="Path to configuration options file")
|
|
82
|
+
parser.add_argument("--config_name", default=defaultConfigName, help="Configuration section name")
|
|
83
|
+
|
|
84
|
+
parser.add_argument("--db_type", default="mongo", help="Database server type (default=mongo)")
|
|
85
|
+
|
|
86
|
+
# parser.add_argument("--document_style", default="rowwise_by_name_with_cardinality",
|
|
87
|
+
# help="Document organization (rowwise_by_name_with_cardinality|rowwise_by_name|columnwise_by_name|rowwise_by_id|rowwise_no_name")
|
|
88
|
+
parser.add_argument("--read_back_check", default=False, action="store_true", help="Perform read back check on all documents")
|
|
89
|
+
#
|
|
90
|
+
parser.add_argument("--num_proc", default=2, help="Number of processes to execute (default=2)")
|
|
91
|
+
parser.add_argument("--chunk_size", default=10, help="Number of files loaded per process")
|
|
92
|
+
parser.add_argument("--document_limit", default=None, help="Load document limit for testing")
|
|
93
|
+
parser.add_argument("--prune_document_size", default=None, help="Prune large documents to this size limit (MB)")
|
|
94
|
+
parser.add_argument("--debug", default=False, action="store_true", help="Turn on verbose logging")
|
|
95
|
+
parser.add_argument("--mock", default=False, action="store_true", help="Use MOCK repository configuration for testing")
|
|
96
|
+
parser.add_argument("--cache_path", default=None, help="Path containing cache directories")
|
|
97
|
+
# parser.add_argument("--use_cache", default=False, action="store_true", help="Use cache files from remote resources")
|
|
98
|
+
parser.add_argument("--rebuild_cache", default=False, action="store_true", help="Rebuild cached resource files")
|
|
99
|
+
# parser.add_argument("--rebuild_schema", default=False, action="store_true", help="Rebuild schema on-the-fly if not cached")
|
|
100
|
+
#
|
|
101
|
+
#
|
|
102
|
+
args = parser.parse_args()
|
|
103
|
+
#
|
|
104
|
+
debugFlag = args.debug
|
|
105
|
+
if debugFlag:
|
|
106
|
+
logger.setLevel(logging.DEBUG)
|
|
107
|
+
# ----------------------- - ----------------------- - ----------------------- - ----------------------- - ----------------------- -
|
|
108
|
+
# Configuration Details
|
|
109
|
+
configPath = args.config_path
|
|
110
|
+
configName = args.config_name
|
|
111
|
+
# useCache = args.use_cache
|
|
112
|
+
if not configPath:
|
|
113
|
+
configPath = os.getenv("DBLOAD_CONFIG_PATH", None)
|
|
114
|
+
try:
|
|
115
|
+
if os.access(configPath, os.R_OK):
|
|
116
|
+
os.environ["DBLOAD_CONFIG_PATH"] = configPath
|
|
117
|
+
logger.info("Using configuation path %s (%s)", configPath, configName)
|
|
118
|
+
else:
|
|
119
|
+
logger.error("Missing or access issue with config file %r", configPath)
|
|
120
|
+
exit(1)
|
|
121
|
+
mockTopPath = os.path.join(TOPDIR, "rcsb", "mock-data") if args.mock else None
|
|
122
|
+
cfgOb = ConfigUtil(configPath=configPath, defaultSectionName=defaultConfigName, mockTopPath=mockTopPath)
|
|
123
|
+
if configName != defaultConfigName:
|
|
124
|
+
cfgOb.replaceSectionName(defaultConfigName, configName)
|
|
125
|
+
#
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.error("Missing or access issue with config file %r with %s", configPath, str(e))
|
|
128
|
+
exit(1)
|
|
129
|
+
|
|
130
|
+
#
|
|
131
|
+
try:
|
|
132
|
+
readBackCheck = args.read_back_check
|
|
133
|
+
tU = TimeUtil()
|
|
134
|
+
dataSetId = args.data_set_id if args.data_set_id else tU.getCurrentWeekSignature()
|
|
135
|
+
seqDataLocator = args.sequence_cluster_data_path if args.sequence_cluster_data_path else cfgOb.getPath("RCSB_SEQUENCE_CLUSTER_DATA_PATH", sectionName=configName)
|
|
136
|
+
sandboxPath = args.sandbox_data_path if args.sandbox_data_path else cfgOb.getPath("RCSB_EXCHANGE_SANDBOX_PATH", sectionName=configName)
|
|
137
|
+
numProc = int(args.num_proc)
|
|
138
|
+
chunkSize = int(args.chunk_size)
|
|
139
|
+
documentLimit = int(args.document_limit) if args.document_limit else None
|
|
140
|
+
|
|
141
|
+
loadType = "full" if args.full else "replace"
|
|
142
|
+
# loadType = 'replace' if args.replace else 'full'
|
|
143
|
+
|
|
144
|
+
cachePath = args.cache_path if args.cache_path else "."
|
|
145
|
+
rebuildCache = args.rebuild_cache if args.rebuild_cache else False
|
|
146
|
+
# rebuildSchemaFlag = args.rebuild_schema if args.rebuild_schema else False
|
|
147
|
+
#
|
|
148
|
+
# if args.document_style not in ['rowwise_by_name', 'rowwise_by_name_with_cardinality', 'columnwise_by_name', 'rowwise_by_id', 'rowwise_no_name']:
|
|
149
|
+
# logger.error("Unsupported document style %s" % args.document_style)
|
|
150
|
+
|
|
151
|
+
if args.db_type != "mongo":
|
|
152
|
+
logger.error("Unsupported database server type %s", args.db_type)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.exception("Argument processing problem %s", str(e))
|
|
155
|
+
parser.print_help(sys.stderr)
|
|
156
|
+
exit(1)
|
|
157
|
+
# ----------------------- - ----------------------- - ----------------------- - ----------------------- - ----------------------- -
|
|
158
|
+
# Rebuild or check resource cache
|
|
159
|
+
ok = buildResourceCache(cfgOb, configName, cachePath, rebuildCache=rebuildCache)
|
|
160
|
+
if not ok:
|
|
161
|
+
logger.error("Cache rebuild or check failure (rebuild %r) %r", rebuildCache, cachePath)
|
|
162
|
+
exit(1)
|
|
163
|
+
##
|
|
164
|
+
if args.db_type == "mongo":
|
|
165
|
+
okS = True
|
|
166
|
+
if args.etl_entity_sequence_clusters:
|
|
167
|
+
cw = SequenceClustersEtlWorker(cfgOb, numProc=numProc, chunkSize=chunkSize, documentLimit=documentLimit, verbose=debugFlag, readBackCheck=readBackCheck, workPath=cachePath)
|
|
168
|
+
ok = cw.etl(dataSetId, seqDataLocator, loadType=loadType)
|
|
169
|
+
okS = loadStatus(cw.getLoadStatus(), cfgOb, cachePath, readBackCheck=readBackCheck)
|
|
170
|
+
|
|
171
|
+
if args.etl_repository_holdings:
|
|
172
|
+
rhw = RepoHoldingsEtlWorker(cfgOb, sandboxPath, cachePath, numProc=numProc, chunkSize=chunkSize, documentLimit=documentLimit, verbose=debugFlag, readBackCheck=readBackCheck)
|
|
173
|
+
ok = rhw.load(dataSetId)
|
|
174
|
+
okS = loadStatus(rhw.getLoadStatus(), cfgOb, cachePath, readBackCheck=readBackCheck)
|
|
175
|
+
|
|
176
|
+
logger.info("Operation completed with status %r " % ok and okS)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
if __name__ == "__main__":
|
|
180
|
+
main()
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
##
|
|
2
|
+
# File: RepoHoldingsEtlWorker.py
|
|
3
|
+
# Date: 2-Jul-2018 jdw
|
|
4
|
+
#
|
|
5
|
+
# ETL utilities for processing repository holding data.
|
|
6
|
+
# Updates:
|
|
7
|
+
# 15-Jul-2018 jdw split out to separate module and add status tracking
|
|
8
|
+
# 26-Nov-2018 jdw add COLLECTION_HOLDINGS_PRERELEASE
|
|
9
|
+
# 14-Dec-2019 jdw reorganize and consolidate repository_holdings collections
|
|
10
|
+
# 25-Sep-2021 jdw substitute RepoHoldingsRemoteDataPrep() for data processing
|
|
11
|
+
# 4-Apr-2023 dwp Add maxStepLength input argument; update success/failure catching logic;
|
|
12
|
+
# add final verification step to ensure all entries were loaded
|
|
13
|
+
# 16-Oct-2024 dwp Remove usage of EDMAPS holdings file
|
|
14
|
+
# 18-Feb-2025 dwp Add support for IHM repository holdings file loading;
|
|
15
|
+
# Change indexed field to be 'rcsb_id'
|
|
16
|
+
# 15-Jul-2025 dwp Adjust loader to load holdings data to DW repository_holdings collections;
|
|
17
|
+
# Turn off loading of repository_holdings_update_entry (since not used by anything downstream);
|
|
18
|
+
# Use indexes defined in py-rcsb_exdb_assets schemas and configuration
|
|
19
|
+
# 6-Aug-2025 dwp Make use of schema configuration file for loading collections and setting indexed fields
|
|
20
|
+
# 6-Oct-2025 dwp Turned OFF loading of "repository_holdings_update_entry" collection as part of transition to DW consolidation (since not used by anything)
|
|
21
|
+
#
|
|
22
|
+
##
|
|
23
|
+
__docformat__ = "restructuredtext en"
|
|
24
|
+
__author__ = "John Westbrook"
|
|
25
|
+
__email__ = "jwest@rcsb.rutgers.edu"
|
|
26
|
+
__license__ = "Apache 2.0"
|
|
27
|
+
|
|
28
|
+
import logging
|
|
29
|
+
import os
|
|
30
|
+
|
|
31
|
+
from rcsb.db.mongo.DocumentLoader import DocumentLoader
|
|
32
|
+
from rcsb.db.processors.DataExchangeStatus import DataExchangeStatus
|
|
33
|
+
from rcsb.db.processors.RepoHoldingsDataPrep import RepoHoldingsDataPrep
|
|
34
|
+
from rcsb.db.processors.RepoHoldingsRemoteDataPrep import RepoHoldingsRemoteDataPrep
|
|
35
|
+
from rcsb.db.mongo.Connection import Connection
|
|
36
|
+
from rcsb.db.mongo.MongoDbUtil import MongoDbUtil
|
|
37
|
+
from rcsb.db.utils.SchemaProvider import SchemaProvider
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RepoHoldingsEtlWorker(object):
|
|
43
|
+
"""Prepare and load repository holdings and repository update data."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, cfgOb, sandboxPath, cachePath, numProc=2, chunkSize=10, maxStepLength=4000, readBackCheck=False, documentLimit=None, verbose=False):
|
|
46
|
+
self.__cfgOb = cfgOb
|
|
47
|
+
self.__cfgSectionName = self.__cfgOb.getDefaultSectionName()
|
|
48
|
+
self.__sandboxPath = sandboxPath
|
|
49
|
+
self.__cachePath = cachePath
|
|
50
|
+
self.__readBackCheck = readBackCheck
|
|
51
|
+
self.__numProc = numProc
|
|
52
|
+
self.__chunkSize = chunkSize
|
|
53
|
+
self.__maxStepLength = maxStepLength
|
|
54
|
+
self.__documentLimit = documentLimit
|
|
55
|
+
self.__resourceName = "MONGO_DB"
|
|
56
|
+
self.__filterType = "assign-dates"
|
|
57
|
+
self.__verbose = verbose
|
|
58
|
+
self.__statusList = []
|
|
59
|
+
#
|
|
60
|
+
self.__collectionGroupName = "repository_holdings"
|
|
61
|
+
self.__schP = SchemaProvider(self.__cfgOb, self.__cachePath)
|
|
62
|
+
self.__databaseNameMongo = self.__schP.getDatabaseMongoName(collectionGroupName=self.__collectionGroupName)
|
|
63
|
+
|
|
64
|
+
def __updateStatus(self, updateId, databaseName, collectionName, status, startTimestamp):
|
|
65
|
+
try:
|
|
66
|
+
sFlag = "Y" if status else "N"
|
|
67
|
+
desp = DataExchangeStatus()
|
|
68
|
+
desp.setStartTime(tS=startTimestamp)
|
|
69
|
+
desp.setObject(databaseName, collectionName)
|
|
70
|
+
desp.setStatus(updateId=updateId, successFlag=sFlag)
|
|
71
|
+
desp.setEndTime()
|
|
72
|
+
self.__statusList.append(desp.getStatus())
|
|
73
|
+
return True
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.exception("Failing with %s", str(e))
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def load(self, updateId):
|
|
79
|
+
# First load PDB holdings (with loadType="full")
|
|
80
|
+
ok1 = self.loadRepoType(updateId, loadType="full", repoType="pdb")
|
|
81
|
+
#
|
|
82
|
+
# Next load IHM holdings (with loadType="replace")
|
|
83
|
+
ok2 = self.loadRepoType(updateId, loadType="replace", repoType="pdb_ihm")
|
|
84
|
+
#
|
|
85
|
+
# Last, verify all pdbx_core data has been loaded (based on repository holdings)
|
|
86
|
+
ok3 = self.verifyCompleteLoad()
|
|
87
|
+
logger.info("Verification of complete load status %r", ok3)
|
|
88
|
+
#
|
|
89
|
+
ok = ok1 and ok2 and ok3
|
|
90
|
+
return ok
|
|
91
|
+
|
|
92
|
+
def loadRepoType(self, updateId, loadType="full", repoType="pdb"):
|
|
93
|
+
"""Load legacy repository holdings and status data -
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
self.__statusList = []
|
|
97
|
+
desp = DataExchangeStatus()
|
|
98
|
+
statusStartTimestamp = desp.setStartTime()
|
|
99
|
+
# ---
|
|
100
|
+
discoveryMode = self.__cfgOb.get("DISCOVERY_MODE", sectionName=self.__cfgSectionName, default="local")
|
|
101
|
+
baseUrlPDB = self.__cfgOb.getPath("PDB_REPO_URL", sectionName=self.__cfgSectionName, default="https://files.wwpdb.org/pub")
|
|
102
|
+
fallbackUrlPDB = self.__cfgOb.getPath("PDB_REPO_FALLBACK_URL", sectionName=self.__cfgSectionName, default="https://files.wwpdb.org/pub")
|
|
103
|
+
# addValues = {"_schema_version": collectionVersion}
|
|
104
|
+
addValues = None
|
|
105
|
+
#
|
|
106
|
+
kwD = {
|
|
107
|
+
"repoType": repoType, # either "pdb" or "pdb_ihm"
|
|
108
|
+
"holdingsTargetUrl": os.path.join(baseUrlPDB, repoType, "holdings"),
|
|
109
|
+
"holdingsFallbackUrl": os.path.join(fallbackUrlPDB, repoType, "holdings"),
|
|
110
|
+
"updateTargetUrl": os.path.join(baseUrlPDB, repoType, "data", "status", "latest"),
|
|
111
|
+
"updateFallbackUrl": os.path.join(fallbackUrlPDB, repoType, "data", "status", "latest"),
|
|
112
|
+
"filterType": self.__filterType,
|
|
113
|
+
}
|
|
114
|
+
# ---
|
|
115
|
+
if discoveryMode == "local":
|
|
116
|
+
rhdp = RepoHoldingsDataPrep(cfgOb=self.__cfgOb, sandboxPath=self.__sandboxPath, cachePath=self.__cachePath, filterType=self.__filterType)
|
|
117
|
+
else:
|
|
118
|
+
rhdp = RepoHoldingsRemoteDataPrep(cachePath=self.__cachePath, **kwD)
|
|
119
|
+
#
|
|
120
|
+
dl = DocumentLoader(
|
|
121
|
+
self.__cfgOb,
|
|
122
|
+
self.__cachePath,
|
|
123
|
+
self.__resourceName,
|
|
124
|
+
numProc=self.__numProc,
|
|
125
|
+
chunkSize=self.__chunkSize,
|
|
126
|
+
maxStepLength=self.__maxStepLength,
|
|
127
|
+
documentLimit=self.__documentLimit,
|
|
128
|
+
verbose=self.__verbose,
|
|
129
|
+
readBackCheck=self.__readBackCheck,
|
|
130
|
+
)
|
|
131
|
+
_, _, collectionNameList, docIndexD = self.__schP.getSchemaInfo(collectionGroupName=self.__collectionGroupName, dataTyping="ANY")
|
|
132
|
+
collectionNameList = [cN for cN in collectionNameList if "_update_entry" not in cN] # Turned OFF loading "update" collection in OCT 2025 for transition to DW loading
|
|
133
|
+
# ['repository_holdings_combined_entry', 'repository_holdings_current_entry', 'repository_holdings_unreleased_entry', 'repository_holdings_removed_entry']
|
|
134
|
+
logger.info("RepoHoldings collectionNameList: %r", collectionNameList)
|
|
135
|
+
|
|
136
|
+
ok = True
|
|
137
|
+
for collectionName in collectionNameList:
|
|
138
|
+
indexDL = docIndexD[collectionName] if collectionName in docIndexD else []
|
|
139
|
+
dList = self.__getHoldingsDocList(repoType, collectionName, rhdp, updateId)
|
|
140
|
+
if dList:
|
|
141
|
+
ok = dl.load(self.__databaseNameMongo, collectionName, loadType=loadType, documentList=dList, keyNames=None, addValues=addValues, indexDL=indexDL) and ok
|
|
142
|
+
self.__updateStatus(updateId, self.__databaseNameMongo, collectionName, ok, statusStartTimestamp)
|
|
143
|
+
logger.info(
|
|
144
|
+
"Completed load of repository holdings for repoType %r, database %r, collection %r, len(dList) %r (status %r)",
|
|
145
|
+
repoType, self.__databaseNameMongo, collectionName, len(dList), ok
|
|
146
|
+
)
|
|
147
|
+
logger.info("Completed load of repository holdings for repoType %r, loadType %r (status %r)", repoType, loadType, ok)
|
|
148
|
+
return ok
|
|
149
|
+
except Exception as e:
|
|
150
|
+
logger.exception("Failing with %s", str(e))
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
def getLoadStatus(self):
|
|
154
|
+
return self.__statusList
|
|
155
|
+
|
|
156
|
+
def verifyCompleteLoad(self):
|
|
157
|
+
"""
|
|
158
|
+
Compare the document counts of the pdbx_core and repository holdings collections.
|
|
159
|
+
"""
|
|
160
|
+
ok = True
|
|
161
|
+
|
|
162
|
+
pdbxCoreEntryL = self.__getUniqueLoadedRcsbIds("pdbx_core", "pdbx_core_entry")
|
|
163
|
+
|
|
164
|
+
repoHoldingsCurrentEntryL = self.__getUniqueLoadedRcsbIds(self.__databaseNameMongo, "repository_holdings_current_entry")
|
|
165
|
+
repoHoldingsCombinedEntryL = self.__getUniqueLoadedRcsbIds(self.__databaseNameMongo, "repository_holdings_combined_entry")
|
|
166
|
+
repoHoldingsRemovedEntryL = self.__getUniqueLoadedRcsbIds(self.__databaseNameMongo, "repository_holdings_removed_entry")
|
|
167
|
+
repoHoldingsUnreleasedEntryL = self.__getUniqueLoadedRcsbIds(self.__databaseNameMongo, "repository_holdings_unreleased_entry")
|
|
168
|
+
|
|
169
|
+
combinedHoldingsExpectedCount = len(repoHoldingsCurrentEntryL) + len(repoHoldingsRemovedEntryL) + len(repoHoldingsUnreleasedEntryL)
|
|
170
|
+
|
|
171
|
+
if len(pdbxCoreEntryL) != len(repoHoldingsCurrentEntryL):
|
|
172
|
+
logger.error(
|
|
173
|
+
"The total entries in the collections of core entry (%d) and current repository holdings (%d) differ.",
|
|
174
|
+
len(pdbxCoreEntryL),
|
|
175
|
+
len(repoHoldingsCurrentEntryL)
|
|
176
|
+
)
|
|
177
|
+
delta = list(set(pdbxCoreEntryL) ^ set(repoHoldingsCurrentEntryL))
|
|
178
|
+
logger.error("List delta is of length %r", len(delta))
|
|
179
|
+
if len(delta) > 0 and len(delta) < 10000:
|
|
180
|
+
logger.error("Delta entry ID list: %r", delta)
|
|
181
|
+
ok = False
|
|
182
|
+
if len(repoHoldingsCombinedEntryL) != combinedHoldingsExpectedCount:
|
|
183
|
+
logger.error(
|
|
184
|
+
"The total entries in repoHoldingsCombinedEntryL (%d) and combinedHoldingsExpectedCount (%d) differ.",
|
|
185
|
+
len(repoHoldingsCombinedEntryL),
|
|
186
|
+
combinedHoldingsExpectedCount
|
|
187
|
+
)
|
|
188
|
+
ok = False
|
|
189
|
+
|
|
190
|
+
if not ok:
|
|
191
|
+
raise ValueError("Data Errors found in ExchangeDB loading")
|
|
192
|
+
|
|
193
|
+
return ok
|
|
194
|
+
|
|
195
|
+
def __getUniqueLoadedRcsbIds(self, databaseName, collectionName):
|
|
196
|
+
"""Get the list of unique loaded 'rcsb_id' values in the given database and collection"""
|
|
197
|
+
loadedRcsbIdL = []
|
|
198
|
+
try:
|
|
199
|
+
#
|
|
200
|
+
with Connection(cfgOb=self.__cfgOb, resourceName=self.__resourceName) as client:
|
|
201
|
+
mg = MongoDbUtil(client)
|
|
202
|
+
selectL = ["rcsb_id"]
|
|
203
|
+
queryD = {}
|
|
204
|
+
loadedDocL = mg.fetch(databaseName, collectionName, selectL, queryD=queryD, suppressId=True)
|
|
205
|
+
loadedRcsbIdL = [docD["rcsb_id"] for docD in loadedDocL]
|
|
206
|
+
loadedRcsbIdL = list(set(loadedRcsbIdL))
|
|
207
|
+
logger.info("Number of entries loaded to database %s collection %s: %r", databaseName, collectionName, len(loadedRcsbIdL))
|
|
208
|
+
except Exception as e:
|
|
209
|
+
logger.exception("Failing with %s", str(e))
|
|
210
|
+
return loadedRcsbIdL
|
|
211
|
+
|
|
212
|
+
def __getHoldingsDocList(self, repoType, holdingsCollectionName, repoHoldingsDataPrep, updateId):
|
|
213
|
+
dList = []
|
|
214
|
+
if "_current_" in holdingsCollectionName.lower():
|
|
215
|
+
dList = repoHoldingsDataPrep.getHoldingsCurrentEntry(updateId=updateId)
|
|
216
|
+
elif "_unreleased_" in holdingsCollectionName.lower():
|
|
217
|
+
dList = repoHoldingsDataPrep.getHoldingsUnreleasedEntry(updateId=updateId)
|
|
218
|
+
elif "_combined_" in holdingsCollectionName.lower():
|
|
219
|
+
dList = repoHoldingsDataPrep.getHoldingsCombinedEntry(updateId=updateId)
|
|
220
|
+
elif repoType != "pdb_ihm" and "_removed_" in holdingsCollectionName.lower():
|
|
221
|
+
dList = repoHoldingsDataPrep.getHoldingsRemovedEntry(updateId=updateId)
|
|
222
|
+
# elif repoType != "pdb_ihm" and "_update_" in holdingsCollectionName.lower(): # TURNED OFF 15-JUL-2025 for transition to DW loading (since not used by anything)
|
|
223
|
+
# dList = repoHoldingsDataPrep.getHoldingsUpdateEntry(updateId=updateId)
|
|
224
|
+
return dList
|