commit c5e844b97f386dc531e67d3453ee1c8021574301
parent 45818068a86bd0c6cb30e3de53e7ad7ad7d888c3
Author: lash <dev@holbrook.no>
Date: Sun, 6 Sep 2026 16:36:43 -0600
Add deterministic uuid in xmp parse, keyword bag
Diffstat:
9 files changed, 81 insertions(+), 25 deletions(-)
diff --git a/adesse/__init__.py b/adesse/__init__.py
@@ -1,4 +1,4 @@
-from .base import Serializer
+from .base import Serializer, rdfn
from .entity import Entity
from .org import Org
from .cert import Cert
diff --git a/adesse/attachment.py b/adesse/attachment.py
@@ -1,8 +1,9 @@
import datetime
import hashlib
-from rdflib import Literal, DC, DCTERMS, XSD, RDF
-from adesse import Entity
+from rdflib import Literal, DC, DCTERMS, XSD, RDF, BNode, Bag
+from adesse import Entity, rdfn
+from adesse.crypto import Sums, sum_from_urn
from adesse.uri import to_uuid_uri
from adesse.ns import DF
@@ -16,11 +17,14 @@ class Attachment(Entity):
self.mime = mime
self.typ = typ
self.sum = None
+ self.tag = []
- def set_sum(self, v):
+ def set_sum(self, v, typ=None):
if not isinstance(v, bytes):
raise TypeError('sum not bytes')
+ if typ != None and typ != Sums.SHA256:
+ raise ValueError('sum must be sha256')
if len(v) > 32:
raise ValueError('sum must be sha256')
self.sum = v
@@ -30,10 +34,21 @@ class Attachment(Entity):
raise NotImplementedError()
- def set_sum_from_urn(self, v):
- if v[:11] != 'URN:sha256:':
- raise ValueError('only sha256 urn supported')
- return self.set_sum(bytes.fromhex(v[11:]))
+ def set_sum_from_urn(self, v, scheme=None):
+ r = sum_from_urn(v, scheme=scheme)
+ return self.set_sum(r)
+
+
+ def add_tag(self, v):
+ self.tag.append(v)
+
+
+ def _apply_tags(self, o, uu):
+ nod = BNode()
+ r = Bag(o, nod)
+ for v in self.tag:
+ r.append(Literal(v))
+ o.add((uu, DC.subject, nod))
def apply(self, g):
@@ -41,7 +56,8 @@ class Attachment(Entity):
g.add((uu, DC.format, Literal(self.mime)))
g.add((uu, DCTERMS.title, Literal(self.common_name)))
g.add((uu, DCTERMS.description, Literal(self.description)))
- g.add((uu, DF.sum, Literal(self.sum.hex(), datatype=XSD.hexBinary)))
+ g.add((uu, DF.sumSHA256, Literal(self.sum.hex(), datatype=XSD.hexBinary)))
g.add((uu, DCTERMS.created, Literal(self.dt.isoformat(timespec='seconds'), datatype=XSD.dateTime)))
g.add((uu, RDF.type, DF.AttachmentData))
+ self._apply_tags(g.g, uu)
super().apply(g)
diff --git a/adesse/base.py b/adesse/base.py
@@ -1,4 +1,4 @@
-from rdflib import Graph
+from rdflib import Graph, RDF, URIRef
from rdflib.namespace import NamespaceManager
from rdflib.namespace import FOAF, XSD, PROV, DC, DCTERMS
@@ -26,3 +26,8 @@ class Serializer:
def __str__(self):
return self.g.serialize(format=serialize_format)
+
+
+def rdfn(v):
+ s = str(RDF) + '_' + str(int(v))
+ return URIRef(s)
diff --git a/adesse/crypto.py b/adesse/crypto.py
@@ -0,0 +1,12 @@
+import enum
+
+
+class Sums(enum.Enum):
+ SHA256 = 32
+ SHA512 = 64
+
+
+def sum_from_urn(v, scheme=None):
+ if v[:11] != 'URN:sha256:':
+ raise ValueError('only sha256 urn supported')
+ return bytes.fromhex(v[11:])
diff --git a/adesse/ns/__init__.py b/adesse/ns/__init__.py
@@ -8,3 +8,4 @@ from .wot import WOT
from .df import DF
from .pss import PSS
from .xmp import XMP
+from .pdf import PDF
diff --git a/adesse/ns/df.py b/adesse/ns/df.py
@@ -10,7 +10,8 @@ class DF(DefinedNamespace):
verdict: URIRef
hasClaim: URIRef
testimonyFor: URIRef
- sum: URIRef
+ sumSHA256: URIRef
+ sumSHA512: URIRef
# classes
Event: URIRef
diff --git a/adesse/ns/pdf.py b/adesse/ns/pdf.py
@@ -0,0 +1,8 @@
+from .inc import *
+
+
+class PDF(DefinedNamespace):
+
+ Keywords: URIRef
+
+ _NS = Namespace('http://ns.adobe.com/pdf/1.3/')
diff --git a/adesse/util/xmp.py b/adesse/util/xmp.py
@@ -3,11 +3,13 @@ import logging
import hashlib
import mimetypes
import datetime
+import uuid
import lxml.etree
from rdflib import Graph, Namespace, RDF, URIRef, DC, Literal
-from adesse import Attachment
-from adesse.ns import XMP
+from adesse import Attachment, rdfn
+from adesse.ns import XMP, PDF
+from adesse.crypto import sum_from_urn
logg = logging.getLogger('util.xmp')
@@ -45,12 +47,6 @@ def _parse_xmp(xmp_file, resource_file, search_dir=None):
return (uu, mime, s,)
-
-def rdfn(v):
- s = str(RDF) + '_' + str(int(v))
- return URIRef(s)
-
-
def _get_alt_lang(sbj, prd, o, lang=None):
v = o.value(sbj, prd)
typ = o.value(v, RDF.type)
@@ -82,6 +78,7 @@ def _get_bag(sbj, prd, o):
break
r.append(v.value)
i += 1
+ logg.debug('bag for {} {} is {}'.format(sbj, prd, r))
return r
@@ -107,7 +104,16 @@ def scan_lang(sbj, o):
return (r, v,)
-def attachment_from_xmp(xml_file, resource_file=None, search_dir=None):
+def get_tags(sbj, o):
+ #return _get_bag(sbj, PDF.Keywords, o)
+ v = o.value(sbj, PDF.Keywords)
+ r = []
+ for s in v.split(','):
+ r.append(s.strip())
+ return r
+
+
+def attachment_from_xmp(xml_file, resource_file=None, search_dir=None, uuidns=None):
if search_dir == None:
search_dir = ['.']
r = _parse_xmp(xml_file, resource_file=resource_file, search_dir=search_dir)
@@ -124,6 +130,12 @@ def attachment_from_xmp(xml_file, resource_file=None, search_dir=None):
mime = str(r[1][0])
logg.debug('have title {} desc {} mime {}'.format(title, desc, mime))
slug = os.path.splitext(xml_file)[0]
- v = Attachment(title, desc, date, mime, lang=default_lang)
- v.set_sum_from_urn(z)
- return v
+
+ uu = None
+ if uuidns != None:
+ uu = uuid.uuid5(uuidns, sum_from_urn(z))
+ r = Attachment(title, desc, date, mime, lang=default_lang, uu=uu)
+ r.set_sum_from_urn(z)
+ for v in get_tags(sbj, o):
+ r.add_tag(v)
+ return r
diff --git a/test/test_xmp.py b/test/test_xmp.py
@@ -3,6 +3,7 @@ import datetime
import hashlib
import os
import logging
+import uuid
from rdflib.term import URIRef
from rdflib import Graph
@@ -18,12 +19,12 @@ thisdir = os.path.realpath(os.path.dirname(__file__))
class TestXmpLoad(unittest.TestCase):
def setUp(self):
- pass
+ self.uubase = uuid.UUID('f253542c-78d1-4187-84f6-e15f3e686591')
def test_parse(self):
fp = os.path.join(thisdir, 'import.xmp')
- r = xmp.attachment_from_xmp(fp, 'import.pdf', search_dir=[thisdir])
+ r = xmp.attachment_from_xmp(fp, 'import.pdf', search_dir=[thisdir], uuidns=self.uubase)
z = Serializer()
r.apply(z)
print(z)