commit d4340f1d41ac5210cc7355ad988964949ec244c7
parent 84805b603dac3c924427681d08522c5fbf764491
Author: lash <dev@holbrook.no>
Date: Fri, 13 Feb 2026 10:51:12 +0000
Add XML export
Diffstat:
3 files changed, 83 insertions(+), 14 deletions(-)
diff --git a/dummy/tests/asset.py b/dummy/tests/asset.py
@@ -2,8 +2,11 @@ import logging
import os
import unittest
+import lxml.etree
+
from usawa.asset import Asset
+
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -18,5 +21,12 @@ class TestAsset(unittest.TestCase):
logg.debug('asset {}'.format(asset))
+ def test_asset_export(self):
+ fp = os.path.join(testdir, 'test.xml')
+ asset = Asset.from_file(fp, slug='foo', description='barbarbar', extref='xyzzy', localref='plugh')
+ tree = asset.to_tree()
+ logg.debug('asset {}'.format(lxml.etree.tostring(tree)))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/dummy/usawa/asset.py b/dummy/usawa/asset.py
@@ -2,10 +2,14 @@ import hashlib
import mimetypes
import logging
import os
+import uuid
+import lxml.etree
import magic
-logg = logging.getLogger('asset')
+from .xml import nsmap
+
+logg = logging.getLogger('usawa.asset')
BLOCKSIZE = 512
@@ -28,10 +32,12 @@ class Asset:
self.enc = None
self.slug = None
self.ext = None
+ self.localref = None
+ self.extref = None
+ self.uuid = None
+ self.description = None
-
-
def get_filename(self):
s = self.slug
if self.ext != None:
@@ -46,15 +52,22 @@ class Asset:
return s
+ @staticmethod
+ def from_file(filepath, description=None, slug=None, mimetype=None, localref=None, extref=None):
+ f = open(filepath, 'rb')
+ return Asset.from_io(f, filepath, f.close, description=description, slug=slug, mimetype=mimetype, localref=localref, extref=extref)
+
+ """
+ :todo: make sure stream close on exception
+ """
@staticmethod
- def from_file(filepath, description=None, slug=None, mimetype=None):
+ def from_io(io, path, closer, description=None, slug=None, mimetype=None, localref=None, extref=None):
o = Asset()
h = hashlib.sha256()
- f = open(filepath, 'rb')
- b = f.read(BLOCKSIZE)
+ b = io.read(BLOCKSIZE)
if mimetype == None:
- v = mimetypes.guess_file_type(filepath, strict=True)
+ v = mimetypes.guess_file_type(path, strict=True)
if v != None:
mimetype = v[0]
o.enc = v[1]
@@ -64,24 +77,68 @@ class Asset:
h.update(b)
c = BLOCKSIZE
while True:
- b = f.read(BLOCKSIZE)
+ b = io.read(BLOCKSIZE)
if len(b) == 0:
break
h.update(b)
c += len(b)
- f.close()
+ closer()
o.digest = h.digest()
s = mimetypes.guess_extension(o.mime, strict=True)
if s != None:
o.ext = s[1:]
+ (o.slug, o.ext) = parse_path(path)
+ if slug != None:
+ logg.info('overriding file base name {} -> {}'.format(o.slug, slug))
+ o.slug = slug
- (o.slug, o.ext) = parse_path(filepath)
+ logg.debug('asset read {} bytes from path {} mime {}'.format(c, path, o.mime))
- logg.debug('asset read {} bytes from path {} mime {}'.format(c, filepath, o.mime))
+ o.uuid = str(uuid.uuid4())
+ if localref == None:
+ localref = o.uuid
+ o.localref = localref
+ o.extref = extref
+ o.description = description
return o
+ def to_tree(self):
+ tree = lxml.etree.Element('attachment', nsmap=nsmap())
+ tree.set('mime', self.get_mimestring())
+ tree.set('uuid', self.uuid)
+
+ o = lxml.etree.SubElement(tree, 'digest')
+ o.text = self.digest.hex()
+ tree.append(o)
+
+ o = lxml.etree.SubElement(tree, 'lookup')
+ o.text = '.'
+ o.set('method', 'local')
+ tree.append(o)
+
+ o = lxml.etree.SubElement(tree, 'ref')
+ o.text = self.localref
+ tree.append(o)
+
+ if self.extref != None:
+ o = lxml.etree.SubElement(tree, 'extref')
+ o.text = self.extref
+ tree.append(o)
+
+ o = lxml.etree.SubElement(tree, 'filename')
+ o.text = self.get_filename()
+ tree.append(o)
+
+ if self.description != None:
+ o = lxml.etree.SubElement(tree, 'description')
+ o.text = self.description
+ tree.append(o)
+
+ return tree
+
+
def __str__(self):
return 'file ̈́' + self.get_filename() + ' mime ' + self.get_mimestring() + ' digest ' + self.digest.hex()
diff --git a/dummy/usawa/data/schema.xsd b/dummy/usawa/data/schema.xsd
@@ -135,7 +135,7 @@
<xs:complexType name="EntryData">
<xs:sequence>
<xs:element name="parent" type="xs:string" />
- <xs:element name="ref" type="xs:string" />
+ <xs:element name="ext" type="xs:string" />
<xs:element name="serial" type="xs:positiveInteger" />
<xs:element name="date" type="xs:date" />
<xs:element name="dateTimeRegistered" type="xs:dateTime" />
@@ -157,9 +157,11 @@
<xs:complexType name="Attachment">
<xs:sequence>
<xs:element name="digest" type="Digest" />
- <xs:element name="slug" type="xs:string" />
- <xs:element name="description" type="xs:string" />
<xs:element name="lookup" type="Lookup" />
+ <xs:element name="ref" type="xs:string" />
+ <xs:element name="extref" type="xs:string" minOccurs="0" maxOccurs="1" />
+ <xs:element name="filename" type="xs:string" minOccurs="0" maxOccurs="1" />
+ <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1" />
</xs:sequence>
<xs:attribute name="mime" type="xs:string" />
<xs:attribute name="uuid" type="xs:string" />