@@ -262,6 +262,13 @@ def get_anon_id(self, obj, local_prefix="id"):
262
262
class Literal (object ):
263
263
def __init__ (self , value , datatype = None , langtag = None ):
264
264
self ._value = value
265
+ if langtag :
266
+ if datatype is None :
267
+ logger .debug ('Assuming prov:InternationalizedString as the type of "%s"@%s' % (value , langtag ))
268
+ datatype = PROV ["InternationalizedString" ]
269
+ elif datatype != PROV ["InternationalizedString" ]:
270
+ logger .warn ('Invalid data type (%s) for "%s"@%s, overridden as prov:InternationalizedString.' % (value , langtag ))
271
+ datatype = PROV ["InternationalizedString" ]
265
272
self ._datatype = datatype
266
273
self ._langtag = langtag
267
274
@@ -291,14 +298,14 @@ def has_no_langtag(self):
291
298
292
299
def provn_representation (self ):
293
300
if self ._langtag :
294
- # a langtag can only goes with string
301
+ # a language tag can only go with prov:InternationalizedString
295
302
return u'%s@%s' % (_ensure_multiline_string_triple_quoted (self ._value ), unicode (self ._langtag ))
296
303
else :
297
304
return u'%s %%%% %s' % (_ensure_multiline_string_triple_quoted (self ._value ), unicode (self ._datatype ))
298
305
299
306
def json_representation (self ):
300
307
if self ._langtag :
301
- # a langtag can only goes with string
308
+ # a language tag can only go with prov:InternationalizedString
302
309
return {'$' : unicode (self ._value ), 'lang' : self ._langtag }
303
310
else :
304
311
if isinstance (self ._datatype , QName ):
@@ -424,6 +431,9 @@ def __init__(self, record_type, attribute_id):
424
431
self .attribute_id = attribute_id
425
432
self .args += (PROV_N_MAP [record_type ], attribute_id )
426
433
434
+ def __str__ (self ):
435
+ return 'Missing the required attribute "%s" in %s' % (PROV_ID_ATTRIBUTES_MAP [self .attribute_id ], PROV_N_MAP [self .record_type ])
436
+
427
437
428
438
class ProvExceptionNotValidAttribute (ProvException ):
429
439
def __init__ (self , record_type , attribute , attribute_types ):
@@ -432,6 +442,9 @@ def __init__(self, record_type, attribute, attribute_types):
432
442
self .attribute_types = attribute_types
433
443
self .args += (PROV_N_MAP [record_type ], unicode (attribute ), attribute_types )
434
444
445
+ def __str__ (self ):
446
+ return 'Invalid attribute value: %s. %s expected' % (self .attribute , self .attribute_types )
447
+
435
448
436
449
class ProvExceptionCannotUnifyAttribute (ProvException ):
437
450
def __init__ (self , identifier , record_type1 , record_type2 ):
@@ -440,6 +453,9 @@ def __init__(self, identifier, record_type1, record_type2):
440
453
self .record_type2 = record_type2
441
454
self .args += (identifier , PROV_N_MAP [record_type1 ], PROV_N_MAP [record_type2 ])
442
455
456
+ def __str__ (self ):
457
+ return 'Cannot unify two records of type %s and %s with same identifier (%s)' % (self .identifier , PROV_N_MAP [self .record_type1 ], PROV_N_MAP [self .record_type2 ])
458
+
443
459
444
460
class ProvExceptionContraint (ProvException ):
445
461
def __init__ (self , record_type , attribute1 , attribute2 , msg ):
@@ -517,12 +533,10 @@ def get_value(self):
517
533
def _auto_literal_conversion (self , literal ):
518
534
'''This method normalise datatype for literals
519
535
'''
536
+ if isinstance (literal , URIRef ):
537
+ return literal
538
+
520
539
if isinstance (literal , basestring ):
521
- # try if this is a QName
522
- qname = self ._bundle .valid_identifier (literal )
523
- if isinstance (qname , QName ):
524
- return qname
525
- # if not a QName, convert all strings to unicode
526
540
return unicode (literal )
527
541
528
542
if isinstance (literal , Literal ) and literal .has_no_langtag ():
@@ -539,7 +553,9 @@ def parse_extra_attributes(self, extra_attributes):
539
553
if isinstance (extra_attributes , dict ):
540
554
# Converting the dictionary into a list of tuples (i.e. attribute-value pairs)
541
555
extra_attributes = extra_attributes .items ()
542
- attr_set = set ((self ._bundle .valid_identifier (attribute ), self ._auto_literal_conversion (value )) for attribute , value in extra_attributes )
556
+ attr_set = set ((self ._bundle .valid_identifier (attribute ),
557
+ self ._auto_literal_conversion (value ))
558
+ for attribute , value in extra_attributes )
543
559
return attr_set
544
560
545
561
def add_extra_attributes (self , extra_attributes ):
@@ -653,7 +669,7 @@ def optional_attribute(self, attributes, attribute_id, attribute_types):
653
669
return self ._validate_attribute (attribute , attribute_types )
654
670
655
671
def __eq__ (self , other ):
656
- if self .__class__ != other .__class__ :
672
+ if self .get_prov_type () != other .get_prov_type () :
657
673
return False
658
674
if self ._identifier and not (self ._identifier == other ._identifier ):
659
675
return False
@@ -682,6 +698,13 @@ def __eq__(self, other):
682
698
sattr = sorted (self ._extra_attributes , key = _normalise_attributes ) if self ._extra_attributes else None
683
699
oattr = sorted (other ._extra_attributes , key = _normalise_attributes ) if other ._extra_attributes else None
684
700
if sattr != oattr :
701
+ if logger .isEnabledFor (logging .DEBUG ):
702
+ for spair , opair in zip (sattr , oattr ):
703
+ # Log the first unequal pair of attributes
704
+ if spair != opair :
705
+ logger .debug ("Equality (ProvRecord): unequal attribute-value pairs - %s = %s - %s = %s" ,
706
+ spair [0 ], spair [1 ], opair [0 ], opair [1 ])
707
+ break
685
708
return False
686
709
return True
687
710
@@ -740,17 +763,28 @@ def rdf(self, graph=None, subj=None):
740
763
graph .add ((subj , pred , obj ))
741
764
if self ._extra_attributes :
742
765
for (attr , value ) in self ._extra_attributes :
766
+ try :
767
+ # try if there is a RDF representation defined
768
+ obj = value .rdf_representation ()
769
+ except Exception , e :
770
+ obj = RDFLiteral (value )
771
+ if attr == PROV ['location' ]:
772
+ pred = PROV ['atLocation' ].rdf_representation ()
773
+ if isinstance (value , (URIRef , QName )):
774
+ if isinstance (value , QName ):
775
+ value = URIRef (value .get_uri ())
776
+ graph .add ((subj , pred , value ))
777
+ graph .add ((value , RDF .type ,
778
+ PROV ['Location' ].rdf_representation ()))
779
+ else :
780
+ graph .add ((subj , pred , obj ))
781
+ continue
743
782
if attr == PROV ['type' ]:
744
783
pred = RDF .type
745
784
elif attr == PROV ['label' ]:
746
785
pred = RDFS .label
747
786
else :
748
787
pred = attr .rdf_representation ()
749
- try :
750
- # try if there is a RDF representation defined
751
- obj = value .rdf_representation ()
752
- except Exception , e :
753
- obj = RDFLiteral (value )
754
788
graph .add ((subj , pred , obj ))
755
789
return graph
756
790
@@ -853,8 +887,7 @@ def add_attributes(self, attributes, extra_attributes):
853
887
startTime = self .optional_attribute (attributes , PROV_ATTR_STARTTIME , datetime .datetime )
854
888
endTime = self .optional_attribute (attributes , PROV_ATTR_ENDTIME , datetime .datetime )
855
889
if startTime and endTime and startTime > endTime :
856
- # TODO Raise logic exception here
857
- pass
890
+ raise ValueError ('StartTime %s > EndTime %s' % (startTime , endTime ))
858
891
attributes = OrderedDict ()
859
892
attributes [PROV_ATTR_STARTTIME ] = startTime
860
893
attributes [PROV_ATTR_ENDTIME ] = endTime
@@ -1337,8 +1370,8 @@ def get_valid_identifier(self, identifier):
1337
1370
# create and return an identifier in the default namespace
1338
1371
return self ._default [identifier ]
1339
1372
else :
1340
- # TODO Should an exception raised here
1341
- return Identifier ( identifier )
1373
+ # This is not an identifier
1374
+ return None
1342
1375
1343
1376
def get_anonymous_identifier (self , local_prefix = 'id' ):
1344
1377
self ._anon_id_count += 1
@@ -1362,11 +1395,7 @@ def __init__(self, bundle=None, identifier=None, attributes=None, other_attribut
1362
1395
self ._records = list ()
1363
1396
self ._id_map = dict ()
1364
1397
self ._bundles = dict ()
1365
- if bundle is None :
1366
- self ._namespaces = NamespaceManager (namespaces )
1367
- else :
1368
- self ._namespaces = bundle ._namespaces
1369
- self ._namespaces .add_namespaces (namespaces )
1398
+ self ._namespaces = NamespaceManager (namespaces , parent = (bundle ._namespaces if bundle is not None else None ))
1370
1399
1371
1400
# Initializing record-specific attributes
1372
1401
super (ProvBundle , self ).__init__ (bundle , identifier , attributes , other_attributes , asserted )
@@ -1379,9 +1408,6 @@ def get_default_namespace(self):
1379
1408
return self ._namespaces .get_default_namespace ()
1380
1409
1381
1410
def add_namespace (self , namespace_or_prefix , uri = None ):
1382
- if self ._bundle is not None : # This is a bundle
1383
- logger .warn ("Namespace cannot be added into a bundle. It will be added to the document instead." )
1384
-
1385
1411
if uri is None :
1386
1412
self ._namespaces .add_namespace (namespace_or_prefix )
1387
1413
else :
@@ -1398,10 +1424,12 @@ def get_anon_id(self, record):
1398
1424
return self ._namespaces .get_anonymous_identifier ()
1399
1425
1400
1426
def get_records (self , class_or_type_or_tuple = None ):
1401
- if class_or_type_or_tuple is None :
1402
- return self ._records
1427
+ # Only returning asserted records
1428
+ results = [rec for rec in self ._records if rec .is_asserted ()]
1429
+ if class_or_type_or_tuple :
1430
+ return filter (lambda rec : isinstance (rec , class_or_type_or_tuple ), results )
1403
1431
else :
1404
- return filter ( lambda rec : isinstance ( rec , class_or_type_or_tuple ), self . _records )
1432
+ return results
1405
1433
1406
1434
def get_record (self , identifier ):
1407
1435
if identifier is None :
@@ -1453,22 +1481,21 @@ def _encode_json_representation(self, value):
1453
1481
return value
1454
1482
1455
1483
def _decode_json_representation (self , literal ):
1456
- try :
1484
+ if isinstance (literal , dict ):
1485
+ # complex type
1457
1486
value = literal ['$' ]
1458
- if 'lang' in literal :
1459
- return Literal (value , langtag = literal ['lang' ])
1487
+ datatype = literal ['type' ] if 'type' in literal else None
1488
+ langtag = literal ['lang' ] if 'lang' in literal else None
1489
+ if datatype == u'xsd:anyURI' :
1490
+ return Identifier (value )
1491
+ elif datatype == u'xsd:QName' :
1492
+ return self .valid_identifier (value )
1460
1493
else :
1461
- datatype = literal ['type' ]
1462
- if datatype == u'xsd:anyURI' :
1463
- return Identifier (value )
1464
- elif datatype == u'xsd:QName' :
1465
- return self .valid_identifier (value )
1466
- else :
1467
- # The literal of standard Python types is not converted here
1468
- # It will be automatically converted when added to a record by _auto_literal_conversion()
1469
- return Literal (value , self .valid_identifier (datatype ))
1470
- except :
1471
- # simple type, just return it
1494
+ # The literal of standard Python types is not converted here
1495
+ # It will be automatically converted when added to a record by _auto_literal_conversion()
1496
+ return Literal (value , self .valid_identifier (datatype ), langtag )
1497
+ else :
1498
+ # simple type, just return it
1472
1499
return literal
1473
1500
1474
1501
def _encode_JSON_container (self ):
@@ -1701,12 +1728,10 @@ def get_flattened(self):
1701
1728
return document
1702
1729
1703
1730
def __eq__ (self , other ):
1704
- try :
1705
- other_records = set (other ._records )
1706
- except :
1707
- # other is not a bundle
1731
+ if not isinstance (other , ProvBundle ):
1708
1732
return False
1709
- this_records = set (self ._records )
1733
+ other_records = set (other .get_records ())
1734
+ this_records = set (self .get_records ())
1710
1735
if len (this_records ) != len (other_records ):
1711
1736
return False
1712
1737
# check if all records for equality
@@ -1721,12 +1746,12 @@ def __eq__(self, other):
1721
1746
other_records .remove (record_b )
1722
1747
continue
1723
1748
else :
1724
- logger .debug ("Unequal PROV records:" )
1725
- logger .debug ("%s" % unicode (record_a ))
1726
- logger .debug ("%s" % unicode (record_b ))
1749
+ logger .debug ("Equality (ProvBundle): Unequal PROV records:" )
1750
+ logger .debug ("%s" , unicode (record_a ))
1751
+ logger .debug ("%s" , unicode (record_b ))
1727
1752
return False
1728
1753
else :
1729
- logger .debug ("Could not find a record with this identifier: %s" % unicode (record_a ._identifier ))
1754
+ logger .debug ("Equality (ProvBundle): Could not find a record with this identifier: %s" , unicode (record_a ._identifier ))
1730
1755
return False
1731
1756
else :
1732
1757
# Manually look for the record
@@ -1737,7 +1762,7 @@ def __eq__(self, other):
1737
1762
found = True
1738
1763
break
1739
1764
if not found :
1740
- logger .debug ("Could not find this record: %s" % unicode (record_a ))
1765
+ logger .debug ("Equality (ProvBundle): Could not find this record: %s" , unicode (record_a ))
1741
1766
return False
1742
1767
return True
1743
1768
0 commit comments