diff --git a/.gitignore b/.gitignore index 3be99ef..ebb4812 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ pip-delete-this-directory.txt .tox/ .coverage .cache +htmlcov nosetests.xml coverage.xml diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 0000000..8ec39bb --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,65 @@ +Example usage +============= + +Parsing METS documents +---------------------- + +Example of listing the relative file paths of preservation files referenced in +a METS file::: + + import metsrw + + mets = metsrw.METSDocument.fromfile('fixtures/complete_mets_2.xml') + for entry in mets.all_files(): + if entry.use == 'preservation': + print entry.path + +Example of retrieving a file by UUID::: + + import metsrw + + mets = metsrw.METSDocument.fromfile('fixtures/complete_mets_2.xml') + entry = mets.get_file('46b7cb96-792c-4441-a5d6-67c83313501c') + print entry.path + +Creating/modifying METS documents +--------------------------------- + +Example creation of a METS document (without PREMIS or Dublin Core metadata)::: + + import metsrw + import uuid + + mw = metsrw.METSDocument() + + # Create object entries + file1 = metsrw.FSEntry('objects/cat.png', file_uuid=str(uuid.uuid4())) + file2 = metsrw.FSEntry('objects/dog.jpg', file_uuid=str(uuid.uuid4())) + + # Create preservation derivative entries + file1p = metsrw.FSEntry('objects/cat-preservation.tiff', use='preservation', file_uuid=str(uuid.uuid4()), derived_from=file1) + file2p = metsrw.FSEntry('objects/dog-preservation.tiff', use='preservation', file_uuid=str(uuid.uuid4()), derived_from=file2) + + # Create object directory entry + objects = metsrw.FSEntry('objects', type='Directory', children=[file1, file2, file1p, file2p]) + + # Create metadata subdirectories then metadata directory entry + children = [ + metsrw.FSEntry('transfers', type='Directory', children=[]), + metsrw.FSEntry('metadata/metadata.csv', use='metadata', file_uuid=str(uuid.uuid4())), + ] + metadata = metsrw.FSEntry('metadata', type='Directory', children=children) + + # Create submission METS entry and submission documentation parent directory entry + children = [ + metsrw.FSEntry('submissionDocumentation/METS.xml', use='submissionDocumentation', file_uuid=str(uuid.uuid4())), + ] + sub_doc = metsrw.FSEntry('submissionDocumentation', type='Directory', children=children) + + # Create SIP entry containing objects, metadata, and submission documentaton entries + children = [objects, metadata, sub_doc] + sip = metsrw.FSEntry('sipname-uuid', type='Directory', children=children) + + # Add SIP entry to METS document and write to file + mw.append_file(sip) + mw.write('mets.xml', fully_qualified=True, pretty_print=True) diff --git a/fixtures/complete_mets_2.xml b/fixtures/complete_mets_2.xml new file mode 100644 index 0000000..43e130e --- /dev/null +++ b/fixtures/complete_mets_2.xml @@ -0,0 +1,7541 @@ + + + + + + + + Example DC title + Example DC creator + Example DC subject + Example DC description + Example DC publisher + Example DC contributor + 1984-01-01 + Example DC format + Example DC identifier + Example DC source + Example DC relation + en + Example DC coverage + Example DC rights + + + + + + + + + + + UUID + 5344bfe5-2607-4924-9970-5bdedfe44984 + + + 0 + + sha256 + 414f3aced62db61bc9c6d893d745e2455415e4e05762dc44503a3ca742ff2dff + + 1437921 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/799px-Euroleague-LE_Roma_vs_Toulouse_IC-27-4af513d6-3fb0-44a7-a6cd-e55dd31466b9.tif + + derivation + has source + + UUID + 46b7cb96-792c-4441-a5d6-67c83313501c + + + UUID + 42f1e1a1-9389-4c01-b50e-80a56f92f35d + + + + + + + + + + + + UUID + 4af513d6-3fb0-44a7-a6cd-e55dd31466b9 + + creation + 2015-10-23T23:23:59 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 2f1c43eb-13f6-49c5-b281-2d8586d8bd71 + + message digest calculation + 2015-10-23T23:23:59 + program="python"; module="hashlib.sha256()" + + + + 414f3aced62db61bc9c6d893d745e2455415e4e05762dc44503a3ca742ff2dff + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 5f1f395e-4d2e-46be-b652-aafc9255a4fa + + fixity check + 2015-10-23T23:26:52 + program="python"; module="hashlib.sha256()" + + Pass + + 414f3aced62db61bc9c6d893d745e2455415e4e05762dc44503a3ca742ff2dff verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 46b7cb96-792c-4441-a5d6-67c83313501c + + + 0 + + sha256 + b4961eac5fb7a1ffae4b63ac033a6a25827e7b839594f6e8e0b8e4fb01ebd7c4 + + 1437654 + + + Generic Bitmap + + + + Archivematica Format Policy Registry + .bmp + + + + + + + + + + + + + + + + + + + + + + + + + + + 9.90 + 799px-Euroleague-LE_Roma_vs_Toulouse_IC-27.bmp + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 1404 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:19:52+00:00 + 2015:10:23 23:18:27+00:00 + rw-rw---- + BMP + image/bmp + 799 + 599 + 1 + 24 + None + 1437600 + 11811 + 11811 + Use BitDepth + All + 799x599 + 0.479 + + + + + + 284 + 1 + General + General + 0 + 1 + RGB + RGB + RGB + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/799px-Euroleague-LE_Roma_vs_Toulouse_IC-27.bmp + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 799px-Euroleague-LE_Roma_vs_Toulouse_IC-27 + bmp + Bitmap + Bitmap + bmp + Bitmap + image/bmp + Bitmap + Bitmap + bmp + 1437654 + 1.37 MiB + 1 MiB + 1.4 MiB + 1.37 MiB + 1.371 MiB + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + RGB + RGB + RGB + RGB + 799 + 799 pixels + 599 + 599 pixels + 24 + 24 bits + 24 + 24 bits + + + + + + %transferDirectory%objects/799px-Euroleague-LE Roma vs Toulouse IC-27.bmp + + derivation + is source of + + UUID + 5344bfe5-2607-4924-9970-5bdedfe44984 + + + UUID + 42f1e1a1-9389-4c01-b50e-80a56f92f35d + + + + + + + + + + + + UUID + a5e5ce6a-06a8-4a7d-adf0-8ed3f29b039d + + ingestion + 2015-10-23T23:17:25 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + f079503d-6fb6-4e0e-95c1-f2b67c4d6bad + + message digest calculation + 2015-10-23T23:17:40 + program="python"; module="hashlib.sha256()" + + + + b4961eac5fb7a1ffae4b63ac033a6a25827e7b839594f6e8e0b8e4fb01ebd7c4 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + be4621ad-cf00-4583-ba34-d8bdd9ef0e39 + + virus check + 2015-10-23T23:18:03 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4cfcb431-dbde-4b5a-b144-39adc628364b + + name cleanup + 2015-10-23T23:18:28 + prohibited characters removed:program="sanitizeNames"; version="1.10.d204c68e72645b2b4228520680ca211f7bc20b3b" + + + + Original name="%transferDirectory%objects/799px-Euroleague-LE Roma vs Toulouse IC-27.bmp"; cleaned up name="%transferDirectory%objects/799px-Euroleague-LE_Roma_vs_Toulouse_IC-27.bmp" + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 707c547e-5265-433f-9abd-9d2597f9d551 + + format identification + 2015-10-23T23:19:21 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 42f1e1a1-9389-4c01-b50e-80a56f92f35d + + normalization + 2015-10-23T23:23:59 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/799px-Euroleague-LE_Roma_vs_Toulouse_IC-27-4af513d6-3fb0-44a7-a6cd-e55dd31466b9.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 5c79dee9-a54e-48e0-ad49-6d2267352f99 + + fixity check + 2015-10-23T23:26:39 + program="python"; module="hashlib.sha256()" + + Pass + + b4961eac5fb7a1ffae4b63ac033a6a25827e7b839594f6e8e0b8e4fb01ebd7c4 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 63777966-a55c-4975-8283-9a80a5d864bc + + + 0 + + sha256 + c0fa53ae576cc4381890099a48d5dc3f40733a3415965fb477e79503d7653b5c + + 1080282 + + + Generic AI file + + + + Archivematica Format Policy Registry + .ai + + + + + + + + + 1.5 + + + + 2015:10:15 20:52:33-07:00 + 2012-03-22T18:38:02Z + 2012:01:23 20:56:01-08:00 + Adobe PDF library 9.00/Adobe Illustrator CS4 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + BBhelmet.ai + 1080282 + 1444967553000 + + + + + 457 + 521 + + + + + + PDF document, version 1.5 +application/pdf; charset=binary + application/pdf + PDF document, version 1.5 + + + + + ExifToolVersion 9.13 +FileName BBhelmet.ai +Directory /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects +FileSize 1055 kB +FileModifyDate 2015:10:15 20:52:33-07:00 +FileAccessDate 2015:10:23 16:17:42-07:00 +FileInodeChangeDate 2015:10:23 16:17:22-07:00 +FilePermissions rw-rw---- +FileType AI +MIMEType application/vnd.adobe.illustrator +PDFVersion 1.5 +Linearized No +XMPToolkit Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00 +Format application/pdf +MetadataDate 2012:03:22 11:38:02-07:00 +CreatorTool Adobe Illustrator CS4 +ThumbnailWidth 228 +ThumbnailHeight 256 +ThumbnailFormat JPEG +ThumbnailImage (Binary data 19717 bytes, use -b option to extract) +InstanceID uuid:19df14ac-2b67-5940-b611-4669665d0d38 +DocumentID xmp.did:FA7F1174072068119F06ECE830E58C3D +OriginalDocumentID uuid:5D20892493BFDB11914A8590D31508C8 +RenditionClass proof:pdf +DerivedFromInstanceID uuid:e42563fc-4adb-7949-a074-00702d802691 +DerivedFromDocumentID xmp.did:F77F1174072068119F06ECE830E58C3D +DerivedFromOriginalDocumentID uuid:5D20892493BFDB11914A8590D31508C8 +DerivedFromRenditionClass proof:pdf +HistoryAction converted, saved, converted, converted, saved, saved, saved, saved, saved, converted, saved, converted, saved, saved, saved, saved, saved, saved, saved, saved, saved, saved, saved, converted, saved, converted, saved, converted, saved, converted, saved, saved, saved, saved, saved, saved, saved, saved, saved +HistoryInstanceID xmp.iid:D27F11740720681191099C3B601C4548, xmp.iid:F97F1174072068118D4ED246B3ADB1C6, xmp.iid:FA7F1174072068118D4ED246B3ADB1C6, xmp.iid:EF7F117407206811A46CA4519D24356B, xmp.iid:F07F117407206811A46CA4519D24356B, xmp.iid:F77F117407206811BDDDFD38D0CF24DD, xmp.iid:F97F117407206811BDDDFD38D0CF24DD, xmp.iid:FA7F117407206811BDDDFD38D0CF24DD, xmp.iid:FB7F117407206811BDDDFD38D0CF24DD, xmp.iid:FC7F117407206811BDDDFD38D0CF24DD, xmp.iid:FD7F117407206811BDDDFD38D0CF24DD, xmp.iid:FE7F117407206811BDDDFD38D0CF24DD, xmp.iid:B233668C16206811BDDDFD38D0CF24DD, xmp.iid:B333668C16206811BDDDFD38D0CF24DD, xmp.iid:B433668C16206811BDDDFD38D0CF24DD, xmp.iid:F77F11740720681197C1BF14D1759E83, xmp.iid:F87F11740720681197C1BF14D1759E83, xmp.iid:F97F11740720681197C1BF14D1759E83, xmp.iid:FA7F117407206811B628E3BF27C8C41B, xmp.iid:FF7F117407206811B628E3BF27C8C41B, xmp.iid:07C3BD25102DDD1181B594070CEB88D9, xmp.iid:F87F1174072068119098B097FDA39BEF, xmp.iid:F77F117407206811BB1DBF8F242B6F84, xmp.iid:F97F117407206811ACAFB8DA80854E76, xmp.iid:0180117407206811834383CD3A8D2303, xmp.iid:01E540664A3DDD11BD33D3EB8D3A1068, xmp.iid:6B6AE2A5723EDD11A6F1BABF7C5A7A51, xmp.iid:0B9FED35200A11689FE8CB9EA85C5459, xmp.iid:F77F1174072068119F06ECE830E58C3D, xmp.iid:FA7F1174072068119F06ECE830E58C3D +HistoryWhen 2008:04:17 14:19:15+05:30, 2008:05:15 16:23:06-07:00, 2008:05:15 17:10:45-07:00, 2008:05:15 22:53:33-07:00, 2008:05:15 23:07:07-07:00, 2008:05:16 10:35:43-07:00, 2008:05:16 10:40:59-07:00, 2008:05:16 11:26:55-07:00, 2008:05:16 11:29:01-07:00, 2008:05:16 11:29:20-07:00, 2008:05:16 11:30:54-07:00, 2008:05:16 11:31:22-07:00, 2008:05:16 12:23:46-07:00, 2008:05:16 13:27:54-07:00, 2008:05:16 13:46:13-07:00, 2008:05:16 15:47:57-07:00, 2008:05:16 15:51:06-07:00, 2008:05:16 15:52:22-07:00, 2008:05:22 13:28:01-07:00, 2008:05:22 16:23:53-07:00, 2008:05:28 16:45:26-07:00, 2008:06:02 13:25:25-07:00, 2008:06:09 14:58:36-07:00, 2008:06:11 14:31:27-07:00, 2008:06:11 22:37:35-07:00, 2008:06:18 22:24:01+07:00, 2008:06:19 20:30:34-07:00, 2008:06:26 06:07:42-07:00, 2012:01:21 14:49:33-08:00, 2012:01:23 20:55:59-08:00 +HistorySoftwareAgent Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4 +HistoryChanged /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, / +HistoryParams from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator +ManifestLinkForm EmbedByReference +ManifestReferenceFilePath /Users/cam/Dropbox/BomberBrewing/cooper126.png +Type Document +StartupProfile Print +HasVisibleOverprint False +HasVisibleTransparency False +NPages 1 +MaxPageSizeW 8.500000 +MaxPageSizeH 11.000000 +MaxPageSizeUnit Inches +FontName HelveticaNeue-BoldCond, HelveticaNeue-BlackCond, HelveticaNeue-ExtBlackCond +FontFamily Helvetica Neue, Helvetica Neue, Helvetica Neue +FontFace 77 Bold Condensed, 97 Black Condensed, 107 Extra Black Condensed +FontType Type 1, Type 1, Type 1 +FontVersion 001.000, 001.000, 001.000 +FontComposite False, False, False +FontFileName HelveNeuBolCon; Helvetica Neue Condensed 2, HelveNeuBlaCon; Helvetica Neue Condensed 1, HelveNeuExtBlaCon; Helvetica Neue Condensed 1 +PlateNames Black +SwatchGroupsGroupName Brights +SwatchGroupsGroupType 1 +SwatchGroupsColorantsSwatchName C=60 M=90 Y=0 K=0 +SwatchGroupsColorantsMode CMYK +SwatchGroupsColorantsType PROCESS +SwatchGroupsColorantsCyan 60.000004 +SwatchGroupsColorantsMagenta 90.000000 +SwatchGroupsColorantsYellow 0.003099 +SwatchGroupsColorantsBlack 0.003099 +PageCount 1 +For cam andrews, +BoundingBox 69 111 526 632 +ContainerVersion 11 +CreatorVersion 15 +CreateDate 2012:01:23 20:56:01-08:00 +Creator Adobe Illustrator CS4 +ModifyDate 2012:03:22 11:38:02-07:00 +Producer Adobe PDF library 9.00 +Title BBhelmet +ImageHeight 521 +ImageWidth 457 +ImageSize 457x521 + 9.13 + BBhelmet.ai + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 1055 kB + 2015:10:15 20:52:33-07:00 + 2015:10:23 16:17:42-07:00 + 2015:10:23 16:17:22-07:00 + rw-rw---- + AI + application/vnd.adobe.illustrator + 1.5 + No + Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00 + application/pdf + 2012:03:22 11:38:02-07:00 + Adobe Illustrator CS4 + 228 + 256 + JPEG + (Binary data 19717 bytes, use -b option to extract) + uuid:19df14ac-2b67-5940-b611-4669665d0d38 + xmp.did:FA7F1174072068119F06ECE830E58C3D + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + uuid:e42563fc-4adb-7949-a074-00702d802691 + xmp.did:F77F1174072068119F06ECE830E58C3D + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + converted, saved, converted, converted, saved, saved, saved, saved, saved, converted, saved, converted, saved, saved, saved, saved, saved, saved, saved, saved, saved, saved, saved, converted, saved, converted, saved, converted, saved, converted, saved, saved, saved, saved, saved, saved, saved, saved, saved + xmp.iid:D27F11740720681191099C3B601C4548, xmp.iid:F97F1174072068118D4ED246B3ADB1C6, xmp.iid:FA7F1174072068118D4ED246B3ADB1C6, xmp.iid:EF7F117407206811A46CA4519D24356B, xmp.iid:F07F117407206811A46CA4519D24356B, xmp.iid:F77F117407206811BDDDFD38D0CF24DD, xmp.iid:F97F117407206811BDDDFD38D0CF24DD, xmp.iid:FA7F117407206811BDDDFD38D0CF24DD, xmp.iid:FB7F117407206811BDDDFD38D0CF24DD, xmp.iid:FC7F117407206811BDDDFD38D0CF24DD, xmp.iid:FD7F117407206811BDDDFD38D0CF24DD, xmp.iid:FE7F117407206811BDDDFD38D0CF24DD, xmp.iid:B233668C16206811BDDDFD38D0CF24DD, xmp.iid:B333668C16206811BDDDFD38D0CF24DD, xmp.iid:B433668C16206811BDDDFD38D0CF24DD, xmp.iid:F77F11740720681197C1BF14D1759E83, xmp.iid:F87F11740720681197C1BF14D1759E83, xmp.iid:F97F11740720681197C1BF14D1759E83, xmp.iid:FA7F117407206811B628E3BF27C8C41B, xmp.iid:FF7F117407206811B628E3BF27C8C41B, xmp.iid:07C3BD25102DDD1181B594070CEB88D9, xmp.iid:F87F1174072068119098B097FDA39BEF, xmp.iid:F77F117407206811BB1DBF8F242B6F84, xmp.iid:F97F117407206811ACAFB8DA80854E76, xmp.iid:0180117407206811834383CD3A8D2303, xmp.iid:01E540664A3DDD11BD33D3EB8D3A1068, xmp.iid:6B6AE2A5723EDD11A6F1BABF7C5A7A51, xmp.iid:0B9FED35200A11689FE8CB9EA85C5459, xmp.iid:F77F1174072068119F06ECE830E58C3D, xmp.iid:FA7F1174072068119F06ECE830E58C3D + 2008:04:17 14:19:15+05:30, 2008:05:15 16:23:06-07:00, 2008:05:15 17:10:45-07:00, 2008:05:15 22:53:33-07:00, 2008:05:15 23:07:07-07:00, 2008:05:16 10:35:43-07:00, 2008:05:16 10:40:59-07:00, 2008:05:16 11:26:55-07:00, 2008:05:16 11:29:01-07:00, 2008:05:16 11:29:20-07:00, 2008:05:16 11:30:54-07:00, 2008:05:16 11:31:22-07:00, 2008:05:16 12:23:46-07:00, 2008:05:16 13:27:54-07:00, 2008:05:16 13:46:13-07:00, 2008:05:16 15:47:57-07:00, 2008:05:16 15:51:06-07:00, 2008:05:16 15:52:22-07:00, 2008:05:22 13:28:01-07:00, 2008:05:22 16:23:53-07:00, 2008:05:28 16:45:26-07:00, 2008:06:02 13:25:25-07:00, 2008:06:09 14:58:36-07:00, 2008:06:11 14:31:27-07:00, 2008:06:11 22:37:35-07:00, 2008:06:18 22:24:01+07:00, 2008:06:19 20:30:34-07:00, 2008:06:26 06:07:42-07:00, 2012:01:21 14:49:33-08:00, 2012:01:23 20:55:59-08:00 + Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4, Adobe Illustrator CS4 + /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, /, / + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + EmbedByReference + /Users/cam/Dropbox/BomberBrewing/cooper126.png + Document + Print + False + False + 1 + 8.500000 + 11.000000 + Inches + HelveticaNeue-BoldCond, HelveticaNeue-BlackCond, HelveticaNeue-ExtBlackCond + Helvetica Neue, Helvetica Neue, Helvetica Neue + 77 Bold Condensed, 97 Black Condensed, 107 Extra Black Condensed + Type 1, Type 1, Type 1 + 001.000, 001.000, 001.000 + False, False, False + HelveNeuBolCon; Helvetica Neue Condensed 2, HelveNeuBlaCon; Helvetica Neue Condensed 1, HelveNeuExtBlaCon; Helvetica Neue Condensed 1 + Black + Brights + 1 + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000004 + 90.000000 + 0.003099 + 0.003099 + 1 + cam andrews, + 69 111 526 632 + 11 + 15 + 2012:01:23 20:56:01-08:00 + Adobe Illustrator CS4 + 2012:03:22 11:38:02-07:00 + Adobe PDF library 9.00 + BBhelmet + 521 + 457 + 457x521 + + + + + + BBhelmet.ai + / + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + true + false + 1080282 + false + true + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + true + true + ai + 2015-10-15 20:52:33 + 20151015 + yyyyMMdd + + HHmmssSSS + application/pdf + null + null + null + unknown + + + A0B6321D33DF4C45A6CFEEA1D364B875 + 7220291B382548FC8353E03F0BAF3E48 + false + BBhelmet + + + Adobe Illustrator CS4 + + Adobe PDF library 9.00 + + + 20120123 + yyyyMMdd + + HHmmssSSS + + + 20120322 + yyyyMMdd + + HHmmssSSS + + false + true + false + false + false + SinglePage + UseNone + + 1.5 + + false + + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/BBhelmet.ai + BBhelmet.ai + 1080282 + 1444967553000 + + + + + + PDF + Portable Document Format + doc + + application/pdf + + + pdf + + + + + + + 2012-01-24T04:56:01Z + + + 2012-03-22T18:38:02Z + + + 2012-03-22T18:38:02Z + + + 2012-01-24T04:56:01Z + + + 2012-03-22T18:38:02Z + + + 2012-03-22T18:38:02Z + + + 2012-03-22T18:38:02Z + + + 1 + + + 2012-01-24T04:56:01Z + + + BBhelmet + + + Mon Jan 23 20:56:01 PST 2012 + + + Adobe PDF library 9.00 + + + application/pdf + + + Adobe Illustrator CS4 + + + 2012-03-22T18:38:02Z + + + BBhelmet + + + + + + + + %transferDirectory%objects/BBhelmet.ai + + + + + + + + + + UUID + e76ac39b-3271-4fc1-ad65-2df74c29449b + + ingestion + 2015-10-23T23:17:28 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4b2bb325-771b-4bd9-9ac6-626507b852de + + message digest calculation + 2015-10-23T23:17:43 + program="python"; module="hashlib.sha256()" + + + + c0fa53ae576cc4381890099a48d5dc3f40733a3415965fb477e79503d7653b5c + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4c625839-4dca-4df1-9a1e-1f57d409fe24 + + virus check + 2015-10-23T23:18:06 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 1253217c-e459-4760-b64f-255352260d9e + + format identification + 2015-10-23T23:19:24 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 8e3ab525-e215-4c5f-afad-79c83c6bfb66 + + fixity check + 2015-10-23T23:27:16 + program="python"; module="hashlib.sha256()" + + Pass + + c0fa53ae576cc4381890099a48d5dc3f40733a3415965fb477e79503d7653b5c verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 15734e00-2c89-4061-b071-4690ebc2c878 + + + 0 + + sha256 + 1c09fba54281f48e81922531c0cd7edc609017b6b498861cd74e8764d2135c88 + + 1001801 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/G31DS-1693db8c-96e1-40cd-85ff-287ba329e626.tif + + derivation + has source + + UUID + 26b0fdea-506b-4bf2-b10e-1e2719859762 + + + UUID + edb7e8c2-143f-4253-b8f5-66d96563bfd2 + + + + + + + + + + + + UUID + 1693db8c-96e1-40cd-85ff-287ba329e626 + + creation + 2015-10-23T23:24:07 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 06dd5844-0006-411c-9660-880ea666753e + + message digest calculation + 2015-10-23T23:24:07 + program="python"; module="hashlib.sha256()" + + + + 1c09fba54281f48e81922531c0cd7edc609017b6b498861cd74e8764d2135c88 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + fd8f2c32-b256-4ff9-bba1-d1f6040402d8 + + fixity check + 2015-10-23T23:27:00 + program="python"; module="hashlib.sha256()" + + Pass + + 1c09fba54281f48e81922531c0cd7edc609017b6b498861cd74e8764d2135c88 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 26b0fdea-506b-4bf2-b10e-1e2719859762 + + + 0 + + sha256 + 99ea9022d2cbb615d0d2b47eeeb44355d12234cb68014a96098c793f22772500 + + 125968 + + + TIFF + + + + PRONOM + fmt/353 + + + + + + 9.90 + G31DS.TIF + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 123 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:17:45+00:00 + 2015:10:23 23:17:22+00:00 + rw-rw---- + TIFF + image/tiff + Big-endian (Motorola, MM) + 2464 + 3248 + 1 + T4/Group 3 Fax + WhiteIsZero + Reversed + /tmp/test.pbm + converted PBM file + (Binary data 98 bytes, use -b option to extract) + Horizontal (normal) + 1 + 200 + (Binary data 89 bytes, use -b option to extract) + 300 + 300 + Chunky + inches + 2464x3248 + 8.0 + + + + + + 284 + 1 + General + General + 0 + 1 + CCITT T.4 + CCITT T.4 + CCITT T.4 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/G31DS.TIF + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + G31DS + TIF + TIFF + TIFF + tiff tif + TIFF + image/tiff + TIFF + TIFF + tiff tif + 125968 + 123 KiB + 123 KiB + 123 KiB + 123 KiB + 123.0 KiB + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + CCITT T.4 + CCITT T.4 + CCITT T.4 + CCITT T.4 + 2464 + 2 464 pixels + 3248 + 3 248 pixels + Y + 1 + 1 bit + 1 + 1 bit + Lossless + Lossless + + + + + + %transferDirectory%objects/G31DS.TIF + + derivation + is source of + + UUID + 15734e00-2c89-4061-b071-4690ebc2c878 + + + UUID + edb7e8c2-143f-4253-b8f5-66d96563bfd2 + + + + + + + + + + + + UUID + 7d5c511d-0747-4cd5-a9c6-207f891ab42b + + ingestion + 2015-10-23T23:17:31 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 172b4bb3-9823-4cdb-aeca-501510708fe7 + + message digest calculation + 2015-10-23T23:17:46 + program="python"; module="hashlib.sha256()" + + + + 99ea9022d2cbb615d0d2b47eeeb44355d12234cb68014a96098c793f22772500 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + e837e09b-a0d0-4a37-b235-265e9216c275 + + virus check + 2015-10-23T23:18:10 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d4b2bc07-aee1-41a6-894c-f94a802c5090 + + format identification + 2015-10-23T23:19:27 + program="File Extension"; version="0.1" + + Positive + + fmt/353 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + daed73e2-3825-49ad-8460-6f978b19b582 + + validation + 2015-10-23T23:20:37 + program="JHOVE"; version="1.6" + + pass + + format="TIFF"; version="4.0"; result="Well-Formed and valid" + + Example event outcome detail extension + + + + + Archivematica user pk + 1 + Preserver + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + Example Object Identifier Type + Example Object Identifier Value + Example Object Role + + + + + + + + + + + UUID + edb7e8c2-143f-4253-b8f5-66d96563bfd2 + + normalization + 2015-10-23T23:24:07 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/G31DS-1693db8c-96e1-40cd-85ff-287ba329e626.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 2429c08e-6af0-46e6-89d2-82bd931120fe + + fixity check + 2015-10-23T23:27:15 + program="python"; module="hashlib.sha256()" + + Pass + + 99ea9022d2cbb615d0d2b47eeeb44355d12234cb68014a96098c793f22772500 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + c65e1dfd-1ce5-46de-aa3e-e75f4f83575b + + + 0 + + sha256 + ba390814f958e7e48cf88c034a43879bfeda5e13136ba6bca19db455f2d9f5f3 + + 2176316 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/Nemastylis_geminiflora_Flower-f1c7562e-3914-4897-af56-1d59e0ca368e.tif + + derivation + has source + + UUID + 9836449f-f655-4aaa-84a2-b942eb9e92f0 + + + UUID + c0361352-9a59-4dde-b13b-5c4940e08494 + + + + + + + + + + + + UUID + f1c7562e-3914-4897-af56-1d59e0ca368e + + creation + 2015-10-23T23:23:54 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 90b22d21-1e02-44b8-bedf-43476d1d1383 + + message digest calculation + 2015-10-23T23:23:54 + program="python"; module="hashlib.sha256()" + + + + ba390814f958e7e48cf88c034a43879bfeda5e13136ba6bca19db455f2d9f5f3 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d109a809-1cea-4599-8fb6-7fad29921560 + + fixity check + 2015-10-23T23:26:52 + program="python"; module="hashlib.sha256()" + + Pass + + ba390814f958e7e48cf88c034a43879bfeda5e13136ba6bca19db455f2d9f5f3 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 9836449f-f655-4aaa-84a2-b942eb9e92f0 + + + 0 + + sha256 + 0992e4174b21ed2a7f5fe909206f7ae73455a3444dab5410b4271e7e00a1d304 + + 2050617 + + + Generic PNG + + + + Archivematica Format Policy Registry + .png + + + + + + + + + + + + + + + + + + + + + + + + + + + 9.90 + Nemastylis_geminiflora_Flower.PNG + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 2003 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:17:45+00:00 + 2015:10:23 23:17:22+00:00 + rw-rw---- + PNG + image/png + 757 + 957 + 8 + RGB + Deflate/Inflate + Adaptive + Noninterlaced + +AAAAAA== + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 757x957 + 0.724 + + + + + + 284 + 1 + General + General + 0 + 1 + PNG + PNG + PNG + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/Nemastylis_geminiflora_Flower.PNG + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + Nemastylis_geminiflora_Flower + PNG + PNG + PNG + Portable Network Graphic + png + PNG + image/png + PNG + PNG + Portable Network Graphic + png + 2050617 + 1.96 MiB + 2 MiB + 2.0 MiB + 1.96 MiB + 1.956 MiB + 0 + 0.00 Byte (0%) + Byte0 + 0.0 Byte + 0.00 Byte + 0.000 Byte + 0.00 Byte (0%) + 0.00000 + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + PNG + Portable Network Graphic + PNG + LZ77 + image/png + PNG + PNG + 757 + 757 pixels + 957 + 957 pixels + 24 + 24 bits + 24 + 24 bits + Lossless + Lossless + 2050617 + 1.96 MiB (100%) + 2 MiB + 2.0 MiB + 1.96 MiB + 1.956 MiB + 1.96 MiB (100%) + 1.00000 + + + + + + %transferDirectory%objects/Nemastylis_geminiflora_Flower.PNG + + derivation + is source of + + UUID + c65e1dfd-1ce5-46de-aa3e-e75f4f83575b + + + UUID + c0361352-9a59-4dde-b13b-5c4940e08494 + + + + + + + + + + + + UUID + 0a85d128-d314-43fe-9a6b-86f2efcc3406 + + ingestion + 2015-10-23T23:17:31 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 60f574ac-ba7c-48e7-a371-3b9ecb95f04e + + message digest calculation + 2015-10-23T23:17:45 + program="python"; module="hashlib.sha256()" + + + + 0992e4174b21ed2a7f5fe909206f7ae73455a3444dab5410b4271e7e00a1d304 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 41138a88-33c8-47ce-9ad3-eb4e3a754c67 + + virus check + 2015-10-23T23:18:13 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + fe4a884b-a570-468c-9785-a3dac118ae64 + + format identification + 2015-10-23T23:19:27 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + c0361352-9a59-4dde-b13b-5c4940e08494 + + normalization + 2015-10-23T23:23:54 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/Nemastylis_geminiflora_Flower-f1c7562e-3914-4897-af56-1d59e0ca368e.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 238a418d-cf70-43d9-857e-3ce2e100dd54 + + fixity check + 2015-10-23T23:26:40 + program="python"; module="hashlib.sha256()" + + Pass + + 0992e4174b21ed2a7f5fe909206f7ae73455a3444dab5410b4271e7e00a1d304 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 57a612fb-44d5-47aa-b178-1c19bb532c81 + + + 0 + + sha256 + 734f68af433324b649fd67efd8c565374f1d6d05064480e01d2daaff000aa661 + + 33553 + + + Generic SVG + + + + + + + + + + %SIPDirectory%objects/Vector.NET-Free-Vector-Art-Pack-28-Freedom-Flight-28fcaca8-30f1-4036-98e0-45fd3c798c8e.svg + + derivation + has source + + UUID + 2159dba2-9e5f-49ff-b4c9-5d1b395d2811 + + + UUID + dc80466a-e891-4943-a4a4-51478c2d1e2b + + + + + + + + + + + + UUID + 28fcaca8-30f1-4036-98e0-45fd3c798c8e + + creation + 2015-10-23T23:24:00 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 0792a9eb-8985-4333-8318-9be1dd70c619 + + message digest calculation + 2015-10-23T23:24:00 + program="python"; module="hashlib.sha256()" + + + + 734f68af433324b649fd67efd8c565374f1d6d05064480e01d2daaff000aa661 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 9b073d89-99c7-4a9d-8cca-630051a6ce64 + + fixity check + 2015-10-23T23:27:11 + program="python"; module="hashlib.sha256()" + + Pass + + 734f68af433324b649fd67efd8c565374f1d6d05064480e01d2daaff000aa661 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 2159dba2-9e5f-49ff-b4c9-5d1b395d2811 + + + 0 + + sha256 + 32b57788590a44246ce1a5e9b59c7b9a85846bd38ee48d60e08001c8db1dd363 + + 1041114 + + + Generic EPS + + + + Archivematica Format Policy Registry + .eps + + + + + + 9.90 + Vector.NET-Free-Vector-Art-Pack-28-Freedom-Flight.eps + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 1017 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:17:48+00:00 + 2015:10:23 23:17:22+00:00 + rw-rw---- + EPS + application/postscript + Little-endian (Intel, II) + (Binary data 881762 bytes, use -b option to extract) + Adobe Illustrator(R) 8.0 + + + gig + + + + freedom5.eps + 3/12/2010 3:14 PM + 0 52 596 790 + Adobe Illustrator (R) Version 5.0 Level 2 Emulation + 1.2 0 + + + 04/10/93 + + + + (C) 1987-1996 Adobe Systems Incorporated All Rights Reserved + Adobe Illustrator (R) Version 8.0 Full Prolog + 1.3 0 + + + 3/7/1994 + + + + (C) 1987-1998 Adobe Systems Incorporated All Rights Reserved + Adobe Illustrator (R) Version 5.0 Pattern Operators + 1.1 0 + + + 03/26/93 + + + + (C) 1987-1996 Adobe Systems Incorporated All Rights Reserved + Writing System Operators + 2.0 8 + + + 1/23/89 + + + + (C) 1992-1996 Adobe Systems Incorporated All Rights Reserved + Adobe Illustrator 8 Shading Procset + 1.0 0 + + + 12/17/97 + + + + (C) 1987-1997 Adobe Systems Incorporated All Rights Reserved + Full-resolution Image + 596 + 738 + 8 + Uncompressed + RGB Palette + 2 + Chunky + 159364 + 879696 + (Binary data 1536 bytes, use -b option to extract) + Associated Alpha + Path + 738 + 596 + 596x738 + 0.440 + + + + + %transferDirectory%objects/Vector.NET-Free-Vector-Art-Pack-28-Freedom-Flight.eps + + derivation + is source of + + UUID + 57a612fb-44d5-47aa-b178-1c19bb532c81 + + + UUID + dc80466a-e891-4943-a4a4-51478c2d1e2b + + + + + + + + + + + + UUID + fea38c01-f498-4454-896d-fc3ac479065a + + ingestion + 2015-10-23T23:17:35 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 5922a5ac-fdba-411b-825d-1837ea0dc0c4 + + message digest calculation + 2015-10-23T23:17:48 + program="python"; module="hashlib.sha256()" + + + + 32b57788590a44246ce1a5e9b59c7b9a85846bd38ee48d60e08001c8db1dd363 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 112a3782-d365-4e1e-bb09-ac193f455f92 + + virus check + 2015-10-23T23:18:16 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + a5460bbd-89ae-4197-b33d-69e427533bf7 + + format identification + 2015-10-23T23:19:31 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + dc80466a-e891-4943-a4a4-51478c2d1e2b + + normalization + 2015-10-23T23:24:00 + ArchivematicaFPRCommandID="64c450b4-135c-46d1-a9aa-3f9b15671677"; program="inkscape"; version="Inkscape 0.48.4 r9939 (Jan 22 2014)" + + + + + %SIPDirectory%objects/Vector.NET-Free-Vector-Art-Pack-28-Freedom-Flight-28fcaca8-30f1-4036-98e0-45fd3c798c8e.svg + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + f864982b-2871-44cc-9c8e-3bfd5d8789ce + + fixity check + 2015-10-23T23:26:43 + program="python"; module="hashlib.sha256()" + + Pass + + 32b57788590a44246ce1a5e9b59c7b9a85846bd38ee48d60e08001c8db1dd363 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 60110e22-8cbe-4403-a0cd-d4d07db91105 + + + 0 + + sha256 + d1d42ab7c3df15b1ca94c40885794d6a9843827e969a6b2c98041b1d6e031667 + + 209005 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/WFPC01-7bf291cc-9a46-4ee7-97d3-66d0f11674f7.tif + + derivation + has source + + UUID + da4d5e8a-7c0d-48b7-9535-22b1e15c1e5c + + + UUID + 4402a1af-e960-454d-b22d-eeddb1cd6443 + + + + + + + + + + + + UUID + 7bf291cc-9a46-4ee7-97d3-66d0f11674f7 + + creation + 2015-10-23T23:24:12 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + a1674e61-67b5-4e7f-9e17-7d9783655c84 + + message digest calculation + 2015-10-23T23:24:12 + program="python"; module="hashlib.sha256()" + + + + d1d42ab7c3df15b1ca94c40885794d6a9843827e969a6b2c98041b1d6e031667 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 0d59c4e3-5e58-40b3-aa90-0c86cff1eb4e + + fixity check + 2015-10-23T23:27:04 + program="python"; module="hashlib.sha256()" + + Pass + + d1d42ab7c3df15b1ca94c40885794d6a9843827e969a6b2c98041b1d6e031667 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + da4d5e8a-7c0d-48b7-9535-22b1e15c1e5c + + + 0 + + sha256 + 35e0cc683d75704fc5b04fc3633f6c654e10cd3af57471271f370309c7ff9dba + + 113318 + + + Generic gif + + + + Archivematica Format Policy Registry + .gif + + + + + + + + + + + + + + + + + + + + + + + + + + + 9.90 + WFPC01.GIF + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 111 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:17:50+00:00 + 2015:10:23 23:17:22+00:00 + rw-rw---- + GIF + image/gif + +UFVCTElDIElORk9STUFUSU9OIE9GRklDRQ0KSkVUIFBST1BVTFNJT04gTEFC +T1JBVE9SWQ0KQ0FMSUZPUk5JQSBJTlNUSVRVVEUgT0YgVEVDSE5PTE9HWQ0K +TkFUSU9OQUwgQUVST05BVVRJQ1MgQU5EIFNQQUNFIEFETUlOSVNUUkFUSU9O +DQpQQVNBREVOQSwgQ0FMSUYuIDkxMTA5LiBURUxFUEhPTkUgKDgxOCkgMzU0 +LTUwMTENCg0KUEhPVE8gQ0FQVElPTiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgIEphbnVhcnkgMTMsIDE5OTQNCg0KVGhpcyBjb21wYXJp +c29uIGltYWdlIG9mIHRoZSBjb3JlIG9mIHRoZSBnYWxheHkgTTEwMCBzaG93 +cyB0aGUNCmRyYW1hdGljIGltcHJvdmVtZW50IGluIHRoZSBIdWJibGUgU3Bh +Y2UgVGVsZXNjb3BlJ3MgdmlldyBvZiB0aGUNCnVuaXZlcnNlLiAgVGhlIG5l +dyBpbWFnZSwgdGFrZW4gd2l0aCB0aGUgc2Vjb25kLWdlbmVyYXRpb24gV2lk +ZQ0KZmllbGQgYW5kIFBsYW5ldGFyeSBDYW1lcmEgKFdGUEMtSUkpIGluc3Rh +bGxlZCBkdXJpbmcgdGhlIFNUUy02MQ0KSHViYmxlIHNlcnZpY2luZyBtaXNz +aW9uLCBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgY2FtZXJhJ3MNCmNvcnJlY3Rp +dmUgb3B0aWNzIGNvbXBlbnNhdGUgZnVsbHkgZm9yIG9wdGljYWwgYWJlcnJh +dGlvbiBpbg0KSHViYmxlJ3MgcHJpbWFyeSBtaXJyb3IuICBXaXRoIHRoZSBu +ZXcgY2FtZXJhLCB0aGUgSHViYmxlIHdpbGwNCnByb2JlIHRoZSB1bml2ZXJz +ZSB3aXRoIHVucHJlY2VkZW50ZWQgY2xhcml0eSBhbmQgc2Vuc2l0aXZpdHks +DQphbmQgZnVsZmlsbCBpdHMgbW9zdCBpbXBvcnRhbnQgc2NpZW50aWZpYyBv +YmplY3RpdmVzIGZvciB3aGljaA0KdGhlIHRlbGVzY29wZSB3YXMgb3JpZ2lu +YWxseSBidWlsdC4NCg0KQXQgcmlnaHQgaXMgdGhlIGNvcmUgb2YgdGhlIGdy +YW5kIGRlc2lnbiBzcGlyYWwgZ2FsYXh5IE0xMDAsIGFzDQppbWFnZWQgYnkg +V0ZQQy1JSSBpbiBpdHMgaGlnaC1yZXNvbHV0aW9uIGNoYW5uZWwuICBXRlBD +LUlJJ3MNCm1vZGlmaWVkIG9wdGljcyBjb3JyZWN0IGZvciBIdWJibGUncyBw +cmV2aW91c2x5IGJsdXJyeSB2aXNpb24sDQphbGxvd2luZyB0aGUgdGVsZXNj +b3BlIGZvciB0aGUgZmlyc3QgdGltZSB0byBjbGVhbmx5IHJlc29sdmUNCmZh +aW50IHN0cnVjdHVyZSBhcyBzbWFsbCBhcyAzMCBsaWdodC15ZWFycyBhY3Jv +c3MgaW4gYSBnYWxheHkNCnRlbnMgb2YgbWlsbGlvbnMgb2YgbGlnaHQteWVh +cnMgYXdheS4gIFRoZSBpbWFnZSB3YXMgdGFrZW4gb24NCkRlY2VtYmVyIDMx +LCAxOTkzLg0KDQpGb3IgY29tcGFyaXNvbiwgYXQgbGVmdCBpcyBhIHBpY3R1 +cmUgdGFrZW4gd2l0aCB0aGUgV0ZQQy1JIGNhbWVyYQ0KaW4gd2lkZS1maWVs +ZCBtb2RlIG9uIE5vdmVtYmVyIDI3LCAxOTkzLCBqdXN0IGEgZmV3IGRheXMg +YmVmb3JlDQp0aGUgU1RTLTYxIHNlcnZpY2luZyBtaXNzaW9uLiAgVGhlIGVm +ZmVjdHMgb2Ygb3B0aWNhbCBhYmVycmF0aW9uDQppbiB0aGUgdGVsZXNjb3Bl +J3MgMi40LW1ldGVyIHByaW1hcnkgbWlycm9yIGJsdXIgc3RhcmxpZ2h0LCBz +bWVhcg0Kb3V0IGZpbmUgZGV0YWlsIGFuZCBsaW1pdCB0aGUgdGVsZXNjb3Bl +J3MgYWJpbGl0eSB0byBzZWUgZmFpbnQNCnN0cnVjdHVyZS4NCg0KQm90aCBI +dWJibGUgaW1hZ2VzIGFyZSAicmF3IjsgdGhleSBoYXZlIG5vdCBiZWVuIHBy +b2Nlc3NlZCB1c2luZw0KY29tcHV0ZXIgaW1hZ2UgcmVjb25zdHJ1Y3Rpb24g +dGVjaG5pcXVlcyB0aGF0IGltcHJvdmVkIGFiZXJyYXRlZA0KaW1hZ2VzIG1h +ZGUgYmVmb3JlIHRoZSBzZXJ2aWNpbmcgbWlzc2lvbi4NCg0KVGhlIEpldCBQ +cm9wdWxzaW9uIExhYm9yYXRvcnkgZGV2ZWxvcGVkIHRoZSBXaWRlIEZpZWxk +IGFuZA0KUGxhbmV0YXJ5IENhbWVyYS1JSSBmb3IgTkFTQSdzIE9mZmljZSBv +ZiBTcGFjZSBTY2llbmNlLg0KDQogICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAjIyMjIw0KTlCTqUo= + + 89a + 640 + 320 + Yes + 8 + 8 + 0 + 640x320 + 0.205 + + + + + + 284 + 1 + General + General + 0 + 1 + GIF + GIF + GIF89a + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/WFPC01.GIF + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + WFPC01 + GIF + GIF + GIF + Graphics Interchange Format + gif + GIF + image/gif + GIF + GIF + Graphics Interchange Format + gif + 113318 + 111 KiB + 111 KiB + 111 KiB + 111 KiB + 110.7 KiB + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + GIF + Graphics Interchange Format + GIF + 89a + image/gif + GIF89a + GIF89a + 640 + 640 pixels + 320 + 320 pixels + Lossless + Lossless + + + + + + %transferDirectory%objects/WFPC01.GIF + + derivation + is source of + + UUID + 60110e22-8cbe-4403-a0cd-d4d07db91105 + + + UUID + 4402a1af-e960-454d-b22d-eeddb1cd6443 + + + + + + + + + + + + UUID + d708301c-f3ab-42d1-a568-56f931de45db + + ingestion + 2015-10-23T23:17:36 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 796b203a-3e8b-49b5-8e0a-eb46a8674644 + + message digest calculation + 2015-10-23T23:17:51 + program="python"; module="hashlib.sha256()" + + + + 35e0cc683d75704fc5b04fc3633f6c654e10cd3af57471271f370309c7ff9dba + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 0512cb78-19ef-4e82-98c9-97044060e6ba + + virus check + 2015-10-23T23:18:19 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + edadc34c-f039-4f82-adfd-9b4acc9f86d3 + + format identification + 2015-10-23T23:19:34 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 972cacc3-d646-4e17-8b9b-519e3da525b7 + + validation + 2015-10-23T23:20:47 + program="JHOVE"; version="1.6" + + pass + + format="GIF"; version="89a"; result="Well-Formed and valid" + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4402a1af-e960-454d-b22d-eeddb1cd6443 + + normalization + 2015-10-23T23:24:12 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/WFPC01-7bf291cc-9a46-4ee7-97d3-66d0f11674f7.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 62b608f1-7864-4fbd-8c3e-8c3ae2ee3dcf + + fixity check + 2015-10-23T23:27:08 + program="python"; module="hashlib.sha256()" + + Pass + + 35e0cc683d75704fc5b04fc3633f6c654e10cd3af57471271f370309c7ff9dba verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + c0803066-1d6d-42f4-ac42-814c3e77cd77 + + + 0 + + sha256 + 19e6834dfc3fe0e71263bb478fed085e31cc8dc54b36e58ced0beec0a0189a3a + + 23625 + + + Generic SVG + + + + + + + + + + %SIPDirectory%objects/lion-b14f6df1-0365-44f2-a843-6ef8bf05a9bf.svg + + derivation + has source + + UUID + dd8ed402-b199-4fea-8676-92d5b89ceca2 + + + UUID + d28961f1-62f9-4573-9b57-f1d8d002e34d + + + + + + + + + + + + UUID + b14f6df1-0365-44f2-a843-6ef8bf05a9bf + + creation + 2015-10-23T23:24:09 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 940ad887-6fa4-4cd2-84c1-367d36ebf439 + + message digest calculation + 2015-10-23T23:24:09 + program="python"; module="hashlib.sha256()" + + + + 19e6834dfc3fe0e71263bb478fed085e31cc8dc54b36e58ced0beec0a0189a3a + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + a9eef1bb-88b8-496d-a7b1-88d1daed385c + + fixity check + 2015-10-23T23:27:12 + program="python"; module="hashlib.sha256()" + + Pass + + 19e6834dfc3fe0e71263bb478fed085e31cc8dc54b36e58ced0beec0a0189a3a verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + dd8ed402-b199-4fea-8676-92d5b89ceca2 + + + 0 + + sha256 + f78615cd834f7fb84832177e73f13e3479f5b5b22ae7a9506c7fa0a14fd9df9e + + 18324 + + + Generic SVG + + + + Archivematica Format Policy Registry + .svg + + + + + + + + + + + + + 2015:10:15 20:52:33-07:00 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + lion.svg + 18324 + 1444967553000 + + + + + SVG + + + + + + SVG Scalable Vector Graphics image +image/svg+xml; charset=us-ascii + image/svg+xml + SVG Scalable Vector Graphics image + + + + + ExifToolVersion 9.13 +FileName lion.svg +Directory /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects +FileSize 18 kB +FileModifyDate 2015:10:15 20:52:33-07:00 +FileAccessDate 2015:10:23 16:17:42-07:00 +FileInodeChangeDate 2015:10:23 16:17:22-07:00 +FilePermissions rw-rw---- +FileType SVG +MIMEType image/svg+xml +Xmlns http://www.w3.org/2000/svg +ImageWidth 15cm +ImageHeight 15cm +ImageSize 15cmx15cm + 9.13 + lion.svg + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 18 kB + 2015:10:15 20:52:33-07:00 + 2015:10:23 16:17:42-07:00 + 2015:10:23 16:17:22-07:00 + rw-rw---- + SVG + image/svg+xml + http://www.w3.org/2000/svg + 15cm + 15cm + 15cmx15cm + + + + + + lion.svg + / + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + true + false + 18324 + false + true + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + true + true + svg + 2015-10-15 20:52:33 + 20151015 + yyyyMMdd + + HHmmssSSS + application/xml + null + null + null + unknown + + + 1.0 + unspecified + unspecified + svg + http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd + -//W3C//DTD SVG 1.1//EN + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/lion.svg + lion.svg + 18324 + 1444967553000 + + + + + + XML + Extensible Markup Language + doc + + text/xml + + + xml + + + + + + + image/svg+xml + + + + + + + + %transferDirectory%objects/lion.svg + + derivation + is source of + + UUID + c0803066-1d6d-42f4-ac42-814c3e77cd77 + + + UUID + d28961f1-62f9-4573-9b57-f1d8d002e34d + + + + + + + + + + + + UUID + 11404ae2-80e9-42f9-9ff0-069aeee9d92a + + ingestion + 2015-10-23T23:17:28 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + bfeba77b-c577-4ef5-bdcb-d69f9dbf3b6d + + message digest calculation + 2015-10-23T23:17:43 + program="python"; module="hashlib.sha256()" + + + + f78615cd834f7fb84832177e73f13e3479f5b5b22ae7a9506c7fa0a14fd9df9e + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + ad0de9ce-7082-4050-969d-5ea36ef312d6 + + virus check + 2015-10-23T23:18:09 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 3a6b7bba-0ab8-4f61-9358-aab937a4696f + + format identification + 2015-10-23T23:19:24 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d28961f1-62f9-4573-9b57-f1d8d002e34d + + normalization + 2015-10-23T23:24:09 + ArchivematicaFPRCommandID="64c450b4-135c-46d1-a9aa-3f9b15671677"; program="inkscape"; version="Inkscape 0.48.4 r9939 (Jan 22 2014)" + + + + + %SIPDirectory%objects/lion-b14f6df1-0365-44f2-a843-6ef8bf05a9bf.svg + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 3a5b50a3-9220-4536-950d-18cdd583ed0b + + fixity check + 2015-10-23T23:26:56 + program="python"; module="hashlib.sha256()" + + Pass + + f78615cd834f7fb84832177e73f13e3479f5b5b22ae7a9506c7fa0a14fd9df9e verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 275ee03e-dcae-44b8-b48a-ce8c27ae1392 + + + 0 + + sha256 + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 + + 408 + + + Unknown + + + + + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + dc.json + 408 + 1445642515000 + + + + + US-ASCII + + + + + + ASCII text, with very long lines, with no line terminators +text/plain; charset=us-ascii + text/plain + Plain text + US-ASCII + no + + + + + ExifToolVersion 9.13 +FileName dc.json +Directory /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata +FileSize 408 bytes +FileModifyDate 2015:10:23 16:21:55-07:00 +FileAccessDate 2015:10:23 16:26:11-07:00 +FileInodeChangeDate 2015:10:23 16:24:42-07:00 +FilePermissions rw-rw---- +Error Unknown file type + 9.13 + dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata + 408 bytes + 2015:10:23 16:21:55-07:00 + 2015:10:23 16:26:11-07:00 + 2015:10:23 16:24:42-07:00 + rw-rw---- + Unknown file type + + + + + + dc.json + / + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + true + false + 408 + false + true + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + true + true + json + 2015-10-23 16:21:55 + 20151023 + yyyyMMdd + + HHmmssSSS + file/unknown + null + null + null + unknown + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/dc.json + dc.json + 408 + 1445642515000 + + + + + + + Unknown Binary + + + application/octet-stream + + + + + + + + ISO-8859-1 + + + text/plain; charset=ISO-8859-1 + + + + + + + + %SIPDirectory%objects/metadata/dc.json + + + + + + + + + + UUID + df8ec5f7-6c38-4955-97b1-93f6fafcd737 + + ingestion + 2015-10-23T23:26:08 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4e08de6c-e186-412c-8f37-a56d0ee7904b + + message digest calculation + 2015-10-23T23:26:12 + program="python"; module="hashlib.sha256()" + + + + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 39fb43f7-066f-44e5-b25a-c964559b4876 + + virus check + 2015-10-23T23:26:19 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + b4f5f1a7-1560-43de-85ba-02d7ec0c7f4b + + fixity check + 2015-10-23T23:27:08 + program="python"; module="hashlib.sha256()" + + Pass + + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 1e2346ef-e183-44ef-8124-b8d23852e8a2 + + + 0 + + sha256 + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 + + 408 + + + Unknown + + + + + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + dc.json + 408 + 1445642762000 + + + + + US-ASCII + + + + + + ASCII text, with very long lines, with no line terminators +text/plain; charset=us-ascii + text/plain + Plain text + US-ASCII + no + + + + + ExifToolVersion 9.13 +FileName dc.json +Directory /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd +FileSize 408 bytes +FileModifyDate 2015:10:23 16:26:02-07:00 +FileAccessDate 2015:10:23 16:26:11-07:00 +FileInodeChangeDate 2015:10:23 16:26:02-07:00 +FilePermissions rw-r--r-- +Error Unknown file type + 9.13 + dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + 408 bytes + 2015:10:23 16:26:02-07:00 + 2015:10:23 16:26:11-07:00 + 2015:10:23 16:26:02-07:00 + rw-r--r-- + Unknown file type + + + + + + dc.json + / + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + true + false + 408 + false + true + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + true + true + json + 2015-10-23 16:26:02 + 20151023 + yyyyMMdd + + HHmmssSSS + file/unknown + null + null + null + unknown + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + dc.json + 408 + 1445642762000 + + + + + + + Unknown Binary + + + application/octet-stream + + + + + + + + ISO-8859-1 + + + text/plain; charset=ISO-8859-1 + + + + + + + + %SIPDirectory%objects/metadata/transfers/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/dc.json + + + + + + + + + + UUID + 2eaae5f0-bdd7-4976-9534-b54ecbf348d5 + + ingestion + 2015-10-23T23:26:07 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 2e2c69b6-6377-46f8-ab83-065da4b018d9 + + message digest calculation + 2015-10-23T23:26:12 + program="python"; module="hashlib.sha256()" + + + + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 3580d7c9-6e90-4ef3-b11a-513b0d0a04f5 + + virus check + 2015-10-23T23:26:18 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + a249b830-f659-4e88-a2e2-bdee144c2452 + + fixity check + 2015-10-23T23:27:00 + program="python"; module="hashlib.sha256()" + + Pass + + b23087b26876dcfe78546dc13cb5c787c5da6872ed4ef8782ffc4916d88ea313 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 4ee4365a-70dd-4c8a-98a9-976c76096b0c + + + 0 + + sha256 + 09553442c02a1a52b756ab4b7f5f695af3e3ada114d0409e253e93094ff47929 + + 1586860 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/oakland03-39108830-3e30-4aa2-8982-f1190290cfd9.tif + + derivation + has source + + UUID + e9400f17-5535-40bf-909b-e990fb9c2037 + + + UUID + a428bcc3-43bf-49e7-9da6-074a9d1b87eb + + + + + + + + + + + + UUID + 39108830-3e30-4aa2-8982-f1190290cfd9 + + creation + 2015-10-23T23:24:03 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + c32818d4-7fe5-401a-99c4-18357f42f5f3 + + message digest calculation + 2015-10-23T23:24:03 + program="python"; module="hashlib.sha256()" + + + + 09553442c02a1a52b756ab4b7f5f695af3e3ada114d0409e253e93094ff47929 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + e75d6592-6885-43e6-9d26-f64ddc588c6c + + fixity check + 2015-10-23T23:26:43 + program="python"; module="hashlib.sha256()" + + Pass + + 09553442c02a1a52b756ab4b7f5f695af3e3ada114d0409e253e93094ff47929 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + e9400f17-5535-40bf-909b-e990fb9c2037 + + Example object category + + Example preservation level value + Example preservation level role + Example preservation level rationale + Example preservation level date + + + Example significant property type + Example significant property value + + Example significant property extension + + + + 0 + + sha256 + d10bbb2cddc343cd50a304c21e67cb9d5937a93bcff5e717de2df65e0a6309d6 + Example message digest originator + + 527345 + + + JP2 (JPEG 2000 part 1) + Example format version + + + PRONOM + x-fmt/392 + Example registry role + + Example format note #1 + Example format note #2 + + + Example creating application name + Example creating application version + Example creating application create date + + Example creating application extension #1 + + + Example creating application extension #2 + + + + Example inhibitor type + Example inhibitor target #1 + Example inhibitor target #2 + Example inhibitor key + + + + + + + + + + + + + + + + + + + + + + + + + + 9.90 + oakland03.jp2 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + 515 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:17:47+00:00 + 2015:10:23 23:17:22+00:00 + rw-rw---- + JP2 + image/jp2 + JPEG 2000 Image (.JP2) + 0.0.0 + + + jp2 + + + 582 + 906 + 3 + 8 Bits, Unsigned + JPEG 2000 + Enumerated + 0 + Not Specified + sRGB + 906x582 + 0.527 + + + + + + 284 + 1 + General + General + 0 + 1 + JPEG 2000 + JPEG 2000 + JPEG 2000 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/oakland03.jp2 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects + oakland03 + jp2 + JPEG 2000 + JPEG 2000 + http://www.morgan-multimedia.com/JPEG 2000/ + jp2 + JPEG 2000 + MPEG-4 + image/jp2 + jp2 + JPEG 2000 + JPEG 2000 + http://www.morgan-multimedia.com/JPEG 2000/ + jp2 + 527345 + 515 KiB + 515 KiB + 515 KiB + 515 KiB + 515.0 KiB + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + JPEG 2000 + http://www.morgan-multimedia.com/JPEG 2000/ + JPEG 2000 + image/jp2 + JPEG 2000 + JPEG 2000 + 906 + 906 pixels + 582 + 582 pixels + RGB + 4:4:4 + 8 + 8 bits + 8 + 8 bits + + + + + + %transferDirectory%objects/oakland03.jp2 + + + Example storage content location type + Example storage content location value + + Examploe storage medium + + + Example environment characteristic + Example environment purpose #1 + Example environment purpose #2 + Example environment note #1 + Example environment note #2 + + Example environment dependency name + + Example environment dependency identifier type + Example environment dependency identifier value + + + + Example environment software name + Example environment software version + Example environment software type + Example environment software other information #1 + Example environment software other information #2 + Example environment software dependency #1 + Example environment software dependency #2 + + + Example environment hardware name + Example environment hardware type + Example environment hardware other information #1 + Example environment hardware other information #2 + + + Example environment extension #1 + + + Example environment extension #2 + + + + + Example signature encoding + Example signature signer + Example signature method + Example signature value + Example signature validation rules + Example signature property #1 + Example signature property #2 + Example signature key information + + + Example signature information extension + + + + derivation + is source of + + UUID + 4ee4365a-70dd-4c8a-98a9-976c76096b0c + Example related object sequence + + + UUID + a428bcc3-43bf-49e7-9da6-074a9d1b87eb + Example related event sequence + + + + Example linking event identifier type + Example linking event identifier value + + + Example linking entity identifier type + Example linking entity identifier value + + + Example linking rights statement identifier type + Example linking rights statement identifier value + + + + + + + + + + + UUID + 005447a2-76e5-4a2a-968c-77e43bfa1d0f + + ingestion + 2015-10-23T23:17:34 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 6e0ad93f-425f-4228-9281-a2d1fdd6d42f + + message digest calculation + 2015-10-23T23:17:48 + program="python"; module="hashlib.sha256()" + + + + d10bbb2cddc343cd50a304c21e67cb9d5937a93bcff5e717de2df65e0a6309d6 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + e6f1c0cf-4b24-407b-9f85-7686f1ef3064 + + virus check + 2015-10-23T23:18:13 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 9bd81a7f-2443-48a7-81c8-5ae786ba6662 + + format identification + 2015-10-23T23:19:31 + program="File Extension"; version="0.1" + + Positive + + x-fmt/392 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 18a9d3d2-dafe-4c0e-98fe-e3a7c6ae46af + + validation + 2015-10-23T23:20:42 + program="JHOVE"; version="1.6" + + pass + + format="JPEG 2000"; result="Well-Formed and valid" + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + a428bcc3-43bf-49e7-9da6-074a9d1b87eb + + normalization + 2015-10-23T23:24:03 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/oakland03-39108830-3e30-4aa2-8982-f1190290cfd9.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + b7e039ff-717b-4862-9784-52bf4c9bf853 + + fixity check + 2015-10-23T23:26:47 + program="python"; module="hashlib.sha256()" + + Pass + + d10bbb2cddc343cd50a304c21e67cb9d5937a93bcff5e717de2df65e0a6309d6 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + e8137104-96d4-406c-a050-473ab3754136 + + + 0 + + sha256 + 4eaa9dd92d9ae76d876e511e6ca6d02edcacb89ea3cae444a48de2e09718fb34 + + 29965168 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/pictures/Landing_zone-67c12724-bfbe-4fb8-a8a6-fb2d4c6a14e4.tif + + derivation + has source + + UUID + 5d18cfb6-d433-466f-a6e9-7d6390b5debe + + + UUID + 0da1f58e-a68d-43b2-a65b-09c184f94be5 + + + + + + + + + + + + UUID + 67c12724-bfbe-4fb8-a8a6-fb2d4c6a14e4 + + creation + 2015-10-23T23:24:04 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + e66914f5-1f84-4073-9c3c-fcf01fe27aac + + message digest calculation + 2015-10-23T23:24:05 + program="python"; module="hashlib.sha256()" + + + + 4eaa9dd92d9ae76d876e511e6ca6d02edcacb89ea3cae444a48de2e09718fb34 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + b41ef55d-e1e2-4d9d-8f04-610a3415f1b0 + + fixity check + 2015-10-23T23:26:48 + program="python"; module="hashlib.sha256()" + + Pass + + 4eaa9dd92d9ae76d876e511e6ca6d02edcacb89ea3cae444a48de2e09718fb34 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 5d18cfb6-d433-466f-a6e9-7d6390b5debe + + + 0 + + sha256 + a469c730e705d757d66f53f38bb4455e89d5691a3d87fc7bc069b91fa2a50d46 + + 1361321 + + + Generic JPEG + + + + Archivematica Format Policy Registry + .jpg + + + + + + + + + + + + + + + + + + + + + + + + + + + 9.90 + [minor] Possibly incorrect maker notes offsets (fix by -74?) + Landing_zone.jpg + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/pictures + 1329 kB + 2015:10:16 03:52:33+00:00 + 2015:10:23 23:19:52+00:00 + 2015:10:23 23:18:27+00:00 + rw-rw---- + JPEG + image/jpeg + Little-endian (Intel, II) + 3648 + 2736 + Baseline DCT, Huffman coding + 8 + 3 + YCbCr4:2:0 (2 2) + 1.01 + inches + 72 + 72 + Panasonic + DMC-FS20 + Horizontal (normal) + 72 + 72 + inches + GIMP 2.4.7 + 2008:09:15 11:01:51 + Co-sited + 1/250 + 4.0 + Landscape + 100 + 0221 + 2008:09:10 16:51:18 + 2008:09:10 16:51:18 + Y, Cb, Cr, - + 4 + 0 + 3.3 + Multi-segment + Unknown + Off, Did not fire + 5.2 mm + 0100 + sRGB + 3648 + 2736 + One-chip color area + Digital Camera + Directly photographed + Normal + Auto + Auto + 0 + 30 mm + Standard + None + Normal + Normal + Normal + High + 0.1.1.2 + Auto + Auto + Tracking + On, Mode 2 + Off + Scenery + No + (Binary data 8200 bytes, use -b option to extract) + 0 + +AAAAAAAAAAAAAAAAAAAAAA== + + 0260 + Off + 00:00:52.21 + Off + 0 + High + Standard + Off + Horizontal (normal) + Enabled but Not Used + Normal + + Standard + Off + n/a + Destination + Off + n/a + 5 + Off + 0 + inf 0.00015 + 2 + 4 0 14674 56 + 2 7 4 0 + 0121 + Scenery + 2030 + 1054 + 1800 + No + Off + Off + +Aw== + + R98 - DCF basic file (sRGB) + 0100 + 0250 + JPEG (old-style) + Horizontal (normal) + 180 + 180 + inches + 10050 + 8789 + Co-sited + Scenery (intelligent auto) + 4.0 + 1.70778 + 3648x2736 + 10.0 + 1.925996 + 5.8 + 1/250 + (Binary data 8789 bytes, use -b option to extract) + 0.005 mm + 61.9 deg + 5.2 mm (35 mm equivalent: 30.0 mm) + 1.30 m + 12.0 + + + + + + 284 + 1 + General + General + 0 + 1 + JPEG + JPEG + JPEG + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/pictures/Landing_zone.jpg + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/pictures + Landing_zone + jpg + JPEG + JPEG + jpeg jpg jpe + JPEG + image/jpeg + JPEG + JPEG + jpeg jpg jpe + 1361321 + 1.30 MiB + 1 MiB + 1.3 MiB + 1.30 MiB + 1.298 MiB + 0 + 0.00 Byte (0%) + Byte0 + 0.0 Byte + 0.00 Byte + 0.000 Byte + 0.00 Byte (0%) + 0.00000 + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + JPEG + JPEG + image/jpeg + JPEG + JPEG + 3648 + 3 648 pixels + 2736 + 2 736 pixels + YUV + 4:2:0 + 8 + 8 bits + 8 + 8 bits + Lossy + Lossy + 1361321 + 1.30 MiB (100%) + 1 MiB + 1.3 MiB + 1.30 MiB + 1.298 MiB + 1.30 MiB (100%) + 1.00000 + + + + + + %transferDirectory%objects/pictures/Landing zone.jpg + + derivation + is source of + + UUID + e8137104-96d4-406c-a050-473ab3754136 + + + UUID + 0da1f58e-a68d-43b2-a65b-09c184f94be5 + + + + + + + + + + + + UUID + 73de8b63-b419-4b98-a1a1-77ebe7fd513b + + ingestion + 2015-10-23T23:17:25 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 63e11713-0af5-4dd9-9a84-6606c658ab96 + + message digest calculation + 2015-10-23T23:17:40 + program="python"; module="hashlib.sha256()" + + + + a469c730e705d757d66f53f38bb4455e89d5691a3d87fc7bc069b91fa2a50d46 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d427c03e-8768-41c3-8c3e-3e9d70fc3d15 + + virus check + 2015-10-23T23:18:04 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 4cfcb431-dbde-4b5a-b144-39adc628364b + + name cleanup + 2015-10-23T23:18:28 + prohibited characters removed:program="sanitizeNames"; version="1.10.d204c68e72645b2b4228520680ca211f7bc20b3b" + + + + Original name="%transferDirectory%objects/pictures/Landing zone.jpg"; cleaned up name="%transferDirectory%objects/pictures/Landing_zone.jpg" + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 31608056-17db-4735-9f6b-3a23bac05b76 + + format identification + 2015-10-23T23:19:21 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 2a3441dd-18e9-4ab8-aff3-45e66c56aec0 + + validation + 2015-10-23T23:20:30 + program="JHOVE"; version="1.6" + + pass + + format="JPEG"; version="1.01"; result="Well-Formed and valid" + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 0da1f58e-a68d-43b2-a65b-09c184f94be5 + + normalization + 2015-10-23T23:24:05 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/pictures/Landing_zone-67c12724-bfbe-4fb8-a8a6-fb2d4c6a14e4.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 2d676f19-dfb7-40a7-8d3f-697f0a87acd8 + + fixity check + 2015-10-23T23:26:55 + program="python"; module="hashlib.sha256()" + + Pass + + a469c730e705d757d66f53f38bb4455e89d5691a3d87fc7bc069b91fa2a50d46 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + 02f10198-96d6-4550-9818-e659c0ae2b54 + + + 0 + + sha256 + 50590624089e224889090079f47df6aa1a9023c97a83e7ef0103f6f1a80bb88d + + 4269757 + + + TIFF + + + + + + + + + + %SIPDirectory%objects/pictures/MARBLES-6e90d08d-2a92-4843-8e7b-95cebaa5c73c.tif + + derivation + has source + + UUID + a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + + + UUID + 3d34ef01-dffd-4799-879c-4e5cc85841a0 + + + + + + + + + + + + UUID + 6e90d08d-2a92-4843-8e7b-95cebaa5c73c + + creation + 2015-10-23T23:23:55 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + f084d5bb-9f49-48f5-8e57-3bc0bd672c56 + + message digest calculation + 2015-10-23T23:23:55 + program="python"; module="hashlib.sha256()" + + + + 50590624089e224889090079f47df6aa1a9023c97a83e7ef0103f6f1a80bb88d + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d4417714-ebe8-4da6-9fa6-bdf120cf0997 + + fixity check + 2015-10-23T23:26:35 + program="python"; module="hashlib.sha256()" + + Pass + + 50590624089e224889090079f47df6aa1a9023c97a83e7ef0103f6f1a80bb88d verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + + + 0 + + sha256 + 91a5ddca3637590c2ddb50da5feb73ff0b8a98cd09a98afb79adc2cf70bc6220 + + 4261301 + + + Generic TGA + + + + Archivematica Format Policy Registry + .tga + + + + + + + + + + + + + + + + + + + + + + + + + + + + 284 + 1 + General + General + 0 + 1 + Raw + Raw + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/pictures/MARBLES.TGA + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/extractPackagesChoice/Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/objects/pictures + MARBLES + TGA + TGA + TGA + tga + TGA + Version 2 + image/tga + TGA + TGA + tga + 4261301 + 4.06 MiB + 4 MiB + 4.1 MiB + 4.06 MiB + 4.064 MiB + UTC 2015-10-16 03:52:33 + 2015-10-16 03:52:33 + + + 105 + 1 + Image + Image + 0 + Raw + Raw + 2 + 1419 + 1 419 pixels + 1001 + 1 001 pixels + RGB + 24 + 24 bits + 24 + 24 bits + + + + + + %transferDirectory%objects/pictures/MARBLES.TGA + + derivation + is source of + + UUID + 02f10198-96d6-4550-9818-e659c0ae2b54 + + + UUID + 3d34ef01-dffd-4799-879c-4e5cc85841a0 + + + + + + + + + + + + UUID + 4132305c-ecd7-4be3-aa03-51dd7228f3a3 + + ingestion + 2015-10-23T23:17:37 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + bc3678e9-3d8a-4de3-9aa2-82d50753873f + + message digest calculation + 2015-10-23T23:17:51 + program="python"; module="hashlib.sha256()" + + + + 91a5ddca3637590c2ddb50da5feb73ff0b8a98cd09a98afb79adc2cf70bc6220 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 61ee01a7-0009-40bf-a710-e75630707eda + + virus check + 2015-10-23T23:18:20 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 988404b3-0ac4-4118-ba0c-2c86f411db2a + + format identification + 2015-10-23T23:19:34 + program="File Extension"; version="0.1" + + Positive + + No Matching Format + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 3d34ef01-dffd-4799-879c-4e5cc85841a0 + + normalization + 2015-10-23T23:23:55 + ArchivematicaFPRCommandID="a34ddc9b-c922-4bb6-8037-bbe713332175"; program="convert"; version="Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org" + + + + + %SIPDirectory%objects/pictures/MARBLES-6e90d08d-2a92-4843-8e7b-95cebaa5c73c.tif + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 6194ea25-43ad-48f3-9273-237fa779704c + + fixity check + 2015-10-23T23:26:35 + program="python"; module="hashlib.sha256()" + + Pass + + 91a5ddca3637590c2ddb50da5feb73ff0b8a98cd09a98afb79adc2cf70bc6220 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + UUID + e8fe6308-a2ea-4e1e-8a3e-b6d4126b781d + + + 0 + + sha256 + 609f9c54f6233f4803c5945b693108f12b8bd309c51e772bf6ebc731e8a182b6 + + 94038 + + + Unknown + + + + + + + + + + + 1.0 + + + + 2015:10:23 16:19:46-07:00 + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + METS.xml + 94038 + 1445642386000 + + + + + ASCII + XML + 1.0 + http://www.loc.gov/standards/mets/mets.xsd + + + + + + XML 1.0 document text +application/xml; charset=us-ascii + application/xml + XML 1.0 document text + + + + + ExifToolVersion 9.13 +FileName METS.xml +Directory /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd +FileSize 92 kB +FileModifyDate 2015:10:23 16:19:46-07:00 +FileAccessDate 2015:10:23 16:25:24-07:00 +FileInodeChangeDate 2015:10:23 16:25:17-07:00 +FilePermissions rw-r--r-- +FileType XML +MIMEType application/xml +MetsObjid 64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd +MetsSchemaLocation http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/mets.xsd +MetsMetsHdrCreatedate 2015:10:23 23:17:55 +MetsMetsHdrAgentOthertype SOFTWARE +MetsMetsHdrAgentRole CREATOR +MetsMetsHdrAgentType OTHER +MetsMetsHdrAgentName b9d676ff-7c9d-4777-9a19-1b4b76a6542f +MetsMetsHdrAgentNote Archivematica dashboard UUID +MetsAmdSecId digiprov-46b7cb96-792c-4441-a5d6-67c83313501c +MetsAmdSecDigiprovMDId digiprovMD_5 +MetsAmdSecDigiprovMDMdWrapMdtype PREMIS:EVENT +MetsAmdSecDigiprovMDMdWrapXmlDataEventSchemaLocation info:lc/xmlns/premis-v2 http://www.loc.gov/standards/premis/v2/premis-v2-2.xsd +MetsAmdSecDigiprovMDMdWrapXmlDataEventVersion 2.2 +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventIdentifierEventIdentifierType UUID +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventIdentifierEventIdentifierValue 707c547e-5265-433f-9abd-9d2597f9d551 +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventType format identification +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventDateTime 2015:10:23 23:19:21 +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventDetail program="File Extension"; version="0.1" +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventOutcomeInformationEventOutcome Positive +MetsAmdSecDigiprovMDMdWrapXmlDataEventEventOutcomeInformationEventOutcomeDetailEventOutcomeDetailNote No Matching Format +MetsAmdSecDigiprovMDMdWrapXmlDataEventLinkingAgentIdentifierLinkingAgentIdentifierType repository code +MetsAmdSecDigiprovMDMdWrapXmlDataEventLinkingAgentIdentifierLinkingAgentIdentifierValue demo +MetsFileSecFileGrpUse original +MetsFileSecFileGrpFileId file-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 +MetsFileSecFileGrpFileAdmid digiprov-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 +MetsFileSecFileGrpFileFLocatHref objects/pictures/MARBLES.TGA +MetsFileSecFileGrpFileFLocatLoctype OTHER +MetsFileSecFileGrpFileFLocatOtherloctype SYSTEM +MetsStructMapLabel processed +MetsStructMapType physical +MetsStructMapDivType directory +MetsStructMapDivLabel Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd +MetsStructMapDivDivType directory +MetsStructMapDivDivLabel objects +MetsStructMapDivDivFptrFileid file-e9400f17-5535-40bf-909b-e990fb9c2037 +MetsStructMapDivDivDivType directory +MetsStructMapDivDivDivLabel pictures +MetsStructMapDivDivDivFptrFileid file-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + 9.13 + METS.xml + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + 92 kB + 2015:10:23 16:19:46-07:00 + 2015:10:23 16:25:24-07:00 + 2015:10:23 16:25:17-07:00 + rw-r--r-- + XML + application/xml + 64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/mets.xsd + 2015:10:23 23:17:55 + SOFTWARE + CREATOR + OTHER + b9d676ff-7c9d-4777-9a19-1b4b76a6542f + Archivematica dashboard UUID + digiprov-46b7cb96-792c-4441-a5d6-67c83313501c + digiprovMD_5 + PREMIS:EVENT + info:lc/xmlns/premis-v2 http://www.loc.gov/standards/premis/v2/premis-v2-2.xsd + 2.2 + UUID + 707c547e-5265-433f-9abd-9d2597f9d551 + format identification + 2015:10:23 23:19:21 + program="File Extension"; version="0.1" + Positive + No Matching Format + repository code + demo + original + file-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + digiprov-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + objects/pictures/MARBLES.TGA + OTHER + SYSTEM + processed + physical + directory + Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + directory + objects + file-e9400f17-5535-40bf-909b-e990fb9c2037 + directory + pictures + file-a1859d2e-ac0d-4b4c-94f4-9c6a594e8794 + + + + + + METS.xml + / + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + true + false + 94038 + false + true + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + file:/var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + true + true + xml + 2015-10-23 16:19:46 + 20151023 + yyyyMMdd + + HHmmssSSS + application/xml + null + null + null + unknown + + + 1.0 + ASCII + unspecified + + + + + + + /var/archivematica/sharedDirectory/watchedDirectories/workFlowDecisions/metadataReminder/Dogg-ff1fe159-6660-4449-9d1f-8719396c2cb0/objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + METS.xml + 94038 + 1445642386000 + + + + + + + + + + + http://www.loc.gov/standards/mets/mets.xsd + + + + + + + XML + Extensible Markup Language + doc + + text/xml + + + xml + + + + + + + application/xml + + + + + + + + %SIPDirectory%objects/submissionDocumentation/transfer-Dogg-64efab7e-1fc7-43f6-9dc2-33f6ac31b9bd/METS.xml + + + + + + + + + + UUID + 71b98d32-b95c-42c4-8000-7068088d20e9 + + ingestion + 2015-10-23T23:25:21 + + + + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + bf78be24-aa12-4def-8161-8c36628d8cf2 + + message digest calculation + 2015-10-23T23:25:25 + program="python"; module="hashlib.sha256()" + + + + 609f9c54f6233f4803c5945b693108f12b8bd309c51e772bf6ebc731e8a182b6 + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + d7ff9da1-ffd4-42b3-8f49-ee9888d4bfcf + + virus check + 2015-10-23T23:25:31 + program="Clam AV"; version="ClamAV 0.98.7"; virusDefinitions="21002/Fri Oct 23 13:38:56 2015 +" + + Pass + + + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + UUID + 561c292d-15be-4c78-8036-712dbdeeb2f6 + + fixity check + 2015-10-23T23:27:04 + program="python"; module="hashlib.sha256()" + + Pass + + 609f9c54f6233f4803c5945b693108f12b8bd309c51e772bf6ebc731e8a182b6 verified + + + + Archivematica user pk + 1 + + + preservation system + Archivematica-1.4.1 + + + repository code + demo + + + + + + + + + + + preservation system + Archivematica-1.4.1 + + Archivematica + software + + + + + + + + + + repository code + demo + + demo + organization + + + + + + + + + + Archivematica user pk + 1 + + username="demo", first_name="demo", last_name="demo" + Archivematica user + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/metsrw/__init__.py b/metsrw/__init__.py index aa602b9..d4b5907 100644 --- a/metsrw/__init__.py +++ b/metsrw/__init__.py @@ -20,6 +20,7 @@ AM_PNTR_SCT_PATH, get_schematron, validate, + get_file_path, get_xmlschema, xsd_validate, schematron_validate, @@ -40,14 +41,15 @@ LOGGER = logging.getLogger(__name__) LOGGER.addHandler(logging.NullHandler()) -__version__ = '0.2.0' +__version__ = '0.2.1' __all__ = ['MetsError', 'ParseError', 'FSEntry', 'AMDSec', 'SubSection', 'MDRef', 'MDWrap', 'METSDocument', 'NAMESPACES', 'SCHEMA_LOCATIONS', 'lxmlns', 'FILE_ID_PREFIX', 'GROUP_ID_PREFIX', 'METS_XSD_PATH', 'AM_SCT_PATH', 'AM_PNTR_SCT_PATH', 'get_schematron', 'validate', - 'get_xmlschema', 'xsd_validate', 'schematron_validate', - 'sct_report_string', 'xsd_error_log_string', 'report_string', - 'FeatureBroker', 'set_feature_broker_to_default_state', - 'feature_broker', 'Dependency', 'has_class_methods', 'has_methods', - 'is_class', 'plugins', '__version__'] + 'get_file_path', 'get_xmlschema', 'xsd_validate', + 'schematron_validate', 'sct_report_string', 'xsd_error_log_string', + 'report_string', 'FeatureBroker', + 'set_feature_broker_to_default_state', 'feature_broker', + 'Dependency', 'has_class_methods', 'has_methods', 'is_class', + 'plugins', '__version__'] diff --git a/metsrw/di.py b/metsrw/di.py index 7817f79..51fe20f 100644 --- a/metsrw/di.py +++ b/metsrw/di.py @@ -19,7 +19,10 @@ See http://code.activestate.com/recipes/413268/ """ -from .plugins import premisrw +from .plugins import ( + premisrw, + dcrw +) class FeatureBroker(object): @@ -62,10 +65,21 @@ def __getitem__(self, feature_name): def set_feature_broker_to_default_state(fb): + """Provide dependencies via the global singleton feature broker. + + To use yapremisrw, provide different class(es) from that plugin, e.g., to + use ``yapremisrw.Event``:: + + >>> from .plugins import yapremisrw + >>> from metsrw import feature_broker as fb + >>> fb.provide('premis_event_class', yapremisrw.Event) + + """ fb.clear() fb.provide('premis_object_class', premisrw.PREMISObject) fb.provide('premis_event_class', premisrw.PREMISEvent) fb.provide('premis_agent_class', premisrw.PREMISAgent) + fb.provide('dublin_core_class', dcrw.DublinCoreXmlData) feature_broker = FeatureBroker() # global singleton feature broker diff --git a/metsrw/fsentry.py b/metsrw/fsentry.py index 2c621c2..c3f50ff 100644 --- a/metsrw/fsentry.py +++ b/metsrw/fsentry.py @@ -89,10 +89,16 @@ class FSEntry(object): has_methods('serialize'), has_class_methods('fromtree'), is_class) + dublin_core_class = Dependency( + 'dublin_core_class', + has_methods('serialize'), + has_class_methods('fromtree'), + is_class) PREMIS_OBJECT = 'PREMIS:OBJECT' PREMIS_EVENT = 'PREMIS:EVENT' PREMIS_AGENT = 'PREMIS:AGENT' + DublinCore = 'DC' def __init__(self, path=None, label=None, use='original', type=u'Item', children=None, file_uuid=None, derived_from=None, @@ -131,6 +137,11 @@ def __init__(self, path=None, label=None, use='original', type=u'Item', self.amdsecs = [] self.dmdsecs = [] + # Convenient access to metadata (without cycling through amdsecs) + self.techmds = [] + self.digiprovmds = [] + self.rightsmds = [] + def __str__(self): return '{s.type}: {s.path}'.format(s=self) @@ -271,7 +282,9 @@ def add_premis_rights(self, md, mode='mdwrap'): def add_dublin_core(self, md, mode='mdwrap'): # TODO add extra args and create DC object here - return self.add_dmdsec(md, 'DC', mode) + return self.add_dmdsec( + self.serialize_md_inst(md, self.dublin_core_class), + self.DublinCore, mode) def add_child(self, child): """Add a child FSEntry to this FSEntry. @@ -399,9 +412,12 @@ def serialize_structmap(self, recurse=True, normative=False): return el def get_subsections_of_type(self, mdtype, md_class): - return [md_class.fromtree(ss.contents.document) - for ss in self.amdsecs[0].subsections - if ss.contents.mdtype == mdtype] + try: + return [md_class.fromtree(ss.contents.document) + for ss in self.amdsecs[0].subsections + if ss.contents.mdtype == mdtype] + except IndexError: + return [] def get_premis_objects(self): return self.get_subsections_of_type( @@ -414,3 +430,7 @@ def get_premis_events(self): def get_premis_agents(self): return self.get_subsections_of_type( self.PREMIS_AGENT, self.premis_agent_class) + + def get_dublin_core(self): + return self.get_subsections_of_type( + self.DublinCore, self.dublin_core_class) diff --git a/metsrw/metadata.py b/metsrw/metadata.py index 95c9e46..4bf7759 100644 --- a/metsrw/metadata.py +++ b/metsrw/metadata.py @@ -11,6 +11,7 @@ from . import exceptions from . import utils +from .plugins.dcrw import DublinCoreXmlData LOGGER = logging.getLogger(__name__) @@ -298,7 +299,10 @@ class MDWrap(object): include "PREMIS:OBJECT", "PREMIS:EVENT,", "DC" and "OTHER". :param str othermdtype: The OTHERMDTYPE of the XML document. Should be set if mdtype is "OTHER". """ - def __init__(self, document, mdtype, othermdtype=None): + + MDTYPE_CLASSES = {'DC': DublinCoreXmlData} + + def __init__(self, document, mdtype, othermdtype=None, data=None): parser = etree.XMLParser(remove_blank_text=True) if isinstance(document, six.string_types): self.document = etree.fromstring(document, parser=parser) @@ -306,6 +310,7 @@ def __init__(self, document, mdtype, othermdtype=None): self.document = document self.mdtype = mdtype self.othermdtype = othermdtype + self.data = data @classmethod def parse(cls, root): @@ -321,6 +326,12 @@ def parse(cls, root): mdtype = root.get('MDTYPE') if not mdtype: raise exceptions.ParseError('mdWrap must have a MDTYPE') + if mdtype in MDWrap.MDTYPE_CLASSES.keys(): + mdtype_class = MDWrap.MDTYPE_CLASSES[mdtype]() + data = mdtype_class.parse(root.find('mets:xmlData', namespaces=utils.NAMESPACES)).__dict__ + else: + data = None + othermdtype = root.get('OTHERMDTYPE') document = root.xpath('mets:xmlData/*', namespaces=utils.NAMESPACES) if len(document) == 0: @@ -329,7 +340,7 @@ def parse(cls, root): ' one has none') elif len(document) == 1: document = document[0] - return cls(document, mdtype, othermdtype) + return cls(document, mdtype, othermdtype=othermdtype, data=data) def serialize(self): el = etree.Element(utils.lxmlns('mets') + 'mdWrap', MDTYPE=self.mdtype) diff --git a/metsrw/mets.py b/metsrw/mets.py index bc2332f..9e58377 100755 --- a/metsrw/mets.py +++ b/metsrw/mets.py @@ -389,6 +389,11 @@ def _add_amdsecs_to_fs_entry(amdids, fs_entry, tree): namespaces=utils.NAMESPACES) amdsec = metadata.AMDSec.parse(amdsec_elem) fs_entry.amdsecs.append(amdsec) + # Add subsections to convience properties + for subsection in amdsec.subsections: + getattr( + fs_entry, subsection.subsection.lower() + 's').append( + subsection) def _parse_tree(self, tree=None): if tree is None: diff --git a/metsrw/plugins/dcrw/__init__.py b/metsrw/plugins/dcrw/__init__.py new file mode 100644 index 0000000..e48e838 --- /dev/null +++ b/metsrw/plugins/dcrw/__init__.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import + +import logging + +from .dc import DublinCoreXmlData +from .utils import ( + NAMESPACES, + DUBLINCORE_SCHEMA_LOCATIONS, + lxmlns, +) +from .exceptions import ( + DcError, + ConstructError, + ParseError +) + + +LOGGER = logging.getLogger(__name__) +LOGGER.addHandler(logging.NullHandler()) + + +__all__ = [ + 'DublinCoreXmlData', + 'NAMESPACES', + 'DUBLINCORE_SCHEMA_LOCATIONS', + 'lxmlns', + 'DcError', + 'ConstructError', + 'ParseError', +] diff --git a/metsrw/plugins/dcrw/dc.py b/metsrw/plugins/dcrw/dc.py new file mode 100644 index 0000000..1bf9755 --- /dev/null +++ b/metsrw/plugins/dcrw/dc.py @@ -0,0 +1,75 @@ +from __future__ import absolute_import + +from collections import OrderedDict +import logging +from lxml import etree + +from .exceptions import ParseError +from .utils import lxmlns, NAMESPACES, DUBLINCORE_SCHEMA_LOCATIONS + +LOGGER = logging.getLogger(__name__) + + +class DublinCoreXmlData(object): + """ + An object representing a METS xmlData element containing a Dublin Core element. + + :raises ParseError: If the root element tag is not xmlData. + """ + DC_ELEMENTS = ['title', 'creator', 'subject', 'description', 'publisher', + 'contributor', 'date', 'format', 'identifier', 'source', + 'relation', 'language', 'coverage', 'rights'] + + def __init__(self, **kwargs): + for element in self.DC_ELEMENTS: + setattr(self, element, kwargs.get(element)) + + @classmethod + def parse(cls, root): + """ + Parse an xmlData element containing a Dublin Core dublincore element. + + :param root: Element or ElementTree to be parsed into an object. + :raises ParseError: If the root is not xmlData or doesn't contain a dublincore element. + """ + if root.tag != lxmlns('mets') + 'xmlData': + raise ParseError('DublinCoreXmlData can only parse xmlData elements with mets namespace.') + + dc_el = root.find('dcterms:dublincore', namespaces=NAMESPACES) + + if dc_el is None or dc_el.tag != lxmlns('dcterms') + 'dublincore': + raise ParseError('xmlData can only contain a dublincore element with the dcterms namespace.') + + kwargs = {} + + for element in DublinCoreXmlData.DC_ELEMENTS: + kwargs[element] = dc_el.findtext("dc:" + element, namespaces=NAMESPACES) + + return cls(**kwargs) + + fromtree = parse + + def serialize(self): + nsmap = OrderedDict([ + ('mets', NAMESPACES['mets']), + ('xsi', NAMESPACES['xsi']), + ('xlink', NAMESPACES['xlink']) + ]) + root = etree.Element(lxmlns('mets') + 'xmlData', nsmap=nsmap) + root.append(self._serialize_dublincore()) + return root + + def _serialize_dublincore(self): + nsmap = OrderedDict([ + ('dcterms', NAMESPACES['dcterms']), + ('dc', NAMESPACES['dc']) + ]) + attrib = {'{}schemaLocation'.format(lxmlns('xsi')): DUBLINCORE_SCHEMA_LOCATIONS} + dc_root = etree.Element(lxmlns('dcterms') + 'dublincore', nsmap=nsmap, attrib=attrib) + + for element in DublinCoreXmlData.DC_ELEMENTS: + dc_el = etree.Element(lxmlns('dc') + element) + dc_el.text = getattr(self, element) + dc_root.append(dc_el) + + return dc_root diff --git a/metsrw/plugins/dcrw/exceptions.py b/metsrw/plugins/dcrw/exceptions.py new file mode 100644 index 0000000..3a34f12 --- /dev/null +++ b/metsrw/plugins/dcrw/exceptions.py @@ -0,0 +1,19 @@ +"""Exceptions for dcrw. + +All exceptions generated by this library will descend from DcError. +""" + + +class DcError(Exception): + """ Base Exception for this module. """ + pass + + +class ConstructError(DcError): + """ Error constructing an object. """ + pass + + +class ParseError(DcError): + """ Error parsing a DC element. """ + pass diff --git a/metsrw/plugins/dcrw/utils.py b/metsrw/plugins/dcrw/utils.py new file mode 100644 index 0000000..69dab56 --- /dev/null +++ b/metsrw/plugins/dcrw/utils.py @@ -0,0 +1,17 @@ +NAMESPACES = { + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "mets": "http://www.loc.gov/METS/", + "premis": "info:lc/xmlns/premis-v2", + "dcterms": "http://purl.org/dc/terms/", + "fits": "http://hul.harvard.edu/ois/xml/ns/fits/fits_output", + "xlink": "http://www.w3.org/1999/xlink", + "dc": "http://purl.org/dc/elements/1.1/" +} + +DUBLINCORE_SCHEMA_LOCATIONS = "http://purl.org/dc/terms/ " + \ + "http://dublincore.org/schemas/xmls/qdc/2008/02/11/dcterms.xsd" + + +def lxmlns(arg): + """ Return XPath-usable namespace. """ + return '{' + NAMESPACES[arg] + '}' diff --git a/metsrw/plugins/yapremisrw/__init__.py b/metsrw/plugins/yapremisrw/__init__.py new file mode 100644 index 0000000..7483e92 --- /dev/null +++ b/metsrw/plugins/yapremisrw/__init__.py @@ -0,0 +1,40 @@ +from __future__ import absolute_import + +import logging + +from .object import ( + Object, + ObjectCharacteristics +) +from .event import Event +from .utils import ( + NAMESPACES, + PREMIS_SCHEMA_LOCATIONS, + PREMIS_VERSION, + lxmlns, + append_text_as_element_if_not_none +) +from .exceptions import ( + PremisError, + ConstructError, + ParseError +) + + +LOGGER = logging.getLogger(__name__) +LOGGER.addHandler(logging.NullHandler()) + + +__all__ = [ + 'Object', + 'ObjectCharacteristics', + 'Event', + 'NAMESPACES', + 'PREMIS_SCHEMA_LOCATIONS', + 'PREMIS_VERSION', + 'lxmlns', + 'append_text_as_element_if_not_none', + 'PremisError', + 'ConstructError', + 'ParseError' +] diff --git a/metsrw/plugins/yapremisrw/event.py b/metsrw/plugins/yapremisrw/event.py new file mode 100644 index 0000000..94474c3 --- /dev/null +++ b/metsrw/plugins/yapremisrw/event.py @@ -0,0 +1,274 @@ +"""PREMIS-Reader-Writer 2 Event + +Supplies a PREMIS ``Event`` class for reading and writing PREMIS events. +Supports the API required for a metsrw plugin, i.e., provides the following +methods: + +1. A ``fromtree`` class method that parses an lxml element and returns a Python + instance. + +2. A ``serialize`` method that returns an lxml element. + +The ``metsrw.FSEntry`` class can accept ``yapremisrw.Event`` as a dependency. To +inject it:: + + >>> from metsrw import feature_broker + >>> from metsrw.plugins import yapremisrw + >>> feature_broker.provide('premis_event_class', yapremisrw.Event) + +""" + +from collections import OrderedDict +from copy import deepcopy +from lxml import etree + +from .exceptions import ParseError +from . import utils + + +class Event(object): + """An object representing a PREMIS event element. + + :param str identifier_type: Identifier type. + :param str identifier_value: Identifier value. + :param str event_type: Event type. + :param str event_datetime: Event date/time. + :param str detail: Event details. + :param list outcomes: List of dicts containing outcome data. + :param list linking_agent_identifiers: List of dicts containing linking + agent identifier data. + :param list linking_object_identifiers: List of dicts containing linking + object identifier data. + :raises exceptions.ParseError: If the root tag is not event. + """ + def __init__(self, identifier_type, identifier_value, event_type, + event_datetime, detail=None, outcomes=None, + linking_agent_identifiers=None, + linking_object_identifiers=None): + self.identifier_type = identifier_type + self.identifier_value = identifier_value + self.event_type = event_type + self.event_datetime = event_datetime + self.detail = detail + self.outcomes = outcomes + self.linking_agent_identifiers = linking_agent_identifiers + self.linking_object_identifiers = linking_object_identifiers + + @classmethod + def parse(cls, root): + """ + Create a new Event by parsing root. + + :param root: Element or ElementTree to be parsed into an object. + :raises ParseError: If the root is not event. + """ + if root.tag != utils.lxmlns('premis') + 'event': + raise ParseError('Event can only parse event elements with PREMIS namespace.') + + identifier_el = root.find("premis:eventIdentifier", namespaces=utils.NAMESPACES) + + if identifier_el is not None: + identifier_type = identifier_el.findtext("premis:eventIdentifierType", namespaces=utils.NAMESPACES) + identifier_value = identifier_el.findtext("premis:eventIdentifierValue", namespaces=utils.NAMESPACES) + + event_type = root.findtext("premis:eventType", namespaces=utils.NAMESPACES) + event_datetime = root.findtext("premis:eventDateTime", namespaces=utils.NAMESPACES) + detail = root.findtext("premis:eventDetail", namespaces=utils.NAMESPACES) + + outcome_info_els = root.findall("premis:eventOutcomeInformation", namespaces=utils.NAMESPACES) + outcomes = Event._parse_outcomes(outcome_info_els) + + linking_agent_identifier_els = root.findall("premis:linkingAgentIdentifier", namespaces=utils.NAMESPACES) + linking_agent_identifiers = Event._parse_linking_agent_identifiers(linking_agent_identifier_els) + + linking_object_identifier_els = root.findall("premis:linkingObjectIdentifier", namespaces=utils.NAMESPACES) + linking_object_identifiers = Event._parse_linking_object_identifiers(linking_object_identifier_els) + + return cls(identifier_type, identifier_value, event_type, event_datetime, detail, outcomes, linking_agent_identifiers, linking_object_identifiers) + + # So that ``premisrw.Event`` will conform to the API required by + # ``metsrw.FSEntry`` + fromtree = parse + + @classmethod + def _parse_outcomes(cls, outcome_information_els): + outcomes = [] + + for outcome_information_el in outcome_information_els: + details = [] + + detail_els = outcome_information_el.findall( + "premis:eventOutcomeDetail", namespaces=utils.NAMESPACES) + + if detail_els is not None: + for detail_el in detail_els: + extensions = detail_el.findall("premis:eventOutcomeDetailExtension", namespaces=utils.NAMESPACES) + + details.append({ + 'note': detail_el.findtext("premis:eventOutcomeDetailNote", namespaces=utils.NAMESPACES), + 'extensions': extensions + }) + + outcomes.append({ + 'outcome': outcome_information_el.findtext("premis:eventOutcome", namespaces=utils.NAMESPACES), + 'details': details + }) + + return outcomes + + @classmethod + def _parse_linking_agent_identifiers(cls, identifier_els): + identifiers = [] + + for identifier in identifier_els: + roles = [] + + for role_el in identifier.findall("premis:linkingAgentRole", namespaces=utils.NAMESPACES): + role = role_el.text if role_el is not None else None + if role is not None: + roles.append(role) + + identifiers.append({ + 'identifier_type': identifier.findtext("premis:linkingAgentIdentifierType", namespaces=utils.NAMESPACES), + 'identifier_value': identifier.findtext("premis:linkingAgentIdentifierValue", namespaces=utils.NAMESPACES), + 'roles': roles + }) + + return identifiers + + @classmethod + def _parse_linking_object_identifiers(cls, identifier_els): + identifiers = [] + + for identifier in identifier_els: + roles = [] + + for role_el in identifier.findall("premis:linkingObjectRole", namespaces=utils.NAMESPACES): + role = role_el.text if role_el is not None else None + if role is not None: + roles.append(role) + + identifiers.append({ + 'identifier_type': identifier.findtext("premis:linkingObjectIdentifierType", namespaces=utils.NAMESPACES), + 'identifier_value': identifier.findtext("premis:linkingObjectIdentifierValue", namespaces=utils.NAMESPACES), + 'roles': roles + }) + + return identifiers + + def serialize(self): + root = self._document_root() + root.append(self._serialize_identifier()) + + etree.SubElement( + root, utils.lxmlns('premis') + 'eventType').text = self.event_type + etree.SubElement(root, utils.lxmlns('premis') + 'eventDateTime').text = \ + self.event_datetime + + if self.detail is not None: + etree.SubElement( + root, utils.lxmlns('premis') + 'eventDetail').text = self.detail + + for outcome_el in self._serialize_outcomes(): + root.append(outcome_el) + + for identifier_el in self._serialize_linking_agent_identifiers(): + root.append(identifier_el) + + for identifier_el in self._serialize_linking_object_identifiers(): + root.append(identifier_el) + + return root + + def _document_root(self): + """ + Return the premis Element for the document root. + """ + nsmap = OrderedDict([ + ('premis', utils.NAMESPACES['premis']), + ('xsi', utils.NAMESPACES['xsi']), + ('xlink', utils.NAMESPACES['xlink']) + ]) + + attrib = { + '{}schemaLocation'.format(utils.lxmlns('xsi')): utils.PREMIS_SCHEMA_LOCATIONS, + 'version': utils.PREMIS_VERSION + } + + return etree.Element(utils.lxmlns('premis') + 'event', nsmap=nsmap, attrib=attrib) + + def _serialize_identifier(self): + root = etree.Element(utils.lxmlns('premis') + "eventIdentifier") + + identifier_type_el = etree.Element(utils.lxmlns('premis') + "eventIdentifierType") + identifier_type_el.text = self.identifier_type + root.append(identifier_type_el) + + identifier_value_el = etree.Element(utils.lxmlns('premis') + "eventIdentifierValue") + identifier_value_el.text = self.identifier_value + root.append(identifier_value_el) + + return root + + def _serialize_outcomes(self): + outcome_info_els = [] + + if self.outcomes is not None: + for outcome in self.outcomes: + outcome_info_el = etree.Element(utils.lxmlns('premis') + "eventOutcomeInformation") + + outcome_el = etree.Element(utils.lxmlns('premis') + "eventOutcome") + outcome_el.text = outcome['outcome'] + outcome_info_el.append(outcome_el) + + if outcome['details'] is not None: + for detail in outcome['details']: + detail_el = etree.Element(utils.lxmlns('premis') + "eventOutcomeDetail") + + utils.append_text_as_element_if_not_none(detail_el, detail['note'], 'premis', 'eventOutcomeDetailNote') + + if detail['extensions'] is not None: + for extension_el in detail['extensions']: + detail_el.append(deepcopy(extension_el)) + + outcome_info_el.append(detail_el) + + outcome_info_els.append(outcome_info_el) + + return outcome_info_els + + def _serialize_linking_agent_identifiers(self): + identifiers = [] + + if self.linking_agent_identifiers is not None: + for identifier in self.linking_agent_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "linkingAgentIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['identifier_type'], 'premis', 'linkingAgentIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['identifier_value'], 'premis', 'linkingAgentIdentifierValue') + + if identifier['roles'] is not None: + for role in identifier['roles']: + utils.append_text_as_element_if_not_none(identifier_el, role, 'premis', 'linkingAgentRole') + + identifiers.append(identifier_el) + + return identifiers + + def _serialize_linking_object_identifiers(self): + identifiers = [] + + if self.linking_object_identifiers is not None: + for identifier in self.linking_object_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "linkingObjectIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['identifier_type'], 'premis', 'linkingObjectIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['identifier_value'], 'premis', 'linkingObjectIdentifierValue') + + if identifier['roles'] is not None: + for role in identifier['roles']: + utils.append_text_as_element_if_not_none(identifier_el, role, 'premis', 'linkingObjectRole') + + identifiers.append(identifier_el) + + return identifiers diff --git a/metsrw/plugins/yapremisrw/exceptions.py b/metsrw/plugins/yapremisrw/exceptions.py new file mode 100644 index 0000000..4cba4fe --- /dev/null +++ b/metsrw/plugins/yapremisrw/exceptions.py @@ -0,0 +1,19 @@ +"""Exceptions for yapremisrw. + +All exceptions generated by this library will descend from PremisError. +""" + + +class PremisError(Exception): + """ Base Exception for this module. """ + pass + + +class ConstructError(PremisError): + """ Error constructing an object. """ + pass + + +class ParseError(PremisError): + """ Error parsing a PREMIS element. """ + pass diff --git a/metsrw/plugins/yapremisrw/object.py b/metsrw/plugins/yapremisrw/object.py new file mode 100644 index 0000000..7a9b4fa --- /dev/null +++ b/metsrw/plugins/yapremisrw/object.py @@ -0,0 +1,1068 @@ +"""PREMIS-Reader-Writer 2 Object + +Supplies a PREMIS ``Object`` class for reading and writing PREMIS objects. +Supports the API required for a metsrw plugin, i.e., provides the following +methods: + +1. A ``fromtree`` class method that parses an lxml element and returns a Python + instance. + +2. A ``serialize`` method that returns an lxml element. + +The ``metsrw.FSEntry`` class can accept ``yapremisrw.Object`` as a dependency. To +inject it:: + + >>> from metsrw import feature_broker + >>> from metsrw.plugins import yapremisrw + >>> feature_broker.provide('premis_object_class', yapremisrw.Object) + +""" + +from collections import OrderedDict +from copy import deepcopy +from lxml import etree + +from .exceptions import ConstructError, ParseError +from . import utils + + +class Object(object): + """ + An object representing a PREMIS object element. + + :param list object_identifiers: List of dicts containing object identifier data. + :param str object_category: Category. + :param list preservation_levels: List of dicts containing preservation level data. + :param list significate_properties: List of dicts containing significant properties data. + :param list characteristics: List of :class:`ObjectCharacteristics` instances in this PREMIS object. + :param str original_name: Filename. + :param list storage: List of dicts containing storage data. + :param list environments: List of dicts containing environment data. + :param list signature_information: List of dicts containing signature information data. + :param list relationships: List of dicts containing relationship data. + :param list linking_event_identifiers: List of dicts containing linking event identifier data. + :param list linking_intellectual_entity_identifiers: List of dicts containing linking intellectual entity identifier data. + :param list linking_rights_statement_identifiers: List of dicts containing linking rights statement identifier data. + :raises exceptions.ParseError: If the root element tag is not object. + """ + def __init__(self, object_identifiers, object_category, preservation_levels=None, significant_properties=None, characteristics=None, original_name=None, storage=None, environments=None, signature_information=None, relationships=None, linking_event_identifiers=None, linking_intellectual_entity_identifiers=None, linking_rights_statement_identifiers=None, strict=True): + if strict and object_identifiers is None: + raise ConstructError('object_identifiers argument is required.') + + if strict and object_category is None: + raise ConstructError('object_category argument is required.') + + if strict and characteristics is None: + raise ConstructError('characteristics argument is required.') + + self.object_identifiers = object_identifiers + self.object_category = object_category + self.preservation_levels = preservation_levels + self.significant_properties = significant_properties + self.characteristics = characteristics + self.original_name = original_name + self.storage = storage + self.environments = environments + self.signature_information = signature_information + self.relationships = relationships + self.linking_event_identifiers = linking_event_identifiers + self.linking_intellectual_entity_identifiers = linking_intellectual_entity_identifiers + self.linking_rights_statement_identifiers = linking_rights_statement_identifiers + + @classmethod + def parse(cls, root, strict=True): + """ + Create a new Object by parsing root. + + :param root: Element or ElementTree to be parsed into an object. + :raises exceptions.ParseError: If the root is not object. + """ + if root.tag != utils.lxmlns('premis') + 'object': + raise ParseError('Object can only parse object elements with PREMIS namespace.') + + identifier_els = root.findall("premis:objectIdentifier", namespaces=utils.NAMESPACES) + object_identifiers = Object._parse_object_identifiers(identifier_els) + object_category = root.findtext("premis:objectCategory", namespaces=utils.NAMESPACES) + original_name = root.findtext("premis:originalName", namespaces=utils.NAMESPACES) + + preservation_level_els = root.findall("premis:preservationLevel", namespaces=utils.NAMESPACES) + preservation_levels = Object._parse_preservation_levels(preservation_level_els) + + significant_properties_els = root.findall("premis:significantProperties", namespaces=utils.NAMESPACES) + significant_properties = Object._parse_significant_properties(significant_properties_els) + + storage_els = root.findall("premis:storage", namespaces=utils.NAMESPACES) + storage = Object._parse_storage(storage_els) + + environment_els = root.findall("premis:environment", namespaces=utils.NAMESPACES) + environments = Object._parse_environments(environment_els) + + characteristics_els = root.findall("premis:objectCharacteristics", namespaces=utils.NAMESPACES) + if characteristics_els is not None: + characteristics = [] + for characteristics_el in characteristics_els: + # Store characteristics objects as dicts for consistency + characteristics.append(ObjectCharacteristics.parse(characteristics_el).__dict__) + + signature_information_els = root.findall("premis:signatureInformation", namespaces=utils.NAMESPACES) + signature_information = Object._parse_signature_information(signature_information_els) + + relationship_els = root.findall("premis:relationship", namespaces=utils.NAMESPACES) + relationships = Object._parse_relationships(relationship_els) + + event_identifier_els = root.findall('premis:linkingEventIdentifier', namespaces=utils.NAMESPACES) + linking_event_identifiers = Object._parse_linking_event_identifiers(event_identifier_els) + + intellectual_entity_identifier_els = root.findall('premis:linkingIntellectualEntityIdentifier', namespaces=utils.NAMESPACES) + linking_intellectual_entity_identifiers = Object._parse_linking_intellectual_entity_identifiers(intellectual_entity_identifier_els) + + linking_rights_statement_identifier_els = root.findall('premis:linkingRightsStatementIdentifier', namespaces=utils.NAMESPACES) + linking_rights_statement_identifiers = Object._parse_linking_rights_statement_identifiers(linking_rights_statement_identifier_els) + + return cls(object_identifiers, object_category, preservation_levels, significant_properties, characteristics, original_name, storage, environments, signature_information, relationships, linking_event_identifiers, linking_intellectual_entity_identifiers, linking_rights_statement_identifiers, strict) + + @classmethod + def fromtree(cls, root): + return cls.parse(root, strict=False) + + @classmethod + def _parse_object_identifiers(cls, identifier_els): + """ + Parse a list of objectIdentifier elements and return a list of dicts. + + :param list identifier_els: List of objectIdentifier Elements to be parsed. + """ + identifiers = [] + + if identifier_els is not None: + for identifier_el in identifier_els: + if identifier_el is not None: + identifier_type = identifier_el.findtext("premis:objectIdentifierType", namespaces=utils.NAMESPACES) + identifier_value = identifier_el.findtext("premis:objectIdentifierValue", namespaces=utils.NAMESPACES) + else: + identifier_type = None + identifier_value = None + + identifiers.append({ + 'type': identifier_type, + 'value': identifier_value + }) + + return identifiers + + @classmethod + def _parse_preservation_levels(cls, preservation_level_els): + """ + Parse a list of preservationLevel elements and return a list of dicts. + + :param list preservation_level_els: List of preservationLevel Elements to be parsed. + """ + preservation_levels = [] + + if preservation_level_els is not None: + for preservation_level_el in preservation_level_els: + rationales = [] + + for rationale_el in preservation_level_el.findall("premis:preservationLevelRationale", namespaces=utils.NAMESPACES): + rationale = rationale_el.text if rationale_el is not None else None + if rationale is not None: + rationales.append(rationale) + + date_assigned = preservation_level_el.findtext("premis:preservationLevelDateAssigned", namespaces=utils.NAMESPACES) + + preservation_levels.append({ + 'value': preservation_level_el.findtext("premis:preservationLevelValue", namespaces=utils.NAMESPACES), + 'role': preservation_level_el.findtext("premis:preservationLevelRole", namespaces=utils.NAMESPACES), + 'rationales': rationales, + 'date_assigned': date_assigned + }) + + return preservation_levels + + @classmethod + def _parse_significant_properties(cls, significant_properties_els): + """ + Parse a list of significantProperties elements and return a list of dicts. + + :param list significant_properties_els: List of significantProperties Elements to be parsed. + """ + significant_properties = [] + + if significant_properties_els is not None: + for significant_properties_el in significant_properties_els: + extensions = significant_properties_el.findall("premis:significantPropertiesExtension", namespaces=utils.NAMESPACES) + + significant_properties.append({ + 'type': significant_properties_el.findtext("premis:significantPropertiesType", namespaces=utils.NAMESPACES), + 'value': significant_properties_el.findtext("premis:significantPropertiesValue", namespaces=utils.NAMESPACES), + 'extensions': extensions + }) + + return significant_properties + + @classmethod + def _parse_storage(cls, storage_els): + """ + Parse a list of storage elements and return a list of dicts. + + :param list storage_els: List of storage Elements to be parsed. + """ + storage = [] + + if storage_els is not None: + for storage_el in storage_els: + content_location_el = storage_el.find("premis:contentLocation", namespaces=utils.NAMESPACES) + + if content_location_el is not None: + location_type = content_location_el.findtext("premis:contentLocationType", namespaces=utils.NAMESPACES) + location_value = content_location_el.findtext("premis:contentLocationValue", namespaces=utils.NAMESPACES) + else: + location_type = None + location_value = None + + medium = storage_el.findtext("premis:storageMedium", namespaces=utils.NAMESPACES) + + storage.append({ + 'location_type': location_type, + 'location_value': location_value, + 'medium': medium + }) + + return storage + + @classmethod + def _parse_environments(cls, environment_els): + """ + Parse a list of environment elements and return a list of dicts. + + :param list environment_els: List of environment Elements to be parsed. + """ + environments = [] + + if environment_els is not None: + for environment_el in environment_els: + characteristic = environment_el.findtext("premis:environmentCharacteristic", namespaces=utils.NAMESPACES) + + purposes = [] + + for purpose_el in environment_el.findall("premis:environmentPurpose", namespaces=utils.NAMESPACES): + purpose = purpose_el.text if purpose_el is not None else None + if purpose is not None: + purposes.append(purpose) + + notes = [] + + for note_el in environment_el.findall("premis:environmentNote", namespaces=utils.NAMESPACES): + note = note_el.text if note_el is not None else None + if note is not None: + notes.append(note) + + dependencies = [] + + for dependency_el in environment_el.findall("premis:dependency", namespaces=utils.NAMESPACES): + names = [] + + for name_el in dependency_el.findall("premis:dependencyName", namespaces=utils.NAMESPACES): + name = name_el.text if name_el is not None else None + if name is not None: + names.append(name) + + identifiers = [] + + for identifier_el in dependency_el.findall("premis:dependencyIdentifier", namespaces=utils.NAMESPACES): + identifiers.append({ + 'type': identifier_el.findtext("premis:dependencyIdentifierType", namespaces=utils.NAMESPACES), + 'value': identifier_el.findtext("premis:dependencyIdentifierValue", namespaces=utils.NAMESPACES) + }) + + dependencies.append({ + 'names': names, + 'identifiers': identifiers + }) + + software = [] + + for software_el in environment_el.findall("premis:software", namespaces=utils.NAMESPACES): + other_informations = [] + + other_information_els = software_el.findall("premis:swOtherInformation", namespaces=utils.NAMESPACES) + for other_information_el in other_information_els: + other_information = other_information_el.text if other_information_el is not None else None + if other_information is not None: + other_informations.append(other_information) + + sw_dependencies = [] + for sw_dependency_el in software_el.findall("premis:swDependency", namespaces=utils.NAMESPACES): + sw_dependency = sw_dependency_el.text if sw_dependency_el is not None else None + if sw_dependency is not None: + sw_dependencies.append(sw_dependency) + + software.append({ + 'swname': software_el.findtext("premis:swName", namespaces=utils.NAMESPACES), + 'swversion': software_el.findtext("premis:swVersion", namespaces=utils.NAMESPACES), + 'swtype': software_el.findtext("premis:swType", namespaces=utils.NAMESPACES), + 'other_information': other_informations, + 'dependencies': sw_dependencies + }) + + hardware = [] + hardware_els = environment_el.findall("premis:hardware", namespaces=utils.NAMESPACES) + for hardware_el in hardware_els: + other_informations = [] + + for other_information_el in hardware_el.findall("premis:hwOtherInformation", namespaces=utils.NAMESPACES): + other_information = other_information_el.text if other_information_el is not None else None + if other_information is not None: + other_informations.append(other_information) + + hardware.append({ + 'hwname': hardware_el.findtext("premis:hwName", namespaces=utils.NAMESPACES), + 'hwtype': hardware_el.findtext("premis:hwType", namespaces=utils.NAMESPACES), + 'other_information': other_informations + }) + + extensions = environment_el.findall("premis:environmentExtension", namespaces=utils.NAMESPACES) + + environments.append({ + 'characteristic': characteristic, + 'purposes': purposes, + 'notes': notes, + 'dependencies': dependencies, + 'software': software, + 'hardware': hardware, + 'extensions': extensions + }) + + return environments + + @classmethod + def _parse_signature_information(cls, signature_information_els): + """ + Parse a list of signatureInformation elements and return a list of dicts. + + :param list signature_information_els: List of signatureInformation Elements to be parsed. + """ + signature_information = [] + + if signature_information_els is not None: + for signature_information_el in signature_information_els: + signatures = [] + + for signature_el in signature_information_el.findall("premis:signature", namespaces=utils.NAMESPACES): + properties = [] + property_els = signature_el.findall("premis:signatureProperties", namespaces=utils.NAMESPACES) + + for property_el in property_els: + properties.append(property_el.text) + + signatures.append({ + 'encoding': signature_el.findtext("premis:signatureEncoding", namespaces=utils.NAMESPACES), + 'signer': signature_el.findtext("premis:signer", namespaces=utils.NAMESPACES), + 'method': signature_el.findtext("premis:signatureMethod", namespaces=utils.NAMESPACES), + 'value': signature_el.findtext("premis:signatureValue", namespaces=utils.NAMESPACES), + 'validation_rules': signature_el.findtext("premis:signatureValidationRules", namespaces=utils.NAMESPACES), + 'properties': properties, + 'key_info': signature_el.findtext("premis:keyInformation", namespaces=utils.NAMESPACES) + }) + + extensions = signature_information_el.findall("premis:signatureInformationExtension", namespaces=utils.NAMESPACES) + + signature_information.append({ + 'signatures': signatures, + 'extensions': extensions + }) + + return signature_information + + @classmethod + def _parse_relationships(cls, relationship_els): + """ + Parse a list of relationship elements and return a list of dicts. + + :param list relationship_els: List of relationship Elements to be parsed. + """ + relationships = [] + + if relationship_els is not None: + for relationship_el in relationship_els: + related_object_identification = [] + + for related_object_id_el in relationship_el.findall("premis:relatedObjectIdentification", namespaces=utils.NAMESPACES): + related_object_identification.append({ + 'type': related_object_id_el.findtext("premis:relatedObjectIdentifierType", namespaces=utils.NAMESPACES), + 'value': related_object_id_el.findtext("premis:relatedObjectIdentifierValue", namespaces=utils.NAMESPACES), + 'sequence': related_object_id_el.findtext("premis:relatedObjectSequence", namespaces=utils.NAMESPACES) + }) + + related_event_identification = [] + related_event_id_els = relationship_el.findall("premis:relatedEventIdentification", namespaces=utils.NAMESPACES) + for related_event_id_el in related_event_id_els: + related_event_identification.append({ + 'type': related_event_id_el.findtext("premis:relatedEventIdentifierType", namespaces=utils.NAMESPACES), + 'value': related_event_id_el.findtext("premis:relatedEventIdentifierValue", namespaces=utils.NAMESPACES), + 'sequence': related_event_id_el.findtext("premis:relatedEventSequence", namespaces=utils.NAMESPACES) + }) + + relationships.append({ + 'type': relationship_el.findtext("premis:relationshipType", namespaces=utils.NAMESPACES), + 'subtype': relationship_el.findtext("premis:relationshipSubType", namespaces=utils.NAMESPACES), + 'related_objects': related_object_identification, + 'related_events': related_event_identification + }) + + return relationships + + @classmethod + def _parse_linking_event_identifiers(cls, identifier_els): + """ + Parse a list of linkingEventIdentifier elements and return a list of dicts. + + :param list identifier_els: List of linkingEventIdentifier Elements to be parsed. + """ + identifiers = [] + + if identifier_els is not None: + for identifier_el in identifier_els: + identifiers.append({ + 'type': identifier_el.findtext("premis:linkingEventIdentifierType", namespaces=utils.NAMESPACES), + 'value': identifier_el.findtext("premis:linkingEventIdentifierValue", namespaces=utils.NAMESPACES) + }) + + return identifiers + + @classmethod + def _parse_linking_intellectual_entity_identifiers(cls, identifier_els): + """ + Parse a list of linkingIntellectualEntityIdentifier elements and return a list of dicts. + + :param list identifier_els: List of linkingIntellectualEntityIdentifier Elements to be parsed. + """ + identifiers = [] + + if identifier_els is not None: + for identifier_el in identifier_els: + identifiers.append({ + 'type': identifier_el.findtext("premis:linkingIntellectualEntityIdentifierType", namespaces=utils.NAMESPACES), + 'value': identifier_el.findtext("premis:linkingIntellectualEntityIdentifierValue", namespaces=utils.NAMESPACES) + }) + + return identifiers + + @classmethod + def _parse_linking_rights_statement_identifiers(cls, linking_rights_statement_identifier_els): + """ + Parse a list of linkingRightsStatementIdentifier elements and return a list of dicts. + + :param list identifier_els: List of linkingRightsStatementIdentifier Elements to be parsed. + """ + identifiers = [] + + if linking_rights_statement_identifier_els is not None: + for identifier_el in linking_rights_statement_identifier_els: + identifiers.append({ + 'type': identifier_el.findtext("premis:linkingRightsStatementIdentifierType", namespaces=utils.NAMESPACES), + 'value': identifier_el.findtext("premis:linkingRightsStatementIdentifierValue", namespaces=utils.NAMESPACES) + }) + + return identifiers + + def serialize(self): + """ + Returns this PREMIS object serialized to an xml Element. + + :return: Element for this document + """ + root = self._document_root() + + for identifier_el in self._serialize_object_identifiers(): + root.append(identifier_el) + + if self.object_category is not None: + category_el = etree.Element(utils.lxmlns('premis') + 'objectCategory') + category_el.text = self.object_category + root.append(category_el) + + for level_el in self._serialize_preservation_levels(): + root.append(level_el) + + for properties_el in self._serialize_significant_properties(): + root.append(properties_el) + + for characteristics_el in self._serialize_object_characteristics(): + root.append(characteristics_el) + + if self.original_name is not None: + name_el = etree.Element(utils.lxmlns('premis') + 'originalName') + name_el.text = self.original_name + root.append(name_el) + + for storage_el in self._serialize_storage(): + root.append(storage_el) + + for environment_el in self._serialize_environment(): + root.append(environment_el) + + for signature_info_el in self._serialize_signature_information(): + root.append(signature_info_el) + + for relationship_el in self._serialize_relationships(): + root.append(relationship_el) + + for identifier_el in self._serialize_linking_event_identifiers(): + root.append(identifier_el) + + for identifier_el in self._serialize_linking_intellectual_entity_identifiers(): + root.append(identifier_el) + + for identifier_el in self._serialize_linking_rights_statement_identifiers(): + root.append(identifier_el) + + return root + + def _document_root(self): + """ + Return the root PREMIS object Element. + """ + nsmap = OrderedDict([ + ('premis', utils.NAMESPACES['premis']), + ('xsi', utils.NAMESPACES['xsi']), + ('xlink', utils.NAMESPACES['xlink']) + ]) + + attrib = { + '{}type'.format(utils.lxmlns('xsi')): 'premis:file', + '{}schemaLocation'.format(utils.lxmlns('xsi')): utils.PREMIS_SCHEMA_LOCATIONS, + 'version': utils.PREMIS_VERSION + } + + return etree.Element(utils.lxmlns('premis') + 'object', nsmap=nsmap, attrib=attrib) + + def _serialize_object_identifiers(self): + identifier_els = [] + + if self.object_identifiers is not None: + for identifier in self.object_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "objectIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['type'], 'premis', 'objectIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['value'], 'premis', 'objectIdentifierValue') + + identifier_els.append(identifier_el) + + return identifier_els + + def _serialize_preservation_levels(self): + level_els = [] + + if self.preservation_levels is not None: + for level in self.preservation_levels: + level_el = etree.Element(utils.lxmlns('premis') + "preservationLevel") + + utils.append_text_as_element_if_not_none(level_el, level['value'], 'premis', 'preservationLevelValue') + utils.append_text_as_element_if_not_none(level_el, level['role'], 'premis', 'preservationLevelRole') + + if level['rationales'] is not None: + for rationale in level['rationales']: + utils.append_text_as_element_if_not_none(level_el, rationale, 'premis', 'preservationLevelRationale') + + utils.append_text_as_element_if_not_none(level_el, level['date_assigned'], 'premis', 'preservationLevelDateAssigned') + + level_els.append(level_el) + + return level_els + + def _serialize_significant_properties(self): + properties_els = [] + + if self.significant_properties is not None: + for properties in self.significant_properties: + properties_el = etree.Element(utils.lxmlns('premis') + "significantProperties") + + utils.append_text_as_element_if_not_none(properties_el, properties['type'], 'premis', 'significantPropertiesType') + utils.append_text_as_element_if_not_none(properties_el, properties['value'], 'premis', 'significantPropertiesValue') + + if properties['extensions'] is not None: + for extension_el in properties['extensions']: + # As these are elements, need to copy so append doesn't move them in the source element tree + properties_el.append(deepcopy(extension_el)) + + properties_els.append(properties_el) + + return properties_els + + def _serialize_object_characteristics(self): + characteristics_els = [] + + if self.characteristics is not None: + for characteristics in self.characteristics: + characteristics_el = etree.Element(utils.lxmlns('premis') + "objectCharacteristics") + + utils.append_text_as_element_if_not_none(characteristics_el, characteristics['composition_level'], 'premis', 'compositionLevel') + + for item in characteristics['fixity']: + fixity_el = etree.Element(utils.lxmlns('premis') + "fixity") + utils.append_text_as_element_if_not_none(fixity_el, item['digest_algorithm'], 'premis', 'messageDigestAlgorithm') + utils.append_text_as_element_if_not_none(fixity_el, item['digest'], 'premis', 'messageDigest') + utils.append_text_as_element_if_not_none(fixity_el, item['digest_originator'], 'premis', 'messageDigestOriginator') + characteristics_el.append(fixity_el) + + utils.append_text_as_element_if_not_none(characteristics_el, characteristics['size'], 'premis', 'size') + + for item in characteristics['formats']: + format_el = etree.Element(utils.lxmlns('premis') + "format") + + if item['name'] is not None or item['version'] is not None: + designation_el = etree.Element(utils.lxmlns('premis') + "formatDesignation") + utils.append_text_as_element_if_not_none(designation_el, item['name'], 'premis', 'formatName') + utils.append_text_as_element_if_not_none(designation_el, item['version'], 'premis', 'formatVersion') + format_el.append(designation_el) + + if item['registry_name'] is not None or item['registry_key'] is not None or item['registry_role'] is not None: + registry_el = etree.Element(utils.lxmlns('premis') + "formatRegistry") + utils.append_text_as_element_if_not_none(registry_el, item['registry_name'], 'premis', 'formatRegistryName') + utils.append_text_as_element_if_not_none(registry_el, item['registry_key'], 'premis', 'formatRegistryKey') + utils.append_text_as_element_if_not_none(registry_el, item['registry_role'], 'premis', 'formatRegistryRole') + format_el.append(registry_el) + + if item['notes'] is not None: + for note in item['notes']: + utils.append_text_as_element_if_not_none(format_el, note, 'premis', 'formatNote') + + characteristics_el.append(format_el) + + for application in characteristics['creating_applications']: + application_el = etree.Element(utils.lxmlns('premis') + "creatingApplication") + utils.append_text_as_element_if_not_none(application_el, application['name'], 'premis', 'creatingApplicationName') + utils.append_text_as_element_if_not_none(application_el, application['version'], 'premis', 'creatingApplicationVersion') + utils.append_text_as_element_if_not_none(application_el, application['create_date'], 'premis', 'dateCreatedByApplication') + for extension in application['extensions']: + # As these are elements, need to copy so append doesn't move them in the source element tree + application_el.append(deepcopy(extension)) + + characteristics_el.append(application_el) + + for inhibitor in characteristics['inhibitors']: + inhibitors_el = etree.Element(utils.lxmlns('premis') + "inhibitors") + utils.append_text_as_element_if_not_none(inhibitors_el, inhibitor['type'], 'premis', 'inhibitorType') + for target in inhibitor['targets']: + utils.append_text_as_element_if_not_none(inhibitors_el, target, 'premis', 'inhibitorTarget') + utils.append_text_as_element_if_not_none(inhibitors_el, inhibitor['key'], 'premis', 'inhibitorKey') + characteristics_el.append(inhibitors_el) + + for extension in characteristics['extensions']: + # As these are elements, need to copy so append doesn't move them in the source element tree + characteristics_el.append(deepcopy(extension)) + + characteristics_els.append(characteristics_el) + + return characteristics_els + + def _serialize_storage(self): + storage_els = [] + + if self.storage is not None: + for item in self.storage: + storage_el = etree.Element(utils.lxmlns('premis') + "storage") + + if item['location_type'] is not None or item['location_value'] is not None: + location_el = etree.Element(utils.lxmlns('premis') + "contentLocation") + + if item['location_type'] is not None: + type_el = etree.Element(utils.lxmlns('premis') + "contentLocationType") + type_el.text = item['location_type'] + location_el.append(type_el) + + if item['location_value'] is not None: + value_el = etree.Element(utils.lxmlns('premis') + "contentLocationValue") + value_el.text = item['location_value'] + location_el.append(value_el) + + storage_el.append(location_el) + + if item['medium'] is not None: + medium_el = etree.Element(utils.lxmlns('premis') + "storageMedium") + medium_el.text = item['medium'] + storage_el.append(medium_el) + + storage_els.append(storage_el) + + return storage_els + + def _serialize_environment(self): + environment_els = [] + + if self.environments is not None: + for environment in self.environments: + environment_el = etree.Element(utils.lxmlns('premis') + "environment") + + if environment['characteristic'] is not None: + characteristic_el = etree.Element(utils.lxmlns('premis') + "environmentCharacteristic") + characteristic_el.text = environment['characteristic'] + environment_el.append(characteristic_el) + + if environment['purposes'] is not None: + for purpose in environment['purposes']: + purpose_el = etree.Element(utils.lxmlns('premis') + "environmentPurpose") + purpose_el.text = purpose + environment_el.append(purpose_el) + + if environment['notes'] is not None: + for note in environment['notes']: + note_el = etree.Element(utils.lxmlns('premis') + "environmentNote") + note_el.text = note + environment_el.append(note_el) + + if environment['dependencies'] is not None: + dependency_el = etree.Element(utils.lxmlns('premis') + "dependency") + + for dependency in environment['dependencies']: + if dependency['names'] is not None: + for name in dependency['names']: + name_el = etree.Element(utils.lxmlns('premis') + "dependencyName") + name_el.text = name + dependency_el.append(name_el) + + if dependency['identifiers'] is not None: + for identifier in dependency['identifiers']: + identifier_el = etree.Element(utils.lxmlns('premis') + "dependencyIdentifier") + + if identifier['type'] is not None: + type_el = etree.Element(utils.lxmlns('premis') + "dependencyIdentifierType") + type_el.text = identifier['type'] + identifier_el.append(type_el) + + if identifier['value'] is not None: + value_el = etree.Element(utils.lxmlns('premis') + "dependencyIdentifierValue") + value_el.text = identifier['value'] + identifier_el.append(value_el) + + dependency_el.append(identifier_el) + + environment_el.append(dependency_el) + + if environment['software'] is not None: + for software in environment['software']: + software_el = etree.Element(utils.lxmlns('premis') + "software") + + if software['swname'] is not None: + name_el = etree.Element(utils.lxmlns('premis') + "swName") + name_el.text = software['swname'] + software_el.append(name_el) + + if software['swversion'] is not None: + version_el = etree.Element(utils.lxmlns('premis') + "swVersion") + version_el.text = software['swversion'] + software_el.append(version_el) + + if software['swtype'] is not None: + type_el = etree.Element(utils.lxmlns('premis') + "swType") + type_el.text = software['swtype'] + software_el.append(type_el) + + if software['other_information'] is not None: + for other_info in software['other_information']: + other_el = etree.Element(utils.lxmlns('premis') + "swOtherInformation") + other_el.text = other_info + software_el.append(other_el) + + if software['dependencies'] is not None: + for dependency in software['dependencies']: + dependency_el = etree.Element(utils.lxmlns('premis') + "swDependency") + dependency_el.text = dependency + software_el.append(dependency_el) + + environment_el.append(software_el) + + if environment['hardware'] is not None: + for hardware in environment['hardware']: + hardware_el = etree.Element(utils.lxmlns('premis') + "hardware") + + if hardware['hwname'] is not None: + name_el = etree.Element(utils.lxmlns('premis') + "hwName") + name_el.text = hardware['hwname'] + hardware_el.append(name_el) + + if hardware['hwtype'] is not None: + type_el = etree.Element(utils.lxmlns('premis') + "hwType") + type_el.text = hardware['hwtype'] + hardware_el.append(type_el) + + if hardware['other_information'] is not None: + for other_info in hardware['other_information']: + other_el = etree.Element(utils.lxmlns('premis') + "hwOtherInformation") + other_el.text = other_info + hardware_el.append(other_el) + + environment_el.append(hardware_el) + + if environment['extensions'] is not None: + for extension_el in environment['extensions']: + # As these are elements, need to copy so append doesn't move them in the source element tree + environment_el.append(deepcopy(extension_el)) + + environment_els.append(environment_el) + + return environment_els + + def _serialize_signature_information(self): + info_els = [] + + if self.signature_information is not None: + for info in self.signature_information: + info_el = etree.Element(utils.lxmlns('premis') + "signatureInformation") + + for signature in info['signatures']: + signature_el = etree.Element(utils.lxmlns('premis') + "signature") + + if signature['encoding'] is not None: + utils.append_text_as_element_if_not_none(signature_el, signature['encoding'], 'premis', 'signatureEncoding') + utils.append_text_as_element_if_not_none(signature_el, signature['signer'], 'premis', 'signer') + utils.append_text_as_element_if_not_none(signature_el, signature['method'], 'premis', 'signatureMethod') + utils.append_text_as_element_if_not_none(signature_el, signature['value'], 'premis', 'signatureValue') + utils.append_text_as_element_if_not_none(signature_el, signature['validation_rules'], 'premis', 'signatureValidationRules') + + for property in signature['properties']: + utils.append_text_as_element_if_not_none(signature_el, property, 'premis', 'signatureProperties') + + utils.append_text_as_element_if_not_none(signature_el, signature['key_info'], 'premis', 'keyInformation') + + info_el.append(signature_el) + + for extension_el in info['extensions']: + # As these are elements, need to copy so append doesn't move them in the source element tree + info_el.append(deepcopy(extension_el)) + + info_els.append(info_el) + + return info_els + + def _serialize_relationships(self): + relationship_els = [] + + if self.relationships is not None: + for relationship in self.relationships: + relationship_el = etree.Element(utils.lxmlns('premis') + "relationship") + + utils.append_text_as_element_if_not_none(relationship_el, relationship['type'], 'premis', 'relationshipType') + utils.append_text_as_element_if_not_none(relationship_el, relationship['subtype'], 'premis', 'relationshipSubType') + + if relationship['related_objects'] is not None: + for related_object in relationship['related_objects']: + related_object_el = etree.Element(utils.lxmlns('premis') + "relatedObjectIdentification") + utils.append_text_as_element_if_not_none(related_object_el, related_object['type'], 'premis', 'relatedObjectIdentifierType') + utils.append_text_as_element_if_not_none(related_object_el, related_object['value'], 'premis', 'relatedObjectIdentifierValue') + utils.append_text_as_element_if_not_none(related_object_el, related_object['sequence'], 'premis', 'relatedObjectSequence') + relationship_el.append(related_object_el) + + if relationship['related_events'] is not None: + for related_event in relationship['related_events']: + related_event_el = etree.Element(utils.lxmlns('premis') + "relatedEventIdentification") + utils.append_text_as_element_if_not_none(related_event_el, related_event['type'], 'premis', 'relatedEventIdentifierType') + utils.append_text_as_element_if_not_none(related_event_el, related_event['value'], 'premis', 'relatedEventIdentifierValue') + utils.append_text_as_element_if_not_none(related_event_el, related_event['sequence'], 'premis', 'relatedEventSequence') + relationship_el.append(related_event_el) + + relationship_els.append(relationship_el) + + return relationship_els + + def _serialize_linking_event_identifiers(self): + identifier_els = [] + + if self.linking_event_identifiers is not None: + for identifier in self.linking_event_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "linkingEventIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['type'], 'premis', 'linkingEventIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['value'], 'premis', 'linkingEventIdentifierValue') + + identifier_els.append(identifier_el) + + return identifier_els + + def _serialize_linking_intellectual_entity_identifiers(self): + identifier_els = [] + + if self.linking_intellectual_entity_identifiers is not None: + for identifier in self.linking_intellectual_entity_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "linkingIntellectualEntityIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['type'], 'premis', 'linkingIntellectualEntityIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['value'], 'premis', 'linkingIntellectualEntityIdentifierValue') + + identifier_els.append(identifier_el) + + return identifier_els + + def _serialize_linking_rights_statement_identifiers(self): + identifier_els = [] + + if self.linking_rights_statement_identifiers is not None: + for identifier in self.linking_rights_statement_identifiers: + identifier_el = etree.Element(utils.lxmlns('premis') + "linkingRightsStatementIdentifier") + + utils.append_text_as_element_if_not_none(identifier_el, identifier['type'], 'premis', 'linkingRightsStatementIdentifierType') + utils.append_text_as_element_if_not_none(identifier_el, identifier['value'], 'premis', 'linkingRightsStatementIdentifierValue') + + identifier_els.append(identifier_el) + + return identifier_els + + +class ObjectCharacteristics(object): + """ + An object representing a PREMIS objectCharacteristics element. + + :param str composition_level: Composition level. + :param list fixity: List of dicts containing fixity data. + :param str size: File size in bytes. + :param list formats: List of dicts containing format data. + :param list creating_applications: List of dicts containing data about creating applications. + :param list inhibitors: List of dicts containing inhibitor data. + :param list exntensions: List of :class:`Element` instances for extension elements. + :param boolean is_mets: Whether or not the file is a METS file. + :raises exceptions.ParseError: If the root element tag is not objectCharacteristics. + """ + + def __init__(self, composition_level=None, fixity=None, size=None, formats=None, creating_applications=None, inhibitors=None, extensions=None, is_mets=None): + self.composition_level = composition_level + self.fixity = fixity + self.size = size + self.formats = formats + self.creating_applications = creating_applications + self.inhibitors = inhibitors + self.extensions = extensions + self.is_mets = is_mets + + @classmethod + def parse(cls, root): + """ + Create a new ObjectCharacteristics by parsing root. + + :param root: Element or ElementTree to be parsed into an object. + :raises exceptions.ParseError: If the root is not objectCharacteristics. + """ + if root.tag != utils.lxmlns('premis') + 'objectCharacteristics': + raise ParseError('ObjectCharacteristics can only parse objectCharacteristics elements with PREMIS namespace.') + + composition_level = root.findtext("premis:compositionLevel", namespaces=utils.NAMESPACES) + + fixity_els = root.findall("premis:fixity", namespaces=utils.NAMESPACES) + fixity = ObjectCharacteristics._parse_fixity(fixity_els) + + size = root.findtext("premis:size", namespaces=utils.NAMESPACES) + + format_els = root.findall("premis:format", namespaces=utils.NAMESPACES) + formats = ObjectCharacteristics._parse_format(format_els) + + creating_application_els = root.findall("premis:creatingApplication", namespaces=utils.NAMESPACES) + creating_applications = ObjectCharacteristics._parse_creating_applications(creating_application_els) + + inhibitor_els = root.findall("premis:inhibitors", namespaces=utils.NAMESPACES) + inhibitors = ObjectCharacteristics._parse_inhibitors(inhibitor_els) + + # Determine if object is a METS file + mets_markup_selector = "premis:objectCharacteristicsExtension/fits:fits/fits:metadata/fits:text/fits:markupLanguage" + + markup_el = root.find(mets_markup_selector, namespaces=utils.NAMESPACES) + + extensions = root.findall("premis:objectCharacteristicsExtension", namespaces=utils.NAMESPACES) + + is_mets = markup_el is not None and markup_el.text == 'http://www.loc.gov/standards/mets/mets.xsd' + + return cls(composition_level, fixity, size, formats, creating_applications, inhibitors, extensions, is_mets) + + @classmethod + def _parse_fixity(cls, fixity_els): + fixity = [] + + if fixity_els is not None: + for fixity_el in fixity_els: + fixity.append({ + 'digest_algorithm': fixity_el.findtext("premis:messageDigestAlgorithm", namespaces=utils.NAMESPACES), + "digest": fixity_el.findtext("premis:messageDigest", namespaces=utils.NAMESPACES), + "digest_originator": fixity_el.findtext("premis:messageDigestOriginator", namespaces=utils.NAMESPACES) + }) + + return fixity + + @classmethod + def _parse_format(cls, format_els): + formats = [] + + if format_els is not None: + for format_el in format_els: + designation_el = format_el.find("premis:formatDesignation", namespaces=utils.NAMESPACES) + + if designation_el is not None: + format_name = designation_el.findtext("premis:formatName", namespaces=utils.NAMESPACES) + format_version = designation_el.findtext("premis:formatVersion", namespaces=utils.NAMESPACES) + else: + format_name = None + format_version = None + + registry_el = format_el.find("premis:formatRegistry", namespaces=utils.NAMESPACES) + + if registry_el is not None: + registry_name = registry_el.findtext("premis:formatRegistryName", namespaces=utils.NAMESPACES) + registry_key = registry_el.findtext("premis:formatRegistryKey", namespaces=utils.NAMESPACES) + registry_role = registry_el.findtext("premis:formatRegistryRole", namespaces=utils.NAMESPACES) + else: + registry_name = None + registry_key = None + registry_role = None + + notes = [] + + note_els = format_el.findall("premis:formatNote", namespaces=utils.NAMESPACES) + + if note_els is not None: + for note_el in note_els: + notes.append(note_el.text) + + formats.append({ + 'name': format_name, + 'version': format_version, + 'registry_name': registry_name, + 'registry_key': registry_key, + 'registry_role': registry_role, + 'notes': notes + }) + + return formats + + @classmethod + def _parse_creating_applications(cls, creating_application_els): + creating_applications = [] + + if creating_application_els is not None: + for creating_application_el in creating_application_els: + extensions = creating_application_el.findall("premis:creatingApplicationExtension", namespaces=utils.NAMESPACES) + + creating_applications.append({ + 'name': creating_application_el.findtext("premis:creatingApplicationName", namespaces=utils.NAMESPACES), + 'version': creating_application_el.findtext("premis:creatingApplicationVersion", namespaces=utils.NAMESPACES), + 'create_date': creating_application_el.findtext("premis:dateCreatedByApplication", namespaces=utils.NAMESPACES), + 'extensions': extensions + }) + + return creating_applications + + @classmethod + def _parse_inhibitors(cls, inhibitor_els): + inhibitors = [] + + if inhibitor_els is not None: + for inhibitor_el in inhibitor_els: + targets = [] + target_els = inhibitor_el.findall("premis:inhibitorTarget", namespaces=utils.NAMESPACES) + for target_el in target_els: + targets.append(target_el.text) + + inhibitors.append({ + 'type': inhibitor_el.findtext("premis:inhibitorType", namespaces=utils.NAMESPACES), + 'key': inhibitor_el.findtext("premis:inhibitorKey", namespaces=utils.NAMESPACES), + 'targets': targets + }) + + return inhibitors diff --git a/metsrw/plugins/yapremisrw/utils.py b/metsrw/plugins/yapremisrw/utils.py new file mode 100644 index 0000000..2881ae8 --- /dev/null +++ b/metsrw/plugins/yapremisrw/utils.py @@ -0,0 +1,26 @@ +from lxml import etree + +NAMESPACES = { + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "premis": "info:lc/xmlns/premis-v2", + "fits": "http://hul.harvard.edu/ois/xml/ns/fits/fits_output", + "xlink": "http://www.w3.org/1999/xlink", +} + +PREMIS_SCHEMA_LOCATIONS = "info:lc/xmlns/premis-v2 " + \ + "http://www.loc.gov/standards/premis/v2/premis-v2-2.xsd" + +PREMIS_VERSION = "2.2" + + +def lxmlns(arg): + """ Return XPath-usable namespace. """ + return '{' + NAMESPACES[arg] + '}' + + +def append_text_as_element_if_not_none(parent_el, text, namespace, element_name): + """ If a string is supplied, create a node with it and append it to a parent element """ + if text is not None: + el = etree.Element(lxmlns(namespace) + element_name) + el.text = text + parent_el.append(el) diff --git a/metsrw/validate.py b/metsrw/validate.py index c2a41e1..31d3fad 100644 --- a/metsrw/validate.py +++ b/metsrw/validate.py @@ -14,7 +14,7 @@ AM_PNTR_SCT_PATH = 'resources/archivematica_mets_pointer_file_schematron.xml' -def _get_file_path(path): +def get_file_path(path): if not os.path.isfile(path): path_2 = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -31,7 +31,7 @@ def get_schematron(sct_path): """Return an lxml ``isoschematron.Schematron()`` instance using the schematron file at ``sct_path``. """ - sct_path = _get_file_path(sct_path) + sct_path = get_file_path(sct_path) parser = etree.XMLParser(remove_blank_text=True) sct_doc = etree.parse(sct_path, parser=parser) return isoschematron.Schematron(sct_doc, store_report=True) @@ -73,7 +73,7 @@ def get_xmlschema(xmlschema, mets_doc): - https://stackoverflow.com/questions/26712645/xml-type-definition-is-absent - https://stackoverflow.com/questions/2979824/in-document-schema-declarations-and-lxml """ - xsd_path = _get_file_path(xmlschema) + xsd_path = get_file_path(xmlschema) xmlschema = etree.parse(xsd_path) schema_locations = set( mets_doc.xpath('//*/@xsi:schemaLocation', namespaces=NAMESPACES)) diff --git a/requirements/dev.txt b/requirements/dev.txt index d3a09bb..7195b0f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,5 +1,6 @@ -r base.txt pytest pytest-cov +pytest-mock>=1,<2 sphinx>=1.3 tox diff --git a/setup.py b/setup.py index 3a3bd97..72fc367 100644 --- a/setup.py +++ b/setup.py @@ -5,27 +5,36 @@ https://github.com/pypa/sampleproject """ -# Always prefer setuptools over distutils +import codecs +import os +import re + from setuptools import setup, find_packages -# To use a consistent encoding -from codecs import open -from os import path -from metsrw import __version__ -here = path.abspath(path.dirname(__file__)) +def read(*parts): + path = os.path.join(os.path.dirname(__file__), *parts) + with codecs.open(path, encoding='utf-8') as fobj: + return fobj.read() + + +README = read('README.md') + -# Get the long description from the relevant file -with open(path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = f.read() +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") setup( name='metsrw', - version=__version__, + version=find_version('metsrw', '__init__.py'), description='Library for dealing with METS files.', - long_description=long_description, + long_description=README, url='https://github.com/artefactual-labs/mets-reader-writer/', diff --git a/tests/plugins/dcrw/__init__.py b/tests/plugins/dcrw/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/plugins/dcrw/test_dublincore.py b/tests/plugins/dcrw/test_dublincore.py new file mode 100644 index 0000000..bac9895 --- /dev/null +++ b/tests/plugins/dcrw/test_dublincore.py @@ -0,0 +1,63 @@ +from lxml import etree +import pytest +from unittest import TestCase + +import metsrw +import metsrw.plugins.dcrw as dcrw +import tests.helpers as h + + +class TestDublinCoreXmlData(TestCase): + """ Test DublinCoreXmlData class. """ + + def test_fromfile(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:dmdSec[@ID='dmdSec_1']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + h.print_element(xml_data_el) + + # Test properties + dc_object = dcrw.DublinCoreXmlData.parse(xml_data_el) + assert dc_object.title == 'Example DC title' + assert dc_object.creator == 'Example DC creator' + assert dc_object.subject == 'Example DC subject' + assert dc_object.description == 'Example DC description' + assert dc_object.publisher == 'Example DC publisher' + assert dc_object.contributor == 'Example DC contributor' + assert dc_object.date == '1984-01-01' + assert dc_object.format == 'Example DC format' + assert dc_object.identifier == 'Example DC identifier' + assert dc_object.source == 'Example DC source' + assert dc_object.relation == 'Example DC relation' + assert dc_object.language == 'en' + assert dc_object.coverage == 'Example DC coverage' + assert dc_object.rights == 'Example DC rights' + + def test_parse_wrong_element(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + mdwrap_el = root.find("mets:dmdSec[@ID='dmdSec_1']/" + + "mets:mdWrap", namespaces=metsrw.NAMESPACES) + + with pytest.raises(dcrw.ParseError): + dcrw.DublinCoreXmlData.parse(mdwrap_el) + + def test_serialization(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + fixture_dc_el = root.find("mets:dmdSec[@ID='dmdSec_1']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + + parsed_dc = dcrw.DublinCoreXmlData.parse(fixture_dc_el) + parsed_dc_el = parsed_dc.serialize() + + fixture_dc_xml = etree.tostring(fixture_dc_el, pretty_print=True) + parsed_dc_xml = etree.tostring(parsed_dc_el, pretty_print=True) + + assert fixture_dc_xml == parsed_dc_xml diff --git a/tests/plugins/yapremisrw/__init__.py b/tests/plugins/yapremisrw/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/plugins/yapremisrw/test_event.py b/tests/plugins/yapremisrw/test_event.py new file mode 100644 index 0000000..2d254ae --- /dev/null +++ b/tests/plugins/yapremisrw/test_event.py @@ -0,0 +1,99 @@ +from lxml import etree +import pytest +from unittest import TestCase + +import metsrw +import metsrw.plugins.yapremisrw as premisrw + + +class TestPremisEvent(TestCase): + """ Test Event class. """ + + def test_fromfile(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:amdSec[@ID='amdSec_5']/" + + "mets:digiprovMD[@ID='digiprovMD_35']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + event_el = xml_data_el.find("premis:event", + namespaces=premisrw.NAMESPACES) + + # Test misc. properties + premis_event = premisrw.Event.parse(event_el) + assert premis_event.identifier_type == 'UUID' + assert premis_event.identifier_value == 'daed73e2-3825-49ad-8460-6f978b19b582' + assert premis_event.event_type == 'validation' + assert premis_event.event_datetime == '2015-10-23T23:20:37' + assert premis_event.detail == 'program="JHOVE"; version="1.6"' + + # Test outcomes + assert premis_event.outcomes is not None + assert len(premis_event.outcomes) == 1 + assert premis_event.outcomes[0]['outcome'] == 'pass' + assert premis_event.outcomes[0]['details'] is not None + assert len(premis_event.outcomes[0]['details']) == 1 + assert premis_event.outcomes[0]['details'][0][ + 'note'] == ( + 'format="TIFF"; version="4.0"; result="Well-Formed and valid"') + assert premis_event.outcomes[0]['details'][0]['extensions'][0].find( + 'info').text == 'Example event outcome detail extension' + + # Test linking agent parsing + assert premis_event.linking_agent_identifiers is not None + assert len(premis_event.linking_agent_identifiers) == 3 + assert premis_event.linking_agent_identifiers[0]['identifier_type'] == 'Archivematica user pk' + assert premis_event.linking_agent_identifiers[0]['identifier_value'] == '1' + assert premis_event.linking_agent_identifiers[0]['roles'] is not None + assert premis_event.linking_agent_identifiers[0]['roles'][0] == 'Preserver' + + # Test linking object parsing + assert premis_event.linking_object_identifiers is not None + assert len(premis_event.linking_object_identifiers) == 1 + assert premis_event.linking_object_identifiers[0]['identifier_type'] == 'Example Object Identifier Type' + assert premis_event.linking_object_identifiers[0]['identifier_value'] == 'Example Object Identifier Value' + assert premis_event.linking_object_identifiers[0]['roles'] is not None + assert premis_event.linking_object_identifiers[0]['roles'][0] == 'Example Object Role' + + def test_parse_wrong_element(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + object_el = root.find("mets:amdSec[@ID='amdSec_17']/" + + "mets:techMD[@ID='techMD_17']/" + + "mets:mdWrap/" + + "mets:xmlData/" + + "premis:object", namespaces=metsrw.NAMESPACES) + + with pytest.raises(premisrw.ParseError): + premisrw.Event.parse(object_el) + + def test_serialization_basic(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:amdSec[@ID='amdSec_5']/" + + "mets:digiprovMD[@ID='digiprovMD_35']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + fixture_event_el = xml_data_el.find("premis:event", + namespaces=premisrw.NAMESPACES) + + event = premisrw.Event.parse(fixture_event_el) + el = event.serialize() + assert el.tag == '{}event'.format(premisrw.lxmlns('premis')) + assert el.attrib['{}schemaLocation'.format(premisrw.lxmlns('xsi'))] == premisrw.PREMIS_SCHEMA_LOCATIONS + assert el.attrib['version'] == premisrw.PREMIS_VERSION + + type_el = el.find(premisrw.lxmlns('premis') + 'eventType') + assert type_el is not None + assert type_el.text == 'validation' + + date_el = el.find(premisrw.lxmlns('premis') + 'eventDateTime') + assert date_el is not None + assert date_el.text == '2015-10-23T23:20:37' + + detail_el = el.find(premisrw.lxmlns('premis') + 'eventDetail') + assert detail_el is not None + assert detail_el.text == 'program="JHOVE"; version="1.6"' diff --git a/tests/plugins/yapremisrw/test_object.py b/tests/plugins/yapremisrw/test_object.py new file mode 100644 index 0000000..84cdb0b --- /dev/null +++ b/tests/plugins/yapremisrw/test_object.py @@ -0,0 +1,206 @@ +from lxml import etree +import pytest +from unittest import TestCase + +import metsrw +import metsrw.plugins.yapremisrw as premisrw + + +class TestPremisObject(TestCase): + """ Test Object class. """ + + def test_fromfile(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:amdSec[@ID='amdSec_17']/" + + "mets:techMD[@ID='techMD_17']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + object_el = xml_data_el.find("premis:object", + namespaces=premisrw.NAMESPACES) + + # Test misc. properties + premis_object = premisrw.Object.parse(object_el) + assert premis_object.object_category == 'Example object category' + assert premis_object.original_name == '%transferDirectory%objects/oakland03.jp2' + assert premis_object.object_identifiers is not None + assert len(premis_object.object_identifiers) == 1 + assert premis_object.object_identifiers[0]['type'] == 'UUID' + assert premis_object.object_identifiers[0]['value'] == 'e9400f17-5535-40bf-909b-e990fb9c2037' + + # Test characteristics + assert premis_object.characteristics[0]['composition_level'] == '0' + assert premis_object.characteristics[0]['fixity'] is not None + assert len(premis_object.characteristics[0]['fixity']) == 1 + assert premis_object.characteristics[0]['fixity'][0]['digest_algorithm'] == 'sha256' + assert premis_object.characteristics[0]['fixity'][0]['digest'] == 'd10bbb2cddc343cd50a304c21e67cb9d5937a93bcff5e717de2df65e0a6309d6' + assert premis_object.characteristics[0]['fixity'][0]['digest_originator'] == 'Example message digest originator' + assert premis_object.characteristics[0]['size'] == '527345' + assert premis_object.characteristics[0]['formats'] is not None + assert len(premis_object.characteristics[0]['formats']) == 1 + assert premis_object.characteristics[0]['formats'][0]['name'] == 'JP2 (JPEG 2000 part 1)' + assert premis_object.characteristics[0]['formats'][0]['version'] == 'Example format version' + assert premis_object.characteristics[0]['formats'][0]['registry_name'] == 'PRONOM' + assert premis_object.characteristics[0]['formats'][0]['registry_key'] == 'x-fmt/392' + assert premis_object.characteristics[0]['formats'][0]['registry_role'] == 'Example registry role' + assert premis_object.characteristics[0]['formats'][0]['notes'] is not None + assert len(premis_object.characteristics[0]['formats'][0]['notes']) == 2 + assert premis_object.characteristics[0]['formats'][0]['notes'][0] == 'Example format note #1' + assert premis_object.characteristics[0]['formats'][0]['notes'][1] == 'Example format note #2' + assert premis_object.characteristics[0]['creating_applications'] is not None + assert len(premis_object.characteristics[0]['creating_applications']) == 1 + assert premis_object.characteristics[0]['creating_applications'][0]['name'] == 'Example creating application name' + assert premis_object.characteristics[0]['creating_applications'][0]['version'] == 'Example creating application version' + assert premis_object.characteristics[0]['creating_applications'][0]['create_date'] == 'Example creating application create date' + assert premis_object.characteristics[0]['creating_applications'] is not None + assert len(premis_object.characteristics[0]['creating_applications'][0]['extensions']) == 2 + assert premis_object.characteristics[0]['creating_applications'][0]['extensions'][0].find('info').text == 'Example creating application extension #1' + assert premis_object.characteristics[0]['creating_applications'][0]['extensions'][1].find('info').text == 'Example creating application extension #2' + assert premis_object.characteristics[0]['inhibitors'] is not None + assert len(premis_object.characteristics[0]['inhibitors']) == 1 + assert premis_object.characteristics[0]['inhibitors'][0]['type'] == 'Example inhibitor type' + assert premis_object.characteristics[0]['inhibitors'][0]['key'] == 'Example inhibitor key' + assert premis_object.characteristics[0]['inhibitors'][0]['targets'] is not None + assert len(premis_object.characteristics[0]['inhibitors'][0]['targets']) == 2 + assert premis_object.characteristics[0]['inhibitors'][0]['targets'][0] == 'Example inhibitor target #1' + assert premis_object.characteristics[0]['inhibitors'][0]['targets'][1] == 'Example inhibitor target #2' + assert premis_object.characteristics[0]['extensions'] is not None + assert len(premis_object.characteristics[0]['extensions']) == 1 + + # Test signature information + assert premis_object.signature_information is not None + assert len(premis_object.signature_information) == 1 + assert premis_object.signature_information[0]['signatures'][0]['encoding'] == 'Example signature encoding' + assert premis_object.signature_information[0]['signatures'][0]['signer'] == 'Example signature signer' + assert premis_object.signature_information[0]['signatures'][0]['method'] == 'Example signature method' + assert premis_object.signature_information[0]['signatures'][0]['value'] == 'Example signature value' + assert premis_object.signature_information[0]['signatures'][0]['validation_rules'] == 'Example signature validation rules' + assert premis_object.signature_information[0]['signatures'][0]['properties'] is not None + assert len(premis_object.signature_information[0]['signatures'][0]['properties']) == 2 + assert premis_object.signature_information[0]['signatures'][0]['properties'][0] == 'Example signature property #1' + assert premis_object.signature_information[0]['signatures'][0]['key_info'] == 'Example signature key information' + assert len(premis_object.signature_information[0]['extensions']) == 1 + assert premis_object.signature_information[0]['extensions'][0].find('info').text == 'Example signature information extension' + + # Test relationships + assert premis_object.relationships is not None + assert premis_object.relationships[0]['type'] == 'derivation' + assert premis_object.relationships[0]['subtype'] == 'is source of' + assert premis_object.relationships[0]['related_objects'][0]['type'] == 'UUID' + assert premis_object.relationships[0]['related_objects'][0]['value'] == '4ee4365a-70dd-4c8a-98a9-976c76096b0c' + assert premis_object.relationships[0]['related_objects'][0]['sequence'] == 'Example related object sequence' + assert premis_object.relationships[0]['related_events'][0]['type'] == 'UUID' + assert premis_object.relationships[0]['related_events'][0]['value'] == 'a428bcc3-43bf-49e7-9da6-074a9d1b87eb' + + # Test preservation levels + assert premis_object.preservation_levels is not None + assert len(premis_object.preservation_levels) == 1 + assert premis_object.preservation_levels[0]['value'] == 'Example preservation level value' + assert premis_object.preservation_levels[0]['role'] == 'Example preservation level role' + assert premis_object.preservation_levels[0]['date_assigned'] == 'Example preservation level date' + assert premis_object.preservation_levels[0]['rationales'][0] == 'Example preservation level rationale' + + # Test significant properties + assert premis_object.significant_properties is not None + assert len(premis_object.significant_properties) == 1 + assert premis_object.significant_properties[0]['value'] == 'Example significant property value' + assert premis_object.significant_properties[0]['type'] == 'Example significant property type' + assert len(premis_object.significant_properties[0]['extensions']) == 1 + assert premis_object.significant_properties[0]['extensions'][0].find("info").text == 'Example significant property extension' + + # Test storage + assert premis_object.storage is not None + assert len(premis_object.storage) == 1 + assert premis_object.storage[0]['location_type'] == 'Example storage content location type' + assert premis_object.storage[0]['location_value'] == 'Example storage content location value' + assert premis_object.storage[0]['medium'] == 'Examploe storage medium' + + # Test environment + assert premis_object.environments is not None + assert len(premis_object.environments) == 1 + assert premis_object.environments[0]['characteristic'] == 'Example environment characteristic' + assert premis_object.environments[0]['purposes'][0] == 'Example environment purpose #1' + assert premis_object.environments[0]['purposes'][1] == 'Example environment purpose #2' + assert premis_object.environments[0]['notes'][0] == 'Example environment note #1' + assert premis_object.environments[0]['notes'][1] == 'Example environment note #2' + assert premis_object.environments[0]['dependencies'][0]['names'][0] == 'Example environment dependency name' + assert premis_object.environments[0]['dependencies'][0]['identifiers'][0]['type'] == 'Example environment dependency identifier type' + assert premis_object.environments[0]['dependencies'][0]['identifiers'][0]['value'] == 'Example environment dependency identifier value' + assert premis_object.environments[0]['software'][0]['swname'] == 'Example environment software name' + assert premis_object.environments[0]['software'][0]['swversion'] == 'Example environment software version' + assert premis_object.environments[0]['software'][0]['swtype'] == 'Example environment software type' + assert premis_object.environments[0]['software'][0]['other_information'][0] == 'Example environment software other information #1' + assert premis_object.environments[0]['software'][0]['other_information'][1] == 'Example environment software other information #2' + assert premis_object.environments[0]['software'][0]['dependencies'][0] == 'Example environment software dependency #1' + assert premis_object.environments[0]['software'][0]['dependencies'][1] == 'Example environment software dependency #2' + assert premis_object.environments[0]['hardware'][0]['hwname'] == 'Example environment hardware name' + assert premis_object.environments[0]['hardware'][0]['hwtype'] == 'Example environment hardware type' + assert premis_object.environments[0]['hardware'][0]['other_information'][0] == 'Example environment hardware other information #1' + assert premis_object.environments[0]['hardware'][0]['other_information'][1] == 'Example environment hardware other information #2' + assert premis_object.environments[0]['extensions'][0].find('info').text == 'Example environment extension #1' + assert premis_object.environments[0]['extensions'][1].find('info').text == 'Example environment extension #2' + + # Test liking event identifiers + assert premis_object.linking_event_identifiers is not None + assert len(premis_object.linking_event_identifiers) == 1 + assert premis_object.linking_event_identifiers[0]['type'] == 'Example linking event identifier type' + assert premis_object.linking_event_identifiers[0]['value'] == 'Example linking event identifier value' + + # Test linking intellectual entity identifiers + assert premis_object.linking_intellectual_entity_identifiers is not None + assert len(premis_object.linking_intellectual_entity_identifiers) == 1 + assert premis_object.linking_intellectual_entity_identifiers[0]['type'] == 'Example linking entity identifier type' + assert premis_object.linking_intellectual_entity_identifiers[0]['value'] == 'Example linking entity identifier value' + + # Test linking rights statement identifiers + assert premis_object.linking_rights_statement_identifiers is not None + assert len(premis_object.linking_rights_statement_identifiers) == 1 + assert premis_object.linking_rights_statement_identifiers[0]['type'] == 'Example linking rights statement identifier type' + assert premis_object.linking_rights_statement_identifiers[0]['value'] == 'Example linking rights statement identifier value' + + def test_object_construction(self): + with pytest.raises(premisrw.ConstructError): + premisrw.Object(None, 'Category', None, None, []) + with pytest.raises(premisrw.ConstructError): + premisrw.Object([], None, None, None, []) + with pytest.raises(premisrw.ConstructError): + premisrw.Object([], 'Category', None, None, None) + + def test_parse_wrong_element(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:amdSec[@ID='amdSec_5']/" + + "mets:digiprovMD[@ID='digiprovMD_35']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + event_el = xml_data_el.find("premis:event", + namespaces=premisrw.NAMESPACES) + with pytest.raises(premisrw.ParseError): + premisrw.Object.parse(event_el) + + def test_serialization(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + xml_data_el = root.find("mets:amdSec[@ID='amdSec_17']/" + + "mets:techMD[@ID='techMD_17']/" + + "mets:mdWrap/" + + "mets:xmlData", namespaces=metsrw.NAMESPACES) + fixture_object_el = xml_data_el.find("premis:object", + namespaces=premisrw.NAMESPACES) + + parsed_object = premisrw.Object.parse(fixture_object_el) + el = parsed_object.serialize() + assert el.tag == '{}object'.format(premisrw.lxmlns('premis')) + assert el.attrib['{}schemaLocation'.format(premisrw.lxmlns('xsi'))] == premisrw.PREMIS_SCHEMA_LOCATIONS + assert el.attrib['version'] == premisrw.PREMIS_VERSION + + category_el = el.find(premisrw.lxmlns('premis') + 'objectCategory') + assert category_el is not None + assert category_el.text == 'Example object category' + + name_el = el.find(premisrw.lxmlns('premis') + 'originalName') + assert name_el is not None + assert name_el.text == '%transferDirectory%objects/oakland03.jp2' diff --git a/tests/test_dependency_injection.py b/tests/test_dependency_injection.py index b65b9cc..1df4ded 100644 --- a/tests/test_dependency_injection.py +++ b/tests/test_dependency_injection.py @@ -2,11 +2,13 @@ import metsrw import metsrw.plugins.premisrw as premisrw +import metsrw.plugins.yapremisrw as yapremisrw from .constants import ( EX_AGT_1, EX_AGT_2, EX_COMPR_EVT, + EX_COMPR_EVT_TYPE, EX_PTR_AIP_SUBTYPE, EX_PTR_DATE_CREATED_BY_APPLICATION, EX_PTR_FORMAT_NAME, @@ -152,7 +154,7 @@ def test_dependency_injection(self): # Clear the feature broker and then register/provide the premisrw # plugin classes (services) with the feature broker. feature_broker = metsrw.feature_broker - assert len(feature_broker) == 3 + assert len(feature_broker) == 4 feature_broker.clear() assert not feature_broker feature_broker.provide('premis_object_class', premisrw.PREMISObject) @@ -271,6 +273,48 @@ def test_dependency_injection(self): assert (mets_doc_el.find(xpath, namespaces=metsrw.NAMESPACES).text == EX_PTR_IDENTIFIER_VALUE) + # Now change the feature broker so that ``FSEntry``'s dependencies on + # ``premis_object_class`` and ``premis_event_class`` class attributes + # are being fulfilled by the relevant classes from yapremisrw. + feature_broker.provide('premis_object_class', yapremisrw.Object) + feature_broker.provide('premis_event_class', yapremisrw.Event) + + # premis_object_tree + premis_object = yapremisrw.Object.fromtree(premis_object_tree) + premis_event_tree = premis_events[0].serialize() + premis_event = yapremisrw.Event.fromtree(premis_event_tree) + + # Create metsrw ``METSDocument`` and ``FSEntry`` instances. + mets_doc = metsrw.METSDocument() + fs_entry = metsrw.FSEntry( + path=EX_PTR_PATH, + file_uuid=EX_PTR_IDENTIFIER_VALUE, + use=EX_PTR_PACKAGE_TYPE, + type=EX_PTR_PACKAGE_TYPE, + transform_files=transform_files, + mets_div_type=EX_PTR_AIP_SUBTYPE) + mets_doc.append_file(fs_entry) + + # Use the ``add_premis_...`` methods to add the PREMIS metadata + # elements to the ``FSEntry`` instance. This will assert that each + # PREMIS instance is of the correct type (e.g., that ``premis_object`` + # is an instance of ``FSEntry().premis_object_class``) and will call the + # instance's ``serialize`` method and incorporate the resulting + # ``lxml.etree._ElementTree`` instance into the ``FSEntry`` instance + # appropriately. + fs_entry.add_premis_object(premis_object) + fs_entry.add_premis_event(premis_event) + + # Assert that the instances returned by the + # ``FSEntry().get_premis_...`` methods are of the anticipated type. + for new_premis_event in fs_entry.get_premis_events(): + assert isinstance(new_premis_event, yapremisrw.Event) + assert new_premis_event.event_type == EX_COMPR_EVT_TYPE + for new_premis_object in fs_entry.get_premis_objects(): + assert isinstance(new_premis_object, yapremisrw.Object) + for po_id in new_premis_object.object_identifiers: + assert po_id['value'] == EX_PTR_IDENTIFIER_VALUE + # Reset the feature broker to its default state so subsequent tests # don't break. metsrw.set_feature_broker_to_default_state(feature_broker) diff --git a/tests/test_mdwrap.py b/tests/test_mdwrap.py new file mode 100644 index 0000000..98ed4dc --- /dev/null +++ b/tests/test_mdwrap.py @@ -0,0 +1,43 @@ +from lxml import etree +import pytest +from unittest import TestCase + +import metsrw + + +class TestMDWrap(TestCase): + """ Test MDWrap class. """ + + def test_fromfile(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + mdwrap_el = root.find("mets:dmdSec[@ID='dmdSec_1']/" + + "mets:mdWrap", namespaces=metsrw.NAMESPACES) + + # Test properties + mdwrap = metsrw.MDWrap.parse(mdwrap_el) + assert mdwrap.data is not None + assert mdwrap.data['title'] == 'Example DC title' + assert mdwrap.data['creator'] == 'Example DC creator' + assert mdwrap.data['subject'] == 'Example DC subject' + assert mdwrap.data['description'] == 'Example DC description' + assert mdwrap.data['publisher'] == 'Example DC publisher' + assert mdwrap.data['contributor'] == 'Example DC contributor' + assert mdwrap.data['date'] == '1984-01-01' + assert mdwrap.data['format'] == 'Example DC format' + assert mdwrap.data['identifier'] == 'Example DC identifier' + assert mdwrap.data['source'] == 'Example DC source' + assert mdwrap.data['relation'] == 'Example DC relation' + assert mdwrap.data['language'] == 'en' + assert mdwrap.data['coverage'] == 'Example DC coverage' + assert mdwrap.data['rights'] == 'Example DC rights' + + def test_parse_wrong_element(self): + parser = etree.XMLParser(remove_blank_text=True) + root = etree.parse('fixtures/complete_mets_2.xml', parser=parser) + + dmdsec_el = root.find("mets:dmdSec[@ID='dmdSec_1']", namespaces=metsrw.NAMESPACES) + + with pytest.raises(metsrw.ParseError): + metsrw.MDWrap.parse(dmdsec_el) diff --git a/tests/test_mets.py b/tests/test_mets.py index d089549..c14fa26 100644 --- a/tests/test_mets.py +++ b/tests/test_mets.py @@ -581,8 +581,19 @@ def test_parse_production_pointer_file(self): def assert_mets_valid(self, mets_doc, schematron=metsrw.AM_SCT_PATH): is_valid, report = metsrw.validate(mets_doc, schematron=schematron) - if not is_valid: + try: + assert is_valid + except AssertionError: raise AssertionError(report['report']) def assert_pointer_valid(self, mets_doc): self.assert_mets_valid(mets_doc, schematron=metsrw.AM_PNTR_SCT_PATH) + + +def test_invalid_mets_file(): + mets_path = 'fixtures/mets_without_groupid_in_file.xml' + mets_doc = etree.parse(mets_path) + schematron = metsrw.AM_SCT_PATH + is_valid, report = metsrw.validate(mets_doc, schematron=schematron) + assert not is_valid + assert 'An amdSec element MUST contain a techMD' in report['report'] diff --git a/tests/test_validate.py b/tests/test_validate.py new file mode 100644 index 0000000..3e4603e --- /dev/null +++ b/tests/test_validate.py @@ -0,0 +1,32 @@ +# -*- coding: utf8 -*- +"""Tests for the metsrw.validate module.""" + +from __future__ import print_function + +import os + +import pytest + +import metsrw + + +def test_get_schematron(mocker): + bad_path = 'some/nonexistent/path/' + with mocker.patch('metsrw.get_file_path') as get_file_path: + with pytest.raises(ValueError): + metsrw.get_schematron(bad_path) + get_file_path.assert_called_once_with(bad_path) + + with mocker.patch('metsrw.get_file_path') as get_file_path: + mocker.patch.object(os.path, 'isfile', return_value=True) + with pytest.raises(IOError): + metsrw.get_schematron(bad_path) + get_file_path.assert_called_once_with(bad_path) + + def mockisfile(path): + return not (path == bad_path) + + mocker.patch.object(os.path, 'isfile', mockisfile) + with pytest.raises(IOError): + metsrw.get_schematron(bad_path) + assert os.path.isfile.call_count == 2