1
+ import contextlib
1
2
import functools
2
3
import hashlib
3
4
import logging
@@ -76,12 +77,6 @@ class UploadState(str, Enum):
76
77
CANCELED = "CANCELED"
77
78
78
79
79
- class Level (str , Enum ):
80
- INFO = "INFO"
81
- WARNING = "WARNING"
82
- FATAL = "FATAL"
83
-
84
-
85
80
@dataclass
86
81
class MetadataObject :
87
82
"""Data structure to store freshly created model instances.
@@ -121,10 +116,12 @@ class ProcessedObject:
121
116
@dataclass
122
117
class UploadReportEntry :
123
118
message : str
124
- level : Level | None = None
119
+ level : int | None = None
125
120
126
121
def __str__ (self ):
127
- return ": " .join ([k for k in (self .level , self .message ) if k ])
122
+ if self .level is None :
123
+ return self .message
124
+ return f"{ logging .getLevelName (self .level )} : { self .message } "
128
125
129
126
130
127
@dataclass
@@ -137,18 +134,12 @@ class UploadReport:
137
134
def __post_init__ (self ) -> None :
138
135
self .task_id = f"task { self .task .request .id } : " if self .task else ""
139
136
140
- def log (self , level : Level , message : str ) -> None :
137
+ def log (self , level : int , message : str ) -> None :
141
138
msg = f"{ self .task_id } { message } "
142
- if level == Level . FATAL :
139
+ if level == logging . ERROR :
143
140
self .failed = True
144
141
self .upload_state = UploadState .REPORTING
145
- logger .error (msg )
146
- elif level == Level .WARNING :
147
- logger .warning (msg )
148
- else :
149
- # must be info
150
- logger .info (msg )
151
-
142
+ logger .log (level , msg )
152
143
self .stack .append (UploadReportEntry (level = level , message = message ))
153
144
self ._update_task (self .json ())
154
145
@@ -169,17 +160,14 @@ def json(self):
169
160
def _update_task (self , message : str | list ) -> None :
170
161
if not self .task :
171
162
return
172
- try :
163
+ with contextlib . suppress ( AttributeError ) :
173
164
logger .debug ("taskstuff %s" , dir (self .task ))
174
165
self .task .update_state (
175
166
state = self .upload_state ,
176
167
meta = {
177
168
"description" : message ,
178
169
},
179
170
)
180
- except AttributeError :
181
- # no task passed to method, nothing to do
182
- pass
183
171
184
172
185
173
def _validate_bundle_against_mode (config_yaml : Dict [str , Any ]) -> Optional [str ]:
@@ -343,14 +331,14 @@ def wrapper_create_objects(
343
331
instance_data .key ,
344
332
instance_data .fields ,
345
333
)
346
- self .report .log (Level . FATAL , msg )
334
+ self .report .log (logging . ERROR , msg )
347
335
failed = failed + 1
348
336
except IntegrityError :
349
337
msg = "{} object {} failed to save" .format (
350
338
instance_data .model_class ._meta .object_name , # pylint: disable=protected-access
351
339
instance_data .key ,
352
340
)
353
- self .report .log (Level . FATAL , msg )
341
+ self .report .log (logging . ERROR , msg )
354
342
failed = failed + 1
355
343
356
344
if not obj :
@@ -377,7 +365,7 @@ def wrapper_create_objects(
377
365
created ,
378
366
existing ,
379
367
) # pylint: disable=protected-access
380
- self .report .log (Level .INFO , msg )
368
+ self .report .log (logging .INFO , msg )
381
369
382
370
return result
383
371
@@ -455,7 +443,7 @@ def __init__(
455
443
# Initial (reassuring message)
456
444
bundle_filename = os .path .basename (self .bundle_path )
457
445
self .report .log (
458
- Level .INFO ,
446
+ logging .INFO ,
459
447
f"Created TargetLoader for '{ bundle_filename } ' proposal_ref='{ proposal_ref } '" ,
460
448
)
461
449
@@ -480,7 +468,7 @@ def validate_map_files(
480
468
"""
481
469
482
470
def logfunc (_ , message ):
483
- self .report .log (Level .WARNING , message )
471
+ self .report .log (logging .WARNING , message )
484
472
485
473
result = []
486
474
for item in file_struct :
@@ -531,9 +519,9 @@ def validate_files(
531
519
532
520
def logfunc (key , message ):
533
521
if key in required :
534
- self .report .log (Level . FATAL , message )
522
+ self .report .log (logging . ERROR , message )
535
523
else :
536
- self .report .log (Level .WARNING , message )
524
+ self .report .log (logging .WARNING , message )
537
525
538
526
result = {}
539
527
for key , value in file_struct .items ():
@@ -598,16 +586,13 @@ def _check_file(
598
586
key : str ,
599
587
logfunc : Callable ,
600
588
) -> Tuple [str | None , str | None ]:
601
- file_hash = value .get ("sha256" , None )
589
+ file_hash = value .get ("sha256" )
602
590
try :
603
591
filename = value ["file" ]
604
592
except KeyError :
605
593
# this is rather unexpected, haven't seen it yet
606
594
filename = None
607
- logfunc (
608
- key ,
609
- "{}: malformed dict, key 'file' missing" .format (obj_identifier ),
610
- )
595
+ logfunc (key , f"{ obj_identifier } : malformed dict, key 'file' missing" )
611
596
return filename , file_hash
612
597
613
598
def _check_file_hash (
@@ -621,15 +606,11 @@ def _check_file_hash(
621
606
file_path = self .raw_data .joinpath (filename )
622
607
if file_path .is_file ():
623
608
if file_hash and file_hash != calculate_sha256 (file_path ):
624
- logfunc (key , "Invalid hash for file {}" . format ( filename ) )
609
+ logfunc (key , f "Invalid hash for file { filename } " )
625
610
else :
626
611
logfunc (
627
612
key ,
628
- "{} referenced in {}: {} but not found in archive" .format (
629
- key ,
630
- METADATA_FILE ,
631
- obj_identifier ,
632
- ),
613
+ f"{ key } referenced in { METADATA_FILE } : { obj_identifier } but not found in archive" ,
633
614
)
634
615
635
616
@create_objects (depth = 1 )
@@ -714,7 +695,8 @@ def process_experiment(
714
695
else :
715
696
exp_type = - 1
716
697
self .report .log (
717
- Level .FATAL , f"Unexpected 'type' '{ dtype } ' value for { experiment_name } "
698
+ logging .ERROR ,
699
+ f"Unexpected 'type' '{ dtype } ' value for { experiment_name } " ,
718
700
)
719
701
720
702
dstatus = extract (key = "status" )
@@ -731,7 +713,7 @@ def process_experiment(
731
713
except KeyError :
732
714
status = - 1
733
715
self .report .log (
734
- Level . FATAL , f"Unexpected status '{ dstatus } ' for { experiment_name } "
716
+ logging . ERROR , f"Unexpected status '{ dstatus } ' for { experiment_name } "
735
717
)
736
718
737
719
# TODO: unhandled atm
@@ -811,10 +793,8 @@ def process_compound(
811
793
else "ligand_cif"
812
794
)
813
795
self .report .log (
814
- Level .WARNING ,
815
- "{} missing from {} in '{}' experiment section" .format (
816
- exc , smiles , protein_name
817
- ),
796
+ logging .WARNING ,
797
+ f"{ exc } missing from { smiles } in '{ protein_name } ' experiment section" ,
818
798
)
819
799
return None
820
800
@@ -907,7 +887,7 @@ def process_quat_assembly(
907
887
item_name = assembly_name ,
908
888
)
909
889
910
- chains = extract (key = "chains" , level = Level .WARNING )
890
+ chains = extract (key = "chains" , level = logging .WARNING )
911
891
912
892
fields = {
913
893
"name" : assembly_name ,
@@ -1180,7 +1160,7 @@ def process_site_observation(
1180
1160
data = data ,
1181
1161
section_name = "crystals" ,
1182
1162
item_name = experiment_id ,
1183
- level = Level .WARNING ,
1163
+ level = logging .WARNING ,
1184
1164
)
1185
1165
1186
1166
experiment = experiments [experiment_id ].instance
@@ -1228,18 +1208,13 @@ def process_site_observation(
1228
1208
logger .debug ('looking for ligand_mol: %s' , ligand_mol )
1229
1209
mol_data = None
1230
1210
if ligand_mol :
1231
- try :
1211
+ with contextlib . suppress ( TypeError , FileNotFoundError ) :
1232
1212
with open (
1233
1213
self .raw_data .joinpath (ligand_mol ),
1234
1214
"r" ,
1235
1215
encoding = "utf-8" ,
1236
1216
) as f :
1237
1217
mol_data = f .read ()
1238
- except (TypeError , FileNotFoundError ):
1239
- # this site observation doesn't have a ligand. perfectly
1240
- # legitimate case
1241
- pass
1242
-
1243
1218
smiles = extract (key = "ligand_smiles" )
1244
1219
1245
1220
fields = {
@@ -1287,19 +1262,15 @@ def process_bundle(self):
1287
1262
upload_dir = next (up_iter )
1288
1263
except StopIteration as exc :
1289
1264
msg = "Upload directory missing from uploaded file"
1290
- self .report .log (Level . FATAL , msg )
1265
+ self .report .log (logging . ERROR , msg )
1291
1266
# what do you mean unused?!
1292
1267
raise StopIteration (
1293
1268
msg
1294
1269
) from exc # pylint: disable=# pylint: disable=protected-access
1295
1270
1296
- try :
1271
+ with contextlib . suppress ( StopIteration ) :
1297
1272
upload_dir = next (up_iter )
1298
- self .report .log (Level .WARNING , "Multiple upload directories in archive" )
1299
- except StopIteration :
1300
- # just a warning, ignoring the second one
1301
- pass
1302
-
1273
+ self .report .log (logging .WARNING , "Multiple upload directories in archive" )
1303
1274
# now that target name is not included in path, I don't need
1304
1275
# it here, need it just before creating target object. Also,
1305
1276
# there's probably no need to throw a fatal here, I can
@@ -1309,7 +1280,7 @@ def process_bundle(self):
1309
1280
config_file = next (config_it )
1310
1281
except StopIteration as exc :
1311
1282
msg = f"config file missing from { str (upload_dir )} "
1312
- self .report .log (Level . FATAL , msg )
1283
+ self .report .log (logging . ERROR , msg )
1313
1284
raise StopIteration () from exc
1314
1285
1315
1286
# load necessary files
@@ -1325,15 +1296,15 @@ def process_bundle(self):
1325
1296
# Validate the upload's XCA version information against any MODE-based conditions.
1326
1297
# An error message is returned if the bundle is not supported.
1327
1298
if vb_err_msg := _validate_bundle_against_mode (config ):
1328
- self .report .log (Level . FATAL , vb_err_msg )
1299
+ self .report .log (logging . ERROR , vb_err_msg )
1329
1300
raise AssertionError (vb_err_msg )
1330
1301
1331
1302
# Target (very least) is required
1332
1303
try :
1333
1304
self .target_name = config ["target_name" ]
1334
1305
except KeyError as exc :
1335
1306
msg = "target_name missing in config file"
1336
- self .report .log (Level . FATAL , msg )
1307
+ self .report .log (logging . ERROR , msg )
1337
1308
raise KeyError (msg ) from exc
1338
1309
1339
1310
# moved this bit from init
@@ -1358,7 +1329,7 @@ def process_bundle(self):
1358
1329
# remove uploaded file
1359
1330
Path (self .bundle_path ).unlink ()
1360
1331
msg = f"{ self .bundle_name } already uploaded"
1361
- self .report .log (Level . FATAL , msg )
1332
+ self .report .log (logging . ERROR , msg )
1362
1333
raise FileExistsError (msg )
1363
1334
1364
1335
if project_created and committer .pk == settings .ANONYMOUS_USER :
@@ -1543,7 +1514,7 @@ def _load_yaml(self, yaml_file: Path) -> dict | None:
1543
1514
contents = yaml .safe_load (file )
1544
1515
except FileNotFoundError :
1545
1516
self .report .log (
1546
- Level . FATAL , f"File { yaml_file .name } not found in data archive"
1517
+ logging . ERROR , f"File { yaml_file .name } not found in data archive"
1547
1518
)
1548
1519
1549
1520
return contents
@@ -1558,7 +1529,7 @@ def _get_yaml_blocks(self, yaml_data: dict, blocks: Iterable) -> list[dict]:
1558
1529
result .append (yaml_data [block ])
1559
1530
except KeyError :
1560
1531
msg = error_text .format (block )
1561
- self .report .log (Level . FATAL , msg )
1532
+ self .report .log (logging . ERROR , msg )
1562
1533
1563
1534
return result
1564
1535
@@ -1568,26 +1539,18 @@ def _extract(
1568
1539
key : str | int ,
1569
1540
section_name : str ,
1570
1541
item_name : str ,
1571
- level : Level = Level . FATAL ,
1542
+ level : int = logging . ERROR ,
1572
1543
return_type : type = str ,
1573
1544
) -> Any :
1574
1545
try :
1575
1546
result = data [key ]
1576
1547
except KeyError as exc :
1577
- if level == Level .INFO :
1578
- result = ""
1579
- else :
1580
- result = "missing"
1548
+ result = "" if level == logging .INFO else "missing"
1581
1549
if return_type == list :
1582
1550
result = [result ]
1583
1551
1584
1552
self .report .log (
1585
- level ,
1586
- "{} missing from {}: {} section" .format (
1587
- exc ,
1588
- section_name ,
1589
- item_name ,
1590
- ),
1553
+ level , f"{ exc } missing from { section_name } : { item_name } section"
1591
1554
)
1592
1555
1593
1556
return result
@@ -1631,11 +1594,10 @@ def _tag_site_observations(self, site_observation_objects, category):
1631
1594
]
1632
1595
1633
1596
for tag in tags :
1634
- if tag not in groups .keys ():
1635
- groups [tag ] = [obj .instance ]
1636
- else :
1597
+ if tag in groups :
1637
1598
groups [tag ].append (obj .instance )
1638
-
1599
+ else :
1600
+ groups [tag ] = [obj .instance ]
1639
1601
# I suspect I need to group them by site..
1640
1602
for tag , so_list in groups .items ():
1641
1603
try :
@@ -1727,7 +1689,7 @@ def load_target(
1727
1689
1728
1690
# Decompression can take some time, so we want to report progress
1729
1691
bundle_filename = os .path .basename (data_bundle )
1730
- target_loader .report .log (Level .INFO , f"Decompressing '{ bundle_filename } '" )
1692
+ target_loader .report .log (logging .INFO , f"Decompressing '{ bundle_filename } '" )
1731
1693
1732
1694
try :
1733
1695
# archive is first extracted to temporary dir and moved later
@@ -1743,7 +1705,7 @@ def load_target(
1743
1705
target_loader .experiment_upload .message = exc .args [0 ]
1744
1706
raise FileNotFoundError (msg ) from exc
1745
1707
1746
- target_loader .report .log (Level .INFO , f"Decompressed '{ bundle_filename } '" )
1708
+ target_loader .report .log (logging .INFO , f"Decompressed '{ bundle_filename } '" )
1747
1709
1748
1710
try :
1749
1711
with transaction .atomic ():
0 commit comments